diff options
Diffstat (limited to 'src/map/script.c')
-rw-r--r-- | src/map/script.c | 8197 |
1 files changed, 4727 insertions, 3470 deletions
diff --git a/src/map/script.c b/src/map/script.c index 8460b23b0..0887b7f4e 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -8,7 +8,7 @@ #include "../common/nullpo.h" #include "../common/random.h" #include "../common/showmsg.h" -#include "../common/socket.h" // usage: getcharip +#include "../common/socket.h" // usage: getcharip #include "../common/strlib.h" #include "../common/timer.h" #include "../common/utils.h" @@ -66,11 +66,9 @@ static inline void SETVALUE(unsigned char* buf, int i, int n) { struct script_interface script_s; -const char* script_op2name(int op) -{ +const char* script_op2name(int op) { #define RETURN_OP_NAME(type) case type: return #type - switch( op ) - { + switch( op ) { RETURN_OP_NAME(C_NOP); RETURN_OP_NAME(C_POS); RETURN_OP_NAME(C_INT); @@ -85,6 +83,8 @@ const char* script_op2name(int op) RETURN_OP_NAME(C_USERFUNC); RETURN_OP_NAME(C_USERFUNC_POS); + RETURN_OP_NAME(C_REF); + // operators RETURN_OP_NAME(C_OP3); RETURN_OP_NAME(C_LOR); @@ -108,6 +108,10 @@ const char* script_op2name(int op) RETURN_OP_NAME(C_NOT); RETURN_OP_NAME(C_R_SHIFT); RETURN_OP_NAME(C_L_SHIFT); + RETURN_OP_NAME(C_ADD_POST); + RETURN_OP_NAME(C_SUB_POST); + RETURN_OP_NAME(C_ADD_PRE); + RETURN_OP_NAME(C_SUB_PRE); default: ShowDebug("script_op2name: unexpected op=%d\n", op); @@ -208,10 +212,7 @@ void script_reportdata(struct script_data* data) case C_NAME:// reference if( reference_tovariable(data) ) {// variable const char* name = reference_getname(data); - if( not_array_variable(*name) ) - ShowDebug("Data: variable name='%s'\n", name); - else - ShowDebug("Data: variable name='%s' index=%d\n", name, reference_getindex(data)); + ShowDebug("Data: variable name='%s' index=%d\n", name, reference_getindex(data)); } else if( reference_toconstant(data) ) {// constant ShowDebug("Data: constant name='%s' value=%d\n", reference_getname(data), reference_getconstant(data)); } else if( reference_toparam(data) ) {// param @@ -271,14 +272,14 @@ void script_reportfunc(struct script_state* st) /*========================================== * Output error message *------------------------------------------*/ -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) 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; longjmp( script->error_jump, 1 ); } -#define disp_error_message(mes,pos) script->disp_error_message2(mes,pos,1) +#define disp_error_message(mes,pos) (disp_error_message2((mes),(pos),1)) 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); @@ -297,13 +298,47 @@ void check_event(struct script_state *st, const char *evt) /*========================================== * Hashes the input string *------------------------------------------*/ -unsigned int calc_hash(const char* p) -{ +unsigned int calc_hash(const char* p) { unsigned int h; #if defined(SCRIPT_HASH_DJB2) h = 5381; while( *p ) // hash*33 + c + h = ( h << 5 ) + h + ((unsigned char)(*p++)); +#elif defined(SCRIPT_HASH_SDBM) + h = 0; + while( *p ) // hash*65599 + c + h = ( h << 6 ) + ( h << 16 ) - h + ((unsigned char)(*p++)); +#elif defined(SCRIPT_HASH_ELF) // UNIX ELF hash + h = 0; + while( *p ) { + unsigned int g; + h = ( h << 4 ) + ((unsigned char)(*p++)); + g = h & 0xF0000000; + if( g ) { + h ^= g >> 24; + h &= ~g; + } + } +#else // athena hash + h = 0; + while( *p ) + h = ( h << 1 ) + ( h >> 3 ) + ( h >> 5 ) + ( h >> 8 ) + (unsigned char)(*p++); +#endif + + return h % SCRIPT_HASH_SIZE; +} + +/*========================================== + * Hashes the input string in a case insensitive way + *------------------------------------------*/ +unsigned int calc_hash_ci(const char* p) { + unsigned int h = 0; +#ifdef ENABLE_CASE_CHECK + +#if defined(SCRIPT_HASH_DJB2) + h = 5381; + while( *p ) // hash*33 + c h = ( h << 5 ) + h + ((unsigned char)TOLOWER(*p++)); #elif defined(SCRIPT_HASH_SDBM) h = 0; @@ -311,12 +346,11 @@ unsigned int calc_hash(const char* p) h = ( h << 6 ) + ( h << 16 ) - h + ((unsigned char)TOLOWER(*p++)); #elif defined(SCRIPT_HASH_ELF) // UNIX ELF hash h = 0; - while( *p ){ + while( *p ) { unsigned int g; h = ( h << 4 ) + ((unsigned char)TOLOWER(*p++)); g = h & 0xF0000000; - if( g ) - { + if( g ) { h ^= g >> 24; h &= ~g; } @@ -327,6 +361,7 @@ unsigned int calc_hash(const char* p) h = ( h << 1 ) + ( h >> 3 ) + ( h >> 5 ) + ( h >> 8 ) + (unsigned char)TOLOWER(*p++); #endif +#endif // ENABLE_CASE_CHECK return h % SCRIPT_HASH_SIZE; } @@ -347,28 +382,118 @@ int script_search_str(const char* p) { int i; - for( i = script->str_hash[script->calc_hash(p)]; i != 0; i = script->str_data[i].next ) - if( strcasecmp(script->get_str(i),p) == 0 ) + for( i = script->str_hash[script->calc_hash(p)]; i != 0; i = script->str_data[i].next ) { + if( strcmp(script->get_str(i),p) == 0 ) { return i; + } + } return -1; } +void script_casecheck_clear_sub(struct casecheck_data *ccd) { +#ifdef ENABLE_CASE_CHECK + if (ccd->str_data) { + aFree(ccd->str_data); + ccd->str_data = NULL; + } + ccd->str_data_size = 0; + ccd->str_num = 1; + if (ccd->str_buf) { + aFree(ccd->str_buf); + ccd->str_buf = NULL; + } + ccd->str_pos = 0; + ccd->str_size = 0; + memset(ccd->str_hash, 0, sizeof(ccd->str_hash)); +#endif // ENABLE_CASE_CHECK +} + +void script_global_casecheck_clear(void) { + script_casecheck_clear_sub(&script->global_casecheck); +} + +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) { +#ifdef ENABLE_CASE_CHECK + int len, i; + int h = script->calc_hash_ci(p); + if( ccd->str_hash[h] == 0 ) { //empty bucket, add new node here + ccd->str_hash[h] = ccd->str_num; + } else { + const char *s = NULL; + for( i = ccd->str_hash[h]; ; i = ccd->str_data[i].next ) { + Assert( i >= 0 && i < ccd->str_size ); + s = ccd->str_buf+ccd->str_data[i].str; + if( strcasecmp(s,p) == 0 ) { + return s; // string already in list + } + if( ccd->str_data[i].next == 0 ) + break; // reached the end + } + + // append node to end of list + ccd->str_data[i].next = ccd->str_num; + } + + // grow list if neccessary + if( ccd->str_num >= ccd->str_data_size ) { + ccd->str_data_size += 1280; + RECREATE(ccd->str_data,struct str_data_struct,ccd->str_data_size); + memset(ccd->str_data + (ccd->str_data_size - 1280), '\0', 1280); + } + + len=(int)strlen(p); + + // grow string buffer if neccessary + while( ccd->str_pos+len+1 >= ccd->str_size ) { + ccd->str_size += 10240; + RECREATE(ccd->str_buf,char,ccd->str_size); + memset(ccd->str_buf + (ccd->str_size - 10240), '\0', 10240); + } + + safestrncpy(ccd->str_buf+ccd->str_pos, p, len+1); + ccd->str_data[ccd->str_num].type = C_NOP; + ccd->str_data[ccd->str_num].str = ccd->str_pos; + ccd->str_data[ccd->str_num].val = 0; + ccd->str_data[ccd->str_num].next = 0; + ccd->str_data[ccd->str_num].func = NULL; + ccd->str_data[ccd->str_num].backpatch = -1; + ccd->str_data[ccd->str_num].label = -1; + ccd->str_pos += len+1; + + ccd->str_num++; +#endif // ENABLE_CASE_CHECK + return NULL; +} + +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) { + 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) { - int i, h; - int len; - - h = script->calc_hash(p); + int i, len, h = script->calc_hash(p); +#ifdef ENABLE_CASE_CHECK + const char *existingentry = NULL; +#endif // ENABLE_CASE_CHECK if( script->str_hash[h] == 0 ) {// empty bucket, add new node here script->str_hash[h] = script->str_num; } else {// scan for end of list, or occurence of identical string for( i = script->str_hash[h]; ; i = script->str_data[i].next ) { - if( strcasecmp(script->get_str(i),p) == 0 ) + if( strcmp(script->get_str(i),p) == 0 ) { return i; // string already in list + } if( script->str_data[i].next == 0 ) break; // reached the end } @@ -377,6 +502,25 @@ int script_add_str(const char* p) script->str_data[i].next = script->str_num; } +#ifdef ENABLE_CASE_CHECK + if( (strncmp(p, ".@", 2) == 0) ) // Local scope vars are checked separately to decrease false positives + existingentry = script->local_casecheck.add_str(p); + else { + existingentry = script->global_casecheck.add_str(p); + if( existingentry ) { + if( strcasecmp(p, "disguise") == 0 || strcasecmp(p, "Poison_Spore") == 0 + || strcasecmp(p, "PecoPeco_Egg") == 0 || strcasecmp(p, "Soccer_Ball") == 0 + || strcasecmp(p, "Horn") == 0 || strcasecmp(p, "Treasure_Box_") == 0 + || strcasecmp(p, "Lord_of_Death") == 0 + ) // Known duplicates, don't bother warning the user + existingentry = NULL; + } + } + if( existingentry ) { + DeprecationWarning2("script_add_str", p, existingentry, script->parser_current_file); // TODO + } +#endif // ENABLE_CASE_CHECK + // grow list if neccessary if( script->str_num >= script->str_data_size ) { script->str_data_size += 1280; @@ -456,7 +600,7 @@ void add_scriptl(int l) { int backpatch = script->str_data[l].backpatch; - switch(script->str_data[l].type){ + switch(script->str_data[l].type) { case C_POS: case C_USERFUNC_POS: script->addc(C_POS); @@ -494,18 +638,18 @@ void set_label(int l,int pos, const char* script_pos) { int i,next; - if(script->str_data[l].type==C_INT || script->str_data[l].type==C_PARAM || script->str_data[l].type==C_FUNC) - { //Prevent overwriting constants values, parameters and built-in functions [Skotlex] + if(script->str_data[l].type==C_INT || script->str_data[l].type==C_PARAM || script->str_data[l].type==C_FUNC) { + //Prevent overwriting constants values, parameters and built-in functions [Skotlex] disp_error_message("set_label: invalid label name",script_pos); return; } - if(script->str_data[l].label!=-1){ + if(script->str_data[l].label!=-1) { disp_error_message("set_label: dup label ",script_pos); return; } script->str_data[l].type=(script->str_data[l].type == C_USERFUNC ? C_USERFUNC_POS : C_POS); script->str_data[l].label=pos; - for(i=script->str_data[l].backpatch;i>=0 && i!=0x00ffffff;){ + for(i=script->str_data[l].backpatch;i>=0 && i!=0x00ffffff;) { next=GETVALUE(script->buf,i); script->buf[i-1]=(script->str_data[l].type == C_USERFUNC ? C_USERFUNC_POS : C_POS); SETVALUE(script->buf,i,pos); @@ -581,7 +725,7 @@ const char* skip_word(const char* p) { /// @see skip_word /// @see script->add_str int add_word(const char* p) { - int len; + size_t len; int i; // Check for a word @@ -592,13 +736,13 @@ int add_word(const char* p) { // Duplicate the word if( len+1 > script->word_size ) RECREATE(script->word_buf, char, (script->word_size = (len+1))); - + memcpy(script->word_buf, p, len); script->word_buf[len] = 0; // add the word i = script->add_str(script->word_buf); - + return i; } @@ -610,17 +754,17 @@ const char* parse_callfunc(const char* p, int require_paren, int is_custom) { const char *p2; char *arg = NULL; + char null_arg = '\0'; int func; func = script->add_word(p); - if( script->str_data[func].type == C_FUNC ){ - char argT = 0; + if( script->str_data[func].type == C_FUNC ) { // buildin function script->addl(func); script->addc(C_ARG); arg = script->buildin[script->str_data[func].val]; - if( !arg ) arg = &argT; - } else if( script->str_data[func].type == C_USERFUNC || script->str_data[func].type == C_USERFUNC_POS ){ + if( !arg ) arg = &null_arg; // Use a dummy, null string + } else if( script->str_data[func].type == C_USERFUNC || script->str_data[func].type == C_USERFUNC_POS ) { // script defined function script->addl(script->buildin_callsub_ref); script->addc(C_ARG); @@ -666,12 +810,12 @@ const char* parse_callfunc(const char* p, int require_paren, int is_custom) script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_NO_PAREN; */ } else {// <func name> <arg list> - if( require_paren ){ + if( require_paren ) { if( *p != '(' ) disp_error_message("need '('",p); ++p; // skip '(' script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_PAREN; - } else if( *p == '(' ){ + } else if( *p == '(' ) { script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_UNDEFINED; } else { script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_NO_PAREN; @@ -695,7 +839,7 @@ const char* parse_callfunc(const char* p, int require_paren, int is_custom) disp_error_message2("parse_callfunc: not enough arguments, expected ','", p, script->config.warn_func_mismatch_paramnum); if( script->syntax.curly[script->syntax.curly_count].type != TYPE_ARGLIST ) disp_error_message("parse_callfunc: DEBUG last curly is not an argument list",p); - if( script->syntax.curly[script->syntax.curly_count].flag == ARGLIST_PAREN ){ + if( script->syntax.curly[script->syntax.curly_count].flag == ARGLIST_PAREN ) { if( *p != ')' ) disp_error_message("parse_callfunc: expected ')' to close argument list",p); ++p; @@ -721,6 +865,38 @@ void parse_nextline(bool first, const char* p) script->str_data[LABEL_NEXTLINE].label = -1; } +/** + * Pushes a variable into stack, processing its array index if needed. + * @see parse_variable + */ +void parse_variable_sub_push(int word, const char *p2) { + const char* p3 = NULL; + + if( p2 ) { + // process the variable index + + // push the getelementofarray method into the stack + script->addl(script->buildin_getelementofarray_ref); + script->addc(C_ARG); + script->addl(word); + + // process the sub-expression for this assignment + p3 = script->parse_subexpr(p2 + 1, 1); + p3 = script->skip_space(p3); + + if( *p3 != ']' ) {// closing parenthesis is required for this script + disp_error_message("Missing closing ']' parenthesis for the variable assignment.", p3); + } + + // push the closing function stack operator onto the stack + script->addc(C_FUNC); + p3++; + } else { + // No array index, simply push the variable or value onto the stack + script->addl(word); + } +} + /// 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 @@ -730,21 +906,30 @@ const char* parse_variable(const char* p) { const char *p2 = NULL; const char *var = p; + if( ( p[0] == '+' && p[1] == '+' && (type = C_ADD_PRE) ) // pre ++ + || ( p[0] == '-' && p[1] == '-' && (type = C_SUB_PRE) ) // pre -- + ) { + var = p = script->skip_space(&p[2]); + } + // skip the variable where applicable p = script->skip_word(p); p = script->skip_space(p); - if( p == NULL ) {// end of the line or invalid buffer + if( p == NULL ) { + // end of the line or invalid buffer return NULL; } - if( *p == '[' ) {// array variable so process the array as appropriate + if( *p == '[' ) { + // array variable so process the array as appropriate for( p2 = p, i = 0, j = 1; p; ++ i ) { if( *p ++ == ']' && --(j) == 0 ) break; if( *p == '[' ) ++ j; } - if( !(p = script->skip_space(p)) ) {// end of line or invalid characters remaining + if( !(p = script->skip_space(p)) ) { + // end of line or invalid characters remaining disp_error_message("Missing right expression or closing bracket for variable.", p); } } @@ -759,9 +944,8 @@ const char* parse_variable(const char* p) { || ( p[0] == '*' && p[1] == '=' && (type = C_MUL) ) // *= || ( p[0] == '/' && p[1] == '=' && (type = C_DIV) ) // /= || ( p[0] == '%' && p[1] == '=' && (type = C_MOD) ) // %= - || ( p[0] == '~' && p[1] == '=' && (type = C_NOT) ) // ~= - || ( p[0] == '+' && p[1] == '+' && (type = C_ADD_PP) ) // ++ - || ( p[0] == '-' && p[1] == '-' && (type = C_SUB_PP) ) // -- + || ( p[0] == '+' && p[1] == '+' && (type = C_ADD_POST) ) // post ++ + || ( p[0] == '-' && p[1] == '-' && (type = C_SUB_POST) ) // post -- || ( p[0] == '<' && p[1] == '<' && p[2] == '=' && (type = C_L_SHIFT) ) // <<= || ( p[0] == '>' && p[1] == '>' && p[2] == '=' && (type = C_R_SHIFT) ) // >>= ) ) @@ -770,23 +954,26 @@ const char* parse_variable(const char* p) { } switch( type ) { - case C_EQ: {// incremental modifier + case C_ADD_PRE: // pre ++ + case C_SUB_PRE: // pre -- + // (nothing more to skip) + break; + + case C_EQ: // = p = script->skip_space( &p[1] ); - } - break; + break; - case C_L_SHIFT: - case C_R_SHIFT: {// left or right shift modifier + case C_L_SHIFT: // <<= + case C_R_SHIFT: // >>= p = script->skip_space( &p[3] ); - } - break; + break; - default: {// normal incremental command + default: // everything else p = script->skip_space( &p[2] ); - } } - if( p == NULL ) {// end of line or invalid buffer + if( p == NULL ) { + // end of line or invalid buffer return NULL; } @@ -800,56 +987,45 @@ const char* parse_variable(const char* p) { script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_PAREN; // increment the total curly count for the position in the script - ++ script->syntax.curly_count; + ++script->syntax.curly_count; // parse the variable currently being modified word = script->add_word(var); - if( script->str_data[word].type == C_FUNC || script->str_data[word].type == C_USERFUNC || script->str_data[word].type == C_USERFUNC_POS ) - {// cannot assign a variable which exists as a function or label + if( script->str_data[word].type == C_FUNC + || script->str_data[word].type == C_USERFUNC + || script->str_data[word].type == C_USERFUNC_POS + ) { + // cannot assign a variable which exists as a function or label disp_error_message("Cannot modify a variable which has the same name as a function or label.", p); } - if( p2 ) {// process the variable index - const char* p3 = NULL; - - // push the getelementofarray method into the stack - script->addl(script->buildin_getelementofarray_ref); - script->addc(C_ARG); - script->addl(word); - - // process the sub-expression for this assignment - p3 = script->parse_subexpr(p2 + 1, 1); - p3 = script->skip_space(p3); - - if( *p3 != ']' ) {// closing parenthesis is required for this script - disp_error_message("Missing closing ']' parenthesis for the variable assignment.", p3); - } + parse_variable_sub_push(word, p2); // Push variable onto the stack - // push the closing function stack operator onto the stack - script->addc(C_FUNC); - p3 ++; - } else {// simply push the variable or value onto the stack - script->addl(word); + if( type != C_EQ ) { + parse_variable_sub_push(word, p2); // Push variable onto the stack once again (first argument of setr) } - if( type != C_EQ ) - script->addc(C_REF); + if( type == C_ADD_POST || type == C_SUB_POST ) { // post ++ / -- + script->addi(1); + script->addc(type == C_ADD_POST ? C_ADD : C_SUB); - if( type == C_ADD_PP || type == C_SUB_PP ) {// incremental operator for the method + parse_variable_sub_push(word, p2); // Push variable onto the stack (third argument of setr) + } else if( type == C_ADD_PRE || type == C_SUB_PRE ) { // pre ++ / -- script->addi(1); - script->addc(type == C_ADD_PP ? C_ADD : C_SUB); - } else {// process the value as an expression + script->addc(type == C_ADD_PRE ? C_ADD : C_SUB); + } else { + // process the value as an expression p = script->parse_subexpr(p, -1); - if( type != C_EQ ) - {// push the type of modifier onto the stack + if( type != C_EQ ) { + // push the type of modifier onto the stack script->addc(type); } } // decrement the curly count for the position within the script - -- script->syntax.curly_count; + --script->syntax.curly_count; // close the script by appending the function operator script->addc(C_FUNC); @@ -858,67 +1034,108 @@ const char* parse_variable(const char* p) { return p; } +/* + * Checks whether the gives string is a number literal + * + * Mainly necessary to differentiate between number literals and NPC name + * constants, since several of those start with a digit. + * + * All this does is to check if the string begins with an optional + or - sign, + * followed by a hexadecimal or decimal number literal literal and is NOT + * followed by a underscore or letter. + * + * @param p Pointer to the string to check + * @return Whether the string is a number literal + */ +bool is_number(const char *p) { + const char *np; + if (!p) + return false; + if (*p == '-' || *p == '+') + p++; + np = p; + if (*p == '0' && p[1] == 'x') { + p+=2; + np = p; + // Hexadecimal + while (ISXDIGIT(*np)) + np++; + } else { + // Decimal + while (ISDIGIT(*np)) + np++; + } + if (p != np && *np != '_' && !ISALPHA(*np)) // At least one digit, and next isn't a letter or _ + return true; + return false; +} + /*========================================== * Analysis section *------------------------------------------*/ -const char* parse_simpleexpr(const char *p) -{ - long long i; +const char* parse_simpleexpr(const char *p) { + int i; p=script->skip_space(p); if(*p==';' || *p==',') disp_error_message("parse_simpleexpr: unexpected end of expression",p); - if(*p=='('){ + if(*p=='(') { if( (i=script->syntax.curly_count-1) >= 0 && script->syntax.curly[i].type == TYPE_ARGLIST ) ++script->syntax.curly[i].count; p=script->parse_subexpr(p+1,-1); p=script->skip_space(p); - if( (i=script->syntax.curly_count-1) >= 0 && script->syntax.curly[i].type == TYPE_ARGLIST && - script->syntax.curly[i].flag == ARGLIST_UNDEFINED && --script->syntax.curly[i].count == 0 - ){ - if( *p == ',' ){ + if( (i=script->syntax.curly_count-1) >= 0 && script->syntax.curly[i].type == TYPE_ARGLIST + && script->syntax.curly[i].flag == ARGLIST_UNDEFINED && --script->syntax.curly[i].count == 0 + ) { + if( *p == ',' ) { script->syntax.curly[i].flag = ARGLIST_PAREN; return p; - } else + } else { script->syntax.curly[i].flag = ARGLIST_NO_PAREN; + } } if( *p != ')' ) disp_error_message("parse_simpleexpr: unmatched ')'",p); ++p; - } else if(ISDIGIT(*p) || ((*p=='-' || *p=='+') && ISDIGIT(p[1]))){ + } else if(is_number(p)) { char *np; - while(*p == '0' && ISDIGIT(p[1])) p++; - i=strtoll(p,&np,0); - if( i < INT_MIN ) { - i = INT_MIN; + long long lli; + while(*p == '0' && ISDIGIT(p[1])) p++; // Skip leading zeros, we don't support octal literals + lli=strtoll(p,&np,0); + if( lli < INT_MIN ) { + lli = INT_MIN; script->disp_warning_message("parse_simpleexpr: underflow detected, capping value to INT_MIN",p); - } else if( i > INT_MAX ) { - i = INT_MAX; + } else if( lli > INT_MAX ) { + lli = INT_MAX; script->disp_warning_message("parse_simpleexpr: overflow detected, capping value to INT_MAX",p); } - script->addi((int)i); + script->addi((int)lli); // Cast is safe, as it's already been checked for overflows p=np; - } else if(*p=='"'){ + } else if(*p=='"') { script->addc(C_STR); - p++; - while( *p && *p != '"' ){ - if( (unsigned char)p[-1] <= 0x7e && *p == '\\' ) { - char buf[8]; - size_t len = sv->skip_escaped_c(p) - p; - size_t n = sv->unescape_c(buf, p, len); - if( n != 1 ) - ShowDebug("parse_simpleexpr: unexpected length %d after unescape (\"%.*s\" -> %.*s)\n", (int)n, (int)len, p, (int)n, buf); - p += len; - script->addb(*buf); - continue; - } else if( *p == '\n' ) - disp_error_message("parse_simpleexpr: unexpected newline @ string",p); - script->addb(*p++); - } - if(!*p) - disp_error_message("parse_simpleexpr: unexpected end of file @ string",p); + do { + p++; + while( *p && *p != '"' ) { + if( (unsigned char)p[-1] <= 0x7e && *p == '\\' ) { + char buf[8]; + size_t len = sv->skip_escaped_c(p) - p; + size_t n = sv->unescape_c(buf, p, len); + if( n != 1 ) + ShowDebug("parse_simpleexpr: unexpected length %d after unescape (\"%.*s\" -> %.*s)\n", (int)n, (int)len, p, (int)n, buf); + p += len; + script->addb(*buf); + continue; + } else if( *p == '\n' ) { + disp_error_message("parse_simpleexpr: unexpected newline @ string",p); + } + script->addb(*p++); + } + if(!*p) + disp_error_message("parse_simpleexpr: unexpected end of file @ string",p); + p++; //'"' + p = script->skip_space(p); + } while( *p && *p == '"' ); script->addb(0); - p++; //'"' } else { int l; const char* pv; @@ -928,24 +1145,24 @@ const char* parse_simpleexpr(const char *p) disp_error_message("parse_simpleexpr: unexpected character",p); l=script->add_word(p); - if( script->str_data[l].type == C_FUNC || script->str_data[l].type == C_USERFUNC || script->str_data[l].type == C_USERFUNC_POS) + if( script->str_data[l].type == C_FUNC || script->str_data[l].type == C_USERFUNC || script->str_data[l].type == C_USERFUNC_POS) { return script->parse_callfunc(p,1,0); #ifdef SCRIPT_CALLFUNC_CHECK - else { + } else { const char* name = script->get_str(l); if( strdb_get(script->userfunc_db,name) != NULL ) { return script->parse_callfunc(p,1,1); } - } #endif + } - if( (pv = script->parse_variable(p)) ) - {// successfully processed a variable assignment + if( (pv = script->parse_variable(p)) ) { + // successfully processed a variable assignment return pv; } p=script->skip_word(p); - if( *p == '[' ){ + if( *p == '[' ) { // array(name[i] => getelementofarray(name,i) ) script->addl(script->buildin_getelementofarray_ref); script->addc(C_ARG); @@ -957,8 +1174,9 @@ const char* parse_simpleexpr(const char *p) disp_error_message("parse_simpleexpr: unmatched ']'",p); ++p; script->addc(C_FUNC); - }else + } else { script->addl(l); + } } @@ -968,48 +1186,51 @@ const char* parse_simpleexpr(const char *p) /*========================================== * Analysis of the expression *------------------------------------------*/ -const char* script_parse_subexpr(const char* p,int limit) -{ +const char* script_parse_subexpr(const char* p,int limit) { int op,opl,len; const char* tmpp; p=script->skip_space(p); - if( *p == '-' ){ - tmpp = script->skip_space(p+1); - if( *tmpp == ';' || *tmpp == ',' ){ + if( *p == '-' ) { + tmpp = script->skip_space(p+1); + if( *tmpp == ';' || *tmpp == ',' ) { script->addl(LABEL_NEXTLINE); p++; return p; } } - if((op=C_NEG,*p=='-') || (op=C_LNOT,*p=='!') || (op=C_NOT,*p=='~')){ - p=script->parse_subexpr(p+1,10); + if( (p[0]=='+' && p[1]=='+') /* C_ADD_PRE */ || (p[0]=='-'&&p[1]=='-') /* C_SUB_PRE */ ) { // Pre ++ -- operators + p=script->parse_variable(p); + } else if( (op=C_NEG,*p=='-') || (op=C_LNOT,*p=='!') || (op=C_NOT,*p=='~') ) { // Unary - ! ~ operators + p=script->parse_subexpr(p+1,11); script->addc(op); - } else + } else { p=script->parse_simpleexpr(p); + } p=script->skip_space(p); while(( - (op=C_OP3,opl=0,len=1,*p=='?') || - (op=C_ADD,opl=8,len=1,*p=='+') || - (op=C_SUB,opl=8,len=1,*p=='-') || - (op=C_MUL,opl=9,len=1,*p=='*') || - (op=C_DIV,opl=9,len=1,*p=='/') || - (op=C_MOD,opl=9,len=1,*p=='%') || - (op=C_LAND,opl=2,len=2,*p=='&' && p[1]=='&') || - (op=C_AND,opl=6,len=1,*p=='&') || - (op=C_LOR,opl=1,len=2,*p=='|' && p[1]=='|') || - (op=C_OR,opl=5,len=1,*p=='|') || - (op=C_XOR,opl=4,len=1,*p=='^') || - (op=C_EQ,opl=3,len=2,*p=='=' && p[1]=='=') || - (op=C_NE,opl=3,len=2,*p=='!' && p[1]=='=') || - (op=C_R_SHIFT,opl=7,len=2,*p=='>' && p[1]=='>') || - (op=C_GE,opl=3,len=2,*p=='>' && p[1]=='=') || - (op=C_GT,opl=3,len=1,*p=='>') || - (op=C_L_SHIFT,opl=7,len=2,*p=='<' && p[1]=='<') || - (op=C_LE,opl=3,len=2,*p=='<' && p[1]=='=') || - (op=C_LT,opl=3,len=1,*p=='<')) && opl>limit){ + (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_MUL, opl=10,len=1,*p=='*') // * + || (op=C_DIV, opl=10,len=1,*p=='/') // / + || (op=C_MOD, opl=10,len=1,*p=='%') // % + || (op=C_LAND, opl=2, len=2,*p=='&' && p[1]=='&') // && + || (op=C_AND, opl=5, len=1,*p=='&') // & + || (op=C_LOR, opl=1, len=2,*p=='|' && p[1]=='|') // || + || (op=C_OR, opl=3, len=1,*p=='|') // | + || (op=C_XOR, opl=4, len=1,*p=='^') // ^ + || (op=C_EQ, opl=6, len=2,*p=='=' && p[1]=='=') // == + || (op=C_NE, opl=6, len=2,*p=='!' && p[1]=='=') // != + || (op=C_R_SHIFT,opl=8, len=2,*p=='>' && p[1]=='>') // >> + || (op=C_GE, opl=7, len=2,*p=='>' && p[1]=='=') // >= + || (op=C_GT, opl=7, len=1,*p=='>') // > + || (op=C_L_SHIFT,opl=8, len=2,*p=='<' && p[1]=='<') // << + || (op=C_LE, opl=7, len=2,*p=='<' && p[1]=='=') // <= + || (op=C_LT, opl=7, len=1,*p=='<') // < + ) && opl>limit) { p+=len; if(op == C_OP3) { p=script->parse_subexpr(p,-1); @@ -1032,7 +1253,7 @@ const char* script_parse_subexpr(const char* p,int limit) *------------------------------------------*/ const char* parse_expr(const char *p) { - switch(*p){ + switch(*p) { case ')': case ';': case ':': case '[': case ']': case '}': disp_error_message("parse_expr: unexpected char",p); @@ -1143,7 +1364,7 @@ const char* parse_curly_close(const char* p) sprintf(label,"__SW%x_FIN",script->syntax.curly[pos].index); l=script->add_str(label); script->set_label(l,script->pos, p); - linkdb_final(&script->syntax.curly[pos].case_label); // free the list of case label + linkdb_final(&script->syntax.curly[pos].case_label); // free the list of case label script->syntax.curly_count--; //Closing decision if, for , while p = script->parse_syntax_close(p + 1); @@ -1164,7 +1385,7 @@ const char* parse_syntax(const char* p) switch(*p) { case 'B': case 'b': - if(p2 - p == 5 && !strncasecmp(p,"break",5)) { + if( p2 - p == 5 && strncmp(p,"break",5) == 0 ) { // break Processing char label[256]; int pos = script->syntax.curly_count - 1; @@ -1197,11 +1418,15 @@ const char* parse_syntax(const char* p) // Closing decision if, for , while p = script->parse_syntax_close(p + 1); return p; +#ifdef ENABLE_CASE_CHECK + } else if( p2 - p == 5 && strncasecmp(p, "break", 5) == 0 ) { + disp_deprecation_message("parse_syntax", "break", p); // TODO +#endif // ENABLE_CASE_CHECK } break; case 'c': case 'C': - if(p2 - p == 4 && !strncasecmp(p,"case",4)) { + if( p2 - p == 4 && strncmp(p, "case", 4) == 0 ) { //Processing case int pos = script->syntax.curly_count-1; if(pos < 0 || script->syntax.curly[pos].type != TYPE_SWITCH) { @@ -1229,21 +1454,23 @@ const char* parse_syntax(const char* p) disp_error_message("parse_syntax: expect space ' '",p); } // check whether case label is integer or not - v = strtol(p,&np,0); - if(np == p) { //Check for constants + if(is_number(p)) { + //Numeric value + v = (int)strtol(p,&np,0); + if((*p == '-' || *p == '+') && ISDIGIT(p[1])) // pre-skip because '-' can not skip_word + p++; + p = script->skip_word(p); + if(np != p) + disp_error_message("parse_syntax: 'case' label is not an integer",np); + } else { + //Check for constants p2 = script->skip_word(p); - v = p2-p; // length of word at p2 + v = (int)(size_t) (p2-p); // length of word at p2 memcpy(label,p,v); label[v]='\0'; if( !script->get_constant(label, &v) ) disp_error_message("parse_syntax: 'case' label is not an integer",p); p = script->skip_word(p); - } else { //Numeric value - if((*p == '-' || *p == '+') && ISDIGIT(p[1])) // pre-skip because '-' can not skip_word - p++; - p = script->skip_word(p); - if(np != p) - disp_error_message("parse_syntax: 'case' label is not an integer",np); } p = script->skip_space(p); if(*p != ':') @@ -1274,7 +1501,7 @@ const char* parse_syntax(const char* p) script->syntax.curly[pos].count++; } return p + 1; - } else if(p2 - p == 8 && !strncasecmp(p,"continue",8)) { + } else if( p2 - p == 8 && strncmp(p, "continue", 8) == 0 ) { // Processing continue char label[256]; int pos = script->syntax.curly_count - 1; @@ -1305,11 +1532,17 @@ const char* parse_syntax(const char* p) //Closing decision if, for , while p = script->parse_syntax_close(p + 1); return p; +#ifdef ENABLE_CASE_CHECK + } else if( p2 - p == 4 && strncasecmp(p, "case", 4) == 0 ) { + disp_deprecation_message("parse_syntax", "case", p); // TODO + } else if( p2 - p == 8 && strncasecmp(p, "continue", 8) == 0 ) { + disp_deprecation_message("parse_syntax", "continue", p); // TODO +#endif // ENABLE_CASE_CHECK } break; case 'd': case 'D': - if(p2 - p == 7 && !strncasecmp(p,"default",7)) { + if( p2 - p == 7 && strncmp(p, "default", 7) == 0 ) { // Switch - default processing int pos = script->syntax.curly_count-1; if(pos < 0 || script->syntax.curly[pos].type != TYPE_SWITCH) { @@ -1343,7 +1576,7 @@ const char* parse_syntax(const char* p) script->syntax.curly[pos].count++; } return p + 1; - } else if(p2 - p == 2 && !strncasecmp(p,"do",2)) { + } else if( p2 - p == 2 && strncmp(p, "do", 2) == 0 ) { int l; char label[256]; p=script->skip_space(p2); @@ -1358,11 +1591,17 @@ const char* parse_syntax(const char* p) script->set_label(l,script->pos,p); script->syntax.curly_count++; return p; +#ifdef ENABLE_CASE_CHECK + } else if( p2 - p == 7 && strncasecmp(p, "default", 7) == 0 ) { + disp_deprecation_message("parse_syntax", "default", p); // TODO + } else if( p2 - p == 2 && strncasecmp(p, "do", 2) == 0 ) { + disp_deprecation_message("parse_syntax", "do", p); // TODO +#endif // ENABLE_CASE_CHECK } break; case 'f': case 'F': - if(p2 - p == 3 && !strncasecmp(p,"for",3)) { + if( p2 - p == 3 && strncmp(p, "for", 3) == 0 ) { int l; char label[256]; int pos = script->syntax.curly_count; @@ -1436,9 +1675,8 @@ const char* parse_syntax(const char* p) l=script->add_str(label); script->set_label(l,script->pos,p); return p; - } - else if( p2 - p == 8 && strncasecmp(p,"function",8) == 0 ) - {// internal script function + } else if( p2 - p == 8 && strncmp(p, "function", 8) == 0 ) { + // internal script function const char *func_name; func_name = script->skip_space(p2); @@ -1498,11 +1736,17 @@ const char* parse_syntax(const char* p) { disp_error_message("expect ';' or '{' at function syntax",p); } +#ifdef ENABLE_CASE_CHECK + } else if( p2 - p == 3 && strncasecmp(p, "for", 3) == 0 ) { + disp_deprecation_message("parse_syntax", "for", p); // TODO + } else if( p2 - p == 8 && strncasecmp(p, "function", 8) == 0 ) { + disp_deprecation_message("parse_syntax", "function", p); // TODO +#endif // ENABLE_CASE_CHECK } break; case 'i': case 'I': - if(p2 - p == 2 && !strncasecmp(p,"if",2)) { + if( p2 - p == 2 && strncmp(p, "if", 2) == 0 ) { // If process char label[256]; p=script->skip_space(p2); @@ -1522,11 +1766,15 @@ const char* parse_syntax(const char* p) script->addl(script->add_str(label)); script->addc(C_FUNC); return p; +#ifdef ENABLE_CASE_CHECK + } else if( p2 - p == 2 && strncasecmp(p, "if", 2) == 0 ) { + disp_deprecation_message("parse_syntax", "if", p); // TODO +#endif // ENABLE_CASE_CHECK } break; case 's': case 'S': - if(p2 - p == 6 && !strncasecmp(p,"switch",6)) { + if( p2 - p == 6 && strncmp(p, "switch", 6) == 0 ) { // Processing of switch () char label[256]; p=script->skip_space(p2); @@ -1549,11 +1797,15 @@ const char* parse_syntax(const char* p) } script->addc(C_FUNC); return p + 1; +#ifdef ENABLE_CASE_CHECK + } else if( p2 - p == 6 && strncasecmp(p, "switch", 6) == 0 ) { + disp_deprecation_message("parse_syntax", "switch", p); // TODO +#endif // ENABLE_CASE_CHECK } break; case 'w': case 'W': - if(p2 - p == 5 && !strncasecmp(p,"while",5)) { + if( p2 - p == 5 && strncmp(p, "while", 5) == 0 ) { int l; char label[256]; p=script->skip_space(p2); @@ -1579,6 +1831,10 @@ const char* parse_syntax(const char* p) script->addl(script->add_str(label)); script->addc(C_FUNC); return p; +#ifdef ENABLE_CASE_CHECK + } else if( p2 - p == 5 && strncasecmp(p, "while", 5) == 0 ) { + disp_deprecation_message("parse_syntax", "while", p); // TODO +#endif // ENABLE_CASE_CHECK } break; } @@ -1596,8 +1852,8 @@ const char* parse_syntax_close(const char *p) { } // Close judgment if, for, while, of do -// flag == 1 : closed -// flag == 0 : not closed +// flag == 1 : closed +// flag == 0 : not closed const char* parse_syntax_close_sub(const char* p,int* flag) { char label[256]; @@ -1629,11 +1885,11 @@ const char* parse_syntax_close_sub(const char* p,int* flag) script->syntax.curly[pos].count++; p = script->skip_space(p); p2 = script->skip_word(p); - if(!script->syntax.curly[pos].flag && p2 - p == 4 && !strncasecmp(p,"else",4)) { + if( !script->syntax.curly[pos].flag && p2 - p == 4 && strncmp(p, "else", 4) == 0 ) { // else or else - if p = script->skip_space(p2); p2 = script->skip_word(p); - if(p2 - p == 2 && !strncasecmp(p,"if",2)) { + if( p2 - p == 2 && strncmp(p, "if", 2) == 0 ) { // else - if p=script->skip_space(p2); if(*p != '(') { @@ -1648,6 +1904,10 @@ const char* parse_syntax_close_sub(const char* p,int* flag) script->addc(C_FUNC); *flag = 0; return p; +#ifdef ENABLE_CASE_CHECK + } else if( p2 - p == 2 && strncasecmp(p, "if", 2) == 0 ) { + disp_deprecation_message("parse_syntax", "if", p); // TODO +#endif // ENABLE_CASE_CHECK } else { // else if(!script->syntax.curly[pos].flag) { @@ -1656,6 +1916,10 @@ const char* parse_syntax_close_sub(const char* p,int* flag) return p; } } +#ifdef ENABLE_CASE_CHECK + } else if( !script->syntax.curly[pos].flag && p2 - p == 4 && strncasecmp(p, "else", 4) == 0 ) { + disp_deprecation_message("parse_syntax", "else", p); // TODO +#endif // ENABLE_CASE_CHECK } // Close if script->syntax.curly_count--; @@ -1669,8 +1933,6 @@ const char* parse_syntax_close_sub(const char* p,int* flag) } return p; } else if(script->syntax.curly[pos].type == TYPE_DO) { - int l; - char label[256]; const char *p2; if(script->syntax.curly[pos].flag) { @@ -1683,8 +1945,12 @@ const char* parse_syntax_close_sub(const char* p,int* flag) // Skip to the end point if the condition is false p = script->skip_space(p); p2 = script->skip_word(p); - if(p2 - p != 5 || strncasecmp(p,"while",5)) + if( p2 - p != 5 || strncmp(p, "while", 5) != 0 ) { +#ifdef ENABLE_CASE_CHECK + if( p2 - p == 5 && strncasecmp(p, "while", 5) == 0 ) disp_deprecation_message("parse_syntax", "while", p); // TODO +#endif // ENABLE_CASE_CHECK disp_error_message("parse_syntax: need 'while'",p); + } p = script->skip_space(p2); if(*p != '(') { @@ -1752,10 +2018,7 @@ const char* parse_syntax_close_sub(const char* p,int* flag) script->set_label(l,script->pos,p); script->syntax.curly_count--; return p; - } else if(script->syntax.curly[script->syntax.curly_count-1].type == TYPE_USERFUNC) { - int pos = script->syntax.curly_count-1; - char label[256]; - int l; + } else if(script->syntax.curly[pos].type == TYPE_USERFUNC) { // Back sprintf(label,"return;"); script->syntax.curly[script->syntax.curly_count++].type = TYPE_NULL; @@ -1805,8 +2068,18 @@ void script_set_constant(const char* name, int value, bool isparameter) { void script_set_constant2(const char *name, int value, bool isparameter) { int n = script->add_str(name); - if( ( script->str_data[n].type == C_NAME || script->str_data[n].type == C_PARAM ) && ( script->str_data[n].val != 0 || script->str_data[n].backpatch != -1 ) ) { // existing parameter or constant - ShowNotice("Conflicting item/script var '%s', prioritising the script var\n",name); + if( script->str_data[n].type == C_PARAM ) { + ShowError("script_set_constant2: Attempted to overwrite existing parameter '%s' with a constant (value=%d).\n", name, value); + return; + } + + if( script->str_data[n].type == C_NAME && script->str_data[n].val ) { + ShowWarning("script_set_constant2: Attempted to overwrite existing variable '%s' with a constant (value=%d).\n", name, value); + return; + } + + if( script->str_data[n].type == C_INT && value && value != script->str_data[n].val ) { // existing constant + ShowWarning("script_set_constant2: Attempted to overwrite existing constant '%s' (old value=%d, new value=%d).\n", name, script->str_data[n].val, value); return; } @@ -1820,21 +2093,6 @@ void script_set_constant2(const char *name, int value, bool isparameter) { script->str_data[n].val = value; } -/* same as constant2 except it will override if necessary, used to clear conflicts during reload */ -void script_set_constant_force(const char *name, int value, bool isparameter) { - int n = script->add_str(name); - - if( script->str_data[n].type == C_PARAM ) - return;/* the one type we don't mess with, reload doesn't affect it. */ - - if( script->str_data[n].type != C_NOP ) { - script->str_data[n].type = C_NOP; - script->str_data[n].val = 0; - script->str_data[n].func = NULL; - script->str_data[n].backpatch = -1; - script->str_data[n].label = -1; - } -} /*========================================== * Reading constant databases * const.txt @@ -1846,7 +2104,7 @@ void read_constdb(void) { sprintf(line, "%s/const.txt", map->db_path); fp=fopen(line, "r"); - if(fp==NULL){ + if(fp==NULL) { ShowError("can't read %s\n", line); return ; } @@ -1856,73 +2114,104 @@ void read_constdb(void) { continue; type=0; if(sscanf(line,"%[A-Za-z0-9_],%[-0-9xXA-Fa-f],%d",name,val,&type)>=2 || - sscanf(line,"%[A-Za-z0-9_] %[-0-9xXA-Fa-f] %d",name,val,&type)>=2){ + sscanf(line,"%[A-Za-z0-9_] %[-0-9xXA-Fa-f] %d",name,val,&type)>=2) { script->set_constant(name, (int)strtol(val, NULL, 0), (bool)type); } } fclose(fp); } +// Standard UNIX tab size is 8 +#define TAB_SIZE 8 +#define update_tabstop(tabstop,chars) \ + do { \ + (tabstop) -= (chars); \ + while ((tabstop) <= 0) (tabstop) += TAB_SIZE; \ + } while (false) + /*========================================== * Display emplacement line of script *------------------------------------------*/ const char* script_print_line(StringBuf* buf, const char* p, const char* mark, int line) { - int i; + int i, mark_pos = 0, tabstop = TAB_SIZE; if( p == NULL || !p[0] ) return NULL; if( line < 0 ) - StrBuf->Printf(buf, "*% 5d : ", -line); + StrBuf->Printf(buf, "*%5d: ", -line); // len = 8 else - StrBuf->Printf(buf, " % 5d : ", line); - for(i=0;p[i] && p[i] != '\n';i++){ - if(p + i != mark) - StrBuf->Printf(buf, "%c", p[i]); + StrBuf->Printf(buf, " %5d: ", line); // len = 8 + update_tabstop(tabstop,8); // len = 8 + for( i=0; p[i] && p[i] != '\n'; i++ ) { + char c = p[i]; + int w = 1; + // Like Clang does, let's print the code with tabs expanded to spaces to ensure that the marker will be under the right character + if( c == '\t' ) { + c = ' '; + w = tabstop; + } + update_tabstop(tabstop, w); + if( p + i < mark) + mark_pos += w; + if( p + i != mark) + StrBuf->Printf(buf, "%*c", w, c); else - StrBuf->Printf(buf, "\'%c\'", p[i]); + StrBuf->Printf(buf, CL_BT_RED"%*c"CL_RESET, w, c); } StrBuf->AppendStr(buf, "\n"); + if( mark ) { + StrBuf->AppendStr(buf, " "CL_BT_CYAN); // len = 8 + for( ; mark_pos > 0; mark_pos-- ) { + StrBuf->AppendStr(buf, "~"); + } + StrBuf->AppendStr(buf, CL_RESET CL_BT_GREEN"^"CL_RESET"\n"); + } return p+i+(p[i] == '\n' ? 1 : 0); } +#undef TAB_SIZE +#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) { // Find the line where the error occurred int j; int line = start_line; - const char *p; - const char *linestart[5] = { NULL, NULL, NULL, NULL, NULL }; + const char *p, *error_linepos; + const char *linestart[CONTEXTLINES] = { NULL }; - for(p=src;p && *p;line++){ + for(p=src;p && *p;line++) { const char *lineend=strchr(p,'\n'); - if(lineend==NULL || error_pos<lineend){ + if(lineend==NULL || error_pos<lineend) { break; } - for( j = 0; j < 4; j++ ) { + for( j = 0; j < CONTEXTLINES-1; j++ ) { linestart[j] = linestart[j+1]; } - linestart[4] = p; - p=lineend+1; + linestart[CONTEXTLINES-1] = p; + p = lineend+1; } + error_linepos = p; if( line >= 0 ) - StrBuf->Printf(buf, "script error on %s line %d\n", file, line); + StrBuf->Printf(buf, "script error in file '%s' line %d column %d\n", file, line, error_pos-error_linepos+1); else - StrBuf->Printf(buf, "script error on %s item ID %d\n", file, -line); + StrBuf->Printf(buf, "script error in file '%s' item ID %d\n", file, -line); StrBuf->Printf(buf, " %s\n", error_msg); - for(j = 0; j < 5; j++ ) { - script->print_line(buf, linestart[j], NULL, line + j - 5); + for(j = 0; j < CONTEXTLINES; j++ ) { + script->print_line(buf, linestart[j], NULL, line + j - CONTEXTLINES); } p = script->print_line(buf, p, error_pos, -line); - for(j = 0; j < 5; j++) { + for(j = 0; j < CONTEXTLINES; j++) { p = script->print_line(buf, p, NULL, line + j + 1 ); } } +#undef CONTEXTLINES 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); - StrBuf->AppendStr(&buf, "\a\n"); + StrBuf->AppendStr(&buf, "\a"); script->errorwarning_sub(&buf, src, file, start_line, error_msg, error_pos); @@ -1951,7 +2240,7 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o struct script_code* code = NULL; char end; bool unresolved_names = false; - + script->parser_current_src = src; script->parser_current_file = file; script->parser_current_line = line; @@ -1973,7 +2262,6 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o if( setjmp( script->error_jump ) != 0 ) { //Restore program state when script has problems. [from jA] - int i; const int size = ARRAYLENGTH(script->syntax.curly); if( script->error_report ) script->error(src,file,line,script->error_msg,script->error_pos); @@ -1986,6 +2274,12 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o if(script->str_data[i].type == C_NOP) script->str_data[i].type = C_NAME; for(i=0; i<size; i++) linkdb_final(&script->syntax.curly[i].case_label); +#ifdef ENABLE_CASE_CHECK + script->local_casecheck.clear(); + script->parser_current_src = NULL; + script->parser_current_file = NULL; + script->parser_current_line = 0; +#endif // ENABLE_CASE_CHECK return NULL; } @@ -2000,6 +2294,12 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o script->pos = 0; script->size = 0; script->buf = NULL; +#ifdef ENABLE_CASE_CHECK + script->local_casecheck.clear(); + script->parser_current_src = NULL; + script->parser_current_file = NULL; + script->parser_current_line = 0; +#endif // ENABLE_CASE_CHECK return NULL; } end = '\0'; @@ -2015,17 +2315,23 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o script->pos = 0; script->size = 0; script->buf = NULL; +#ifdef ENABLE_CASE_CHECK + script->local_casecheck.clear(); + script->parser_current_src = NULL; + script->parser_current_file = NULL; + script->parser_current_line = 0; +#endif // ENABLE_CASE_CHECK return NULL; } end = '}'; } // clear references of labels, variables and internal functions - for(i=LABEL_START;i<script->str_num;i++){ + for(i=LABEL_START;i<script->str_num;i++) { if( script->str_data[i].type==C_POS || script->str_data[i].type==C_NAME || script->str_data[i].type==C_USERFUNC || script->str_data[i].type == C_USERFUNC_POS - ){ + ) { script->str_data[i].type=C_NOP; script->str_data[i].backpatch=-1; script->str_data[i].label=-1; @@ -2038,7 +2344,7 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o disp_error_message("unexpected end of script",p); // Special handling only label tmpp=script->skip_space(script->skip_word(p)); - if(*tmpp==':' && !(!strncasecmp(p,"default:",8) && p + 7 == tmpp)){ + if(*tmpp==':' && !(strncmp(p,"default:",8) == 0 && p + 7 == tmpp)) { i=script->add_word(p); script->set_label(i,script->pos,p); if( script->parse_options&SCRIPT_USE_LABEL_DB ) @@ -2062,12 +2368,12 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o RECREATE(script->buf,unsigned char,script->pos); // default unknown references to variables - for(i=LABEL_START;i<script->str_num;i++){ - if(script->str_data[i].type==C_NOP){ + for(i=LABEL_START;i<script->str_num;i++) { + if(script->str_data[i].type==C_NOP) { int j,next; script->str_data[i].type=C_NAME; script->str_data[i].label=i; - for(j=script->str_data[i].backpatch;j>=0 && j!=0x00ffffff;){ + for(j=script->str_data[i].backpatch;j>=0 && j!=0x00ffffff;) { next=GETVALUE(script->buf,j); SETVALUE(script->buf,j,i); j=next; @@ -2086,7 +2392,7 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o } #ifdef SCRIPT_DEBUG_DISP - for(i=0;i<script->pos;i++){ + for(i=0;i<script->pos;i++) { if((i&15)==0) ShowMessage("%04x : ",i); ShowMessage("%02x ",script->buf[i]); if((i&15)==15) ShowMessage("\n"); @@ -2115,7 +2421,7 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o i += 3; break; case C_STR: - j = strlen(script->buf + i); + j = strlen((char*)script->buf + i); ShowMessage(" %s", script->buf + i); i += j+1; break; @@ -2129,6 +2435,12 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o code->script_buf = script->buf; code->script_size = script->size; code->script_vars = NULL; +#ifdef ENABLE_CASE_CHECK + script->local_casecheck.clear(); + script->parser_current_src = NULL; + script->parser_current_file = NULL; + script->parser_current_line = 0; +#endif // ENABLE_CASE_CHECK return code; } @@ -2136,7 +2448,7 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o /// If there is no player attached, the script is terminated. TBL_PC *script_rid2sd(struct script_state *st) { TBL_PC *sd; - if( !( sd = map->id2sd(st->rid) ) ){ + if( !( sd = map->id2sd(st->rid) ) ) { ShowError("script_rid2sd: fatal error ! player not attached!\n"); script->reportfunc(st); script->reportsrc(st); @@ -2145,19 +2457,21 @@ TBL_PC *script_rid2sd(struct script_state *st) { return sd; } -/// Dereferences a variable/constant, replacing it with a copy of the value. -/// -/// @param st Script state -/// @param data Variable/constant -void get_val(struct script_state* st, struct script_data* data) -{ +/** + * Dereferences a variable/constant, replacing it with a copy of the value. + * + * @param st Script state + * @param data Variable/constant + * @return pointer to data, for convenience + */ +struct script_data *get_val(struct script_state* st, struct script_data* data) { const char* name; char prefix; char postfix; TBL_PC* sd = NULL; if( !data_isreference(data) ) - return;// not a variable/constant + return data;// not a variable/constant name = reference_getname(data); prefix = name[0]; @@ -2176,7 +2490,7 @@ void get_val(struct script_state* st, struct script_data* data) data->type = C_INT; data->u.num = 0; } - return; + return data; } } @@ -2191,32 +2505,32 @@ void get_val(struct script_state* st, struct script_data* data) break; case '#': if( name[1] == '#' ) - data->u.str = pc_readaccountreg2str(sd, name);// global + data->u.str = pc_readaccountreg2str(sd, data->u.num);// global else - data->u.str = pc_readaccountregstr(sd, name);// local + data->u.str = pc_readaccountregstr(sd, data->u.num);// local break; case '.': { - struct DBMap* n = - data->ref ? *data->ref: - name[1] == '@' ? st->stack->var_function:// instance/scope variable - st->script->script_vars;// npc variable + struct DBMap* n = data->ref ? + *data->ref : name[1] == '@' ? + st->stack->var_function : // instance/scope variable + st->script->script_vars; // npc variable if( n ) - data->u.str = (char*)idb_get(n,reference_getuid(data)); + data->u.str = (char*)i64db_get(n,reference_getuid(data)); else data->u.str = NULL; } break; case '\'': if ( st->instance_id >= 0 ) { - data->u.str = (char*)idb_get(instance->list[st->instance_id].vars,reference_getuid(data)); + data->u.str = (char*)i64db_get(instance->list[st->instance_id].vars,reference_getuid(data)); } else { ShowWarning("script_get_val: cannot access instance variable '%s', defaulting to \"\"\n", name); data->u.str = NULL; } break; default: - data->u.str = pc_readglobalreg_str(sd, name); + data->u.str = pc_readglobalreg_str(sd, data->u.num); break; } @@ -2246,99 +2560,336 @@ void get_val(struct script_state* st, struct script_data* data) break; case '#': if( name[1] == '#' ) - data->u.num = pc_readaccountreg2(sd, name);// global + data->u.num = pc_readaccountreg2(sd, data->u.num);// global else - data->u.num = pc_readaccountreg(sd, name);// local + data->u.num = pc_readaccountreg(sd, data->u.num);// local break; case '.': { - struct DBMap* n = - data->ref ? *data->ref: - name[1] == '@' ? st->stack->var_function:// instance/scope variable - st->script->script_vars;// npc variable + struct DBMap* n = data->ref ? + *data->ref : name[1] == '@' ? + st->stack->var_function : // instance/scope variable + st->script->script_vars; // npc variable if( n ) - data->u.num = (int)idb_iget(n,reference_getuid(data)); + data->u.num = (int)i64db_iget(n,reference_getuid(data)); else data->u.num = 0; } break; case '\'': if( st->instance_id >= 0 ) - data->u.num = (int)idb_iget(instance->list[st->instance_id].vars,reference_getuid(data)); + data->u.num = (int)i64db_iget(instance->list[st->instance_id].vars,reference_getuid(data)); else { ShowWarning("script_get_val: cannot access instance variable '%s', defaulting to 0\n", name); data->u.num = 0; } break; default: - data->u.num = pc_readglobalreg(sd, name); + data->u.num = pc_readglobalreg(sd, data->u.num); break; } } - return; + return data; } /// Retrieves the value of a reference identified by uid (variable, constant, param) /// The value is left in the top of the stack and needs to be removed manually. -void* get_val2(struct script_state* st, int uid, struct DBMap** ref) { +void* get_val2(struct script_state* st, int64 uid, struct DBMap** ref) { struct script_data* data; script->push_val(st->stack, C_NAME, uid, ref); data = script_getdatatop(st, -1); script->get_val(st, data); - return (data->type == C_INT ? (void*)__64BPTRSIZE(data->u.num) : (void*)__64BPTRSIZE(data->u.str)); + return (data->type == C_INT ? (void*)__64BPTRSIZE((int32)data->u.num) : (void*)__64BPTRSIZE(data->u.str)); // u.num is int32 because it comes from script->get_val } +/** + * 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 DBMap** ref) { + const char *name = script->get_str(script_getvarid(uid)); + struct DBMap *src = script->array_src(st, sd ? sd : st->rid ? map->id2sd(st->rid) : NULL, name, ref); + struct script_array *sa = NULL; + bool insert = false; + + if( sd && !st ) /* when sd comes, st isn't available */ + insert = true; + else { + if( is_string_variable(name) ) { + char* str = (char*)script->get_val2(st, uid, ref); + if( str && *str ) + insert = true; + script_removetop(st, -1, 0); + } else { + int32 num = (int32)__64BPTRSIZE(script->get_val2(st, uid, ref)); + if( num ) + insert = true; + script_removetop(st, -1, 0); + } + } + if( src ) { + if( (sa = idb_get(src, script_getvarid(uid)) ) ) { + unsigned int i; + + ARR_FIND(0, sa->size, i, sa->members[i] == 0); + if( i != sa->size ) { + if( !insert ) + script->array_remove_member(src,sa,i); + return; + } + + script->array_add_member(sa,0); + } else if( insert ) { + script->array_update(&src,reference_uid(script_getvarid(uid), 0),false); + } + } +} +/** + * Returns array size by ID + **/ +unsigned int script_array_size(struct script_state *st, struct map_session_data *sd, const char *name, struct DBMap **ref) { + struct script_array *sa = NULL; + struct DBMap *src = script->array_src(st, sd, name, ref); + + if( src ) + sa = idb_get(src, script->search_str(name)); + + return sa ? sa->size : 0; +} +/** + * 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 DBMap **ref) { + struct script_array *sa = NULL; + struct DBMap *src = script->array_src(st, sd, name, ref); + + + if( src ) { + int key = script->add_word(name); + + script->array_ensure_zero(st,sd,reference_uid(key, 0),ref); + + if( ( sa = idb_get(src, key) ) ) { + unsigned int i, highest_key = 0; + + for(i = 0; i < sa->size; i++) { + if( sa->members[i] > highest_key ) + highest_key = sa->members[i]; + } + + return sa->size ? highest_key + 1 : 0; + } + } + + return 0; +} +int script_free_array_db(DBKey key, DBData *data, va_list ap) { + struct script_array *sa = DB->data2ptr(data); + aFree(sa->members); + ers_free(script->array_ers, sa); + return 0; +} +/** + * Clears script_array and removes it from script->array_db + **/ +void script_array_delete(struct DBMap *src, struct script_array *sa) { + aFree(sa->members); + idb_remove(src, sa->id); + ers_free(script->array_ers, sa); +} +/** + * Removes a member from a script_array list + * + * @param idx the index of the member in script_array struct list, not of the actual array member + **/ +void script_array_remove_member(struct DBMap *src,struct script_array *sa, unsigned int idx) { + unsigned int i, cursor; + + /* its the only member left, no need to do anything other than delete the array data */ + if( sa->size == 1 ) { + script->array_delete(src,sa); + return; + } + + sa->members[idx] = UINT_MAX; + + for(i = 0, cursor = 0; i < sa->size; i++) { + if( sa->members[i] == UINT_MAX ) + continue; + if( i != cursor ) + sa->members[cursor] = sa->members[i]; + cursor++; + } + + sa->size = cursor; +} +/** + * Appends a new array index to the list in script_array + * + * @param idx the index of the array member being inserted + **/ +void script_array_add_member(struct script_array *sa, unsigned int idx) { + + RECREATE(sa->members, unsigned int, ++sa->size); + + sa->members[sa->size - 1] = idx; + +} +/** + * Obtains the source of the array database for this type and scenario + * Initializes such database when not yet initialised. + **/ +struct DBMap *script_array_src(struct script_state *st, struct map_session_data *sd, const char *name, struct DBMap **ref) { + struct DBMap **src = NULL; + + switch( name[0] ) { + /* from player */ + default: /* char reg */ + case '@':/* temp char reg */ + case '#':/* account reg */ + src = &sd->array_db; + break; + case '$':/* map reg */ + src = &mapreg->array_db; + break; + case '.':/* npc/script */ + if( ref ) + src = (struct DBMap **)((char *)ref + sizeof(struct DBMap *)); + else + src = (name[1] == '@') ? &st->stack->array_function_db : &st->script->script_arrays_db; + break; + case '\'':/* instance */ + if( st->instance_id >= 0 ) { + src = &instance->list[st->instance_id].array_db; + } + break; + } + + if( src ) { + if( !*src ) + *src = idb_alloc(DB_OPT_BASE); + return *src; + } + + return NULL; +} +/** + * Processes a array member modification, and update data accordingly + **/ +void script_array_update(struct DBMap **src, int64 num, bool empty) { + struct script_array *sa = NULL; + int id = script_getvarid(num); + unsigned int index = script_getvaridx(num); + + if( !*src ) { + *src = idb_alloc(DB_OPT_BASE); + } else { + sa = idb_get(*src, id); + } + + if( sa ) { + unsigned int i; + + /* search */ + for(i = 0; i < sa->size; i++) { + if( sa->members[i] == index ) + break; + } + + /* if existent */ + if( i != sa->size ) { + /* if empty, we gotta remove it */ + if( empty ) { + script->array_remove_member(*src,sa,i); + } + } else if( !empty ) { /* new entry */ + script->array_add_member(sa,index); + /* we do nothing if its empty, no point in modifying array data for a new empty member */ + } + } else if ( !empty ) {/* we only move to create if not empty */ + sa = ers_alloc(script->array_ers, struct script_array); + sa->id = id; + sa->members = NULL; + sa->size = 0; + script->array_add_member(sa,index); + idb_put(*src, id, sa); + } +} /*========================================== * Stores the value of a script variable * Return value is 0 on fail, 1 on success. + * 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, TBL_PC* sd, int num, const char* name, const void* value, struct DBMap** ref) -{ +int set_reg(struct script_state* st, TBL_PC* sd, int64 num, const char* name, const void* value, struct DBMap** ref) { char prefix = name[0]; + + if( is_string_variable(name) ) {// string variable + const char *str = (const char*)value; - if( is_string_variable(name) ) - {// string variable - const char* str = (const char*)value; switch (prefix) { - case '@': - return pc->setregstr(sd, num, str); - case '$': - return mapreg->setregstr(num, str); - case '#': - return (name[1] == '#') ? - pc_setaccountreg2str(sd, name, str) : - pc_setaccountregstr(sd, name, str); - case '.': - { - struct DBMap* n; - n = (ref) ? *ref : (name[1] == '@') ? st->stack->var_function : st->script->script_vars; - if( n ) { - idb_remove(n, num); - if (str[0]) idb_put(n, num, aStrdup(str)); + case '@': + pc->setregstr(sd, num, str); + return 1; + case '$': + return mapreg->setregstr(num, str); + case '#': + return (name[1] == '#') ? + pc_setaccountreg2str(sd, num, str) : + pc_setaccountregstr(sd, num, str); + case '.': + { + struct DBMap* n; + n = (ref) ? *ref : (name[1] == '@') ? st->stack->var_function : st->script->script_vars; + if( n ) { + if (str[0]) { + i64db_put(n, num, aStrdup(str)); + if( script_getvaridx(num) ) + script->array_update( + (name[1] == '@') ? + &st->stack->array_function_db : + &st->script->script_arrays_db, + num, + false); + } else { + i64db_remove(n, num); + if( script_getvaridx(num) ) + script->array_update( + (name[1] == '@') ? + &st->stack->array_function_db : + &st->script->script_arrays_db, + num, + true); + } + } } - } - return 1; - case '\'': - if( st->instance_id >= 0 ) { - idb_remove(instance->list[st->instance_id].vars, num); - if( str[0] ) idb_put(instance->list[st->instance_id].vars, num, aStrdup(str)); - } - return 1; - default: - return pc_setglobalreg_str(sd, name, str); + return 1; + case '\'': + if( st->instance_id >= 0 ) { + if( str[0] ) { + i64db_put(instance->list[st->instance_id].vars, num, aStrdup(str)); + if( script_getvaridx(num) ) + script->array_update(&instance->list[st->instance_id].array_db,num,false); + } else { + i64db_remove(instance->list[st->instance_id].vars, num); + if( script_getvaridx(num) ) + script->array_update(&instance->list[st->instance_id].array_db,num,true); + } + } else { + ShowError("script_set_reg: cannot write instance variable '%s', NPC not in a instance!\n", name); + script_reportsrc(st); + } + return 1; + default: + return pc_setglobalreg_str(sd, num, str); } - } - else - {// integer variable + } else {// integer variable int val = (int)__64BPTRSIZE(value); - if(script->str_data[num&0x00ffffff].type == C_PARAM) - { - if( pc->setparam(sd, script->str_data[num&0x00ffffff].val, val) == 0 ) - { - if( st != NULL ) - { + + if(script->str_data[script_getvarid(num)].type == C_PARAM) { + if( pc->setparam(sd, script->str_data[script_getvarid(num)].val, val) == 0 ) { + if( st != NULL ) { ShowError("script:set_reg: failed to set param '%s' to %d.\n", name, val); script->reportsrc(st); st->state = END; @@ -2349,41 +2900,66 @@ int set_reg(struct script_state* st, TBL_PC* sd, int num, const char* name, cons } switch (prefix) { - case '@': - return pc->setreg(sd, num, val); - case '$': - return mapreg->setreg(num, val); - case '#': - return (name[1] == '#') ? - pc_setaccountreg2(sd, name, val) : - pc_setaccountreg(sd, name, val); - case '.': - { - struct DBMap* n; - n = (ref) ? *ref : (name[1] == '@') ? st->stack->var_function : st->script->script_vars; - if( n ) { - idb_remove(n, num); - if( val != 0 ) - idb_iput(n, num, val); + case '@': + pc->setreg(sd, num, val); + return 1; + case '$': + return mapreg->setreg(num, val); + case '#': + return (name[1] == '#') ? + pc_setaccountreg2(sd, num, val) : + pc_setaccountreg(sd, num, val); + case '.': + { + struct DBMap* n; + n = (ref) ? *ref : (name[1] == '@') ? st->stack->var_function : st->script->script_vars; + if( n ) { + if( val != 0 ) { + i64db_iput(n, num, val); + if( script_getvaridx(num) ) + script->array_update( + (name[1] == '@') ? + &st->stack->array_function_db : + &st->script->script_arrays_db, + num, + false); + } else { + i64db_remove(n, num); + if( script_getvaridx(num) ) + script->array_update( + (name[1] == '@') ? + &st->stack->array_function_db : + &st->script->script_arrays_db, + num, + true); + } + } } - } - return 1; - case '\'': - if( st->instance_id >= 0 ) { - idb_remove(instance->list[st->instance_id].vars, num); - if( val != 0 ) - idb_iput(instance->list[st->instance_id].vars, num, val); - } - return 1; - default: - return pc_setglobalreg(sd, name, val); + return 1; + case '\'': + if( st->instance_id >= 0 ) { + if( val != 0 ) { + i64db_iput(instance->list[st->instance_id].vars, num, val); + if( script_getvaridx(num) ) + script->array_update(&instance->list[st->instance_id].array_db,num,false); + } else { + i64db_remove(instance->list[st->instance_id].vars, num); + if( script_getvaridx(num) ) + script->array_update(&instance->list[st->instance_id].array_db,num,true); + } + } else { + ShowError("script_set_reg: cannot write instance variable '%s', NPC not in a instance!\n", name); + script_reportsrc(st); + } + return 1; + default: + return pc_setglobalreg(sd, num, val); } } } -int set_var(TBL_PC* sd, char* name, void* val) -{ - return script->set_reg(NULL, sd, reference_uid(script->add_str(name),0), name, val, NULL); +int set_var(TBL_PC* sd, char* name, void* val) { + return script->set_reg(NULL, sd, reference_uid(script->add_str(name),0), name, val, NULL); } void setd_sub(struct script_state *st, TBL_PC *sd, const char *varname, int elem, void *value, struct DBMap **ref) @@ -2403,7 +2979,7 @@ const char* conv_str(struct script_state* st, struct script_data* data) else if( data_isint(data) ) {// int -> string CREATE(p, char, ITEM_NAME_LENGTH); - snprintf(p, ITEM_NAME_LENGTH, "%d", data->u.num); + snprintf(p, ITEM_NAME_LENGTH, "%"PRId64"", data->u.num); p[ITEM_NAME_LENGTH-1] = '\0'; data->type = C_STR; data->u.str = p; @@ -2477,7 +3053,7 @@ int conv_num(struct script_state* st, struct script_data* data) { data->u.num = 0; } #endif - return data->u.num; + return (int)data->u.num; } // @@ -2494,7 +3070,7 @@ 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, int val, struct DBMap** ref) { +struct script_data* push_val(struct script_stack* stack, enum c_op type, int64 val, struct DBMap** ref) { if( stack->sp >= stack->sp_max ) script->stack_expand(stack); stack->stack_data[stack->sp].type = type; @@ -2591,12 +3167,18 @@ void pop_stack(struct script_state* st, int start, int end) stack->stack_data[i].type = C_NOP; } // adjust stack pointers - if( st->start > end ) st->start -= end - start; - else if( st->start > start ) st->start = start; - if( st->end > end ) st->end -= end - start; - else if( st->end > start ) st->end = start; - if( stack->defsp > end ) stack->defsp -= end - start; - else if( stack->defsp > start ) stack->defsp = start; + if( st->start > end ) + st->start -= end - start; + else if( st->start > start ) + st->start = start; + if( st->end > end ) + st->end -= end - start; + else if( st->end > start ) + st->end = start; + if( stack->defsp > end ) + stack->defsp -= end - start; + else if( stack->defsp > start ) + stack->defsp = start; stack->sp -= end - start; } @@ -2617,6 +3199,8 @@ void script_free_vars(struct DBMap* var_storage) { void script_free_code(struct script_code* code) { script->free_vars( code->script_vars ); + if( code->script_arrays_db ) + code->script_arrays_db->destroy(code->script_arrays_db,script->array_free_db); aFree( code->script_buf ); aFree( code ); } @@ -2630,14 +3214,15 @@ void script_free_code(struct script_code* code) /// @return Script state 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); st->stack = ers_alloc(script->stack_ers, struct script_stack); st->stack->sp = 0; st->stack->sp_max = 64; CREATE(st->stack->stack_data, struct script_data, st->stack->sp_max); st->stack->defsp = st->stack->sp; - st->stack->var_function = idb_alloc(DB_OPT_RELEASE_DATA); + st->stack->var_function = i64db_alloc(DB_OPT_RELEASE_DATA); + st->stack->array_function_db = NULL; st->state = RUN; st->script = rootscript; st->pos = pos; @@ -2645,15 +3230,15 @@ struct script_state* script_alloc_state(struct script_code* rootscript, int pos, st->oid = oid; st->sleep.timer = INVALID_TIMER; st->npc_item_flag = battle_config.item_enabled_npc; - + if( !st->script->script_vars ) - st->script->script_vars = idb_alloc(DB_OPT_RELEASE_DATA); - + st->script->script_vars = i64db_alloc(DB_OPT_RELEASE_DATA); + st->id = script->next_id++; script->active_scripts++; idb_put(script->st_db, st->id, st); - + return st; } @@ -2670,14 +3255,22 @@ void script_free_state(struct script_state* st) { timer->delete(st->sleep.timer, script->run_timer); if( st->stack ) { script->free_vars(st->stack->var_function); + if( st->stack->array_function_db ) + st->stack->array_function_db->destroy(st->stack->array_function_db,script->array_free_db); script->pop_stack(st, 0, st->stack->sp); aFree(st->stack->stack_data); ers_free(script->stack_ers, st->stack); st->stack = NULL; } - if( st->script && st->script->script_vars && !db_size(st->script->script_vars) ) { - script->free_vars(st->script->script_vars); - st->script->script_vars = NULL; + if( st->script ) { + if( st->script->script_vars && !db_size(st->script->script_vars) ) { + script->free_vars(st->script->script_vars); + st->script->script_vars = NULL; + } + if( st->script->script_arrays_db && !db_size(st->script->script_arrays_db) ) { + script->free_vars(st->script->script_arrays_db); + st->script->script_arrays_db = NULL; + } } st->pos = -1; idb_remove(script->st_db, st->id); @@ -2698,10 +3291,10 @@ c_op get_com(unsigned char *scriptbuf,int *pos) { int i = 0, j = 0; - if(scriptbuf[*pos]>=0x80){ + if(scriptbuf[*pos]>=0x80) { return C_INT; } - while(scriptbuf[*pos]>=0x40){ + while(scriptbuf[*pos]>=0x40) { i=scriptbuf[(*pos)++]<<j; j+=6; } @@ -2715,27 +3308,13 @@ int get_num(unsigned char *scriptbuf,int *pos) { int i,j; i=0; j=0; - while(scriptbuf[*pos]>=0xc0){ + while(scriptbuf[*pos]>=0xc0) { i+=(scriptbuf[(*pos)++]&0x7f)<<j; j+=6; } return i+((scriptbuf[(*pos)++]&0x7f)<<j); } -/*========================================== - * Remove the value from the stack - *------------------------------------------*/ -int pop_val(struct script_state* st) -{ - if(st->stack->sp<=0) - return 0; - st->stack->sp--; - script->get_val(st,&(st->stack->stack_data[st->stack->sp])); - if(st->stack->stack_data[st->stack->sp].type==C_INT) - return st->stack->stack_data[st->stack->sp].u.num; - return 0; -} - /// Ternary operators /// test ? if_true : if_false void op_3(struct script_state* st, int op) @@ -2749,7 +3328,7 @@ void op_3(struct script_state* st, int op) if( data_isstring(data) ) flag = data->u.str[0];// "" -> false else if( data_isint(data) ) - flag = data->u.num;// 0 -> false + flag = data->u.num == 0 ? 0 : 1;// 0 -> false else { ShowError("script:op_3: invalid data for the ternary operator test\n"); @@ -2778,7 +3357,7 @@ void op_2str(struct script_state* st, int op, const char* s1, const char* s2) { int a = 0; - switch(op){ + switch(op) { case C_EQ: a = (strcmp(s1,s2) == 0); break; case C_NE: a = (strcmp(s1,s2) != 0); break; case C_GT: a = (strcmp(s1,s2) > 0); break; @@ -2811,21 +3390,20 @@ void op_2num(struct script_state* st, int op, int i1, int i2) int ret; double ret_double; - switch( op ) - { - case C_AND: ret = i1 & i2; break; - case C_OR: ret = i1 | i2; break; - case C_XOR: ret = i1 ^ i2; break; - case C_LAND: ret = (i1 && i2); break; - case C_LOR: ret = (i1 || i2); break; - case C_EQ: ret = (i1 == i2); break; - case C_NE: ret = (i1 != i2); break; - case C_GT: ret = (i1 > i2); break; - case C_GE: ret = (i1 >= i2); break; - case C_LT: ret = (i1 < i2); break; - case C_LE: ret = (i1 <= i2); break; - case C_R_SHIFT: ret = i1>>i2; break; - case C_L_SHIFT: ret = i1<<i2; break; + switch( op ) { + case C_AND: ret = i1 & i2; break; + case C_OR: ret = i1 | i2; break; + case C_XOR: ret = i1 ^ i2; break; + case C_LAND: ret = (i1 && i2); break; + case C_LOR: ret = (i1 || i2); break; + case C_EQ: ret = (i1 == i2); break; + case C_NE: ret = (i1 != i2); break; + case C_GT: ret = (i1 > i2); break; + case C_GE: ret = (i1 >= i2); break; + case C_LT: ret = (i1 < i2); break; + case C_LE: ret = (i1 <= i2); break; + case C_R_SHIFT: ret = i1>>i2; break; + case C_L_SHIFT: ret = i1<<i2; break; case C_DIV: case C_MOD: if( i2 == 0 ) @@ -2920,8 +3498,8 @@ void op_2(struct script_state *st, int op) } else if( data_isint(left) && data_isint(right) ) {// ii => op_2num - int i1 = left->u.num; - int i2 = right->u.num; + int i1 = (int)left->u.num; + int i2 = (int)right->u.num; script_removetop(st, leftref.type == C_NOP ? -2 : -1, 0); script->op_2num(st, op, i1, i2); @@ -2963,19 +3541,18 @@ void op_1(struct script_state* st, int op) return; } - i1 = data->u.num; + i1 = (int)data->u.num; script_removetop(st, -1, 0); - switch( op ) - { - case C_NEG: i1 = -i1; break; - case C_NOT: i1 = ~i1; break; - case C_LNOT: i1 = !i1; break; - default: - ShowError("script:op_1: unexpected operator %s i1=%d\n", script->op2name(op), i1); - script->reportsrc(st); - script_pushnil(st); - st->state = END; - return; + switch( op ) { + case C_NEG: i1 = -i1; break; + case C_NOT: i1 = ~i1; break; + case C_LNOT: i1 = !i1; break; + default: + ShowError("script:op_1: unexpected operator %s i1=%d\n", script->op2name(op), i1); + script->reportsrc(st); + script_pushnil(st); + st->state = END; + return; } script_pushint(st, i1); } @@ -2995,7 +3572,7 @@ void script_check_buildin_argtype(struct script_state* st, int func) struct script_data* data = script_getdata(st, idx); type = sf[idx-2]; - + if( type == '?' || type == '*' ) {// optional argument or unknown number of optional parameters ( no types are after this ) break; } else if( type == 0 ) {// more arguments than necessary ( should not happen, as it is checked before ) @@ -3036,7 +3613,7 @@ void script_check_buildin_argtype(struct script_state* st, int func) } break; case 'r': - if( !data_isreference(data) ) + if( !data_isreference(data) || reference_toconstant(data) ) {// variables ShowWarning("Unexpected type for argument %d. Expected variable, got %s.\n", idx-1,script->op2name(data->type)); script->reportdata(data); @@ -3086,7 +3663,7 @@ int run_func(struct script_state *st) data = &st->stack->stack_data[st->start]; if( data->type == C_NAME && script->str_data[data->u.num].type == C_FUNC ) - func = data->u.num; + func = (int)data->u.num; else { ShowError("script:run_func: not a buildin command.\n"); @@ -3100,11 +3677,11 @@ int run_func(struct script_state *st) script->check_buildin_argtype(st, func); } - if(script->str_data[func].func){ + if(script->str_data[func].func) { if (!(script->str_data[func].func(st))) //Report error script->reportsrc(st); } else { - ShowError("script:run_func: '%s' (id=%d type=%s) has no C function. please report this!!!\n", script->get_str(func), func, script->op2name(script->str_data[func].type)); + ShowError("script:run_func: '%s' (id=%"PRId64" type=%s) has no C function. please report this!!!\n", script->get_str(func), func, script->op2name(script->str_data[func].type)); script->reportsrc(st); st->state = END; } @@ -3154,37 +3731,37 @@ void run_script(struct script_code *rootscript,int pos,int rid,int oid) { if( rootscript == NULL || pos < 0 ) return; - + // TODO In jAthena, this function can take over the pending script in the player. [FlavioJS] // It is unclear how that can be triggered, so it needs the be traced/checked in more detail. // NOTE At the time of this change, this function wasn't capable of taking over the script state because st->scriptroot was never set. st = script->alloc_state(rootscript, pos, rid, oid); - + script->run_main(st); } void script_stop_instances(struct script_code *code) { DBIterator *iter; struct script_state* st; - + if( !script->active_scripts ) return;//dont even bother. - + iter = db_iterator(script->st_db); - + for( st = dbi_first(iter); dbi_exists(iter); st = dbi_next(iter) ) { if( st->script == code ) { script->free_state(st); } } - + dbi_destroy(iter); } /*========================================== * Timer function for sleep *------------------------------------------*/ -int run_script_timer(int tid, unsigned int tick, int id, intptr_t data) { +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 ) { TBL_PC *sd = map->id2sd(st->rid); @@ -3217,13 +3794,9 @@ void script_detach_state(struct script_state* st, bool dequeue_event) { st->bk_st = NULL; st->bk_npcid = 0; } else if(dequeue_event) { - /** - * For the Secure NPC Timeout option (check config/Secure.h) [RR] - **/ + // For the Secure NPC Timeout option (check config/Secure.h) [RR] #ifdef SECURE_NPCTIMEOUT - /** - * We're done with this NPC session, so we cancel the timer (if existent) and move on - **/ + // We're done with this NPC session, so we cancel the timer (if existent) and move on if( sd->npc_idle_timer != INVALID_TIMER ) { timer->delete(sd->npc_idle_timer,npc->secure_timeout_timer); sd->npc_idle_timer = INVALID_TIMER; @@ -3296,9 +3869,9 @@ void run_script_main(struct script_state *st) { } else if(st->state != END) st->state = RUN; - while( st->state == RUN ){ + while( st->state == RUN ) { enum c_op c = script->get_com(st->script->script_buf,&st->pos); - switch(c){ + switch(c) { case C_EOL: if( stack->defsp > stack->sp ) ShowError("script:run_script_main: unexpected stack position (defsp=%d sp=%d). please report this!!!\n", stack->defsp, stack->sp); @@ -3322,9 +3895,9 @@ void run_script_main(struct script_state *st) { break; case C_FUNC: script->run_func(st); - if(st->state==GOTO){ + if(st->state==GOTO) { st->state = RUN; - if( !st->freeloop && gotocount>0 && (--gotocount)<=0 ){ + if( !st->freeloop && gotocount>0 && (--gotocount)<=0 ) { ShowError("run_script: infinity loop !\n"); script->reportsrc(st); st->state=END; @@ -3376,8 +3949,8 @@ void run_script_main(struct script_state *st) { st->state=END; break; } - if( !st->freeloop && cmdcount>0 && (--cmdcount)<=0 ){ - ShowError("run_script: infinity loop !\n"); + if( !st->freeloop && cmdcount>0 && (--cmdcount)<=0 ) { + ShowError("run_script: too many opeartions being processed non-stop !\n"); script->reportsrc(st); st->state=END; } @@ -3391,7 +3964,7 @@ void run_script_main(struct script_state *st) { st->sleep.charid = sd?sd->status.char_id:0; st->sleep.timer = timer->add(timer->gettick()+st->sleep.tick, script->run_timer, st->sleep.charid, (intptr_t)st->id); - } else if(st->state != END && st->rid){ + } else if(st->state != END && st->rid) { //Resume later (st is already attached to player). if(st->bk_st) { ShowWarning("Unable to restore stack! Double continuation!\n"); @@ -3407,16 +3980,14 @@ void run_script_main(struct script_state *st) { } else { //Dispose of script. if ((sd = map->id2sd(st->rid))!=NULL) { //Restore previous stack and save char. - if(sd->state.using_fake_npc){ + if(sd->state.using_fake_npc) { clif->clearunit_single(sd->npc_id, CLR_OUTSIGHT, sd->fd); sd->state.using_fake_npc = 0; } //Restore previous script if any. script->detach_state(st, true); - if (sd->state.reg_dirty&2) - intif->saveregistry(sd,2); - if (sd->state.reg_dirty&1) - intif->saveregistry(sd,1); + if (sd->vars_dirty) + intif->saveregistry(sd); } script->free_state(st); st = NULL; @@ -3429,7 +4000,7 @@ int script_config_read(char *cfgName) { FILE *fp; - if( !( fp = fopen(cfgName,"r") ) ){ + if( !( fp = fopen(cfgName,"r") ) ) { ShowError("File not found: %s\n", cfgName); return 1; } @@ -3458,7 +4029,7 @@ int script_config_read(char *cfgName) { else if(strcmpi(w1,"warn_func_mismatch_argtypes")==0) { script->config.warn_func_mismatch_argtypes = config_switch(w2); } - else if(strcmpi(w1,"import")==0){ + else if(strcmpi(w1,"import")==0) { script->config_read(w2); } else { @@ -3503,70 +4074,102 @@ 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) -{ +void script_cleararray_pc(struct map_session_data* sd, const char* varname, void* value) { + struct script_array *sa = NULL; + struct DBMap *src = NULL; + unsigned int i, *list = NULL, size = 0; int key; - uint8 idx; - - if( not_array_variable(varname[0]) || !not_server_variable(varname[0]) ) - { - ShowError("script_cleararray_pc: Variable '%s' has invalid scope (char_id=%d).\n", varname, sd->status.char_id); - return; - } key = script->add_str(varname); - - if( is_string_variable(varname) ) - { - for( idx = 0; idx < SCRIPT_MAX_ARRAYSIZE; idx++ ) - { - pc->setregstr(sd, reference_uid(key, idx), (const char*)value); - } - } - else - { - for( idx = 0; idx < SCRIPT_MAX_ARRAYSIZE; idx++ ) - { - pc->setreg(sd, reference_uid(key, idx), (int)__64BPTRSIZE(value)); - } + + if( !(src = script->array_src(NULL,sd,varname,NULL) ) ) + return; + + if( value ) + script->array_ensure_zero(NULL,sd,reference_uid(key,0),NULL); + + if( !(sa = idb_get(src, key)) ) /* non-existent array, nothing to empty */ + return; + + size = sa->size; + list = script->array_cpy_list(sa); + + for(i = 0; i < size; i++) { + script->set_reg(NULL,sd,reference_uid(key, list[i]),varname,value,NULL); } } /// 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, uint8 idx, void* value, int* refcache) -{ +void script_setarray_pc(struct map_session_data* sd, const char* varname, uint32 idx, void* value, int* refcache) { int key; - - if( not_array_variable(varname[0]) || !not_server_variable(varname[0]) ) - { - ShowError("script_setarray_pc: Variable '%s' has invalid scope (char_id=%d).\n", varname, sd->status.char_id); - return; - } - - if( idx >= SCRIPT_MAX_ARRAYSIZE ) - { - ShowError("script_setarray_pc: Variable '%s' has invalid index '%d' (char_id=%d).\n", varname, (int)idx, sd->status.char_id); + + 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); - - if( is_string_variable(varname) ) - { - pc->setregstr(sd, reference_uid(key, idx), (const char*)value); - } - else - { - pc->setreg(sd, reference_uid(key, idx), (int)__64BPTRSIZE(value)); - } - + + script->set_reg(NULL,sd,reference_uid(key, idx),varname,value,NULL); + if( refcache ) {// save to avoid repeated script->add_str calls refcache[0] = key; } } +/** + * Clears persistent variables from memory + **/ +int script_reg_destroy(DBKey key, DBData *data, va_list ap) { + struct script_reg_state *src; + + if( data->type != DB_DATA_PTR )/* got no need for those! */ + return 0; + + src = DB->data2ptr(data); + + if( src->type ) { + struct script_reg_str *p = (struct script_reg_str *)src; + + if( p->value ) + aFree(p->value); + + ers_free(pc->str_reg_ers,p); + } else { + ers_free(pc->num_reg_ers,(struct script_reg_num*)src); + } + + return 0; +} +/** + * Clears a single persistent variable + **/ +void script_reg_destroy_single(struct map_session_data *sd, int64 reg, struct script_reg_state *data) { + i64db_remove(sd->var_db, reg); + + if( data->type ) { + struct script_reg_str *p = (struct script_reg_str*)data; + + if( p->value ) + aFree(p->value); + + ers_free(pc->str_reg_ers,p); + } else { + ers_free(pc->num_reg_ers,(struct script_reg_num*)data); + } +} +unsigned int *script_array_cpy_list(struct script_array *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) { + script->generic_ui_array_size += plus + 100; + RECREATE(script->generic_ui_array, unsigned int, script->generic_ui_array_size); +} /*========================================== * Destructor *------------------------------------------*/ @@ -3574,7 +4177,7 @@ void do_final_script(void) { int i; DBIterator *iter; struct script_state *st; - + #ifdef SCRIPT_DEBUG_HASH if (battle_config.etc_log) { @@ -3601,19 +4204,19 @@ void do_final_script(void) { for(i=0; i<SCRIPT_HASH_SIZE; i++) { fprintf(fp," hash %3d = %d\n",i,count[i]); if(min > count[i]) - min = count[i]; // minimun count of collision + min = count[i]; // minimun count of collision if(max < count[i]) - max = count[i]; // maximun count of collision + max = count[i]; // maximun count of collision if(count[i] == 0) zero++; ++count2[count[i]]; } fprintf(fp,"\n--------------------\n items : buckets\n--------------------\n"); - for( i=min; i <= max; ++i ){ + for( i=min; i <= max; ++i ) { fprintf(fp," %5d : %7d\n",i,count2[i]); mean += 1.0f*i*count2[i]/SCRIPT_HASH_SIZE; // Note: this will always result in <nr labels>/<nr buckets> } - for( i=min; i <= max; ++i ){ + for( i=min; i <= max; ++i ) { n += count2[i]; if( n*2 >= SCRIPT_HASH_SIZE ) { @@ -3631,18 +4234,18 @@ void do_final_script(void) { #endif iter = db_iterator(script->st_db); - + for( st = dbi_first(iter); dbi_exists(iter); st = dbi_next(iter) ) { script->free_state(st); } - + dbi_destroy(iter); - + mapreg->final(); script->userfunc_db->destroy(script->userfunc_db, script->db_free_code_sub); script->autobonus_db->destroy(script->autobonus_db, script->db_free_code_sub); - + if (script->str_data) aFree(script->str_data); if (script->str_buf) @@ -3654,7 +4257,7 @@ void do_final_script(void) { if( atcommand->binding_count != 0 ) aFree(atcommand->binding); - + for( i = 0; i < script->buildin_count; i++) { if( script->buildin[i] ) { aFree(script->buildin[i]); @@ -3663,7 +4266,7 @@ void do_final_script(void) { } aFree(script->buildin); - + if( script->hqs ) { for( i = 0; i < script->hqs; i++ ) { if( script->hq[i].item != NULL ) @@ -3682,31 +4285,46 @@ void do_final_script(void) { aFree(script->hqi); if( script->word_buf != NULL ) aFree(script->word_buf); - + +#ifdef ENABLE_CASE_CHECK + script->global_casecheck.clear(); + script->local_casecheck.clear(); +#endif // ENABLE_CASE_CHECK + ers_destroy(script->st_ers); ers_destroy(script->stack_ers); - + db_destroy(script->st_db); - + if( script->labels != NULL ) aFree(script->labels); + + ers_destroy(script->array_ers); + + if( script->generic_ui_array ) + aFree(script->generic_ui_array); } /*========================================== * Initialization *------------------------------------------*/ -void do_init_script(void) { +void do_init_script(bool minimal) { script->st_db = idb_alloc(DB_OPT_BASE); script->userfunc_db = strdb_alloc(DB_OPT_DUP_KEY,0); script->autobonus_db = strdb_alloc(DB_OPT_DUP_KEY,0); - script->st_ers = ers_new(sizeof(struct script_state), "script.c::st_ers", ERS_OPT_NONE); - script->stack_ers = ers_new(sizeof(struct script_stack), "script.c::script_stack", ERS_OPT_NONE); + script->st_ers = ers_new(sizeof(struct script_state), "script.c::st_ers", ERS_OPT_CLEAN|ERS_OPT_FLEX_CHUNK); + script->stack_ers = ers_new(sizeof(struct script_stack), "script.c::script_stack", ERS_OPT_NONE|ERS_OPT_FLEX_CHUNK); + script->array_ers = ers_new(sizeof(struct script_array), "script.c::array_ers", ERS_OPT_CLEAN|ERS_OPT_CLEAR); ers_chunk_size(script->st_ers, 10); ers_chunk_size(script->stack_ers, 10); - + script->parse_builtin(); script->read_constdb(); + + if (minimal) + return; + mapreg->init(); } @@ -3715,14 +4333,18 @@ int script_reload(void) { DBIterator *iter; struct script_state *st; +#ifdef ENABLE_CASE_CHECK + script->global_casecheck.clear(); +#endif // ENABLE_CASE_CHECK + iter = db_iterator(script->st_db); - + for( st = dbi_first(iter); dbi_exists(iter); st = dbi_next(iter) ) { script->free_state(st); } - + dbi_destroy(iter); - + script->userfunc_db->clear(script->userfunc_db, script->db_free_code_sub); script->label_count = 0; @@ -3734,23 +4356,31 @@ int script_reload(void) { aFree(atcommand->binding); atcommand->binding_count = 0; - + db_clear(script->st_db); - + mapreg->reload(); - - itemdb->force_name_constants(); - + + itemdb->name_constants(); + return 0; } +/* returns name of current function being run, from within the stack [Ind/Hercules] */ +const char *script_getfuncname(struct script_state *st) { + struct script_data *data; + + data = &st->stack->stack_data[st->start]; + + if( data->type == C_NAME && script->str_data[data->u.num].type == C_FUNC ) + return script->get_str(script_getvarid(data->u.num)); + + return NULL; +} //----------------------------------------------------------------------------- // buildin functions // -#define BUILDIN_DEF(x,args) { buildin_ ## x , #x , args } -#define BUILDIN_DEF2(x,x2,args) { buildin_ ## x , x2 , args } - ///////////////////////////////////////////////////////////////////// // NPC interaction // @@ -3763,18 +4393,18 @@ BUILDIN(mes) { TBL_PC* sd = script->rid2sd(st); if( sd == NULL ) return true; - + if( !script_hasdata(st, 3) ) {// only a single line detected in the script clif->scriptmes(sd, st->oid, script_getstr(st, 2)); } else {// parse multiple lines as they exist int i; - + for( i = 2; script_hasdata(st, i); i++ ) { // send the message to the client clif->scriptmes(sd, st->oid, script_getstr(st, i)); } } - + return true; } @@ -3785,7 +4415,7 @@ BUILDIN(mes) { BUILDIN(next) { TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true; @@ -3803,11 +4433,11 @@ BUILDIN(next) /// close; BUILDIN(close) { TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true; - + st->state = sd->state.dialog == 1 ? CLOSE : END; clif->scriptclose(sd, st->oid); return true; @@ -3819,11 +4449,11 @@ BUILDIN(close) { /// close2; BUILDIN(close2) { TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true; - + if( sd->state.dialog == 1 ) st->state = STOP; else { @@ -3842,11 +4472,11 @@ int menu_countoptions(const char* str, int max_count, int* total) { int count = 0; int bogus_total; - + if( total == NULL ) total = &bogus_total; ++(*total); - + // initial empty options while( *str == ':' ) { @@ -3892,35 +4522,35 @@ BUILDIN(menu) int i; const char* text; TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true; - + #ifdef SECURE_NPCTIMEOUT sd->npc_idle_type = NPCT_MENU; #endif - + // TODO detect multiple scripts waiting for input at the same time, and what to do when that happens if( sd->state.menu_or_input == 0 ) { struct StringBuf buf; struct script_data* data; - + if( script_lastdata(st) % 2 == 0 ) {// argument count is not even (1st argument is at index 2) ShowError("script:menu: illegal number of arguments (%d).\n", (script_lastdata(st) - 1)); st->state = END; return false; } - + StrBuf->Init(&buf); sd->npc_menu = 0; for( i = 2; i < script_lastdata(st); i += 2 ) { // menu options text = script_getstr(st, i); - + // target label data = script_getdata(st, i+1); if( !data_islabel(data) ) @@ -3931,7 +4561,7 @@ BUILDIN(menu) st->state = END; return false; } - + // append option(s) if( text[0] == '\0' ) continue;// empty string, ignore @@ -3942,10 +4572,8 @@ BUILDIN(menu) } st->state = RERUNLINE; sd->state.menu_or_input = 1; - - /** - * menus beyond this length crash the client (see bugreport:6402) - **/ + + /* 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; @@ -3956,9 +4584,9 @@ BUILDIN(menu) aFree(menu); } else clif->scriptmenu(sd, st->oid, StrBuf->Value(&buf)); - + StrBuf->Destroy(&buf); - + if( sd->npc_menu >= 0xff ) {// 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); @@ -3973,7 +4601,7 @@ BUILDIN(menu) else {// goto target label int menu = 0; - + sd->state.menu_or_input = 0; if( sd->npc_menu <= 0 ) { @@ -3981,7 +4609,7 @@ BUILDIN(menu) st->state = END; return false; } - + // get target label for( i = 2; i < script_lastdata(st); i += 2 ) { @@ -4021,36 +4649,34 @@ BUILDIN(select) int i; const char* text; TBL_PC* sd; - + 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) - **/ + + /* 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; @@ -4062,7 +4688,7 @@ BUILDIN(select) } else 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); script->reportsrc(st); @@ -4072,7 +4698,7 @@ BUILDIN(select) 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); @@ -4100,19 +4726,19 @@ BUILDIN(prompt) int i; const char *text; TBL_PC* sd; - + 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 ) @@ -4123,13 +4749,11 @@ BUILDIN(prompt) 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) - **/ + + /* 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; @@ -4141,7 +4765,7 @@ BUILDIN(prompt) } 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); @@ -4158,7 +4782,7 @@ BUILDIN(prompt) else {// return selected option int menu = 0; - + sd->state.menu_or_input = 0; for( i = 2; i <= script_lastdata(st); ++i ) { @@ -4190,7 +4814,7 @@ BUILDIN(goto) st->state = END; return false; } - + st->pos = script_getnum(st,2); st->state = GOTO; return true; @@ -4206,7 +4830,7 @@ BUILDIN(callfunc) struct script_code* scr; const char* str = script_getstr(st,2); DBMap **ref = NULL; - + scr = (struct script_code*)strdb_get(script->userfunc_db, str); if( !scr ) { @@ -4214,7 +4838,7 @@ BUILDIN(callfunc) st->state = END; return false; } - + for( i = st->start+3, j = 0; i < st->end; i++, j++ ) { struct script_data* data = script->push_copy(st->stack,i); @@ -4223,14 +4847,23 @@ BUILDIN(callfunc) const char* name = reference_getname(data); if( name[0] == '.' ) { if( !ref ) { - ref = (struct DBMap**)aCalloc(sizeof(struct DBMap*), 1); + ref = (struct DBMap**)aCalloc(sizeof(struct DBMap*), 2); ref[0] = (name[1] == '@' ? st->stack->var_function : st->script->script_vars); + if( name[1] == '@' ) { + if( !st->stack->array_function_db ) + st->stack->array_function_db = idb_alloc(DB_OPT_BASE); + ref[1] = st->stack->array_function_db; + } else { + if( !st->script->script_arrays_db ) + st->script->script_arrays_db = idb_alloc(DB_OPT_BASE); + ref[1] = st->script->script_arrays_db; + } } data->ref = ref; } } } - + CREATE(ri, struct script_retinfo, 1); ri->script = st->script;// script code ri->var_function = st->stack->var_function;// scope variables @@ -4238,13 +4871,13 @@ BUILDIN(callfunc) ri->nargs = j;// argument count ri->defsp = st->stack->defsp;// default stack pointer script->push_retinfo(st->stack, ri, ref); - + st->pos = 0; st->script = scr; st->stack->defsp = st->stack->sp; st->state = GOTO; - st->stack->var_function = idb_alloc(DB_OPT_RELEASE_DATA); - + st->stack->var_function = i64db_alloc(DB_OPT_RELEASE_DATA); + return true; } /*========================================== @@ -4256,7 +4889,7 @@ BUILDIN(callsub) struct script_retinfo* ri; int pos = script_getnum(st,2); DBMap **ref = NULL; - + if( !data_islabel(script_getdata(st,2)) && !data_isfunclabel(script_getdata(st,2)) ) { ShowError("script:callsub: argument is not a label\n"); @@ -4264,7 +4897,7 @@ BUILDIN(callsub) st->state = END; return false; } - + for( i = st->start+3, j = 0; i < st->end; i++, j++ ) { struct script_data* data = script->push_copy(st->stack,i); @@ -4273,14 +4906,17 @@ BUILDIN(callsub) const char* name = reference_getname(data); if( name[0] == '.' && name[1] == '@' ) { if ( !ref ) { - ref = (struct DBMap**)aCalloc(sizeof(struct DBMap*), 1); + ref = (struct DBMap**)aCalloc(sizeof(struct DBMap*), 2); ref[0] = st->stack->var_function; + if( !st->stack->array_function_db ) + st->stack->array_function_db = idb_alloc(DB_OPT_BASE); + ref[1] = st->stack->array_function_db; } data->ref = ref; } } } - + CREATE(ri, struct script_retinfo, 1); ri->script = st->script;// script code ri->var_function = st->stack->var_function;// scope variables @@ -4288,12 +4924,12 @@ BUILDIN(callsub) ri->nargs = j;// argument count ri->defsp = st->stack->defsp;// default stack pointer script->push_retinfo(st->stack, ri, ref); - + st->pos = pos; st->stack->defsp = st->stack->sp; st->state = GOTO; - st->stack->var_function = idb_alloc(DB_OPT_RELEASE_DATA); - + st->stack->var_function = i64db_alloc(DB_OPT_RELEASE_DATA); + return true; } @@ -4305,7 +4941,7 @@ BUILDIN(getarg) { struct script_retinfo* ri; int idx; - + if( st->stack->defsp < 1 || st->stack->stack_data[st->stack->defsp - 1].type != C_RETINFO ) { ShowError("script:getarg: no callfunc or callsub!\n"); @@ -4313,9 +4949,9 @@ BUILDIN(getarg) return false; } ri = st->stack->stack_data[st->stack->defsp - 1].u.ri; - + idx = script_getnum(st,2); - + if( idx >= 0 && idx < ri->nargs ) script->push_copy(st->stack, st->stack->defsp - 1 - ri->nargs + idx); else if( script_hasdata(st,3) ) @@ -4326,7 +4962,7 @@ BUILDIN(getarg) st->state = END; return false; } - + return true; } @@ -4347,12 +4983,16 @@ BUILDIN(return) const char* name = reference_getname(data); if( name[0] == '.' && name[1] == '@' ) {// scope variable - if( !data->ref || data->ref == (DBMap**)&st->stack->var_function ) + if( !data->ref || data->ref[0] == st->stack->var_function ) script->get_val(st, data);// current scope, convert to value } else if( name[0] == '.' && !data->ref ) {// script variable, link to current script - data->ref = &st->script->script_vars; + data->ref = (struct DBMap**)aCalloc(sizeof(struct DBMap*), 2); + data->ref[0] = st->script->script_vars; + if( !st->script->script_arrays_db ) + st->script->script_arrays_db = idb_alloc(DB_OPT_BASE); + data->ref[1] = st->script->script_arrays_db; } } } @@ -4374,7 +5014,7 @@ BUILDIN(rand) int range; int min; int max; - + if( script_hasdata(st,3) ) {// min,max min = script_getnum(st,2); @@ -4392,7 +5032,7 @@ BUILDIN(rand) script_pushint(st, min); else script_pushint(st, rnd()%range + min); - + return true; } @@ -4405,27 +5045,27 @@ BUILDIN(warp) int x,y; const char* str; TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true; - + str = script_getstr(st,2); x = script_getnum(st,3); y = script_getnum(st,4); - + if(strcmp(str,"Random")==0) ret = pc->randomwarp(sd,CLR_TELEPORT); else if(strcmp(str,"SavePoint")==0 || strcmp(str,"Save")==0) ret = pc->setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT); else - ret = pc->setpos(sd,mapindex_name2id(str),x,y,CLR_OUTSIGHT); - + ret = pc->setpos(sd,mapindex->name2id(str),x,y,CLR_OUTSIGHT); + if( ret ) { ShowError("buildin_warp: moving player '%s' to \"%s\",%d,%d failed.\n", sd->status.name, str, x, y); script->reportsrc(st); } - + return true; } /*========================================== @@ -4435,29 +5075,29 @@ int buildin_areawarp_sub(struct block_list *bl,va_list ap) { int x2,y2,x3,y3; unsigned int index; - + index = va_arg(ap,unsigned int); x2 = va_arg(ap,int); y2 = va_arg(ap,int); x3 = va_arg(ap,int); y3 = va_arg(ap,int); - + if(index == 0) pc->randomwarp((TBL_PC *)bl,CLR_TELEPORT); else if(x3 && y3) { int max, tx, ty, j = 0; - + // choose a suitable max number of attempts if( (max = (y3-y2+1)*(x3-x2+1)*3) > 1000 ) max = 1000; - + // find a suitable map cell do { tx = rnd()%(x3-x2+1)+x2; ty = rnd()%(y3-y2+1)+y2; j++; } while( map->getcell(index,tx,ty,CELL_CHKNOPASS) && j < max ); - + pc->setpos((TBL_PC *)bl,index,tx,ty,CLR_OUTSIGHT); } else @@ -4470,7 +5110,7 @@ BUILDIN(areawarp) unsigned int index; const char *str; const char *mapname; - + mapname = script_getstr(st,2); x0 = script_getnum(st,3); y0 = script_getnum(st,4); @@ -4479,9 +5119,9 @@ BUILDIN(areawarp) str = script_getstr(st,7); x2 = script_getnum(st,8); y2 = script_getnum(st,9); - + if( script_hasdata(st,10) && script_hasdata(st,11) ) { // Warp area to area - if( (x3 = script_getnum(st,10)) < 0 || (y3 = script_getnum(st,11)) < 0 ){ + if( (x3 = script_getnum(st,10)) < 0 || (y3 = script_getnum(st,11)) < 0 ) { x3 = 0; y3 = 0; } else if( x3 && y3 ) { @@ -4490,15 +5130,15 @@ BUILDIN(areawarp) if( y3 < y2 ) swap(y3,y2); } } - + if( (m = map->mapname2mapid(mapname)) < 0 ) return true; - + if( strcmp(str,"Random") == 0 ) index = 0; - else if( !(index=mapindex_name2id(str)) ) + else if( !(index=mapindex->name2id(str)) ) return true; - + map->foreachinarea(script->buildin_areawarp_sub, m,x0,y0,x1,y1, BL_PC, index,x2,y2,x3,y3); return true; } @@ -4518,7 +5158,7 @@ BUILDIN(areapercentheal) { int hp,sp,m; const char *mapname; int x0,y0,x1,y1; - + mapname=script_getstr(st,2); x0=script_getnum(st,3); y0=script_getnum(st,4); @@ -4526,10 +5166,10 @@ BUILDIN(areapercentheal) { y1=script_getnum(st,6); hp=script_getnum(st,7); sp=script_getnum(st,8); - + if( (m=map->mapname2mapid(mapname))< 0) return true; - + map->foreachinarea(script->buildin_areapercentheal_sub,m,x0,y0,x1,y1,BL_PC,hp,sp); return true; } @@ -4544,24 +5184,24 @@ BUILDIN(warpchar) { int x,y,a; const char *str; TBL_PC *sd; - + str=script_getstr(st,2); x=script_getnum(st,3); y=script_getnum(st,4); a=script_getnum(st,5); - + sd = map->charid2sd(a); if( sd == NULL ) return true; - + if(strcmp(str, "Random") == 0) pc->randomwarp(sd, CLR_TELEPORT); else if(strcmp(str, "SavePoint") == 0) pc->setpos(sd, sd->status.save_point.map,sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT); else - pc->setpos(sd, mapindex_name2id(str), x, y, CLR_TELEPORT); - + pc->setpos(sd, mapindex->name2id(str), x, y, CLR_TELEPORT); + return true; } /*========================================== @@ -4575,9 +5215,9 @@ BUILDIN(warpparty) TBL_PC *pl_sd; struct party_data* p; int type; - int mapindex; + int map_index; int i; - + const char* str = script_getstr(st,2); int x = script_getnum(st,3); int y = script_getnum(st,4); @@ -4585,17 +5225,17 @@ BUILDIN(warpparty) const char* str2 = NULL; if ( script_hasdata(st,6) ) str2 = script_getstr(st,6); - + p = party->search(p_id); if(!p) return true; - + 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: @@ -4603,32 +5243,32 @@ BUILDIN(warpparty) if (i == MAX_PARTY || !p->data[i].sd) //Leader not found / not online return true; pl_sd = p->data[i].sd; - mapindex = pl_sd->mapindex; + map_index = pl_sd->mapindex; x = pl_sd->bl.x; y = pl_sd->bl.y; break; case 4: - mapindex = mapindex_name2id(str); + map_index = mapindex->name2id(str); break; case 2: //"SavePoint" uses save point of the currently attached player if (( sd = script->rid2sd(st) ) == NULL ) return true; default: - mapindex = 0; + 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 ) continue; - + if( str2 && strcmp(str2, map->list[pl_sd->bl.m].name) != 0 ) continue; - + if( pc_isdead(pl_sd) ) continue; - + switch( type ) { case 0: // Random @@ -4646,11 +5286,11 @@ BUILDIN(warpparty) 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,mapindex,x,y,CLR_TELEPORT); + pc->setpos(pl_sd,map_index,x,y,CLR_TELEPORT); break; } } - + return true; } /*========================================== @@ -4664,32 +5304,32 @@ BUILDIN(warpguild) struct guild* g; struct s_mapiterator* iter; int type; - + const char* str = script_getstr(st,2); int x = script_getnum(st,3); int y = script_getnum(st,4); int gid = script_getnum(st,5); - + g = guild->search(gid); if( g == NULL ) return true; - + type = ( strcmp(str,"Random")==0 ) ? 0 : ( strcmp(str,"SavePointAll")==0 ) ? 1 : ( strcmp(str,"SavePoint")==0 ) ? 2 : 3; - + if( type == 2 && ( sd = script->rid2sd(st) ) == NULL ) {// "SavePoint" uses save point of the currently attached player return true; } - + iter = mapit_getallusers(); for( pl_sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); pl_sd = (TBL_PC*)mapit->next(iter) ) { if( pl_sd->status.guild_id != gid ) continue; - + switch( type ) { case 0: // Random @@ -4706,12 +5346,12 @@ BUILDIN(warpguild) break; case 3: // m,x,y if(!map->list[pl_sd->bl.m].flag.noreturn && !map->list[pl_sd->bl.m].flag.nowarp) - pc->setpos(pl_sd,mapindex_name2id(str),x,y,CLR_TELEPORT); + pc->setpos(pl_sd,mapindex->name2id(str),x,y,CLR_TELEPORT); break; } } mapit->free(iter); - + return true; } /*========================================== @@ -4720,10 +5360,10 @@ BUILDIN(warpguild) BUILDIN(heal) { TBL_PC *sd; int hp,sp; - + sd = script->rid2sd(st); if (!sd) return true; - + hp=script_getnum(st,2); sp=script_getnum(st,3); status->heal(&sd->bl, hp, sp, 1); @@ -4736,16 +5376,16 @@ BUILDIN(itemheal) { TBL_PC *sd; int hp,sp; - + hp=script_getnum(st,2); sp=script_getnum(st,3); - + if(script->potion_flag==1) { script->potion_hp = hp; script->potion_sp = sp; return true; } - + sd = script->rid2sd(st); if (!sd) return true; pc->itemheal(sd,sd->itemid,hp,sp); @@ -4758,16 +5398,16 @@ BUILDIN(percentheal) { int hp,sp; TBL_PC* sd; - + hp=script_getnum(st,2); sp=script_getnum(st,3); - + if(script->potion_flag==1) { script->potion_per_hp = hp; script->potion_per_sp = sp; return true; } - + sd = script->rid2sd(st); if( sd == NULL ) return true; @@ -4785,22 +5425,22 @@ BUILDIN(percentheal) BUILDIN(jobchange) { int job, upper=-1; - + job=script_getnum(st,2); if( script_hasdata(st,3) ) upper=script_getnum(st,3); - + if (pcdb_checkid(job)) { TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true; - + pc->jobchange(sd, job, upper); } - + return true; } @@ -4825,17 +5465,17 @@ BUILDIN(input) { TBL_PC* sd; struct script_data* data; - int uid; + int64 uid; const char* name; int min; int max; - + sd = script->rid2sd(st); if( sd == NULL ) return true; - + data = script_getdata(st,2); - if( !data_isreference(data) ){ + if( !data_isreference(data) ) { ShowError("script:input: not a variable\n"); script->reportdata(data); st->state = END; @@ -4845,22 +5485,21 @@ BUILDIN(input) name = reference_getname(data); min = (script_hasdata(st,3) ? script_getnum(st,3) : script->config.input_min_value); max = (script_hasdata(st,4) ? script_getnum(st,4) : script->config.input_max_value); - + #ifdef SECURE_NPCTIMEOUT sd->npc_idle_type = NPCT_WAIT; #endif - - if( !sd->state.menu_or_input ) - { // first invocation, display npc input box + + if( !sd->state.menu_or_input ) { + // first invocation, display npc input box sd->state.menu_or_input = 1; st->state = RERUNLINE; if( is_string_variable(name) ) clif->scriptinputstr(sd,st->oid); else clif->scriptinput(sd,st->oid); - } - else - { // take received text/value and store it in the designated variable + } else { + // take received text/value and store it in the designated variable sd->state.menu_or_input = 0; if( is_string_variable(name) ) { @@ -4886,75 +5525,81 @@ BUILDIN(copyarray); /// The value is converted to the type of the variable. /// /// set(<variable>,<value>) -> <variable> -BUILDIN(set) -{ +BUILDIN(setr) { TBL_PC* sd = NULL; struct script_data* data; //struct script_data* datavalue; - int num; + int64 num; const char* name; char prefix; - + data = script_getdata(st,2); //datavalue = script_getdata(st,3); - if( !data_isreference(data) ) - { + if( !data_isreference(data) || reference_toconstant(data) ) { ShowError("script:set: not a variable\n"); script->reportdata(script_getdata(st,2)); st->state = END; return false; } - + num = reference_getuid(data); name = reference_getname(data); prefix = *name; - - if( not_server_variable(prefix) ) - { + + if( not_server_variable(prefix) ) { sd = script->rid2sd(st); - if( sd == NULL ) - { + if( sd == NULL ) { ShowError("script:set: no player attached for player variable '%s'\n", name); return true; } } - + #if 0 - if( data_isreference(datavalue) ) - {// the value being referenced is a variable + // TODO: see de43fa0f73be01080bd11c08adbfb7c158324c81 + if( data_isreference(datavalue) ) { + // the value being referenced is a variable const char* namevalue = reference_getname(datavalue); - - if( !not_array_variable(*namevalue) ) - {// array variable being copied into another array variable - if( sd == NULL && not_server_variable(*namevalue) && !(sd = script->rid2sd(st)) ) - {// player must be attached in order to copy a player variable + + if( !not_array_variable(*namevalue) ) { + // array variable being copied into another array variable + if( sd == NULL && not_server_variable(*namevalue) && !(sd = script->rid2sd(st)) ) { + // player must be attached in order to copy a player variable ShowError("script:set: no player attached for player variable '%s'\n", namevalue); return true; } - - if( is_string_variable(namevalue) != is_string_variable(name) ) - {// non-matching array value types + + if( is_string_variable(namevalue) != is_string_variable(name) ) { + // non-matching array value types ShowWarning("script:set: two array variables do not match in type.\n"); return true; } - + // push the maximum number of array values to the stack script->push_val(st->stack, C_INT, SCRIPT_MAX_ARRAYSIZE,NULL); - + // call the copy array method directly return buildin_copyarray(st); } } #endif - + + if( script_hasdata(st, 4) ) { + // Optional argument used by post-increment/post-decrement constructs to return the previous value + if( is_string_variable(name) ) { + script_pushstrcopy(st, script_getstr(st, 4)); + } else { + script_pushint(st, script_getnum(st, 4)); + } + } else { + // return a copy of the variable reference + script_pushcopy(st,2); + } + if( is_string_variable(name) ) script->set_reg(st,sd,num,name,(void*)script_getstr(st,3),script_getref(st,2)); else script->set_reg(st,sd,num,name,(void*)__64BPTRSIZE(script_getnum(st,3)),script_getref(st,2)); - - // return a copy of the variable reference - script_pushcopy(st,2); - + return true; } @@ -4962,34 +5607,6 @@ BUILDIN(set) /// Array variables /// -/// Returns the size of the specified array -int32 getarraysize(struct script_state* st, int32 id, int32 idx, int isstring, struct DBMap** ref) -{ - int32 ret = idx; - - if( isstring ) - { - for( ; idx < SCRIPT_MAX_ARRAYSIZE; ++idx ) - { - char* str = (char*)script->get_val2(st, reference_uid(id, idx), ref); - if( str && *str ) - ret = idx + 1; - script_removetop(st, -1, 0); - } - } - else - { - for( ; idx < SCRIPT_MAX_ARRAYSIZE; ++idx ) - { - int32 num = (int32)__64BPTRSIZE(script->get_val2(st, reference_uid(id, idx), ref)); - if( num ) - ret = idx + 1; - script_removetop(st, -1, 0); - } - } - return ret; -} - /// Sets values of an array, from the starting index. /// ex: setarray arr[1],1,2,3; /// @@ -4998,43 +5615,36 @@ BUILDIN(setarray) { struct script_data* data; const char* name; - int32 start; - int32 end; + uint32 start; + uint32 end; int32 id; int32 i; TBL_PC* sd = NULL; - + data = script_getdata(st, 2); - if( !data_isreference(data) ) + if( !data_isreference(data) || reference_toconstant(data) ) { ShowError("script:setarray: not a variable\n"); script->reportdata(data); st->state = END; return false;// not a variable } - + id = reference_getid(data); start = reference_getindex(data); name = reference_getname(data); - if( not_array_variable(*name) ) - { - ShowError("script:setarray: illegal scope\n"); - script->reportdata(data); - st->state = END; - return false;// not supported - } - + if( not_server_variable(*name) ) { sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached } - + end = start + script_lastdata(st) - 2; if( end > SCRIPT_MAX_ARRAYSIZE ) end = SCRIPT_MAX_ARRAYSIZE; - + if( is_string_variable(name) ) {// string array for( i = 3; start < end; ++start, ++i ) @@ -5056,12 +5666,12 @@ BUILDIN(cleararray) { struct script_data* data; const char* name; - int32 start; - int32 end; + uint32 start; + uint32 end; int32 id; void* v; TBL_PC* sd = NULL; - + data = script_getdata(st, 2); if( !data_isreference(data) ) { @@ -5070,34 +5680,27 @@ BUILDIN(cleararray) st->state = END; return false;// not a variable } - + id = reference_getid(data); start = reference_getindex(data); name = reference_getname(data); - if( not_array_variable(*name) ) - { - ShowError("script:cleararray: illegal scope\n"); - script->reportdata(data); - st->state = END; - return false;// not supported - } - + if( not_server_variable(*name) ) { sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached } - + if( is_string_variable(name) ) v = (void*)script_getstr(st, 3); else v = (void*)__64BPTRSIZE(script_getnum(st, 3)); - + end = start + script_getnum(st, 4); if( end > SCRIPT_MAX_ARRAYSIZE ) end = SCRIPT_MAX_ARRAYSIZE; - + for( ; start < end; ++start ) script->set_reg(st, sd, reference_uid(id, start), name, v, script_getref(st,2)); return true; @@ -5119,9 +5722,9 @@ BUILDIN(copyarray) int32 id2; void* v; int32 i; - int32 count; + uint32 count; TBL_PC* sd = NULL; - + data1 = script_getdata(st, 2); data2 = script_getdata(st, 3); if( !data_isreference(data1) || !data_isreference(data2) ) @@ -5132,22 +5735,14 @@ BUILDIN(copyarray) st->state = END; return false;// not a variable } - + id1 = reference_getid(data1); id2 = reference_getid(data2); idx1 = reference_getindex(data1); idx2 = reference_getindex(data2); name1 = reference_getname(data1); name2 = reference_getname(data2); - if( not_array_variable(*name1) || not_array_variable(*name2) ) - { - ShowError("script:copyarray: illegal scope\n"); - script->reportdata(data1); - script->reportdata(data2); - st->state = END; - return false;// not supported - } - + if( is_string_variable(name1) != is_string_variable(name2) ) { ShowError("script:copyarray: type mismatch\n"); @@ -5156,20 +5751,20 @@ BUILDIN(copyarray) st->state = END; return false;// data type mismatch } - + if( not_server_variable(*name1) || not_server_variable(*name2) ) { sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached } - + count = script_getnum(st, 4); if( count > SCRIPT_MAX_ARRAYSIZE - idx1 ) count = SCRIPT_MAX_ARRAYSIZE - idx1; if( count <= 0 || (id1 == id2 && idx1 == idx2) ) return true;// nothing to copy - + if( id1 == id2 && idx1 > idx2 ) {// destination might be overlapping the source - copy in reverse order for( i = count - 1; i >= 0; --i ) @@ -5204,8 +5799,7 @@ BUILDIN(copyarray) BUILDIN(getarraysize) { struct script_data* data; - const char* name; - + data = script_getdata(st, 2); if( !data_isreference(data) ) { @@ -5215,20 +5809,13 @@ BUILDIN(getarraysize) st->state = END; return false;// not a variable } - - name = reference_getname(data); - if( not_array_variable(*name) ) - { - ShowError("script:getarraysize: illegal scope\n"); - script->reportdata(data); - script_pushnil(st); - st->state = END; - return false;// not supported - } - - script_pushint(st, script->getarraysize(st, reference_getid(data), reference_getindex(data), is_string_variable(name), reference_getref(data))); + + 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) { + return ( *(unsigned int*)a - *(unsigned int*)b ); +} /// Deletes count or all the elements in an array, from the starting index. /// ex: deletearray arr[4],2; @@ -5239,11 +5826,13 @@ BUILDIN(deletearray) { struct script_data* data; const char* name; - int start; - int end; + unsigned int start, end, i; int id; TBL_PC *sd = NULL; - + struct script_array *sa = NULL; + struct DBMap *src = NULL; + void *value; + data = script_getdata(st, 2); if( !data_isreference(data) ) { @@ -5252,58 +5841,94 @@ BUILDIN(deletearray) st->state = END; return false;// not a variable } - + id = reference_getid(data); start = reference_getindex(data); name = reference_getname(data); - if( not_array_variable(*name) ) - { - ShowError("script:deletearray: illegal scope\n"); - script->reportdata(data); - st->state = END; - return false;// not supported - } - + if( not_server_variable(*name) ) { sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached } + + if( !(src = script->array_src(st,sd,name, reference_getref(data)) ) ) { + ShowError("script:deletearray: not a array\n"); + script->reportdata(data); + st->state = END; + return false;// not a variable + } + + script->array_ensure_zero(st,NULL,data->u.num,reference_getref(data)); - end = SCRIPT_MAX_ARRAYSIZE; + if ( !(sa = idb_get(src, id)) ) { /* non-existent array, nothing to empty */ + return true;// not a variable + } + + end = script->array_highest_key(st,sd,name,reference_getref(data)); if( start >= end ) return true;// nothing to free + + if( is_string_variable(name) ) + value = (void *)""; + else + value = (void *)0; - if( script_hasdata(st,3) ) - { - int count = script_getnum(st, 3); + if( script_hasdata(st,3) ) { + unsigned int count = script_getnum(st, 3); if( count > end - start ) count = end - start; if( count <= 0 ) return true;// nothing to free + + if( end - start < sa->size ) { + // Better to iterate directly on the array, no speed-up from using sa + for( ; start + count < end; ++start ) { + // Compact and overwrite + void* v = script->get_val2(st, reference_uid(id, start + count), reference_getref(data)); + script->set_reg(st, sd, reference_uid(id, start), name, v, reference_getref(data)); + script_removetop(st, -1, 0); + } + for( ; start < end; start++ ) { + // Clean up any leftovers that weren't overwritten + script->set_reg(st, sd, reference_uid(id, start), name, value, reference_getref(data)); + } + } else { + // using sa to speed up + unsigned int *list = NULL, size = 0; + list = script->array_cpy_list(sa); + size = sa->size; + qsort(list, size, sizeof(unsigned int), script_array_index_cmp); + + ARR_FIND(0, size, i, list[i] >= start); + + for( ; i < size && list[i] < start + count; i++ ) { + // Clear any entries between start and start+count, if they exist + script->set_reg(st, sd, reference_uid(id, list[i]), name, value, reference_getref(data)); + } + + for( ; i < size && list[i] < end; i++ ) { + // Move back count positions any entries between start+count to fill the gaps + void* v = script->get_val2(st, reference_uid(id, list[i]), reference_getref(data)); + script->set_reg(st, sd, reference_uid(id, list[i]-count), name, v, reference_getref(data)); + script_removetop(st, -1, 0); + // Clear their originals + script->set_reg(st, sd, reference_uid(id, list[i]), name, value, reference_getref(data)); + } + } + } else { + unsigned int *list = NULL, size = 0; + list = script->array_cpy_list(sa); + size = sa->size; - // move rest of the elements backward - for( ; start + count < end; ++start ) - { - void* v = script->get_val2(st, reference_uid(id, start + count), reference_getref(data)); - script->set_reg(st, sd, reference_uid(id, start), name, v, reference_getref(data)); - script_removetop(st, -1, 0); + for(i = 0; i < size; i++) { + if( list[i] >= start ) // Less expensive than sorting it, most likely + script->set_reg(st, sd, reference_uid(id, list[i]), name, value, reference_getref(data)); } } - - // clear the rest of the array - if( is_string_variable(name) ) - { - for( ; start < end; ++start ) - script->set_reg(st, sd, reference_uid(id, start), name, (void *)"", reference_getref(data)); - } - else - { - for( ; start < end; ++start ) - script->set_reg(st, sd, reference_uid(id, start), name, (void*)0, reference_getref(data)); - } + return true; } @@ -5314,10 +5939,9 @@ BUILDIN(deletearray) BUILDIN(getelementofarray) { struct script_data* data; - const char* name; int32 id; - int i; - + int64 i; + data = script_getdata(st, 2); if( !data_isreference(data) ) { @@ -5327,29 +5951,20 @@ BUILDIN(getelementofarray) st->state = END; return false;// not a variable } - + id = reference_getid(data); - name = reference_getname(data); - if( not_array_variable(*name) ) - { - ShowError("script:getelementofarray: illegal scope\n"); - script->reportdata(data); - script_pushnil(st); - st->state = END; - return false;// not supported - } - + i = script_getnum(st, 3); if( i < 0 || i >= SCRIPT_MAX_ARRAYSIZE ) { - ShowWarning("script:getelementofarray: index out of range (%d)\n", i); + ShowWarning("script:getelementofarray: index out of range (%lld)\n", i); script->reportdata(data); script_pushnil(st); st->state = END; return false;// out of range } - - script->push_val(st->stack, C_NAME, reference_uid(id, i), reference_getref(data)); + + script->push_val(st->stack, C_NAME, reference_uid(id, (unsigned int)i), reference_getref(data)); return true; } @@ -5364,16 +5979,16 @@ BUILDIN(setlook) { int type,val; TBL_PC* sd; - + type=script_getnum(st,2); val=script_getnum(st,3); - + sd = script->rid2sd(st); if( sd == NULL ) return true; - + pc->changelook(sd,type,val); - + return true; } @@ -5381,16 +5996,16 @@ BUILDIN(changelook) { // As setlook but only client side int type,val; TBL_PC* sd; - + type=script_getnum(st,2); val=script_getnum(st,3); - + sd = script->rid2sd(st); if( sd == NULL ) return true; - + clif->changelook(&sd->bl,type,val); - + return true; } @@ -5400,11 +6015,11 @@ BUILDIN(changelook) BUILDIN(cutin) { TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true; - + clif->cutin(sd,script_getstr(st,2),script_getnum(st,3)); return true; } @@ -5416,104 +6031,90 @@ BUILDIN(viewpoint) { int type,x,y,id,color; TBL_PC* sd; - + type=script_getnum(st,2); x=script_getnum(st,3); y=script_getnum(st,4); id=script_getnum(st,5); color=script_getnum(st,6); - + sd = script->rid2sd(st); if( sd == NULL ) return true; - + clif->viewpoint(sd,st->oid,type,x,y,id,color); - + return true; } /*========================================== * *------------------------------------------*/ -BUILDIN(countitem) -{ +BUILDIN(countitem) { int nameid, i; int count = 0; struct item_data* id = NULL; - struct script_data* data; - + TBL_PC* sd = script->rid2sd(st); if (!sd) { script_pushint(st,0); return true; } - - data = script_getdata(st,2); - script->get_val(st, data); // convert into value in case of a variable - - if( data_isstring(data) ) - {// item name - id = itemdb->search_name(script->conv_str(st, data)); - } - else - {// item id - id = itemdb->exists(script->conv_num(st, data)); + + if( script_isstringtype(st, 2) ) { + // item name + id = itemdb->search_name(script_getstr(st, 2)); + } else { + // item id + id = itemdb->exists(script_getnum(st, 2)); } - - if( id == NULL ) - { + + if( id == NULL ) { ShowError("buildin_countitem: Invalid item '%s'.\n", script_getstr(st,2)); // returns string, regardless of what it was script_pushint(st,0); return false; } - + nameid = id->nameid; - + for(i = 0; i < MAX_INVENTORY; i++) if(sd->status.inventory[i].nameid == nameid) count += sd->status.inventory[i].amount; - + script_pushint(st,count); return true; } /*========================================== - * countitem2(nameID,Identified,Refine,Attribute,Card0,Card1,Card2,Card3) [Lupus] - * returns number of items that meet the conditions + * countitem2(nameID,Identified,Refine,Attribute,Card0,Card1,Card2,Card3) [Lupus] + * returns number of items that meet the conditions *------------------------------------------*/ -BUILDIN(countitem2) -{ +BUILDIN(countitem2) { int nameid, iden, ref, attr, c1, c2, c3, c4; int count = 0; int i; struct item_data* id = NULL; - struct script_data* data; - + TBL_PC* sd = script->rid2sd(st); if (!sd) { script_pushint(st,0); return true; } - - data = script_getdata(st,2); - script->get_val(st, data); // convert into value in case of a variable - - if( data_isstring(data) ) - {// item name - id = itemdb->search_name(script->conv_str(st, data)); - } - else - {// item id - id = itemdb->exists(script->conv_num(st, data)); + + if( script_isstringtype(st, 2) ) { + // item name + id = itemdb->search_name(script_getstr(st, 2)); + } else { + // item id + id = itemdb->exists(script_getnum(st, 2)); } - - if( id == NULL ) - { + + if( id == NULL ) { ShowError("buildin_countitem2: Invalid item '%s'.\n", script_getstr(st,2)); // returns string, regardless of what it was script_pushint(st,0); return false; } - + nameid = id->nameid; iden = script_getnum(st,3); ref = script_getnum(st,4); @@ -5522,7 +6123,7 @@ BUILDIN(countitem2) c2 = (short)script_getnum(st,7); c3 = (short)script_getnum(st,8); c4 = (short)script_getnum(st,9); - + for(i = 0; i < MAX_INVENTORY; 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 && @@ -5532,7 +6133,7 @@ BUILDIN(countitem2) sd->status.inventory[i].card[3] == c4 ) count += sd->status.inventory[i].amount; - + script_pushint(st,count); return true; } @@ -5541,8 +6142,8 @@ BUILDIN(countitem2) * Check if item with this amount can fit in inventory * Checking : weight, stack amount >32k, slots amount >(MAX_INVENTORY) * Return - * 0 : fail - * 1 : success (npc side only) + * 0 : fail + * 1 : success (npc side only) *------------------------------------------*/ BUILDIN(checkweight) { @@ -5550,73 +6151,76 @@ BUILDIN(checkweight) unsigned int weight=0, i, nbargs; struct item_data* id = NULL; struct map_session_data* sd; - struct script_data* data; - - if( ( sd = script->rid2sd(st) ) == NULL ){ + + if( ( sd = script->rid2sd(st) ) == NULL ) { return true; } nbargs = script_lastdata(st)+1; - if(nbargs%2){ - ShowError("buildin_checkweight: Invalid nb of args should be a multiple of 2.\n"); - script_pushint(st,0); - return false; + if(nbargs%2) { + ShowError("buildin_checkweight: Invalid nb of args should be a multiple of 2.\n"); + script_pushint(st,0); + return false; } slots = pc->inventoryblank(sd); //nb of empty slot - - for(i=2; i<nbargs; i=i+2){ - data = script_getdata(st,i); - script->get_val(st, data); // convert into value in case of a variable - if( data_isstring(data) ){// item name - id = itemdb->search_name(script->conv_str(st, data)); - } else {// item id - id = itemdb->exists(script->conv_num(st, data)); - } - if( id == NULL ) { - ShowError("buildin_checkweight: Invalid item '%s'.\n", script_getstr(st,i)); // returns string, regardless of what it was - script_pushint(st,0); - return false; - } - nameid = id->nameid; - - amount = script_getnum(st,i+1); - if( amount < 1 ) { - ShowError("buildin_checkweight: Invalid amount '%d'.\n", amount); - script_pushint(st,0); - return false; - } - - weight += itemdb_weight(nameid)*amount; //total weight for all chk - if( weight + sd->weight > sd->max_weight ) - {// too heavy - script_pushint(st,0); - return true; - } - - switch( pc->checkadditem(sd, nameid, amount) ) - { - case ADDITEM_EXIST: - // item is already in inventory, but there is still space for the requested amount - break; - case ADDITEM_NEW: - if( itemdb->isstackable(nameid) ) {// stackable - amount2++; - if( slots < amount2 ) { - script_pushint(st,0); - return true; - } - } - else {// non-stackable - amount2 += amount; - if( slots < amount2){ - script_pushint(st,0); - return true; - } - } - break; - case ADDITEM_OVERAMOUNT: - script_pushint(st,0); - return true; - } + + for( i = 2; i < nbargs; i += 2 ) { + if( script_isstringtype(st, i) ) { + // item name + id = itemdb->search_name(script_getstr(st, i)); + } else if ( script_isinttype(st, i) ) { + // item id + id = itemdb->exists(script_getnum(st, i)); + } else { + ShowError("buildin_checkweight: invalid type for argument '%d'.\n", i); + script_pushint(st,0); + return false; + } + if( id == NULL ) { + ShowError("buildin_checkweight: Invalid item '%s'.\n", script_getstr(st,i)); // returns string, regardless of what it was + script_pushint(st,0); + return false; + } + nameid = id->nameid; + + amount = script_getnum(st,i+1); + if( amount < 1 ) { + ShowError("buildin_checkweight: Invalid amount '%d'.\n", amount); + script_pushint(st,0); + return false; + } + + weight += itemdb_weight(nameid)*amount; //total weight for all chk + if( weight + sd->weight > sd->max_weight ) + {// too heavy + script_pushint(st,0); + return true; + } + + switch( pc->checkadditem(sd, nameid, amount) ) { + case ADDITEM_EXIST: + // item is already in inventory, but there is still space for the requested amount + break; + case ADDITEM_NEW: + if( itemdb->isstackable(nameid) ) { + // stackable + amount2++; + if( slots < amount2 ) { + script_pushint(st,0); + return true; + } + } else { + // non-stackable + amount2 += amount; + if( slots < amount2) { + script_pushint(st,0); + return true; + } + } + break; + case ADDITEM_OVERAMOUNT: + script_pushint(st,0); + return true; + } } script_pushint(st,1); return true; @@ -5628,7 +6232,7 @@ BUILDIN(checkweight2) int32 nameid=-1, amount=-1; int i=0, amount2=0, slots=0, weight=0; short fail=0; - + //variable for array parsing struct script_data* data_it; struct script_data* data_nb; @@ -5637,13 +6241,13 @@ BUILDIN(checkweight2) int32 id_it, id_nb; int32 idx_it, idx_nb; int nb_it, nb_nb; //array size - + TBL_PC *sd = script->rid2sd(st); - nullpo_retr(1,sd); - + nullpo_retr(false,sd); + data_it = script_getdata(st, 2); data_nb = script_getdata(st, 3); - + if( !data_isreference(data_it) || !data_isreference(data_nb)) { ShowError("script:checkweight2: parameter not a variable\n"); @@ -5656,70 +6260,64 @@ BUILDIN(checkweight2) idx_nb = reference_getindex(data_nb); name_it = reference_getname(data_it); name_nb = reference_getname(data_nb); - - if( not_array_variable(*name_it) || not_array_variable(*name_nb)) - { - ShowError("script:checkweight2: illegal scope\n"); - script_pushint(st,0); - return false;// not supported - } - if(is_string_variable(name_it) || is_string_variable(name_nb)){ + + if(is_string_variable(name_it) || is_string_variable(name_nb)) { ShowError("script:checkweight2: illegal type, need int\n"); script_pushint(st,0); return false;// not supported } - nb_it = script->getarraysize(st, id_it, idx_it, 0, reference_getref(data_it)); - nb_nb = script->getarraysize(st, id_nb, idx_nb, 0, reference_getref(data_nb)); - if(nb_it != nb_nb){ + nb_it = script->array_highest_key(st,sd,reference_getname(data_it),reference_getref(data_it)); + nb_nb = script->array_highest_key(st,sd,reference_getname(data_nb),reference_getref(data_nb)); + if(nb_it != nb_nb) { ShowError("Size mistmatch: nb_it=%d, nb_nb=%d\n",nb_it,nb_nb); fail = 1; } - + slots = pc->inventoryblank(sd); - for(i=0; i<nb_it; i++){ + for(i=0; i<nb_it; i++) { nameid = (int32)__64BPTRSIZE(script->get_val2(st,reference_uid(id_it,idx_it+i),reference_getref(data_it))); - script_removetop(st, -1, 0); - amount = (int32)__64BPTRSIZE(script->get_val2(st,reference_uid(id_nb,idx_nb+i),reference_getref(data_nb))); - script_removetop(st, -1, 0); - if(fail) continue; //cpntonie to depop rest - - if(itemdb->exists(nameid) == NULL ){ + script_removetop(st, -1, 0); + amount = (int32)__64BPTRSIZE(script->get_val2(st,reference_uid(id_nb,idx_nb+i),reference_getref(data_nb))); + script_removetop(st, -1, 0); + if(fail) continue; //cpntonie to depop rest + + if(itemdb->exists(nameid) == NULL ) { ShowError("buildin_checkweight2: Invalid item '%d'.\n", nameid); fail=1; continue; } - if(amount < 0 ){ + if(amount < 0 ) { ShowError("buildin_checkweight2: Invalid amount '%d'.\n", amount); fail = 1; continue; } - weight += itemdb_weight(nameid)*amount; - if( weight + sd->weight > sd->max_weight ){ + weight += itemdb_weight(nameid)*amount; + if( weight + sd->weight > sd->max_weight ) { fail = 1; continue; - } - switch( pc->checkadditem(sd, nameid, amount) ) { - case ADDITEM_EXIST: + } + switch( pc->checkadditem(sd, nameid, amount) ) { + case ADDITEM_EXIST: // item is already in inventory, but there is still space for the requested amount - break; - case ADDITEM_NEW: - if( itemdb->isstackable(nameid) ){// stackable - amount2++; - if( slots < amount2 ) - fail = 1; - } - else {// non-stackable - amount2 += amount; - if( slots < amount2 ){ - fail = 1; - } - } - break; - case ADDITEM_OVERAMOUNT: - fail = 1; - } //end switch + break; + case ADDITEM_NEW: + if( itemdb->isstackable(nameid) ) {// stackable + amount2++; + if( slots < amount2 ) + fail = 1; + } + else {// non-stackable + amount2 += amount; + if( slots < amount2 ) { + fail = 1; + } + } + break; + case ADDITEM_OVERAMOUNT: + fail = 1; + } //end switch } //end loop DO NOT break it prematurly we need to depop all stack - + fail?script_pushint(st,0):script_pushint(st,1); return true; } @@ -5727,66 +6325,78 @@ BUILDIN(checkweight2) /*========================================== * getitem <item id>,<amount>{,<account ID>}; * getitem "<item name>",<amount>{,<account ID>}; + * + * getitembound <item id>,<amount>,<type>{,<account ID>}; + * getitembound "<item id>",<amount>,<type>{,<account ID>}; *------------------------------------------*/ -BUILDIN(getitem) -{ - int nameid,amount,get_count,i,flag = 0; +BUILDIN(getitem) { + int nameid,amount,get_count,i,flag = 0, offset = 0; struct item it; TBL_PC *sd; - struct script_data *data; struct item_data *item_data; - - data=script_getdata(st,2); - script->get_val(st,data); - if( data_isstring(data) ) - {// "<item name>" - const char *name=script->conv_str(st,data); - if( (item_data = itemdb->search_name(name)) == NULL ){ - ShowError("buildin_getitem: Nonexistant item %s requested.\n", name); + + if( script_isstringtype(st, 2) ) { + // "<item name>" + const char *name = script_getstr(st, 2); + if( (item_data = itemdb->search_name(name)) == NULL ) { + ShowError("buildin_%s: Nonexistant item %s requested.\n", script->getfuncname(st), name); return false; //No item created. } nameid=item_data->nameid; - } else if( data_isint(data) ) {// <item id> - nameid=script->conv_num(st,data); + } else { + // <item id> + nameid = script_getnum(st, 2); //Violet Box, Blue Box, etc - random item pick if( nameid < 0 ) { nameid = -nameid; flag = 1; } - if( nameid <= 0 || !(item_data = itemdb->exists(nameid)) ){ - ShowError("buildin_getitem: Nonexistant item %d requested.\n", nameid); + if( nameid <= 0 || !(item_data = itemdb->exists(nameid)) ) { + ShowError("buildin_%s: Nonexistant item %d requested.\n", script->getfuncname(st), nameid); return false; //No item created. } - } else { - ShowError("buildin_getitem: invalid data type for argument #1 (%d).", data->type); - return false; } - + // <amount> if( (amount=script_getnum(st,3)) <= 0) return true; //return if amount <=0, skip the useles iteration - + memset(&it,0,sizeof(it)); it.nameid=nameid; + if(!flag) it.identify=1; else it.identify=itemdb->isidentified2(item_data); - - if( script_hasdata(st,4) ) - sd=map->id2sd(script_getnum(st,4)); // <Account ID> + + if( !strcmp(script->getfuncname(st),"getitembound") ) { + int bound = script_getnum(st,4); + if( bound < IBT_MIN || bound > IBT_MAX ) { //Not a correct bound type + ShowError("script_getitembound: Not a correct bound type! Type=%d\n",bound); + return false; + } + if( item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR ) { + ShowError("script_getitembound: can't bind a pet egg/armor!\n",bound); + return false; + } + it.bound = (unsigned char)bound; + offset += 1; + } + + if( script_hasdata(st,4+offset) ) + sd=map->id2sd(script_getnum(st,4+offset)); // <Account ID> else sd=script->rid2sd(st); // Attached player - + if( sd == NULL ) // no target return true; - + //Check if it's stackable. if (!itemdb->isstackable(nameid)) get_count = 1; else get_count = amount; - + for (i = 0; i < amount; i += get_count) { // if not pet egg if (!pet->create_egg(sd, nameid)) { @@ -5797,42 +6407,46 @@ BUILDIN(getitem) } } } - + return true; } /*========================================== * *------------------------------------------*/ -BUILDIN(getitem2) -{ - int nameid,amount,get_count,i,flag = 0; - int iden,ref,attr,c1,c2,c3,c4; - struct item_data *item_data; - struct item item_tmp; +BUILDIN(getitem2) { + int nameid,amount,i,flag = 0, offset = 0; + int iden,ref,attr,c1,c2,c3,c4, bound = 0; TBL_PC *sd; - struct script_data *data; - - if( script_hasdata(st,11) ) - sd=map->id2sd(script_getnum(st,11)); // <Account ID> + + if( !strcmp(script->getfuncname(st),"getitembound2") ) { + bound = script_getnum(st,11); + if( bound < IBT_MIN || bound > IBT_MAX ) { //Not a correct bound type + ShowError("script_getitembound2: Not a correct bound type! Type=%d\n",bound); + return false; + } + offset += 1; + } + + if( script_hasdata(st,11+offset) ) + sd=map->id2sd(script_getnum(st,11+offset)); // <Account ID> else sd=script->rid2sd(st); // Attached player - + if( sd == NULL ) // no target return true; - - data=script_getdata(st,2); - script->get_val(st,data); - if( data_isstring(data) ){ - const char *name=script->conv_str(st,data); + + if( script_isstringtype(st, 2) ) { + const char *name = script_getstr(st, 2); struct item_data *item_data = itemdb->search_name(name); if( item_data ) nameid=item_data->nameid; else nameid=UNKNOWN_ITEM_ID; - }else - nameid=script->conv_num(st,data); - + } else { + nameid = script_getnum(st, 2); + } + amount=script_getnum(st,3); iden=script_getnum(st,4); ref=script_getnum(st,5); @@ -5841,18 +6455,25 @@ BUILDIN(getitem2) c2=(short)script_getnum(st,8); c3=(short)script_getnum(st,9); c4=(short)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!\n",bound); + return false; + } + if(nameid<0) { // Invalide nameid nameid = -nameid; flag = 1; } - + if(nameid > 0) { + struct item item_tmp; + struct item_data *item_data = itemdb->exists(nameid); + int get_count; memset(&item_tmp,0,sizeof(item_tmp)); - item_data=itemdb->exists(nameid); if (item_data == NULL) return -1; - if(item_data->type==IT_WEAPON || item_data->type==IT_ARMOR){ + if(item_data->type==IT_WEAPON || item_data->type==IT_ARMOR) { if(ref > MAX_REFINE) ref = MAX_REFINE; } else if(item_data->type==IT_PETEGG) { @@ -5863,7 +6484,7 @@ BUILDIN(getitem2) iden = 1; ref = attr = 0; } - + item_tmp.nameid=nameid; if(!flag) item_tmp.identify=iden; @@ -5871,17 +6492,18 @@ BUILDIN(getitem2) item_tmp.identify=0; 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; - + //Check if it's stackable. if (!itemdb->isstackable(nameid)) get_count = 1; else get_count = amount; - + for (i = 0; i < amount; i += get_count) { // if not pet egg if (!pet->create_egg(sd, nameid)) { @@ -5893,7 +6515,7 @@ BUILDIN(getitem2) } } } - + return true; } @@ -5901,23 +6523,17 @@ BUILDIN(getitem2) * rentitem <item id>,<seconds> * rentitem "<item name>",<seconds> *------------------------------------------*/ -BUILDIN(rentitem) -{ +BUILDIN(rentitem) { struct map_session_data *sd; - struct script_data *data; struct item it; int seconds; int nameid = 0, flag; - - data = script_getdata(st,2); - script->get_val(st,data); - + if( (sd = script->rid2sd(st)) == NULL ) return true; - - if( data_isstring(data) ) - { - const char *name = script->conv_str(st,data); + + if( script_isstringtype(st, 2) ) { + const char *name = script_getstr(st, 2); struct item_data *itd = itemdb->search_name(name); if( itd == NULL ) { @@ -5925,34 +6541,27 @@ BUILDIN(rentitem) return false; } nameid = itd->nameid; - } - else if( data_isint(data) ) - { - nameid = script->conv_num(st,data); - if( nameid <= 0 || !itemdb->exists(nameid) ) - { + } else { + nameid = script_getnum(st, 2); + if( nameid <= 0 || !itemdb->exists(nameid) ) { ShowError("buildin_rentitem: Nonexistant item %d requested.\n", nameid); return false; } } - else - { - ShowError("buildin_rentitem: invalid data type for argument #1 (%d).\n", data->type); - return false; - } - + seconds = script_getnum(st,3); memset(&it, 0, sizeof(it)); it.nameid = nameid; it.identify = 1; it.expire_time = (unsigned int)(time(NULL) + seconds); - + it.bound = 0; + if( (flag = pc->additem(sd, &it, 1, LOG_TYPE_SCRIPT)) ) { clif->additem(sd, 0, 0, flag); return false; } - + return true; } @@ -5962,53 +6571,48 @@ BUILDIN(rentitem) * Returned Qty is always 1, only works on equip-able * equipment *------------------------------------------*/ -BUILDIN(getnameditem) -{ +BUILDIN(getnameditem) { int nameid; struct item item_tmp; TBL_PC *sd, *tsd; - struct script_data *data; - + sd = script->rid2sd(st); - if (sd == NULL) - { //Player not attached! + if (sd == NULL) { + //Player not attached! script_pushint(st,0); return true; } - - data=script_getdata(st,2); - script->get_val(st,data); - if( data_isstring(data) ){ - const char *name=script->conv_str(st,data); + + if( script_isstringtype(st, 2) ) { + const char *name = script_getstr(st, 2); struct item_data *item_data = itemdb->search_name(name); - if( item_data == NULL) - { //Failed + if( item_data == NULL) { + //Failed script_pushint(st,0); return true; } nameid = item_data->nameid; - }else - nameid = script->conv_num(st,data); - - if(!itemdb->exists(nameid)/* || itemdb->isstackable(nameid)*/) - { //Even though named stackable items "could" be risky, they are required for certain quests. + } else { + nameid = script_getnum(st, 2); + } + + if(!itemdb->exists(nameid)/* || itemdb->isstackable(nameid)*/) { + //Even though named stackable items "could" be risky, they are required for certain quests. script_pushint(st,0); return true; } - - data=script_getdata(st,3); - script->get_val(st,data); - if( data_isstring(data) ) //Char Name - tsd=map->nick2sd(script->conv_str(st,data)); + + if( script_isstringtype(st, 3) ) //Char Name + tsd=map->nick2sd(script_getstr(st, 3)); else //Char Id was given - tsd=map->charid2sd(script->conv_num(st,data)); - - if( tsd == NULL ) - { //Failed + tsd=map->charid2sd(script_getnum(st, 3)); + + if( tsd == NULL ) { + //Failed script_pushint(st,0); return true; } - + memset(&item_tmp,0,sizeof(item_tmp)); item_tmp.nameid=nameid; item_tmp.amount=1; @@ -6018,9 +6622,9 @@ BUILDIN(getnameditem) item_tmp.card[3]=tsd->status.char_id >> 16; if(pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT)) { script_pushint(st,0); - return true; //Failed to add item, we will not drop if they don't fit + return true; //Failed to add item, we will not drop if they don't fit } - + script_pushint(st,1); return true; } @@ -6032,7 +6636,7 @@ BUILDIN(getnameditem) BUILDIN(grouprandomitem) { struct item_data *data; int nameid; - + if( script_hasdata(st, 2) ) nameid = script_getnum(st, 2); else if ( script->current_item_id ) @@ -6042,7 +6646,7 @@ BUILDIN(grouprandomitem) { script_pushint(st, 0); return true; } - + if( !(data = itemdb->exists(nameid)) ) { ShowWarning("buildin_grouprandomitem: unknown item id %d\n",nameid); script_pushint(st, 0); @@ -6052,7 +6656,7 @@ BUILDIN(grouprandomitem) { } else { script_pushint(st, itemdb->group_item(data->group)); } - + return true; } @@ -6065,29 +6669,26 @@ BUILDIN(makeitem) int x,y,m; const char *mapname; struct item item_tmp; - struct script_data *data; struct item_data *item_data; - data=script_getdata(st,2); - script->get_val(st,data); - if( data_isstring(data) ){ - const char *name=script->conv_str(st,data); + if( script_isstringtype(st, 2) ) { + const char *name = script_getstr(st, 2); if( (item_data = itemdb->search_name(name)) ) nameid=item_data->nameid; else nameid=UNKNOWN_ITEM_ID; } else { - nameid=script->conv_num(st,data); - if( nameid <= 0 || !(item_data = itemdb->exists(nameid)) ){ + nameid = script_getnum(st, 2); + if( nameid <= 0 || !(item_data = itemdb->exists(nameid)) ) { ShowError("makeitem: Nonexistant item %d requested.\n", nameid); return false; //No item created. } } - amount=script_getnum(st,3); - mapname =script_getstr(st,4); - x =script_getnum(st,5); - y =script_getnum(st,6); - + amount = script_getnum(st,3); + mapname = script_getstr(st,4); + x = script_getnum(st,5); + y = script_getnum(st,6); + if(strcmp(mapname,"this")==0) { TBL_PC *sd; sd = script->rid2sd(st); @@ -6095,22 +6696,22 @@ BUILDIN(makeitem) m=sd->bl.m; } else m=map->mapname2mapid(mapname); - + if( m == -1 ) { ShowError("makeitem: creating map on unexistent map '%s'!\n", mapname); return false; } - - + + memset(&item_tmp,0,sizeof(item_tmp)); item_tmp.nameid=nameid; if(!flag) item_tmp.identify=1; else item_tmp.identify=itemdb->isidentified2(item_data); - + map->addflooritem(&item_tmp,amount,m,x,y,0,0,0,0); - + return true; } @@ -6122,9 +6723,9 @@ void buildin_delitem_delete(struct map_session_data* sd, int idx, int* amount, b { int delamount; struct item* inv = &sd->status.inventory[idx]; - + delamount = ( amount[0] < inv->amount ) ? amount[0] : inv->amount; - + if( delete_items ) { if( sd->inventory_data[idx]->type == IT_PETEGG && inv->card[0] == CARD0_PET ) @@ -6133,7 +6734,7 @@ void buildin_delitem_delete(struct map_session_data* sd, int idx, int* amount, b } pc->delitem(sd, idx, delamount, 0, 0, LOG_TYPE_SCRIPT); } - + amount[0]-= delamount; } @@ -6148,10 +6749,10 @@ bool buildin_delitem_search(struct map_session_data* sd, struct item* it, bool e bool delete_items = false; int i, amount, important; struct item* inv; - + // prefer always non-equipped items it->equip = 0; - + // when searching for nameid only, prefer additionally if( !exact_match ) { @@ -6160,28 +6761,28 @@ bool buildin_delitem_search(struct map_session_data* sd, struct item* it, bool e // card-less items memset(it->card, 0, sizeof(it->card)); } - + for(;;) { amount = it->amount; important = 0; - + // 1st pass -- less important items / exact match for( i = 0; amount && i < ARRAYLENGTH(sd->status.inventory); i++ ) { inv = &sd->status.inventory[i]; - + if( !inv->nameid || !sd->inventory_data[i] || inv->nameid != it->nameid ) {// wrong/invalid item continue; } - + if( inv->equip != it->equip || inv->refine != it->refine ) {// not matching attributes important++; continue; } - + if( exact_match ) { if( inv->identify != it->identify || inv->attribute != it->attribute || memcmp(inv->card, it->card, sizeof(inv->card)) ) @@ -6204,11 +6805,11 @@ bool buildin_delitem_search(struct map_session_data* sd, struct item* it, bool e continue; } } - + // count / delete item script->buildin_delitem_delete(sd, i, &amount, delete_items); } - + // 2nd pass -- any matching item if( amount == 0 || important == 0 ) {// either everything was already consumed or no items were skipped @@ -6217,17 +6818,17 @@ bool buildin_delitem_search(struct map_session_data* sd, struct item* it, bool e else for( i = 0; amount && i < ARRAYLENGTH(sd->status.inventory); i++ ) { inv = &sd->status.inventory[i]; - + if( !inv->nameid || !sd->inventory_data[i] || inv->nameid != it->nameid ) {// wrong/invalid item continue; } - + if( sd->inventory_data[i]->type == IT_PETEGG && inv->card[0] == CARD0_PET && intif->CheckForCharServer() ) {// pet which cannot be deleted continue; } - + if( exact_match ) { if( inv->refine != it->refine || inv->identify != it->identify || inv->attribute != it->attribute || memcmp(inv->card, it->card, sizeof(inv->card)) ) @@ -6235,11 +6836,11 @@ bool buildin_delitem_search(struct map_session_data* sd, struct item* it, bool e continue; } } - + // count / delete item script->buildin_delitem_delete(sd, i, &amount, delete_items); } - + if( amount ) {// not enough items return false; @@ -6261,12 +6862,10 @@ 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) -{ +BUILDIN(delitem) { TBL_PC *sd; struct item it; - struct script_data *data; - + if( script_hasdata(st,4) ) { int account_id = script_getnum(st,4); @@ -6284,24 +6883,18 @@ BUILDIN(delitem) if( sd == NULL ) return true; } - - data = script_getdata(st,2); - script->get_val(st,data); - if( data_isstring(data) ) - { - const char* item_name = script->conv_str(st,data); + + if( script_isstringtype(st, 2) ) { + const char* item_name = script_getstr(st, 2); struct item_data* id = itemdb->search_name(item_name); - if( id == NULL ) - { + if( id == NULL ) { ShowError("script:delitem: unknown item \"%s\".\n", item_name); st->state = END; return false; } it.nameid = id->nameid;// "<item name>" - } - else - { - it.nameid = script->conv_num(st,data);// <item id> + } else { + it.nameid = script_getnum(st, 2);// <item id> if( !itemdb->exists( it.nameid ) ) { ShowError("script:delitem: unknown item \"%d\".\n", it.nameid); @@ -6309,17 +6902,17 @@ BUILDIN(delitem) return false; } } - + it.amount=script_getnum(st,3); - + if( it.amount <= 0 ) return true;// nothing to do - + if( script->buildin_delitem_search(sd, &it, false) ) {// success return true; } - + ShowError("script:delitem: failed to delete %d items (AID=%d item_id=%d).\n", it.amount, sd->status.account_id, it.nameid); st->state = END; clif->scriptclose(sd, st->oid); @@ -6333,8 +6926,7 @@ BUILDIN(delitem) BUILDIN(delitem2) { TBL_PC *sd; struct item it; - struct script_data *data; - + if( script_hasdata(st,11) ) { int account_id = script_getnum(st,11); sd = map->id2sd(account_id); // <account id> @@ -6350,32 +6942,25 @@ BUILDIN(delitem2) { if( sd == NULL ) return true; } - - data = script_getdata(st,2); - script->get_val(st,data); - if( data_isstring(data) ) - { - const char* item_name = script->conv_str(st,data); + + if( script_isstringtype(st, 2) ) { + const char* item_name = script_getstr(st, 2); struct item_data* id = itemdb->search_name(item_name); - if( id == NULL ) - { + if( id == NULL ) { ShowError("script:delitem2: unknown item \"%s\".\n", item_name); st->state = END; return false; } it.nameid = id->nameid;// "<item name>" - } - else - { - it.nameid = script->conv_num(st,data);// <item id> - if( !itemdb->exists( it.nameid ) ) - { + } else { + it.nameid = script_getnum(st, 2);// <item id> + if( !itemdb->exists( it.nameid ) ) { ShowError("script:delitem: unknown item \"%d\".\n", it.nameid); st->state = END; return false; } } - + it.amount=script_getnum(st,3); it.identify=script_getnum(st,4); it.refine=script_getnum(st,5); @@ -6384,15 +6969,15 @@ BUILDIN(delitem2) { it.card[1]=(short)script_getnum(st,8); it.card[2]=(short)script_getnum(st,9); it.card[3]=(short)script_getnum(st,10); - + if( it.amount <= 0 ) return true;// nothing to do - + if( script->buildin_delitem_search(sd, &it, true) ) {// success return true; } - + ShowError("script:delitem2: failed to delete %d items (AID=%d item_id=%d).\n", it.amount, sd->status.account_id, it.nameid); st->state = END; clif->scriptclose(sd, st->oid); @@ -6427,47 +7012,47 @@ BUILDIN(disableitemuse) BUILDIN(readparam) { int type; TBL_PC *sd; - + type=script_getnum(st,2); if( script_hasdata(st,3) ) sd=map->nick2sd(script_getstr(st,3)); else sd=script->rid2sd(st); - - if(sd==NULL){ + + if(sd==NULL) { script_pushint(st,-1); return true; } - + script_pushint(st,pc->readparam(sd,type)); - + return true; } /*========================================== * Return charid identification * return by @num : - * 0 : char_id - * 1 : party_id - * 2 : guild_id - * 3 : account_id - * 4 : bg_id + * 0 : char_id + * 1 : party_id + * 2 : guild_id + * 3 : account_id + * 4 : bg_id *------------------------------------------*/ BUILDIN(getcharid) { int num; TBL_PC *sd; - + num = script_getnum(st,2); if( script_hasdata(st,3) ) sd=map->nick2sd(script_getstr(st,3)); else 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; @@ -6479,7 +7064,7 @@ BUILDIN(getcharid) { script_pushint(st,0); break; } - + return true; } /*========================================== @@ -6489,7 +7074,7 @@ 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 ) @@ -6499,7 +7084,7 @@ BUILDIN(getnpcid) return false; } } - + switch (num) { case 0: script_pushint(st,nd ? nd->bl.id : st->oid); @@ -6509,7 +7094,7 @@ BUILDIN(getnpcid) script_pushint(st,0); return false; } - + return true; } @@ -6521,9 +7106,9 @@ BUILDIN(getpartyname) { int party_id; struct party_data* p; - + party_id = script_getnum(st,2); - + if( ( p = party->search(party_id) ) != NULL ) { script_pushstrcopy(st,p->party.name); @@ -6539,23 +7124,23 @@ BUILDIN(getpartyname) * Get the information of the members of a party by type * @party_id, @type * return by @type : - * - : nom des membres - * 1 : char_id des membres - * 2 : account_id des membres + * - : nom des membres + * 1 : char_id des membres + * 2 : account_id des membres *------------------------------------------*/ BUILDIN(getpartymember) { struct party_data *p; int i,j=0,type=0; - + p=party->search(script_getnum(st,2)); - + if( script_hasdata(st,3) ) - type=script_getnum(st,3); - - if(p!=NULL){ - for(i=0;i<MAX_PARTY;i++){ - if(p->party.member[i].account_id){ + type=script_getnum(st,3); + + if(p!=NULL) { + for(i=0;i<MAX_PARTY;i++) { + 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); @@ -6571,7 +7156,7 @@ BUILDIN(getpartymember) } } mapreg->setreg(script->add_str("$@partymembercount"),j); - + return true; } @@ -6583,16 +7168,16 @@ BUILDIN(getpartyleader) { int party_id, type = 0, i=0; struct party_data *p; - + party_id=script_getnum(st,2); if( script_hasdata(st,3) ) - type=script_getnum(st,3); - + type=script_getnum(st,3); + p=party->search(party_id); - + if (p) //Search leader for(i = 0; i < MAX_PARTY && !p->party.member[i].leader; i++); - + if (!p || i == MAX_PARTY) { //leader not found if (type) script_pushint(st,-1); @@ -6600,7 +7185,7 @@ BUILDIN(getpartyleader) script_pushconststr(st,"null"); return true; } - + switch (type) { case 1: script_pushint(st,p->party.member[i].account_id); break; case 2: script_pushint(st,p->party.member[i].char_id); break; @@ -6620,9 +7205,9 @@ BUILDIN(getguildname) { int guild_id; struct guild* g; - + guild_id = script_getnum(st,2); - + if( ( g = guild->search(guild_id) ) != NULL ) { script_pushstrcopy(st,g->name); @@ -6642,9 +7227,9 @@ BUILDIN(getguildmaster) { int guild_id; struct guild* g; - + guild_id = script_getnum(st,2); - + if( ( g = guild->search(guild_id) ) != NULL ) { script_pushstrcopy(st,g->member[0].name); @@ -6660,9 +7245,9 @@ BUILDIN(getguildmasterid) { int guild_id; struct guild* g; - + guild_id = script_getnum(st,2); - + if( ( g = guild->search(guild_id) ) != NULL ) { script_pushint(st,g->member[0].char_id); @@ -6677,11 +7262,11 @@ BUILDIN(getguildmasterid) /*========================================== * Get char string information by type : * Return by @type : - * 0 : char_name - * 1 : party_name or "" - * 2 : guild_name or "" - * 3 : map_name - * - : "" + * 0 : char_name + * 1 : party_name or "" + * 2 : guild_name or "" + * 3 : map_name + * - : "" *------------------------------------------*/ BUILDIN(strcharinfo) { @@ -6689,14 +7274,14 @@ BUILDIN(strcharinfo) int num; struct guild* g; struct party_data* p; - + sd=script->rid2sd(st); if (!sd) { //Avoid crashing.... script_pushconststr(st,""); return true; } num=script_getnum(st,2); - switch(num){ + switch(num) { case 0: script_pushstrcopy(st,sd->status.name); break; @@ -6722,32 +7307,32 @@ BUILDIN(strcharinfo) script_pushconststr(st,""); break; } - + return true; } /*========================================== * Get npc string information by type * return by @type: - * 0 : name - * 1 : str# - * 2 : #str - * 3 : ::str - * 4 : map name + * 0 : name + * 1 : str# + * 2 : #str + * 3 : ::str + * 4 : map name *------------------------------------------*/ BUILDIN(strnpcinfo) { TBL_NPC* nd; int num; char *buf,*name=NULL; - + nd = map->id2nd(st->oid); if (!nd) { script_pushconststr(st, ""); return true; } - + num = script_getnum(st,2); - switch(num){ + switch(num) { case 0: // display name name = aStrdup(nd->name); break; @@ -6767,38 +7352,39 @@ BUILDIN(strnpcinfo) { name = aStrdup(nd->exname); break; case 4: // map name - name = aStrdup(map->list[nd->bl.m].name); + if( nd->bl.m >= 0 ) // Only valid map indexes allowed (issue:8034) + name = aStrdup(map->list[nd->bl.m].name); break; } - + if(name) script_pushstr(st, name); else script_pushconststr(st, ""); - + return true; } /*========================================== - * GetEquipID(Pos); Pos: 1-10 + * GetEquipID(Pos); Pos: 1-SCRIPT_EQUIP_TABLE_SIZE *------------------------------------------*/ BUILDIN(getequipid) { int i, num; TBL_PC* sd; struct item_data* item; - + sd = script->rid2sd(st); if( sd == NULL ) return true; - + num = script_getnum(st,2) - 1; if( num < 0 || num >= ARRAYLENGTH(script->equip) ) { script_pushint(st,-1); return true; } - + // get inventory position of item i = pc->checkequip(sd,script->equip[num]); if( i < 0 ) @@ -6806,13 +7392,13 @@ BUILDIN(getequipid) script_pushint(st,-1); return true; } - + item = sd->inventory_data[i]; if( item != 0 ) script_pushint(st,item->nameid); else script_pushint(st,0); - + return true; } @@ -6825,18 +7411,18 @@ BUILDIN(getequipname) int i, num; TBL_PC* sd; struct item_data* item; - + sd = script->rid2sd(st); if( sd == NULL ) return true; - + num = script_getnum(st,2) - 1; if( num < 0 || num >= ARRAYLENGTH(script->equip) ) { script_pushconststr(st,""); return true; } - + // get inventory position of item i = pc->checkequip(sd,script->equip[num]); if( i < 0 ) @@ -6844,13 +7430,13 @@ BUILDIN(getequipname) script_pushconststr(st,""); return true; } - + item = sd->inventory_data[i]; if( item != 0 ) script_pushstrcopy(st,item->jname); else script_pushconststr(st,""); - + return true; } @@ -6861,24 +7447,24 @@ BUILDIN(getbrokenid) { int i,num,id=0,brokencounter=0; TBL_PC *sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true; - + num=script_getnum(st,2); for(i=0; i<MAX_INVENTORY; i++) { - if(sd->status.inventory[i].attribute){ + if(sd->status.inventory[i].attribute) { brokencounter++; - if(num==brokencounter){ + if(num==brokencounter) { id=sd->status.inventory[i].nameid; break; } } } - + script_pushint(st,id); - + return true; } @@ -6890,16 +7476,16 @@ BUILDIN(repair) int i,num; int repaircounter=0; TBL_PC *sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true; - + num=script_getnum(st,2); for(i=0; i<MAX_INVENTORY; i++) { - if(sd->status.inventory[i].attribute){ + if(sd->status.inventory[i].attribute) { repaircounter++; - if(num==repaircounter){ + if(num==repaircounter) { sd->status.inventory[i].attribute=0; clif->equiplist(sd); clif->produce_effect(sd, 0, sd->status.inventory[i].nameid); @@ -6908,7 +7494,7 @@ BUILDIN(repair) } } } - + return true; } @@ -6919,11 +7505,11 @@ BUILDIN(repairall) { int i, repaircounter = 0; TBL_PC *sd; - + sd = script->rid2sd(st); if(sd == NULL) return true; - + for(i = 0; i < MAX_INVENTORY; i++) { if(sd->status.inventory[i].nameid && sd->status.inventory[i].attribute) @@ -6933,13 +7519,13 @@ BUILDIN(repairall) repaircounter++; } } - + if(repaircounter) { clif->misceffect(&sd->bl, 3); clif->equiplist(sd); } - + return true; } @@ -6950,15 +7536,15 @@ BUILDIN(getequipisequiped) { int i = -1,num; TBL_PC *sd; - + num = script_getnum(st,2); sd = script->rid2sd(st); if( sd == NULL ) return true; - + if (num > 0 && num <= ARRAYLENGTH(script->equip)) i=pc->checkequip(sd,script->equip[num-1]); - + if(i >= 0) script_pushint(st,1); else @@ -6970,78 +7556,78 @@ BUILDIN(getequipisequiped) * Chk if the player have something equiped at pos * if so chk if this item ain't marked not refinable or rental * return (npc) - * 1 : true - * 0 : false + * 1 : true + * 0 : false *------------------------------------------*/ BUILDIN(getequipisenableref) { int i = -1,num; TBL_PC *sd; - + num = script_getnum(st,2); sd = script->rid2sd(st); if( sd == NULL ) return true; - + if( num > 0 && num <= ARRAYLENGTH(script->equip) ) i = pc->checkequip(sd,script->equip[num-1]); if( i >= 0 && sd->inventory_data[i] && !sd->inventory_data[i]->flag.no_refine && !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 + * 1 : true + * 0 : false *------------------------------------------*/ BUILDIN(getequipisidentify) { int i = -1,num; TBL_PC *sd; - + num = script_getnum(st,2); sd = script->rid2sd(st); if( sd == NULL ) return true; - + if (num > 0 && num <= ARRAYLENGTH(script->equip)) i=pc->checkequip(sd,script->equip[num-1]); if(i >= 0) script_pushint(st,sd->status.inventory[i].identify); else script_pushint(st,0); - + return true; } /*========================================== * Get the item refined value at pos * return (npc) - * x : refine amount - * 0 : false (not refined) + * x : refine amount + * 0 : false (not refined) *------------------------------------------*/ BUILDIN(getequiprefinerycnt) { int i = -1,num; TBL_PC *sd; - + num = script_getnum(st,2); sd = script->rid2sd(st); if( sd == NULL ) return true; - + if (num > 0 && num <= ARRAYLENGTH(script->equip)) i=pc->checkequip(sd,script->equip[num-1]); if(i >= 0) script_pushint(st,sd->status.inventory[i].refine); else script_pushint(st,0); - + return true; } @@ -7049,95 +7635,98 @@ BUILDIN(getequiprefinerycnt) * Get the weapon level value at pos * (pos should normally only be EQI_HAND_L or EQI_HAND_R) * return (npc) - * x : weapon level - * 0 : false + * x : weapon level + * 0 : false *------------------------------------------*/ BUILDIN(getequipweaponlv) { int i = -1,num; TBL_PC *sd; - + num = script_getnum(st,2); sd = script->rid2sd(st); if( sd == NULL ) return true; - + if (num > 0 && num <= ARRAYLENGTH(script->equip)) i=pc->checkequip(sd,script->equip[num-1]); if(i >= 0 && sd->inventory_data[i]) script_pushint(st,sd->inventory_data[i]->wlv); else script_pushint(st,0); - + return true; } /*========================================== * Get the item refine chance (from refine.txt) for item at pos * return (npc) - * x : refine chance - * 0 : false (max refine level or unequip..) + * x : refine chance + * 0 : false (max refine level or unequip..) *------------------------------------------*/ BUILDIN(getequippercentrefinery) { int i = -1,num; TBL_PC *sd; - + num = script_getnum(st,2); sd = script->rid2sd(st); if( sd == NULL ) return true; - + 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)); else script_pushint(st,0); - + return true; } /*========================================== * Refine +1 item at pos and log and display refine *------------------------------------------*/ -BUILDIN(successrefitem) -{ - int i=-1,num,ep; +BUILDIN(successrefitem) { + int i = -1 , num, ep, up = 1; TBL_PC *sd; - + num = script_getnum(st,2); sd = script->rid2sd(st); if( sd == NULL ) return true; + + if( script_hasdata(st, 3) ) + up = script_getnum(st, 3); if (num > 0 && num <= ARRAYLENGTH(script->equip)) i=pc->checkequip(sd,script->equip[num-1]); if(i >= 0) { ep=sd->status.inventory[i].equip; - + //Logs items, got from (N)PC scripts [Lupus] logs->pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->status.inventory[i],sd->inventory_data[i]); - + if (sd->status.inventory[i].refine >= MAX_REFINE) return true; - - sd->status.inventory[i].refine++; + + sd->status.inventory[i].refine += up; + sd->status.inventory[i].refine = cap_value( sd->status.inventory[i].refine, 0, MAX_REFINE); pc->unequipitem(sd,i,2); // status calc will happen in pc->equipitem() below - + clif->refine(sd->fd,0,i,sd->status.inventory[i].refine); clif->delitem(sd,i,1,3); - + //Logs items, got from (N)PC scripts [Lupus] logs->pick_pc(sd, LOG_TYPE_SCRIPT, 1, &sd->status.inventory[i],sd->inventory_data[i]); - + clif->additem(sd,i,1,0); pc->equipitem(sd,i,ep); clif->misceffect(&sd->bl,3); 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]) - ){ // Fame point system [DracoRPG] - switch (sd->inventory_data[i]->wlv){ + ) { // Fame point system [DracoRPG] + switch (sd->inventory_data[i]->wlv) { case 1: pc->addfame(sd,1); // Success to refine to +10 a lv1 weapon you forged = +1 fame point break; @@ -7150,7 +7739,7 @@ BUILDIN(successrefitem) } } } - + return true; } @@ -7161,24 +7750,24 @@ BUILDIN(failedrefitem) { int i=-1,num; TBL_PC *sd; - + num = script_getnum(st,2); sd = script->rid2sd(st); if( sd == NULL ) return true; - + if (num > 0 && num <= ARRAYLENGTH(script->equip)) i=pc->checkequip(sd,script->equip[num-1]); if(i >= 0) { sd->status.inventory[i].refine = 0; pc->unequipitem(sd,i,3); //recalculate bonus clif->refine(sd->fd,1,i,sd->status.inventory[i].refine); //notify client of failure - + pc->delitem(sd,i,1,0,2,LOG_TYPE_SCRIPT); - - clif->misceffect(&sd->bl,2); // display failure effect + + clif->misceffect(&sd->bl,2); // display failure effect } - + return true; } @@ -7189,37 +7778,37 @@ BUILDIN(downrefitem) { int i = -1,num,ep, down = 1; TBL_PC *sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true; num = script_getnum(st,2); if( script_hasdata(st, 3) ) down = script_getnum(st, 3); - + if (num > 0 && num <= ARRAYLENGTH(script->equip)) i = pc->checkequip(sd,script->equip[num-1]); if(i >= 0) { ep = sd->status.inventory[i].equip; - + //Logs items, got from (N)PC scripts [Lupus] logs->pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->status.inventory[i],sd->inventory_data[i]); - + pc->unequipitem(sd,i,2); // status calc will happen in pc->equipitem() below sd->status.inventory[i].refine -= down; sd->status.inventory[i].refine = cap_value( sd->status.inventory[i].refine, 0, MAX_REFINE); clif->refine(sd->fd,2,i,sd->status.inventory[i].refine); clif->delitem(sd,i,1,3); - + //Logs items, got from (N)PC scripts [Lupus] logs->pick_pc(sd, LOG_TYPE_SCRIPT, 1, &sd->status.inventory[i],sd->inventory_data[i]); - + clif->additem(sd,i,1,0); pc->equipitem(sd,i,ep); clif->misceffect(&sd->bl,2); } - + return true; } @@ -7230,37 +7819,36 @@ BUILDIN(delequip) { int i=-1,num; TBL_PC *sd; - + num = script_getnum(st,2); sd = script->rid2sd(st); if( sd == NULL ) return true; - + if (num > 0 && num <= ARRAYLENGTH(script->equip)) i=pc->checkequip(sd,script->equip[num-1]); if(i >= 0) { pc->unequipitem(sd,i,3); //recalculate bonus pc->delitem(sd,i,1,0,2,LOG_TYPE_SCRIPT); } - + return true; } /*========================================== * *------------------------------------------*/ -BUILDIN(statusup) -{ +BUILDIN(statusup) { int type; TBL_PC *sd; - + type=script_getnum(st,2); sd = script->rid2sd(st); if( sd == NULL ) return true; - - pc->statusup(sd,type); - + + pc->statusup(sd, type, 1); + return true; } /*========================================== @@ -7270,15 +7858,15 @@ BUILDIN(statusup2) { int type,val; TBL_PC *sd; - + type=script_getnum(st,2); val=script_getnum(st,3); sd = script->rid2sd(st); if( sd == NULL ) return true; - + pc->statusup2(sd,type,val); - + return true; } @@ -7289,8 +7877,7 @@ 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) -{ +BUILDIN(bonus) { int type; int val1; int val2 = 0; @@ -7298,11 +7885,11 @@ BUILDIN(bonus) int val4 = 0; int val5 = 0; TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true; // no player attached - + type = script_getnum(st,2); switch( type ) { case SP_AUTOSPELL: @@ -7322,13 +7909,16 @@ BUILDIN(bonus) case SP_FIXCASTRATE: case SP_SKILL_USE_SP: // these bonuses support skill names - val1 = ( script_isstring(st,3) ? skill->name2id(script_getstr(st,3)) : script_getnum(st,3) ); - break; + if (script_isstringtype(st, 3)) { + val1 = skill->name2id(script_getstr(st, 3)); + break; + } + // else fall through default: val1 = script_getnum(st,3); break; } - + switch( script_lastdata(st)-2 ) { case 1: pc->bonus(sd, type, val1); @@ -7343,21 +7933,21 @@ BUILDIN(bonus) pc->bonus3(sd, type, val1, val2, val3); break; case 4: - if( type == SP_AUTOSPELL_ONSKILL && script_isstring(st,4) ) + if( type == SP_AUTOSPELL_ONSKILL && script_isstringtype(st,4) ) val2 = skill->name2id(script_getstr(st,4)); // 2nd value can be skill name else val2 = script_getnum(st,4); - + val3 = script_getnum(st,5); val4 = script_getnum(st,6); pc->bonus4(sd, type, val1, val2, val3, val4); break; case 5: - if( type == SP_AUTOSPELL_ONSKILL && script_isstring(st,4) ) + if( type == SP_AUTOSPELL_ONSKILL && script_isstringtype(st,4) ) val2 = skill->name2id(script_getstr(st,4)); // 2nd value can be skill name else val2 = script_getnum(st,4); - + val3 = script_getnum(st,5); val4 = script_getnum(st,6); val5 = script_getnum(st,7); @@ -7367,7 +7957,7 @@ BUILDIN(bonus) ShowDebug("buildin_bonus: unexpected number of arguments (%d)\n", (script_lastdata(st) - 1)); break; } - + return true; } @@ -7377,25 +7967,25 @@ BUILDIN(autobonus) { short atk_type = 0; TBL_PC* sd; const char *bonus_script, *other_script = NULL; - + sd = script->rid2sd(st); if( sd == NULL ) return true; // no player attached - + if( sd->state.autobonus&sd->status.inventory[status->current_equip_item_index].equip ) return true; - + rate = script_getnum(st,3); dur = script_getnum(st,4); bonus_script = script_getstr(st,2); if( !rate || !dur || !bonus_script ) return true; - + if( script_hasdata(st,5) ) atk_type = script_getnum(st,5); if( script_hasdata(st,6) ) other_script = script_getstr(st,6); - + if( pc->addautobonus(sd->autobonus,ARRAYLENGTH(sd->autobonus),bonus_script,rate,dur,atk_type,other_script, sd->status.inventory[status->current_equip_item_index].equip,false) ) { @@ -7403,7 +7993,7 @@ BUILDIN(autobonus) { if( other_script ) script->add_autobonus(other_script); } - + return true; } @@ -7413,25 +8003,25 @@ BUILDIN(autobonus2) { short atk_type = 0; TBL_PC* sd; const char *bonus_script, *other_script = NULL; - + sd = script->rid2sd(st); if( sd == NULL ) return true; // no player attached - + if( sd->state.autobonus&sd->status.inventory[status->current_equip_item_index].equip ) return true; - + rate = script_getnum(st,3); dur = script_getnum(st,4); bonus_script = script_getstr(st,2); if( !rate || !dur || !bonus_script ) return true; - + if( script_hasdata(st,5) ) atk_type = script_getnum(st,5); if( script_hasdata(st,6) ) other_script = script_getstr(st,6); - + if( pc->addautobonus(sd->autobonus2,ARRAYLENGTH(sd->autobonus2),bonus_script,rate,dur,atk_type,other_script, sd->status.inventory[status->current_equip_item_index].equip,false) ) { @@ -7439,7 +8029,7 @@ BUILDIN(autobonus2) { if( other_script ) script->add_autobonus(other_script); } - + return true; } @@ -7448,24 +8038,24 @@ BUILDIN(autobonus3) { short rate,atk_type; TBL_PC* sd; const char *bonus_script, *other_script = NULL; - + sd = script->rid2sd(st); if( sd == NULL ) return true; // no player attached - + if( sd->state.autobonus&sd->status.inventory[status->current_equip_item_index].equip ) return true; - + rate = script_getnum(st,3); dur = script_getnum(st,4); - atk_type = ( script_isstring(st,5) ? skill->name2id(script_getstr(st,5)) : script_getnum(st,5) ); + atk_type = ( script_isstringtype(st,5) ? skill->name2id(script_getstr(st,5)) : script_getnum(st,5) ); bonus_script = script_getstr(st,2); if( !rate || !dur || !atk_type || !bonus_script ) return true; - + if( script_hasdata(st,6) ) other_script = script_getstr(st,6); - + if( pc->addautobonus(sd->autobonus3,ARRAYLENGTH(sd->autobonus3),bonus_script,rate,dur,atk_type,other_script, sd->status.inventory[status->current_equip_item_index].equip,true) ) { @@ -7473,7 +8063,7 @@ BUILDIN(autobonus3) { if( other_script ) script->add_autobonus(other_script); } - + return true; } @@ -7487,23 +8077,22 @@ BUILDIN(autobonus3) { /// skill <skill id>,<level> /// skill "<skill name>",<level>,<flag> /// skill "<skill name>",<level> -BUILDIN(skill) -{ +BUILDIN(skill) { int id; int level; int flag = 1; TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - - id = ( script_isstring(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); + + id = ( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); level = script_getnum(st,3); if( script_hasdata(st,4) ) flag = script_getnum(st,4); pc->skill(sd, id, level, flag); - + return true; } @@ -7516,23 +8105,22 @@ BUILDIN(skill) /// addtoskill "<skill name>",<amount> /// /// @see skill -BUILDIN(addtoskill) -{ +BUILDIN(addtoskill) { int id; int level; int flag = 2; TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - - id = ( script_isstring(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); + + id = ( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); level = script_getnum(st,3); if( script_hasdata(st,4) ) flag = script_getnum(st,4); pc->skill(sd, id, level, flag); - + return true; } @@ -7540,22 +8128,21 @@ BUILDIN(addtoskill) /// /// guildskill <skill id>,<amount>; /// guildskill "<skill name>",<amount>; -BUILDIN(guildskill) -{ +BUILDIN(guildskill) { int id; int level; TBL_PC* sd; int i; - + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - - id = ( script_isstring(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); + + id = ( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); level = script_getnum(st,3); for( i=0; i < level; i++ ) guild->skillup(sd, id); - + return true; } @@ -7563,18 +8150,17 @@ BUILDIN(guildskill) /// /// getskilllv(<skill id>) -> <level> /// getskilllv("<skill name>") -> <level> -BUILDIN(getskilllv) -{ +BUILDIN(getskilllv) { int id; TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - - id = ( script_isstring(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); + + id = ( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); script_pushint(st, pc->checkskill(sd,id)); - + return true; } @@ -7582,20 +8168,19 @@ BUILDIN(getskilllv) /// /// getgdskilllv(<guild id>,<skill id>) -> <level> /// getgdskilllv(<guild id>,"<skill name>") -> <level> -BUILDIN(getgdskilllv) -{ +BUILDIN(getgdskilllv) { int guild_id; uint16 skill_id; struct guild* g; - + guild_id = script_getnum(st,2); - skill_id = ( script_isstring(st,3) ? skill->name2id(script_getstr(st,3)) : script_getnum(st,3) ); + skill_id = ( script_isstringtype(st,3) ? skill->name2id(script_getstr(st,3)) : script_getnum(st,3) ); g = guild->search(guild_id); if( g == NULL ) script_pushint(st, -1); else script_pushint(st, guild->checkskill(g,skill_id)); - + return true; } @@ -7616,13 +8201,13 @@ BUILDIN(basicskillcheck) BUILDIN(getgmlevel) { TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - - script_pushint(st, pc->get_group_level(sd)); - + + script_pushint(st, pc_get_group_level(sd)); + return true; } @@ -7632,12 +8217,12 @@ BUILDIN(getgmlevel) BUILDIN(getgroupid) { TBL_PC* sd; - + sd = script->rid2sd(st); if (sd == NULL) return false; // no player attached, report source script_pushint(st, pc_get_group_id(sd)); - + return true; } @@ -7656,17 +8241,17 @@ BUILDIN(checkoption) { int option; TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + option = script_getnum(st,2); if( sd->sc.option&option ) script_pushint(st, 1); else script_pushint(st, 0); - + return true; } @@ -7677,17 +8262,17 @@ BUILDIN(checkoption1) { int opt1; TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + opt1 = script_getnum(st,2); if( sd->sc.opt1 == opt1 ) script_pushint(st, 1); else script_pushint(st, 0); - + return true; } @@ -7698,17 +8283,17 @@ BUILDIN(checkoption2) { int opt2; TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + opt2 = script_getnum(st,2); if( sd->sc.opt2&opt2 ) script_pushint(st, 1); else script_pushint(st, 0); - + return true; } @@ -7724,28 +8309,28 @@ BUILDIN(setoption) int option; int flag = 1; TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + option = script_getnum(st,2); if( script_hasdata(st,3) ) flag = script_getnum(st,3); - else if( !option ){// Request to remove everything. + else if( !option ) {// Request to remove everything. flag = 0; option = OPTION_FALCON|OPTION_RIDING; #ifndef NEW_CARTS option |= OPTION_CART; #endif } - if( flag ){// Add option + if( flag ) {// Add option if( option&OPTION_WEDDING && !battle_config.wedding_modifydisplay ) option &= ~OPTION_WEDDING;// Do not show the wedding sprites pc->setoption(sd, sd->sc.option|option); } else// Remove option pc->setoption(sd, sd->sc.option&~option); - + return true; } @@ -7757,16 +8342,16 @@ BUILDIN(setoption) BUILDIN(checkcart) { TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + if( pc_iscarton(sd) ) script_pushint(st, 1); else script_pushint(st, 0); - + return true; } @@ -7785,15 +8370,15 @@ BUILDIN(setcart) { int type = 1; TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + if( script_hasdata(st,2) ) type = script_getnum(st,2); pc->setcart(sd, type); - + return true; } @@ -7805,16 +8390,16 @@ BUILDIN(setcart) BUILDIN(checkfalcon) { TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + if( pc_isfalcon(sd) ) script_pushint(st, 1); else script_pushint(st, 0); - + return true; } @@ -7827,16 +8412,16 @@ BUILDIN(setfalcon) { int flag = 1; TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + if( script_hasdata(st,2) ) flag = script_getnum(st,2); - + pc->setfalcon(sd, flag); - + return true; } @@ -7848,16 +8433,16 @@ BUILDIN(setfalcon) BUILDIN(checkriding) { TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + if( pc_isriding(sd) || pc_isridingwug(sd) || pc_isridingdragon(sd) ) script_pushint(st, 1); else script_pushint(st, 0); - + return true; } @@ -7870,15 +8455,15 @@ BUILDIN(setriding) { int flag = 1; TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + if( script_hasdata(st,2) ) flag = script_getnum(st,2); pc->setriding(sd, flag); - + return true; } @@ -7889,16 +8474,16 @@ BUILDIN(setriding) BUILDIN(checkwug) { TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + if( pc_iswug(sd) || pc_isridingwug(sd) ) script_pushint(st, 1); else script_pushint(st, 0); - + return true; } @@ -7909,16 +8494,16 @@ BUILDIN(checkwug) BUILDIN(checkmadogear) { TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + if( pc_ismadogear(sd) ) script_pushint(st, 1); else script_pushint(st, 0); - + return true; } @@ -7931,15 +8516,15 @@ BUILDIN(setmadogear) { int flag = 1; TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + if( script_hasdata(st,2) ) flag = script_getnum(st,2); pc->setmadogear(sd, flag); - + return true; } @@ -7953,18 +8538,18 @@ BUILDIN(savepoint) { short mapid; const char* str; TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + str = script_getstr(st,2); x = script_getnum(st,3); y = script_getnum(st,4); - mapid = mapindex_name2id(str); + mapid = mapindex->name2id(str); if( mapid ) pc->setsavepoint(sd, mapid, x, y); - + return true; } @@ -7975,10 +8560,10 @@ BUILDIN(gettimetick) { /* Asgard Version */ int type; time_t clock; struct tm *t; - + type=script_getnum(st,2); - - switch(type){ + + switch(type) { case 2: //type 2:(Get the number of seconds elapsed since 00:00 hours, Jan 1, 1970 UTC // from the system clock.) @@ -7993,7 +8578,7 @@ BUILDIN(gettimetick) { /* Asgard Version */ case 0: default: //type 0:(System Ticks) - script_pushint(st,timer->gettick()); + script_pushint(st,(int)timer->gettick()); // TODO: change this to int64 when we'll support 64 bit script values break; } return true; @@ -8008,13 +8593,13 @@ BUILDIN(gettime) { /* Asgard Version */ int type; time_t clock; struct tm *t; - + type=script_getnum(st,2); - + time(&clock); t=localtime(&clock); - - switch(type){ + + switch(type) { case 1://Sec(0~59) script_pushint(st,t->tm_sec); break; @@ -8055,14 +8640,14 @@ BUILDIN(gettimestr) const char *fmtstr; int maxlen; time_t now = time(NULL); - + fmtstr=script_getstr(st,2); maxlen=script_getnum(st,3); - + tmpstr=(char *)aMalloc((maxlen+1)*sizeof(char)); strftime(tmpstr,maxlen,fmtstr,localtime(&now)); tmpstr[maxlen]='\0'; - + script_pushstr(st,tmpstr); return true; } @@ -8072,11 +8657,11 @@ BUILDIN(gettimestr) *------------------------------------------*/ BUILDIN(openstorage) { TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true; - + storage->open(sd); return true; } @@ -8084,11 +8669,11 @@ BUILDIN(openstorage) { BUILDIN(guildopenstorage) { TBL_PC* sd; int ret; - + sd = script->rid2sd(st); if( sd == NULL ) return true; - + ret = gstorage->open(sd); script_pushint(st,ret); return true; @@ -8103,12 +8688,12 @@ BUILDIN(itemskill) { int id; int lv; TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL || sd->ud.skilltimer != INVALID_TIMER ) return true; - - id = ( script_isstring(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); + + id = ( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); lv = script_getnum(st,3); /* temporarily disabled, awaiting for kenpachi to detail this so we can make it work properly */ #if 0 @@ -8129,11 +8714,11 @@ BUILDIN(produce) { int trigger; TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true; - + trigger=script_getnum(st,2); clif->skill_produce_mix_list(sd, -1, trigger); return true; @@ -8145,11 +8730,11 @@ BUILDIN(cooking) { int trigger; TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true; - + trigger=script_getnum(st,2); clif->cooking_list(sd, trigger, AM_PHARMACY, 1, 1); return true; @@ -8161,25 +8746,24 @@ BUILDIN(makepet) { TBL_PC* sd; int id,pet_id; - + id=script_getnum(st,2); sd = script->rid2sd(st); if( sd == NULL ) return true; - + pet_id = pet->search_petDB_index(id, PET_CLASS); - + if (pet_id < 0) pet_id = pet->search_petDB_index(id, PET_EGG); if (pet_id >= 0 && sd) { 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, - 100, 0, 1, pet->db[pet_id].jname); + 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, + 100, 0, 1, pet->db[pet_id].jname); } - + return true; } /*========================================== @@ -8190,23 +8774,23 @@ BUILDIN(getexp) TBL_PC* sd; int base=0,job=0; double bonus; - + sd = script->rid2sd(st); if( sd == NULL ) return true; - + base=script_getnum(st,2); job =script_getnum(st,3); if(base<0 || job<0) return true; - + // bonus for npc-given exp bonus = battle_config.quest_exp_rate / 100.; base = (int) cap_value(base * bonus, 0, INT_MAX); job = (int) cap_value(job * bonus, 0, INT_MAX); - + pc->gainexp(sd, NULL, base, job, true); - + return true; } @@ -8217,17 +8801,17 @@ BUILDIN(guildgetexp) { TBL_PC* sd; int exp; - + sd = script->rid2sd(st); if( sd == NULL ) return true; - + exp = script_getnum(st,2); if(exp < 0) return true; if(sd && sd->status.guild_id > 0) guild->getexp (sd, exp); - + return true; } @@ -8238,49 +8822,49 @@ BUILDIN(guildchangegm) { TBL_PC *sd; int guild_id; const char *name; - + guild_id = script_getnum(st,2); name = script_getstr(st,3); sd=map->nick2sd(name); - + if (!sd) script_pushint(st,0); else script_pushint(st,guild->gm_change(guild_id, sd)); - + return true; } /*========================================== * Spawn a monster : - @mapn,x,y : location - @str : monster name - @class_ : mob_id - @amount : nb to spawn - @event : event to attach to mob + * @mapn,x,y : location + * @str : monster name + * @class_ : mob_id + * @amount : nb to spawn + * @event : event to attach to mob *------------------------------------------*/ BUILDIN(monster) { - const char* mapn = script_getstr(st,2); - int x = script_getnum(st,3); - int y = script_getnum(st,4); - const char* str = script_getstr(st,5); - int class_ = script_getnum(st,6); - int amount = script_getnum(st,7); - const char* event = ""; - unsigned int size = SZ_SMALL; - unsigned int ai = AI_NONE; + const char *mapn = script_getstr(st,2); + int x = script_getnum(st,3); + int y = script_getnum(st,4); + const char *str = script_getstr(st,5); + int class_ = script_getnum(st,6); + int amount = script_getnum(st,7); + const char *event = ""; + unsigned int size = SZ_MEDIUM; + unsigned int ai = AI_NONE; int mob_id; - + struct map_session_data* sd; int16 m; - + if (script_hasdata(st, 8)) { event = script_getstr(st, 8); script->check_event(st, event); } - + if (script_hasdata(st, 9)) { size = script_getnum(st, 9); @@ -8290,7 +8874,7 @@ BUILDIN(monster) return false; } } - + if (script_hasdata(st, 10)) { ai = script_getnum(st, 10); @@ -8300,15 +8884,15 @@ BUILDIN(monster) return false; } } - + if (class_ >= 0 && !mob->db_checkid(class_)) { ShowWarning("buildin_monster: Attempted to spawn non-existing monster class %d\n", class_); return false; } - + sd = map->id2sd(st->rid); - + if (sd && strcmp(mapn, "this") == 0) m = sd->bl.m; else { @@ -8316,7 +8900,7 @@ BUILDIN(monster) ShowWarning("buildin_monster: Attempted to spawn monster class %d on non-existing map '%s'\n",class_, mapn); return false; } - + if (map->list[m].flag.src4instance && st->instance_id >= 0) { // Try to redirect to the instance map, not the src map if ((m = instance->mapid2imapid(m, st->instance_id)) < 0) { ShowError("buildin_monster: Trying to spawn monster (%d) on instance map (%s) without instance attached.\n", class_, mapn); @@ -8324,7 +8908,7 @@ BUILDIN(monster) } } } - + mob_id = mob->once_spawn(sd, m, x, y, str, class_, amount, event, size, ai); script_pushint(st, mob_id); return true; @@ -8337,59 +8921,58 @@ BUILDIN(getmobdrops) int class_ = script_getnum(st,2); int i, j = 0; struct mob_db *monster; - + if( !mob->db_checkid(class_) ) { script_pushint(st, 0); return true; } - + monster = mob->db(class_); - + for( i = 0; i < MAX_MOB_DROP; i++ ) { if( monster->dropitem[i].nameid < 1 ) continue; 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); - + j++; } - + mapreg->setreg(script->add_str("$@MobDrop_count"), j); script_pushint(st, 1); - + return true; } /*========================================== * Same as monster but randomize location in x0,x1,y0,y1 area *------------------------------------------*/ -BUILDIN(areamonster) -{ - const char* mapn = script_getstr(st,2); - int x0 = script_getnum(st,3); - int y0 = script_getnum(st,4); - int x1 = script_getnum(st,5); - int y1 = script_getnum(st,6); - const char* str = script_getstr(st,7); - int class_ = script_getnum(st,8); - int amount = script_getnum(st,9); - const char* event = ""; - unsigned int size = SZ_SMALL; - unsigned int ai = AI_NONE; +BUILDIN(areamonster) { + const char *mapn = script_getstr(st,2); + int x0 = script_getnum(st,3); + int y0 = script_getnum(st,4); + int x1 = script_getnum(st,5); + int y1 = script_getnum(st,6); + const char *str = script_getstr(st,7); + int class_ = script_getnum(st,8); + int amount = script_getnum(st,9); + const char *event = ""; + unsigned int size = SZ_MEDIUM; + unsigned int ai = AI_NONE; int mob_id; - + struct map_session_data* sd; int16 m; - + if (script_hasdata(st,10)) { event = script_getstr(st, 10); script->check_event(st, event); } - + if (script_hasdata(st, 11)) { size = script_getnum(st, 11); if (size > 3) { @@ -8397,7 +8980,7 @@ BUILDIN(areamonster) return false; } } - + if (script_hasdata(st, 12)) { ai = script_getnum(st, 12); if (ai > 4) { @@ -8405,9 +8988,9 @@ BUILDIN(areamonster) return false; } } - + sd = map->id2sd(st->rid); - + if (sd && strcmp(mapn, "this") == 0) m = sd->bl.m; else { @@ -8422,10 +9005,10 @@ BUILDIN(areamonster) } } } - + mob_id = mob->once_spawn_area(sd, m, x0, y0, x1, y1, str, class_, amount, event, size, ai); script_pushint(st, mob_id); - + return true; } /*========================================== @@ -8436,13 +9019,13 @@ int buildin_killmonster_sub_strip(struct block_list *bl,va_list ap) TBL_MOB* md = (TBL_MOB*)bl; char *event=va_arg(ap,char *); int allflag=va_arg(ap,int); - + md->state.npc_killmonster = 1; - - if(!allflag){ + + if(!allflag) { if(strcmp(event,md->npc_event)==0) status_kill(bl); - }else{ + } else { if(!md->spawn) status_kill(bl); } @@ -8454,11 +9037,11 @@ int buildin_killmonster_sub(struct block_list *bl,va_list ap) TBL_MOB* md = (TBL_MOB*)bl; char *event=va_arg(ap,char *); int allflag=va_arg(ap,int); - - if(!allflag){ + + if(!allflag) { if(strcmp(event,md->npc_event)==0) status_kill(bl); - }else{ + } else { if(!md->spawn) status_kill(bl); } @@ -8473,20 +9056,20 @@ BUILDIN(killmonster) { allflag = 1; else script->check_event(st, event); - + if( (m=map->mapname2mapid(mapname))<0 ) return true; - + if( map->list[m].flag.src4instance && st->instance_id >= 0 && (m = instance->mapid2imapid(m, st->instance_id)) < 0 ) return true; - + if( script_hasdata(st,4) ) { if ( script_getnum(st,4) == 1 ) { map->foreachinmap(script->buildin_killmonster_sub, m, BL_MOB, event ,allflag); return true; } } - + map->freeblock_lock(); map->foreachinmap(script->buildin_killmonster_sub_strip, m, BL_MOB, event ,allflag); map->freeblock_unlock(); @@ -8496,11 +9079,11 @@ BUILDIN(killmonster) { 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; - + md = BL_CAST(BL_MOB, bl); if (md->npc_event[0]) md->npc_event[0] = 0; - + status_kill(bl); return 0; } @@ -8513,20 +9096,20 @@ BUILDIN(killmonsterall) { const char *mapname; int16 m; mapname=script_getstr(st,2); - + if( (m = map->mapname2mapid(mapname))<0 ) return true; - + if( map->list[m].flag.src4instance && st->instance_id >= 0 && (m = instance->mapid2imapid(m, st->instance_id)) < 0 ) return true; - + if( script_hasdata(st,3) ) { if ( script_getnum(st,3) == 1 ) { map->foreachinmap(script->buildin_killmonsterall_sub,m,BL_MOB); return true; } } - + map->foreachinmap(script->buildin_killmonsterall_sub_strip,m,BL_MOB); return true; } @@ -8540,32 +9123,32 @@ BUILDIN(clone) { int char_id,master_id=0,x,y, mode = 0, flag = 0, m; unsigned int duration = 0; const char *mapname, *event=""; - + mapname=script_getstr(st,2); x=script_getnum(st,3); y=script_getnum(st,4); event=script_getstr(st,5); char_id=script_getnum(st,6); - + if( script_hasdata(st,7) ) master_id=script_getnum(st,7); - + if( script_hasdata(st,8) ) mode=script_getnum(st,8); - + if( script_hasdata(st,9) ) flag=script_getnum(st,9); - + if( script_hasdata(st,10) ) duration=script_getnum(st,10); - + script->check_event(st, event); - + m = map->mapname2mapid(mapname); if (m < 0) return true; - + sd = map->charid2sd(char_id); - + if (master_id) { msd = map->charid2sd(master_id); if (msd) @@ -8577,7 +9160,7 @@ BUILDIN(clone) { script_pushint(st,mob->clone_spawn(sd, m, x, y, event, master_id, mode, flag, 1000*duration)); else //Failed to create clone. script_pushint(st,0); - + return true; } /*========================================== @@ -8586,12 +9169,12 @@ BUILDIN(doevent) { const char* event = script_getstr(st,2); struct map_session_data* sd; - + if( ( sd = script->rid2sd(st) ) == NULL ) { return true; } - + script->check_event(st, event); npc->event(sd, event, 0); return true; @@ -8612,9 +9195,8 @@ BUILDIN(donpcevent) } /// for Aegis compatibility -/// basically a specialized 'donpcevent', with the event specified as two arguments instead of one -BUILDIN(cmdothernpc) // Added by RoVeRT -{ +/// basically a specialized 'donpcevent', with the event specified as two arguments instead of one [RoVeRT] +BUILDIN(cmdothernpc) { const char* npc_name = script_getstr(st,2); const char* command = script_getstr(st,3); char event[EVENT_NAME_LENGTH]; @@ -8631,12 +9213,12 @@ BUILDIN(addtimer) int tick = script_getnum(st,2); const char* event = script_getstr(st, 3); TBL_PC* sd; - + script->check_event(st, event); sd = script->rid2sd(st); if( sd == NULL ) return true; - + pc->addeventtimer(sd,tick,event); return true; } @@ -8646,12 +9228,12 @@ BUILDIN(deltimer) { const char *event; TBL_PC* sd; - + event=script_getstr(st, 2); sd = script->rid2sd(st); if( sd == NULL ) return true; - + script->check_event(st, event); pc->deleventtimer(sd,event); return true; @@ -8663,13 +9245,13 @@ BUILDIN(addtimercount) const char *event; int tick; TBL_PC* sd; - + event=script_getstr(st, 2); tick=script_getnum(st,3); sd = script->rid2sd(st); if( sd == NULL ) return true; - + script->check_event(st, event); pc->addeventtimercount(sd,event,tick); return true; @@ -8681,17 +9263,16 @@ BUILDIN(initnpctimer) { struct npc_data *nd; int flag = 0; - - if( script_hasdata(st,3) ) - { //Two arguments: NPC name and attach flag. + + if( script_hasdata(st,3) ) { + //Two arguments: NPC name and attach flag. nd = npc->name2id(script_getstr(st, 2)); flag = script_getnum(st,3); - } - else if( script_hasdata(st,2) ) - { //Check if argument is numeric (flag) or string (npc name) + } else if( script_hasdata(st,2) ) { + //Check if argument is numeric (flag) or string (npc name) struct script_data *data; data = script_getdata(st,2); - script->get_val(st,data); + script->get_val(st,data); // dereference if it's a variable if( data_isstring(data) ) //NPC name nd = npc->name2id(script->conv_str(st, data)); else if( data_isint(data) ) { @@ -8704,7 +9285,7 @@ BUILDIN(initnpctimer) } } else nd = (struct npc_data *)map->id2bl(st->oid); - + if( !nd ) return true; if( flag ) //Attach @@ -8714,7 +9295,7 @@ BUILDIN(initnpctimer) return true; nd->u.scr.rid = sd->bl.id; } - + nd->u.scr.timertick = 0; npc->settimerevent_tick(nd,0); npc->timerevent_start(nd, st->rid); @@ -8726,17 +9307,16 @@ BUILDIN(startnpctimer) { struct npc_data *nd; int flag = 0; - - if( script_hasdata(st,3) ) - { //Two arguments: NPC name and attach flag. + + if( script_hasdata(st,3) ) { + //Two arguments: NPC name and attach flag. nd = npc->name2id(script_getstr(st, 2)); flag = script_getnum(st,3); - } - else if( script_hasdata(st,2) ) - { //Check if argument is numeric (flag) or string (npc name) + } else if( script_hasdata(st,2) ) { + //Check if argument is numeric (flag) or string (npc name) struct script_data *data; data = script_getdata(st,2); - script->get_val(st,data); + script->get_val(st,data); // dereference if it's a variable if( data_isstring(data) ) //NPC name nd = npc->name2id(script->conv_str(st, data)); else if( data_isint(data) ) { @@ -8749,7 +9329,7 @@ BUILDIN(startnpctimer) } } else nd=(struct npc_data *)map->id2bl(st->oid); - + if( !nd ) return true; if( flag ) //Attach @@ -8759,7 +9339,7 @@ BUILDIN(startnpctimer) return true; nd->u.scr.rid = sd->bl.id; } - + npc->timerevent_start(nd, st->rid); return true; } @@ -8768,17 +9348,16 @@ BUILDIN(startnpctimer) BUILDIN(stopnpctimer) { struct npc_data *nd; int flag = 0; - - if( script_hasdata(st,3) ) - { //Two arguments: NPC name and attach flag. + + if( script_hasdata(st,3) ) { + //Two arguments: NPC name and attach flag. nd = npc->name2id(script_getstr(st, 2)); flag = script_getnum(st,3); - } - else if( script_hasdata(st,2) ) - { //Check if argument is numeric (flag) or string (npc name) + } else if( script_hasdata(st,2) ) { + //Check if argument is numeric (flag) or string (npc name) struct script_data *data; data = script_getdata(st,2); - script->get_val(st,data); + script->get_val(st,data); // Dereference if it's a variable if( data_isstring(data) ) //NPC name nd = npc->name2id(script->conv_str(st, data)); else if( data_isint(data) ) { @@ -8791,12 +9370,12 @@ BUILDIN(stopnpctimer) { } } else nd=(struct npc_data *)map->id2bl(st->oid); - + if( !nd ) return true; if( flag ) //Detach nd->u.scr.rid = 0; - + npc->timerevent_stop(nd); return true; } @@ -8807,21 +9386,21 @@ BUILDIN(getnpctimer) { TBL_PC *sd; int type = script_getnum(st,2); int val = 0; - + if( script_hasdata(st,3) ) nd = npc->name2id(script_getstr(st,3)); else nd = (struct npc_data *)map->id2bl(st->oid); - + if( !nd || nd->bl.type != BL_NPC ) { script_pushint(st,0); ShowError("getnpctimer: Invalid NPC.\n"); return false; } - + switch( type ) { - case 0: val = npc->gettimerevent_tick(nd); break; + case 0: val = (int)npc->gettimerevent_tick(nd); break; // FIXME: change this to int64 when we'll support 64 bit script values case 1: if( nd->u.scr.rid ) { sd = map->id2sd(nd->u.scr.rid); @@ -8836,7 +9415,7 @@ BUILDIN(getnpctimer) { break; case 2: val = nd->u.scr.timeramount; break; } - + script_pushint(st,val); return true; } @@ -8846,19 +9425,19 @@ BUILDIN(setnpctimer) { int tick; struct npc_data *nd; - + tick = script_getnum(st,2); if( script_hasdata(st,3) ) nd = npc->name2id(script_getstr(st,3)); else nd = (struct npc_data *)map->id2bl(st->oid); - + if( !nd || nd->bl.type != BL_NPC ) { script_pushint(st,1); ShowError("setnpctimer: Invalid NPC.\n"); return false; } - + npc->settimerevent_tick(nd,tick); script_pushint(st,0); return true; @@ -8870,26 +9449,26 @@ BUILDIN(setnpctimer) BUILDIN(attachnpctimer) { TBL_PC *sd; struct npc_data *nd = (struct npc_data *)map->id2bl(st->oid); - + if( !nd || nd->bl.type != BL_NPC ) { script_pushint(st,1); ShowError("setnpctimer: Invalid NPC.\n"); return false; } - + if( script_hasdata(st,2) ) sd = map->nick2sd(script_getstr(st,2)); else sd = script->rid2sd(st); - + if( !sd ) { script_pushint(st,1); ShowWarning("attachnpctimer: Invalid player.\n"); return false; } - + nd->u.scr.rid = sd->bl.id; script_pushint(st,0); return true; @@ -8900,19 +9479,19 @@ BUILDIN(attachnpctimer) { *------------------------------------------*/ BUILDIN(detachnpctimer) { struct npc_data *nd; - + if( script_hasdata(st,2) ) nd = npc->name2id(script_getstr(st,2)); else nd = (struct npc_data *)map->id2bl(st->oid); - + if( !nd || nd->bl.type != BL_NPC ) { script_pushint(st,1); ShowError("detachnpctimer: Invalid NPC.\n"); return false; } - + nd->u.scr.rid = 0; script_pushint(st,0); return true; @@ -8941,14 +9520,14 @@ BUILDIN(announce) { int fontSize = script_hasdata(st,6) ? script_getnum(st,6) : 12; // default fontSize int fontAlign = script_hasdata(st,7) ? script_getnum(st,7) : 0; // default fontAlign int fontY = script_hasdata(st,8) ? script_getnum(st,8) : 0; // default fontY - + if( flag&(BC_TARGET_MASK|BC_SOURCE_MASK) ) { // Broadcast source or broadcast region defined send_target target; struct block_list *bl = (flag&BC_NPC) ? map->id2bl(st->oid) : (struct block_list *)script->rid2sd(st); // If bc_npc flag is set, use NPC as broadcast source if (bl == NULL) return true; - + switch( flag&BC_TARGET_MASK ) { case BC_MAP: target = ALL_SAMEMAP; break; case BC_AREA: target = AREA; break; @@ -8957,12 +9536,12 @@ BUILDIN(announce) { } if (fontColor) - clif->broadcast2(bl, mes, (int)strlen(mes)+1, strtol(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY, target); + clif->broadcast2(bl, mes, (int)strlen(mes)+1, (unsigned int)strtoul(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY, target); else clif->broadcast(bl, mes, (int)strlen(mes)+1, flag&BC_COLOR_MASK, target); } else { if (fontColor) - intif->broadcast2(mes, (int)strlen(mes)+1, strtol(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY); + intif->broadcast2(mes, (int)strlen(mes)+1, (unsigned int)strtoul(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY); else intif->broadcast(mes, (int)strlen(mes)+1, flag&BC_COLOR_MASK); } @@ -8981,7 +9560,7 @@ int buildin_announce_sub(struct block_list *bl, va_list ap) short fontAlign = (short)va_arg(ap, int); short fontY = (short)va_arg(ap, int); if (fontColor) - clif->broadcast2(bl, mes, len, strtol(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY, SELF); + clif->broadcast2(bl, mes, len, (unsigned int)strtoul(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY, SELF); else clif->broadcast(bl, mes, len, type, SELF); return 0; @@ -8992,36 +9571,29 @@ int buildin_announce_sub(struct block_list *bl, va_list ap) BUILDIN(itemeffect) { TBL_NPC *nd; TBL_PC *sd; - struct script_data *data; struct item_data *item_data; - - nullpo_retr( 1, ( sd = script->rid2sd( st ) ) ); - nullpo_retr( 1, ( nd = (TBL_NPC *)map->id2bl( sd->npc_id ) ) ); - - data = script_getdata( st, 2 ); - script->get_val( st, data ); - - if( data_isstring( data ) ){ - const char *name = script->conv_str( st, data ); - - if( ( item_data = itemdb->search_name( name ) ) == NULL ){ + + nullpo_retr( false, ( sd = script->rid2sd( st ) ) ); + nullpo_retr( false, ( nd = (TBL_NPC *)map->id2bl( sd->npc_id ) ) ); + + if( script_isstringtype(st, 2) ) { + const char *name = script_getstr(st, 2); + + if( ( item_data = itemdb->search_name( name ) ) == NULL ) { ShowError( "buildin_itemeffect: Nonexistant item %s requested.\n", name ); return false; } - } else if( data_isint( data ) ){ - int nameid = script->conv_num( st, data ); - - if( ( item_data = itemdb->exists( nameid ) ) == NULL ){ + } else { + int nameid = script_getnum(st, 2); + + if( ( item_data = itemdb->exists( nameid ) ) == NULL ) { ShowError("buildin_itemeffect: Nonexistant item %d requested.\n", nameid ); return false; } - } else { - ShowError("buildin_itemeffect: invalid data type for argument #1 (%d).", data->type ); - return false; } - + script->run( item_data->script, 0, sd->bl.id, nd->bl.id ); - + return true; } @@ -9035,10 +9607,10 @@ BUILDIN(mapannounce) { int fontAlign = script_hasdata(st,8) ? script_getnum(st,8) : 0; // default fontAlign int fontY = script_hasdata(st,9) ? script_getnum(st,9) : 0; // default fontY int16 m; - + if ((m = map->mapname2mapid(mapname)) < 0) return true; - + map->foreachinmap(script->buildin_announce_sub, m, BL_PC, mes, strlen(mes)+1, flag&BC_COLOR_MASK, fontColor, fontType, fontSize, fontAlign, fontY); return true; @@ -9059,10 +9631,10 @@ BUILDIN(areaannounce) { int fontAlign = script_hasdata(st,12) ? script_getnum(st,12) : 0; // default fontAlign int fontY = script_hasdata(st,13) ? script_getnum(st,13) : 0; // default fontY int16 m; - + if ((m = map->mapname2mapid(mapname)) < 0) return true; - + map->foreachinarea(script->buildin_announce_sub, m, x0, y0, x1, y1, BL_PC, mes, strlen(mes)+1, flag&BC_COLOR_MASK, fontColor, fontType, fontSize, fontAlign, fontY); return true; @@ -9074,9 +9646,9 @@ BUILDIN(getusers) { int flag, val = 0; struct map_session_data* sd; struct block_list* bl = NULL; - + flag = script_getnum(st,2); - + switch(flag&0x07) { case 0: if(flag&0x8) { @@ -9086,7 +9658,7 @@ BUILDIN(getusers) { // pc bl = &sd->bl; } - + if(bl) { val = map->list[bl->m].users; } @@ -9099,7 +9671,7 @@ BUILDIN(getusers) { script_pushint(st,0); return false; } - + script_pushint(st,val); return true; } @@ -9111,17 +9683,17 @@ BUILDIN(getusersname) TBL_PC *sd, *pl_sd; int /*disp_num=1,*/ group_level = 0; struct s_mapiterator* iter; - + sd = script->rid2sd(st); if (!sd) return true; - - group_level = pc->get_group_level(sd); + + group_level = pc_get_group_level(sd); iter = mapit_getallusers(); for( pl_sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); pl_sd = (TBL_PC*)mapit->next(iter) ) { - if (pc->has_permission(pl_sd, PC_PERM_HIDE_SESSION) && pc->get_group_level(pl_sd) > group_level) + if (pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) && pc_get_group_level(pl_sd) > group_level) continue; // skip hidden sessions - + /* Temporary fix for bugreport:1023. * Do not uncomment unless you want thousands of 'next' buttons. if((disp_num++)%10==0) @@ -9129,7 +9701,7 @@ BUILDIN(getusersname) clif->scriptmes(sd,st->oid,pl_sd->status.name); } mapit->free(iter); - + return true; } /*========================================== @@ -9149,15 +9721,15 @@ BUILDIN(getmapguildusers) return true; } g = guild->search(gid); - - if (g){ + + if (g) { for(i = 0; i < g->max_member; i++) { if (g->member[i].sd && g->member[i].sd->bl.m == m) c++; } } - + script_pushint(st,c); return true; } @@ -9167,7 +9739,7 @@ BUILDIN(getmapusers) { const char *str; int16 m; str=script_getstr(st,2); - if( (m=map->mapname2mapid(str))< 0){ + if( (m=map->mapname2mapid(str))< 0) { script_pushint(st,-1); return true; } @@ -9191,7 +9763,7 @@ BUILDIN(getareausers) y0=script_getnum(st,4); x1=script_getnum(st,5); y1=script_getnum(st,6); - if( (m=map->mapname2mapid(str))< 0){ + if( (m=map->mapname2mapid(str))< 0) { script_pushint(st,-1); return true; } @@ -9208,37 +9780,34 @@ int buildin_getareadropitem_sub(struct block_list *bl,va_list ap) int item=va_arg(ap,int); int *amount=va_arg(ap,int *); struct flooritem_data *drop=(struct flooritem_data *)bl; - + if(drop->item_data.nameid==item) (*amount)+=drop->item_data.amount; - + return 0; } -BUILDIN(getareadropitem) -{ +BUILDIN(getareadropitem) { const char *str; int16 m,x0,y0,x1,y1; int item,amount=0; - struct script_data *data; - + str=script_getstr(st,2); x0=script_getnum(st,3); y0=script_getnum(st,4); x1=script_getnum(st,5); y1=script_getnum(st,6); - - data=script_getdata(st,7); - script->get_val(st,data); - if( data_isstring(data) ){ - const char *name=script->conv_str(st,data); + + if( script_isstringtype(st, 7) ) { + const char *name = script_getstr(st, 7); struct item_data *item_data = itemdb->search_name(name); item=UNKNOWN_ITEM_ID; if( item_data ) item=item_data->nameid; - }else - item=script->conv_num(st,data); - - if( (m=map->mapname2mapid(str))< 0){ + } else { + item=script_getnum(st, 7); + } + + if( (m=map->mapname2mapid(str))< 0) { script_pushint(st,-1); return true; } @@ -9294,7 +9863,7 @@ BUILDIN(sc_start) { int tick; int val1; int val4 = 0; - + type = (sc_type)script_getnum(st,2); tick = script_getnum(st,3); val1 = script_getnum(st,4); @@ -9302,22 +9871,22 @@ BUILDIN(sc_start) { bl = map->id2bl(script_getnum(st,5)); else bl = map->id2bl(st->rid); - + if( tick == 0 && val1 > 0 && type > SC_NONE && type < SC_MAX && status->sc2skill(type) != 0 ) { // When there isn't a duration specified, try to get it from the skill_db tick = skill->get_time(status->sc2skill(type), val1); } - + if( script->potion_flag == 1 && script->potion_target ) { //skill.c set the flags before running the script, this must be a potion-pitched effect. bl = map->id2bl(script->potion_target); tick /= 2;// Thrown potions only last half. val4 = 1;// Mark that this was a thrown sc_effect } - + if( bl ) - status->change_start(bl, type, 10000, val1, 0, 0, val4, tick, 2); - + status->change_start(NULL, bl, type, 10000, val1, 0, 0, val4, tick, 2); + return true; } @@ -9331,7 +9900,7 @@ BUILDIN(sc_start2) { int val1; int val4 = 0; int rate; - + type = (sc_type)script_getnum(st,2); tick = script_getnum(st,3); val1 = script_getnum(st,4); @@ -9340,22 +9909,22 @@ BUILDIN(sc_start2) { bl = map->id2bl(script_getnum(st,6)); else bl = map->id2bl(st->rid); - + if( tick == 0 && val1 > 0 && type > SC_NONE && type < SC_MAX && status->sc2skill(type) != 0 ) { // When there isn't a duration specified, try to get it from the skill_db tick = skill->get_time(status->sc2skill(type), val1); } - + if( script->potion_flag == 1 && script->potion_target ) { //skill.c set the flags before running the script, this must be a potion-pitched effect. bl = map->id2bl(script->potion_target); tick /= 2;// Thrown potions only last half. val4 = 1;// Mark that this was a thrown sc_effect } - + if( bl ) - status->change_start(bl, type, rate, val1, 0, 0, val4, tick, 2); - + status->change_start(NULL, bl, type, rate, val1, 0, 0, val4, tick, 2); + return true; } @@ -9370,7 +9939,7 @@ BUILDIN(sc_start4) { int val2; int val3; int val4; - + type = (sc_type)script_getnum(st,2); tick = script_getnum(st,3); val1 = script_getnum(st,4); @@ -9381,21 +9950,21 @@ BUILDIN(sc_start4) { bl = map->id2bl(script_getnum(st,8)); else bl = map->id2bl(st->rid); - + if( tick == 0 && val1 > 0 && type > SC_NONE && type < SC_MAX && status->sc2skill(type) != 0 ) { // When there isn't a duration specified, try to get it from the skill_db tick = skill->get_time(status->sc2skill(type), val1); } - + if( script->potion_flag == 1 && script->potion_target ) { //skill.c set the flags before running the script, this must be a potion-pitched effect. bl = map->id2bl(script->potion_target); tick /= 2;// Thrown potions only last half. } - + if( bl ) - status->change_start(bl, type, 10000, val1, val2, val3, val4, tick, 2); - + status->change_start(NULL, bl, type, 10000, val1, val2, val3, val4, tick, 2); + return true; } @@ -9405,26 +9974,27 @@ BUILDIN(sc_start4) { BUILDIN(sc_end) { struct block_list* bl; int type; - + type = script_getnum(st, 2); if (script_hasdata(st, 3)) bl = map->id2bl(script_getnum(st, 3)); else bl = map->id2bl(st->rid); - + if (script->potion_flag == 1 && script->potion_target) //##TODO how does this work [FlavioJS] bl = map->id2bl(script->potion_target); - + if (!bl) return true; - + if (type >= 0 && type < SC_MAX) { struct status_change *sc = status->get_sc(bl); struct status_change_entry *sce = sc ? sc->data[type] : NULL; - + if (!sce) return true; - + + /* status that can't be individually removed (TODO sc_config option?) */ switch (type) { case SC_WEIGHTOVER50: case SC_WEIGHTOVER90: @@ -9434,14 +10004,14 @@ BUILDIN(sc_end) { default: break; } - + //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; status_change_end(bl, (sc_type)type, INVALID_TIMER); } else status->change_clear(bl, 3); // remove all effects - + return true; } @@ -9451,17 +10021,17 @@ BUILDIN(sc_end) { BUILDIN(getscrate) { struct block_list *bl; int type,rate; - + type=script_getnum(st,2); rate=script_getnum(st,3); if( script_hasdata(st,4) ) //get for the bl assigned bl = map->id2bl(script_getnum(st,4)); else bl = map->id2bl(st->rid); - + if (bl) - rate = status->get_sc_def(bl, (sc_type)type, 10000, 10000, 0); - + rate = status->get_sc_def(bl, bl, (sc_type)type, 10000, 10000, 0); + script_pushint(st,rate); return true; } @@ -9473,45 +10043,45 @@ BUILDIN(getstatus) { int id, type; struct map_session_data* sd = script->rid2sd(st); - + if( sd == NULL ) {// no player attached return true; } - + id = script_getnum(st, 2); type = script_hasdata(st, 3) ? script_getnum(st, 3) : 0; - + if( id <= SC_NONE || id >= SC_MAX ) {// invalid status type given ShowWarning("script.c:getstatus: Invalid status type given (%d).\n", id); return true; } - + if( sd->sc.count == 0 || !sd->sc.data[id] ) {// no status is active script_pushint(st, 0); return true; } - + switch( type ) { - case 1: script_pushint(st, sd->sc.data[id]->val1); break; - case 2: script_pushint(st, sd->sc.data[id]->val2); break; - case 3: script_pushint(st, sd->sc.data[id]->val3); break; - case 4: script_pushint(st, sd->sc.data[id]->val4); break; + case 1: script_pushint(st, sd->sc.data[id]->val1); break; + case 2: script_pushint(st, sd->sc.data[id]->val2); break; + case 3: script_pushint(st, sd->sc.data[id]->val3); break; + case 4: script_pushint(st, sd->sc.data[id]->val4); break; case 5: { struct TimerData* td = (struct TimerData*)timer->get(sd->sc.data[id]->timer); - + if( td ) { // return the amount of time remaining - script_pushint(st, td->tick - timer->gettick()); + 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; } - + return true; } @@ -9532,12 +10102,12 @@ BUILDIN(catchpet) { int pet_id; TBL_PC *sd; - + pet_id= script_getnum(st,2); sd=script->rid2sd(st); if( sd == NULL ) return true; - + pet->catch_process1(sd,pet_id); return true; } @@ -9548,11 +10118,11 @@ BUILDIN(catchpet) BUILDIN(homunculus_evolution) { TBL_PC *sd; - + sd=script->rid2sd(st); if( sd == NULL ) return true; - + if(homun_alive(sd->hd)) { if (sd->hd->homunculus.intimacy > 91000) homun->evolve(sd->hd); @@ -9564,44 +10134,82 @@ BUILDIN(homunculus_evolution) /*========================================== * [Xantara] + * Checks for vaporized morph state + * and deletes ITEMID_STRANGE_EMBRYO. *------------------------------------------*/ BUILDIN(homunculus_mutate) { int homun_id; enum homun_type m_class, m_id; TBL_PC *sd; - + bool success = false; + sd = script->rid2sd(st); if( sd == NULL || sd->hd == NULL ) return true; - - if( script_hasdata(st,2) ) - homun_id = script_getnum(st,2); - else - homun_id = 6048 + (rnd() % 4); - - if( homun_alive(sd->hd) ) { + + if( sd->hd->homunculus.vaporize == HOM_ST_MORPH ) { + int i = pc->search_inventory(sd, ITEMID_STRANGE_EMBRYO); + if( script_hasdata(st,2) ) + homun_id = script_getnum(st,2); + else + homun_id = 6048 + (rnd() % 4); + m_class = homun->class2type(sd->hd->homunculus.class_); m_id = homun->class2type(homun_id); - - if( m_class != HT_INVALID && m_id != HT_INVALID && m_class == HT_EVO && m_id == HT_S && sd->hd->homunculus.level >= 99 ) + + if( m_class == HT_EVO && m_id == HT_S && + sd->hd->homunculus.level >= 99 && i >= 0 && + !pc->delitem(sd, i, 1, 0, 0, LOG_TYPE_SCRIPT) ) { + sd->hd->homunculus.vaporize = HOM_ST_REST; // Remove morph state. + homun->call(sd); // Respawn homunculus. homun->mutate(sd->hd, homun_id); - else + success = true; + } else clif->emotion(&sd->hd->bl, E_SWT); - } + } else + clif->emotion(&sd->hd->bl, E_SWT); + + script_pushint(st,success?1:0); return true; } -// [Zephyrus] -BUILDIN(homunculus_shuffle) { +/*========================================== + * Puts homunculus into morph state + * and gives ITEMID_STRANGE_EMBRYO. + *------------------------------------------*/ +BUILDIN(homunculus_morphembryo) { + enum homun_type m_class; + int i = 0; TBL_PC *sd; - - sd=script->rid2sd(st); - if( sd == NULL ) + bool success = false; + + sd = script->rid2sd(st); + if( sd == NULL || sd->hd == NULL ) return true; - - if(homun_alive(sd->hd)) - homun->shuffle(sd->hd); - + + if( homun_alive(sd->hd) ) { + m_class = homun->class2type(sd->hd->homunculus.class_); + + if ( m_class == HT_EVO && sd->hd->homunculus.level >= 99 ) { + struct item item_tmp; + + memset(&item_tmp, 0, sizeof(item_tmp)); + item_tmp.nameid = ITEMID_STRANGE_EMBRYO; + item_tmp.identify = 1; + + if( (i = pc->additem(sd, &item_tmp, 1, LOG_TYPE_SCRIPT)) ) { + clif->additem(sd, 0, 0, i); + clif->emotion(&sd->hd->bl, E_SWT); + } else { + homun->vaporize(sd, HOM_ST_MORPH); + success = true; + } + } else + clif->emotion(&sd->hd->bl, E_SWT); + } else + clif->emotion(&sd->hd->bl, E_SWT); + + script_pushint(st, success?1:0); return true; } @@ -9612,20 +10220,28 @@ BUILDIN(homunculus_shuffle) { * 1 = Homunculus is vaporized (rest) * 2 = Homunculus is in morph state *------------------------------------------*/ -BUILDIN(checkhomcall) -{ +BUILDIN(homunculus_checkcall) { TBL_PC *sd = script->rid2sd(st); - TBL_HOM *hd; - if( sd == NULL ) - return false; - - hd = sd->hd; - - if( !hd ) + if( sd == NULL || !sd->hd ) script_pushint(st, -1); else - script_pushint(st, hd->homunculus.vaporize); + script_pushint(st, sd->hd->homunculus.vaporize); + + return true; +} + + +// [Zephyrus] +BUILDIN(homunculus_shuffle) { + TBL_PC *sd; + + sd=script->rid2sd(st); + if( sd == NULL ) + return true; + + if(homun_alive(sd->hd)) + homun->shuffle(sd->hd); return true; } @@ -9675,12 +10291,12 @@ BUILDIN(birthpet) sd=script->rid2sd(st); if( sd == NULL ) return true; - + if( sd->status.pet_id ) {// do not send egg list, when you already have a pet return true; } - + clif->sendegg(sd); return true; } @@ -9688,21 +10304,21 @@ BUILDIN(birthpet) /*========================================== * Added - AppleGirl For Advanced Classes, (Updated for Cleaner Script Purposes) * @type - * 1 : make like after rebirth - * 2 : blvl,jlvl=1, skillpoint=0 - * 3 : don't reset skill, blvl=1 - * 4 : jlvl=0 + * 1 : make like after rebirth + * 2 : blvl,jlvl=1, skillpoint=0 + * 3 : don't reset skill, blvl=1 + * 4 : jlvl=0 *------------------------------------------*/ BUILDIN(resetlvl) { TBL_PC *sd; - + int type=script_getnum(st,2); - + sd=script->rid2sd(st); if( sd == NULL ) return true; - + pc->resetlvl(sd,type); return true; } @@ -9745,15 +10361,15 @@ BUILDIN(skillpointcount) BUILDIN(changebase) { TBL_PC *sd=NULL; int vclass; - + if( script_hasdata(st,3) ) sd=map->id2sd(script_getnum(st,3)); else sd=script->rid2sd(st); - + if(sd == NULL) return true; - + vclass = script_getnum(st,2); if(vclass == JOB_WEDDING) { @@ -9762,7 +10378,7 @@ BUILDIN(changebase) { ) return true; } - + if(sd->disguise == -1 && vclass != sd->vd.class_) { status->set_viewdata(&sd->bl, vclass); //Updated client view. Base, Weapon and Cloth Colors. @@ -9772,7 +10388,7 @@ BUILDIN(changebase) { clif->changelook(&sd->bl,LOOK_CLOTHES_COLOR,sd->vd.cloth_color); clif->skillinfoblock(sd); } - + return true; } @@ -9784,7 +10400,7 @@ BUILDIN(changesex) int i; TBL_PC *sd = NULL; sd = script->rid2sd(st); - + pc->resetskill(sd,4); // to avoid any problem with equipment and invalid sex, equipment is unequiped. for( i=0; i<EQI_MAX; i++ ) @@ -9800,18 +10416,19 @@ BUILDIN(globalmes) { struct block_list *bl = map->id2bl(st->oid); struct npc_data *nd = (struct npc_data *)bl; const char *name=NULL,*mes; - + mes=script_getstr(st,2); if(mes==NULL) return true; - - if(script_hasdata(st,3)){ // npc name to display + + if(script_hasdata(st,3)) { + // npc name to display name=script_getstr(st,3); } else { name=nd->name; //use current npc name } - - npc->globalmessage(name,mes); // broadcast to all players connected - + + npc->globalmessage(name,mes); // broadcast to all players connected + return true; } @@ -9832,11 +10449,11 @@ BUILDIN(waitingroom) { int zeny = script_hasdata(st,6) ? script_getnum(st,6) : 0; int minLvl = script_hasdata(st,7) ? script_getnum(st,7) : 1; int maxLvl = script_hasdata(st,8) ? script_getnum(st,8) : MAX_LEVEL; - + nd = (struct npc_data *)map->id2bl(st->oid); if( nd != NULL ) chat->create_npc_chat(nd, title, limit, pub, trigger, ev, zeny, minLvl, maxLvl); - + return true; } @@ -9862,12 +10479,12 @@ BUILDIN(delwaitingroom) { BUILDIN(waitingroomkickall) { struct npc_data* nd; struct chat_data* cd; - + if( script_hasdata(st,2) ) nd = npc->name2id(script_getstr(st,2)); else nd = (struct npc_data *)map->id2bl(st->oid); - + if( nd != NULL && (cd=(struct chat_data *)map->id2bl(nd->chat_id)) != NULL ) chat->npc_kick_all(cd); return true; @@ -9880,12 +10497,12 @@ BUILDIN(waitingroomkickall) { BUILDIN(enablewaitingroomevent) { struct npc_data* nd; struct chat_data* cd; - + if( script_hasdata(st,2) ) nd = npc->name2id(script_getstr(st, 2)); else nd = (struct npc_data *)map->id2bl(st->oid); - + if( nd != NULL && (cd=(struct chat_data *)map->id2bl(nd->chat_id)) != NULL ) chat->enable_event(cd); return true; @@ -9898,12 +10515,12 @@ BUILDIN(enablewaitingroomevent) { BUILDIN(disablewaitingroomevent) { struct npc_data *nd; struct chat_data *cd; - + if( script_hasdata(st,2) ) nd = npc->name2id(script_getstr(st, 2)); else nd = (struct npc_data *)map->id2bl(st->oid); - + if( nd != NULL && (cd=(struct chat_data *)map->id2bl(nd->chat_id)) != NULL ) chat->disable_event(cd); return true; @@ -9927,18 +10544,18 @@ BUILDIN(getwaitingroomstate) { struct npc_data *nd; struct chat_data *cd; int type; - + type = script_getnum(st,2); if( script_hasdata(st,3) ) nd = npc->name2id(script_getstr(st, 3)); else nd = (struct npc_data *)map->id2bl(st->oid); - + if( nd == NULL || (cd=(struct chat_data *)map->id2bl(nd->chat_id)) == NULL ) { script_pushint(st, -1); return true; } - + switch(type) { case 0: script_pushint(st, cd->users); break; case 1: script_pushint(st, cd->limit); break; @@ -9975,27 +10592,27 @@ BUILDIN(warpwaitingpc) { struct npc_data* nd; struct chat_data* cd; TBL_PC* sd; - + nd = (struct npc_data *)map->id2bl(st->oid); if( nd == NULL || (cd=(struct chat_data *)map->id2bl(nd->chat_id)) == NULL ) return true; - + map_name = script_getstr(st,2); x = script_getnum(st,3); y = script_getnum(st,4); n = cd->trigger&0x7f; - + if( script_hasdata(st,5) ) n = script_getnum(st,5); - + for( i = 0; i < n && cd->users > 0; i++ ) { sd = cd->usersd[0]; - + if( strcmp(map_name,"SavePoint") == 0 && map->list[sd->bl.m].flag.noteleport ) { // can't teleport on this map break; } - + if( cd->zeny ) { // fee set if( (uint32)sd->status.zeny < cd->zeny ) { @@ -10004,15 +10621,15 @@ BUILDIN(warpwaitingpc) { } pc->payzeny(sd, cd->zeny, LOG_TYPE_NPC, NULL); } - + mapreg->setreg(reference_uid(script->add_str("$@warpwaitingpc"), i), sd->bl.id); - + if( strcmp(map_name,"Random") == 0 ) pc->randomwarp(sd,CLR_TELEPORT); else if( strcmp(map_name,"SavePoint") == 0 ) pc->setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT); else - pc->setpos(sd, mapindex_name2id(map_name), x, y, CLR_OUTSIGHT); + pc->setpos(sd, mapindex->name2id(map_name), x, y, CLR_OUTSIGHT); } mapreg->setreg(script->add_str("$@warpwaitingpcnum"), i); return true; @@ -10037,10 +10654,10 @@ void script_detach_rid(struct script_state* st) { *------------------------------------------*/ BUILDIN(attachrid) { int rid = script_getnum(st,2); - + if (map->id2sd(rid) != NULL) { script->detach_rid(st); - + st->rid = rid; script->attach_state(st); script_pushint(st,1); @@ -10074,23 +10691,23 @@ BUILDIN(isloggedin) { *------------------------------------------*/ BUILDIN(setmapflagnosave) { int16 m,x,y; - unsigned short mapindex; + unsigned short map_index; const char *str,*str2; - + str=script_getstr(st,2); str2=script_getstr(st,3); x=script_getnum(st,4); y=script_getnum(st,5); m = map->mapname2mapid(str); - mapindex = mapindex_name2id(str2); - - if(m >= 0 && mapindex) { + map_index = mapindex->name2id(str2); + + if(m >= 0 && map_index) { map->list[m].flag.nosave=1; - map->list[m].save.map=mapindex; + map->list[m].save.map=map_index; map->list[m].save.x=x; map->list[m].save.y=y; } - + return true; } @@ -10098,10 +10715,10 @@ BUILDIN(getmapflag) { int16 m,i; const char *str; - + str=script_getstr(st,2); i=script_getnum(st,3); - + m = map->mapname2mapid(str); if(m >= 0) { switch(i) { @@ -10155,9 +10772,10 @@ BUILDIN(getmapflag) case MF_BATTLEGROUND: script_pushint(st,map->list[m].flag.battleground); break; 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; } } - + return true; } /* pvp timer handling */ @@ -10178,26 +10796,24 @@ int script_mapflag_pvp_sub(struct block_list *bl,va_list ap) { BUILDIN(setmapflag) { int16 m,i; const char *str, *val2 = NULL; - struct script_data* data; int val=0; - + str=script_getstr(st,2); - + i = script_getnum(st, 3); - - if(script_hasdata(st,4)) { - data = script_getdata(st,4); - script->get_val(st, data); - - - if( data_isstring(data) ) + + if (script_hasdata(st,4)) { + if (script_isstringtype(st, 4)) { val2 = script_getstr(st, 4); - else + } else if (script_isinttype(st, 4)) { val = script_getnum(st, 4); - + } else { + ShowError("buildin_setmapflag: invalid data type for argument 3.\n"); + return false; + } } m = map->mapname2mapid(str); - + if(m >= 0) { switch(i) { case MF_NOMEMO: map->list[m].flag.nomemo = 1; break; @@ -10246,13 +10862,14 @@ BUILDIN(setmapflag) { case MF_NORETURN: map->list[m].flag.noreturn = 1; break; case MF_NOWARPTO: map->list[m].flag.nowarpto = 1; break; case MF_NIGHTMAREDROP: map->list[m].flag.pvp_nightmaredrop = 1; break; - case MF_ZONE: { - char zone[6] = "zone\0"; - char empty[1] = "\0"; - char params[MAP_ZONE_MAPFLAG_LENGTH]; - memcpy(params, val2, MAP_ZONE_MAPFLAG_LENGTH); - npc->parse_mapflag(map->list[m].name, empty, zone, params, empty, empty, empty); - } + case MF_ZONE: + if( val2 ) { + char zone[6] = "zone\0"; + char empty[1] = "\0"; + char params[MAP_ZONE_MAPFLAG_LENGTH]; + memcpy(params, val2, MAP_ZONE_MAPFLAG_LENGTH); + npc->parse_mapflag(map->list[m].name, empty, zone, params, empty, empty, empty); + } break; case MF_NOCOMMAND: map->list[m].nocommand = (val <= 0) ? 100 : val; break; case MF_NODROP: map->list[m].flag.nodrop = 1; break; @@ -10271,16 +10888,17 @@ BUILDIN(setmapflag) { case MF_BATTLEGROUND: map->list[m].flag.battleground = (val <= 0 || val > 2) ? 1 : val; break; 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; } } - + return true; } BUILDIN(removemapflag) { int16 m,i; const char *str; - + str=script_getstr(st,2); i=script_getnum(st,3); @@ -10356,9 +10974,10 @@ BUILDIN(removemapflag) { case MF_BATTLEGROUND: map->list[m].flag.battleground = 0; break; 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; } } - + return true; } @@ -10368,34 +10987,34 @@ BUILDIN(pvpon) { TBL_PC* sd = NULL; struct s_mapiterator* iter; struct block_list bl; - + str = script_getstr(st,2); m = map->mapname2mapid(str); if( m < 0 || map->list[m].flag.pvp ) return true; // nothing to do - + if( !strdb_exists(map->zone_db,MAP_ZONE_PVP_NAME) ) { ShowError("buildin_pvpon: zone_db missing '%s'\n",MAP_ZONE_PVP_NAME); return true; } - + map->zone_change2(m, strdb_get(map->zone_db, MAP_ZONE_PVP_NAME)); map->list[m].flag.pvp = 1; clif->map_property_mapall(m, MAPPROPERTY_FREEPVPZONE); bl.type = BL_NUL; bl.m = m; clif->maptypeproperty2(&bl,ALL_SAMEMAP); - - + + if(battle_config.pk_mode) // disable ranking functions if pk_mode is on [Valaris] return true; - + iter = mapit_getallusers(); for( sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); sd = (TBL_PC*)mapit->next(iter) ) { 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); sd->pvp_rank = 0; sd->pvp_lastusers = 0; @@ -10404,7 +11023,7 @@ BUILDIN(pvpon) { sd->pvp_lost = 0; } mapit->free(iter); - + return true; } @@ -10423,22 +11042,22 @@ BUILDIN(pvpoff) { int16 m; const char *str; struct block_list bl; - + str=script_getstr(st,2); m = map->mapname2mapid(str); if(m < 0 || !map->list[m].flag.pvp) return true; //fixed Lupus - + map->zone_change2(m, map->list[m].prev_zone); map->list[m].flag.pvp = 0; clif->map_property_mapall(m, MAPPROPERTY_NOTHING); bl.type = BL_NUL; bl.m = m; clif->maptypeproperty2(&bl,ALL_SAMEMAP); - + if(battle_config.pk_mode) // disable ranking options if pk_mode is on [Valaris] return true; - + map->foreachinmap(script->buildin_pvpoff_sub, m, BL_PC); return true; } @@ -10446,17 +11065,17 @@ BUILDIN(pvpoff) { BUILDIN(gvgon) { int16 m; const char *str; - + str=script_getstr(st,2); m = map->mapname2mapid(str); if(m >= 0 && !map->list[m].flag.gvg) { struct block_list 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; } - + map->zone_change2(m, strdb_get(map->zone_db, MAP_ZONE_GVG_NAME)); map->list[m].flag.gvg = 1; clif->map_property_mapall(m, MAPPROPERTY_AGITZONE); @@ -10464,13 +11083,13 @@ BUILDIN(gvgon) { bl.m = m; clif->maptypeproperty2(&bl,ALL_SAMEMAP); } - + return true; } BUILDIN(gvgoff) { int16 m; const char *str; - + str=script_getstr(st,2); m = map->mapname2mapid(str); if(m >= 0 && map->list[m].flag.gvg) { @@ -10482,25 +11101,25 @@ BUILDIN(gvgoff) { bl.m = m; clif->maptypeproperty2(&bl,ALL_SAMEMAP); } - + return true; } /*========================================== - * Shows an emoticon on top of the player/npc - * emotion emotion#, <target: 0 - NPC, 1 - PC>, <NPC/PC name> + * Shows an emoticon on top of the player/npc + * emotion emotion#, <target: 0 - NPC, 1 - PC>, <NPC/PC name> *------------------------------------------*/ //Optional second parameter added by [Skotlex] BUILDIN(emotion) { int type; int player=0; - + type=script_getnum(st,2); if(type < 0 || type > 100) return true; - + if( script_hasdata(st,3) ) player=script_getnum(st,3); - + if (player) { TBL_PC *sd = NULL; if( script_hasdata(st,4) ) @@ -10523,14 +11142,14 @@ 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); int flag=va_arg(ap,int); - + if(!sd || sd->bl.m != m) return 0; if( - (sd->status.guild_id == g_id && flag&1) || //Warp out owners - (sd->status.guild_id != g_id && flag&2) || //Warp out outsiders - (sd->status.guild_id == 0) // Warp out players not in guild [Valaris] - ) + (sd->status.guild_id == g_id && flag&1) //Warp out owners + || (sd->status.guild_id != g_id && flag&2) //Warp out outsiders + || (sd->status.guild_id == 0) // Warp out players not in guild [Valaris] + ) pc->setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT); return 1; } @@ -10538,10 +11157,10 @@ int buildin_maprespawnguildid_sub_pc(struct map_session_data* sd, va_list ap) int buildin_maprespawnguildid_sub_mob(struct block_list *bl,va_list ap) { struct mob_data *md=(struct mob_data *)bl; - + if(!md->guardian_data && md->class_ != MOBID_EMPERIUM) status_kill(bl); - + return 0; } @@ -10549,12 +11168,12 @@ BUILDIN(maprespawnguildid) { const char *mapname=script_getstr(st,2); int g_id=script_getnum(st,3); int flag=script_getnum(st,4); - + int16 m=map->mapname2mapid(mapname); - + if(m == -1) return true; - + //Catch ALL players (in case some are 'between maps' on execution time) map->foreachpc(script->buildin_maprespawnguildid_sub_pc,m,g_id,flag); if (flag&4) //Remove script mobs. @@ -10591,7 +11210,7 @@ BUILDIN(agitend2) { } /*========================================== - * Returns whether woe is on or off. // choice script + * Returns whether woe is on or off. *------------------------------------------*/ BUILDIN(agitcheck) { script_pushint(st,map->agit_flag); @@ -10599,7 +11218,7 @@ BUILDIN(agitcheck) { } /*========================================== - * Returns whether woese is on or off. // choice script + * Returns whether woese is on or off. *------------------------------------------*/ BUILDIN(agitcheck2) { script_pushint(st,map->agit2_flag); @@ -10612,9 +11231,9 @@ BUILDIN(agitcheck2) { BUILDIN(flagemblem) { TBL_NPC* nd; int g_id = script_getnum(st,2); - + if(g_id < 0) return true; - + nd = (TBL_NPC*)map->id2nd(st->oid); if( nd == NULL ) { ShowError("script:flagemblem: npc %d not found\n", st->oid); @@ -10635,7 +11254,7 @@ BUILDIN(flagemblem) { BUILDIN(getcastlename) { - const char* mapname = mapindex_getmapname(script_getstr(st,2),NULL); + const char* mapname = mapindex->getmapname(script_getstr(st,2),NULL); struct guild_castle* gc = guild->mapname2gc(mapname); const char* name = (gc) ? gc->castle_name : ""; script_pushstrcopy(st,name); @@ -10644,16 +11263,16 @@ BUILDIN(getcastlename) BUILDIN(getcastledata) { - const char *mapname = mapindex_getmapname(script_getstr(st,2),NULL); + const char *mapname = mapindex->getmapname(script_getstr(st,2),NULL); int index = script_getnum(st,3); struct guild_castle *gc = guild->mapname2gc(mapname); - + if (gc == NULL) { script_pushint(st,0); ShowWarning("buildin_setcastledata: guild castle for map '%s' not found\n", mapname); return false; } - + switch (index) { case 1: script_pushint(st,gc->guild_id); break; @@ -10687,21 +11306,21 @@ BUILDIN(getcastledata) BUILDIN(setcastledata) { - const char *mapname = mapindex_getmapname(script_getstr(st,2),NULL); + const char *mapname = mapindex->getmapname(script_getstr(st,2),NULL); int index = script_getnum(st,3); int value = script_getnum(st,4); struct guild_castle *gc = guild->mapname2gc(mapname); - + if (gc == NULL) { ShowWarning("buildin_setcastledata: guild castle for map '%s' not found\n", mapname); return false; } - + if (index <= 0 || index > 9+MAX_GUARDIANS) { ShowWarning("buildin_setcastledata: index = '%d' is out of allowed range\n", index); return false; } - + guild->castledatasave(gc->castle_id, index, value); return true; } @@ -10712,12 +11331,12 @@ BUILDIN(requestguildinfo) { int guild_id=script_getnum(st,2); const char *event=NULL; - - if( script_hasdata(st,3) ){ + + if( script_hasdata(st,3) ) { event=script_getstr(st,3); script->check_event(st, event); } - + if(guild_id>0) guild->npc_request_info(guild_id,event); return true; @@ -10730,28 +11349,28 @@ BUILDIN(getequipcardcnt) int i=-1,j,num; TBL_PC *sd; int count; - + num=script_getnum(st,2); sd=script->rid2sd(st); if (num > 0 && num <= ARRAYLENGTH(script->equip)) i=pc->checkequip(sd,script->equip[num-1]); - + if (i < 0 || !sd->inventory_data[i]) { script_pushint(st,0); return true; } - + if(itemdb_isspecial(sd->status.inventory[i].card[0])) { script_pushint(st,0); return true; } - + count = 0; for( j = 0; j < sd->inventory_data[i]->slot; j++ ) if( sd->status.inventory[i].card[j] && itemdb_type(sd->status.inventory[i].card[j]) == IT_CARD ) count++; - + script_pushint(st,count); return true; } @@ -10761,20 +11380,20 @@ BUILDIN(getequipcardcnt) /// successremovecards <slot>; BUILDIN(successremovecards) { int i=-1,j,c,cardflag=0; - + TBL_PC* sd = script->rid2sd(st); int num = script_getnum(st,2); - + if (num > 0 && num <= ARRAYLENGTH(script->equip)) i=pc->checkequip(sd,script->equip[num-1]); - + if (i < 0 || !sd->inventory_data[i]) { return true; } - + 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 int flag; @@ -10783,34 +11402,37 @@ BUILDIN(successremovecards) { cardflag = 1; item_tmp.nameid = sd->status.inventory[i].card[c]; item_tmp.identify = 1; - - if((flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))){ // get back the cart in inventory + + 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(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } } } - + if(cardflag == 1) {//if card was remove remplace item with no card int flag; 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,3,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 + 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(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } - + clif->misceffect(&sd->bl,3); } return true; @@ -10824,76 +11446,79 @@ BUILDIN(successremovecards) { /// <type>=? : will just display the failure effect. BUILDIN(failedremovecards) { int i=-1,j,c,cardflag=0; - + TBL_PC* sd = script->rid2sd(st); int num = script_getnum(st,2); int typefail = script_getnum(st,3); - + if (num > 0 && num <= ARRAYLENGTH(script->equip)) i=pc->checkequip(sd,script->equip[num-1]); - + if (i < 0 || !sd->inventory_data[i]) return true; - + 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 ) { cardflag = 1; - + if(typefail == 2) {// add cards to inventory, clear int flag; struct item item_tmp; - + memset(&item_tmp,0,sizeof(item_tmp)); - + item_tmp.nameid = sd->status.inventory[i].card[c]; item_tmp.identify = 1; - - if((flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))){ + + if((flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))) { clif->additem(sd,0,0,flag); map->addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } } } } - + 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,2,LOG_TYPE_SCRIPT); } - if(typefail == 1){ // destroy the card + if(typefail == 1) { + // destroy the card int flag; 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,2,LOG_TYPE_SCRIPT); - - if((flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))){ + + if((flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))) { clif->additem(sd,0,0,flag); map->addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } } clif->misceffect(&sd->bl,2); } - + return true; } /* ================================================================ * mapwarp "<from map>","<to map>",<x>,<y>,<type>,<ID for Type>; - * type: 0=everyone, 1=guild, 2=party; [Reddozen] + * type: 0=everyone, 1=guild, 2=party; [Reddozen] * improved by [Lance] * ================================================================*/ // Added by RoVeRT @@ -10908,24 +11533,24 @@ BUILDIN(mapwarp) { str=script_getstr(st,3); x=script_getnum(st,4); y=script_getnum(st,5); - if(script_hasdata(st,7)){ + if(script_hasdata(st,7)) { check_val=script_getnum(st,6); check_ID=script_getnum(st,7); } - + if((m=map->mapname2mapid(mapname))< 0) return true; - - if(!(index=mapindex_name2id(str))) + + if(!(index=mapindex->name2id(str))) return true; - - switch(check_val){ + + switch(check_val) { case 1: g = guild->search(check_ID); - if (g){ + if (g) { for( i=0; i < g->max_member; i++) { - if(g->member[i].sd && g->member[i].sd->bl.m==m){ + if(g->member[i].sd && g->member[i].sd->bl.m==m) { pc->setpos(g->member[i].sd,index,x,y,CLR_TELEPORT); } } @@ -10933,9 +11558,9 @@ BUILDIN(mapwarp) { break; case 2: p = party->search(check_ID); - if(p){ - for(i=0;i<MAX_PARTY; i++){ - if(p->data[i].sd && p->data[i].sd->bl.m == m){ + if(p) { + for(i=0;i<MAX_PARTY; i++) { + if(p->data[i].sd && p->data[i].sd->bl.m == m) { pc->setpos(p->data[i].sd,index,x,y,CLR_TELEPORT); } } @@ -10945,12 +11570,12 @@ BUILDIN(mapwarp) { map->foreachinmap(script->buildin_areawarp_sub,m,BL_PC,index,x,y,0,0); break; } - + return true; } -int buildin_mobcount_sub(struct block_list *bl,va_list ap) // Added by RoVeRT -{ +// Added by RoVeRT +int buildin_mobcount_sub(struct block_list *bl,va_list ap) { char *event=va_arg(ap,char *); struct mob_data *md = ((struct mob_data *)bl); if( md->status.hp > 0 && (!event || strcmp(event,md->npc_event) == 0) ) @@ -10964,7 +11589,7 @@ BUILDIN(mobcount) { int16 m; mapname=script_getstr(st,2); event=script_getstr(st,3); - + if( strcmp(event, "all") == 0 ) event = NULL; else @@ -10989,7 +11614,7 @@ BUILDIN(mobcount) { } script_pushint(st,map->foreachinmap(script->buildin_mobcount_sub, m, BL_MOB, event)); - + return true; } @@ -10997,8 +11622,8 @@ BUILDIN(marriage) { const char *partner=script_getstr(st,2); TBL_PC *sd=script->rid2sd(st); TBL_PC *p_sd=map->nick2sd(partner); - - if(sd==NULL || p_sd==NULL || pc->marriage(sd,p_sd) < 0){ + + if(sd==NULL || p_sd==NULL || pc->marriage(sd,p_sd) < 0) { script_pushint(st,0); return true; } @@ -11008,7 +11633,7 @@ BUILDIN(marriage) { BUILDIN(wedding_effect) { TBL_PC *sd=script->rid2sd(st); struct block_list *bl; - + if(sd==NULL) { bl=map->id2bl(st->oid); } else @@ -11019,7 +11644,7 @@ BUILDIN(wedding_effect) { BUILDIN(divorce) { TBL_PC *sd=script->rid2sd(st); - if(sd==NULL || pc->divorce(sd) < 0){ + if(sd==NULL || pc->divorce(sd) < 0) { script_pushint(st,0); return true; } @@ -11029,86 +11654,82 @@ BUILDIN(divorce) BUILDIN(ispartneron) { TBL_PC *sd=script->rid2sd(st); - - if(sd==NULL || !pc->ismarried(sd) || - map->charid2sd(sd->status.partner_id) == NULL) { + + if (sd==NULL || !pc->ismarried(sd) + || map->charid2sd(sd->status.partner_id) == NULL) { script_pushint(st,0); return true; } - + script_pushint(st,1); return true; } -BUILDIN(getpartnerid) -{ - TBL_PC *sd=script->rid2sd(st); - if (sd == NULL) { - script_pushint(st,0); - return true; - } - - script_pushint(st,sd->status.partner_id); - return true; +BUILDIN(getpartnerid) { + TBL_PC *sd=script->rid2sd(st); + if (sd == NULL) { + script_pushint(st,0); + return true; + } + + script_pushint(st,sd->status.partner_id); + return true; } -BUILDIN(getchildid) -{ - TBL_PC *sd=script->rid2sd(st); - if (sd == NULL) { - script_pushint(st,0); - return true; - } - - script_pushint(st,sd->status.child); - return true; +BUILDIN(getchildid) { + TBL_PC *sd=script->rid2sd(st); + if (sd == NULL) { + script_pushint(st,0); + return true; + } + + script_pushint(st,sd->status.child); + return true; } -BUILDIN(getmotherid) -{ - TBL_PC *sd=script->rid2sd(st); - if (sd == NULL) { - script_pushint(st,0); - return true; - } - - script_pushint(st,sd->status.mother); - return true; +BUILDIN(getmotherid) { + TBL_PC *sd=script->rid2sd(st); + if (sd == NULL) { + script_pushint(st,0); + return true; + } + + script_pushint(st,sd->status.mother); + return true; } -BUILDIN(getfatherid) -{ - TBL_PC *sd=script->rid2sd(st); - if (sd == NULL) { - script_pushint(st,0); - return true; - } - - script_pushint(st,sd->status.father); - return true; +BUILDIN(getfatherid) { + TBL_PC *sd=script->rid2sd(st); + if (sd == NULL) { + script_pushint(st,0); + return true; + } + + script_pushint(st,sd->status.father); + return true; } BUILDIN(warppartner) { int x,y; - unsigned short mapindex; + unsigned short map_index; const char *str; TBL_PC *sd=script->rid2sd(st); TBL_PC *p_sd=NULL; - - if(sd==NULL || !pc->ismarried(sd) || - (p_sd=map->charid2sd(sd->status.partner_id)) == NULL) { + + if ( sd==NULL || !pc->ismarried(sd) + || (p_sd=map->charid2sd(sd->status.partner_id)) == NULL) { script_pushint(st,0); return true; } - + str=script_getstr(st,2); x=script_getnum(st,3); y=script_getnum(st,4); - - mapindex = mapindex_name2id(str); - if (mapindex) { - pc->setpos(p_sd,mapindex,x,y,CLR_OUTSIGHT); + + map_index = mapindex->name2id(str); + if (map_index) { + pc->setpos(p_sd,map_index,x,y,CLR_OUTSIGHT); script_pushint(st,1); } else script_pushint(st,0); @@ -11120,10 +11741,10 @@ BUILDIN(warppartner) *------------------------------------------------*/ BUILDIN(strmobinfo) { - + int num=script_getnum(st,2); int class_=script_getnum(st,3); - + if(!mob->db_checkid(class_)) { if (num < 3) //requested a string @@ -11132,7 +11753,7 @@ BUILDIN(strmobinfo) script_pushint(st,0); return true; } - + switch (num) { case 1: script_pushstrcopy(st,mob->db(class_)->name); break; case 2: script_pushstrcopy(st,mob->db(class_)->jname); break; @@ -11155,28 +11776,27 @@ BUILDIN(strmobinfo) BUILDIN(guardian) { int class_ = 0, x = 0, y = 0, guardian = 0; const char *str, *mapname, *evt=""; - struct script_data *data; bool has_index = false; - + mapname = script_getstr(st,2); x = script_getnum(st,3); y = script_getnum(st,4); str = script_getstr(st,5); class_ = script_getnum(st,6); - + if( script_hasdata(st,8) ) {// "<event label>",<guardian index> evt=script_getstr(st,7); guardian=script_getnum(st,8); has_index = true; - } else if( script_hasdata(st,7) ){ - data=script_getdata(st,7); - script->get_val(st,data); - if( data_isstring(data) ) - {// "<event label>" + } else if( script_hasdata(st,7) ) { + struct script_data *data = script_getdata(st,7); + script->get_val(st,data); // Dereference if it's a variable + if( data_isstring(data) ) { + // "<event label>" evt=script_getstr(st,7); - } else if( data_isint(data) ) - {// <guardian index> + } else if( data_isint(data) ) { + // <guardian index> guardian=script_getnum(st,7); has_index = true; } else { @@ -11185,10 +11805,10 @@ BUILDIN(guardian) { return false; } } - + script->check_event(st, evt); script_pushint(st, mob->spawn_guardian(mapname,x,y,str,class_,evt,guardian,has_index)); - + return true; } /*========================================== @@ -11198,7 +11818,7 @@ BUILDIN(setwall) { const char *mapname, *name; int x, y, m, size, dir; bool shootable; - + mapname = script_getstr(st,2); x = script_getnum(st,3); y = script_getnum(st,4); @@ -11206,17 +11826,17 @@ BUILDIN(setwall) { dir = script_getnum(st,6); shootable = script_getnum(st,7); name = script_getstr(st,8); - + if( (m = map->mapname2mapid(mapname)) < 0 ) return true; // Invalid Map - + map->iwall_set(m, x, y, size, dir, shootable, name); return true; } BUILDIN(delwall) { const char *name = script_getstr(st,2); map->iwall_remove(name); - + return true; } @@ -11228,18 +11848,18 @@ BUILDIN(delwall) { /// 2 - current hp /// BUILDIN(guardianinfo) { - const char* mapname = mapindex_getmapname(script_getstr(st,2),NULL); + const char* mapname = mapindex->getmapname(script_getstr(st,2),NULL); int id = script_getnum(st,3); int type = script_getnum(st,4); - + struct guild_castle* gc = guild->mapname2gc(mapname); struct mob_data* gd; - + if( gc == NULL || id < 0 || id >= MAX_GUARDIANS ) { script_pushint(st,-1); return true; } - + if( type == 0 ) script_pushint(st, gc->guardian[id].visible); else if( !gc->guardian[id].visible ) @@ -11252,39 +11872,34 @@ BUILDIN(guardianinfo) { script_pushint(st,gd->status.hp); else script_pushint(st,-1); - + return true; } /*========================================== * Get the item name by item_id or null *------------------------------------------*/ -BUILDIN(getitemname) -{ +BUILDIN(getitemname) { int item_id=0; struct item_data *i_data; char *item_name; - struct script_data *data; - - data=script_getdata(st,2); - script->get_val(st,data); - - if( data_isstring(data) ){ - const char *name=script->conv_str(st,data); + + if( script_isstringtype(st, 2) ) { + const char *name = script_getstr(st, 2); struct item_data *item_data = itemdb->search_name(name); if( item_data ) item_id=item_data->nameid; - }else - item_id=script->conv_num(st,data); - + } else { + item_id = script_getnum(st, 2); + } + i_data = itemdb->exists(item_id); - if (i_data == NULL) - { + if (i_data == NULL) { script_pushconststr(st,"null"); return true; } item_name=(char *)aMalloc(ITEM_NAME_LENGTH*sizeof(char)); - + memcpy(item_name, i_data->jname, ITEM_NAME_LENGTH); script_pushstr(st,item_name); return true; @@ -11296,11 +11911,11 @@ BUILDIN(getitemslots) { int item_id; struct item_data *i_data; - + item_id=script_getnum(st,2); - + i_data = itemdb->exists(item_id); - + if (i_data) script_pushint(st,i_data->slot); else @@ -11313,35 +11928,35 @@ BUILDIN(getitemslots) /*========================================== * 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 + * 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) { int item_id,n; int *item_arr; struct item_data *i_data; - - item_id = script_getnum(st,2); - n = script_getnum(st,3); - i_data = itemdb->exists(item_id); - + + item_id = script_getnum(st,2); + n = script_getnum(st,3); + i_data = itemdb->exists(item_id); + if (i_data && n>=0 && n<=14) { item_arr = (int*)&i_data->value_buy; script_pushint(st,item_arr[n]); @@ -11353,24 +11968,24 @@ BUILDIN(getiteminfo) /*========================================== * 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 + * 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) @@ -11378,12 +11993,12 @@ BUILDIN(setiteminfo) int item_id,n,value; int *item_arr; struct item_data *i_data; - - item_id = script_getnum(st,2); - n = script_getnum(st,3); - value = script_getnum(st,4); - i_data = 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 (i_data && n>=0 && n<=14) { item_arr = (int*)&i_data->value_buy; item_arr[n] = value; @@ -11395,21 +12010,21 @@ BUILDIN(setiteminfo) /*========================================== * Returns value from equipped item slot n [Lupus] - getequpcardid(num,slot) - where - num = eqip position slot - slot = 0,1,2,3 (Card Slot N) - - This func returns CARD ID, 255,254,-255 (for card 0, if the item is produced) - it's useful when you want to check item cards or if it's signed - Useful for such quests as "Sign this refined item with players name" etc - Hat[0] +4 -> Player's Hat[0] +4 + * getequpcardid(num,slot) + * where + * num = eqip position slot + * slot = 0,1,2,3 (Card Slot N) + * + * This func returns CARD ID, 255,254,-255 (for card 0, if the item is produced) + * it's useful when you want to check item cards or if it's signed + * Useful for such quests as "Sign this refined item with players name" etc + * Hat[0] +4 -> Player's Hat[0] +4 *------------------------------------------*/ BUILDIN(getequipcardid) { int i=-1,num,slot; TBL_PC *sd; - + num=script_getnum(st,2); slot=script_getnum(st,3); sd=script->rid2sd(st); @@ -11419,7 +12034,7 @@ BUILDIN(getequipcardid) script_pushint(st,sd->status.inventory[i].card[slot]); else script_pushint(st,0); - + return true; } @@ -11429,12 +12044,12 @@ BUILDIN(getequipcardid) BUILDIN(petskillbonus) { struct pet_data *pd; - + TBL_PC *sd=script->rid2sd(st); - + if(sd==NULL || sd->pd==NULL) return true; - + pd=sd->pd; if (pd->bonus) { //Clear previous bonus @@ -11442,21 +12057,21 @@ BUILDIN(petskillbonus) timer->delete(pd->bonus->timer, pet->skill_bonus_timer); } else //init pd->bonus = (struct pet_bonus *) aMalloc(sizeof(struct pet_bonus)); - + pd->bonus->type=script_getnum(st,2); pd->bonus->val=script_getnum(st,3); pd->bonus->duration=script_getnum(st,4); pd->bonus->delay=script_getnum(st,5); - + if (pd->state.skillbonus == 1) - pd->state.skillbonus=0; // waiting state - + pd->state.skillbonus=0; // waiting state + // wait for timer to start if (battle_config.pet_equip_required && pd->pet.equip == 0) pd->bonus->timer = INVALID_TIMER; else pd->bonus->timer = timer->add(timer->gettick()+pd->bonus->delay*1000, pet->skill_bonus_timer, sd->bl.id, 0); - + return true; } @@ -11468,32 +12083,32 @@ BUILDIN(petloot) int max; struct pet_data *pd; TBL_PC *sd=script->rid2sd(st); - + if(sd==NULL || sd->pd==NULL) return true; - + max=script_getnum(st,2); - + if(max < 1) - max = 1; //Let'em loot at least 1 item. + max = 1; //Let'em loot at least 1 item. else if (max > MAX_PETLOOT_SIZE) max = MAX_PETLOOT_SIZE; - + pd = sd->pd; - if (pd->loot != NULL) - { //Release whatever was there already and reallocate memory + if (pd->loot != NULL) { + //Release whatever was there already and reallocate memory pet->lootitem_drop(pd, pd->msd); aFree(pd->loot->item); } else pd->loot = (struct pet_loot *)aMalloc(sizeof(struct pet_loot)); - + pd->loot->item = (struct item *)aCalloc(max,sizeof(struct item)); - + pd->loot->max=max; pd->loot->count = 0; pd->loot->weight = 0; - + return true; } /*========================================== @@ -11507,11 +12122,11 @@ BUILDIN(getinventorylist) { TBL_PC *sd=script->rid2sd(st); char card_var[NAME_LENGTH]; - + int i,j=0,k; if(!sd) return true; - for(i=0;i<MAX_INVENTORY;i++){ - if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount > 0){ + for(i=0;i<MAX_INVENTORY;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_str("@inventorylist_equip"), j),sd->status.inventory[i].equip); @@ -11524,6 +12139,7 @@ BUILDIN(getinventorylist) pc->setreg(sd,reference_uid(script->add_str(card_var), j),sd->status.inventory[i].card[k]); } 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); j++; } } @@ -11536,8 +12152,8 @@ BUILDIN(getskilllist) TBL_PC *sd=script->rid2sd(st); int i,j=0; if(!sd) return true; - for(i=0;i<MAX_SKILL;i++){ - if(sd->status.skill[i].id > 0 && sd->status.skill[i].lv > 0){ + for(i=0;i<MAX_SKILL;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); @@ -11569,15 +12185,15 @@ BUILDIN(disguise) int id; TBL_PC* sd = script->rid2sd(st); if (sd == NULL) return true; - + id = script_getnum(st,2); - + if (mob->db_checkid(id) || npcdb_checkid(id)) { pc->disguise(sd, id); script_pushint(st,id); } else script_pushint(st,0); - + return true; } @@ -11588,7 +12204,7 @@ BUILDIN(undisguise) { TBL_PC* sd = script->rid2sd(st); if (sd == NULL) return true; - + if (sd->disguise != -1) { pc->disguise(sd, -1); script_pushint(st,0); @@ -11605,9 +12221,9 @@ BUILDIN(undisguise) BUILDIN(classchange) { int _class,type; struct block_list *bl=map->id2bl(st->oid); - + if(bl==NULL) return true; - + _class=script_getnum(st,2); type=script_getnum(st,3); clif->class_change(bl,_class,type); @@ -11620,13 +12236,13 @@ BUILDIN(classchange) { BUILDIN(misceffect) { int type; - + type=script_getnum(st,2); if(st->oid && st->oid != npc->fake_nd->bl.id) { struct block_list *bl = map->id2bl(st->oid); if (bl) clif->specialeffect(bl,type,AREA); - } else{ + } else { TBL_PC *sd=script->rid2sd(st); if(sd) clif->specialeffect(&sd->bl,type,AREA); @@ -11636,34 +12252,34 @@ BUILDIN(misceffect) /*========================================== * Play a BGM on a single client [Rikter/Yommy] *------------------------------------------*/ -BUILDIN(playBGM) +BUILDIN(playbgm) { const char* name; struct map_session_data* sd; - + if( ( sd = script->rid2sd(st) ) != NULL ) { name = script_getstr(st,2); - + clif->playBGM(sd, name); } - + return true; } -int playBGM_sub(struct block_list* bl,va_list ap) +int playbgm_sub(struct block_list* bl,va_list ap) { const char* name = va_arg(ap,const char*); - + clif->playBGM(BL_CAST(BL_PC, bl), name); - + return 0; } -int playBGM_foreachpc_sub(struct map_session_data* sd, va_list args) +int playbgm_foreachpc_sub(struct map_session_data* sd, va_list args) { const char* name = va_arg(args, const char*); - + clif->playBGM(sd, name); return 0; } @@ -11671,11 +12287,11 @@ int playBGM_foreachpc_sub(struct map_session_data* sd, va_list args) /*========================================== * Play a BGM on multiple client [Rikter/Yommy] *------------------------------------------*/ -BUILDIN(playBGMall) { +BUILDIN(playbgmall) { const char* name; - + name = script_getstr(st,2); - + if( script_hasdata(st,7) ) { // specified part of map const char *mapname = script_getstr(st,3); @@ -11684,29 +12300,29 @@ BUILDIN(playBGMall) { int x1 = script_getnum(st,6); int y1 = script_getnum(st,7); int m; - + if ( ( m = map->mapname2mapid(mapname) ) == -1 ) { - ShowWarning("playBGMall: Attempted to play song '%s' on non-existent map '%s'\n",name, mapname); + ShowWarning("playbgmall: Attempted to play song '%s' on non-existent map '%s'\n",name, mapname); return true; } - - map->foreachinarea(script->playBGM_sub, m, x0, y0, x1, y1, BL_PC, name); + + map->foreachinarea(script->playbgm_sub, m, x0, y0, x1, y1, BL_PC, name); } else if( script_hasdata(st,3) ) { // entire map const char* mapname = script_getstr(st,3); int m; - + if ( ( m = map->mapname2mapid(mapname) ) == -1 ) { - ShowWarning("playBGMall: Attempted to play song '%s' on non-existent map '%s'\n",name, mapname); + ShowWarning("playbgmall: Attempted to play song '%s' on non-existent map '%s'\n",name, mapname); return true; } - - map->foreachinmap(script->playBGM_sub, m, BL_PC, name); + + map->foreachinmap(script->playbgm_sub, m, BL_PC, name); } else { // entire server - map->foreachpc(script->playBGM_foreachpc_sub, name); + map->foreachpc(script->playbgm_foreachpc_sub, name); } - + return true; } @@ -11718,7 +12334,7 @@ BUILDIN(soundeffect) TBL_PC* sd = script->rid2sd(st); const char* name = script_getstr(st,2); int type = script_getnum(st,3); - + if(sd) { clif->soundeffect(sd,&sd->bl,name,type); @@ -11730,9 +12346,9 @@ int soundeffect_sub(struct block_list* bl,va_list ap) { char* name = va_arg(ap,char*); int type = va_arg(ap,int); - + clif->soundeffect((TBL_PC *)bl, bl, name, type); - + return true; } @@ -11744,28 +12360,28 @@ BUILDIN(soundeffectall) { struct block_list* bl; const char* name; int type; - + bl = (st->rid) ? &(script->rid2sd(st)->bl) : map->id2bl(st->oid); if (!bl) return true; - + name = script_getstr(st,2); type = script_getnum(st,3); - + //FIXME: enumerating map squares (map->foreach) is slower than enumerating the list of online players (map->foreachpc?) [ultramage] - + if(!script_hasdata(st,4)) { // area around clif->soundeffectall(bl, name, type, AREA); } else { if(!script_hasdata(st,5)) { // entire map const char *mapname = script_getstr(st,4); int m; - + if ( ( m = map->mapname2mapid(mapname) ) == -1 ) { ShowWarning("soundeffectall: Attempted to play song '%s' (type %d) on non-existent map '%s'\n",name,type, mapname); return true; } - + map->foreachinmap(script->soundeffect_sub, m, BL_PC, name, type); } else if(script_hasdata(st,8)) { // specified part of map const char *mapname = script_getstr(st,4); @@ -11774,18 +12390,18 @@ BUILDIN(soundeffectall) { int x1 = script_getnum(st,7); int y1 = script_getnum(st,8); int m; - + if ( ( m = map->mapname2mapid(mapname) ) == -1 ) { ShowWarning("soundeffectall: Attempted to play song '%s' (type %d) on non-existent map '%s'\n",name,type, mapname); return true; } - + map->foreachinarea(script->soundeffect_sub, m, x0, y0, x1, y1, BL_PC, name, type); } else { ShowError("buildin_soundeffectall: insufficient arguments for specific area broadcast.\n"); } } - + return true; } /*========================================== @@ -11795,23 +12411,23 @@ BUILDIN(petrecovery) { struct pet_data *pd; TBL_PC *sd=script->rid2sd(st); - + if(sd==NULL || sd->pd==NULL) return true; - + pd=sd->pd; - + if (pd->recovery) { //Halt previous bonus if (pd->recovery->timer != INVALID_TIMER) timer->delete(pd->recovery->timer, pet->recovery_timer); } else //Init pd->recovery = (struct pet_recovery *)aMalloc(sizeof(struct pet_recovery)); - + pd->recovery->type = (sc_type)script_getnum(st,2); pd->recovery->delay = script_getnum(st,3); pd->recovery->timer = INVALID_TIMER; - + return true; } @@ -11822,10 +12438,10 @@ BUILDIN(petheal) { struct pet_data *pd; TBL_PC *sd=script->rid2sd(st); - + if(sd==NULL || sd->pd==NULL) return true; - + pd=sd->pd; if (pd->s_skill) { //Clear previous skill @@ -11838,20 +12454,20 @@ BUILDIN(petheal) } } else //init memory pd->s_skill = (struct pet_skill_support *) aMalloc(sizeof(struct pet_skill_support)); - + pd->s_skill->id=0; //This id identifies that it IS petheal rather than pet_skillsupport //Use the lv as the amount to heal pd->s_skill->lv=script_getnum(st,2); pd->s_skill->delay=script_getnum(st,3); pd->s_skill->hp=script_getnum(st,4); pd->s_skill->sp=script_getnum(st,5); - + //Use delay as initial offset to avoid skill/heal exploits if (battle_config.pet_equip_required && pd->pet.equip == 0) pd->s_skill->timer = INVALID_TIMER; else pd->s_skill->timer = timer->add(timer->gettick()+pd->s_skill->delay*1000,pet->heal_timer,sd->bl.id,0); - + return true; } @@ -11860,24 +12476,23 @@ BUILDIN(petheal) *------------------------------------------*/ /// petskillattack <skill id>,<level>,<rate>,<bonusrate> /// petskillattack "<skill name>",<level>,<rate>,<bonusrate> -BUILDIN(petskillattack) -{ +BUILDIN(petskillattack) { struct pet_data *pd; TBL_PC *sd=script->rid2sd(st); - + if(sd==NULL || sd->pd==NULL) return true; - + pd=sd->pd; if (pd->a_skill == NULL) pd->a_skill = (struct pet_skill_attack *)aMalloc(sizeof(struct pet_skill_attack)); - - pd->a_skill->id=( script_isstring(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); + + pd->a_skill->id=( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); pd->a_skill->lv=script_getnum(st,3); pd->a_skill->div_ = 0; pd->a_skill->rate=script_getnum(st,4); pd->a_skill->bonusrate=script_getnum(st,5); - + return true; } @@ -11886,24 +12501,23 @@ BUILDIN(petskillattack) *------------------------------------------*/ /// petskillattack2 <skill id>,<level>,<div>,<rate>,<bonusrate> /// petskillattack2 "<skill name>",<level>,<div>,<rate>,<bonusrate> -BUILDIN(petskillattack2) -{ +BUILDIN(petskillattack2) { struct pet_data *pd; TBL_PC *sd=script->rid2sd(st); - + if(sd==NULL || sd->pd==NULL) return true; - + pd=sd->pd; if (pd->a_skill == NULL) pd->a_skill = (struct pet_skill_attack *)aMalloc(sizeof(struct pet_skill_attack)); - - pd->a_skill->id=( script_isstring(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); + + pd->a_skill->id=( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); pd->a_skill->lv=script_getnum(st,3); pd->a_skill->div_ = script_getnum(st,4); pd->a_skill->rate=script_getnum(st,5); pd->a_skill->bonusrate=script_getnum(st,6); - + return true; } @@ -11912,14 +12526,13 @@ BUILDIN(petskillattack2) *------------------------------------------*/ /// petskillsupport <skill id>,<level>,<delay>,<hp>,<sp> /// petskillsupport "<skill name>",<level>,<delay>,<hp>,<sp> -BUILDIN(petskillsupport) -{ +BUILDIN(petskillsupport) { struct pet_data *pd; TBL_PC *sd=script->rid2sd(st); - + if(sd==NULL || sd->pd==NULL) return true; - + pd=sd->pd; if (pd->s_skill) { //Clear previous skill @@ -11932,19 +12545,19 @@ BUILDIN(petskillsupport) } } else //init memory pd->s_skill = (struct pet_skill_support *) aMalloc(sizeof(struct pet_skill_support)); - - pd->s_skill->id=( script_isstring(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); + + pd->s_skill->id=( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); pd->s_skill->lv=script_getnum(st,3); pd->s_skill->delay=script_getnum(st,4); pd->s_skill->hp=script_getnum(st,5); pd->s_skill->sp=script_getnum(st,6); - + //Use delay as initial offset to avoid skill/heal exploits if (battle_config.pet_equip_required && pd->pet.equip == 0) pd->s_skill->timer = INVALID_TIMER; else pd->s_skill->timer = timer->add(timer->gettick()+pd->s_skill->delay*1000,pet->skill_support_timer,sd->bl.id,0); - + return true; } @@ -11953,16 +12566,15 @@ BUILDIN(petskillsupport) *------------------------------------------*/ /// skilleffect <skill id>,<level> /// skilleffect "<skill name>",<level> -BUILDIN(skilleffect) -{ +BUILDIN(skilleffect) { TBL_PC *sd; - - uint16 skill_id=( script_isstring(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); + + uint16 skill_id=( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); uint16 skill_lv=script_getnum(st,3); sd=script->rid2sd(st); - + clif->skill_nodamage(&sd->bl,&sd->bl,skill_id,skill_lv,1); - + return true; } @@ -11973,15 +12585,15 @@ BUILDIN(skilleffect) /// npcskilleffect "<skill name>",<level>,<x>,<y> BUILDIN(npcskilleffect) { struct block_list *bl= map->id2bl(st->oid); - - uint16 skill_id=( script_isstring(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); + + uint16 skill_id=( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); uint16 skill_lv=script_getnum(st,3); int x=script_getnum(st,4); int y=script_getnum(st,5); - + if (bl) clif->skill_poseffect(bl,skill_id,skill_lv,x,y,timer->gettick()); - + return true; } @@ -11992,10 +12604,10 @@ BUILDIN(specialeffect) { struct block_list *bl=map->id2bl(st->oid); int type = script_getnum(st,2); enum send_target target = script_hasdata(st,3) ? (send_target)script_getnum(st,3) : AREA; - + if(bl==NULL) return true; - + if( script_hasdata(st,4) ) { TBL_NPC *nd = npc->name2id(script_getstr(st,4)); @@ -12012,7 +12624,7 @@ BUILDIN(specialeffect) { clif->specialeffect(bl, type, target); } } - + return true; } @@ -12020,13 +12632,13 @@ BUILDIN(specialeffect2) { TBL_PC *sd=script->rid2sd(st); int type = script_getnum(st,2); enum send_target target = script_hasdata(st,3) ? (send_target)script_getnum(st,3) : AREA; - + if( script_hasdata(st,4) ) sd = map->nick2sd(script_getstr(st,4)); - + if (sd) clif->specialeffect(&sd->bl, type, target); - + return true; } @@ -12037,10 +12649,10 @@ BUILDIN(nude) { TBL_PC *sd = script->rid2sd(st); int i, calcflag = 0; - + if( sd == NULL ) return true; - + for( i = 0 ; i < EQI_MAX; i++ ) { if( sd->equip_index[ i ] >= 0 ) { if( !calcflag ) @@ -12048,10 +12660,10 @@ BUILDIN(nude) pc->unequipitem( sd , sd->equip_index[ i ] , 2); } } - + if( calcflag ) - status_calc_pc(sd,0); - + status_calc_pc(sd,SCO_NONE); + return true; } @@ -12063,16 +12675,16 @@ BUILDIN(atcommand) { int fd; const char* cmd; bool ret = true; - + cmd = script_getstr(st,2); - + if (st->rid) { sd = script->rid2sd(st); fd = sd->fd; } else { //Use a dummy character. sd = dummy_sd = pc->get_dummy_sd(); fd = 0; - + if (st->oid) { struct block_list* bl = map->id2bl(st->oid); memcpy(&sd->bl, bl, sizeof(struct block_list)); @@ -12080,8 +12692,8 @@ BUILDIN(atcommand) { safestrncpy(sd->status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH); } } - - if (!atcommand->parse(fd, sd, cmd, 0)) { + + if (!atcommand->exec(fd, sd, cmd, false)) { ShowWarning("script: buildin_atcommand: failed to execute command '%s'\n", cmd); script->reportsrc(st); ret = false; @@ -12099,7 +12711,7 @@ BUILDIN(dispbottom) const char *message; message=script_getstr(st,2); if(sd) - clif->disp_onlyself(sd,message,(int)strlen(message)); + clif_disp_onlyself(sd,message,(int)strlen(message)); return true; } @@ -12111,7 +12723,7 @@ BUILDIN(recovery) { TBL_PC* sd; struct s_mapiterator* iter; - + iter = mapit_getallusers(); for( sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); sd = (TBL_PC*)mapit->next(iter) ) { @@ -12134,7 +12746,7 @@ BUILDIN(getpetinfo) TBL_PC *sd=script->rid2sd(st); TBL_PET *pd; int type=script_getnum(st,2); - + if(!sd || !sd->pd) { if (type == 2) script_pushconststr(st,"null"); @@ -12143,7 +12755,7 @@ BUILDIN(getpetinfo) return true; } pd = sd->pd; - switch(type){ + switch(type) { case 0: script_pushint(st,pd->pet.pet_id); break; case 1: script_pushint(st,pd->pet.class_); break; case 2: script_pushstrcopy(st,pd->pet.name); break; @@ -12166,27 +12778,24 @@ BUILDIN(getpetinfo) BUILDIN(gethominfo) { TBL_PC *sd=script->rid2sd(st); - TBL_HOM *hd; - int type=script_getnum(st,2); - - hd = sd?sd->hd:NULL; - if(!homun_alive(hd)) - { + int type = script_getnum(st,2); + + if(!sd || !sd->hd) { if (type == 2) script_pushconststr(st,"null"); else script_pushint(st,0); return true; } - - switch(type){ - case 0: script_pushint(st,hd->homunculus.hom_id); break; - case 1: script_pushint(st,hd->homunculus.class_); break; - case 2: script_pushstrcopy(st,hd->homunculus.name); break; - case 3: script_pushint(st,hd->homunculus.intimacy); break; - case 4: script_pushint(st,hd->homunculus.hunger); break; - case 5: script_pushint(st,hd->homunculus.rename_flag); break; - case 6: script_pushint(st,hd->homunculus.level); break; + + switch(type) { + case 0: script_pushint(st,sd->hd->homunculus.hom_id); break; + case 1: script_pushint(st,sd->hd->homunculus.class_); break; + case 2: script_pushstrcopy(st,sd->hd->homunculus.name); break; + case 3: script_pushint(st,sd->hd->homunculus.intimacy); break; + case 4: script_pushint(st,sd->hd->homunculus.hunger); break; + case 5: script_pushint(st,sd->hd->homunculus.rename_flag); break; + case 6: script_pushint(st,sd->hd->homunculus.level); break; default: script_pushint(st,0); break; @@ -12200,12 +12809,12 @@ BUILDIN(getmercinfo) { int type, char_id; struct map_session_data* sd; struct mercenary_data* md; - + type = script_getnum(st,2); - + if( script_hasdata(st,3) ) { char_id = script_getnum(st,3); - + if( ( sd = map->charid2sd(char_id) ) == NULL ) { ShowError("buildin_getmercinfo: No such character (char_id=%d).\n", char_id); script_pushnil(st); @@ -12217,9 +12826,9 @@ BUILDIN(getmercinfo) { return true; } } - + md = ( sd->status.mer_id && sd->md ) ? sd->md : NULL; - + switch( type ) { case 0: script_pushint(st,md ? md->mercenary.mercenary_id : 0); break; @@ -12240,29 +12849,29 @@ BUILDIN(getmercinfo) { script_pushnil(st); return false; } - + return true; } /*========================================== * Shows wether your inventory(and equips) contain - selected card or not. - checkequipedcard(4001); + * selected card or not. + * checkequipedcard(4001); *------------------------------------------*/ BUILDIN(checkequipedcard) { TBL_PC *sd=script->rid2sd(st); - - if(sd){ + + if(sd) { int n,i,c=0; c=script_getnum(st,2); - - for(i=0;i<MAX_INVENTORY;i++){ - if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount && sd->inventory_data[i]){ + + for(i=0;i<MAX_INVENTORY;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++){ - if(sd->status.inventory[i].card[n]==c){ + for(n=0;n<sd->inventory_data[i]->slot;n++) { + if(sd->status.inventory[i].card[n]==c) { script_pushint(st,1); return true; } @@ -12280,12 +12889,12 @@ BUILDIN(jump_zero) sel=script_getnum(st,2); if(!sel) { int pos; - if( !data_islabel(script_getdata(st,3)) ){ + if( !data_islabel(script_getdata(st,3)) ) { ShowError("script: jump_zero: not label !\n"); st->state=END; return false; } - + pos=script_getnum(st,3); st->pos=pos; st->state=GOTO; @@ -12300,14 +12909,14 @@ BUILDIN(movenpc) { TBL_NPC *nd = NULL; const char *npc_name; int x,y; - + npc_name = script_getstr(st,2); x = script_getnum(st,3); y = script_getnum(st,4); - + if ((nd = npc->name2id(npc_name)) == NULL) return -1; - + if (script_hasdata(st,5)) nd->dir = script_getnum(st,5) % 8; npc->movenpc(nd, x, y); @@ -12320,14 +12929,14 @@ BUILDIN(movenpc) { BUILDIN(message) { const char *msg,*player; TBL_PC *pl_sd = NULL; - + player = script_getstr(st,2); msg = script_getstr(st,3); - + if((pl_sd=map->nick2sd((char *) player)) == NULL) return true; clif->message(pl_sd->fd, msg); - + return true; } @@ -12337,10 +12946,10 @@ BUILDIN(message) { BUILDIN(npctalk) { const char* str; char name[NAME_LENGTH], message[256]; - + struct npc_data* nd = (struct npc_data *)map->id2bl(st->oid); str = script_getstr(st,2); - + if(nd) { safestrncpy(name, nd->name, sizeof(name)); @@ -12348,7 +12957,7 @@ BUILDIN(npctalk) { safesnprintf(message, sizeof(message), "%s : %s", name, str); clif->disp_overhead(&nd->bl, message); } - + return true; } @@ -12356,47 +12965,47 @@ BUILDIN(npctalk) { BUILDIN(npcspeed) { struct npc_data* nd; int speed; - + speed = script_getnum(st,2); nd = (struct npc_data *)map->id2bl(st->oid); - + if( nd ) { unit->bl2ud2(&nd->bl); // ensure nd->ud is safe to edit nd->speed = speed; nd->ud->state.speed_changed = 1; } - + return true; } // make an npc walk to a position [Valaris] BUILDIN(npcwalkto) { struct npc_data *nd=(struct npc_data *)map->id2bl(st->oid); int x=0,y=0; - + x=script_getnum(st,2); y=script_getnum(st,3); - + if( nd ) { unit->bl2ud2(&nd->bl); // ensure nd->ud is safe to edit if (!nd->status.hp) { - status_calc_npc(nd, true); + status_calc_npc(nd, SCO_FIRST); } else { - status_calc_npc(nd, false); + status_calc_npc(nd, SCO_NONE); } unit->walktoxy(&nd->bl,x,y,0); } - + return true; } // stop an npc's movement [Valaris] BUILDIN(npcstop) { struct npc_data *nd = (struct npc_data *)map->id2bl(st->oid); - + if( nd ) { unit->bl2ud2(&nd->bl); // ensure nd->ud is safe to edit unit->stop_walking(&nd->bl,1|4); } - + return true; } @@ -12409,22 +13018,22 @@ BUILDIN(getlook) int type,val; TBL_PC *sd; sd=script->rid2sd(st); - + type=script_getnum(st,2); - val=-1; + val = -1; 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_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_SHOES: break; //9 - case LOOK_ROBE: val=sd->status.robe; break; //12 + 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_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_SHOES: break; //9 + case LOOK_ROBE: val = sd->status.robe; break; //12 } - + script_pushint(st,val); return true; } @@ -12436,15 +13045,15 @@ BUILDIN(getsavepoint) { TBL_PC* sd; int type; - + sd = script->rid2sd(st); if (sd == NULL) { script_pushint(st,0); return true; } - + type = script_getnum(st,2); - + switch(type) { case 0: script_pushstrcopy(st,mapindex_id2name(sd->status.save_point.map)); break; case 1: script_pushint(st,sd->status.save_point.x); break; @@ -12482,44 +13091,44 @@ BUILDIN(getmapxy) { struct block_list *bl = NULL; TBL_PC *sd=NULL; - - int num; + + int64 num; const char *name; char prefix; - + int x,y,type; char mapname[MAP_NAME_LENGTH]; - - if( !data_isreference(script_getdata(st,2)) ){ + + if( !data_isreference(script_getdata(st,2)) ) { ShowWarning("script: buildin_getmapxy: not mapname variable\n"); script_pushint(st,-1); return false; } - if( !data_isreference(script_getdata(st,3)) ){ + if( !data_isreference(script_getdata(st,3)) ) { ShowWarning("script: buildin_getmapxy: not mapx variable\n"); script_pushint(st,-1); return false; } - if( !data_isreference(script_getdata(st,4)) ){ + if( !data_isreference(script_getdata(st,4)) ) { ShowWarning("script: buildin_getmapxy: not mapy variable\n"); script_pushint(st,-1); return false; } - + // Possible needly check function parameters on C_STR,C_INT,C_INT type=script_getnum(st,5); - - switch (type){ - case 0: //Get Character Position + + switch (type) { + case 0: //Get Character Position if( script_hasdata(st,6) ) sd=map->nick2sd(script_getstr(st,6)); else sd=script->rid2sd(st); - + if (sd) bl = &sd->bl; break; - case 1: //Get NPC Position + case 1: //Get NPC Position if( script_hasdata(st,6) ) { struct npc_data *nd; @@ -12529,23 +13138,23 @@ BUILDIN(getmapxy) } else //In case the origin is not an npc? bl=map->id2bl(st->oid); break; - case 2: //Get Pet Position + case 2: //Get Pet Position if(script_hasdata(st,6)) sd=map->nick2sd(script_getstr(st,6)); else sd=script->rid2sd(st); - + if (sd && sd->pd) bl = &sd->pd->bl; break; - case 3: //Get Mob Position + case 3: //Get Mob Position break; //Not supported? - case 4: //Get Homun Position + case 4: //Get Homun Position if(script_hasdata(st,6)) sd=map->nick2sd(script_getstr(st,6)); else sd=script->rid2sd(st); - + if (sd && sd->hd) bl = &sd->hd->bl; break; @@ -12554,7 +13163,7 @@ BUILDIN(getmapxy) sd=map->nick2sd(script_getstr(st,6)); else sd=script->rid2sd(st); - + if (sd && sd->md) bl = &sd->md->bl; break; @@ -12563,7 +13172,7 @@ BUILDIN(getmapxy) sd=map->nick2sd(script_getstr(st,6)); else sd=script->rid2sd(st); - + if (sd && sd->ed) bl = &sd->ed->bl; break; @@ -12576,44 +13185,44 @@ BUILDIN(getmapxy) script_pushint(st,-1); return true; } - + x= bl->x; y= bl->y; safestrncpy(mapname, map->list[bl->m].name, MAP_NAME_LENGTH); - + //Set MapName$ num=st->stack->stack_data[st->start+2].u.num; - name=script->get_str(num&0x00ffffff); + name=script->get_str(script_getvarid(num)); prefix=*name; - + if(not_server_variable(prefix)) sd=script->rid2sd(st); else sd=NULL; script->set_reg(st,sd,num,name,(void*)mapname,script_getref(st,2)); - + //Set MapX num=st->stack->stack_data[st->start+3].u.num; - name=script->get_str(num&0x00ffffff); + name=script->get_str(script_getvarid(num)); prefix=*name; - + if(not_server_variable(prefix)) sd=script->rid2sd(st); else sd=NULL; script->set_reg(st,sd,num,name,(void*)__64BPTRSIZE(x),script_getref(st,3)); - + //Set MapY num=st->stack->stack_data[st->start+4].u.num; - name=script->get_str(num&0x00ffffff); + name=script->get_str(script_getvarid(num)); prefix=*name; - + if(not_server_variable(prefix)) sd=script->rid2sd(st); else sd=NULL; script->set_reg(st,sd,num,name,(void*)__64BPTRSIZE(y),script_getref(st,4)); - + //Return Success value script_pushint(st,0); return true; @@ -12626,11 +13235,11 @@ BUILDIN(logmes) { const char *str; TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return false; - + str = script_getstr(st,2); logs->npc(sd,str); return true; @@ -12642,23 +13251,23 @@ BUILDIN(summon) const char *str,*event=""; TBL_PC *sd; struct mob_data *md; - int tick = timer->gettick(); - + int64 tick = timer->gettick(); + sd=script->rid2sd(st); if (!sd) return true; - - str =script_getstr(st,2); - _class=script_getnum(st,3); + + str = script_getstr(st,2); + _class = script_getnum(st,3); if( script_hasdata(st,4) ) timeout=script_getnum(st,4); - if( script_hasdata(st,5) ){ + if( script_hasdata(st,5) ) { event=script_getstr(st,5); script->check_event(st, event); } - + clif->skill_poseffect(&sd->bl,AM_CALLHOMUN,1,sd->bl.x,sd->bl.y,tick); - - md = mob->once_spawn_sub(&sd->bl, sd->bl.m, sd->bl.x, sd->bl.y, str, _class, event, SZ_SMALL, AI_NONE); + + md = mob->once_spawn_sub(&sd->bl, sd->bl.m, sd->bl.x, sd->bl.y, str, _class, event, SZ_MEDIUM, AI_NONE); if (md) { md->master_id=sd->bl.id; md->special_state.ai = AI_ATTACK; @@ -12667,7 +13276,7 @@ BUILDIN(summon) md->deletetimer = timer->add(tick+(timeout>0?timeout*1000:60000),mob->timer_delete,md->bl.id,0); mob->spawn (md); //Now it is ready for spawning. clif->specialeffect(&md->bl,344,AREA); - sc_start4(&md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, 60000); + sc_start4(NULL, &md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, 60000); } return true; } @@ -12694,18 +13303,18 @@ BUILDIN(isequippedcnt) TBL_PC *sd; int i, j, k, id = 1; int ret = 0; - + sd = script->rid2sd(st); if (!sd) { //If the player is not attached it is a script error anyway... but better prevent the map server from crashing... script_pushint(st,0); return true; } - + for (i=0; id!=0; i++) { - script_fetch(st,i+2, id) else id = 0; + script_fetch(st,i+2, id); if (id <= 0) continue; - + for (j=0; j<EQI_MAX; j++) { int index; index = sd->equip_index[j]; @@ -12713,10 +13322,10 @@ BUILDIN(isequippedcnt) if(j == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == index) continue; if(j == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == index) continue; if(j == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == index || sd->equip_index[EQI_HEAD_LOW] == index)) continue; - + if(!sd->inventory_data[index]) continue; - + if (itemdb_type(id) != IT_CARD) { //No card. Count amount in inventory. if (sd->inventory_data[index]->nameid == id) ret+= sd->status.inventory[index].amount; @@ -12730,7 +13339,7 @@ BUILDIN(isequippedcnt) } } } - + script_pushint(st,ret); return true; } @@ -12749,18 +13358,18 @@ BUILDIN(isequipped) int ret = -1; //Original hash to reverse it when full check fails. unsigned int setitem_hash = 0, setitem_hash2 = 0; - + sd = script->rid2sd(st); - + if (!sd) { //If the player is not attached it is a script error anyway... but better prevent the map server from crashing... script_pushint(st,0); return true; } - + setitem_hash = sd->bonus.setitem_hash; setitem_hash2 = sd->bonus.setitem_hash2; for (i=0; id!=0; i++) { - script_fetch(st,i+2, id) else id = 0; + script_fetch(st,i+2, id); if (id <= 0) continue; flag = 0; @@ -12770,10 +13379,10 @@ BUILDIN(isequipped) if(j == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == index) continue; if(j == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == index) continue; if(j == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == index || sd->equip_index[EQI_HEAD_LOW] == index)) continue; - + if(!sd->inventory_data[index]) continue; - + if (itemdb_type(id) != IT_CARD) { if (sd->inventory_data[index]->nameid != id) continue; @@ -12783,18 +13392,18 @@ BUILDIN(isequipped) if (sd->inventory_data[index]->slot == 0 || itemdb_isspecial(sd->status.inventory[index].card[0])) continue; - - for (k = 0; k < sd->inventory_data[index]->slot; k++) - { //New hash system which should support up to 4 slots on any equipment. [Skotlex] + + for (k = 0; k < sd->inventory_data[index]->slot; k++) { + //New hash system which should support up to 4 slots on any equipment. [Skotlex] unsigned int hash = 0; if (sd->status.inventory[index].card[k] != id) continue; - + hash = 1<<((j<5?j:j-5)*4 + k); // check if card is already used by another set if ( ( j < 5 ? sd->bonus.setitem_hash : sd->bonus.setitem_hash2 ) & hash) continue; - + // We have found a match flag = 1; // Set hash so this card cannot be used by another @@ -12830,20 +13439,20 @@ BUILDIN(cardscnt) { int i, k, id = 1; int ret = 0; int index; - + sd = script->rid2sd(st); - + for (i=0; id!=0; i++) { - script_fetch(st,i+2, id) else id = 0; + script_fetch(st,i+2, id); if (id <= 0) continue; - + index = status->current_equip_item_index; //we get CURRENT WEAPON inventory index from status.c [Lupus] if(index < 0) continue; - + if(!sd->inventory_data[index]) continue; - + if(itemdb_type(id) != IT_CARD) { if (sd->inventory_data[index]->nameid == id) ret+= sd->status.inventory[index].amount; @@ -12857,7 +13466,7 @@ BUILDIN(cardscnt) { } } script_pushint(st,ret); - // script_pushint(st,status->current_equip_item_index); + // script_pushint(st,status->current_equip_item_index); return true; } @@ -12894,7 +13503,7 @@ BUILDIN(unequip) int i; size_t num; TBL_PC *sd; - + num = script_getnum(st,2); sd = script->rid2sd(st); if( sd != NULL && num >= 1 && num <= ARRAYLENGTH(script->equip) ) @@ -12911,19 +13520,19 @@ BUILDIN(equip) int nameid=0,i; TBL_PC *sd; struct item_data *item_data; - + sd = script->rid2sd(st); - + nameid=script_getnum(st,2); if((item_data = itemdb->exists(nameid)) == NULL) { ShowError("wrong item ID : equipitem(%i)\n",nameid); return false; } - ARR_FIND( 0, MAX_INVENTORY, i, sd->status.inventory[i].nameid == nameid ); + 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); - + return true; } @@ -12933,19 +13542,19 @@ BUILDIN(autoequip) struct item_data *item_data; nameid=script_getnum(st,2); flag=script_getnum(st,3); - + if( ( item_data = itemdb->exists(nameid) ) == NULL ) { ShowError("buildin_autoequip: Invalid item '%d'.\n", nameid); return false; } - + if( !itemdb->isequip2(item_data) ) { ShowError("buildin_autoequip: Item '%d' cannot be equipped.\n", nameid); return false; } - + item_data->flag.autoequip = flag>0?1:0; return true; } @@ -12953,15 +13562,15 @@ BUILDIN(autoequip) BUILDIN(setbattleflag) { const char *flag, *value; - + flag = script_getstr(st,2); value = script_getstr(st,3); // HACK: Retrieve number as string (auto-converted) for battle_set_value - + if (battle->config_set_value(flag, value) == 0) ShowWarning("buildin_setbattleflag: unknown battle_config flag '%s'\n",flag); else ShowInfo("buildin_setbattleflag: battle_config flag '%s' is now set to '%s'.\n",flag,value); - + return true; } @@ -12978,10 +13587,10 @@ BUILDIN(getbattleflag) //------------------------------------------------------- BUILDIN(getstrlen) { - + const char *str = script_getstr(st,2); int len = (str) ? (int)strlen(str) : 0; - + script_pushint(st,len); return true; } @@ -12993,9 +13602,9 @@ BUILDIN(charisalpha) { const char *str=script_getstr(st,2); int pos=script_getnum(st,3); - + int val = ( str && pos >= 0 && (unsigned int)pos < strlen(str) ) ? ISALPHA( str[pos] ) != 0 : 0; - + script_pushint(st,val); return true; } @@ -13007,9 +13616,9 @@ BUILDIN(charisupper) { const char *str = script_getstr(st,2); int pos = script_getnum(st,3); - + int val = ( str && pos >= 0 && (unsigned int)pos < strlen(str) ) ? ISUPPER( str[pos] ) : 0; - + script_pushint(st,val); return true; } @@ -13021,9 +13630,9 @@ BUILDIN(charislower) { const char *str = script_getstr(st,2); int pos = script_getnum(st,3); - + int val = ( str && pos >= 0 && (unsigned int)pos < strlen(str) ) ? ISLOWER( str[pos] ) : 0; - + script_pushint(st,val); return true; } @@ -13034,7 +13643,7 @@ BUILDIN(charislower) BUILDIN(charat) { const char *str = script_getstr(st,2); int pos = script_getnum(st,3); - + if( pos >= 0 && (unsigned int)pos < strlen(str) ) { char output[2]; output[0] = str[pos]; @@ -13054,10 +13663,10 @@ BUILDIN(setchar) const char *c = script_getstr(st,3); int index = script_getnum(st,4); char *output = aStrdup(str); - + if(index >= 0 && index < strlen(output)) output[index] = *c; - + script_pushstr(st, output); return true; } @@ -13072,19 +13681,19 @@ BUILDIN(insertchar) int index = script_getnum(st,4); char *output; size_t len = strlen(str); - + if(index < 0) index = 0; else if(index > len) - index = len; - + index = (int)len; + output = (char*)aMalloc(len + 2); - + memcpy(output, str, index); output[index] = c[0]; memcpy(&output[index+1], &str[index], len - index); output[len+1] = '\0'; - + script_pushstr(st, output); return true; } @@ -13098,19 +13707,19 @@ BUILDIN(delchar) int index = script_getnum(st,3); char *output; size_t len = strlen(str); - + if(index < 0 || index > len) { //return original output = aStrdup(str); script_pushstr(st, output); return true; } - + output = (char*)aMalloc(len); - + memcpy(output, str, index); memcpy(&output[index], &str[index+1], len - index); - + script_pushstr(st, output); return true; } @@ -13123,12 +13732,12 @@ BUILDIN(strtoupper) const char *str = script_getstr(st,2); char *output = aStrdup(str); char *cursor = output; - + while (*cursor != '\0') { *cursor = TOUPPER(*cursor); cursor++; } - + script_pushstr(st, output); return true; } @@ -13141,12 +13750,12 @@ BUILDIN(strtolower) const char *str = script_getstr(st,2); char *output = aStrdup(str); char *cursor = output; - + while (*cursor != '\0') { *cursor = TOLOWER(*cursor); cursor++; } - + script_pushstr(st, output); return true; } @@ -13160,18 +13769,18 @@ BUILDIN(substr) char *output; int start = script_getnum(st,3); int end = script_getnum(st,4); - + int len = 0; - + if(start >= 0 && end < strlen(str) && start <= end) { len = end - start + 1; output = (char*)aMalloc(len + 1); memcpy(output, &str[start], len); } else output = (char*)aMalloc(1); - + output[len] = '\0'; - + script_pushstr(st, output); return true; } @@ -13189,15 +13798,15 @@ BUILDIN(explode) size_t len = strlen(str); int i = 0, j = 0; int start; - - + + char *temp; const char* name; - + TBL_PC* sd = NULL; - + temp = (char*)aMalloc(len + 1); - + if( !data_isreference(data) ) { ShowError("script:explode: not a variable\n"); @@ -13205,19 +13814,11 @@ BUILDIN(explode) st->state = END; return false;// not a variable } - + id = reference_getid(data); start = reference_getindex(data); name = reference_getname(data); - - if( not_array_variable(*name) ) - { - ShowError("script:explode: illegal scope\n"); - script->reportdata(data); - st->state = END; - return false;// not supported - } - + if( !is_string_variable(name) ) { ShowError("script:explode: not string array\n"); @@ -13225,14 +13826,14 @@ BUILDIN(explode) st->state = END; return false;// data type mismatch } - + if( not_server_variable(*name) ) { sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached } - + while(str[i] != '\0') { if(str[i] == delimiter && start < SCRIPT_MAX_ARRAYSIZE-1) { //break at delimiter but ignore after reaching last array index temp[j] = '\0'; @@ -13246,7 +13847,7 @@ BUILDIN(explode) //set last string temp[j] = '\0'; script->set_reg(st, sd, reference_uid(id, start), name, (void*)temp, reference_getref(data)); - + aFree(temp); return true; } @@ -13259,14 +13860,14 @@ BUILDIN(implode) { struct script_data* data = script_getdata(st, 2); const char *glue = NULL, *name, *temp; - int32 glue_len = 0, array_size, id; - size_t len = 0; - int i, k = 0; - + uint32 array_size, id; + size_t len = 0, glue_len = 0, k = 0; + int i; + TBL_PC* sd = NULL; - + char *output; - + if( !data_isreference(data) ) { ShowError("script:implode: not a variable\n"); @@ -13274,18 +13875,10 @@ BUILDIN(implode) st->state = END; return false;// not a variable } - + id = reference_getid(data); name = reference_getname(data); - - if( not_array_variable(*name) ) - { - ShowError("script:implode: illegal scope\n"); - script->reportdata(data); - st->state = END; - return false;// not supported - } - + if( !is_string_variable(name) ) { ShowError("script:implode: not string array\n"); @@ -13293,29 +13886,29 @@ BUILDIN(implode) st->state = END; return false;// data type mismatch } - + if( not_server_variable(*name) ) { sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached } - + //count chars - array_size = script->getarraysize(st, id, reference_getindex(data), is_string_variable(name), reference_getref(data)) - 1; - - if(array_size == -1) //empty array check (AmsTaff) - { - ShowWarning("script:implode: array length = 0\n"); - output = (char*)aMalloc(sizeof(char)*5); - sprintf(output,"%s","NULL"); + array_size = script->array_highest_key(st,sd,name,reference_getref(data)) - 1; + + if(array_size == -1) { + //empty array check (AmsTaff) + ShowWarning("script:implode: array length = 0\n"); + output = (char*)aMalloc(sizeof(char)*5); + sprintf(output,"%s","NULL"); } else { for(i = 0; i <= array_size; ++i) { temp = (char*) script->get_val2(st, reference_uid(id, i), reference_getref(data)); len += strlen(temp); script_removetop(st, -1, 0); } - + //allocate mem if( script_hasdata(st,3) ) { glue = script_getstr(st,3); @@ -13323,7 +13916,7 @@ BUILDIN(implode) len += glue_len * (array_size); } output = (char*)aMalloc(len + 1); - + //build output for(i = 0; i < array_size; ++i) { temp = (char*) script->get_val2(st, reference_uid(id, i), reference_getref(data)); @@ -13341,10 +13934,10 @@ BUILDIN(implode) memcpy(&output[k], temp, len); k += len; script_removetop(st, -1, 0); - + output[k] = '\0'; } - + script_pushstr(st, output); return true; } @@ -13354,232 +13947,242 @@ BUILDIN(implode) // Implements C sprintf, except format %n. The resulting string is // returned, instead of being saved in variable by reference. //------------------------------------------------------- -BUILDIN(sprintf) -{ - unsigned int len, argc = 0, arg = 0, buf2_len = 0; - const char* format; - char* p; - char* q; - char* buf = NULL; - char* buf2 = NULL; - struct script_data* data; - StringBuf final_buf; - - // Fetch init data - format = script_getstr(st, 2); - argc = script_lastdata(st)-2; - len = strlen(format); - - // Skip parsing, where no parsing is required. - if(len==0){ - script_pushconststr(st,""); - return true; - } - - // Pessimistic alloc - CREATE(buf, char, len+1); - - // Need not be parsed, just solve stuff like %%. - if(argc==0){ +BUILDIN(sprintf) { + unsigned int argc = 0, arg = 0; + const char* format; + char* p; + char* q; + char* buf = NULL; + char* buf2 = NULL; + struct script_data* data; + size_t len, buf2_len = 0; + StringBuf final_buf; + + // Fetch init data + format = script_getstr(st, 2); + argc = script_lastdata(st)-2; + len = strlen(format); + + // Skip parsing, where no parsing is required. + if(len==0) { + script_pushconststr(st,""); + return true; + } + + // Pessimistic alloc + CREATE(buf, char, len+1); + + // Need not be parsed, just solve stuff like %%. + if(argc==0) { memcpy(buf,format,len+1); - script_pushstrcopy(st, buf); - aFree(buf); - return true; - } - - safestrncpy(buf, format, len+1); - - // Issue sprintf for each parameter - StrBuf->Init(&final_buf); - q = buf; - while((p = strchr(q, '%'))!=NULL){ - if(p!=q){ - len = p-q+1; - if(buf2_len<len){ - RECREATE(buf2, char, len); - buf2_len = len; - } - safestrncpy(buf2, q, len); - StrBuf->AppendStr(&final_buf, buf2); - q = p; - } - p = q+1; - if(*p=='%'){ // %% - StrBuf->AppendStr(&final_buf, "%"); - q+=2; - continue; - } - if(*p=='n'){ // %n - ShowWarning("buildin_sprintf: Format %%n not supported! Skipping...\n"); - script->reportsrc(st); - q+=2; - continue; - } - if(arg>=argc){ - ShowError("buildin_sprintf: Not enough arguments passed!\n"); - if(buf) aFree(buf); - if(buf2) aFree(buf2); - StrBuf->Destroy(&final_buf); - script_pushconststr(st,""); - return false; - } - if((p = strchr(q+1, '%'))==NULL){ - p = strchr(q, 0); // EOS - } - len = p-q+1; - if(buf2_len<len){ - RECREATE(buf2, char, len); - buf2_len = len; - } - safestrncpy(buf2, q, len); - q = p; - - // Note: This assumes the passed value being the correct - // type to the current format specifier. If not, the server - // probably crashes or returns anything else, than expected, - // but it would behave in normal code the same way so it's - // the scripter's responsibility. - data = script_getdata(st, arg+3); - if(data_isstring(data)){ // String - StrBuf->Printf(&final_buf, buf2, script_getstr(st, arg+3)); - }else if(data_isint(data)){ // Number - StrBuf->Printf(&final_buf, buf2, script_getnum(st, arg+3)); - }else if(data_isreference(data)){ // Variable - char* name = reference_getname(data); - if(name[strlen(name)-1]=='$'){ // var Str - StrBuf->Printf(&final_buf, buf2, script_getstr(st, arg+3)); - }else{ // var Int - StrBuf->Printf(&final_buf, buf2, script_getnum(st, arg+3)); - } - }else{ // Unsupported type - ShowError("buildin_sprintf: Unknown argument type!\n"); - if(buf) aFree(buf); - if(buf2) aFree(buf2); - StrBuf->Destroy(&final_buf); - script_pushconststr(st,""); - return false; - } - arg++; - } - - // Append anything left - if(*q){ - StrBuf->AppendStr(&final_buf, q); - } - - // Passed more, than needed - if(arg<argc){ - ShowWarning("buildin_sprintf: Unused arguments passed.\n"); - script->reportsrc(st); - } - - script_pushstrcopy(st, StrBuf->Value(&final_buf)); - - if(buf) aFree(buf); - if(buf2) aFree(buf2); - StrBuf->Destroy(&final_buf); - - return true; + script_pushstrcopy(st, buf); + aFree(buf); + return true; + } + + safestrncpy(buf, format, len+1); + + // Issue sprintf for each parameter + StrBuf->Init(&final_buf); + q = buf; + while((p = strchr(q, '%'))!=NULL) { + if(p!=q) { + len = p-q+1; + if(buf2_len<len) { + RECREATE(buf2, char, len); + buf2_len = len; + } + safestrncpy(buf2, q, len); + StrBuf->AppendStr(&final_buf, buf2); + q = p; + } + p = q+1; + if(*p=='%') { // %% + StrBuf->AppendStr(&final_buf, "%"); + q+=2; + continue; + } + if(*p=='n') { // %n + ShowWarning("buildin_sprintf: Format %%n not supported! Skipping...\n"); + script->reportsrc(st); + q+=2; + continue; + } + if(arg>=argc) { + ShowError("buildin_sprintf: Not enough arguments passed!\n"); + if(buf) aFree(buf); + if(buf2) aFree(buf2); + StrBuf->Destroy(&final_buf); + script_pushconststr(st,""); + return false; + } + if((p = strchr(q+1, '%'))==NULL) { + p = strchr(q, 0); // EOS + } + len = p-q+1; + if(buf2_len<len) { + RECREATE(buf2, char, len); + buf2_len = len; + } + safestrncpy(buf2, q, len); + q = p; + + // Note: This assumes the passed value being the correct + // type to the current format specifier. If not, the server + // probably crashes or returns anything else, than expected, + // but it would behave in normal code the same way so it's + // the scripter's responsibility. + data = script_getdata(st, arg+3); + if(data_isstring(data)) { // String + StrBuf->Printf(&final_buf, buf2, script_getstr(st, arg+3)); + } else if(data_isint(data)) { // Number + StrBuf->Printf(&final_buf, buf2, script_getnum(st, arg+3)); + } else if(data_isreference(data)) { // Variable + char* name = reference_getname(data); + if(name[strlen(name)-1]=='$') { // var Str + StrBuf->Printf(&final_buf, buf2, script_getstr(st, arg+3)); + } else { // var Int + StrBuf->Printf(&final_buf, buf2, script_getnum(st, arg+3)); + } + } else { // Unsupported type + ShowError("buildin_sprintf: Unknown argument type!\n"); + if(buf) aFree(buf); + if(buf2) aFree(buf2); + StrBuf->Destroy(&final_buf); + script_pushconststr(st,""); + return false; + } + arg++; + } + + // Append anything left + if(*q) { + StrBuf->AppendStr(&final_buf, q); + } + + // Passed more, than needed + if(arg<argc) { + ShowWarning("buildin_sprintf: Unused arguments passed.\n"); + script->reportsrc(st); + } + + script_pushstrcopy(st, StrBuf->Value(&final_buf)); + + if(buf) aFree(buf); + if(buf2) aFree(buf2); + StrBuf->Destroy(&final_buf); + + return true; } //======================================================= // sscanf(<str>, <format>, ...); // Implements C sscanf. //------------------------------------------------------- -BUILDIN(sscanf){ - unsigned int argc, arg = 0, len; - struct script_data* data; - struct map_session_data* sd = NULL; - const char* str; - const char* format; - const char* p; - const char* q; - char* buf = NULL; - char* buf_p; - char* ref_str = NULL; - int ref_int; - - // Get data - str = script_getstr(st, 2); - format = script_getstr(st, 3); - argc = script_lastdata(st)-3; - - len = strlen(format); - CREATE(buf, char, len*2+1); - - // Issue sscanf for each parameter - *buf = 0; - q = format; - while((p = strchr(q, '%'))){ - if(p!=q){ - strncat(buf, q, (size_t)(p-q)); - q = p; - } - p = q+1; - if(*p=='*' || *p=='%'){ // Skip - strncat(buf, q, 2); - q+=2; - continue; - } - if(arg>=argc){ - ShowError("buildin_sscanf: Not enough arguments passed!\n"); - script_pushint(st, -1); - if(buf) aFree(buf); - if(ref_str) aFree(ref_str); - return false; - } - if((p = strchr(q+1, '%'))==NULL){ - p = strchr(q, 0); // EOS - } - len = p-q; - strncat(buf, q, len); - q = p; - - // Validate output - data = script_getdata(st, arg+4); - if(!data_isreference(data) || !reference_tovariable(data)){ - ShowError("buildin_sscanf: Target argument is not a variable!\n"); - script_pushint(st, -1); - if(buf) aFree(buf); - if(ref_str) aFree(ref_str); - return false; - } - buf_p = reference_getname(data); - if(not_server_variable(*buf_p) && (sd = script->rid2sd(st))==NULL){ - script_pushint(st, -1); - if(buf) aFree(buf); - if(ref_str) aFree(ref_str); - return true; - } - - // Save value if any - if(buf_p[strlen(buf_p)-1]=='$'){ // String - if(ref_str==NULL){ - CREATE(ref_str, char, strlen(str)+1); - } - if(sscanf(str, buf, ref_str)==0){ - break; - } +BUILDIN(sscanf) { + unsigned int argc, arg = 0; + struct script_data* data; + struct map_session_data* sd = NULL; + const char* str; + const char* format; + const char* p; + const char* q; + char* buf = NULL; + char* buf_p; + char* ref_str = NULL; + int ref_int; + size_t len; + + // Get data + str = script_getstr(st, 2); + format = script_getstr(st, 3); + argc = script_lastdata(st)-3; + + len = strlen(format); + + if (len != 0 && strlen(str) == 0) { + // If the source string is empty but the format string is not, we return -1 + // according to the C specs. (if the format string is also empty, we shall + // continue and return 0: 0 conversions took place out of the 0 attempted.) + script_pushint(st, -1); + return true; + } + + CREATE(buf, char, len*2+1); + + // Issue sscanf for each parameter + *buf = 0; + q = format; + while((p = strchr(q, '%'))) { + if(p!=q) { + strncat(buf, q, (size_t)(p-q)); + q = p; + } + p = q+1; + if(*p=='*' || *p=='%') { // Skip + strncat(buf, q, 2); + q+=2; + continue; + } + if(arg>=argc) { + ShowError("buildin_sscanf: Not enough arguments passed!\n"); + script_pushint(st, -1); + if(buf) aFree(buf); + if(ref_str) aFree(ref_str); + return false; + } + if((p = strchr(q+1, '%'))==NULL) { + p = strchr(q, 0); // EOS + } + len = p-q; + strncat(buf, q, len); + q = p; + + // Validate output + data = script_getdata(st, arg+4); + if(!data_isreference(data) || !reference_tovariable(data)) { + ShowError("buildin_sscanf: Target argument is not a variable!\n"); + script_pushint(st, -1); + if(buf) aFree(buf); + if(ref_str) aFree(ref_str); + return false; + } + buf_p = reference_getname(data); + if(not_server_variable(*buf_p) && (sd = script->rid2sd(st))==NULL) { + script_pushint(st, -1); + if(buf) aFree(buf); + if(ref_str) aFree(ref_str); + return true; + } + + // Save value if any + if(buf_p[strlen(buf_p)-1]=='$') { // String + if(ref_str==NULL) { + CREATE(ref_str, char, strlen(str)+1); + } + if(sscanf(str, buf, ref_str)==0) { + break; + } script->set_reg(st, sd, reference_uid( reference_getid(data), reference_getindex(data) ), buf_p, (void *)(ref_str), reference_getref(data)); - } else { // Number - if(sscanf(str, buf, &ref_int)==0){ - break; - } + } else { // Number + if(sscanf(str, buf, &ref_int)==0) { + break; + } script->set_reg(st, sd, reference_uid( reference_getid(data), reference_getindex(data) ), buf_p, (void *)__64BPTRSIZE(ref_int), reference_getref(data)); - } - arg++; - - // Disable used format (%... -> %*...) - buf_p = strchr(buf, 0); - memmove(buf_p-len+2, buf_p-len+1, len); - *(buf_p-len+1) = '*'; - } - - script_pushint(st, arg); - if(buf) aFree(buf); - if(ref_str) aFree(ref_str); - - return true; + } + arg++; + + // Disable used format (%... -> %*...) + buf_p = strchr(buf, 0); + memmove(buf_p-len+2, buf_p-len+1, len); + *(buf_p-len+1) = '*'; + } + + script_pushint(st, arg); + if(buf) aFree(buf); + if(ref_str) aFree(ref_str); + + return true; } //======================================================= @@ -13594,17 +14197,17 @@ BUILDIN(strpos) { const char *needle = script_getstr(st,3); int i; size_t len; - + if( script_hasdata(st,4) ) i = script_getnum(st,4); else i = 0; - + if (needle[0] == '\0') { script_pushint(st, -1); return true; } - + len = strlen(haystack); for ( ; i < len; ++i ) { if ( haystack[i] == *needle ) { @@ -13642,48 +14245,47 @@ BUILDIN(replacestr) size_t findlen = strlen(find); struct StringBuf output; bool usecase = true; - + int count = 0; int numFinds = 0; int i = 0, f = 0; - + if(findlen == 0) { ShowError("script:replacestr: Invalid search length.\n"); st->state = END; return false; } - + if(script_hasdata(st, 5)) { - if( !script_isstring(st,5) ) + if( script_isinttype(st,5) ) { usecase = script_getnum(st, 5) != 0; - else { - ShowError("script:replacestr: Invalid usecase value. Expected int got string\n"); + } else { + ShowError("script:replacestr: Invalid usecase value. Expected int.\n"); st->state = END; return false; } } - + if(script_hasdata(st, 6)) { - count = script_getnum(st, 6); - if(count == 0) { - ShowError("script:replacestr: Invalid count value. Expected int got string\n"); + if (!script_isinttype(st, 5) || (count = script_getnum(st, 6) == 0)) { + ShowError("script:replacestr: Invalid count value. Expected int.\n"); st->state = END; return false; } } - + StrBuf->Init(&output); - + for(; i < inputlen; i++) { - if(count && count == numFinds) { //found enough, stop looking - break; + if(count && count == numFinds) { + break; //found enough, stop looking } - + for(f = 0; f <= findlen; f++) { if(f == findlen) { //complete match numFinds++; StrBuf->AppendStr(&output, replace); - + i += findlen - 1; break; } else { @@ -13701,11 +14303,11 @@ BUILDIN(replacestr) } } } - + //append excess after enough found if(i < inputlen) StrBuf->AppendStr(&output, &(input[i])); - + script_pushstrcopy(st, StrBuf->Value(&output)); StrBuf->Destroy(&output); return true; @@ -13724,26 +14326,26 @@ BUILDIN(countstr) size_t inputlen = strlen(input); size_t findlen = strlen(find); bool usecase = true; - + int numFinds = 0; int i = 0, f = 0; - + if(findlen == 0) { ShowError("script:countstr: Invalid search length.\n"); st->state = END; return false; } - + if(script_hasdata(st, 4)) { - if( !script_isstring(st,4) ) + if( script_isinttype(st,4) ) usecase = script_getnum(st, 4) != 0; else { - ShowError("script:countstr: Invalid usecase value. Expected int got string\n"); + ShowError("script:countstr: Invalid usecase value. Expected int.\n"); st->state = END; return false; } } - + for(; i < inputlen; i++) { for(f = 0; f <= findlen; f++) { if(f == findlen) { //complete match @@ -13775,50 +14377,40 @@ 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) -{ +BUILDIN(setnpcdisplay) { const char* name; const char* newname = NULL; int class_ = -1, size = -1; - struct script_data* data; struct npc_data* nd; - + name = script_getstr(st,2); - data = script_getdata(st,3); - + if( script_hasdata(st,4) ) class_ = script_getnum(st,4); if( script_hasdata(st,5) ) size = script_getnum(st,5); - - script->get_val(st, data); - if( data_isstring(data) ) - newname = script->conv_str(st,data); - else if( data_isint(data) ) - class_ = script->conv_num(st,data); + + if( script_isstringtype(st, 3) ) + newname = script_getstr(st, 3); else - { - ShowError("script:setnpcdisplay: expected string or number\n"); - script->reportdata(data); - return false; - } - + class_ = script_getnum(st, 3); + nd = npc->name2id(name); if( nd == NULL ) {// not found script_pushint(st,1); return true; } - + // update npc if( newname ) npc->setdisplayname(nd, newname); - + if( size != -1 && size != (int)nd->size ) nd->size = size; else size = -1; - + if( class_ != -1 && nd->class_ != class_ ) npc->setclass(nd, class_); else if( size != -1 ) @@ -13826,19 +14418,39 @@ BUILDIN(setnpcdisplay) clif->clearunit_area(&nd->bl, CLR_OUTSIGHT); clif->spawn(&nd->bl); } - + script_pushint(st,0); return true; } -BUILDIN(atoi) -{ +BUILDIN(atoi) { const char *value; value = script_getstr(st,2); script_pushint(st,atoi(value)); return true; } +BUILDIN(axtoi) { + const char *hex = script_getstr(st,2); + long value = strtol(hex, NULL, 16); +#if LONG_MAX > INT_MAX || LONG_MIN < INT_MIN + value = cap_value(value, INT_MIN, INT_MAX); +#endif + script_pushint(st, (int)value); + return true; +} + +BUILDIN(strtol) { + const char *string = script_getstr(st, 2); + int base = script_getnum(st, 3); + long value = strtol(string, NULL, base); +#if LONG_MAX > INT_MAX || LONG_MIN < INT_MIN + value = cap_value(value, INT_MIN, INT_MAX); +#endif + script_pushint(st, (int)value); + return true; +} + // case-insensitive substring search [lordalfa] BUILDIN(compare) { @@ -13873,12 +14485,12 @@ BUILDIN(pow) BUILDIN(distance) { int x0, y0, x1, y1; - + x0 = script_getnum(st,2); y0 = script_getnum(st,3); x1 = script_getnum(st,4); y1 = script_getnum(st,5); - + script_pushint(st,distance_xy(x0,y0,x1,y1)); return true; } @@ -13889,7 +14501,7 @@ BUILDIN(md5) { const char *tmpstr; char *md5str; - + tmpstr = script_getstr(st,2); md5str = (char *)aMalloc((32+1)*sizeof(char)); MD5_String(tmpstr, md5str); @@ -13906,10 +14518,10 @@ BUILDIN(setd) const char *buffer; int elem; buffer = script_getstr(st, 2); - + if(sscanf(buffer, "%99[^[][%d]", varname, &elem) < 2) elem = 0; - + if( not_server_variable(*varname) ) { sd = script->rid2sd(st); @@ -13919,13 +14531,13 @@ BUILDIN(setd) return true; } } - + if( is_string_variable(varname) ) { script->setd_sub(st, sd, varname, elem, (void *)script_getstr(st, 3), NULL); } else { script->setd_sub(st, sd, varname, elem, (void *)__64BPTRSIZE(script_getnum(st, 3)), NULL); } - + return true; } @@ -13936,10 +14548,10 @@ int buildin_query_sql_sub(struct script_state* st, Sql* handle) const char* query; struct script_data* data; const char* name; - int max_rows = SCRIPT_MAX_ARRAYSIZE; // maximum number of rows + unsigned int max_rows = SCRIPT_MAX_ARRAYSIZE; // maximum number of rows int num_vars; int num_cols; - + // check target variables for( i = 3; script_hasdata(st,i); ++i ) { data = script_getdata(st, i); @@ -13953,8 +14565,6 @@ int buildin_query_sql_sub(struct script_state* st, Sql* handle) return false; } } - if( not_array_variable(*name) ) - max_rows = 1;// not an array, limit to one row } else { ShowError("script:query_sql: not a variable\n"); script->reportdata(data); @@ -13963,22 +14573,22 @@ int buildin_query_sql_sub(struct script_state* st, Sql* handle) } } num_vars = i - 3; - + // Execute the query query = script_getstr(st,2); - + if( SQL_ERROR == SQL->QueryStr(handle, query) ) { Sql_ShowDebug(handle); - script_pushint(st, 0); + st->state = END; return false; } - + if( SQL->NumRows(handle) == 0 ) { // No data received SQL->FreeResult(handle); script_pushint(st, 0); return true; } - + // Count the number of columns to store num_cols = SQL->NumColumns(handle); if( num_vars < num_cols ) { @@ -13988,15 +14598,15 @@ int buildin_query_sql_sub(struct script_state* st, Sql* handle) ShowWarning("script:query_sql: Too many variables (%u extra).\n", (unsigned int)(num_vars-num_cols)); script->reportsrc(st); } - + // Store data for( i = 0; i < max_rows && SQL_SUCCESS == SQL->NextRow(handle); ++i ) { for( j = 0; j < num_vars; ++j ) { char* str = NULL; - + if( j < num_cols ) SQL->GetData(handle, j, &str, NULL); - + data = script_getdata(st, j+3); name = reference_getname(data); if( is_string_variable(name) ) @@ -14009,11 +14619,11 @@ int buildin_query_sql_sub(struct script_state* st, Sql* handle) ShowWarning("script:query_sql: Only %d/%u rows have been stored.\n", max_rows, (unsigned int)SQL->NumRows(handle)); script->reportsrc(st); } - + // Free data SQL->FreeResult(handle); script_pushint(st, i); - + return true; } BUILDIN(query_sql) { @@ -14035,7 +14645,7 @@ BUILDIN(escape_sql) const char *str; char *esc_str; size_t len; - + str = script_getstr(st,2); len = strlen(str); esc_str = (char*)aMalloc(len*2+1); @@ -14049,15 +14659,15 @@ BUILDIN(getd) char varname[100]; const char *buffer; int elem; - + buffer = script_getstr(st, 2); - + if(sscanf(buffer, "%[^[][%d]", varname, &elem) < 2) elem = 0; - + // Push the 'pointer' so it's more flexible [Lance] script->push_val(st->stack, C_NAME, reference_uid(script->add_str(varname), elem),NULL); - + return true; } @@ -14069,7 +14679,7 @@ BUILDIN(petstat) struct pet_data *pd; int flag = script_getnum(st,2); sd = script->rid2sd(st); - if(!sd || !sd->status.pet_id || !sd->pd){ + if(!sd || !sd->status.pet_id || !sd->pd) { if(flag == 2) script_pushconststr(st, ""); else @@ -14077,7 +14687,7 @@ BUILDIN(petstat) return true; } pd = sd->pd; - switch(flag){ + switch(flag) { case 1: script_pushint(st,(int)pd->pet.class_); break; case 2: script_pushstrcopy(st, pd->pet.name); break; case 3: script_pushint(st,(int)pd->pet.level); break; @@ -14111,12 +14721,12 @@ BUILDIN(callshop) script_pushint(st,0); return false; } - + if( nd->subtype == SHOP ) { // flag the user as using a valid script call for opening the shop (for floating NPCs) sd->state.callshop = 1; - + switch( flag ) { case 1: npc->buysellsel(sd,nd->bl.id,0); break; //Buy window @@ -14126,7 +14736,7 @@ BUILDIN(callshop) } else clif->cashshop_show(sd, nd); - + sd->npc_shopid = nd->bl.id; script_pushint(st,1); return true; @@ -14138,16 +14748,16 @@ BUILDIN(npcshopitem) struct npc_data* nd = npc->name2id(npcname); int n, i; int amount; - - if( !nd || ( nd->subtype != SHOP && nd->subtype != CASHSHOP ) ) - { //Not found. + + if( !nd || ( nd->subtype != SHOP && nd->subtype != CASHSHOP ) ) { + //Not found. script_pushint(st,0); return true; } - + // get the count of new entries amount = (script_lastdata(st)-2)/2; - + // generate new shop item list RECREATE(nd->u.shop.shop_item, struct npc_item_list, amount); for( n = 0, i = 3; n < amount; n++, i+=2 ) @@ -14156,7 +14766,7 @@ BUILDIN(npcshopitem) nd->u.shop.shop_item[n].value = script_getnum(st,i+1); } nd->u.shop.count = n; - + script_pushint(st,1); return true; } @@ -14167,16 +14777,16 @@ BUILDIN(npcshopadditem) struct npc_data* nd = npc->name2id(npcname); int n, i; int amount; - - if( !nd || ( nd->subtype != SHOP && nd->subtype != CASHSHOP ) ) - { //Not found. + + if( !nd || ( nd->subtype != SHOP && nd->subtype != CASHSHOP ) ) { + //Not found. script_pushint(st,0); return true; } - + // get the count of new entries amount = (script_lastdata(st)-2)/2; - + // append new items to existing shop item list RECREATE(nd->u.shop.shop_item, struct npc_item_list, nd->u.shop.count+amount); for( n = nd->u.shop.count, i = 3; n < nd->u.shop.count+amount; n++, i+=2 ) @@ -14185,7 +14795,7 @@ BUILDIN(npcshopadditem) nd->u.shop.shop_item[n].value = script_getnum(st,i+1); } nd->u.shop.count = n; - + script_pushint(st,1); return true; } @@ -14198,21 +14808,21 @@ BUILDIN(npcshopdelitem) int n, i; int amount; int size; - - if( !nd || ( nd->subtype != SHOP && nd->subtype != CASHSHOP ) ) - { //Not found. + + if( !nd || ( nd->subtype != SHOP && nd->subtype != CASHSHOP ) ) { + //Not found. script_pushint(st,0); return true; } - + amount = script_lastdata(st)-2; size = nd->u.shop.count; - + // remove specified items from the shop item list for( i = 3; i < 3 + amount; i++ ) { nameid = script_getnum(st,i); - + ARR_FIND( 0, size, n, nd->u.shop.shop_item[n].nameid == nameid ); if( n < size ) { @@ -14220,10 +14830,10 @@ BUILDIN(npcshopdelitem) size--; } } - + RECREATE(nd->u.shop.shop_item, struct npc_item_list, size); nd->u.shop.count = size; - + script_pushint(st,1); return true; } @@ -14233,21 +14843,21 @@ BUILDIN(npcshopattach) { const char* npcname = script_getstr(st,2); struct npc_data* nd = npc->name2id(npcname); int flag = 1; - + if( script_hasdata(st,3) ) flag = script_getnum(st,3); - - if( !nd || nd->subtype != SHOP ) - { //Not found. + + if( !nd || nd->subtype != SHOP ) { + //Not found. script_pushint(st,0); return true; } - + if (flag) nd->master_nd = ((struct npc_data *)map->id2bl(st->oid)); else nd->master_nd = NULL; - + script_pushint(st,1); return true; } @@ -14255,11 +14865,11 @@ BUILDIN(npcshopattach) { /*========================================== * Returns some values of an item [Lupus] * Price, Weight, etc... - setitemscript(itemID,"{new item bonus script}",[n]); - Where n: - 0 - script - 1 - Equip script - 2 - Unequip script + * setitemscript(itemID,"{new item bonus script}",[n]); + * Where n: + * 0 - script + * 1 - Equip script + * 2 - Unequip script *------------------------------------------*/ BUILDIN(setitemscript) { @@ -14267,13 +14877,13 @@ BUILDIN(setitemscript) const char *new_bonus_script; struct item_data *i_data; struct script_code **dstscript; - - item_id = script_getnum(st,2); + + item_id = script_getnum(st,2); new_bonus_script = script_getstr(st,3); if( script_hasdata(st,4) ) n=script_getnum(st,4); i_data = itemdb->exists(item_id); - + if (!i_data || new_bonus_script==NULL || ( new_bonus_script[0] && new_bonus_script[0]!='{' )) { script_pushint(st,0); return true; @@ -14291,50 +14901,130 @@ BUILDIN(setitemscript) } if(*dstscript) script->free_code(*dstscript); - + *dstscript = new_bonus_script[0] ? script->parse(new_bonus_script, "script_setitemscript", 0, 0) : NULL; script_pushint(st,1); return true; } -/* Work In Progress [Lupus] - BUILDIN(addmonsterdrop) - { - int class_,item_id,chance; - class_=script_getnum(st,2); - item_id=script_getnum(st,3); - chance=script_getnum(st,4); - if(class_>1000 && item_id>500 && chance>0) { - script_pushint(st,1); - } else { - script_pushint(st,0); - } - } - - BUILDIN(delmonsterdrop) - { - int class_,item_id; - class_=script_getnum(st,2); - item_id=script_getnum(st,3); - if(class_>1000 && item_id>500) { - script_pushint(st,1); - } else { - script_pushint(st,0); - } - } - */ +/*======================================================= + * Temporarily add or update a mob drop + * Original Idea By: [Lupus], [Akinari] + * + * addmonsterdrop <mob_id or name>,<item_id>,<rate>; + * + * If given an item the mob already drops, the rate + * 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) { + struct mob_db *monster; + int item_id, rate, i, c = MAX_MOB_DROP; + + if( script_isstringtype(st,2) ) + monster = mob->db(mob->db_searchname(script_getstr(st,2))); + else + monster = mob->db(script_getnum(st,2)); + + if( monster == mob->dummy ) { + if( script_isstringtype(st,2) ) { + ShowError("buildin_addmonsterdrop: invalid mob name: '%s'.\n", script_getstr(st,2)); + } else { + ShowError("buildin_addmonsterdrop: invalid mob id: '%d'.\n", script_getnum(st,2)); + } + return false; + } + + item_id = script_getnum(st,3); + if( !itemdb->exists(item_id) ) { + ShowError("buildin_addmonsterdrop: Invalid item ID: '%d'.\n", item_id); + return false; + } + + rate = script_getnum(st,4); + if( rate < 1 || rate > 10000 ) { + ShowWarning("buildin_addmonsterdrop: Invalid drop rate '%d'. Capping to the [1:10000] range.\n", rate); + rate = cap_value(rate,1,10000); + } + + for( i = 0; i < MAX_MOB_DROP; i++ ) { + if( monster->dropitem[i].nameid == item_id ) // Item ID found + break; + if( c == MAX_MOB_DROP && monster->dropitem[i].nameid < 1 ) // First empty slot + c = i; + } + if( i < MAX_MOB_DROP ) // If the item ID was found, prefer it + c = i; + + if( c < MAX_MOB_DROP ) { + // Fill in the slot with the item and rate + monster->dropitem[c].nameid = item_id; + monster->dropitem[c].p = rate; + script_pushint(st,1); + } else { + //No place to put the new drop + script_pushint(st,0); + } + + return true; +} + +/*======================================================= + * Temporarily remove a mob drop + * Original Idea By: [Lupus], [Akinari] + * + * delmonsterdrop <mob_id or name>,<item_id>; + * + * Returns 1 if succeeded (deleted a mob drop) + *-------------------------------------------------------*/ +BUILDIN(delmonsterdrop) { + struct mob_db *monster; + int item_id, i; + + if( script_isstringtype(st, 2) ) + monster = mob->db(mob->db_searchname(script_getstr(st, 2))); + else + monster = mob->db(script_getnum(st, 2)); + + if( monster == mob->dummy ) { + if( script_isstringtype(st, 2) ) { + ShowError("buildin_delmonsterdrop: invalid mob name: '%s'.\n", script_getstr(st,2)); + } else { + ShowError("buildin_delmonsterdrop: invalid mob id: '%d'.\n", script_getnum(st,2)); + } + return false; + } + + item_id = script_getnum(st,3); + if( !itemdb->exists(item_id) ) { + ShowError("buildin_delmonsterdrop: Invalid item ID: '%d'.\n", item_id); + return false; + } + + for( i = 0; i < MAX_MOB_DROP; i++ ) { + if( monster->dropitem[i].nameid == item_id ) { + monster->dropitem[i].nameid = 0; + monster->dropitem[i].p = 0; + script_pushint(st,1); + return true; + } + } + // No drop on that monster + script_pushint(st,0); + return true; +} /*========================================== * Returns some values of a monster [Lupus] * Name, Level, race, size, etc... - getmonsterinfo(monsterID,queryIndex); + * getmonsterinfo(monsterID,queryIndex); *------------------------------------------*/ BUILDIN(getmonsterinfo) { struct mob_db *monster; int mob_id; - - mob_id = script_getnum(st,2); + + mob_id = script_getnum(st,2); if (!mob->db_checkid(mob_id)) { ShowError("buildin_getmonsterinfo: Wrong Monster ID: %i\n", mob_id); if ( !script_getnum(st,3) ) //requested a string @@ -14376,17 +15066,17 @@ BUILDIN(getmonsterinfo) BUILDIN(checkvending) // check vending [Nab4] { TBL_PC *sd = NULL; - + if(script_hasdata(st,2)) sd = map->nick2sd(script_getstr(st,2)); else sd = script->rid2sd(st); - + if(sd) script_pushint(st, sd->state.autotrade ? 2 : sd->state.vending); else script_pushint(st,0); - + return true; } @@ -14394,33 +15084,33 @@ BUILDIN(checkvending) // check vending [Nab4] // check chatting [Marka] BUILDIN(checkchatting) { TBL_PC *sd = NULL; - + if(script_hasdata(st,2)) sd = map->nick2sd(script_getstr(st,2)); else sd = script->rid2sd(st); - + if(sd) script_pushint(st,(sd->chatID != 0)); else script_pushint(st,0); - + return true; } BUILDIN(checkidle) { TBL_PC *sd = NULL; - + if (script_hasdata(st, 2)) sd = map->nick2sd(script_getstr(st, 2)); else sd = script->rid2sd(st); - + if (sd) - script_pushint(st, DIFF_TICK(last_tick, sd->idletime)); + script_pushint(st, DIFF_TICK32(sockt->last_tick, sd->idletime)); // TODO: change this to int64 when we'll support 64 bit script values else script_pushint(st, 0); - + return true; } @@ -14430,25 +15120,25 @@ BUILDIN(searchitem) const char *itemname = script_getstr(st,3); struct item_data *items[MAX_SEARCH]; int count; - + char* name; int32 start; int32 id; int32 i; TBL_PC* sd = NULL; - + if ((items[0] = itemdb->exists(atoi(itemname)))) count = 1; else { count = itemdb->search_name_array(items, ARRAYLENGTH(items), itemname, 0); if (count > MAX_SEARCH) count = MAX_SEARCH; } - + if (!count) { script_pushint(st, 0); return true; } - + if( !data_isreference(data) ) { ShowError("script:searchitem: not a variable\n"); @@ -14456,25 +15146,18 @@ BUILDIN(searchitem) st->state = END; return false;// not a variable } - + id = reference_getid(data); start = reference_getindex(data); name = reference_getname(data); - if( not_array_variable(*name) ) - { - ShowError("script:searchitem: illegal scope\n"); - script->reportdata(data); - st->state = END; - return false;// not supported - } - + if( not_server_variable(*name) ) { sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached } - + if( is_string_variable(name) ) {// string array ShowError("script:searchitem: not an integer array reference\n"); @@ -14482,55 +15165,14 @@ BUILDIN(searchitem) st->state = END; return false;// not supported } - + for( i = 0; i < count; ++start, ++i ) {// Set array void* v = (void*)__64BPTRSIZE((int)items[i]->nameid); script->set_reg(st, sd, reference_uid(id, start), name, v, reference_getref(data)); } - - script_pushint(st, count); - return true; -} -int axtoi(const char *hexStg) -{ - int n = 0; // position in string - int16 m = 0; // position in digit[] to shift - int count; // loop index - int intValue = 0; // integer value of hex string - int digit[11]; // hold values to convert - while (n < 10) { - if (hexStg[n]=='\0') - break; - if (hexStg[n] > 0x29 && hexStg[n] < 0x40 ) //if 0 to 9 - digit[n] = hexStg[n] & 0x0f; //convert to int - else if (hexStg[n] >='a' && hexStg[n] <= 'f') //if a to f - digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int - else if (hexStg[n] >='A' && hexStg[n] <= 'F') //if A to F - digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int - else break; - n++; - } - count = n; - m = n - 1; - n = 0; - while(n < count) { - // digit[n] is value of hex digit at position n - // (m << 2) is the number of positions to shift - // OR the bits into return value - intValue = intValue | (digit[n] << (m << 2)); - m--; // adjust the position to set - n++; // next digit to process - } - return (intValue); -} - -// [Lance] Hex string to integer converter -BUILDIN(axtoi) -{ - const char *hex = script_getstr(st,2); - script_pushint(st,script->axtoi(hex)); + script_pushint(st, count); return true; } @@ -14561,56 +15203,56 @@ BUILDIN(rid2name) { BUILDIN(pcblockmove) { int id, flag; TBL_PC *sd = NULL; - + id = script_getnum(st,2); flag = script_getnum(st,3); - + if(id) sd = map->id2sd(id); else sd = script->rid2sd(st); - + if(sd) sd->state.blockedmove = flag > 0; - + return true; } BUILDIN(pcfollow) { int id, targetid; TBL_PC *sd = NULL; - - + + id = script_getnum(st,2); targetid = script_getnum(st,3); - + if(id) sd = map->id2sd(id); else sd = script->rid2sd(st); - + if(sd) pc->follow(sd, targetid); - - return true; + + return true; } BUILDIN(pcstopfollow) { int id; TBL_PC *sd = NULL; - - + + id = script_getnum(st,2); - + if(id) sd = map->id2sd(id); else sd = script->rid2sd(st); - + if(sd) pc->stop_following(sd); - + return true; } // <--- [zBuffer] List of player cont commands @@ -14624,7 +15266,7 @@ BUILDIN(pcstopfollow) /// unitwalk(<unit_id>,<map_id>) -> <bool> BUILDIN(unitwalk) { struct block_list* bl; - + bl = map->id2bl(script_getnum(st,2)); if( bl == NULL ) { script_pushint(st, 0); @@ -14642,7 +15284,7 @@ BUILDIN(unitwalk) { int map_id = script_getnum(st,3); script_pushint(st, unit->walktobl(bl,map->id2bl(map_id),65025,1)); } - + return true; } @@ -14654,7 +15296,7 @@ BUILDIN(unitkill) struct block_list* bl = map->id2bl(script_getnum(st,2)); if( bl != NULL ) status_kill(bl); - + return true; } @@ -14669,29 +15311,29 @@ BUILDIN(unitwarp) { short y; struct block_list* bl; const char *mapname; - + unit_id = script_getnum(st,2); mapname = script_getstr(st, 3); x = (short)script_getnum(st,4); y = (short)script_getnum(st,5); - + if (!unit_id) //Warp the script's runner bl = map->id2bl(st->rid); else bl = map->id2bl(unit_id); - + if( strcmp(mapname,"this") == 0 ) mapid = bl?bl->m:-1; else mapid = map->mapname2mapid(mapname); - + if( mapid >= 0 && bl != NULL ) { unit->bl2ud2(bl); // ensure ((TBL_NPC*)bl)->ud is safe to edit script_pushint(st, unit->warp(bl,mapid,x,y,CLR_OUTSIGHT)); } else { script_pushint(st, 0); } - + return true; } @@ -14705,35 +15347,32 @@ BUILDIN(unitwarp) { BUILDIN(unitattack) { struct block_list* unit_bl; struct block_list* target_bl = NULL; - struct script_data* data; int actiontype = 0; - + // get unit unit_bl = map->id2bl(script_getnum(st,2)); if( unit_bl == NULL ) { script_pushint(st, 0); return true; } - - data = script_getdata(st, 3); - script->get_val(st, data); - if( data_isstring(data) ) { - TBL_PC* sd = map->nick2sd(script->conv_str(st, data)); + + if( script_isstringtype(st, 3) ) { + TBL_PC* sd = map->nick2sd(script_getstr(st, 3)); if( sd != NULL ) target_bl = &sd->bl; } else - target_bl = map->id2bl(script->conv_num(st, data)); + target_bl = map->id2bl(script_getnum(st, 3)); // request the attack if( target_bl == NULL ) { script_pushint(st, 0); return true; } - + // get actiontype if( script_hasdata(st,4) ) actiontype = script_getnum(st,4); - + switch( unit_bl->type ) { case BL_PC: @@ -14761,9 +15400,9 @@ BUILDIN(unitattack) { BUILDIN(unitstop) { int unit_id; struct block_list* bl; - + unit_id = script_getnum(st,2); - + bl = map->id2bl(unit_id); if( bl != NULL ) { unit->bl2ud2(bl); // ensure ((TBL_NPC*)bl)->ud is safe to edit @@ -14772,7 +15411,7 @@ BUILDIN(unitstop) { if( bl->type == BL_MOB ) ((TBL_MOB*)bl)->target_id = 0; } - + return true; } @@ -14783,10 +15422,10 @@ BUILDIN(unittalk) { int unit_id; const char* message; struct block_list* bl; - + unit_id = script_getnum(st,2); message = script_getstr(st, 3); - + bl = map->id2bl(unit_id); if( bl != NULL ) { struct StringBuf sbuf; @@ -14797,7 +15436,7 @@ BUILDIN(unittalk) { clif->message(((TBL_PC*)bl)->fd, StrBuf->Value(&sbuf)); StrBuf->Destroy(&sbuf); } - + return true; } @@ -14810,13 +15449,13 @@ BUILDIN(unitemote) { int unit_id; int emotion; struct block_list* bl; - + unit_id = script_getnum(st,2); emotion = script_getnum(st,3); bl = map->id2bl(unit_id); if( bl != NULL ) clif->emotion(bl, emotion); - + return true; } @@ -14830,25 +15469,25 @@ BUILDIN(unitskilluseid) { uint16 skill_lv; int target_id; struct block_list* bl; - + unit_id = script_getnum(st,2); - skill_id = ( script_isstring(st,3) ? skill->name2id(script_getstr(st,3)) : script_getnum(st,3) ); + skill_id = ( script_isstringtype(st, 3) ? skill->name2id(script_getstr(st, 3)) : script_getnum(st, 3) ); skill_lv = script_getnum(st,4); target_id = ( script_hasdata(st,5) ? script_getnum(st,5) : unit_id ); - + bl = map->id2bl(unit_id); - + if( bl != NULL ) { if( bl->type == BL_NPC ) { if (!((TBL_NPC*)bl)->status.hp) { - status_calc_npc(((TBL_NPC*)bl), true); + status_calc_npc(((TBL_NPC*)bl), SCO_FIRST); } else { - status_calc_npc(((TBL_NPC*)bl), false); + status_calc_npc(((TBL_NPC*)bl), SCO_NONE); } } unit->skilluse_id(bl, target_id, skill_id, skill_lv); } - + return true; } @@ -14863,26 +15502,26 @@ BUILDIN(unitskillusepos) { int skill_x; int skill_y; struct block_list* bl; - + unit_id = script_getnum(st,2); - skill_id = ( script_isstring(st,3) ? skill->name2id(script_getstr(st,3)) : script_getnum(st,3) ); + skill_id = ( script_isstringtype(st, 3) ? skill->name2id(script_getstr(st, 3)) : script_getnum(st, 3) ); skill_lv = script_getnum(st,4); skill_x = script_getnum(st,5); skill_y = script_getnum(st,6); - + bl = map->id2bl(unit_id); - + if( bl != NULL ) { if( bl->type == BL_NPC ) { if (!((TBL_NPC*)bl)->status.hp) { - status_calc_npc(((TBL_NPC*)bl), true); + status_calc_npc(((TBL_NPC*)bl), SCO_FIRST); } else { - status_calc_npc(((TBL_NPC*)bl), false); + status_calc_npc(((TBL_NPC*)bl), SCO_NONE); } } unit->skilluse_pos(bl, skill_x, skill_y, skill_id, skill_lv); } - + return true; } @@ -14894,12 +15533,12 @@ BUILDIN(unitskillusepos) { BUILDIN(sleep) { int ticks; - + ticks = script_getnum(st,2); - + // detach the player script->detach_rid(st); - + if( ticks <= 0 ) {// do nothing } @@ -14922,9 +15561,9 @@ BUILDIN(sleep) /// sleep2(<mili secconds>) -> <bool> BUILDIN(sleep2) { int ticks; - + ticks = script_getnum(st,2); - + if( ticks <= 0 ) { // do nothing script_pushint(st, (map->id2sd(st->rid)!=NULL)); @@ -14948,18 +15587,18 @@ BUILDIN(awake) { DBIterator *iter; struct script_state *tst; struct npc_data* nd; - + if( ( nd = npc->name2id(script_getstr(st, 2)) ) == NULL ) { ShowError("awake: NPC \"%s\" not found\n", script_getstr(st, 2)); return false; } - + iter = db_iterator(script->st_db); - + for( tst = dbi_first(iter); dbi_exists(iter); tst = dbi_next(iter) ) { if( tst->oid == nd->bl.id ) { TBL_PC* sd = map->id2sd(tst->rid); - + if( tst->sleep.timer == INVALID_TIMER ) {// already awake ??? continue; } @@ -14968,7 +15607,7 @@ BUILDIN(awake) { tst->state = END; tst->rid = 0; } - + timer->delete(tst->sleep.timer, script->run_timer); tst->sleep.timer = INVALID_TIMER; if(tst->state != RERUNLINE) @@ -14976,9 +15615,9 @@ BUILDIN(awake) { script->run_main(tst); } } - + dbi_destroy(iter); - + return true; } @@ -14991,7 +15630,7 @@ BUILDIN(getvariableofnpc) struct script_data* data; const char* name; struct npc_data* nd; - + data = script_getdata(st,2); if( !data_isreference(data) ) {// Not a reference (aka varaible name) @@ -15001,7 +15640,7 @@ BUILDIN(getvariableofnpc) st->state = END; return false; } - + name = reference_getname(data); if( *name != '.' || name[1] == '@' ) {// not a npc variable @@ -15011,7 +15650,7 @@ BUILDIN(getvariableofnpc) st->state = END; return false; } - + nd = npc->name2id(script_getstr(st,3)); if( nd == NULL || nd->subtype != SCRIPT || nd->u.scr.script == NULL ) {// NPC not found or has no script @@ -15020,7 +15659,7 @@ BUILDIN(getvariableofnpc) st->state = END; return false; } - + script->push_val(st->stack, C_NAME, reference_getuid(data), &nd->u.scr.script->script_vars ); return true; } @@ -15034,61 +15673,61 @@ BUILDIN(getvariableofnpc) BUILDIN(warpportal) { int spx; int spy; - unsigned short mapindex; + unsigned short map_index; int tpx; int tpy; struct skill_unit_group* group; struct block_list* bl; - + bl = map->id2bl(st->oid); if( bl == NULL ) { ShowError("script:warpportal: npc is needed\n"); return false; } - + spx = script_getnum(st,2); spy = script_getnum(st,3); - mapindex = mapindex_name2id(script_getstr(st, 4)); + map_index = mapindex->name2id(script_getstr(st, 4)); tpx = script_getnum(st,5); tpy = script_getnum(st,6); - - if( mapindex == 0 ) + + if( map_index == 0 ) return true;// map not found - + group = skill->unitsetting(bl, AL_WARP, 4, spx, spy, 0); if( group == NULL ) return true;// failed group->val1 = (group->val1<<16)|(short)0; group->val2 = (tpx<<16) | tpy; - group->val3 = mapindex; - + group->val3 = map_index; + return true; } BUILDIN(openmail) { TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true; - + mail->openmail(sd); - + return true; } BUILDIN(openauction) { TBL_PC* sd; - + sd = script->rid2sd(st); if( sd == NULL ) return true; - + clif->auction_openwindow(sd); - + return true; } @@ -15102,14 +15741,14 @@ BUILDIN(checkcell) { int16 x = script_getnum(st,3); int16 y = script_getnum(st,4); cell_chk type = (cell_chk)script_getnum(st,5); - + if ( m == -1 ) { ShowWarning("checkcell: Attempted to run on unexsitent map '%s', type %d, x/y %d,%d\n",script_getstr(st,2),type,x,y); return true; } - + script_pushint(st, map->getcell(m, x, y, type)); - + return true; } @@ -15126,21 +15765,21 @@ BUILDIN(setcell) { int16 y2 = script_getnum(st,6); cell_t type = (cell_t)script_getnum(st,7); bool flag = (bool)script_getnum(st,8); - + int x,y; - + if ( m == -1 ) { ShowWarning("setcell: Attempted to run on unexistent map '%s', type %d, x1/y1 - %d,%d | x2/y2 - %d,%d\n",script_getstr(st, 2),type,x1,y1,x2,y2); return true; } - + if( x1 > x2 ) swap(x1,x2); if( y1 > y2 ) swap(y1,y2); - + for( y = y1; y <= y2; ++y ) for( x = x1; x <= x2; ++x ) map->list[m].setcell(m, x, y, type, flag); - + return true; } @@ -15151,15 +15790,15 @@ BUILDIN(mercenary_create) { struct map_session_data *sd; int class_, contract_time; - + if( (sd = script->rid2sd(st)) == NULL || sd->md || sd->status.mer_id != 0 ) return true; - + class_ = script_getnum(st,2); - + if( !mercenary->class(class_) ) return true; - + contract_time = script_getnum(st,3); mercenary->create(sd, class_, contract_time); return true; @@ -15168,12 +15807,12 @@ BUILDIN(mercenary_create) BUILDIN(mercenary_heal) { struct map_session_data *sd = script->rid2sd(st); int hp, sp; - + if( sd == NULL || sd->md == NULL ) return true; hp = script_getnum(st,2); sp = script_getnum(st,3); - + status->heal(&sd->md->bl, hp, sp, 0); return true; } @@ -15182,25 +15821,25 @@ BUILDIN(mercenary_sc_start) { struct map_session_data *sd = script->rid2sd(st); enum sc_type type; int tick, val1; - + if( sd == NULL || sd->md == NULL ) return true; - + type = (sc_type)script_getnum(st,2); tick = script_getnum(st,3); val1 = script_getnum(st,4); - - status->change_start(&sd->md->bl, type, 10000, val1, 0, 0, 0, tick, 2); + + status->change_start(NULL, &sd->md->bl, type, 10000, val1, 0, 0, 0, tick, 2); return true; } BUILDIN(mercenary_get_calls) { struct map_session_data *sd = script->rid2sd(st); int guild_id; - + if( sd == NULL ) return true; - + guild_id = script_getnum(st,2); switch( guild_id ) { case ARCH_MERC_GUILD: @@ -15216,20 +15855,20 @@ BUILDIN(mercenary_get_calls) { script_pushint(st,0); break; } - + return true; } BUILDIN(mercenary_set_calls) { struct map_session_data *sd = script->rid2sd(st); int guild_id, value, *calls; - + if( sd == NULL ) return true; - + guild_id = script_getnum(st,2); value = script_getnum(st,3); - + switch( guild_id ) { case ARCH_MERC_GUILD: calls = &sd->status.arch_calls; @@ -15243,20 +15882,20 @@ BUILDIN(mercenary_set_calls) { default: return true; // Invalid Guild } - + *calls += value; *calls = cap_value(*calls, 0, INT_MAX); - + return true; } BUILDIN(mercenary_get_faith) { struct map_session_data *sd = script->rid2sd(st); int guild_id; - + if( sd == NULL ) return true; - + guild_id = script_getnum(st,2); switch( guild_id ) { case ARCH_MERC_GUILD: @@ -15272,20 +15911,20 @@ BUILDIN(mercenary_get_faith) { script_pushint(st,0); break; } - + return true; } BUILDIN(mercenary_set_faith) { struct map_session_data *sd = script->rid2sd(st); int guild_id, value, *calls; - + if( sd == NULL ) return true; - + guild_id = script_getnum(st,2); value = script_getnum(st,3); - + switch( guild_id ) { case ARCH_MERC_GUILD: calls = &sd->status.arch_faith; @@ -15299,12 +15938,12 @@ BUILDIN(mercenary_set_faith) { default: return true; // Invalid Guild } - + *calls += value; *calls = cap_value(*calls, 0, INT_MAX); if( mercenary->get_guild(sd->md) == guild_id ) clif->mercenary_updatestatus(sd,SP_MERCFAITH); - + return true; } @@ -15315,86 +15954,167 @@ BUILDIN(readbook) { struct map_session_data *sd; int book_id, page; - + if( (sd = script->rid2sd(st)) == NULL ) return true; - + book_id = script_getnum(st,2); page = script_getnum(st,3); - + clif->readbook(sd->fd, book_id, page); return true; } -/****************** - Questlog script commands - *******************/ +/**************************** + * Questlog script commands * + ****************************/ -BUILDIN(setquest) +BUILDIN(questinfo) { + struct npc_data *nd = map->id2nd(st->oid); + int quest_id, icon, job, color = 0; + struct questinfo qi; + + if( nd == NULL || nd->bl.m == -1 ) + 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 + + qi.quest_id = quest_id; + qi.icon = (unsigned char)icon; + qi.nd = nd; + + if( script_hasdata(st, 4) ) { + color = script_getnum(st, 4); + if( color < 0 || color > 3 ) { + ShowWarning("buildin_questinfo: invalid color '%d', changing to 0\n",color); + script->reportfunc(st); + color = 0; + } + qi.color = (unsigned char)color; + } + + qi.hasJob = false; + + if(script_hasdata(st, 5)) { + job = script_getnum(st, 5); + + if (!pcdb_checkid(job)) + ShowError("buildin_questinfo: Nonexistant Job Class.\n"); + else { + qi.hasJob = true; + qi.job = (unsigned short)job; + } + } + + map->add_questinfo(nd->bl.m,&qi); + + return true; +} + +BUILDIN(setquest) { struct map_session_data *sd = script->rid2sd(st); - nullpo_ret(sd); - - quest->add(sd, script_getnum(st, 2)); + unsigned short i; + int quest_id; + nullpo_retr(false,sd); + + quest_id = script_getnum(st, 2); + + 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 + } + } + return true; } -BUILDIN(erasequest) -{ +BUILDIN(erasequest) { struct map_session_data *sd = script->rid2sd(st); - nullpo_ret(sd); - + nullpo_retr(false,sd); + quest->delete(sd, script_getnum(st, 2)); return true; } -BUILDIN(completequest) -{ +BUILDIN(completequest) { struct map_session_data *sd = script->rid2sd(st); - nullpo_ret(sd); - + nullpo_retr(false,sd); + quest->update_status(sd, script_getnum(st, 2), Q_COMPLETE); return true; } -BUILDIN(changequest) -{ +BUILDIN(changequest) { struct map_session_data *sd = script->rid2sd(st); - nullpo_ret(sd); - + nullpo_retr(false,sd); + quest->change(sd, script_getnum(st, 2),script_getnum(st, 3)); return true; } -BUILDIN(checkquest) -{ +BUILDIN(checkquest) { struct map_session_data *sd = script->rid2sd(st); - quest_check_type type = HAVEQUEST; - - nullpo_ret(sd); - + enum quest_check_type type = HAVEQUEST; + + nullpo_retr(false,sd); + if( script_hasdata(st, 3) ) - type = (quest_check_type)script_getnum(st, 3); - + type = (enum quest_check_type)script_getnum(st, 3); + script_pushint(st, quest->check(sd, script_getnum(st, 2), type)); - + return true; } BUILDIN(showevent) { TBL_PC *sd = script->rid2sd(st); struct npc_data *nd = map->id2nd(st->oid); - int state, color; - + int icon, color = 0; + if( sd == NULL || nd == NULL ) return true; - state = script_getnum(st, 2); - color = script_getnum(st, 3); - - if( color < 0 || color > 3 ) - color = 0; // set default color - - clif->quest_show_event(sd, &nd->bl, state, color); + + icon = script_getnum(st, 2); + if( script_hasdata(st, 3) ) { + color = script_getnum(st, 3); + if( color < 0 || color > 3 ) { + ShowWarning("buildin_showevent: invalid color '%d', changing to 0\n",color); + script->reportfunc(st); + color = 0; + } + } + + #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 + + clif->quest_show_event(sd, &nd->bl, icon, color); return true; } @@ -15405,41 +16125,41 @@ BUILDIN(waitingroom2bg) { struct npc_data *nd; struct chat_data *cd; const char *map_name, *ev = "", *dev = ""; - int x, y, i, mapindex = 0, bg_id, n; + int x, y, i, map_index = 0, bg_id, n; struct map_session_data *sd; - + if( script_hasdata(st,7) ) nd = npc->name2id(script_getstr(st,7)); else nd = (struct npc_data *)map->id2bl(st->oid); - + if( nd == NULL || (cd = (struct chat_data *)map->id2bl(nd->chat_id)) == NULL ) { script_pushint(st,0); return true; } - + map_name = script_getstr(st,2); if( strcmp(map_name,"-") != 0 ) { - mapindex = mapindex_name2id(map_name); - if( mapindex == 0 ) + map_index = mapindex->name2id(map_name); + if( map_index == 0 ) { // Invalid Map script_pushint(st,0); return true; } } - + x = script_getnum(st,3); y = script_getnum(st,4); ev = script_getstr(st,5); // Logout Event dev = script_getstr(st,6); // Die Event - - if( (bg_id = bg->create(mapindex, x, y, ev, dev)) == 0 ) + + if( (bg_id = bg->create(map_index, x, y, ev, dev)) == 0 ) { // Creation failed script_pushint(st,0); return true; } - + n = cd->users; for( i = 0; i < n && i < MAX_BG_MEMBERS; i++ ) { @@ -15448,7 +16168,7 @@ BUILDIN(waitingroom2bg) { else mapreg->setreg(reference_uid(script->add_str("$@arenamembers"), i), 0); } - + mapreg->setreg(script->add_str("$@arenamembersnum"), i); script_pushint(st,bg_id); return true; @@ -15459,31 +16179,31 @@ BUILDIN(waitingroom2bg_single) { struct npc_data *nd; struct chat_data *cd; struct map_session_data *sd; - int x, y, mapindex, bg_id; - + int x, y, map_index, bg_id; + bg_id = script_getnum(st,2); map_name = script_getstr(st,3); - if( (mapindex = mapindex_name2id(map_name)) == 0 ) + if( (map_index = mapindex->name2id(map_name)) == 0 ) return true; // Invalid Map - + x = script_getnum(st,4); y = script_getnum(st,5); nd = npc->name2id(script_getstr(st,6)); - + if( nd == NULL || (cd = (struct chat_data *)map->id2bl(nd->chat_id)) == NULL || cd->users <= 0 ) return true; - + if( (sd = cd->usersd[0]) == NULL ) return true; - + if( bg->team_join(bg_id, sd) ) { - pc->setpos(sd, mapindex, x, y, CLR_TELEPORT); + pc->setpos(sd, map_index, x, y, CLR_TELEPORT); script_pushint(st,1); } else script_pushint(st,0); - + return true; } @@ -15491,11 +16211,11 @@ BUILDIN(bg_team_setxy) { struct battleground_data *bgd; int bg_id; - + bg_id = script_getnum(st,2); if( (bgd = bg->team_search(bg_id)) == NULL ) return true; - + bgd->x = script_getnum(st,3); bgd->y = script_getnum(st,4); return true; @@ -15503,16 +16223,16 @@ BUILDIN(bg_team_setxy) BUILDIN(bg_warp) { - int x, y, mapindex, bg_id; + int x, y, map_index, bg_id; const char* map_name; - + bg_id = script_getnum(st,2); map_name = script_getstr(st,3); - if( (mapindex = mapindex_name2id(map_name)) == 0 ) + if( (map_index = mapindex->name2id(map_name)) == 0 ) return true; // Invalid Map x = script_getnum(st,4); y = script_getnum(st,5); - bg->team_warp(bg_id, mapindex, x, y); + bg->team_warp(bg_id, map_index, x, y); return true; } @@ -15520,7 +16240,7 @@ BUILDIN(bg_monster) { int class_ = 0, x = 0, y = 0, bg_id = 0; const char *str, *mapname, *evt=""; - + bg_id = script_getnum(st,2); mapname = script_getstr(st,3); x = script_getnum(st,4); @@ -15538,17 +16258,17 @@ BUILDIN(bg_monster_set_team) { struct block_list *mbl; int id = script_getnum(st,2), bg_id = script_getnum(st,3); - + if( (mbl = map->id2bl(id)) == NULL || mbl->type != BL_MOB ) return true; md = (TBL_MOB *)mbl; md->bg_id = bg_id; - + mob_stop_attack(md); mob_stop_walking(md, 0); md->target_id = md->attacked_id = 0; clif->charnameack(0, &md->bl); - + return true; } @@ -15557,7 +16277,7 @@ BUILDIN(bg_leave) struct map_session_data *sd = script->rid2sd(st); if( sd == NULL || !sd->bg_id ) return true; - + bg->team_leave(sd,0); return true; } @@ -15576,20 +16296,20 @@ BUILDIN(bg_getareausers) { int i = 0, c = 0; struct battleground_data *bgd = NULL; struct map_session_data *sd; - + bg_id = script_getnum(st,2); str = script_getstr(st,3); - + if( (bgd = bg->team_search(bg_id)) == NULL || (m = map->mapname2mapid(str)) < 0 ) { script_pushint(st,0); return true; } - + x0 = script_getnum(st,4); y0 = script_getnum(st,5); x1 = script_getnum(st,6); y1 = script_getnum(st,7); - + for( i = 0; i < MAX_BG_MEMBERS; i++ ) { if( (sd = bgd->members[i].sd) == NULL ) @@ -15598,7 +16318,7 @@ BUILDIN(bg_getareausers) { continue; c++; } - + script_pushint(st,c); return true; } @@ -15606,14 +16326,14 @@ BUILDIN(bg_getareausers) { BUILDIN(bg_updatescore) { const char *str; int16 m; - + str = script_getstr(st,2); if( (m = map->mapname2mapid(str)) < 0 ) return true; - + map->list[m].bgscore_lion = script_getnum(st,3); map->list[m].bgscore_eagle = script_getnum(st,4); - + clif->bg_updatescore(m); return true; } @@ -15623,13 +16343,13 @@ BUILDIN(bg_get_data) struct battleground_data *bgd; int bg_id = script_getnum(st,2), type = script_getnum(st,3); - + if( (bgd = bg->team_search(bg_id)) == NULL ) { script_pushint(st,0); return true; } - + switch( type ) { case 0: script_pushint(st, bgd->count); break; @@ -15637,7 +16357,7 @@ BUILDIN(bg_get_data) ShowError("script:bg_get_data: unknown data identifier %d\n", type); break; } - + return true; } @@ -15649,7 +16369,7 @@ BUILDIN(instance_create) { const char *name; int owner_id, res; int type = IOT_PARTY; - + name = script_getstr(st, 2); owner_id = script_getnum(st, 3); if( script_hasdata(st,4) ) { @@ -15659,9 +16379,9 @@ BUILDIN(instance_create) { return true; } } - + res = instance->create(owner_id, name, (enum instance_owner_type) type); - if( res == -4 ) { // Already exists + if( res == -4 ) { // Already exists script_pushint(st, -1); return true; } else if( res < 0 ) { @@ -15676,25 +16396,25 @@ BUILDIN(instance_create) { script_pushint(st, -2); return true; } - + script_pushint(st, res); return true; } BUILDIN(instance_destroy) { int instance_id = -1; - + if( script_hasdata(st, 2) ) instance_id = script_getnum(st, 2); else if( st->instance_id >= 0 ) instance_id = st->instance_id; else return true; - + if( !instance->valid(instance_id) ) { ShowError("buildin_instance_destroy: Trying to destroy invalid instance %d.\n", instance_id); return true; } - + instance->destroy(instance_id); return true; } @@ -15704,22 +16424,22 @@ BUILDIN(instance_attachmap) { int16 m; int instance_id = -1; bool usebasename = false; - + name = script_getstr(st,2); instance_id = script_getnum(st,3); if( script_hasdata(st,4) && script_getnum(st,4) > 0 ) usebasename = true; - + if( script_hasdata(st, 5) ) map_name = script_getstr(st, 5); - + if( (m = instance->add_map(name, instance_id, usebasename, map_name)) < 0 ) { // [Saithis] ShowError("buildin_instance_attachmap: instance creation failed (%s): %d\n", name, m); script_pushconststr(st, ""); return true; } script_pushconststr(st, map->list[m].name); - + return true; } @@ -15727,30 +16447,30 @@ BUILDIN(instance_detachmap) { const char *str; int16 m; int instance_id = -1; - + str = script_getstr(st, 2); if( script_hasdata(st, 3) ) instance_id = script_getnum(st, 3); else if( st->instance_id >= 0 ) instance_id = st->instance_id; else return true; - + if( (m = map->mapname2mapid(str)) < 0 || (m = instance->map2imap(m,instance_id)) < 0 ) { ShowError("buildin_instance_detachmap: Trying to detach invalid map %s\n", str); return true; } - + instance->del_map(m); return true; } BUILDIN(instance_attach) { int instance_id = -1; - + instance_id = script_getnum(st, 2); if( !instance->valid(instance_id) ) return true; - + st->instance_id = instance_id; return true; } @@ -15764,35 +16484,35 @@ BUILDIN(instance_set_timeout) { int progress_timeout, idle_timeout; int instance_id = -1; - + progress_timeout = script_getnum(st, 2); idle_timeout = script_getnum(st, 3); - + if( script_hasdata(st, 4) ) instance_id = script_getnum(st, 4); else if( st->instance_id >= 0 ) instance_id = st->instance_id; else return true; - + if( instance_id >= 0 ) instance->set_timeout(instance_id, progress_timeout, idle_timeout); - + return true; } BUILDIN(instance_init) { int instance_id = script_getnum(st, 2); - + if( !instance->valid(instance_id) ) { ShowError("instance_init: invalid instance id %d.\n",instance_id); return true; } - + if( instance->list[instance_id].state != INSTANCE_IDLE ) { ShowError("instance_init: instance already initialized.\n"); return true; } - + instance->start(instance_id); return true; } @@ -15806,23 +16526,23 @@ BUILDIN(instance_announce) { int fontSize = script_hasdata(st,7) ? script_getnum(st,7) : 12; // default fontSize int fontAlign = script_hasdata(st,8) ? script_getnum(st,8) : 0; // default fontAlign int fontY = script_hasdata(st,9) ? script_getnum(st,9) : 0; // default fontY - + int i; - + if( instance_id == -1 ) { if( st->instance_id >= 0 ) instance_id = st->instance_id; else return true; } - + if( !instance->valid(instance_id) ) return true; - + for( i = 0; i < instance->list[instance_id].num_map; i++ ) map->foreachinmap(script->buildin_announce_sub, instance->list[instance_id].map[i], BL_PC, mes, strlen(mes)+1, flag&BC_COLOR_MASK, fontColor, fontType, fontSize, fontAlign, fontY); - + return true; } @@ -15830,39 +16550,43 @@ BUILDIN(instance_npcname) { const char *str; int instance_id = -1; struct npc_data *nd; - + str = script_getstr(st, 2); if( script_hasdata(st, 3) ) instance_id = script_getnum(st, 3); else if( st->instance_id >= 0 ) instance_id = st->instance_id; - + if( instance_id >= 0 && (nd = npc->name2id(str)) != NULL ) { static char npcname[NAME_LENGTH]; snprintf(npcname, sizeof(npcname), "dup_%d_%d", instance_id, nd->bl.id); - script_pushconststr(st,npcname); + script_pushconststr(st,npcname); } else { ShowError("script:instance_npcname: invalid instance NPC (instance_id: %d, NPC name: \"%s\".)\n", instance_id, str); st->state = END; return false; } - + return true; } BUILDIN(has_instance) { struct map_session_data *sd; - const char *str; + const char *str; int16 m; int instance_id = -1; + bool type = strcmp(script->getfuncname(st),"has_instance2") == 0 ? true : false; - str = script_getstr(st, 2); - + str = script_getstr(st, 2); + if( (m = map->mapname2mapid(str)) < 0 ) { - script_pushconststr(st, ""); + if( type ) + script_pushint(st, -1); + else + script_pushconststr(st, ""); return true; } - + if( script_hasdata(st, 3) ) instance_id = script_getnum(st, 3); else if( st->instance_id >= 0 ) @@ -15904,23 +16628,29 @@ BUILDIN(has_instance) { instance_id = sd->guild->instance[i]; } } - + if( !instance->valid(instance_id) || (m = instance->map2imap(m, instance_id)) < 0 ) { - script_pushconststr(st, ""); + if( type ) + script_pushint(st, -1); + else + script_pushconststr(st, ""); return true; } - - script_pushconststr(st, map->list[m].name); + + if( type ) + script_pushint(st, instance_id); + else + script_pushconststr(st, map->list[m].name); return true; } int buildin_instance_warpall_sub(struct block_list *bl,va_list ap) { struct map_session_data *sd = ((TBL_PC*)bl); - int mapindex = va_arg(ap,int); + int map_index = va_arg(ap,int); int x = va_arg(ap,int); int y = va_arg(ap,int); - - pc->setpos(sd,mapindex,x,y,CLR_TELEPORT); - + + pc->setpos(sd,map_index,x,y,CLR_TELEPORT); + return 0; } BUILDIN(instance_warpall) { @@ -15928,25 +16658,25 @@ BUILDIN(instance_warpall) { int instance_id = -1; const char *mapn; int x, y; - int mapindex; - + int map_index; + mapn = script_getstr(st,2); x = script_getnum(st,3); y = script_getnum(st,4); - + if( script_hasdata(st,5) ) instance_id = script_getnum(st,5); else if( st->instance_id >= 0 ) instance_id = st->instance_id; else return true; - + if( (m = map->mapname2mapid(mapn)) < 0 || (map->list[m].flag.src4instance && (m = instance->mapid2imapid(m, instance_id)) < 0) ) return true; - - mapindex = map_id2index(m); - - map->foreachininstance(script->buildin_instance_warpall_sub, instance_id, BL_PC,mapindex,x,y); + + map_index = map_id2index(m); + + map->foreachininstance(script->buildin_instance_warpall_sub, instance_id, BL_PC,map_index,x,y); return true; } @@ -15965,46 +16695,46 @@ BUILDIN(instance_check_party) { struct map_session_data *pl_sd; int amount, min, max, i, party_id, c = 0; struct party_data *p = NULL; - + amount = script_hasdata(st,3) ? script_getnum(st,3) : 1; // Amount of needed Partymembers for the Instance. min = script_hasdata(st,4) ? script_getnum(st,4) : 1; // Minimum Level needed to join the Instance. max = script_hasdata(st,5) ? script_getnum(st,5) : MAX_LEVEL; // Maxium Level allowed to join the Instance. - - if( min < 1 || min > MAX_LEVEL){ + + if( min < 1 || min > MAX_LEVEL) { ShowError("instance_check_party: Invalid min level, %d\n", min); return true; - } else if( max < 1 || max > MAX_LEVEL){ + } else if( max < 1 || max > MAX_LEVEL) { ShowError("instance_check_party: Invalid max level, %d\n", max); return true; } - + if( script_hasdata(st,2) ) party_id = script_getnum(st,2); else return true; - - if( !(p = party->search(party_id)) ){ + + if( !(p = party->search(party_id)) ) { script_pushint(st, 0); // Returns false if party does not exist. return true; } - + for( i = 0; i < MAX_PARTY; i++ ) if( (pl_sd = p->data[i].sd) ) - if(map->id2bl(pl_sd->bl.id)){ - if(pl_sd->status.base_level < min){ + if(map->id2bl(pl_sd->bl.id)) { + if(pl_sd->status.base_level < min) { script_pushint(st, 0); return true; - }else if(pl_sd->status.base_level > max){ + } else if(pl_sd->status.base_level > max) { script_pushint(st, 0); return true; } c++; } - - if(c < amount){ + + if(c < amount) { script_pushint(st, 0); // Not enough Members in the Party to join Instance. - }else + } else script_pushint(st, 1); - + return true; } @@ -16017,53 +16747,53 @@ BUILDIN(setfont) int font = script_getnum(st,2); if( sd == NULL ) return true; - - if( sd->user_font != font ) - sd->user_font = font; + + if( sd->status.font != font ) + sd->status.font = font; else - sd->user_font = 0; - + sd->status.font = 0; + clif->font(sd); return true; } int buildin_mobuseskill_sub(struct block_list *bl,va_list ap) { - TBL_MOB* md = (TBL_MOB*)bl; + TBL_MOB* md = (TBL_MOB*)bl; struct block_list *tbl; - int mobid = va_arg(ap,int); - uint16 skill_id = va_arg(ap,int); - uint16 skill_lv = va_arg(ap,int); - int casttime = va_arg(ap,int); - int cancel = va_arg(ap,int); - int emotion = va_arg(ap,int); - int target = va_arg(ap,int); - + int mobid = va_arg(ap,int); + uint16 skill_id = va_arg(ap,int); + uint16 skill_lv = va_arg(ap,int); + int casttime = va_arg(ap,int); + int cancel = va_arg(ap,int); + int emotion = va_arg(ap,int); + int target = va_arg(ap,int); + if( md->class_ != mobid ) return 0; - + // 0:self, 1:target, 2:master, default:random switch( target ) { - case 0: tbl = map->id2bl(md->bl.id); break; - case 1: tbl = map->id2bl(md->target_id); break; - case 2: tbl = map->id2bl(md->master_id); break; - default:tbl = battle->get_enemy(&md->bl, DEFAULT_ENEMY_TYPE(md),skill->get_range2(&md->bl, skill_id, skill_lv)); break; + case 0: tbl = map->id2bl(md->bl.id); break; + case 1: tbl = map->id2bl(md->target_id); break; + case 2: tbl = map->id2bl(md->master_id); break; + default: tbl = battle->get_enemy(&md->bl, DEFAULT_ENEMY_TYPE(md),skill->get_range2(&md->bl, skill_id, skill_lv)); break; } - + if( !tbl ) return 0; - + if( md->ud.skilltimer != INVALID_TIMER ) // Cancel the casting skill. unit->skillcastcancel(bl,0); - + if( skill->get_casttype(skill_id) == CAST_GROUND ) unit->skilluse_pos2(&md->bl, tbl->x, tbl->y, skill_id, skill_lv, casttime, cancel); else unit->skilluse_id2(&md->bl, tbl->id, skill_id, skill_lv, casttime, cancel); - + clif->emotion(&md->bl, emotion); - + return 0; } /*========================================== @@ -16073,27 +16803,27 @@ BUILDIN(areamobuseskill) { struct block_list center; int16 m; int range,mobid,skill_id,skill_lv,casttime,emotion,target,cancel; - + if( (m = map->mapname2mapid(script_getstr(st,2))) < 0 ) { ShowError("areamobuseskill: invalid map name.\n"); return true; } - + if( map->list[m].flag.src4instance && st->instance_id >= 0 && (m = instance->mapid2imapid(m, st->instance_id)) < 0 ) return true; - + center.m = m; center.x = script_getnum(st,3); center.y = script_getnum(st,4); range = script_getnum(st,5); mobid = script_getnum(st,6); - skill_id = ( script_isstring(st,7) ? skill->name2id(script_getstr(st,7)) : script_getnum(st,7) ); + skill_id = ( script_isstringtype(st, 7) ? skill->name2id(script_getstr(st, 7)) : script_getnum(st, 7) ); skill_lv = script_getnum(st,8); casttime = script_getnum(st,9); cancel = script_getnum(st,10); emotion = script_getnum(st,11); target = script_getnum(st,12); - + map->foreachinrange(script->buildin_mobuseskill_sub, ¢er, range, BL_MOB, mobid, skill_id, skill_lv, casttime, cancel, emotion, target); return true; } @@ -16104,21 +16834,21 @@ BUILDIN(progressbar) struct map_session_data * sd = script->rid2sd(st); const char * color; unsigned int second; - + if( !st || !sd ) return true; - + st->state = STOP; - + color = script_getstr(st,2); second = script_getnum(st,3); - + sd->progressbar.npc_id = st->oid; sd->progressbar.timeout = timer->gettick() + second*1000; sd->state.workinprogress = 3; - - clif->progressbar(sd, strtol(color, (char **)NULL, 0), second); - return true; + + clif->progressbar(sd, (unsigned int)strtoul(color, (char **)NULL, 0), second); + return true; } BUILDIN(pushpc) @@ -16126,23 +16856,23 @@ BUILDIN(pushpc) uint8 dir; int cells, dx, dy; struct map_session_data* sd; - + if((sd = script->rid2sd(st))==NULL) { return true; } - + dir = script_getnum(st,2); cells = script_getnum(st,3); - + if(dir>7) { ShowWarning("buildin_pushpc: Invalid direction %d specified.\n", dir); script->reportsrc(st); - + dir%= 8; // trim spin-over } - + if(!cells) {// zero distance return true; @@ -16152,10 +16882,10 @@ BUILDIN(pushpc) dir = (dir+4)%8; // turn around cells = -cells; } - + dx = dirx[dir]; dy = diry[dir]; - + unit->blown(&sd->bl, dx, dy, cells, 0); return true; } @@ -16166,11 +16896,11 @@ BUILDIN(pushpc) BUILDIN(buyingstore) { struct map_session_data* sd; - + if( ( sd = script->rid2sd(st) ) == NULL ) { return true; } - + buyingstore->setup(sd, script_getnum(st,2)); return true; } @@ -16183,27 +16913,27 @@ BUILDIN(searchstores) unsigned short effect; unsigned int uses; struct map_session_data* sd; - + if( ( sd = script->rid2sd(st) ) == NULL ) { return true; } - + uses = script_getnum(st,2); effect = script_getnum(st,3); - + if( !uses ) { ShowError("buildin_searchstores: Amount of uses cannot be zero.\n"); return false; } - + if( effect > 1 ) { ShowError("buildin_searchstores: Invalid effect id %hu, specified.\n", effect); return false; } - + searchstore->open(sd, uses, effect); return true; } @@ -16214,25 +16944,25 @@ BUILDIN(showdigit) unsigned int type = 0; int value; struct map_session_data* sd; - + if( ( sd = script->rid2sd(st) ) == NULL ) { return true; } - + value = script_getnum(st,2); - + if( script_hasdata(st,3) ) { type = script_getnum(st,3); - + if( type > 3 ) { ShowError("buildin_showdigit: Invalid type %u.\n", type); return false; } } - + clif->showdigit(sd, (unsigned char)type, value); return true; } @@ -16273,7 +17003,7 @@ BUILDIN(checkdragon) { BUILDIN(setdragon) { TBL_PC* sd; int color = script_hasdata(st,2) ? script_getnum(st,2) : 0; - + if( (sd = script->rid2sd(st)) == NULL ) return true; if( !pc->checkskill(sd,RK_DRAGONTRAINING) || (sd->class_&MAPID_THIRDMASK) != MAPID_RUNE_KNIGHT ) @@ -16285,10 +17015,10 @@ BUILDIN(setdragon) { unsigned int option = OPTION_DRAGON1; if( color ) { option = ( color == 1 ? OPTION_DRAGON1 : - color == 2 ? OPTION_DRAGON2 : - color == 3 ? OPTION_DRAGON3 : - color == 4 ? OPTION_DRAGON4 : - color == 5 ? OPTION_DRAGON5 : 0); + color == 2 ? OPTION_DRAGON2 : + color == 3 ? OPTION_DRAGON3 : + color == 4 ? OPTION_DRAGON4 : + color == 5 ? OPTION_DRAGON5 : 0); if( !option ) { ShowWarning("script_setdragon: Unknown Color %d used; changing to green (1)\n",color); option = OPTION_DRAGON1; @@ -16324,14 +17054,14 @@ BUILDIN(setmounting) { TBL_PC* sd; if( (sd = script->rid2sd(st)) == NULL ) return true; - if( sd->sc.option&(OPTION_WUGRIDER|OPTION_RIDING|OPTION_DRAGON|OPTION_MADOGEAR) ){ + if( sd->sc.option&(OPTION_WUGRIDER|OPTION_RIDING|OPTION_DRAGON|OPTION_MADOGEAR) ) { clif->msgtable(sd->fd, 0X78b); script_pushint(st,0);//can't mount with one of these - }else { + } else { if( sd->sc.data[SC_ALL_RIDING] ) status_change_end(&sd->bl, SC_ALL_RIDING, INVALID_TIMER); else - sc_start(&sd->bl, SC_ALL_RIDING, 100, 0, -1); + sc_start(NULL,&sd->bl, SC_ALL_RIDING, 100, 0, -1); script_pushint(st,1);//in both cases, return 1. } return true; @@ -16342,16 +17072,16 @@ BUILDIN(setmounting) { **/ BUILDIN(getargcount) { struct script_retinfo* ri; - + if( st->stack->defsp < 1 || st->stack->stack_data[st->stack->defsp - 1].type != C_RETINFO ) { ShowError("script:getargcount: used out of function or callsub label!\n"); st->state = END; return false; } ri = st->stack->stack_data[st->stack->defsp - 1].u.ri; - + script_pushint(st, ri->nargs); - + return true; } /** @@ -16359,40 +17089,39 @@ BUILDIN(getargcount) { **/ BUILDIN(getcharip) { struct map_session_data* sd = NULL; - + /* check if a character name is specified */ if( script_hasdata(st, 2) ) { - if (script_isstring(st, 2)) + if (script_isstringtype(st, 2)) { sd = map->nick2sd(script_getstr(st, 2)); - else if (script_isint(st, 2) || script_getnum(st, 2)) { - int id; - id = script_getnum(st, 2); + } else { + int id = script_getnum(st, 2); sd = (map->id2sd(id) ? map->id2sd(id) : map->charid2sd(id)); } - } - else + } else { sd = script->rid2sd(st); - + } + /* check for sd and IP */ if (!sd || !session[sd->fd]->client_addr) { script_pushconststr(st, ""); return true; } - + /* return the client ip_addr converted for output */ if (sd && sd->fd && session[sd->fd]) { /* initiliaze */ const char *ip_addr = NULL; uint32 ip; - + /* set ip, ip_addr and convert to ip and push str */ ip = session[sd->fd]->client_addr; ip_addr = ip2str(ip, NULL); script_pushstrcopy(st, ip_addr); } - + return true; } /** @@ -16400,12 +17129,12 @@ BUILDIN(getcharip) { **/ BUILDIN(is_function) { const char* str = script_getstr(st,2); - + if( strdb_exists(script->userfunc_db, str) ) script_pushint(st,1); else script_pushint(st,0); - + return true; } /** @@ -16413,35 +17142,35 @@ BUILDIN(is_function) { **/ BUILDIN(get_revision) { const char *svn = get_svn_revision(); - + if ( svn[0] != HERC_UNKNOWN_VER ) script_pushint(st,atoi(svn)); else script_pushint(st,-1);//unknown - + return true; } /** * freeloop(<toggle>) -> toggles this script instance's looping-check ability **/ BUILDIN(freeloop) { - + if( script_getnum(st,2) ) st->freeloop = 1; else st->freeloop = 0; - + script_pushint(st, st->freeloop); - + return true; } BUILDIN(sit) { struct map_session_data *sd = NULL; - + if (script_hasdata(st, 2)) sd = map->nick2sd(script_getstr(st, 2)); - + if (sd == NULL) sd = script->rid2sd(st); @@ -16456,13 +17185,13 @@ BUILDIN(sit) { BUILDIN(stand) { struct map_session_data *sd = NULL; - + if (script_hasdata(st, 2)) sd = map->nick2sd(script_getstr(st, 2)); - + if (sd == NULL) sd = script->rid2sd(st); - + if (pc_issit(sd)) { pc->setstand(sd); @@ -16474,10 +17203,10 @@ BUILDIN(stand) { BUILDIN(issit) { struct map_session_data *sd = NULL; - + if (script_hasdata(st, 2)) sd = map->nick2sd(script_getstr(st, 2)); - + if (sd == NULL) sd = script->rid2sd(st); @@ -16497,21 +17226,21 @@ BUILDIN(bindatcmd) { int i, group_lv = 0, group_lv_char = 99; bool log = false; bool create = false; - + atcmd = script_getstr(st,2); eventName = script_getstr(st,3); - + if( *atcmd == atcommand->at_symbol || *atcmd == atcommand->char_symbol ) atcmd++; - + if( script_hasdata(st,4) ) group_lv = script_getnum(st,4); if( script_hasdata(st,5) ) group_lv_char = script_getnum(st,5); if( script_hasdata(st,6) ) log = script_getnum(st,6) ? true : false; - + if( atcommand->binding_count == 0 ) { CREATE(atcommand->binding,struct atcmd_binding_data*,1); - + create = true; } else { ARR_FIND(0, atcommand->binding_count, i, strcmp(atcommand->binding[i]->command,atcmd) == 0); @@ -16523,39 +17252,39 @@ BUILDIN(bindatcmd) { } else create = true; } - + if( create ) { i = atcommand->binding_count; - + if( atcommand->binding_count++ != 0 ) RECREATE(atcommand->binding,struct atcmd_binding_data*,atcommand->binding_count); - + CREATE(atcommand->binding[i],struct atcmd_binding_data,1); - + safestrncpy(atcommand->binding[i]->command, atcmd, 50); safestrncpy(atcommand->binding[i]->npc_event, eventName, 50); atcommand->binding[i]->group_lv = group_lv; atcommand->binding[i]->group_lv_char = group_lv_char; atcommand->binding[i]->log = log; } - + return true; } BUILDIN(unbindatcmd) { const char* atcmd; int i = 0; - + atcmd = script_getstr(st, 2); - + if( *atcmd == atcommand->at_symbol || *atcmd == atcommand->char_symbol ) atcmd++; - + if( atcommand->binding_count == 0 ) { script_pushint(st, 0); return true; } - + ARR_FIND(0, atcommand->binding_count, i, strcmp(atcommand->binding[i]->command, atcmd) == 0); if( i < atcommand->binding_count ) { int cursor = 0; @@ -16565,21 +17294,21 @@ BUILDIN(unbindatcmd) { for( i = 0, cursor = 0; i < atcommand->binding_count; i++ ) { if( atcommand->binding[i] == NULL ) continue; - + if( cursor != i ) { memmove(&atcommand->binding[cursor], &atcommand->binding[i], sizeof(struct atcmd_binding_data*)); } - + cursor++; } - + if( (atcommand->binding_count = cursor) == 0 ) aFree(atcommand->binding); - + script_pushint(st, 1); } else script_pushint(st, 0);/* not found */ - + return true; } @@ -16587,9 +17316,9 @@ BUILDIN(useatcmd) { TBL_PC *sd, *dummy_sd = NULL; int fd; const char* cmd; - + cmd = script_getstr(st,2); - + if( st->rid ) { sd = script->rid2sd(st); fd = sd->fd; @@ -16597,7 +17326,7 @@ BUILDIN(useatcmd) { // Use a dummy character. sd = dummy_sd = pc->get_dummy_sd(); fd = 0; - + if( st->oid ) { struct block_list* bl = map->id2bl(st->oid); memcpy(&sd->bl, bl, sizeof(struct block_list)); @@ -16605,15 +17334,15 @@ BUILDIN(useatcmd) { safestrncpy(sd->status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH); } } - + // compatibility with previous implementation (deprecated!) if( cmd[0] != atcommand->at_symbol ) { cmd += strlen(sd->status.name); while( *cmd != atcommand->at_symbol && *cmd != 0 ) cmd++; } - - atcommand->parse(fd, sd, cmd, 1); + + atcommand->exec(fd, sd, cmd, true); if (dummy_sd) aFree(dummy_sd); return true; } @@ -16621,9 +17350,9 @@ BUILDIN(useatcmd) { BUILDIN(checkre) { int num; - + num=script_getnum(st,2); - switch(num){ + switch(num) { case 0: #ifdef RENEWAL script_pushint(st, 1); @@ -16686,7 +17415,7 @@ BUILDIN(getrandgroupitem) { struct map_session_data *sd = NULL; int nameid = script_getnum(st, 2); int count = script_getnum(st, 3); - + if( !(data = itemdb->exists(nameid)) ) { ShowWarning("buildin_getrandgroupitem: unknown item id %d\n",nameid); script_pushint(st, 1); @@ -16702,19 +17431,19 @@ BUILDIN(getrandgroupitem) { } else { int i, get_count, flag; struct item it; - + memset(&it,0,sizeof(it)); nameid = itemdb->group_item(data->group); it.nameid = nameid; it.identify = itemdb->isidentified(nameid); - + if (!itemdb->isstackable(nameid)) get_count = 1; else get_count = count; - + for (i = 0; i < count; i += get_count) { // if not pet egg if (!pet->create_egg(sd, nameid)) { @@ -16725,10 +17454,10 @@ BUILDIN(getrandgroupitem) { } } } - + script_pushint(st, 0); } - + return true; } @@ -16737,7 +17466,7 @@ BUILDIN(getrandgroupitem) { int script_cleanfloor_sub(struct block_list *bl, va_list ap) { nullpo_ret(bl); map->clearflooritem(bl); - + return 0; } @@ -16745,12 +17474,12 @@ BUILDIN(cleanmap) { const char *mapname; int16 m = -1; int16 x0 = 0, y0 = 0, x1 = 0, y1 = 0; - + mapname = script_getstr(st, 2); m = map->mapname2mapid(mapname); if ( m == -1 ) return false; - + if ((script_lastdata(st) - 2) < 4) { map->foreachinmap(script->cleanfloor_sub, m, BL_ITEM); } else { @@ -16765,7 +17494,7 @@ BUILDIN(cleanmap) { return false; } } - + return true; } /* Cast a skill on the attached player. @@ -16778,14 +17507,14 @@ BUILDIN(npcskill) { unsigned int npc_level; struct npc_data *nd; struct map_session_data *sd; - - skill_id = script_isstring(st, 2) ? skill->name2id(script_getstr(st, 2)) : script_getnum(st, 2); + + skill_id = script_isstringtype(st, 2) ? skill->name2id(script_getstr(st, 2)) : script_getnum(st, 2); skill_level = script_getnum(st, 3); stat_point = script_getnum(st, 4); npc_level = script_getnum(st, 5); sd = script->rid2sd(st); nd = (struct npc_data *)map->id2bl(sd->npc_id); - + if (stat_point > battle_config.max_third_parameter) { ShowError("npcskill: stat point exceeded maximum of %d.\n",battle_config.max_third_parameter ); return false; @@ -16797,24 +17526,98 @@ BUILDIN(npcskill) { if (sd == NULL || nd == NULL) { //ain't possible, but I don't trust people. return false; } - + nd->level = npc_level; nd->stat_point = stat_point; - + if (!nd->status.hp) { - status_calc_npc(nd, true); + status_calc_npc(nd, SCO_FIRST); } else { - status_calc_npc(nd, false); + status_calc_npc(nd, SCO_NONE); } - + if (skill->get_inf(skill_id)&INF_GROUND_SKILL) { unit->skilluse_pos(&nd->bl, sd->bl.x, sd->bl.y, skill_id, skill_level); } else { unit->skilluse_id(&nd->bl, sd->bl.id, skill_id, skill_level); } - + return true; } + +/* 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) { + int tick; + enum sc_type type; + struct block_list* bl; + char msg[CHAT_SIZE_MAX]; + int mob_id, val1, val2, val3, val4; + + if( (bl = map->id2bl(st->rid)) == NULL ) + return true; + + if( script_isstringtype(st, 2) ) { + mob_id = mob->db_searchname(script_getstr(st, 2)); + } else { + mob_id = mob->db_checkid(script_getnum(st, 2)); + } + + if( mob_id == 0 ) { + if( script_isstringtype(st, 2) ) + ShowWarning("buildin_montransform: Attempted to use non-existing monster '%s'.\n", script_getstr(st, 2)); + else + ShowWarning("buildin_montransform: Attempted to use non-existing monster of ID '%d'.\n", script_getnum(st, 2)); + return false; + } + + tick = script_getnum(st, 3); + type = (sc_type)script_getnum(st, 4); + val1 = val2 = val3 = val4 = 0; + + if( !(type > SC_NONE && type < SC_MAX) ) { + ShowWarning("buildin_montransform: Unsupported status change id %d\n", type); + return false; + } + + if (script_hasdata(st, 5)) + val1 = script_getnum(st, 5); + + if (script_hasdata(st, 6)) + val2 = script_getnum(st, 6); + + if (script_hasdata(st, 7)) + val3 = script_getnum(st, 7); + + if (script_hasdata(st, 8)) + val4 = script_getnum(st, 8); + + if( tick != 0 ) { + struct map_session_data *sd = map->id2sd(bl->id); + struct mob_db *monster = mob->db(mob_id); + + if( !sd ) + return true; + + if( battle_config.mon_trans_disable_in_gvg && map_flag_gvg2(sd->bl.m) ) { + clif->message(sd->fd, msg_txt(1488)); // Transforming into monster is not allowed in Guild Wars. + return true; + } + + if( sd->disguise != -1 ) { + clif->message(sd->fd, msg_txt(1486)); // Cannot transform into monster while in disguise. + return true; + } + + sprintf(msg, msg_txt(1485), monster->name); // Traaaansformation-!! %s form!! + clif->ShowScript(&sd->bl, msg); + status_change_end(bl, SC_MONSTER_TRANSFORM, INVALID_TIMER); // Clear previous + sc_start2(NULL, bl, SC_MONSTER_TRANSFORM, 100, mob_id, type, tick); + sc_start4(NULL, bl, type, 100, val1, val2, val3, val4, tick); + } + return true; +} + struct hQueue *script_hqueue_get(int idx) { if( idx < 0 || idx >= script->hqs || script->hq[idx].size == -1 ) return NULL; @@ -16823,19 +17626,19 @@ struct hQueue *script_hqueue_get(int idx) { int script_hqueue_create(void) { int idx = script->hqs; int i; - + for(i = 0; i < script->hqs; i++) { if( script->hq[i].size == -1 ) { break; } } - + if( i == script->hqs ) { RECREATE(script->hq, struct hQueue, ++script->hqs); script->hq[ idx ].item = NULL; } else idx = i; - + script->hq[ idx ].id = idx; script->hq[ idx ].size = 0; script->hq[ idx ].items = 0; @@ -16854,14 +17657,14 @@ BUILDIN(queue) { /* returns queue length */ BUILDIN(queuesize) { int idx = script_getnum(st, 2); - + if( idx < 0 || idx >= script->hqs || script->hq[idx].size == -1 ) { ShowWarning("buildin_queuesize: unknown queue id %d\n",idx); script_pushint(st, 0); } else { script_pushint(st, script->hq[ idx ].items); } - + return true; } bool script_hqueue_add(int idx, int var) { @@ -16871,24 +17674,24 @@ bool script_hqueue_add(int idx, int var) { } else { struct map_session_data *sd; int i; - + for(i = 0; i < script->hq[idx].size; i++) { if( script->hq[idx].item[i] == var ) { return true; } } - + if( i == script->hq[idx].size ) { - + for(i = 0; i < script->hq[idx].size; i++) { if( script->hq[idx].item[i] == 0 ) { break; } } - + if( i == script->hq[idx].size ) RECREATE(script->hq[idx].item, int, ++script->hq[idx].size); - + script->hq[idx].item[i] = var; script->hq[idx].items++; if( var >= START_ACCOUNT_NUM && (sd = map->id2sd(var)) ) { @@ -16897,13 +17700,13 @@ bool script_hqueue_add(int idx, int var) { break; } } - + if( i == sd->queues_count ) RECREATE(sd->queues, int, ++sd->queues_count); - + sd->queues[i] = idx; } - + } } return false; @@ -16913,9 +17716,9 @@ bool script_hqueue_add(int idx, int var) { BUILDIN(queueadd) { int idx = script_getnum(st, 2); int var = script_getnum(st, 3); - + script_pushint(st,script->queue_add(idx,var)?1:0); - + return true; } bool script_hqueue_remove(int idx, int var) { @@ -16924,30 +17727,30 @@ bool script_hqueue_remove(int idx, int var) { return true; } else { int i; - + for(i = 0; i < script->hq[idx].size; i++) { if( script->hq[idx].item[i] == var ) { break; } } - + if( i != script->hq[idx].size ) { struct map_session_data *sd; - + script->hq[idx].item[i] = -1; script->hq[idx].items--; - + if( var >= START_ACCOUNT_NUM && (sd = map->id2sd(var)) ) { for(i = 0; i < sd->queues_count; i++) { if( sd->queues[i] == idx ) { break; } } - + if( i != sd->queues_count ) sd->queues[i] = -1; } - + } } return false; @@ -16959,7 +17762,7 @@ BUILDIN(queueremove) { int var = script_getnum(st, 3); script_pushint(st, script->queue_remove(idx,var)?1:0); - + return true; } @@ -16970,7 +17773,7 @@ BUILDIN(queueremove) { BUILDIN(queueopt) { int idx = script_getnum(st, 2); int var = script_getnum(st, 3); - + if( idx < 0 || idx >= script->hqs || script->hq[idx].size == -1 ) { ShowWarning("buildin_queueopt: unknown queue id %d\n",idx); script_pushint(st, 1); @@ -17003,7 +17806,7 @@ BUILDIN(queueopt) { break; } } - + return true; } bool script_hqueue_del(int idx) { @@ -17013,7 +17816,7 @@ bool script_hqueue_del(int idx) { } else { struct map_session_data *sd; int i; - + for(i = 0; i < script->hq[idx].size; i++) { if( script->hq[idx].item[i] >= START_ACCOUNT_NUM && (sd = map->id2sd(script->hq[idx].item[i])) ) { int j; @@ -17022,13 +17825,13 @@ bool script_hqueue_del(int idx) { break; } } - + if( j != sd->queues_count ) sd->queues[j] = -1; } script->hq[idx].item[i] = 0; } - + script->hq[idx].size = -1; script->hq[idx].items = 0; } @@ -17038,9 +17841,9 @@ bool script_hqueue_del(int idx) { /* deletes queue of id .@queue_id, returns 1 if id not found, 0 otherwise */ BUILDIN(queuedel) { int idx = script_getnum(st, 2); - + script_pushint(st,script->queue_del(idx)?1:0); - + return true; } void script_hqueue_clear(int idx) { @@ -17050,7 +17853,7 @@ void script_hqueue_clear(int idx) { } else { struct map_session_data *sd; int i, j; - + for(i = 0; i < script->hq[idx].size; i++) { if( script->hq[idx].item[i] > 0 ) { @@ -17060,7 +17863,7 @@ void script_hqueue_clear(int idx) { break; } } - + if( j != sd->queues_count ) sd->queues[j] = -1; } @@ -17078,37 +17881,37 @@ BUILDIN(queueiterator) { struct hQueue *queue = NULL; int idx = script->hqis; int i; - + if( qid < 0 || qid >= script->hqs || script->hq[qid].size == -1 || !(queue = script->queue(qid)) ) { ShowWarning("queueiterator: invalid queue id %d\n",qid); return true; } - + /* what if queue->size is 0? (iterating a empty queue?) */ if( queue->size <= 0 ) { ShowWarning("queueiterator: attempting to iterate on on empty queue id %d!\n",qid); return true; } - + for(i = 0; i < script->hqis; i++) { if( script->hqi[i].items == -1 ) { break; } } - + if( i == script->hqis ) { RECREATE(script->hqi, struct hQueueIterator, ++script->hqis); script->hqi[ idx ].item = NULL; } else idx = i; - + RECREATE(script->hqi[ idx ].item, int, queue->size); memcpy(script->hqi[idx].item, queue->item, sizeof(int)*queue->size); - + script->hqi[ idx ].items = queue->size; script->hqi[ idx ].pos = 0; - + script_pushint(st,idx); return true; } @@ -17116,7 +17919,7 @@ BUILDIN(queueiterator) { /* returns next/first member in the iterator, 0 if none */ BUILDIN(qiget) { int idx = script_getnum(st, 2); - + if( idx < 0 || idx >= script->hqis ) { ShowWarning("buildin_qiget: unknown queue iterator id %d\n",idx); script_pushint(st, 0); @@ -17133,7 +17936,7 @@ BUILDIN(qiget) { /* returns 1:0 if there is a next member in the iterator */ BUILDIN(qicheck) { int idx = script_getnum(st, 2); - + if( idx < 0 || idx >= script->hqis ) { ShowWarning("buildin_qicheck: unknown queue iterator id %d\n",idx); script_pushint(st, 0); @@ -17142,13 +17945,13 @@ BUILDIN(qicheck) { } else { script_pushint(st, 1); } - + return true; } /* Queue Iterator Check */ BUILDIN(qiclear) { int idx = script_getnum(st, 2); - + if( idx < 0 || idx >= script->hqis ) { ShowWarning("buildin_qiclear: unknown queue iterator id %d\n",idx); script_pushint(st, 1); @@ -17156,7 +17959,7 @@ BUILDIN(qiclear) { script->hqi[idx].items = -1; script_pushint(st, 0); } - + return true; } /** @@ -17177,7 +17980,7 @@ BUILDIN(packageitem) { script_pushint(st, 1); return true; } - + if( !(data = itemdb->exists(nameid)) ) { ShowWarning("buildin_packageitem: unknown item id %d\n",nameid); script_pushint(st, 1); @@ -17191,7 +17994,7 @@ BUILDIN(packageitem) { itemdb->package_item(sd,data->package); script_pushint(st, 0); } - + return true; } /* New Battlegrounds Stuff */ @@ -17199,25 +18002,25 @@ BUILDIN(packageitem) { /* returns created team id or -1 when fails */ BUILDIN(bg_create_team) { const char *map_name, *ev = "", *dev = "";//ev and dev will be dropped. - int x, y, mapindex = 0, bg_id; - + int x, y, map_index = 0, bg_id; + map_name = script_getstr(st,2); if( strcmp(map_name,"-") != 0 ) { - mapindex = mapindex_name2id(map_name); - if( mapindex == 0 ) { // Invalid Map + map_index = mapindex->name2id(map_name); + if( map_index == 0 ) { // Invalid Map script_pushint(st,0); return true; } } - + x = script_getnum(st,3); y = script_getnum(st,4); - - if( (bg_id = bg->create(mapindex, x, y, ev, dev)) == 0 ) { // Creation failed + + if( (bg_id = bg->create(map_index, x, y, ev, dev)) == 0 ) { // Creation failed script_pushint(st,-1); } else script_pushint(st,bg_id); - + return true; } @@ -17227,33 +18030,402 @@ BUILDIN(bg_create_team) { BUILDIN(bg_join_team) { struct map_session_data *sd; int team_id = script_getnum(st, 2); - + if( script_hasdata(st, 3) ) sd = map->id2sd(script_getnum(st, 3)); else sd = script->rid2sd(st); - + if( !sd ) script_pushint(st, 1); else script_pushint(st,bg->team_join(team_id, sd)?0:1); - + return true; } +/*==============[Mhalicot]================== + * countbound {<type>}; + * Creates an array of bounded item IDs + * Returns amount of items found + * Type: + * 1 - Account Bound + * 2 - Guild Bound + * 3 - Party Bound + * 4 - Character Bound + *------------------------------------------*/ +BUILDIN(countbound) +{ + int i, type, j=0, k=0; + TBL_PC *sd; + + if( (sd = script->rid2sd(st)) == NULL ) + return false; + + type = script_hasdata(st,2)?script_getnum(st,2):0; + + for(i=0;i<MAX_INVENTORY;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); + k++; + j += sd->status.inventory[i].amount; + } + } + + script_pushint(st,j); + return 0; +} + /* bg_match_over( arena_name {, optional canceled } ) */ /* returns 0 when successful, 1 otherwise */ BUILDIN(bg_match_over) { bool canceled = script_hasdata(st,3) ? true : false; struct bg_arena *arena = bg->name2arena((char*)script_getstr(st, 2)); - + if( arena ) { bg->match_over(arena,canceled); script_pushint(st, 0); } else script_pushint(st, 1); - + + return true; +} + +BUILDIN(instance_mapname) { + const char *map_name; + int m; + short instance_id = -1; + + map_name = script_getstr(st,2); + + if( script_hasdata(st,3) ) + instance_id = script_getnum(st,3); + else + instance_id = st->instance_id; + + // Check that instance mapname is a valid map + if( instance_id == -1 || (m = instance->mapname2imap(map_name,instance_id)) == -1 ) + script_pushconststr(st, ""); + else + script_pushconststr(st, map->list[m].name); + + return true; +} +/* 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) { + const char *map_name; + short instance_id = -1; + short mid; + short x,y; + + map_name = script_getstr(st,2); + x = script_getnum(st, 3); + y = script_getnum(st, 4); + + if( script_hasdata(st, 5) ) + instance_id = script_getnum(st, 5); + else + instance_id = st->instance_id; + + if( instance_id == -1 || !instance->valid(instance_id) ) + script_pushint(st, 0); + else if( (mid = map->mapname2mapid(map_name)) == -1 ) { + ShowError("buildin_instance_set_respawn: unknown map '%s'\n",map_name); + script_pushint(st, 0); + } else { + int i; + + for(i = 0; i < instance->list[instance_id].num_map; i++) { + if( map->list[instance->list[instance_id].map[i]].m == mid ) { + instance->list[instance_id].respawn.map = map_id2index(mid); + instance->list[instance_id].respawn.x = x; + instance->list[instance_id].respawn.y = y; + break; + } + } + + if( i != instance->list[instance_id].num_map ) + script_pushint(st, 1); + else { + ShowError("buildin_instance_set_respawn: map '%s' not part of instance '%s'\n",map_name,instance->list[instance_id].name); + script_pushint(st, 0); + } + } + + + return true; +} +/** + * @call openshop({NPC Name}); + * + * @return 1 on success, 0 otherwise. + **/ +BUILDIN(openshop) { + struct npc_data *nd; + struct map_session_data *sd; + const char *name = NULL; + + if( script_hasdata(st, 2) ) { + name = script_getstr(st, 2); + if( !(nd = npc->name2id(name)) || nd->subtype != SCRIPT ) { + ShowWarning("buildin_openshop(\"%s\"): trying to run without a proper NPC!\n",name); + return false; + } + } else if( !(nd = map->id2nd(st->oid)) ) { + ShowWarning("buildin_openshop: trying to run without a proper NPC!\n"); + return false; + } + if( !( sd = script->rid2sd(st) ) ) { + ShowWarning("buildin_openshop: trying to run without a player attached!\n"); + return false; + } else if ( !nd->u.scr.shop || !nd->u.scr.shop->items ) { + ShowWarning("buildin_openshop: trying to open without any items!\n"); + return false; + } + + if( !npc->trader_open(sd,nd) ) + script_pushint(st, 0); + else + script_pushint(st, 1); + + return true; +} +/** + * @call sellitem <Item_ID>,{,price{,qty}}; + * + * adds <Item_ID> (or modifies if present) to shop + * if price not provided (or -1) uses the item's value_sell + **/ +BUILDIN(sellitem) { + struct npc_data *nd; + struct item_data *it; + int i = 0, id = script_getnum(st,2); + int value = 0; + int qty = 0; + + if( !(nd = map->id2nd(st->oid)) ) { + ShowWarning("buildin_sellitem: trying to run without a proper NPC!\n"); + return false; + } else if ( !(it = itemdb->exists(id)) ) { + ShowWarning("buildin_sellitem: unknown item id '%d'!\n",id); + 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->type == NST_MARKET ) { + if( !script_hasdata(st,4) || ( qty = script_getnum(st, 4) ) <= 0 ) { + ShowError("buildin_sellitem: invalid 'qty' for market-type shop!\n"); + return false; + } + } + + if( ( nd->u.scr.shop->type == NST_ZENY || nd->u.scr.shop->type == NST_MARKET ) && value*0.75 < it->value_sell*1.24 ) { + ShowWarning("buildin_sellitem: Item %s [%d] discounted buying price (%d->%d) is less than overcharged selling price (%d->%d) in NPC %s (%s)\n", + 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 ) { + 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); + } else { + 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 ) { + ShowWarning("buildin_sellitem: Can't add %s (%s/%s), shop list is full!\n", it->name, nd->exname, nd->path); + return false; + } + i = nd->u.scr.shop->items; + RECREATE(nd->u.scr.shop->item, struct npc_item_list, ++nd->u.scr.shop->items); + } + + nd->u.scr.shop->item[i].nameid = it->nameid; + nd->u.scr.shop->item[i].value = value; + nd->u.scr.shop->item[i].qty = qty; + } + return true; } +/** + * @call stopselling <Item_ID>; + * + * removes <Item_ID> from the current npc shop + * + * @return 1 on success, 0 otherwise + **/ +BUILDIN(stopselling) { + struct npc_data *nd; + int i, id = script_getnum(st,2); + + 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( i != nd->u.scr.shop->items ) { + int cursor; + + if( nd->u.scr.shop->type == NST_MARKET ) + npc->market_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].qty = 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 ) { + 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].qty = nd->u.scr.shop->item[i].qty; + } + + cursor++; + } + + script_pushint(st, 1); + } else + script_pushint(st, 0); + + return true; +} +/** + * @call setcurrency <Val1>{,<Val2>}; + * + * updates currently-attached player shop currency + **/ +/* setcurrency(<Val1>,{<Val2>}) */ +BUILDIN(setcurrency) { + int val1 = script_getnum(st,2), + val2 = script_hasdata(st, 3) ? script_getnum(st,3) : 0; + struct npc_data *nd; + + if( !(nd = map->id2nd(st->oid)) ) { + ShowWarning("buildin_setcurrency: trying to run without a proper NPC!\n"); + return false; + } + + npc->trader_funds[0] = val1; + npc->trader_funds[1] = val2; + + return true; +} +/** + * @call tradertype(<type>); + * + * defaults to 0, so no need to call when you're doing zeny + * check enum npc_shop_types for list + * cleans shop list on use + **/ +BUILDIN(tradertype) { + int type = script_getnum(st, 2); + struct npc_data *nd; + + if( !(nd = map->id2nd(st->oid)) ) { + ShowWarning("buildin_tradertype: trying to run without a proper NPC!\n"); + return false; + } else if ( type < 0 || type > NST_MAX ) { + ShowWarning("buildin_tradertype: invalid type param %d!\n",type); + return false; + } + + if( !nd->u.scr.shop ) + npc->trader_update(nd->src_id?nd->src_id:nd->bl.id); + else {/* clear list */ + int i; + for( i = 0; i < nd->u.scr.shop->items; i++ ) { + nd->u.scr.shop->item[i].nameid = 0; + nd->u.scr.shop->item[i].value = 0; + nd->u.scr.shop->item[i].qty = 0; + } + npc->market_delfromsql(nd,USHRT_MAX); + } + + nd->u.scr.shop->type = type; + + return true; +} +/** + * @call purchaseok(); + * + * signs the transaction can proceed + **/ +BUILDIN(purchaseok) { + struct npc_data *nd; + + if( !(nd = map->id2nd(st->oid)) || !nd->u.scr.shop ) { + ShowWarning("buildin_purchaseok: trying to run without a proper NPC!\n"); + return false; + } + + npc->trader_ok = true; + + return true; +} +/** + * @call shopcount(<Item_ID>); + * + * @return number of available items in the script's attached shop + **/ +BUILDIN(shopcount) { + struct npc_data *nd; + int id = script_getnum(st, 2); + unsigned short i; + + if( !(nd = map->id2nd(st->oid)) ) { + ShowWarning("buildin_shopcount(%d): trying to run without a proper NPC!\n",id); + return false; + } 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); + return false; + } + + /* lookup */ + for(i = 0; i < nd->u.scr.shop->items; i++) { + if( nd->u.scr.shop->item[i].nameid == id ) { + script_pushint(st, nd->u.scr.shop->item[i].qty); + break; + } + } + + /* didn't find it */ + if( i == nd->u.scr.shop->items ) + script_pushint(st, 0); + + return true; +} + // declarations that were supposed to be exported from npc_chat.c #ifdef PCRE_SUPPORT BUILDIN(defpattern); @@ -17262,45 +18434,99 @@ BUILDIN(bg_match_over) { BUILDIN(deletepset); #endif -bool script_hp_add(char *name, char *args, bool (*func)(struct script_state *st)) { - int n = script->add_str(name), i = 0; - - if( script->str_data[n].type == C_FUNC ) { - script->str_data[n].func = func; - i = script->str_data[n].val; - if( args ) { - int slen = strlen(args); - if( script->buildin[i] ) { - aFree(script->buildin[i]); - } - CREATE(script->buildin[i], char, slen + 1); - safestrncpy(script->buildin[i], args, slen + 1); - } else { - if( script->buildin[i] ) - aFree(script->buildin[i]); - script->buildin[i] = NULL; +/** + * Adds a built-in script function. + * + * @param buildin Script function data + * @param force Whether to override an existing function with the same name + * (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) { + int n = 0, offset = 0; + size_t slen; + if( !buildin ) { + return false; + } + if( buildin->arg ) { + // arg must follow the pattern: (v|s|i|r|l)*\?*\*? + // 'v' - value (either string or int or reference) + // 's' - string + // 'i' - int + // 'r' - reference (of a variable) + // 'l' - label + // '?' - one optional parameter + // '*' - unknown number of optional parameters + char *p = buildin->arg; + while( *p == 'v' || *p == 's' || *p == 'i' || *p == 'r' || *p == 'l' ) ++p; + while( *p == '?' ) ++p; + if( *p == '*' ) ++p; + if( *p != 0 ) { + ShowWarning("add_builtin: ignoring function \"%s\" with invalid arg \"%s\".\n", buildin->name, buildin->arg); + return false; } + } + if( !buildin->name || *script->skip_word(buildin->name) != 0 ) { + ShowWarning("add_builtin: ignoring function with invalid name \"%s\" (must be a word).\n", buildin->name); + return false; + } + if ( !buildin->func ) { + ShowWarning("add_builtin: ignoring function \"%s\" with invalid source function.\n", buildin->name); + return false; + } + slen = buildin->arg ? strlen(buildin->arg) : 0; + n = script->add_str(buildin->name); + if( !override && script->str_data[n].func && script->str_data[n].func != buildin->func ) { + return false; /* something replaced it, skip. */ + } + + if( override && script->str_data[n].type == C_FUNC ) { + // Overriding + offset = script->str_data[n].val; + if( script->buildin[offset] ) + aFree(script->buildin[offset]); + script->buildin[offset] = NULL; } else { - i = script->buildin_count; + // Adding new function + if( strcmp(buildin->name, "setr") == 0 ) script->buildin_set_ref = n; + else if( strcmp(buildin->name, "callsub") == 0 ) script->buildin_callsub_ref = n; + else if( strcmp(buildin->name, "callfunc") == 0 ) script->buildin_callfunc_ref = n; + else if( strcmp(buildin->name, "getelementofarray") == 0 ) script->buildin_getelementofarray_ref = n; + + offset = script->buildin_count; + script->str_data[n].type = C_FUNC; - script->str_data[n].val = i; - script->str_data[n].func = func; - + script->str_data[n].val = offset; + + // Note: This is a no-op if script->buildin is already large enough + // (it'll only have effect when a plugin adds a new command) RECREATE(script->buildin, char *, ++script->buildin_count); - - /* we only store the arguments, its the only thing used out of this */ - if( args != NULL ) { - int slen = strlen(args); - CREATE(script->buildin[i], char, slen + 1); - safestrncpy(script->buildin[i], args, slen + 1); - } else - script->buildin[i] = NULL; } - + + script->str_data[n].func = buildin->func; + + /* we only store the arguments, its the only thing used out of this */ + if( slen ) { + CREATE(script->buildin[offset], char, slen + 1); + safestrncpy(script->buildin[offset], buildin->arg, slen + 1); + } else { + script->buildin[offset] = NULL; + } + return true; } +bool script_hp_add(char *name, char *args, bool (*func)(struct script_state *st)) { + struct script_function buildin; + buildin.name = name; + buildin.arg = args; + buildin.func = func; + return script->add_builtin(&buildin, true); +} + +#define BUILDIN_DEF(x,args) { buildin_ ## x , #x , args } +#define BUILDIN_DEF2(x,x2,args) { buildin_ ## x , x2 , args } void script_parse_builtin(void) { struct script_function BUILDIN[] = { // NPC interaction @@ -17327,7 +18553,8 @@ void script_parse_builtin(void) { BUILDIN_DEF(warpguild,"siii"), // [Fredzilla] BUILDIN_DEF(setlook,"ii"), BUILDIN_DEF(changelook,"ii"), // Simulates but don't Store it - BUILDIN_DEF(set,"rv"), + BUILDIN_DEF2(setr,"set","rv"), + BUILDIN_DEF(setr,"rv?"), // Not meant to be used directly, required for var++/var-- BUILDIN_DEF(setarray,"rv*"), BUILDIN_DEF(cleararray,"rvi"), BUILDIN_DEF(copyarray,"rri"), @@ -17376,7 +18603,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(getequiprefinerycnt,"i"), BUILDIN_DEF(getequipweaponlv,"i"), BUILDIN_DEF(getequippercentrefinery,"i"), - BUILDIN_DEF(successrefitem,"i"), + BUILDIN_DEF(successrefitem,"i?"), BUILDIN_DEF(failedrefitem,"i"), BUILDIN_DEF(downrefitem,"i?"), BUILDIN_DEF(statusup,"i"), @@ -17457,7 +18684,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(sc_end,"i?"), BUILDIN_DEF(getstatus, "i?"), BUILDIN_DEF(getscrate,"ii?"), - BUILDIN_DEF(debugmes,"s"), + BUILDIN_DEF(debugmes,"v"), BUILDIN_DEF2(catchpet,"pet","i"), BUILDIN_DEF2(birthpet,"bpet",""), BUILDIN_DEF(resetlvl,"i"), @@ -17471,8 +18698,8 @@ void script_parse_builtin(void) { BUILDIN_DEF2(waitingroomkickall,"kickwaitingroomall","?"), BUILDIN_DEF(enablewaitingroomevent,"?"), BUILDIN_DEF(disablewaitingroomevent,"?"), - BUILDIN_DEF2(enablewaitingroomevent,"enablearena",""), // Added by RoVeRT - BUILDIN_DEF2(disablewaitingroomevent,"disablearena",""), // Added by RoVeRT + BUILDIN_DEF2(enablewaitingroomevent,"enablearena",""), // Added by RoVeRT + BUILDIN_DEF2(disablewaitingroomevent,"disablearena",""), // Added by RoVeRT BUILDIN_DEF(getwaitingroomstate,"i?"), BUILDIN_DEF(warpwaitingpc,"sii?"), BUILDIN_DEF(attachrid,"i"), @@ -17488,10 +18715,10 @@ void script_parse_builtin(void) { BUILDIN_DEF(gvgoff,"s"), BUILDIN_DEF(emotion,"i??"), BUILDIN_DEF(maprespawnguildid,"sii"), - BUILDIN_DEF(agitstart,""), // <Agit> + BUILDIN_DEF(agitstart,""), // <Agit> BUILDIN_DEF(agitend,""), BUILDIN_DEF(agitcheck,""), // <Agitcheck> - BUILDIN_DEF(flagemblem,"i"), // Flag Emblem + BUILDIN_DEF(flagemblem,"i"), // Flag Emblem BUILDIN_DEF(getcastlename,"s"), BUILDIN_DEF(getcastledata,"si"), BUILDIN_DEF(setcastledata,"sii"), @@ -17517,13 +18744,13 @@ void script_parse_builtin(void) { BUILDIN_DEF(clearitem,""), BUILDIN_DEF(classchange,"ii"), BUILDIN_DEF(misceffect,"i"), - BUILDIN_DEF(playBGM,"s"), - BUILDIN_DEF(playBGMall,"s?????"), + BUILDIN_DEF(playbgm,"s"), + BUILDIN_DEF(playbgmall,"s?????"), BUILDIN_DEF(soundeffect,"si"), - BUILDIN_DEF(soundeffectall,"si?????"), // SoundEffectAll [Codemaster] - BUILDIN_DEF(strmobinfo,"ii"), // display mob data [Valaris] - BUILDIN_DEF(guardian,"siisi??"), // summon guardians - BUILDIN_DEF(guardianinfo,"sii"), // display guardian data [Valaris] + BUILDIN_DEF(soundeffectall,"si?????"), // SoundEffectAll [Codemaster] + BUILDIN_DEF(strmobinfo,"ii"), // display mob data [Valaris] + BUILDIN_DEF(guardian,"siisi??"), // summon guardians + BUILDIN_DEF(guardianinfo,"sii"), // display guardian data [Valaris] BUILDIN_DEF(petskillbonus,"iiii"), // [Valaris] BUILDIN_DEF(petrecovery,"ii"), // [Valaris] BUILDIN_DEF(petloot,"i"), // [Valaris] @@ -17536,7 +18763,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(specialeffect,"i??"), // npc skill effect [Valaris] BUILDIN_DEF(specialeffect2,"i??"), // skill effect on players[Valaris] BUILDIN_DEF(nude,""), // nude command [Valaris] - BUILDIN_DEF(mapwarp,"ssii??"), // Added by RoVeRT + BUILDIN_DEF(mapwarp,"ssii??"), // Added by RoVeRT BUILDIN_DEF(atcommand,"s"), // [MouseJstr] BUILDIN_DEF2(atcommand,"charcommand","s"), // [MouseJstr] BUILDIN_DEF(movenpc,"sii?"), // [MouseJstr] @@ -17548,7 +18775,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(npcspeed,"i"), // [Valaris] BUILDIN_DEF(npcwalkto,"ii"), // [Valaris] BUILDIN_DEF(npcstop,""), // [Valaris] - BUILDIN_DEF(getmapxy,"rrri?"), //by Lorky [Lupus] + BUILDIN_DEF(getmapxy,"rrri?"), //by Lorky [Lupus] BUILDIN_DEF(checkoption1,"i"), BUILDIN_DEF(checkoption2,"i"), BUILDIN_DEF(guildgetexp,"i"), @@ -17626,11 +18853,14 @@ void script_parse_builtin(void) { BUILDIN_DEF(disguise,"i"), //disguise player. Lupus BUILDIN_DEF(undisguise,""), //undisguise player. Lupus BUILDIN_DEF(getmonsterinfo,"ii"), //Lupus + BUILDIN_DEF(addmonsterdrop,"vii"), + BUILDIN_DEF(delmonsterdrop,"vi"), BUILDIN_DEF(axtoi,"s"), BUILDIN_DEF(query_sql,"s*"), BUILDIN_DEF(query_logsql,"s*"), BUILDIN_DEF(escape_sql,"v"), BUILDIN_DEF(atoi,"s"), + BUILDIN_DEF(strtol,"si"), // [zBuffer] List of player cont commands ---> BUILDIN_DEF(rid2name,"i"), BUILDIN_DEF(pcfollow,"ii"), @@ -17653,12 +18883,13 @@ void script_parse_builtin(void) { BUILDIN_DEF(awake,"s"), BUILDIN_DEF(getvariableofnpc,"rs"), BUILDIN_DEF(warpportal,"iisii"), - BUILDIN_DEF2(homunculus_evolution,"homevolution",""), //[orn] + BUILDIN_DEF2(homunculus_evolution,"homevolution",""), //[orn] BUILDIN_DEF2(homunculus_mutate,"hommutate","?"), - BUILDIN_DEF2(homunculus_shuffle,"homshuffle",""), //[Zephyrus] - BUILDIN_DEF(checkhomcall,""), - BUILDIN_DEF(eaclass,"?"), //[Skotlex] - BUILDIN_DEF(roclass,"i?"), //[Skotlex] + BUILDIN_DEF2(homunculus_morphembryo,"morphembryo",""), + BUILDIN_DEF2(homunculus_checkcall,"checkhomcall",""), + BUILDIN_DEF2(homunculus_shuffle,"homshuffle",""), //[Zephyrus] + BUILDIN_DEF(eaclass,"?"), //[Skotlex] + BUILDIN_DEF(roclass,"i?"), //[Skotlex] BUILDIN_DEF(checkvending,"?"), BUILDIN_DEF(checkchatting,"?"), BUILDIN_DEF(checkidle,"?"), @@ -17701,7 +18932,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(bg_get_data,"ii"), BUILDIN_DEF(bg_getareausers,"isiiii"), BUILDIN_DEF(bg_updatescore,"sii"), - + // Instancing BUILDIN_DEF(instance_create,"si?"), BUILDIN_DEF(instance_destroy,"?"), @@ -17716,6 +18947,10 @@ void script_parse_builtin(void) { BUILDIN_DEF(has_instance,"s?"), BUILDIN_DEF(instance_warpall,"sii?"), BUILDIN_DEF(instance_check_party,"i???"), + BUILDIN_DEF(instance_mapname,"s?"), + BUILDIN_DEF(instance_set_respawn,"sii?"), + BUILDIN_DEF2(has_instance,"has_instance2","s"), + /** * 3rd-related **/ @@ -17746,15 +18981,23 @@ void script_parse_builtin(void) { BUILDIN_DEF(bindatcmd, "ss???"), BUILDIN_DEF(unbindatcmd, "s"), BUILDIN_DEF(useatcmd, "s"), - + + /** + * Item bound [Xantara] [Akinari] [Mhalicot/Hercules] + **/ + BUILDIN_DEF2(getitem,"getitembound","vii?"), + BUILDIN_DEF2(getitem2,"getitembound2","viiiiiiiii?"), + BUILDIN_DEF(countbound, "?"), + //Quest Log System [Inkfish] + BUILDIN_DEF(questinfo, "ii??"), BUILDIN_DEF(setquest, "i"), BUILDIN_DEF(erasequest, "i"), BUILDIN_DEF(completequest, "i"), BUILDIN_DEF(checkquest, "i?"), BUILDIN_DEF(changequest, "ii"), - BUILDIN_DEF(showevent, "ii"), - + BUILDIN_DEF(showevent, "i?"), + /** * hQueue [Ind/Hercules] **/ @@ -17768,75 +19011,47 @@ void script_parse_builtin(void) { BUILDIN_DEF(qicheck,"i"), BUILDIN_DEF(qiget,"i"), BUILDIN_DEF(qiclear,"i"), - + BUILDIN_DEF(packageitem,"?"), - + BUILDIN_DEF(sit, "?"), BUILDIN_DEF(stand, "?"), BUILDIN_DEF(issit, "?"), - + + BUILDIN_DEF(montransform, "vii????"), // Monster Transform [malufett/Hercules] + /* New BG Commands [Hercules] */ BUILDIN_DEF(bg_create_team,"sii"), BUILDIN_DEF(bg_join_team,"i?"), BUILDIN_DEF(bg_match_over,"s?"), + + /* New Shop Support */ + BUILDIN_DEF(openshop,"?"), + BUILDIN_DEF(sellitem,"i??"), + BUILDIN_DEF(stopselling,"i"), + BUILDIN_DEF(setcurrency,"i?"), + BUILDIN_DEF(tradertype,"i"), + BUILDIN_DEF(purchaseok,""), + BUILDIN_DEF(shopcount, "i"), }; - int i,n, len = ARRAYLENGTH(BUILDIN), start = script->buildin_count; - char* p; - RECREATE(script->buildin, char *, start + len); + int i, len = ARRAYLENGTH(BUILDIN); + RECREATE(script->buildin, char *, script->buildin_count + len); // Pre-alloc to speed up + memset(script->buildin + script->buildin_count, '\0', sizeof(char *) * len); for( i = 0; i < len; i++ ) { - // arg must follow the pattern: (v|s|i|r|l)*\?*\*? - // 'v' - value (either string or int or reference) - // 's' - string - // 'i' - int - // 'r' - reference (of a variable) - // 'l' - label - // '?' - one optional parameter - // '*' - unknown number of optional parameters - p = BUILDIN[i].arg; - while( *p == 'v' || *p == 's' || *p == 'i' || *p == 'r' || *p == 'l' ) ++p; - while( *p == '?' ) ++p; - if( *p == '*' ) ++p; - if( *p != 0 ){ - ShowWarning("parse_builtin: ignoring function \"%s\" with invalid arg \"%s\".\n", BUILDIN[i].name, BUILDIN[i].arg); - } else if( *script->skip_word(BUILDIN[i].name) != 0 ){ - ShowWarning("parse_builtin: ignoring function with invalid name \"%s\" (must be a word).\n", BUILDIN[i].name); - } else { - int slen = strlen(BUILDIN[i].arg), offset = start + i; - n = script->add_str(BUILDIN[i].name); - - if (!strcmp(BUILDIN[i].name, "set")) script->buildin_set_ref = n; - else if (!strcmp(BUILDIN[i].name, "callsub")) script->buildin_callsub_ref = n; - else if (!strcmp(BUILDIN[i].name, "callfunc")) script->buildin_callfunc_ref = n; - else if (!strcmp(BUILDIN[i].name, "getelementofarray") ) script->buildin_getelementofarray_ref = n; - - if( script->str_data[n].func && script->str_data[n].func != BUILDIN[i].func ) - continue;/* something replaced it, skip. */ - - script->str_data[n].type = C_FUNC; - script->str_data[n].val = offset; - script->str_data[n].func = BUILDIN[i].func; - - /* we only store the arguments, its the only thing used out of this */ - if( slen ) { - CREATE(script->buildin[offset], char, slen + 1); - safestrncpy(script->buildin[offset], BUILDIN[i].arg, slen + 1); - } else - script->buildin[offset] = NULL; - - script->buildin_count++; - - } + script->add_builtin(&BUILDIN[i], false); } } +#undef BUILDIN_DEF +#undef BUILDIN_DEF2 void script_label_add(int key, int pos) { int idx = script->label_count; - + if( script->labels_size == script->label_count ) { script->labels_size += 1024; RECREATE(script->labels, struct script_label_entry, script->labels_size); } - + script->labels[idx].key = key; script->labels[idx].pos = pos; script->label_count++; @@ -17844,24 +19059,24 @@ void script_label_add(int key, int pos) { void script_defaults(void) { // aegis->athena slot position conversion table - unsigned int equip[SCRIPT_EQUIP_TABLE_SIZE] = {EQP_HEAD_TOP,EQP_ARMOR,EQP_HAND_L,EQP_HAND_R,EQP_GARMENT,EQP_SHOES,EQP_ACC_L,EQP_ACC_R,EQP_HEAD_MID,EQP_HEAD_LOW,EQP_COSTUME_HEAD_LOW,EQP_COSTUME_HEAD_MID,EQP_COSTUME_HEAD_TOP,EQP_COSTUME_GARMENT}; + unsigned int equip[SCRIPT_EQUIP_TABLE_SIZE] = {EQP_HEAD_TOP,EQP_ARMOR,EQP_HAND_L,EQP_HAND_R,EQP_GARMENT,EQP_SHOES,EQP_ACC_L,EQP_ACC_R,EQP_HEAD_MID,EQP_HEAD_LOW,EQP_COSTUME_HEAD_LOW,EQP_COSTUME_HEAD_MID,EQP_COSTUME_HEAD_TOP,EQP_COSTUME_GARMENT,EQP_SHADOW_ARMOR, EQP_SHADOW_WEAPON, EQP_SHADOW_SHIELD, EQP_SHADOW_SHOES, EQP_SHADOW_ACC_R, EQP_SHADOW_ACC_L}; script = &script_s; - + script->st_db = NULL; script->active_scripts = 0; script->next_id = 0; script->st_ers = NULL; script->stack_ers = NULL; + script->array_ers = NULL; script->hq = NULL; script->hqi = NULL; script->hqs = script->hqis = 0; - memset(&script->hqe, 0, sizeof(script->hqe)); - + script->buildin = NULL; script->buildin_count = 0; - + script->str_data = NULL; script->str_data_size = 0; script->str_num = LABEL_START; @@ -17869,19 +19084,19 @@ void script_defaults(void) { script->str_size = 0; script->str_pos = 0; memset(script->str_hash, 0, sizeof(script->str_hash)); - + script->word_buf = NULL; script->word_size = 0; - + script->current_item_id = 0; - + script->labels = NULL; script->label_count = 0; script->labels_size = 0; - + script->buf = NULL; script->pos = 0, script->size = 0; - + script->parse_options = 0; script->buildin_set_ref = 0; script->buildin_callsub_ref = 0; @@ -17895,33 +19110,37 @@ void script_defaults(void) { script->parser_current_src = NULL; script->parser_current_file = NULL; script->parser_current_line = 0; - + memset(&script->syntax,0,sizeof(script->syntax)); - + script->parse_syntax_for_flag = 0; - + memcpy(script->equip, &equip, sizeof(script->equip)); - + memset(&script->config, 0, sizeof(script->config)); - + script->autobonus_db = NULL; script->userfunc_db = NULL; - + script->potion_flag = script->potion_hp = script->potion_per_hp = script->potion_sp = script->potion_per_sp = script->potion_target = 0; - + + script->generic_ui_array = NULL; + script->generic_ui_array_size = 0; + /* */ script->init = do_init_script; script->final = do_final_script; script->reload = script_reload; - + /* parse */ script->parse = parse_script; + script->add_builtin = script_add_builtin; script->parse_builtin = script_parse_builtin; script->skip_space = script_skip_space; script->error = script_error; script->warning = script_warning; script->parse_subexpr = script_parse_subexpr; - + script->addScript = script_hp_add; script->conv_num = conv_num; script->conv_str = conv_str; @@ -17935,8 +19154,7 @@ void script_defaults(void) { script->pop_stack = pop_stack; script->set_constant = script_set_constant; script->set_constant2 = script_set_constant2; - script->set_constant_force = script_set_constant_force; - script->get_constant = script_get_constant; + script->get_constant = script_get_constant; script->label_add = script_label_add; script->run = run_script; script->run_main = run_script_main; @@ -17956,14 +19174,14 @@ void script_defaults(void) { script->search_str = script_search_str; script->setd_sub = setd_sub; script->attach_state = script_attach_state; - + script->queue = script_hqueue_get; script->queue_add = script_hqueue_add; script->queue_del = script_hqueue_del; script->queue_remove = script_hqueue_remove; script->queue_create = script_hqueue_create; script->queue_clear = script_hqueue_clear; - + script->parse_curly_close = parse_curly_close; script->parse_syntax_close = parse_syntax_close; script->parse_syntax_close_sub = parse_syntax_close_sub; @@ -17974,7 +19192,6 @@ void script_defaults(void) { script->reportsrc = script_reportsrc; script->reportdata = script_reportdata; script->reportfunc = script_reportfunc; - script->disp_error_message2 = disp_error_message2; script->disp_warning_message = disp_warning_message; script->check_event = check_event; script->calc_hash = calc_hash; @@ -17997,7 +19214,6 @@ void script_defaults(void) { script->set_reg = set_reg; script->stack_expand = stack_expand; script->push_retinfo = push_retinfo; - script->pop_val = pop_val; script->op_3 = op_3; script->op_2str = op_2str; script->op_2num = op_2num; @@ -18010,7 +19226,6 @@ void script_defaults(void) { script->menu_countoptions = menu_countoptions; script->buildin_areawarp_sub = buildin_areawarp_sub; script->buildin_areapercentheal_sub = buildin_areapercentheal_sub; - script->getarraysize = getarraysize; script->buildin_delitem_delete = buildin_delitem_delete; script->buildin_delitem_search = buildin_delitem_search; script->buildin_killmonster_sub_strip = buildin_killmonster_sub_strip; @@ -18025,16 +19240,16 @@ void script_defaults(void) { script->buildin_maprespawnguildid_sub_pc = buildin_maprespawnguildid_sub_pc; script->buildin_maprespawnguildid_sub_mob = buildin_maprespawnguildid_sub_mob; script->buildin_mobcount_sub = buildin_mobcount_sub; - script->playBGM_sub = playBGM_sub; - script->playBGM_foreachpc_sub = playBGM_foreachpc_sub; + script->playbgm_sub = playbgm_sub; + script->playbgm_foreachpc_sub = playbgm_foreachpc_sub; script->soundeffect_sub = soundeffect_sub; script->buildin_query_sql_sub = buildin_query_sql_sub; - script->axtoi = axtoi; script->buildin_instance_warpall_sub = buildin_instance_warpall_sub; script->buildin_mobuseskill_sub = buildin_mobuseskill_sub; script->cleanfloor_sub = script_cleanfloor_sub; script->run_func = run_func; - + script->getfuncname = script_getfuncname; + /* script_config base */ script->config.warn_func_mismatch_argtypes = 1; script->config.warn_func_mismatch_paramnum = 1; @@ -18052,4 +19267,46 @@ void script_defaults(void) { script->config.joblvup_event_name = "OnPCJobLvUpEvent"; script->config.ontouch_name = "OnTouch_";//ontouch_name (runs on first visible char to enter area, picks another char if the first char leaves) script->config.ontouch2_name = "OnTouch";//ontouch2_name (run whenever a char walks into the OnTouch area) + + // for ENABLE_CASE_CHECK + script->calc_hash_ci = calc_hash_ci; + script->local_casecheck.add_str = script_local_casecheck_add_str; + script->local_casecheck.clear = script_local_casecheck_clear; + script->local_casecheck.str_data = NULL; + script->local_casecheck.str_data_size = 0; + script->local_casecheck.str_num = 1; + script->local_casecheck.str_buf = NULL; + script->local_casecheck.str_size = 0; + script->local_casecheck.str_pos = 0; + memset(script->local_casecheck.str_hash, 0, sizeof(script->local_casecheck.str_hash)); + script->global_casecheck.add_str = script_global_casecheck_add_str; + script->global_casecheck.clear = script_global_casecheck_clear; + script->global_casecheck.str_data = NULL; + script->global_casecheck.str_data_size = 0; + script->global_casecheck.str_num = 1; + script->global_casecheck.str_buf = NULL; + script->global_casecheck.str_size = 0; + script->global_casecheck.str_pos = 0; + memset(script->global_casecheck.str_hash, 0, sizeof(script->global_casecheck.str_hash)); + // end ENABLE_CASE_CHECK + + /** + * Array Handling + **/ + script->array_src = script_array_src; + script->array_update = script_array_update; + script->array_add_member = script_array_add_member; + script->array_remove_member = script_array_remove_member; + script->array_delete = script_array_delete; + script->array_size = script_array_size; + script->array_free_db = script_free_array_db; + script->array_highest_key = script_array_highest_key; + script->array_ensure_zero = script_array_ensure_zero; + /* */ + script->reg_destroy_single = script_reg_destroy_single; + script->reg_destroy = script_reg_destroy; + /* */ + script->generic_ui_array_expand = script_generic_ui_array_expand; + script->array_cpy_list = script_array_cpy_list; + } |