summaryrefslogtreecommitdiff
path: root/src/map/script.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/script.c')
-rw-r--r--src/map/script.c1747
1 files changed, 1206 insertions, 541 deletions
diff --git a/src/map/script.c b/src/map/script.c
index c1eb2e8b7..9372299bb 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -848,79 +848,134 @@ static const char *parse_callfunc(const char *p, int require_paren, int is_custo
nullpo_retr(NULL, p);
// is need add check for arg null pointer below?
- func = script->add_word(p);
- if (script->str_data[func].type == C_FUNC) {
- script->syntax.nested_call++;
- if (script->syntax.last_func != -1) {
- if (script->str_data[func].val == script->buildin_lang_macro_offset) {
- script->syntax.lang_macro_active = true;
- macro = true;
- } else if (script->str_data[func].val == script->buildin_lang_macro_fmtstring_offset) {
- script->syntax.lang_macro_fmtstring_active = true;
- macro = true;
- }
+
+ if (*p == '"') {
+ p2 = ++p; // jump to the start of the word
+
+ // find the closing quote
+ while (*p2 != '"') {
+ ++p2;
}
- if( !macro ) {
- // buildin function
+ if (p2[1] == ':' && p2[2] == ':') {
+ func = script->add_str("callfunctionofnpc");
+ arg = "*"; // we already take care of the "vs" part of "vs*"
+
+ script->syntax.nested_call++;
script->syntax.last_func = script->str_data[func].val;
script->addl(func);
script->addc(C_ARG);
- }
- arg = script->buildin[script->str_data[func].val];
- if (script->str_data[func].deprecated)
- DeprecationWarning(p);
- 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);
- script->addl(func);
- arg = script->buildin[script->str_data[script->buildin_callsub_ref].val];
- if( *arg == 0 )
- disp_error_message("parse_callfunc: callsub has no arguments, please review its definition",p);
- if( *arg != '*' )
- ++arg; // count func as argument
+ script->addc(C_STR);
+ do {
+ script->addb(*p++); // npc name
+ } while (p < p2);
+ script->addb(0);
+
+ p = p2 + 3; // skip to start of func name
+ p2 = script->skip_word(p);
+
+ script->addc(C_STR);
+ do {
+ script->addb(*p++); // func name
+ } while (p < p2);
+ script->addb(0);
+
+ p = p2; // skip to just before the ()
+ } else {
+ disp_error_message("script:parse_callfunc: invalid public function call syntax!", p2 + 1);
+ }
} else {
+ func = script->add_word(p);
+ if (script->str_data[func].type == C_FUNC) {
+ script->syntax.nested_call++;
+
+ if (script->syntax.last_func != -1) {
+ if (script->str_data[func].val == script->buildin_lang_macro_offset) {
+ script->syntax.lang_macro_active = true;
+ macro = true;
+ } else if (script->str_data[func].val == script->buildin_lang_macro_fmtstring_offset) {
+ script->syntax.lang_macro_fmtstring_active = true;
+ macro = true;
+ }
+ }
+
+ if (!macro) {
+ // buildin function
+ script->syntax.last_func = script->str_data[func].val;
+ script->addl(func);
+ script->addc(C_ARG);
+ }
+
+ arg = script->buildin[script->str_data[func].val];
+
+ if (script->str_data[func].deprecated == 1) {
+ DeprecationWarning(p);
+ }
+
+ if (arg == NULL) {
+ 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);
+ script->addl(func);
+ arg = script->buildin[script->str_data[script->buildin_callsub_ref].val];
+
+ if (*arg == 0) {
+ disp_error_message("script:parse_callfunc: callsub has no arguments, please review its definition", p);
+ }
+
+ if (*arg != '*') {
+ ++arg; // count func as argument
+ }
+ } else {
#ifdef SCRIPT_CALLFUNC_CHECK
- const char* name = script->get_str(func);
- if( !is_custom && strdb_get(script->userfunc_db, name) == NULL ) {
+ const char *name = script->get_str(func);
+ if (is_custom == 0 && strdb_get(script->userfunc_db, name) == NULL) {
#endif
- disp_error_message("parse_line: expect command, missing function name or calling undeclared function",p);
+ disp_error_message("script:parse_callfunc: expect command, missing function name or calling undeclared function", p);
#ifdef SCRIPT_CALLFUNC_CHECK
- } else {;
- script->addl(script->buildin_callfunc_ref);
- script->addc(C_ARG);
- script->addc(C_STR);
- while( *name ) script->addb(*name ++);
- script->addb(0);
- arg = script->buildin[script->str_data[script->buildin_callfunc_ref].val];
- if( *arg != '*' ) ++ arg;
- }
+ } else {
+ script->addl(script->buildin_callfunc_ref);
+ script->addc(C_ARG);
+ script->addc(C_STR);
+
+ while (*name != '\0') {
+ script->addb(*name++);
+ }
+
+ script->addb(0);
+ arg = script->buildin[script->str_data[script->buildin_callfunc_ref].val];
+
+ if (*arg != '*') {
+ ++ arg;
+ }
+ }
#endif
+ }
}
p = script->skip_word(p);
p = script->skip_space(p);
script->syntax.curly[script->syntax.curly_count].type = TYPE_ARGLIST;
script->syntax.curly[script->syntax.curly_count].count = 0;
- if( *p == ';' )
- {// <func name> ';'
+
+ if (*p == ';') {
+ // <func name> ';'
script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_NO_PAREN;
- } else if( *p == '(' && *(p2=script->skip_space(p+1)) == ')' )
- {// <func name> '(' ')'
+ } else if (*p == '(' && *(p2 = script->skip_space(p + 1)) == ')') {
+ // <func name> '(' ')'
script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_PAREN;
p = p2;
- /*
- } else if( 0 && require_paren && *p != '(' )
- {// <func name>
- script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_NO_PAREN;
- */
- } else {// <func name> <arg list>
- if( require_paren ) {
- if( *p != '(' )
- disp_error_message("need '('",p);
+ } else {
+ // <func name> <arg list>
+ if (require_paren == 1) {
+ if (*p != '(') {
+ disp_error_message("script:parse_callfunc: need '('", p);
+ }
+
++p; // skip '('
script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_PAREN;
} else if( *p == '(' ) {
@@ -928,41 +983,65 @@ static const char *parse_callfunc(const char *p, int require_paren, int is_custo
} else {
script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_NO_PAREN;
}
+
++script->syntax.curly_count;
- while( *arg ) {
- p2=script->parse_subexpr(p,-1);
- if( p == p2 )
- break; // not an argument
- if( *arg != '*' )
- ++arg; // next argument
- p=script->skip_space(p2);
- if( *arg == 0 || *p != ',' )
- break; // no more arguments
+ while (*arg != '\0') {
+ p2 = script->parse_subexpr(p, -1);
+
+ if (p == p2) {
+ // not an argument
+ break;
+ }
+
+ if (*arg != '*') {
+ // next argument
+ ++arg;
+ }
+
+ p = script->skip_space(p2);
+
+ if (*arg == 0 || *p != ',') {
+ // no more arguments
+ break;
+ }
+
++p; // skip comma
}
+
--script->syntax.curly_count;
}
- if( arg && *arg && *arg != '?' && *arg != '*' )
- 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( *p != ')' )
- disp_error_message("parse_callfunc: expected ')' to close argument list",p);
+
+ if (arg != NULL && *arg != '\0' && *arg != '?' && *arg != '*') {
+ disp_error_message2("script: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 (*p != ')') {
+ disp_error_message("script:parse_callfunc: expected ')' to close argument list", p);
+ }
+
++p;
- if (script->str_data[func].val == script->buildin_lang_macro_offset)
+ if (script->str_data[func].val == script->buildin_lang_macro_offset) {
script->syntax.lang_macro_active = false;
- else if (script->str_data[func].val == script->buildin_lang_macro_fmtstring_offset)
+ } else if (script->str_data[func].val == script->buildin_lang_macro_fmtstring_offset) {
script->syntax.lang_macro_fmtstring_active = false;
+ }
}
if (!macro) {
- if (0 == --script->syntax.nested_call)
+ if (0 == --script->syntax.nested_call) {
script->syntax.last_func = -1;
+ }
+
script->addc(C_FUNC);
}
+
return p;
}
@@ -1161,6 +1240,80 @@ static const char *parse_variable(const char *p)
return p;
}
+/**
+ * Converts a number expression literal to an actual integer.
+ * Number separators are skipped.
+ *
+ * expects these formats:
+ * 1337
+ * 0x1337
+ * 0b1001
+ * 0o1337
+ *
+ * example with separating nibbles of a binary literal:
+ * 0b1101_0111_1001_1111
+ *
+ * @param p - a pointer to the first char of the number literal
+ * @param lli - a pointer to the resulting long long integer
+ * @returns a pointer to the first char after the parsed number
+*/
+static const char *parse_number(const char *p, long long *lli) {
+ nullpo_retr(NULL, p);
+
+ const bool unary_plus = (*p == '+');
+ const bool unary_minus = (*p == '-');
+
+ if (unary_plus || unary_minus) {
+ p++;
+ }
+
+ if (ISNSEPARATOR(*p)) {
+ disp_error_message("parse_number: number literals cannot begin with a separator", p);
+ }
+
+#define PARSENUMBER(skip, func, radix) \
+ for (p += skip; func(*p) || (ISNSEPARATOR(*p) && (func(p[1]) || ISNSEPARATOR(p[1]))); ++p) { \
+ if (func(*p)) { \
+ *lli *= radix; \
+ *lli += (*p < 'A') ? (*p & 0xF) : (9 + (*p & 0x7)); \
+ } else if (ISNSEPARATOR(p[1])) { \
+ disp_error_message("parse_number: number literals cannot contain two separators in a row", p + 1); \
+ } \
+ }
+
+ if (*p == '0' && p[1] == 'x') {
+ PARSENUMBER(2, ISXDIGIT, 16);
+ } else if (*p == '0' && p[1] == 'o') {
+ PARSENUMBER(2, ISODIGIT, 8);
+ } else if (*p == '0' && p[1] == 'b') {
+ PARSENUMBER(2, ISBDIGIT, 2);
+ } else {
+ PARSENUMBER(0, ISDIGIT, 10);
+ }
+
+#undef PARSENUMBER
+
+ if (ISNSEPARATOR(*p)) {
+ disp_error_message("parse_number: number literals cannot end with a separator", p);
+ }
+
+ if (unary_minus) {
+ // reverse the sign
+ *lli = -(*lli);
+ }
+
+ // make sure we can't underflow/overflow
+ if (*lli < INT_MIN) {
+ *lli = INT_MIN;
+ script->disp_warning_message("parse_number: underflow detected, capping value to INT_MIN", p);
+ } else if (*lli > INT_MAX) {
+ *lli = INT_MAX;
+ script->disp_warning_message("parse_number: overflow detected, capping value to INT_MAX", p);
+ }
+
+ return p;
+}
+
/*
* Checks whether the gives string is a number literal
*
@@ -1177,24 +1330,44 @@ static const char *parse_variable(const char *p)
static bool is_number(const char *p)
{
const char *np;
- if (!p)
- return false;
- if (*p == '-' || *p == '+')
+ nullpo_retr(false, p);
+
+ if (*p == '-' || *p == '+') {
p++;
+ }
+
np = p;
+
if (*p == '0' && p[1] == 'x') {
- p+=2;
- np = p;
- // Hexadecimal
- while (ISXDIGIT(*np))
+ // Hexadecimal: 0xFFFF
+ np = (p += 2);
+ while (ISXDIGIT(*np) || ISNSEPARATOR(*np)) {
np++;
- } else {
- // Decimal
- while (ISDIGIT(*np))
+ }
+ } else if (*p == '0' && p[1] == 'b') {
+ // Binary: 0b0001
+ np = (p += 2);
+ while (ISBDIGIT(*np) || ISNSEPARATOR(*np)) {
+ np++;
+ }
+ } else if (*p == '0' && p[1] == 'o') {
+ // Octal: 0o1500
+ np = (p += 2);
+ while (ISODIGIT(*np) || ISNSEPARATOR(*np)) {
+ np++;
+ }
+ } else if (ISDIGIT(*p)) {
+ // Decimal: 1234
+ while (ISDIGIT(*np) || ISNSEPARATOR(*np)) {
np++;
+ }
}
- if (p != np && *np != '_' && !ISALPHA(*np)) // At least one digit, and next isn't a letter or _
+
+ if (p != np && *np != '_' && !ISALPHA(*np)) {
+ // At least one digit, and next isn't a letter or _
return true;
+ }
+
return false;
}
@@ -1230,16 +1403,29 @@ static int script_string_dup(char *str)
*------------------------------------------*/
static const char *parse_simpleexpr(const char *p)
{
- p=script->skip_space(p);
+ p = script->skip_space(p);
nullpo_retr(NULL, p);
- if (*p == ';' || *p == ',')
- disp_error_message("parse_simpleexpr: unexpected end of expression",p);
+
+ if (*p == ';' || *p == ',') {
+ disp_error_message("script:parse_simpleexpr: unexpected end of expression", p);
+ }
+
if (*p == '(') {
return script->parse_simpleexpr_paren(p);
} else if (is_number(p)) {
return script->parse_simpleexpr_number(p);
} else if(*p == '"') {
+ const char *p2 = p + 1;
+
+ while (*p2 != '"') {
+ ++p2;
+ }
+
+ if (p2[1] == ':' && p2[2] == ':') {
+ return script->parse_callfunc(p, 1, 0); // XXX: why does callfunc use int for booleans?
+ }
+
return script->parse_simpleexpr_string(p);
} else {
return script->parse_simpleexpr_name(p);
@@ -1275,21 +1461,9 @@ static const char *parse_simpleexpr_paren(const char *p)
static const char *parse_simpleexpr_number(const char *p)
{
- char *np = NULL;
- long long lli;
-
- nullpo_retr(NULL, p);
- while (*p == '0' && ISDIGIT(p[1]))
- p++; // Skip leading zeros, we don't support octal literals
+ long long lli = 0;
+ const char *np = parse_number(p, &lli);
- 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 (lli > INT_MAX) {
- lli = INT_MAX;
- script->disp_warning_message("parse_simpleexpr: overflow detected, capping value to INT_MAX", p);
- }
script->addi((int)lli); // Cast is safe, as it's already been checked for overflows
return np;
@@ -1577,6 +1751,85 @@ static const char *parse_line(const char *p)
return p;
}
+/**
+ * parses a local function expression
+ *
+ * expects these formats:
+ * function <name>;
+ * function <name> { <script> }
+ *
+ * this is invoked by script->parse_syntax() after checking whether the function
+ * is public or not
+ *
+ * @param p - a pointer to the start of the function expression
+ * @param is_public - whether this function should be accessible from outside the NPC scope
+ */
+static const char *parse_syntax_function (const char *p, bool is_public)
+{
+ const char *func_name = script->skip_space(p); // the name of the local function
+ p = script->skip_word(func_name);
+
+ if (p == func_name) {
+ disp_error_message("script:parse_syntax_function: function name is missing or invalid", p);
+ }
+
+ const char *p2 = script->skip_space(p);
+
+ if (*p2 == ';') {
+ // function <name> ;
+ // function declaration - just register the name
+ int l = script->add_word(func_name);
+
+ if (script->str_data[l].type == C_NOP) {
+ // register only, if the name was not used by something else
+ script->str_data[l].type = C_USERFUNC;
+ } else if (script->str_data[l].type != C_USERFUNC) {
+ disp_error_message("script:parse_syntax_function: function name is already in use", func_name);
+ }
+
+ // Close condition of if, for, while
+ p = script->parse_syntax_close(p2 + 1);
+ return p;
+ } else if (*p2 == '{') {
+ // function <name> <line/block of code>
+ script->syntax.curly[script->syntax.curly_count].type = TYPE_USERFUNC;
+ script->syntax.curly[script->syntax.curly_count].count = 1;
+ script->syntax.curly[script->syntax.curly_count].index = script->syntax.index++;
+ script->syntax.curly[script->syntax.curly_count].flag = 0;
+ ++script->syntax.curly_count;
+
+ // Jump over the function code
+ char label[256];
+ sprintf(label, "goto __FN%x_FIN;", (unsigned int)script->syntax.curly[script->syntax.curly_count - 1].index);
+ script->syntax.curly[script->syntax.curly_count].type = TYPE_NULL;
+ ++script->syntax.curly_count;
+ script->parse_line(label);
+ --script->syntax.curly_count;
+
+ // Set the position of the function (label)
+ int l = script->add_word(func_name);
+
+ if (script->str_data[l].type == C_NOP || script->str_data[l].type == C_USERFUNC) {
+ // register only, if the name was not used by something else
+ script->str_data[l].type = C_USERFUNC;
+ script->set_label(l, VECTOR_LENGTH(script->buf), p);
+
+ if ((script->parse_options & SCRIPT_USE_LABEL_DB) != 0) {
+ script->label_add(l, VECTOR_LENGTH(script->buf),
+ LABEL_IS_USERFUNC | (is_public ? LABEL_IS_EXTERN : 0));
+ }
+ } else {
+ disp_error_message("script:parse_syntax_function: function name is already in use", func_name);
+ }
+
+ return script->skip_space(p);
+ } else {
+ disp_error_message("script:parse_syntax_function: expected ';' or '{' at function syntax", p);
+ }
+
+ return p;
+}
+
// { ... } Closing process
static const char *parse_curly_close(const char *p)
{
@@ -1920,65 +2173,11 @@ static const char *parse_syntax(const char *p)
script->set_label(l, VECTOR_LENGTH(script->buf), p);
return p;
} else if( p2 - p == 8 && strncmp(p, "function", 8) == 0 ) {
- // internal script function
- const char *func_name;
-
- func_name = script->skip_space(p2);
- p = script->skip_word(func_name);
- if( p == func_name )
- disp_error_message("parse_syntax:function: function name is missing or invalid", p);
- p2 = script->skip_space(p);
- if( *p2 == ';' )
- {// function <name> ;
- // function declaration - just register the name
- int l;
- l = script->add_word(func_name);
- if( script->str_data[l].type == C_NOP )// register only, if the name was not used by something else
- script->str_data[l].type = C_USERFUNC;
- else if( script->str_data[l].type == C_USERFUNC )
- ; // already registered
- else
- disp_error_message("parse_syntax:function: function name is invalid", func_name);
-
- // Close condition of if, for, while
- p = script->parse_syntax_close(p2 + 1);
- return p;
- }
- else if(*p2 == '{')
- {// function <name> <line/block of code>
- char label[256];
- int l;
-
- script->syntax.curly[script->syntax.curly_count].type = TYPE_USERFUNC;
- script->syntax.curly[script->syntax.curly_count].count = 1;
- script->syntax.curly[script->syntax.curly_count].index = script->syntax.index++;
- script->syntax.curly[script->syntax.curly_count].flag = 0;
- ++script->syntax.curly_count;
-
- // Jump over the function code
- sprintf(label, "goto __FN%x_FIN;", (unsigned int)script->syntax.curly[script->syntax.curly_count-1].index);
- script->syntax.curly[script->syntax.curly_count].type = TYPE_NULL;
- ++script->syntax.curly_count;
- script->parse_line(label);
- --script->syntax.curly_count;
-
- // Set the position of the function (label)
- l=script->add_word(func_name);
- if( script->str_data[l].type == C_NOP || script->str_data[l].type == C_USERFUNC )// register only, if the name was not used by something else
- {
- script->str_data[l].type = C_USERFUNC;
- script->set_label(l, VECTOR_LENGTH(script->buf), p);
- if( script->parse_options&SCRIPT_USE_LABEL_DB )
- script->label_add(l, VECTOR_LENGTH(script->buf));
- }
- else
- disp_error_message("parse_syntax:function: function name is invalid", func_name);
-
- return script->skip_space(p);
- }
- else
- {
- disp_error_message("expect ';' or '{' at function syntax",p);
+ // local function not marked as public or private
+ if (script->config.functions_private_by_default) {
+ return script->parse_syntax_function(p2, false);
+ } else {
+ return script->parse_syntax_function(p2, true);
}
}
break;
@@ -2006,6 +2205,26 @@ static const char *parse_syntax(const char *p)
return p;
}
break;
+ case 'p':
+ case 'P':
+ if (p2 - p == 6 && strncmp(p, "public", 6) == 0) {
+ p2 = script->skip_space(p2);
+ const char *p3 = script->skip_word(p2);
+
+ if (p3 - p2 == 8 && strncmp(p2, "function", 8) == 0) {
+ // local function explicitly marked as public
+ return script->parse_syntax_function(p3, true);
+ }
+ } else if (p2 - p == 7 && strncmp(p, "private", 7) == 0) {
+ p2 = script->skip_space(p2);
+ const char *p3 = script->skip_word(p2);
+
+ if (p3 - p2 == 8 && strncmp(p2, "function", 8) == 0) {
+ // local function explicitly marked as private
+ return script->parse_syntax_function(p3, false);
+ }
+ }
+ break;
case 's':
case 'S':
if( p2 - p == 6 && strncmp(p, "switch", 6) == 0 ) {
@@ -2668,25 +2887,32 @@ static struct script_code *parse_script(const char *src, const char *file, int l
}
}
- while( script->syntax.curly_count != 0 || *p != end )
- {
- if( *p == '\0' )
- disp_error_message("unexpected end of script",p);
+ while (script->syntax.curly_count != 0 || *p != end) {
+ if (*p == '\0') {
+ disp_error_message("script:parse_script: unexpected end of script", p);
+ }
+
// Special handling only label
- tmpp=script->skip_space(script->skip_word(p));
- if(*tmpp==':' && !(strncmp(p,"default:",8) == 0 && p + 7 == tmpp)) {
- i=script->add_word(p);
+ tmpp = script->skip_space(script->skip_word(p));
+
+ if (*tmpp == ':' && !(strncmp(p, "default:", 8) == 0 && p + 7 == tmpp)
+ && !(strncmp(p, "function", 8) == 0 && script->skip_space(p + 8) == tmpp)) {
+ i = script->add_word(p);
script->set_label(i, VECTOR_LENGTH(script->buf), p);
- if( script->parse_options&SCRIPT_USE_LABEL_DB )
- script->label_add(i, VECTOR_LENGTH(script->buf));
- p=tmpp+1;
- p=script->skip_space(p);
+
+ if ((script->parse_options & SCRIPT_USE_LABEL_DB) != 0) {
+ bool is_extern = ((p[0] == 'O' || p[0] == 'o') && (p[1] == 'N' || p[1] == 'n'));
+ script->label_add(i, VECTOR_LENGTH(script->buf), is_extern ? LABEL_IS_EXTERN : 0);
+ }
+
+ p = tmpp + 1;
+ p = script->skip_space(p);
continue;
}
// All other lumped
- p=script->parse_line(p);
- p=script->skip_space(p);
+ p = script->parse_line(p);
+ p = script->skip_space(p);
script->parse_nextline(false, p);
}
@@ -3395,6 +3621,32 @@ static void set_reg_instance_num(struct script_state *st, int64 num, const char
}
/**
+ * Validates if a variable is permanent (stored in database) by passed variable name.
+ *
+ * @param name The variable name to validate.
+ * @return True if variable is permanent, otherwise false.
+ *
+ **/
+static bool script_is_permanent_variable(const char *name)
+{
+ nullpo_retr(false, name);
+
+ if (strlen(name) == 0)
+ return false;
+
+ if (ISALNUM(name[0]) != 0)
+ return true; // Permanent characater variable.
+
+ if (name[0] == '#')
+ return true; // Permanent (global) account variable.
+
+ if (strlen(name) > 1 && name[0] == '$' && ISALNUM(name[1]) != 0)
+ return true; // Permanent server variable.
+
+ return false;
+}
+
+/**
* Stores the value of a script variable
*
* @param st current script state.
@@ -3439,6 +3691,18 @@ static int set_reg(struct script_state *st, struct map_session_data *sd, int64 n
if (is_string_variable(name)) {// string variable
const char *str = (const char*)value;
+ if (script->is_permanent_variable(name) && strlen(str) > SCRIPT_STRING_VAR_LENGTH) {
+ ShowError("script:set_reg: Value of variable %s is too long: %d! Maximum is %d. Skipping...\n",
+ name, (int)strlen(str), SCRIPT_STRING_VAR_LENGTH);
+
+ if (st != NULL) {
+ script->reportsrc(st);
+ st->state = END;
+ }
+
+ return 0;
+ }
+
switch (prefix) {
case '@':
if (ref) {
@@ -4828,6 +5092,8 @@ static bool script_config_read(const char *filename, bool imported)
libconfig->setting_lookup_bool_real(setting, "warn_func_mismatch_paramnum", &script->config.warn_func_mismatch_paramnum);
libconfig->setting_lookup_bool_real(setting, "warn_func_mismatch_argtypes", &script->config.warn_func_mismatch_argtypes);
+ libconfig->setting_lookup_bool_real(setting, "functions_private_by_default", &script->config.functions_private_by_default);
+ libconfig->setting_lookup_bool_real(setting, "functions_as_events", &script->config.functions_as_events);
libconfig->setting_lookup_int(setting, "check_cmdcount", &script->config.check_cmdcount);
libconfig->setting_lookup_int(setting, "check_gotocount", &script->config.check_gotocount);
libconfig->setting_lookup_int(setting, "input_min_value", &script->config.input_min_value);
@@ -6397,6 +6663,111 @@ static BUILDIN(callfunc)
return true;
}
+
+/**
+ * Calls a local function within a NPC as if it was part of the current scope.
+ * Resumes execution in the previous scope once the NPC function returns. This
+ * is essentially a clone of buildin_callsub that can run in arbitrary NPCs.
+ *
+ * Usage:
+ * callfunctionofnpc("<npc name>", "<function name>"{, <arg>...})
+ * callfunctionofnpc(<npc id>, "<function name>"{, <arg>...})
+ *
+ * This buildin is also used internally by this syntax:
+ * "<npc name>"::<function name>({<arg>...})
+ */
+static BUILDIN(callfunctionofnpc) {
+ struct npc_data *nd = NULL;
+
+ if (script_isstring(st, 2)) {
+ nd = npc->name2id(script_getstr(st, 2));
+ } else {
+ nd = map->id2nd(script_getnum(st, 2));
+ }
+
+ if (nd == NULL) {
+ ShowError("script:callfunctionofnpc: NPC not found.\n");
+ st->state = END;
+ return false;
+ }
+
+ const char *function_name = script_getstr(st, 3);
+ int pos = -1;
+
+ // find the function label within the label list of the NPC
+ for (int i = 0; i < nd->u.scr.label_list_num; ++i) {
+ if (strcmp(nd->u.scr.label_list[i].name, function_name) == 0) {
+ if ((nd->u.scr.label_list[i].flags & LABEL_IS_EXTERN) != 0
+ && (nd->u.scr.label_list[i].flags & LABEL_IS_USERFUNC) != 0) {
+ // function label found: set the start location
+ pos = nd->u.scr.label_list[i].pos;
+ } else if ((nd->u.scr.label_list[i].flags & LABEL_IS_USERFUNC) != 0) {
+ ShowError("script:callfunctionofnpc: function '%s' is not marked as public in NPC '%s'.\n", function_name, nd->name);
+ st->state = END;
+ return false;
+ }
+ break;
+ }
+ }
+
+ if (pos < 0) {
+ ShowError("script:callfunctionofnpc: function '%s' not found in NPC '%s'!\n", function_name, nd->name);
+ st->state = END;
+ return false;
+ }
+
+ // alloc a reg_db reference of the current scope for the new scope
+ struct reg_db *ref = (struct reg_db *)aCalloc(sizeof(struct reg_db), 2);
+ // scope variables (.@var)
+ ref[0].vars = st->stack->scope.vars;
+ ref[0].arrays = st->stack->scope.arrays;
+ // npc variables (.var)
+ ref[1].vars = st->script->local.vars;
+ ref[1].arrays = st->script->local.arrays;
+
+ int i = 0;
+
+ // make sure the arguments we push retain their current reg_db references:
+ // this allows to do things like set(getarg(0), ...)
+ for (i = st->start + 4; i < st->end; i++) {
+ struct script_data *data = script->push_copy(st->stack, i);
+
+ if (data_isreference(data) && data->ref == NULL) {
+ const char *name = reference_getname(data);
+
+ if (name[0] == '.') {
+ data->ref = (name[1] == '@' ? &ref[0] : &ref[1]);
+ }
+ }
+ }
+
+ // save the previous scope
+ struct script_retinfo *ri = NULL;
+ CREATE(ri, struct script_retinfo, 1);
+ ri->script = st->script; // script code
+ ri->scope.vars = st->stack->scope.vars; // scope variables
+ ri->scope.arrays = st->stack->scope.arrays; // scope arrays
+ ri->pos = st->pos; // script location
+ ri->nargs = i - st->start - 4; // argument count
+ ri->defsp = st->stack->defsp; // default stack pointer
+ script->push_retinfo(st->stack, ri, ref);
+
+ // change the current scope to the scope of the function
+ st->pos = pos;
+ st->script = nd->u.scr.script;
+ st->stack->defsp = st->stack->sp;
+ st->state = GOTO;
+ st->stack->scope.vars = i64db_alloc(DB_OPT_RELEASE_DATA);
+ st->stack->scope.arrays = idb_alloc(DB_OPT_BASE);
+
+ // make sure local reg_db of the other NPC is initialized
+ if (st->script->local.vars == NULL) {
+ st->script->local.vars = i64db_alloc(DB_OPT_RELEASE_DATA);
+ }
+
+ return true;
+}
+
/*==========================================
* subroutine call
*------------------------------------------*/
@@ -8764,22 +9135,71 @@ static BUILDIN(delitemidx)
return true;
}
-/*==========================================
- * Enables/Disables use of items while in an NPC [Skotlex]
- *------------------------------------------*/
+/**
+ * Enable item actions while interacting with NPC.
+ *
+ * @code{.herc}
+ * enableitemuse({<flag>});
+ * enable_items({<flag>});
+ * @endcode
+ *
+ **/
static BUILDIN(enableitemuse)
{
+ int flag = battle_config.item_enabled_npc;
+
+ if (script_hasdata(st, 2)) {
+ if (!script_isinttype(st, 2))
+ return true;
+
+ flag = script_getnum(st, 2);
+ }
+
+ if (flag < 0)
+ return true;
+
struct map_session_data *sd = script->rid2sd(st);
- if (sd != NULL)
- st->npc_item_flag = sd->npc_item_flag = 1;
+
+ if (sd == NULL)
+ return true;
+
+ st->npc_item_flag |= flag;
+ sd->npc_item_flag |= flag;
+
return true;
}
+/**
+ * Disable item actions while interacting with NPC.
+ *
+ * @code{.herc}
+ * disableitemuse({<flag>});
+ * disable_items({<flag>});
+ * @endcode
+ *
+ **/
static BUILDIN(disableitemuse)
{
+ int flag = battle_config.item_enabled_npc;
+
+ if (script_hasdata(st, 2)) {
+ if (!script_isinttype(st, 2))
+ return true;
+
+ flag = script_getnum(st, 2);
+ }
+
+ if (flag < 0)
+ return true;
+
struct map_session_data *sd = script->rid2sd(st);
- if (sd != NULL)
- st->npc_item_flag = sd->npc_item_flag = 0;
+
+ if (sd == NULL)
+ return true;
+
+ st->npc_item_flag &= ~flag;
+ sd->npc_item_flag &= ~flag;
+
return true;
}
@@ -10852,7 +11272,8 @@ static BUILDIN(gettimetick)
case 0:
default:
//type 0:(System Ticks)
- script_pushint(st,(int)timer->gettick()); // TODO: change this to int64 when we'll support 64 bit script values
+ // Conjunction with INT_MAX is done to prevent overflow. (Script variables are signed integers.)
+ script_pushint(st, timer->gettick() & INT_MAX); // TODO: change this to int64 when we'll support 64 bit script values
break;
}
return true;
@@ -10998,34 +11419,33 @@ static BUILDIN(itemskill)
{
struct map_session_data *sd = script->rid2sd(st);
- if (sd == NULL || sd->ud.skilltimer != INVALID_TIMER)
+ if (sd == NULL)
return true;
- sd->skillitem = script_isstringtype(st, 2) ? skill->name2id(script_getstr(st, 2)) : script_getnum(st, 2);
- sd->skillitemlv = script_getnum(st, 3);
- sd->state.itemskill_conditions_checked = 0; // Skill casting items will check the conditions prior to the target selection in AEGIS. Thus we need a flag to prevent checking them twice.
+ sd->auto_cast_current.type = AUTOCAST_ITEM;
+ sd->auto_cast_current.skill_id = script_isstringtype(st, 2) ? skill->name2id(script_getstr(st, 2)) : script_getnum(st, 2);
+ sd->auto_cast_current.skill_lv = script_getnum(st, 3);
int flag = script_hasdata(st, 4) ? script_getnum(st, 4) : ISF_NONE;
- sd->state.itemskill_no_conditions = ((flag & ISF_IGNORECONDITIONS) == ISF_IGNORECONDITIONS) ? 1 : 0; // Unset in pc_itemskill_clear().
+ sd->auto_cast_current.itemskill_check_conditions = ((flag & ISF_CHECKCONDITIONS) == ISF_CHECKCONDITIONS);
- if (sd->state.itemskill_no_conditions == 0) {
- if (skill->check_condition_castbegin(sd, sd->skillitem, sd->skillitemlv) == 0
- || skill->check_condition_castend(sd, sd->skillitem, sd->skillitemlv) == 0) {
+ if (sd->auto_cast_current.itemskill_check_conditions) {
+ if (skill->check_condition_castbegin(sd, sd->auto_cast_current.skill_id, sd->auto_cast_current.skill_lv) == 0
+ || skill->check_condition_castend(sd, sd->auto_cast_current.skill_id, sd->auto_cast_current.skill_lv) == 0) {
return true;
}
- sd->state.itemskill_conditions_checked = 1; // Unset in pc_itemskill_clear().
+ sd->auto_cast_current.itemskill_conditions_checked = true;
}
- sd->state.itemskill_no_casttime = ((flag & ISF_INSTANTCAST) == ISF_INSTANTCAST) ? 1 : 0; // Unset in pc_itemskill_clear().
- sd->state.itemskill_castonself = ((flag & ISF_CASTONSELF) == ISF_CASTONSELF) ? 1 : 0; // Unset in pc_itemskill_clear().
+ sd->auto_cast_current.itemskill_instant_cast = ((flag & ISF_INSTANTCAST) == ISF_INSTANTCAST);
+ sd->auto_cast_current.itemskill_cast_on_self = ((flag & ISF_CASTONSELF) == ISF_CASTONSELF);
- // itemskill_conditions_checked/itemskill_no_conditions/itemskill_no_casttime/itemskill_castonself abuse prevention. Unset in pc_itemskill_clear().
- sd->itemskill_id = sd->skillitem;
- sd->itemskill_lv = sd->skillitemlv;
+ VECTOR_ENSURE(sd->auto_cast, 1, 1);
+ VECTOR_PUSH(sd->auto_cast, sd->auto_cast_current);
- clif->item_skill(sd, sd->skillitem, sd->skillitemlv);
+ clif->item_skill(sd, sd->auto_cast_current.skill_id, sd->auto_cast_current.skill_lv);
return true;
}
@@ -12114,6 +12534,52 @@ static BUILDIN(mobattached)
return true;
}
+/**
+ * Announces a colored text in '<char_name> Shouts : <message>' format.
+ * Default color is white ("FFFFFF").
+ *
+ * This is a special use case of packet 0x009a where the message's first 34 bytes
+ * are reserved for string "micc" (4B) which identifies the broadcast as megaphone shout,
+ * the character's name (24B) and the text color (6B).
+ *
+ * 009a <packet len>.W <micc>.4B <char name>.24B <color>.6B <message>.?B
+ *
+ * @code{.herc}
+ * loudhailer("<message>"{, "<color>"});
+ * @endcode
+ *
+ **/
+static BUILDIN(loudhailer)
+{
+ const char *mes = script_getstr(st, 2);
+ size_t len_mes = strlen(mes);
+
+ Assert_retr(false, len_mes + 33 < CHAT_SIZE_MAX); // +33 because of the '<char_name> Shouts : ' message prefix.
+
+ const char *color = script_hasdata(st, 3) ? script_getstr(st, 3) : "FFFFFF";
+
+ Assert_retr(false, strlen(color) == 6);
+
+ struct map_session_data *sd = script->rid2sd(st);
+
+ if (sd == NULL)
+ return false;
+
+ char mes_formatted[CHAT_SIZE_MAX + 30] = "";
+
+ strcpy(mes_formatted, sd->status.name);
+ strcpy(mes_formatted + 24, color);
+ safesnprintf(mes_formatted + 30, CHAT_SIZE_MAX, "%s Shouts : %s", sd->status.name, mes);
+
+ size_t len_formatted = 30 + strlen(sd->status.name) + 10 + len_mes + 1;
+
+ clif->broadcast(&sd->bl, mes_formatted, (int)len_formatted, BC_MEGAPHONE, ALL_CLIENT);
+
+ sd->state.using_megaphone = 0;
+
+ return true;
+}
+
/*==========================================
*------------------------------------------*/
static BUILDIN(announce)
@@ -13580,6 +14046,7 @@ static BUILDIN(getmapflag)
case MF_PAIRSHIP_ENDABLE: script_pushint(st, map->list[m].flag.pairship_endable); break;
case MF_NOSTORAGE: script_pushint(st, map->list[m].flag.nostorage); break;
case MF_NOGSTORAGE: script_pushint(st, map->list[m].flag.nogstorage); break;
+ case MF_NOPET: script_pushint(st, map->list[m].flag.nopet); break;
}
}
@@ -13712,6 +14179,7 @@ static BUILDIN(setmapflag)
case MF_PAIRSHIP_ENDABLE: map->list[m].flag.pairship_endable = 1; break;
case MF_NOSTORAGE: map->list[m].flag.nostorage = cap_value(val, 0, 3); break;
case MF_NOGSTORAGE: map->list[m].flag.nogstorage = cap_value(val, 0, 3); break;
+ case MF_NOPET: map->list[m].flag.nopet = 1; break;
}
}
@@ -13805,6 +14273,7 @@ static BUILDIN(removemapflag)
case MF_NOVIEWID: map->list[m].flag.noviewid = EQP_NONE; break;
case MF_NOSTORAGE: map->list[m].flag.nostorage = 0; break;
case MF_NOGSTORAGE: map->list[m].flag.nogstorage = 0; break;
+ case MF_NOPET: map->list[m].flag.nopet = 0; break;
}
}
@@ -14780,24 +15249,34 @@ static BUILDIN(getitemslots)
return true;
}
-// TODO: add matk here if needed
-
-/*==========================================
- * Returns some values of an item [Lupus]
- * Price, Weight, etc...
- *------------------------------------------*/
+/**
+ * Returns various information about an item.
+ *
+ * @code{.herc}
+ * getiteminfo(<item ID>, <type>);
+ * getiteminfo("<item name>", <type>);
+ * @endcode
+ *
+ **/
static BUILDIN(getiteminfo)
{
- int item_id = script_getnum(st, 2);
- int n = script_getnum(st, 3);
- struct item_data *it = itemdb->exists(item_id);
+ struct item_data *it;
+
+ if (script_isstringtype(st, 2)) { /// Item name.
+ const char *name = script_getstr(st, 2);
+ it = itemdb->search_name(name);
+ } else { /// Item ID.
+ it = itemdb->exists(script_getnum(st, 2));
+ }
if (it == NULL) {
script_pushint(st, -1);
return true;
}
- switch (n) {
+ int type = script_getnum(st, 3);
+
+ switch (type) {
case ITEMINFO_BUYPRICE:
script_pushint(st, it->value_buy);
break;
@@ -14909,16 +15388,24 @@ static BUILDIN(getiteminfo)
case ITEMINFO_STACK_AMOUNT:
script_pushint(st, it->stack.amount);
break;
- case ITEMINFO_STACK_FLAG:
- {
- int stack_flag = 0;
- if (it->stack.inventory != 0) stack_flag |= 1;
- if (it->stack.cart != 0) stack_flag |= 2;
- if (it->stack.storage != 0) stack_flag |= 4;
- if (it->stack.guildstorage != 0) stack_flag |= 8;
- script_pushint(st, stack_flag);
- }
+ case ITEMINFO_STACK_FLAG: {
+ int stack_flag = 0;
+
+ if (it->stack.inventory != 0)
+ stack_flag |= 1;
+
+ if (it->stack.cart != 0)
+ stack_flag |= 2;
+
+ if (it->stack.storage != 0)
+ stack_flag |= 4;
+
+ if (it->stack.guildstorage != 0)
+ stack_flag |= 8;
+
+ script_pushint(st, stack_flag);
break;
+ }
case ITEMINFO_ITEM_USAGE_FLAG:
script_pushint(st, it->item_usage.flag);
break;
@@ -14928,11 +15415,21 @@ static BUILDIN(getiteminfo)
case ITEMINFO_GM_LV_TRADE_OVERRIDE:
script_pushint(st, it->gm_lv_trade_override);
break;
+ case ITEMINFO_ID:
+ script_pushint(st, it->nameid);
+ break;
+ case ITEMINFO_AEGISNAME:
+ script_pushstrcopy(st, it->name);
+ break;
+ case ITEMINFO_NAME:
+ script_pushstrcopy(st, it->jname);
+ break;
default:
- ShowError("buildin_getiteminfo: Invalid item type %d.\n", n);
- script_pushint(st,-1);
+ ShowError("buildin_getiteminfo: Invalid item info type %d.\n", type);
+ script_pushint(st, -1);
return false;
}
+
return true;
}
@@ -16085,7 +16582,6 @@ static BUILDIN(atcommand)
struct map_session_data *sd, *dummy_sd = NULL;
int fd;
const char* cmd;
- bool ret = true;
cmd = script_getstr(st,2);
@@ -16108,11 +16604,12 @@ static BUILDIN(atcommand)
if (!atcommand->exec(fd, sd, cmd, false)) {
ShowWarning("script: buildin_atcommand: failed to execute command '%s'\n", cmd);
- script->reportsrc(st);
- ret = false;
+ if (dummy_sd != NULL)
+ aFree(dummy_sd);
+ return false;
}
if (dummy_sd) aFree(dummy_sd);
- return ret;
+ return true;
}
/**
@@ -16558,7 +17055,7 @@ static BUILDIN(npcwalkto)
} else {
status_calc_npc(nd, SCO_NONE);
}
- unit->walktoxy(&nd->bl, x, y, 0);
+ unit->walk_toxy(&nd->bl, x, y, 0);
}
return true;
@@ -18836,7 +19333,14 @@ static BUILDIN(npcshopdelitem)
size--;
}
- RECREATE(nd->u.shop.shop_item, struct npc_item_list, size);
+ int alloc_size = size;
+ if (size < 0) {
+ size = 0;
+ alloc_size = 1;
+ } else if (size < 1) {
+ alloc_size = 1;
+ }
+ RECREATE(nd->u.shop.shop_item, struct npc_item_list, alloc_size);
nd->u.shop.count = size;
script_pushint(st,1);
@@ -19237,12 +19741,14 @@ static BUILDIN(pcblockmove)
static BUILDIN(setpcblock)
{
- struct map_session_data *sd = script->rid2sd(st);
+ struct map_session_data *sd = script_hasdata(st, 4) ? script->id2sd(st, script_getnum(st, 4)) : script->rid2sd(st);
enum pcblock_action_flag type = script_getnum(st, 2);
int state = (script_getnum(st, 3) > 0) ? 1 : 0;
- if (sd == NULL)
+ if (sd == NULL) {
+ script_pushint(st, 0);
return true;
+ }
if ((type & PCBLOCK_MOVE) != 0)
sd->block_action.move = state;
@@ -19271,12 +19777,13 @@ static BUILDIN(setpcblock)
if ((type & PCBLOCK_NPC) != 0)
sd->block_action.npc = state;
+ script_pushint(st, 1);
return true;
}
static BUILDIN(checkpcblock)
{
- struct map_session_data *sd = script->rid2sd(st);
+ struct map_session_data *sd = script_hasdata(st, 2) ? script->id2sd(st, script_getnum(st, 2)) : script->rid2sd(st);
int retval = PCBLOCK_NONE;
if (sd == NULL) {
@@ -19385,26 +19892,25 @@ static BUILDIN(getunittype)
/**
* Sets real-time unit data for a game object.
- * Setunitdata <GUID>,<DataType>,<Val1>{,<Val2>,<Val3>}
+ *
+ * @code{.herc}
+ * setunitdata <GUID>, <DataType>, <Val1>{, <Val2>, <Val3>}
+ * @endcode
+ *
* @param1 GUID GID of the unit.
* @param2 DataType Type of Data to be set for the unit.
* @param3 Value#1 Value to be passed as change in data.
* @param4 Value#2 Optional int value to be passed for certain data types.
* @param5 Value#3 Optional int value to be passed for certain data types.
* @return 1 on success, 0 on failure.
-
- Note: Please make this script command only modify ONE INTEGER value.
- If need to modify string type data, or having multiple arguments, please
- introduce a new script command.
- */
+ *
+ * Note: Please make this script command only modify ONE INTEGER value.
+ * If need to modify string type data, or having multiple arguments, please introduce a new script command.
+ *
+ **/
static BUILDIN(setunitdata)
{
- struct block_list *bl = NULL;
- const char *mapname = NULL, *udtype = NULL;
- int type = 0, val = 0, val2 = 0, val3 = 0;
- struct map_session_data *tsd = NULL;
-
- bl = map->id2bl(script_getnum(st, 2));
+ struct block_list *bl = map->id2bl(script_getnum(st, 2));
if (bl == NULL) {
ShowWarning("buildin_setunitdata: Error in finding object with given GID %d!\n", script_getnum(st, 2));
@@ -19412,22 +19918,26 @@ static BUILDIN(setunitdata)
return false;
}
- type = script_getnum(st, 3);
+ int type = script_getnum(st, 3);
- /* type bounds */
+ // Type bounds.
if (type < UDT_SIZE || type >= UDT_MAX) { // Note: UDT_TYPE is not valid here
ShowError("buildin_setunitdata: Invalid unit data type %d provided.\n", type);
script_pushint(st, 0);
return false;
}
- /* Mandatory Argument 3. Subject to deprecate. */
+ const char *mapname = NULL;
+ int val = 0;
+
+ // Mandatory argument #3. Subject to deprecate.
if (type == UDT_MAPIDXY) {
if (!script_isstringtype(st, 4)) {
ShowError("buildin_setunitdata: Invalid data type for argument #3.\n");
script_pushint(st, 0);
return false;
}
+
mapname = script_getstr(st, 4);
} else {
if (script_isstringtype(st, 4)) {
@@ -19435,68 +19945,87 @@ static BUILDIN(setunitdata)
script_pushint(st, 0);
return false;
}
+
val = script_getnum(st, 4);
}
-/* checks if value is out of bounds. */
+
+/****************************************************************************************************
+ * Define temporary macros. [BEGIN]
+ ****************************************************************************************************/
+
+// Checks if value is out of bounds.
#define setunitdata_check_bounds(arg, min, max) \
do { \
if (script_getnum(st, (arg)) < (min) || script_getnum(st, (arg)) > (max)) { \
- ShowError("buildin_setunitdata: Invalid value %d for argument #%d. (min: %d, max: %d)\n", script_getnum(st, (arg)), (arg)-1, (min), (max)); \
+ ShowError("buildin_setunitdata: Invalid value %d for argument #%d. (min: %d, max: %d)\n", \
+ script_getnum(st, (arg)), (arg) - 1, (min), (max)); \
script_pushint(st, 0); \
return false; \
} \
} while(0);
-/* checks if value is out of bounds. */
+
+// Checks if value is too low.
#define setunitdata_check_min(arg, min) \
do { \
if (script_getnum(st, (arg)) < (min)) { \
- ShowError("buildin_setunitdata: Invalid value %d for argument #%d. (min: %d)\n", script_getnum(st, (arg)), (arg)-1, (min)); \
+ ShowError("buildin_setunitdata: Invalid value %d for argument #%d. (min: %d)\n", \
+ script_getnum(st, (arg)), (arg) - 1, (min)); \
script_pushint(st, 0); \
return false; \
} \
} while(0);
-/* checks if the argument doesn't exist, if required.
- * also checks if the argument exists, if not required. */
+
+// Checks if the argument doesn't exist, if required. Also checks if the argument exists, if not required.
#define setunitdata_assert_arg(arg, required) \
do { \
if (required && !script_hasdata(st, (arg))) { \
- ShowError("buildin_setunitdata: Type %d reqires argument #%d.\n", type, (arg)-1); \
+ ShowError("buildin_setunitdata: Type %d reqires argument #%d.\n", type, (arg) - 1); \
script_pushint(st, 0); \
return false; \
} else if (!required && script_hasdata(st, arg)) { \
- ShowError("buildin_setunitdata: Argument %d is not required for type %d.\n", (arg)-1, type); \
+ ShowError("buildin_setunitdata: Argument %d is not required for type %d.\n", (arg) - 1, type); \
script_pushint(st, 0); \
return false; \
} \
} while (0);
-/* checks if the data is an integer. */
+
+// Checks if the data is an integer.
#define setunitdata_check_int(arg) \
do { \
setunitdata_assert_arg((arg), true); \
if (script_isstringtype(st, (arg))) { \
- ShowError("buildin_setunitdata: Argument #%d expects integer, string given.\n", (arg)-1); \
+ ShowError("buildin_setunitdata: Argument #%d expects integer, string given.\n", (arg) - 1); \
script_pushint(st, 0); \
return false; \
} \
} while(0);
-/* checks if the data is a string. */
+
+// Checks if the data is a string.
#define setunitdata_check_string(arg) \
do { \
setunitdata_assert_arg((arg), true); \
if (script_isinttype(st, (arg))) { \
- ShowError("buildin_setunitdata: Argument #%d expects string, integer given.\n", (arg)-1); \
+ ShowError("buildin_setunitdata: Argument #%d expects string, integer given.\n", (arg) - 1); \
script_pushint(st, 0); \
return false; \
} \
} while(0);
+/****************************************************************************************************
+ * Define temporary macros. [END]
+ ****************************************************************************************************/
+
if (type != UDT_MAPIDXY && type != UDT_WALKTOXY) {
setunitdata_assert_arg(5, false);
setunitdata_assert_arg(6, false);
}
- switch (type)
- {
+ int val2 = 0;
+ int val3 = 0;
+
+ struct map_session_data *tsd = NULL;
+
+ switch (type) {
case UDT_SIZE:
setunitdata_check_bounds(4, SZ_SMALL, SZ_BIG);
break;
@@ -19522,30 +20051,36 @@ static BUILDIN(setunitdata)
case UDT_MASTERAID:
setunitdata_check_min(4, 0);
tsd = map->id2sd(val);
+
if (tsd == NULL) {
- ShowWarning("buildin_setunitdata: Account ID %d not found for master change!\n",val);
+ ShowWarning("buildin_setunitdata: Account ID %d not found for master change!\n", val);
script_pushint(st, 0);
return false;
}
+
break;
case UDT_MASTERCID:
setunitdata_check_min(4, 0);
tsd = map->charid2sd(val);
+
if (tsd == NULL) {
- ShowWarning("buildin_setunitdata: Character ID %d not found for master change!\n",val);
+ ShowWarning("buildin_setunitdata: Character ID %d not found for master change!\n", val);
script_pushint(st, 0);
return false;
}
+
break;
case UDT_MAPIDXY:
- if ((val = map->mapname2mapid(mapname)) == -1) {
+ if ((val = map->mapname2mapid(mapname)) == INDEX_NOT_FOUND) {
ShowError("buildin_setunitdata: Non-existent map %s provided.\n", mapname);
+ script_pushint(st, 0);
return false;
}
+
setunitdata_check_int(5);
setunitdata_check_int(6);
- setunitdata_check_bounds(5, 0, MAX_MAP_SIZE/2);
- setunitdata_check_bounds(6, 0, MAX_MAP_SIZE/2);
+ setunitdata_check_bounds(5, 0, MAX_MAP_SIZE / 2);
+ setunitdata_check_bounds(6, 0, MAX_MAP_SIZE / 2);
val2 = script_getnum(st, 5);
val3 = script_getnum(st, 6);
break;
@@ -19553,8 +20088,8 @@ static BUILDIN(setunitdata)
setunitdata_assert_arg(6, false);
setunitdata_check_int(5);
val2 = script_getnum(st, 5);
- setunitdata_check_bounds(4, 0, MAX_MAP_SIZE/2);
- setunitdata_check_bounds(5, 0, MAX_MAP_SIZE/2);
+ setunitdata_check_bounds(4, 0, MAX_MAP_SIZE / 2);
+ setunitdata_check_bounds(5, 0, MAX_MAP_SIZE / 2);
break;
case UDT_SPEED:
setunitdata_check_bounds(4, 0, MAX_WALK_SPEED);
@@ -19609,7 +20144,7 @@ static BUILDIN(setunitdata)
setunitdata_check_bounds(4, 0, SHRT_MAX);
break;
case UDT_HUNGER:
- setunitdata_check_bounds(4, 0, 99);
+ setunitdata_check_bounds(4, PET_HUNGER_STARVING, PET_HUNGER_STUFFED); // Pets and Homunculi have the same hunger value bounds.
break;
case UDT_RACE:
case UDT_ELETYPE:
@@ -19617,19 +20152,20 @@ static BUILDIN(setunitdata)
setunitdata_check_bounds(4, 0, CHAR_MAX);
break;
case UDT_GROUP:
- {
setunitdata_check_bounds(4, 0, INT_MAX);
+
struct unit_data *ud = unit->bl2ud2(bl);
+
if (ud == NULL) {
ShowError("buildin_setunitdata: ud is NULL!\n");
script_pushint(st, 0);
return false;
}
+
ud->groupId = script_getnum(st, 4);
clif->blname_ack(0, bl); // Send update to client.
script_pushint(st, 1);
return true;
- }
case UDT_DAMAGE_TAKEN_RATE:
setunitdata_check_bounds(4, 1, INT_MAX);
break;
@@ -19637,67 +20173,81 @@ static BUILDIN(setunitdata)
break;
}
+/****************************************************************************************************
+ * Undefine temporary macros. [BEGIN]
+ ****************************************************************************************************/
+
#undef setunitdata_check_bounds
+#undef setunitdata_check_min
#undef setunitdata_assert_arg
#undef setunitdata_check_int
#undef setunitdata_check_string
- /* Set the values */
+/****************************************************************************************************
+ * Undefine temporary macros. [END]
+ ****************************************************************************************************/
+
+ // Set the values.
switch (bl->type) {
- case BL_MOB:
- {
+ case BL_MOB: {
struct mob_data *md = BL_UCAST(BL_MOB, bl);
- nullpo_retr(false, md);
- switch (type)
- {
+ if (md == NULL) {
+ ShowError("buildin_setunitdata: Can't find monster for GID %d!\n", script_getnum(st, 2));
+ script_pushint(st, 0);
+ return false;
+ }
+
+ switch (type) {
case UDT_SIZE:
- md->status.size = (unsigned char) val;
+ md->status.size = (unsigned char)val;
break;
case UDT_LEVEL:
md->level = val;
- if (battle_config.show_mob_info & 4)
+
+ if ((battle_config.show_mob_info & 4) != 0)
clif->blname_ack(0, &md->bl);
+
break;
case UDT_HP:
- status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_hp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
clif->blname_ack(0, &md->bl);
break;
case UDT_MAXHP:
- md->status.max_hp = (unsigned int) val;
+ md->status.max_hp = (unsigned int)val;
clif->blname_ack(0, &md->bl);
break;
case UDT_SP:
- status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_sp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXSP:
- md->status.max_sp = (unsigned int) val;
+ md->status.max_sp = (unsigned int)val;
break;
case UDT_MASTERAID:
md->master_id = val;
break;
case UDT_MAPIDXY:
- unit->warp(bl, (short) val, (short) val2, (short) val3, CLR_TELEPORT);
+ unit->warp(bl, (short)val, (short)val2, (short)val3, CLR_TELEPORT);
break;
case UDT_WALKTOXY:
- if (!unit->walktoxy(bl, (short) val, (short) val2, 2))
- unit->movepos(bl, (short) val, (short) val2, 0, 0);
+ if (unit->walk_toxy(bl, (short)val, (short)val2, 2) != 0)
+ unit->movepos(bl, (short)val, (short)val2, 0, 0);
break;
case UDT_SPEED:
- md->status.speed = (unsigned short) val;
+ md->status.speed = (unsigned short)val;
status->calc_misc(bl, &md->status, md->level);
break;
case UDT_MODE:
- md->status.mode = (enum e_mode) val;
+ md->status.mode = (enum e_mode)val;
break;
case UDT_AI:
- md->special_state.ai = (enum ai) val;
+ md->special_state.ai = (enum ai)val;
break;
case UDT_SCOPTION:
- md->sc.option = (unsigned int) val;
+ md->sc.option = (unsigned int)val;
break;
case UDT_SEX:
- md->vd->sex = (char) val;
+ md->vd->sex = (char)val;
break;
case UDT_CLASS:
mob->class_change(md, val);
@@ -19727,118 +20277,121 @@ static BUILDIN(setunitdata)
clif->changelook(bl, LOOK_WEAPON, val);
break;
case UDT_LOOKDIR:
- unit->setdir(bl, (uint8) val);
+ unit->set_dir(bl, (enum unit_dir)val);
break;
case UDT_CANMOVETICK:
md->ud.canmove_tick = val;
break;
case UDT_STR:
- md->status.str = (unsigned short) val;
+ md->status.str = (unsigned short)val;
status->calc_misc(bl, &md->status, md->level);
break;
case UDT_AGI:
- md->status.agi = (unsigned short) val;
+ md->status.agi = (unsigned short)val;
status->calc_misc(bl, &md->status, md->level);
break;
case UDT_VIT:
- md->status.vit = (unsigned short) val;
+ md->status.vit = (unsigned short)val;
status->calc_misc(bl, &md->status, md->level);
break;
case UDT_INT:
- md->status.int_ = (unsigned short) val;
+ md->status.int_ = (unsigned short)val;
status->calc_misc(bl, &md->status, md->level);
break;
case UDT_DEX:
- md->status.dex = (unsigned short) val;
+ md->status.dex = (unsigned short)val;
status->calc_misc(bl, &md->status, md->level);
break;
case UDT_LUK:
- md->status.luk = (unsigned short) val;
+ md->status.luk = (unsigned short)val;
status->calc_misc(bl, &md->status, md->level);
break;
case UDT_ATKRANGE:
- md->status.rhw.range = (unsigned short) val;
+ md->status.rhw.range = (unsigned short)val;
break;
case UDT_ATKMIN:
- md->status.rhw.atk = (unsigned short) val;
+ md->status.rhw.atk = (unsigned short)val;
break;
case UDT_ATKMAX:
- md->status.rhw.atk2 = (unsigned short) val;
+ md->status.rhw.atk2 = (unsigned short)val;
break;
case UDT_MATKMIN:
- md->status.matk_min = (unsigned short) val;
+ md->status.matk_min = (unsigned short)val;
break;
case UDT_MATKMAX:
- md->status.matk_max = (unsigned short) val;
+ md->status.matk_max = (unsigned short)val;
break;
case UDT_DEF:
- md->status.def = (defType) val;
+ md->status.def = (defType)val;
break;
case UDT_MDEF:
- md->status.mdef = (defType) val;
+ md->status.mdef = (defType)val;
break;
case UDT_HIT:
- md->status.hit = (short) val;
+ md->status.hit = (short)val;
break;
case UDT_FLEE:
- md->status.flee = (short) val;
+ md->status.flee = (short)val;
break;
case UDT_PDODGE:
- md->status.flee2 = (short) val;
+ md->status.flee2 = (short)val;
break;
case UDT_CRIT:
- md->status.cri = (short) val;
+ md->status.cri = (short)val;
break;
case UDT_RACE:
- md->status.race = (unsigned char) val;
+ md->status.race = (unsigned char)val;
break;
case UDT_ELETYPE:
- md->status.def_ele = (unsigned char) val;
+ md->status.def_ele = (unsigned char)val;
break;
case UDT_ELELEVEL:
- md->status.ele_lv = (unsigned char) val;
+ md->status.ele_lv = (unsigned char)val;
break;
case UDT_AMOTION:
- md->status.amotion = (unsigned short) val;
+ md->status.amotion = (unsigned short)val;
break;
case UDT_ADELAY:
- md->status.adelay = (unsigned short) val;
+ md->status.adelay = (unsigned short)val;
break;
case UDT_DMOTION:
- md->status.dmotion = (unsigned short) val;
+ md->status.dmotion = (unsigned short)val;
break;
case UDT_DAMAGE_TAKEN_RATE:
- md->dmg_taken_rate = (int) val;
+ md->dmg_taken_rate = (int)val;
break;
default:
- ShowWarning("buildin_setunitdata: Invalid data type '%s' for mob unit.\n", udtype);
+ ShowWarning("buildin_setunitdata: Invalid data type '%d' for mob unit.\n", type);
script_pushint(st, 0);
return false;
}
- }
+
break;
- case BL_HOM:
- {
+ }
+ case BL_HOM: {
struct homun_data *hd = BL_UCAST(BL_HOM, bl);
- nullpo_retr(false, hd);
+ if (hd == NULL) {
+ ShowError("buildin_setunitdata: Can't find Homunculus for GID %d!\n", script_getnum(st, 2));
+ script_pushint(st, 0);
+ return false;
+ }
- switch (type)
- {
+ switch (type) {
case UDT_SIZE:
- hd->base_status.size = (unsigned char) val;
+ hd->base_status.size = (unsigned char)val;
break;
case UDT_LEVEL:
- hd->homunculus.level = (short) val;
+ hd->homunculus.level = (short)val;
break;
case UDT_HP:
- status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_hp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXHP:
hd->homunculus.max_hp = val;
break;
case UDT_SP:
- status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_sp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXSP:
hd->homunculus.max_sp = val;
@@ -19848,634 +20401,645 @@ static BUILDIN(setunitdata)
hd->master = tsd;
break;
case UDT_MAPIDXY:
- unit->warp(bl, (short) val, (short) val2, (short) val3, CLR_TELEPORT);
+ unit->warp(bl, (short)val, (short)val2, (short)val3, CLR_TELEPORT);
break;
case UDT_WALKTOXY:
- if (!unit->walktoxy(bl, (short) val, (short) val2, 2))
- unit->movepos(bl, (short) val, (short) val2, 0, 0);
+ if (unit->walk_toxy(bl, (short)val, (short)val2, 2) != 0)
+ unit->movepos(bl, (short)val, (short)val2, 0, 0);
break;
case UDT_SPEED:
- hd->base_status.speed = (unsigned short) val;
+ hd->base_status.speed = (unsigned short)val;
status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
break;
case UDT_LOOKDIR:
- unit->setdir(bl, (unsigned char) val);
+ unit->set_dir(bl, (enum unit_dir)val);
break;
case UDT_CANMOVETICK:
hd->ud.canmove_tick = val;
break;
case UDT_STR:
- hd->base_status.str = (unsigned short) val;
+ hd->base_status.str = (unsigned short)val;
status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
break;
case UDT_AGI:
- hd->base_status.agi = (unsigned short) val;
+ hd->base_status.agi = (unsigned short)val;
status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
break;
case UDT_VIT:
- hd->base_status.vit = (unsigned short) val;
+ hd->base_status.vit = (unsigned short)val;
status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
break;
case UDT_INT:
- hd->base_status.int_ = (unsigned short) val;
+ hd->base_status.int_ = (unsigned short)val;
status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
break;
case UDT_DEX:
- hd->base_status.dex = (unsigned short) val;
+ hd->base_status.dex = (unsigned short)val;
status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
break;
case UDT_LUK:
- hd->base_status.luk = (unsigned short) val;
+ hd->base_status.luk = (unsigned short)val;
status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
break;
case UDT_ATKRANGE:
- hd->base_status.rhw.range = (unsigned short) val;
+ hd->base_status.rhw.range = (unsigned short)val;
break;
case UDT_ATKMIN:
- hd->base_status.rhw.atk = (unsigned short) val;
+ hd->base_status.rhw.atk = (unsigned short)val;
break;
case UDT_ATKMAX:
- hd->base_status.rhw.atk2 = (unsigned short) val;
+ hd->base_status.rhw.atk2 = (unsigned short)val;
break;
case UDT_MATKMIN:
- hd->base_status.matk_min = (unsigned short) val;
+ hd->base_status.matk_min = (unsigned short)val;
break;
case UDT_MATKMAX:
- hd->base_status.matk_max = (unsigned short) val;
+ hd->base_status.matk_max = (unsigned short)val;
break;
case UDT_DEF:
- hd->base_status.def = (defType) val;
+ hd->base_status.def = (defType)val;
break;
case UDT_MDEF:
- hd->base_status.mdef = (defType) val;
+ hd->base_status.mdef = (defType)val;
break;
case UDT_HIT:
- hd->base_status.hit = (short) val;
+ hd->base_status.hit = (short)val;
break;
case UDT_FLEE:
- hd->base_status.flee = (short) val;
+ hd->base_status.flee = (short)val;
break;
case UDT_PDODGE:
- hd->base_status.flee2 = (short) val;
+ hd->base_status.flee2 = (short)val;
break;
case UDT_CRIT:
- hd->base_status.cri = (short) val;
+ hd->base_status.cri = (short)val;
break;
case UDT_RACE:
- hd->base_status.race = (unsigned char) val;
+ hd->base_status.race = (unsigned char)val;
break;
case UDT_ELETYPE:
- hd->base_status.def_ele = (unsigned char) val;
+ hd->base_status.def_ele = (unsigned char)val;
break;
case UDT_ELELEVEL:
- hd->base_status.ele_lv = (unsigned char) val;
+ hd->base_status.ele_lv = (unsigned char)val;
break;
case UDT_AMOTION:
- hd->base_status.amotion = (unsigned short) val;
+ hd->base_status.amotion = (unsigned short)val;
break;
case UDT_ADELAY:
- hd->base_status.adelay = (unsigned short) val;
+ hd->base_status.adelay = (unsigned short)val;
break;
case UDT_DMOTION:
- hd->base_status.dmotion = (unsigned short) val;
+ hd->base_status.dmotion = (unsigned short)val;
break;
case UDT_HUNGER:
- hd->homunculus.hunger = (short) val;
+ hd->homunculus.hunger = (short)val;
clif->send_homdata(hd->master, SP_HUNGRY, hd->homunculus.hunger);
break;
case UDT_INTIMACY:
- homun->add_intimacy(hd, (unsigned int) val);
+ homun->add_intimacy(hd, (unsigned int)val);
clif->send_homdata(hd->master, SP_INTIMATE, hd->homunculus.intimacy / 100);
break;
default:
- ShowWarning("buildin_setunitdata: Invalid data type '%s' for homunculus unit.\n", udtype);
+ ShowWarning("buildin_setunitdata: Invalid data type '%d' for homunculus unit.\n", type);
script_pushint(st, 0);
return false;
}
- clif->send_homdata(hd->master, SP_ACK, 0); // send homun data
- }
+ clif->send_homdata(hd->master, SP_ACK, 0); // Send Homunculus data.
break;
- case BL_PET:
- {
+ }
+ case BL_PET: {
struct pet_data *pd = BL_UCAST(BL_PET, bl);
- nullpo_retr(false, pd);
+ if (pd == NULL) {
+ ShowError("buildin_setunitdata: Can't find pet for GID %d!\n", script_getnum(st, 2));
+ script_pushint(st, 0);
+ return false;
+ }
- switch (type)
- {
+ switch (type) {
case UDT_SIZE:
- pd->status.size = (unsigned char) val;
+ pd->status.size = (unsigned char)val;
break;
case UDT_LEVEL:
- pd->pet.level = (short) val;
+ pd->pet.level = (short)val;
+ if (pd->msd != NULL)
+ clif->send_petstatus(pd->msd); // Send pet data.
break;
case UDT_HP:
- status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_hp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXHP:
- pd->status.max_hp = (unsigned int) val;
+ pd->status.max_hp = (unsigned int)val;
break;
case UDT_SP:
- status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_sp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXSP:
- pd->status.max_sp = (unsigned int) val;
+ pd->status.max_sp = (unsigned int)val;
break;
case UDT_MASTERAID:
pd->pet.account_id = val;
pd->msd = tsd;
break;
case UDT_MAPIDXY:
- unit->warp(bl, (short) val, (short) val2, (short) val3, CLR_TELEPORT);
+ unit->warp(bl, (short)val, (short)val2, (short)val3, CLR_TELEPORT);
break;
case UDT_WALKTOXY:
- if (!unit->walktoxy(bl, (short) val, (short) val2, 2))
- unit->movepos(bl, (short) val, (short) val2, 0, 0);
+ if (unit->walk_toxy(bl, (short)val, (short)val2, 2) != 0)
+ unit->movepos(bl, (short)val, (short)val2, 0, 0);
break;
case UDT_SPEED:
- pd->status.speed = (unsigned short) val;
+ pd->status.speed = (unsigned short)val;
status->calc_misc(bl, &pd->status, pd->pet.level);
break;
case UDT_LOOKDIR:
- unit->setdir(bl, (unsigned char) val);
+ unit->set_dir(bl, (enum unit_dir)val);
break;
case UDT_CANMOVETICK:
pd->ud.canmove_tick = val;
break;
case UDT_STR:
- pd->status.str = (unsigned short) val;
+ pd->status.str = (unsigned short)val;
status->calc_misc(bl, &pd->status, pd->pet.level);
break;
case UDT_AGI:
- pd->status.agi = (unsigned short) val;
+ pd->status.agi = (unsigned short)val;
status->calc_misc(bl, &pd->status, pd->pet.level);
break;
case UDT_VIT:
- pd->status.vit = (unsigned short) val;
+ pd->status.vit = (unsigned short)val;
status->calc_misc(bl, &pd->status, pd->pet.level);
break;
case UDT_INT:
- pd->status.int_ = (unsigned short) val;
+ pd->status.int_ = (unsigned short)val;
status->calc_misc(bl, &pd->status, pd->pet.level);
break;
case UDT_DEX:
- pd->status.dex = (unsigned short) val;
+ pd->status.dex = (unsigned short)val;
status->calc_misc(bl, &pd->status, pd->pet.level);
break;
case UDT_LUK:
- pd->status.luk = (unsigned short) val;
+ pd->status.luk = (unsigned short)val;
status->calc_misc(bl, &pd->status, pd->pet.level);
break;
case UDT_ATKRANGE:
- pd->status.rhw.range = (unsigned short) val;
+ pd->status.rhw.range = (unsigned short)val;
break;
case UDT_ATKMIN:
- pd->status.rhw.atk = (unsigned short) val;
+ pd->status.rhw.atk = (unsigned short)val;
break;
case UDT_ATKMAX:
- pd->status.rhw.atk2 = (unsigned short) val;
+ pd->status.rhw.atk2 = (unsigned short)val;
break;
case UDT_MATKMIN:
- pd->status.matk_min = (unsigned short) val;
+ pd->status.matk_min = (unsigned short)val;
break;
case UDT_MATKMAX:
- pd->status.matk_max = (unsigned short) val;
+ pd->status.matk_max = (unsigned short)val;
break;
case UDT_DEF:
- pd->status.def = (defType) val;
+ pd->status.def = (defType)val;
break;
case UDT_MDEF:
- pd->status.mdef = (defType) val;
+ pd->status.mdef = (defType)val;
break;
case UDT_HIT:
- pd->status.hit = (short) val;
+ pd->status.hit = (short)val;
break;
case UDT_FLEE:
- pd->status.flee = (short) val;
+ pd->status.flee = (short)val;
break;
case UDT_PDODGE:
- pd->status.flee2 = (short) val;
+ pd->status.flee2 = (short)val;
break;
case UDT_CRIT:
- pd->status.cri = (short) val;
+ pd->status.cri = (short)val;
break;
case UDT_RACE:
- pd->status.race = (unsigned char) val;
+ pd->status.race = (unsigned char)val;
break;
case UDT_ELETYPE:
- pd->status.def_ele = (unsigned char) val;
+ pd->status.def_ele = (unsigned char)val;
break;
case UDT_ELELEVEL:
- pd->status.ele_lv = (unsigned char) val;
+ pd->status.ele_lv = (unsigned char)val;
break;
case UDT_AMOTION:
- pd->status.amotion = (unsigned short) val;
+ pd->status.amotion = (unsigned short)val;
break;
case UDT_ADELAY:
- pd->status.adelay = (unsigned short) val;
+ pd->status.adelay = (unsigned short)val;
break;
case UDT_DMOTION:
- pd->status.dmotion = (unsigned short) val;
+ pd->status.dmotion = (unsigned short)val;
break;
case UDT_INTIMACY:
pet->set_intimate(pd, val);
- clif->send_petdata(pd->msd, pd, 1, pd->pet.intimate);
break;
case UDT_HUNGER:
- pd->pet.hungry = (short) val;
+ pet->set_hunger(pd, val);
break;
default:
- ShowWarning("buildin_setunitdata: Invalid data type '%s' for pet unit.\n", udtype);
+ ShowWarning("buildin_setunitdata: Invalid data type '%d' for pet unit.\n", type);
script_pushint(st, 0);
return false;
}
- clif->send_petstatus(pd->msd); // send pet data
- }
+
break;
- case BL_MER:
- {
+ }
+ case BL_MER: {
struct mercenary_data *mc = BL_UCAST(BL_MER, bl);
- nullpo_retr(false, mc);
+ if (mc == NULL) {
+ ShowError("buildin_setunitdata: Can't find mercenary for GID %d!\n", script_getnum(st, 2));
+ script_pushint(st, 0);
+ return false;
+ }
- switch (type)
- {
+ switch (type) {
case UDT_SIZE:
- mc->base_status.size = (unsigned char) val;
+ mc->base_status.size = (unsigned char)val;
break;
case UDT_HP:
- status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_hp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXHP:
- mc->base_status.max_hp = (unsigned int) val;
+ mc->base_status.max_hp = (unsigned int)val;
break;
case UDT_SP:
- status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_sp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXSP:
- mc->base_status.max_sp = (unsigned int) val;
+ mc->base_status.max_sp = (unsigned int)val;
break;
case UDT_MASTERCID:
mc->mercenary.char_id = val;
break;
case UDT_MAPIDXY:
- unit->warp(bl, (short) val, (short) val2, (short) val3, CLR_TELEPORT);
+ unit->warp(bl, (short)val, (short)val2, (short)val3, CLR_TELEPORT);
break;
case UDT_WALKTOXY:
- if (!unit->walktoxy(bl, (short) val, (short) val2, 2))
- unit->movepos(bl, (short) val, (short) val2, 0, 0);
+ if (unit->walk_toxy(bl, (short)val, (short)val2, 2) != 0)
+ unit->movepos(bl, (short)val, (short)val2, 0, 0);
break;
case UDT_SPEED:
- mc->base_status.size = (unsigned char) val;
+ mc->base_status.size = (unsigned char)val;
status->calc_misc(bl, &mc->base_status, mc->db->lv);
break;
case UDT_LOOKDIR:
- unit->setdir(bl, (unsigned char) val);
+ unit->set_dir(bl, (enum unit_dir)val);
break;
case UDT_CANMOVETICK:
mc->ud.canmove_tick = val;
break;
case UDT_STR:
- mc->base_status.str = (unsigned short) val;
+ mc->base_status.str = (unsigned short)val;
status->calc_misc(bl, &mc->base_status, mc->db->lv);
break;
case UDT_AGI:
- mc->base_status.agi = (unsigned short) val;
+ mc->base_status.agi = (unsigned short)val;
status->calc_misc(bl, &mc->base_status, mc->db->lv);
break;
case UDT_VIT:
- mc->base_status.vit = (unsigned short) val;
+ mc->base_status.vit = (unsigned short)val;
status->calc_misc(bl, &mc->base_status, mc->db->lv);
break;
case UDT_INT:
- mc->base_status.int_ = (unsigned short) val;
+ mc->base_status.int_ = (unsigned short)val;
status->calc_misc(bl, &mc->base_status, mc->db->lv);
break;
case UDT_DEX:
- mc->base_status.dex = (unsigned short) val;
+ mc->base_status.dex = (unsigned short)val;
status->calc_misc(bl, &mc->base_status, mc->db->lv);
break;
case UDT_LUK:
- mc->base_status.luk = (unsigned short) val;
+ mc->base_status.luk = (unsigned short)val;
status->calc_misc(bl, &mc->base_status, mc->db->lv);
break;
case UDT_ATKRANGE:
- mc->base_status.rhw.range = (unsigned short) val;
+ mc->base_status.rhw.range = (unsigned short)val;
break;
case UDT_ATKMIN:
- mc->base_status.rhw.atk = (unsigned short) val;
+ mc->base_status.rhw.atk = (unsigned short)val;
break;
case UDT_ATKMAX:
- mc->base_status.rhw.atk2 = (unsigned short) val;
+ mc->base_status.rhw.atk2 = (unsigned short)val;
break;
case UDT_MATKMIN:
- mc->base_status.matk_min = (unsigned short) val;
+ mc->base_status.matk_min = (unsigned short)val;
break;
case UDT_MATKMAX:
- mc->base_status.matk_max = (unsigned short) val;
+ mc->base_status.matk_max = (unsigned short)val;
break;
case UDT_DEF:
- mc->base_status.def = (defType) val;
+ mc->base_status.def = (defType)val;
break;
case UDT_MDEF:
- mc->base_status.mdef = (defType) val;
+ mc->base_status.mdef = (defType)val;
break;
case UDT_HIT:
- mc->base_status.hit = (short) val;
+ mc->base_status.hit = (short)val;
break;
case UDT_FLEE:
- mc->base_status.flee = (short) val;
+ mc->base_status.flee = (short)val;
break;
case UDT_PDODGE:
- mc->base_status.flee2 = (short) val;
+ mc->base_status.flee2 = (short)val;
break;
case UDT_CRIT:
- mc->base_status.cri = (short) val;
+ mc->base_status.cri = (short)val;
break;
case UDT_RACE:
- mc->base_status.race = (unsigned char) val;
+ mc->base_status.race = (unsigned char)val;
break;
case UDT_ELETYPE:
- mc->base_status.def_ele = (unsigned char) val;
+ mc->base_status.def_ele = (unsigned char)val;
break;
case UDT_ELELEVEL:
- mc->base_status.ele_lv = (unsigned char) val;
+ mc->base_status.ele_lv = (unsigned char)val;
break;
case UDT_AMOTION:
- mc->base_status.amotion = (unsigned short) val;
+ mc->base_status.amotion = (unsigned short)val;
break;
case UDT_ADELAY:
- mc->base_status.adelay = (unsigned short) val;
+ mc->base_status.adelay = (unsigned short)val;
break;
case UDT_DMOTION:
- mc->base_status.dmotion = (unsigned short) val;
+ mc->base_status.dmotion = (unsigned short)val;
break;
case UDT_MERC_KILLCOUNT:
- mc->mercenary.kill_count = (unsigned int) val;
+ mc->mercenary.kill_count = (unsigned int)val;
break;
case UDT_LIFETIME:
- mc->mercenary.life_time = (unsigned int) val;
+ mc->mercenary.life_time = (unsigned int)val;
break;
default:
- ShowWarning("buildin_setunitdata: Invalid data type '%s' for mercenary unit.\n", udtype);
+ ShowWarning("buildin_setunitdata: Invalid data type '%d' for mercenary unit.\n", type);
script_pushint(st, 0);
return false;
}
+ // Send mercenary data.
clif->mercenary_info(map->charid2sd(mc->mercenary.char_id));
clif->mercenary_skillblock(map->charid2sd(mc->mercenary.char_id));
- }
break;
- case BL_ELEM:
- {
+ }
+ case BL_ELEM: {
struct elemental_data *ed = BL_UCAST(BL_ELEM, bl);
- nullpo_retr(false, ed);
+ if (ed == NULL) {
+ ShowError("buildin_setunitdata: Can't find Elemental for GID %d!\n", script_getnum(st, 2));
+ script_pushint(st, 0);
+ return false;
+ }
- switch (type)
- {
+ switch (type) {
case UDT_SIZE:
- ed->base_status.size = (unsigned char) val;
+ ed->base_status.size = (unsigned char)val;
break;
case UDT_HP:
- status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_hp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXHP:
- ed->base_status.max_hp = (unsigned int) val;
+ ed->base_status.max_hp = (unsigned int)val;
break;
case UDT_SP:
- status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_sp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXSP:
- ed->base_status.max_sp = (unsigned int) val;
+ ed->base_status.max_sp = (unsigned int)val;
break;
case UDT_MASTERCID:
ed->elemental.char_id = val;
break;
case UDT_MAPIDXY:
- unit->warp(bl, (short) val, (short) val2, (short) val3, CLR_TELEPORT);
+ unit->warp(bl, (short)val, (short)val2, (short)val3, CLR_TELEPORT);
break;
case UDT_WALKTOXY:
- if (!unit->walktoxy(bl, (short) val, (short) val2, 2))
- unit->movepos(bl, (short) val, (short) val2, 0, 0);
+ if (unit->walk_toxy(bl, (short)val, (short)val2, 2) != 0)
+ unit->movepos(bl, (short)val, (short)val2, 0, 0);
break;
case UDT_SPEED:
- ed->base_status.speed = (unsigned short) val;
+ ed->base_status.speed = (unsigned short)val;
status->calc_misc(bl, &ed->base_status, ed->db->lv);
break;
case UDT_LOOKDIR:
- unit->setdir(bl, (unsigned char) val);
+ unit->set_dir(bl, (enum unit_dir)val);
break;
case UDT_CANMOVETICK:
ed->ud.canmove_tick = val;
break;
case UDT_STR:
- ed->base_status.str = (unsigned short) val;
+ ed->base_status.str = (unsigned short)val;
status->calc_misc(bl, &ed->base_status, ed->db->lv);
break;
case UDT_AGI:
- ed->base_status.agi = (unsigned short) val;
+ ed->base_status.agi = (unsigned short)val;
status->calc_misc(bl, &ed->base_status, ed->db->lv);
break;
case UDT_VIT:
- ed->base_status.vit = (unsigned short) val;
+ ed->base_status.vit = (unsigned short)val;
status->calc_misc(bl, &ed->base_status, ed->db->lv);
break;
case UDT_INT:
- ed->base_status.int_ = (unsigned short) val;
+ ed->base_status.int_ = (unsigned short)val;
status->calc_misc(bl, &ed->base_status, ed->db->lv);
break;
case UDT_DEX:
- ed->base_status.dex = (unsigned short) val;
+ ed->base_status.dex = (unsigned short)val;
status->calc_misc(bl, &ed->base_status, ed->db->lv);
break;
case UDT_LUK:
- ed->base_status.luk = (unsigned short) val;
+ ed->base_status.luk = (unsigned short)val;
status->calc_misc(bl, &ed->base_status, ed->db->lv);
break;
case UDT_ATKRANGE:
- ed->base_status.rhw.range = (unsigned short) val;
+ ed->base_status.rhw.range = (unsigned short)val;
break;
case UDT_ATKMIN:
- ed->base_status.rhw.atk = (unsigned short) val;
+ ed->base_status.rhw.atk = (unsigned short)val;
break;
case UDT_ATKMAX:
- ed->base_status.rhw.atk2 = (unsigned short) val;
+ ed->base_status.rhw.atk2 = (unsigned short)val;
break;
case UDT_MATKMIN:
- ed->base_status.matk_min = (unsigned short) val;
+ ed->base_status.matk_min = (unsigned short)val;
break;
case UDT_MATKMAX:
- ed->base_status.matk_max = (unsigned short) val;
+ ed->base_status.matk_max = (unsigned short)val;
break;
case UDT_DEF:
- ed->base_status.def = (defType) val;
+ ed->base_status.def = (defType)val;
break;
case UDT_MDEF:
- ed->base_status.mdef = (defType) val;
+ ed->base_status.mdef = (defType)val;
break;
case UDT_HIT:
- ed->base_status.hit = (short) val;
+ ed->base_status.hit = (short)val;
break;
case UDT_FLEE:
- ed->base_status.flee = (short) val;
+ ed->base_status.flee = (short)val;
break;
case UDT_PDODGE:
- ed->base_status.flee2 = (short) val;
+ ed->base_status.flee2 = (short)val;
break;
case UDT_CRIT:
- ed->base_status.cri = (short) val;
+ ed->base_status.cri = (short)val;
break;
case UDT_RACE:
- ed->base_status.race = (unsigned char) val;
+ ed->base_status.race = (unsigned char)val;
break;
case UDT_ELETYPE:
- ed->base_status.def_ele = (unsigned char) val;
+ ed->base_status.def_ele = (unsigned char)val;
break;
case UDT_ELELEVEL:
- ed->base_status.ele_lv = (unsigned char) val;
+ ed->base_status.ele_lv = (unsigned char)val;
break;
case UDT_AMOTION:
- ed->base_status.amotion = (unsigned short) val;
+ ed->base_status.amotion = (unsigned short)val;
break;
case UDT_ADELAY:
- ed->base_status.adelay = (unsigned short) val;
+ ed->base_status.adelay = (unsigned short)val;
break;
case UDT_DMOTION:
- ed->base_status.dmotion = (unsigned short) val;
+ ed->base_status.dmotion = (unsigned short)val;
break;
case UDT_LIFETIME:
ed->elemental.life_time = val;
break;
default:
- ShowWarning("buildin_setunitdata: Invalid data type '%s' for elemental unit.\n", udtype);
+ ShowWarning("buildin_setunitdata: Invalid data type '%d' for elemental unit.\n", type);
script_pushint(st, 0);
return false;
}
- clif->elemental_info(ed->master);
- }
+
+ clif->elemental_info(ed->master); // Send Elemental data.
break;
- case BL_NPC:
- {
+ }
+ case BL_NPC: {
struct npc_data *nd = BL_UCAST(BL_NPC, bl);
- nullpo_retr(false, nd);
+ if (nd == NULL) {
+ ShowError("buildin_setunitdata: Can't find NPC for GID %d!\n", script_getnum(st, 2));
+ script_pushint(st, 0);
+ return false;
+ }
- switch (type)
- {
+ switch (type) {
case UDT_SIZE:
- nd->status.size = (unsigned char) val;
+ nd->status.size = (unsigned char)val;
break;
case UDT_LEVEL:
- nd->level = (unsigned short) val;
+ nd->level = (unsigned short)val;
break;
case UDT_HP:
- status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_hp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXHP:
- nd->status.max_hp = (unsigned int) val;
+ nd->status.max_hp = (unsigned int)val;
break;
case UDT_SP:
- status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_sp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXSP:
- nd->status.max_sp = (unsigned int) val;
+ nd->status.max_sp = (unsigned int)val;
break;
case UDT_MAPIDXY:
- unit->warp(bl, (short) val, (short) val2, (short) val3, CLR_TELEPORT);
+ unit->warp(bl, (short)val, (short)val2, (short)val3, CLR_TELEPORT);
break;
case UDT_WALKTOXY:
- if (!unit->walktoxy(bl, (short) val, (short) val2, 2))
- unit->movepos(bl, (short) val, (short) val2, 0, 0);
+ if (unit->walk_toxy(bl, (short)val, (short)val2, 2) != 0)
+ unit->movepos(bl, (short)val, (short)val2, 0, 0);
break;
case UDT_CLASS:
- npc->setclass(nd, (short) val);
+ npc->setclass(nd, (short)val);
break;
case UDT_SPEED:
- nd->speed = (short) val;
+ nd->speed = (short)val;
status->calc_misc(bl, &nd->status, nd->level);
break;
case UDT_LOOKDIR:
- unit->setdir(bl, (unsigned char) val);
+ unit->set_dir(bl, (enum unit_dir)val);
break;
case UDT_STR:
- nd->status.str = (unsigned short) val;
+ nd->status.str = (unsigned short)val;
status->calc_misc(bl, &nd->status, nd->level);
break;
case UDT_AGI:
- nd->status.agi = (unsigned short) val;
+ nd->status.agi = (unsigned short)val;
status->calc_misc(bl, &nd->status, nd->level);
break;
case UDT_VIT:
- nd->status.vit = (unsigned short) val;
+ nd->status.vit = (unsigned short)val;
status->calc_misc(bl, &nd->status, nd->level);
break;
case UDT_INT:
- nd->status.int_ = (unsigned short) val;
+ nd->status.int_ = (unsigned short)val;
status->calc_misc(bl, &nd->status, nd->level);
break;
case UDT_DEX:
- nd->status.dex = (unsigned short) val;
+ nd->status.dex = (unsigned short)val;
status->calc_misc(bl, &nd->status, nd->level);
break;
case UDT_LUK:
- nd->status.luk = (unsigned short) val;
+ nd->status.luk = (unsigned short)val;
status->calc_misc(bl, &nd->status, nd->level);
break;
case UDT_STATPOINT:
- nd->stat_point = (unsigned short) val;
+ nd->stat_point = (unsigned short)val;
break;
case UDT_ATKRANGE:
- nd->status.rhw.range = (unsigned short) val;
+ nd->status.rhw.range = (unsigned short)val;
break;
case UDT_ATKMIN:
- nd->status.rhw.atk = (unsigned short) val;
+ nd->status.rhw.atk = (unsigned short)val;
break;
case UDT_ATKMAX:
- nd->status.rhw.atk2 = (unsigned short) val;
+ nd->status.rhw.atk2 = (unsigned short)val;
break;
case UDT_MATKMIN:
- nd->status.matk_min = (unsigned short) val;
+ nd->status.matk_min = (unsigned short)val;
break;
case UDT_MATKMAX:
- nd->status.matk_max = (unsigned short) val;
+ nd->status.matk_max = (unsigned short)val;
break;
case UDT_DEF:
- nd->status.def = (defType) val;
+ nd->status.def = (defType)val;
break;
case UDT_MDEF:
- nd->status.mdef = (defType) val;
+ nd->status.mdef = (defType)val;
break;
case UDT_HIT:
- nd->status.hit = (short) val;
+ nd->status.hit = (short)val;
break;
case UDT_FLEE:
- nd->status.flee = (short) val;
+ nd->status.flee = (short)val;
break;
case UDT_PDODGE:
- nd->status.flee2 = (short) val;
+ nd->status.flee2 = (short)val;
break;
case UDT_CRIT:
- nd->status.cri = (short) val;
+ nd->status.cri = (short)val;
break;
case UDT_RACE:
- nd->status.race = (unsigned char) val;
+ nd->status.race = (unsigned char)val;
break;
case UDT_ELETYPE:
- nd->status.def_ele = (unsigned char) val;
+ nd->status.def_ele = (unsigned char)val;
break;
case UDT_ELELEVEL:
- nd->status.ele_lv = (unsigned char) val;
+ nd->status.ele_lv = (unsigned char)val;
break;
case UDT_AMOTION:
- nd->status.amotion = (unsigned short) val;
+ nd->status.amotion = (unsigned short)val;
break;
case UDT_ADELAY:
- nd->status.adelay = (unsigned short) val;
+ nd->status.adelay = (unsigned short)val;
break;
case UDT_DMOTION:
- nd->status.dmotion = (unsigned short) val;
+ nd->status.dmotion = (unsigned short)val;
break;
case UDT_SEX:
nd->vd.sex = (char)val;
@@ -20512,19 +21076,21 @@ static BUILDIN(setunitdata)
clif->changelook(bl, LOOK_BODY2, val);
break;
default:
- ShowWarning("buildin_setunitdata: Invalid data type '%s' for NPC unit.\n", udtype);
+ ShowWarning("buildin_setunitdata: Invalid data type '%d' for NPC unit.\n", type);
script_pushint(st, 0);
return false;
}
- }
+
break;
+ }
default:
ShowError("buildin_setunitdata: Unknown object!\n");
script_pushint(st, 0);
return false;
- } // end of bl->type switch
+ } // End of bl->type switch.
script_pushint(st, 1);
+
return true;
}
@@ -21121,7 +21687,10 @@ static BUILDIN(unitwalk)
if (script_hasdata(st, 4)) {
int x = script_getnum(st, 3);
int y = script_getnum(st, 4);
- script_pushint(st, unit->walktoxy(bl, x, y, 0));// We'll use harder calculations.
+ if (unit->walk_toxy(bl, x, y, 0) == 0) // We'll use harder calculations.
+ script_pushint(st, 1);
+ else
+ script_pushint(st, 0);
}
else {
int target_id = script_getnum(st, 3);
@@ -21131,6 +21700,38 @@ static BUILDIN(unitwalk)
return true;
}
+/**
+ * Checks if a unit is walking.
+ *
+ * Returns 1 if unit is walking, 0 if unit is not walking and -1 on error.
+ *
+ * @code{.herc}
+ * unitiswalking({<GID>});
+ * @endcode
+ *
+ **/
+static BUILDIN(unitiswalking)
+{
+ int gid = script_hasdata(st, 2) ? script_getnum(st, 2) : st->rid;
+ struct block_list *bl = map->id2bl(gid);
+
+ if (bl == NULL) {
+ ShowWarning("buildin_unitiswalking: Error in finding object for GID %d!\n", gid);
+ script_pushint(st, -1);
+ return false;
+ }
+
+ if (unit->bl2ud(bl) == NULL) {
+ ShowWarning("buildin_unitiswalking: Error in finding unit_data for GID %d!\n", gid);
+ script_pushint(st, -1);
+ return false;
+ }
+
+ script_pushint(st, unit->is_walking(bl));
+
+ return true;
+}
+
/// Kills the unit
///
/// unitkill <unit_id>;
@@ -21364,7 +21965,10 @@ static BUILDIN(unitskilluseid)
} else {
status_calc_npc(nd, SCO_NONE);
}
+ } else if (bl->type == BL_PC) {
+ pc->autocast_clear(BL_UCAST(BL_PC, bl));
}
+
unit->skilluse_id(bl, target_id, skill_id, skill_lv);
}
@@ -21400,7 +22004,10 @@ static BUILDIN(unitskillusepos)
} else {
status_calc_npc(nd, SCO_NONE);
}
+ } else if (bl->type == BL_PC) {
+ pc->autocast_clear(BL_UCAST(BL_PC, bl));
}
+
unit->skilluse_pos(bl, skill_x, skill_y, skill_id, skill_lv);
}
@@ -21956,12 +22563,13 @@ static BUILDIN(setquestinfo)
return false;
}
- qi = &VECTOR_LAST(nd->qi_data);
- if (qi == NULL) {
+ if (VECTOR_LENGTH(nd->qi_data) == 0) {
ShowWarning("buildin_setquestinfo: no valide questinfo data has been found for this npc.\n");
return false;
}
+ qi = &VECTOR_LAST(nd->qi_data);
+
switch (type) {
case QINFO_JOB:
{
@@ -23250,7 +23858,6 @@ static BUILDIN(progressbar_unit)
}
static BUILDIN(pushpc)
{
- uint8 dir;
int cells, dx, dy;
struct map_session_data* sd;
@@ -23259,14 +23866,14 @@ static BUILDIN(pushpc)
return true;
}
- dir = script_getnum(st,2);
- cells = script_getnum(st,3);
+ enum unit_dir dir = script_getnum(st, 2);
+ cells = script_getnum(st,3);
- if (dir > 7) {
+ if (dir >= UNIT_DIR_MAX) {
ShowWarning("buildin_pushpc: Invalid direction %d specified.\n", dir);
script->reportsrc(st);
- dir%= 8; // trim spin-over
+ dir %= UNIT_DIR_MAX; // trim spin-over
}
if(!cells)
@@ -23275,10 +23882,11 @@ static BUILDIN(pushpc)
}
else if(cells<0)
{// pushing backwards
- dir = (dir+4)%8; // turn around
- cells = -cells;
+ dir = unit_get_opposite_dir(dir);
+ cells = -cells;
}
+ Assert_retr(false, dir >= UNIT_DIR_FIRST && dir < UNIT_DIR_MAX);
dx = dirx[dir];
dy = diry[dir];
@@ -26688,8 +27296,8 @@ static void script_parse_builtin(void)
BUILDIN_DEF(delitem,"vi?"),
BUILDIN_DEF(delitem2,"viiiiiiii?"),
BUILDIN_DEF(delitemidx, "i??"),
- BUILDIN_DEF2(enableitemuse,"enable_items",""),
- BUILDIN_DEF2(disableitemuse,"disable_items",""),
+ BUILDIN_DEF2(enableitemuse, "enable_items", "?"),
+ BUILDIN_DEF2(disableitemuse, "disable_items", "?"),
BUILDIN_DEF(cutin,"si"),
BUILDIN_DEF(viewpoint,"iiiii"),
BUILDIN_DEF(heal,"ii"),
@@ -26794,6 +27402,7 @@ static void script_parse_builtin(void)
BUILDIN_DEF(detachnpctimer,"?"), // detached the player id from the npc timer [Celest]
BUILDIN_DEF(playerattached,""), // returns id of the current attached player. [Skotlex]
BUILDIN_DEF(mobattached, ""),
+ BUILDIN_DEF(loudhailer, "s?"),
BUILDIN_DEF(announce,"si?????"),
BUILDIN_DEF(mapannounce,"ssi?????"),
BUILDIN_DEF(areaannounce,"siiiisi?????"),
@@ -26970,7 +27579,7 @@ static void script_parse_builtin(void)
BUILDIN_DEF(setnpcdisplay,"sv??"),
BUILDIN_DEF(compare,"ss"), // Lordalfa - To bring strstr to scripting Engine.
BUILDIN_DEF(strcmp,"ss"),
- BUILDIN_DEF(getiteminfo,"ii"), //[Lupus] returns Items Buy / sell Price, etc info
+ BUILDIN_DEF(getiteminfo,"vi"), //[Lupus] returns Items Buy / sell Price, etc info
BUILDIN_DEF(setiteminfo,"iii"), //[Lupus] set Items Buy / sell Price, etc info
BUILDIN_DEF(getequipcardid,"ii"), //[Lupus] returns CARD ID or other info from CARD slot N of equipped item
BUILDIN_DEF(getequippedoptioninfo, "i"),
@@ -27020,8 +27629,8 @@ static void script_parse_builtin(void)
BUILDIN_DEF(pcfollow,"ii"),
BUILDIN_DEF(pcstopfollow,"i"),
BUILDIN_DEF_DEPRECATED(pcblockmove,"ii"), // Deprecated 2018-05-04
- BUILDIN_DEF(setpcblock, "ii"),
- BUILDIN_DEF(checkpcblock, ""),
+ BUILDIN_DEF(setpcblock, "ii?"),
+ BUILDIN_DEF(checkpcblock, "?"),
// <--- [zBuffer] List of player cont commands
// [zBuffer] List of mob control commands --->
BUILDIN_DEF(getunittype,"i"),
@@ -27033,6 +27642,7 @@ static void script_parse_builtin(void)
BUILDIN_DEF(getunittitle,"i"),
BUILDIN_DEF(setunittitle,"is"),
BUILDIN_DEF(unitwalk,"ii?"),
+ BUILDIN_DEF(unitiswalking, "?"),
BUILDIN_DEF(unitkill,"i"),
BUILDIN_DEF(unitwarp,"isii"),
BUILDIN_DEF(unitattack,"iv?"),
@@ -27259,6 +27869,8 @@ static void script_parse_builtin(void)
BUILDIN_DEF(identify, "i"),
BUILDIN_DEF(identifyidx, "i"),
BUILDIN_DEF(openlapineddukddakboxui, "i"),
+
+ BUILDIN_DEF(callfunctionofnpc, "vs*"),
};
int i, len = ARRAYLENGTH(BUILDIN);
RECREATE(script->buildin, char *, script->buildin_count + len); // Pre-alloc to speed up
@@ -27270,7 +27882,7 @@ static void script_parse_builtin(void)
#undef BUILDIN_DEF
#undef BUILDIN_DEF2
-static void script_label_add(int key, int pos)
+static void script_label_add(int key, int pos, enum script_label_flags flags)
{
int idx = script->label_count;
@@ -27281,6 +27893,7 @@ static void script_label_add(int key, int pos)
script->labels[idx].key = key;
script->labels[idx].pos = pos;
+ script->labels[idx].flags = flags;
script->label_count++;
}
@@ -27615,6 +28228,9 @@ static void script_hardcoded_constants(void)
script->set_constant("ITEMINFO_ITEM_USAGE_FLAG", ITEMINFO_ITEM_USAGE_FLAG, false, false);
script->set_constant("ITEMINFO_ITEM_USAGE_OVERRIDE", ITEMINFO_ITEM_USAGE_OVERRIDE, false, false);
script->set_constant("ITEMINFO_GM_LV_TRADE_OVERRIDE", ITEMINFO_GM_LV_TRADE_OVERRIDE, false, false);
+ script->set_constant("ITEMINFO_ID", ITEMINFO_ID, false, false);
+ script->set_constant("ITEMINFO_AEGISNAME", ITEMINFO_AEGISNAME, false, false);
+ script->set_constant("ITEMINFO_NAME", ITEMINFO_NAME, false, false);
script->constdb_comment("getmercinfo options");
script->set_constant("MERCINFO_ID,", MERCINFO_ID, false, false);
@@ -27642,6 +28258,23 @@ static void script_hardcoded_constants(void)
script->set_constant("PETINFO_EVO_EGGID", PETINFO_EVO_EGGID, false, false);
script->set_constant("PETINFO_AUTOFEED", PETINFO_AUTOFEED, false, false);
+ script->constdb_comment("Pet hunger levels");
+ script->set_constant("PET_HUNGER_STARVING", PET_HUNGER_STARVING, false, false);
+ script->set_constant("PET_HUNGER_VERY_HUNGRY", PET_HUNGER_VERY_HUNGRY, false, false);
+ script->set_constant("PET_HUNGER_HUNGRY", PET_HUNGER_HUNGRY, false, false);
+ script->set_constant("PET_HUNGER_NEUTRAL", PET_HUNGER_NEUTRAL, false, false);
+ script->set_constant("PET_HUNGER_SATISFIED", PET_HUNGER_SATISFIED, false, false);
+ script->set_constant("PET_HUNGER_STUFFED", PET_HUNGER_STUFFED, false, false);
+
+ script->constdb_comment("Pet intimacy levels");
+ script->set_constant("PET_INTIMACY_NONE", PET_INTIMACY_NONE, false, false);
+ script->set_constant("PET_INTIMACY_AWKWARD", PET_INTIMACY_AWKWARD, false, false);
+ script->set_constant("PET_INTIMACY_SHY", PET_INTIMACY_SHY, false, false);
+ script->set_constant("PET_INTIMACY_NEUTRAL", PET_INTIMACY_NEUTRAL, false, false);
+ script->set_constant("PET_INTIMACY_CORDIAL", PET_INTIMACY_CORDIAL, false, false);
+ script->set_constant("PET_INTIMACY_LOYAL", PET_INTIMACY_LOYAL, false, false);
+ script->set_constant("PET_INTIMACY_MAX", PET_INTIMACY_MAX, false, false);
+
script->constdb_comment("monster skill states");
script->set_constant("MSS_ANY", MSS_ANY, false, false);
script->set_constant("MSS_IDLE", MSS_IDLE, false, false);
@@ -27679,6 +28312,7 @@ static void script_hardcoded_constants(void)
script->set_constant("MSC_MASTERATTACKED", MSC_MASTERATTACKED, false, false);
script->set_constant("MSC_ALCHEMIST", MSC_ALCHEMIST, false, false);
script->set_constant("MSC_SPAWN", MSC_SPAWN, false, false);
+ script->set_constant("MSC_MAGICATTACKED", MSC_MAGICATTACKED, false, false);
script->constdb_comment("monster skill targets");
script->set_constant("MST_TARGET", MST_TARGET, false, false);
@@ -27696,6 +28330,11 @@ static void script_hardcoded_constants(void)
script->set_constant("MST_AROUND4", MST_AROUND4, false, false);
script->set_constant("MST_AROUND", MST_AROUND , false, false);
+ script->constdb_comment("Monster group constants");
+ script->set_constant("ALL_MOBS_NONBOSS", ALL_MOBS_NONBOSS, false, false);
+ script->set_constant("ALL_MOBS_BOSS", ALL_MOBS_BOSS, false, false);
+ script->set_constant("ALL_MOBS", ALL_MOBS, false, false);
+
script->constdb_comment("pc block constants, use with *setpcblock* and *checkpcblock*");
script->set_constant("PCBLOCK_NONE", PCBLOCK_NONE, false, false);
script->set_constant("PCBLOCK_MOVE", PCBLOCK_MOVE, false, false);
@@ -27708,6 +28347,16 @@ static void script_hardcoded_constants(void)
script->set_constant("PCBLOCK_COMMANDS", PCBLOCK_COMMANDS, false, false);
script->set_constant("PCBLOCK_NPC", PCBLOCK_NPC, false, false);
+ script->constdb_comment("NPC item action constants");
+ script->set_constant("ITEMENABLEDNPC_NONE", ITEMENABLEDNPC_NONE, false, false);
+ script->set_constant("ITEMENABLEDNPC_EQUIP", ITEMENABLEDNPC_EQUIP, false, false);
+ script->set_constant("ITEMENABLEDNPC_CONSUME", ITEMENABLEDNPC_CONSUME, false, false);
+
+ script->constdb_comment("NPC allowed skill use constants");
+ script->set_constant("SKILLENABLEDNPC_NONE", SKILLENABLEDNPC_NONE, false, false);
+ script->set_constant("SKILLENABLEDNPC_SELF", SKILLENABLEDNPC_SELF, false, false);
+ script->set_constant("SKILLENABLEDNPC_ALL", SKILLENABLEDNPC_ALL, false, false);
+
script->constdb_comment("private airship responds");
script->set_constant("P_AIRSHIP_NONE", P_AIRSHIP_NONE, false, false);
script->set_constant("P_AIRSHIP_RETRY", P_AIRSHIP_RETRY, false, false);
@@ -27715,6 +28364,11 @@ static void script_hardcoded_constants(void)
script->set_constant("P_AIRSHIP_INVALID_END_MAP", P_AIRSHIP_INVALID_END_MAP, false, false);
script->set_constant("P_AIRSHIP_ITEM_NOT_ENOUGH", P_AIRSHIP_ITEM_NOT_ENOUGH, false, false);
script->set_constant("P_AIRSHIP_ITEM_INVALID", P_AIRSHIP_ITEM_INVALID, false, false);
+
+ script->constdb_comment("player allowed actions when dead");
+ script->set_constant("PCALLOWACTION_NONE", PCALLOWACTION_NONE, false, false);
+ script->set_constant("PCALLOWACTION_TRADE", PCALLOWACTION_TRADE, false, false);
+ script->set_constant("PCALLOWACTION_CHAT", PCALLOWACTION_CHAT, false, false);
script->constdb_comment("questinfo types");
script->set_constant("QINFO_JOB", QINFO_JOB, false, false);
@@ -27858,10 +28512,17 @@ static void script_hardcoded_constants(void)
script->constdb_comment("itemskill option flags");
script->set_constant("ISF_NONE", ISF_NONE, false, false);
- script->set_constant("ISF_IGNORECONDITIONS", ISF_IGNORECONDITIONS, false, false);
+ script->set_constant("ISF_CHECKCONDITIONS", ISF_CHECKCONDITIONS, false, false);
script->set_constant("ISF_INSTANTCAST", ISF_INSTANTCAST, false, false);
script->set_constant("ISF_CASTONSELF", ISF_CASTONSELF, false, false);
+ script->constdb_comment("Item Bound Types");
+ script->set_constant("IBT_ANY", IBT_NONE, false, false); // for *checkbound()
+ script->set_constant("IBT_ACCOUNT", IBT_ACCOUNT, false, false);
+ script->set_constant("IBT_GUILD", IBT_GUILD, false, false);
+ script->set_constant("IBT_PARTY", IBT_PARTY, false, false);
+ script->set_constant("IBT_CHARACTER", IBT_CHARACTER, false, false);
+
script->constdb_comment("Renewal");
#ifdef RENEWAL
script->set_constant("RENEWAL", 1, false, false);
@@ -28060,6 +28721,7 @@ void script_defaults(void)
script->parse_syntax_close = parse_syntax_close;
script->parse_syntax_close_sub = parse_syntax_close_sub;
script->parse_syntax = parse_syntax;
+ script->parse_syntax_function = parse_syntax_function;
script->get_com = get_com;
script->get_num = get_num;
script->op2name = script_op2name;
@@ -28092,6 +28754,7 @@ void script_defaults(void)
script->load_parameters = script_load_parameters;
script->print_line = script_print_line;
script->errorwarning_sub = script_errorwarning_sub;
+ script->is_permanent_variable = script_is_permanent_variable;
script->set_reg = set_reg;
script->set_reg_ref_str = set_reg_npcscope_str;
script->set_reg_pc_ref_str = set_reg_pc_ref_str;
@@ -28163,6 +28826,8 @@ void script_defaults(void)
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)
script->config.onuntouch_name = "OnUnTouch"; //onuntouch_name (run whenever a char walks from the OnTouch area)
+ script->config.functions_private_by_default = true;
+ script->config.functions_as_events = false;
// for ENABLE_CASE_CHECK
script->calc_hash_ci = calc_hash_ci;