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.c12419
1 files changed, 9720 insertions, 2699 deletions
diff --git a/src/map/script.c b/src/map/script.c
index 007c6e0e1..45c954dc0 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -29,7 +29,9 @@
#include "map/channel.h"
#include "map/chat.h"
#include "map/chrif.h"
+#include "map/clan.h"
#include "map/clif.h"
+#include "map/date.h"
#include "map/elemental.h"
#include "map/guild.h"
#include "map/homunculus.h"
@@ -41,6 +43,7 @@
#include "map/map.h"
#include "map/mapreg.h"
#include "map/mercenary.h"
+#include "map/messages.h"
#include "map/mob.h"
#include "map/npc.h"
#include "map/party.h"
@@ -49,11 +52,13 @@
#include "map/pet.h"
#include "map/pet.h"
#include "map/quest.h"
+#include "map/refine.h"
#include "map/skill.h"
#include "map/status.h"
#include "map/status.h"
#include "map/storage.h"
#include "map/unit.h"
+#include "map/achievement.h"
#include "common/cbasetypes.h"
#include "common/conf.h"
#include "common/db.h"
@@ -80,42 +85,28 @@
#include <sys/time.h>
#endif
-struct script_interface script_s;
+static struct script_interface script_s;
struct script_interface *script;
-static inline int GETVALUE(const unsigned char* buf, int i) {
- return (int)MakeDWord(MakeWord(buf[i], buf[i+1]), MakeWord(buf[i+2], 0));
-}
-static inline void SETVALUE(unsigned char* buf, int i, int n) {
- buf[i] = GetByte(n, 0);
- buf[i+1] = GetByte(n, 1);
- buf[i+2] = GetByte(n, 2);
-}
-
-static inline void script_string_buf_ensure(struct script_string_buf *buf, size_t ensure) {
- if( buf->pos+ensure >= buf->size ) {
- do {
- buf->size += 512;
- } while ( buf->pos+ensure >= buf->size );
- RECREATE(buf->ptr, char, buf->size);
- }
-}
-
-static inline void script_string_buf_addb(struct script_string_buf *buf,uint8 b) {
- if( buf->pos+1 >= buf->size ) {
- buf->size += 512;
- RECREATE(buf->ptr, char, buf->size);
- }
- buf->ptr[buf->pos++] = b;
+static inline int GETVALUE(const struct script_buf *buf, int i) __attribute__((nonnull (1)));
+static inline int GETVALUE(const struct script_buf *buf, int i)
+{
+ Assert_ret(VECTOR_LENGTH(*buf) > i + 2);
+ return (int)MakeDWord(MakeWord(VECTOR_INDEX(*buf, i), VECTOR_INDEX(*buf, i+1)),
+ MakeWord(VECTOR_INDEX(*buf, i+2), 0));
}
-static inline void script_string_buf_destroy(struct script_string_buf *buf) {
- if( buf->ptr )
- aFree(buf->ptr);
- memset(buf,0,sizeof(struct script_string_buf));
+static inline void SETVALUE(struct script_buf *buf, int i, int n) __attribute__((nonnull (1)));
+static inline void SETVALUE(struct script_buf *buf, int i, int n)
+{
+ Assert_retv(VECTOR_LENGTH(*buf) > i + 2);
+ VECTOR_INDEX(*buf, i) = GetByte(n, 0);
+ VECTOR_INDEX(*buf, i+1) = GetByte(n, 1);
+ VECTOR_INDEX(*buf, i+2) = GetByte(n, 2);
}
-const char* script_op2name(int op) {
+static const char *script_op2name(int op)
+{
#define RETURN_OP_NAME(type) case type: return #type
switch( op ) {
RETURN_OP_NAME(C_NOP);
@@ -151,6 +142,7 @@ const char* script_op2name(int op) {
RETURN_OP_NAME(C_ADD);
RETURN_OP_NAME(C_SUB);
RETURN_OP_NAME(C_MUL);
+ RETURN_OP_NAME(C_POW);
RETURN_OP_NAME(C_DIV);
RETURN_OP_NAME(C_MOD);
RETURN_OP_NAME(C_NEG);
@@ -173,9 +165,10 @@ const char* script_op2name(int op) {
}
#ifdef SCRIPT_DEBUG_DUMP_STACK
-static void script_dump_stack(struct script_state* st)
+static void script_dump_stack(struct script_state *st)
{
int i;
+ nullpo_retv(st);
ShowMessage("\tstart = %d\n", st->start);
ShowMessage("\tend = %d\n", st->end);
ShowMessage("\tdefsp = %d\n", st->stack->defsp);
@@ -215,9 +208,11 @@ static void script_dump_stack(struct script_state* st)
#endif
/// Reports on the console the src of a script error.
-void script_reportsrc(struct script_state *st) {
+static void script_reportsrc(struct script_state *st)
+{
struct block_list* bl;
+ nullpo_retv(st);
if( st->oid == 0 )
return; //Can't report source.
@@ -245,7 +240,7 @@ void script_reportsrc(struct script_state *st) {
}
/// Reports on the console information about the script data.
-void script_reportdata(struct script_data* data)
+static void script_reportdata(struct script_data *data)
{
if( data == NULL )
return;
@@ -287,7 +282,7 @@ void script_reportdata(struct script_data* data)
}
/// Reports on the console information about the current built-in function.
-void script_reportfunc(struct script_state* st)
+static void script_reportfunc(struct script_state *st)
{
int params, id;
struct script_data* data;
@@ -322,8 +317,9 @@ void script_reportfunc(struct script_state* st)
/*==========================================
* Output error message
*------------------------------------------*/
-static void disp_error_message2(const char *mes,const char *pos,int report) analyzer_noreturn;
-static void disp_error_message2(const char *mes,const char *pos,int report) {
+static void disp_error_message2(const char *mes, const char *pos, int report) __attribute__((nonnull (1))) analyzer_noreturn;
+static void disp_error_message2(const char *mes, const char *pos, int report)
+{
script->error_msg = aStrdup(mes);
script->error_pos = pos;
script->error_report = report;
@@ -331,12 +327,13 @@ static void disp_error_message2(const char *mes,const char *pos,int report) {
}
#define disp_error_message(mes,pos) (disp_error_message2((mes),(pos),1))
-void disp_warning_message(const char *mes, const char *pos) {
+static void disp_warning_message(const char *mes, const char *pos)
+{
script->warning(script->parser_current_src,script->parser_current_file,script->parser_current_line,mes,pos);
}
/// Checks event parameter validity
-void check_event(struct script_state *st, const char *evt)
+static void check_event(struct script_state *st, const char *evt)
{
if( evt && evt[0] && !stristr(evt, "::On") )
{
@@ -348,9 +345,11 @@ void check_event(struct script_state *st, const char *evt)
/*==========================================
* Hashes the input string
*------------------------------------------*/
-unsigned int calc_hash(const char* p) {
+static unsigned int calc_hash(const char *p)
+{
unsigned int h;
+ nullpo_ret(p);
#if defined(SCRIPT_HASH_DJB2)
h = 5381;
while( *p ) // hash*33 + c
@@ -382,10 +381,12 @@ unsigned int calc_hash(const char* p) {
/*==========================================
* Hashes the input string in a case insensitive way
*------------------------------------------*/
-unsigned int calc_hash_ci(const char* p) {
+static unsigned int calc_hash_ci(const char *p)
+{
unsigned int h = 0;
#ifdef ENABLE_CASE_CHECK
+ nullpo_ret(p);
#if defined(SCRIPT_HASH_DJB2)
h = 5381;
while( *p ) // hash*33 + c
@@ -420,14 +421,14 @@ unsigned int calc_hash_ci(const char* p) {
*------------------------------------------*/
/// Looks up string using the provided id.
-const char* script_get_str(int id)
+static const char *script_get_str(int id)
{
Assert_retr(NULL, id >= LABEL_START && id < script->str_size);
return script->str_buf+script->str_data[id].str;
}
/// Returns the uid of the string, or -1.
-int script_search_str(const char* p)
+static int script_search_str(const char *p)
{
int i;
@@ -440,8 +441,10 @@ int script_search_str(const char* p)
return -1;
}
-void script_casecheck_clear_sub(struct casecheck_data *ccd) {
+static void script_casecheck_clear_sub(struct casecheck_data *ccd)
+{
#ifdef ENABLE_CASE_CHECK
+ nullpo_retv(ccd);
if (ccd->str_data) {
aFree(ccd->str_data);
ccd->str_data = NULL;
@@ -458,19 +461,22 @@ void script_casecheck_clear_sub(struct casecheck_data *ccd) {
#endif // ENABLE_CASE_CHECK
}
-void script_global_casecheck_clear(void) {
+static void script_global_casecheck_clear(void)
+{
script_casecheck_clear_sub(&script->global_casecheck);
}
-void script_local_casecheck_clear(void) {
+static void script_local_casecheck_clear(void)
+{
script_casecheck_clear_sub(&script->local_casecheck);
}
-const char *script_casecheck_add_str_sub(struct casecheck_data *ccd, const char *p)
+static const char *script_casecheck_add_str_sub(struct casecheck_data *ccd, const char *p)
{
#ifdef ENABLE_CASE_CHECK
int len;
int h = script->calc_hash_ci(p);
+ nullpo_retr(NULL, ccd);
if (ccd->str_hash[h] == 0) {
//empty bucket, add new node here
ccd->str_hash[h] = ccd->str_num;
@@ -522,17 +528,19 @@ const char *script_casecheck_add_str_sub(struct casecheck_data *ccd, const char
return NULL;
}
-const char *script_global_casecheck_add_str(const char *p) {
+static const char *script_global_casecheck_add_str(const char *p)
+{
return script_casecheck_add_str_sub(&script->global_casecheck, p);
}
-const char *script_local_casecheck_add_str(const char *p) {
+static const char *script_local_casecheck_add_str(const char *p)
+{
return script_casecheck_add_str_sub(&script->local_casecheck, p);
}
/// Stores a copy of the string and returns its id.
/// If an identical string is already present, returns its id instead.
-int script_add_str(const char* p)
+static int script_add_str(const char *p)
{
int len, h = script->calc_hash(p);
#ifdef ENABLE_CASE_CHECK
@@ -606,22 +614,39 @@ int script_add_str(const char* p)
return script->str_num++;
}
-/// Appends 1 byte to the script buffer.
-void add_scriptb(int a)
+static int script_add_variable(const char *varname)
{
- if( script->pos+1 >= script->size )
- {
- script->size += SCRIPT_BLOCK_SIZE;
- RECREATE(script->buf,unsigned char,script->size);
+ int key = script->search_str(varname);
+
+ if (key < 0) {
+ key = script->add_str(varname);
+ script->str_data[key].type = C_NAME;
}
- script->buf[script->pos++] = (uint8)(a);
+
+ return key;
}
-/// Appends a c_op value to the script buffer.
-/// The value is variable-length encoded into 8-bit blocks.
-/// The encoding scheme is ( 01?????? )* 00??????, LSB first.
-/// All blocks but the last hold 7 bits of data, topmost bit is always 1 (carries).
-void add_scriptc(int a)
+/**
+ * Appends 1 byte to the script buffer.
+ *
+ * @param a The byte to append.
+ */
+static void add_scriptb(int a)
+{
+ VECTOR_ENSURE(script->buf, 1, SCRIPT_BLOCK_SIZE);
+ VECTOR_PUSH(script->buf, (uint8)a);
+}
+
+/**
+ * Appends a c_op value to the script buffer.
+ *
+ * The value is variable-length encoded into 8-bit blocks.
+ * The encoding scheme is ( 01?????? )* 00??????, LSB first.
+ * All blocks but the last hold 7 bits of data, topmost bit is always 1 (carries).
+ *
+ * @param a The value to append.
+ */
+static void add_scriptc(int a)
{
while( a >= 0x40 )
{
@@ -632,11 +657,16 @@ void add_scriptc(int a)
script->addb(a);
}
-/// Appends an integer value to the script buffer.
-/// The value is variable-length encoded into 8-bit blocks.
-/// The encoding scheme is ( 11?????? )* 10??????, LSB first.
-/// All blocks but the last hold 7 bits of data, topmost bit is always 1 (carries).
-void add_scripti(int a)
+/**
+ * Appends an integer value to the script buffer.
+ *
+ * The value is variable-length encoded into 8-bit blocks.
+ * The encoding scheme is ( 11?????? )* 10??????, LSB first.
+ * All blocks but the last hold 7 bits of data, topmost bit is always 1 (carries).
+ *
+ * @param a The value to append.
+ */
+static void add_scripti(int a)
{
while( a >= 0x40 )
{
@@ -646,12 +676,12 @@ void add_scripti(int a)
script->addb(a|0x80);
}
-/// Appends a script->str_data object (label/function/variable/integer) to the script buffer.
-
-///
-/// @param l The id of the script->str_data entry
-// Maximum up to 16M
-void add_scriptl(int l)
+/**
+ * Appends a script->str_data object (label/function/variable/integer) to the script buffer.
+ *
+ * @param l The id of the script->str_data entry (Maximum up to 16M)
+ */
+static void add_scriptl(int l)
{
int backpatch = script->str_data[l].backpatch;
@@ -667,7 +697,7 @@ void add_scriptl(int l)
case C_USERFUNC:
// Embedded data backpatch there is a possibility of label
script->addc(C_NAME);
- script->str_data[l].backpatch = script->pos;
+ script->str_data[l].backpatch = VECTOR_LENGTH(script->buf);
script->addb(backpatch);
script->addb(backpatch>>8);
script->addb(backpatch>>16);
@@ -689,7 +719,7 @@ void add_scriptl(int l)
/*==========================================
* Resolve the label
*------------------------------------------*/
-void set_label(int l,int pos, const char* script_pos)
+static void set_label(int l, int pos, const char *script_pos)
{
int i;
@@ -705,15 +735,15 @@ void set_label(int l,int pos, const char* script_pos)
script->str_data[l].type=(script->str_data[l].type == C_USERFUNC ? C_USERFUNC_POS : C_POS);
script->str_data[l].label=pos;
for (i = script->str_data[l].backpatch; i >= 0 && i != 0x00ffffff; ) {
- int next = GETVALUE(script->buf,i);
- script->buf[i-1]=(script->str_data[l].type == C_USERFUNC ? C_USERFUNC_POS : C_POS);
- SETVALUE(script->buf,i,pos);
+ int next = GETVALUE(&script->buf, i);
+ VECTOR_INDEX(script->buf, i-1) = (script->str_data[l].type == C_USERFUNC ? C_USERFUNC_POS : C_POS);
+ SETVALUE(&script->buf, i, pos);
i = next;
}
}
/// Skips spaces and/or comments.
-const char* script_skip_space(const char* p)
+static const char *script_skip_space(const char *p)
{
if( p == NULL )
return NULL;
@@ -752,7 +782,9 @@ const char* script_skip_space(const char* p)
/// Skips a word.
/// A word consists of undercores and/or alphanumeric characters,
/// and valid variable prefixes/postfixes.
-const char* skip_word(const char* p) {
+static const char *skip_word(const char *p)
+{
+ nullpo_retr(NULL, p);
// prefix
switch( *p ) {
case '@':// temporary char variable
@@ -767,7 +799,7 @@ const char* skip_word(const char* p) {
p += ( p[1] == '@' ? 2 : 1 ); break;
}
- while( ISALNUM(*p) || *p == '_' || *p == '\'' )
+ while (ISALNUM(*p) || *p == '_')
++p;
// postfix
@@ -779,10 +811,12 @@ const char* skip_word(const char* p) {
/// Adds a word to script->str_data.
/// @see skip_word
/// @see script->add_str
-int add_word(const char* p) {
+static int add_word(const char *p)
+{
size_t len;
int i;
+ nullpo_retr(0, p);
// Check for a word
len = script->skip_word(p) - p;
if( len == 0 )
@@ -804,33 +838,32 @@ int add_word(const char* p) {
/// Parses a function call.
/// The argument list can have parenthesis or not.
/// The number of arguments is checked.
-static
-const char* parse_callfunc(const char* p, int require_paren, int is_custom)
+static const char *parse_callfunc(const char *p, int require_paren, int is_custom)
{
const char *p2;
char *arg = NULL;
char null_arg = '\0';
int func;
- bool nested_call = false, macro = false;
+ bool macro = false;
+ 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 ) {
- /** only when unset (-1), valid values are >= 0 **/
- if( script->syntax.last_func == -1 )
- script->syntax.last_func = script->str_data[func].val;
- else { //Nested function call
- script->syntax.nested_call++;
- nested_call = true;
-
- if( script->str_data[func].val == script->buildin_lang_macro_offset ) {
+ 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);
}
@@ -919,30 +952,29 @@ const char* parse_callfunc(const char* p, int require_paren, int is_custom)
disp_error_message("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)
+ script->syntax.lang_macro_fmtstring_active = false;
}
- if( nested_call )
- script->syntax.nested_call--;
-
- if( !script->syntax.nested_call )
- script->syntax.last_func = -1;
-
- if( !macro )
+ if (!macro) {
+ if (0 == --script->syntax.nested_call)
+ script->syntax.last_func = -1;
script->addc(C_FUNC);
+ }
return p;
}
/// Processes end of logical script line.
/// @param first When true, only fix up scheduling data is initialized
/// @param p Script position for error reporting in set_label
-void parse_nextline(bool first, const char* p)
+static void parse_nextline(bool first, const char *p)
{
if( !first )
{
script->addc(C_EOL); // mark end of line for stack cleanup
- script->set_label(LABEL_NEXTLINE, script->pos, p); // fix up '-' labels
+ script->set_label(LABEL_NEXTLINE, VECTOR_LENGTH(script->buf), p); // fix up '-' labels
}
// initialize data for new '-' label fix up scheduling
@@ -955,7 +987,7 @@ void parse_nextline(bool first, const char* p)
* Pushes a variable into stack, processing its array index if needed.
* @see parse_variable
*/
-void parse_variable_sub_push(int word, const char *p2)
+static void parse_variable_sub_push(int word, const char *p2)
{
if( p2 ) {
const char* p3 = NULL;
@@ -986,13 +1018,14 @@ void parse_variable_sub_push(int word, const char *p2)
/// Parse a variable assignment using the direct equals operator
/// @param p script position where the function should run from
/// @return NULL if not a variable assignment, the new position otherwise
-const char* parse_variable(const char* p)
+static const char *parse_variable(const char *p)
{
int word;
c_op type = C_NOP;
const char *p2 = NULL;
const char *var = p;
+ nullpo_retr(NULL, p);
if( ( p[0] == '+' && p[1] == '+' && (type = C_ADD_PRE, true) ) // pre ++
|| ( p[0] == '-' && p[1] == '-' && (type = C_SUB_PRE, true) ) // pre --
) {
@@ -1030,6 +1063,7 @@ const char* parse_variable(const char* p)
|| ( p[0] == '|' && p[1] == '=' && (type = C_OR, true) ) // |=
|| ( p[0] == '&' && p[1] == '=' && (type = C_AND, true) ) // &=
|| ( p[0] == '*' && p[1] == '=' && (type = C_MUL, true) ) // *=
+ || ( p[0] == '*' && p[1] == '*' && p[2] == '=' && (type = C_POW, true) ) // **=
|| ( p[0] == '/' && p[1] == '=' && (type = C_DIV, true) ) // /=
|| ( p[0] == '%' && p[1] == '=' && (type = C_MOD, true) ) // %=
|| ( p[0] == '+' && p[1] == '+' && (type = C_ADD_POST, true) ) // post ++
@@ -1053,6 +1087,7 @@ const char* parse_variable(const char* p)
case C_L_SHIFT: // <<=
case C_R_SHIFT: // >>=
+ case C_POW: // **=
p = script->skip_space( &p[3] );
break;
@@ -1066,6 +1101,8 @@ const char* parse_variable(const char* p)
}
// push the set function onto the stack
+ script->syntax.nested_call++;
+ script->syntax.last_func = script->str_data[script->buildin_set_ref].val;
script->addl(script->buildin_set_ref);
script->addc(C_ARG);
@@ -1117,6 +1154,8 @@ const char* parse_variable(const char* p)
// close the script by appending the function operator
script->addc(C_FUNC);
+ if (--script->syntax.nested_call == 0)
+ script->syntax.last_func = -1;
// push the buffer from the method
return p;
@@ -1135,7 +1174,8 @@ const char* parse_variable(const char* p)
* @param p Pointer to the string to check
* @return Whether the string is a number literal
*/
-bool is_number(const char *p) {
+static bool is_number(const char *p)
+{
const char *np;
if (!p)
return false;
@@ -1159,13 +1199,22 @@ bool is_number(const char *p) {
}
/**
+ * Duplicates a script string into the script string list.
*
- **/
-int script_string_dup(char *str) {
- size_t len = strlen(str);
+ * Grows the script string list as needed.
+ *
+ * @param str The string to insert.
+ * @return the string position in the script string list.
+ */
+static int script_string_dup(char *str)
+{
+ int len;
int pos = script->string_list_pos;
- while( pos+len+1 >= script->string_list_size ) {
+ nullpo_retr(pos, str);
+ len = (int)strlen(str);
+
+ while (pos+len+1 >= script->string_list_size) {
script->string_list_size += (1024*1024)/2;
RECREATE(script->string_list,char,script->string_list_size);
}
@@ -1179,240 +1228,214 @@ int script_string_dup(char *str) {
/*==========================================
* Analysis section
*------------------------------------------*/
-const char* parse_simpleexpr(const char *p)
+static const char *parse_simpleexpr(const char *p)
{
p=script->skip_space(p);
- if(*p==';' || *p==',')
+ nullpo_retr(NULL, p);
+ if (*p == ';' || *p == ',')
disp_error_message("parse_simpleexpr: unexpected end of expression",p);
- if(*p=='(') {
- int i = script->syntax.curly_count-1;
- if (i >= 0 && script->syntax.curly[i].type == TYPE_ARGLIST)
- ++script->syntax.curly[i].count;
- p=script->parse_subexpr(p+1,-1);
- p=script->skip_space(p);
- if( (i=script->syntax.curly_count-1) >= 0 && script->syntax.curly[i].type == TYPE_ARGLIST
- && script->syntax.curly[i].flag == ARGLIST_UNDEFINED && --script->syntax.curly[i].count == 0
- ) {
- if( *p == ',' ) {
- script->syntax.curly[i].flag = ARGLIST_PAREN;
- return p;
- } else {
- script->syntax.curly[i].flag = ARGLIST_NO_PAREN;
- }
- }
- if( *p != ')' )
- disp_error_message("parse_simpleexpr: unmatched ')'",p);
- ++p;
- } else if(is_number(p)) {
- char *np;
- long long lli;
- while(*p == '0' && ISDIGIT(p[1])) p++; // Skip leading zeros, we don't support octal literals
- lli=strtoll(p,&np,0);
- if( lli < INT_MIN ) {
- lli = INT_MIN;
- script->disp_warning_message("parse_simpleexpr: underflow detected, capping value to INT_MIN",p);
- } else if( 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
- p=np;
- } else if(*p=='"') {
- struct string_translation *st = NULL;
- const char *start_point = p;
- bool duplicate = true;
- struct script_string_buf *sbuf = &script->parse_simpleexpr_str;
-
- do {
- p++;
- while( *p && *p != '"' ) {
- if( (unsigned char)p[-1] <= 0x7e && *p == '\\' ) {
- char buf[8];
- size_t len = sv->skip_escaped_c(p) - p;
- size_t n = sv->unescape_c(buf, p, len);
- if( n != 1 )
- ShowDebug("parse_simpleexpr: unexpected length %d after unescape (\"%.*s\" -> %.*s)\n", (int)n, (int)len, p, (int)n, buf);
- p += len;
- script_string_buf_addb(sbuf, *buf);
- continue;
- } else if( *p == '\n' ) {
- disp_error_message("parse_simpleexpr: unexpected newline @ string",p);
- }
- script_string_buf_addb(sbuf, *p++);
- }
- if(!*p)
- disp_error_message("parse_simpleexpr: unexpected end of file @ string",p);
- p++; //'"'
- p = script->skip_space(p);
- } while( *p && *p == '"' );
-
- script_string_buf_addb(sbuf, 0);
-
- if (!(script->syntax.translation_db && (st = strdb_get(script->syntax.translation_db, sbuf->ptr)) != NULL)) {
- script->addc(C_STR);
-
- if( script->pos+sbuf->pos >= script->size ) {
- do {
- script->size += SCRIPT_BLOCK_SIZE;
- } while( script->pos+sbuf->pos >= script->size );
- RECREATE(script->buf,unsigned char,script->size);
- }
+ if (*p == '(') {
+ return script->parse_simpleexpr_paren(p);
+ } else if (is_number(p)) {
+ return script->parse_simpleexpr_number(p);
+ } else if(*p == '"') {
+ return script->parse_simpleexpr_string(p);
+ } else {
+ return script->parse_simpleexpr_name(p);
+ }
+}
- memcpy(script->buf+script->pos, sbuf->ptr, sbuf->pos);
- script->pos += sbuf->pos;
+static const char *parse_simpleexpr_paren(const char *p)
+{
+ int i = script->syntax.curly_count - 1;
+ nullpo_retr(NULL, p);
+ if (i >= 0 && script->syntax.curly[i].type == TYPE_ARGLIST)
+ ++script->syntax.curly[i].count;
+ p = script->parse_subexpr(p + 1, -1);
+ p = script->skip_space(p);
+ if ((i = script->syntax.curly_count - 1) >= 0
+ && script->syntax.curly[i].type == TYPE_ARGLIST
+ && script->syntax.curly[i].flag == ARGLIST_UNDEFINED
+ && --script->syntax.curly[i].count == 0
+ ) {
+ if (*p == ',') {
+ script->syntax.curly[i].flag = ARGLIST_PAREN;
+ return p;
} else {
- int expand = sizeof(int) + sizeof(uint8);
- unsigned char j;
- unsigned int st_cursor = 0;
+ script->syntax.curly[i].flag = ARGLIST_NO_PAREN;
+ }
+ }
+ if (*p != ')')
+ disp_error_message("parse_simpleexpr: unmatched ')'", p);
- script->addc(C_LSTR);
+ return p + 1;
+}
- expand += (sizeof(char*) + sizeof(uint8)) * st->translations;
+static const char *parse_simpleexpr_number(const char *p)
+{
+ char *np = NULL;
+ long long lli;
- while( script->pos+expand >= script->size ) {
- script->size += SCRIPT_BLOCK_SIZE;
- RECREATE(script->buf,unsigned char,script->size);
- }
+ nullpo_retr(NULL, p);
+ while (*p == '0' && ISDIGIT(p[1]))
+ p++; // Skip leading zeros, we don't support octal literals
- *((int *)(&script->buf[script->pos])) = st->string_id;
- *((uint8 *)(&script->buf[script->pos + sizeof(int)])) = st->translations;
+ 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
- script->pos += sizeof(int) + sizeof(uint8);
+ return np;
+}
- for(j = 0; j < st->translations; j++) {
- *((uint8 *)(&script->buf[script->pos])) = RBUFB(st->buf, st_cursor);
- *((char **)(&script->buf[script->pos+sizeof(uint8)])) = &st->buf[st_cursor + sizeof(uint8)];
- script->pos += sizeof(char*) + sizeof(uint8);
- st_cursor += sizeof(uint8);
- while(st->buf[st_cursor++]);
- st_cursor += sizeof(uint8);
- }
- }
+static const char *parse_simpleexpr_string(const char *p)
+{
+ const char *start_point = p;
- /* When exporting we don't know what is a translation and what isn't */
- if( script->lang_export_fp && sbuf->pos > 1 ) {//sbuf->pos will always be at least 1 because of the '\0'
- if( !script->syntax.strings ) {
- script->syntax.strings = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_ALLOW_NULL_DATA, 0);
+ nullpo_retr(NULL, p);
+ do {
+ p++;
+ while (*p != '\0' && *p != '"') {
+ if ((unsigned char)p[-1] <= 0x7e && *p == '\\') {
+ char buf[8];
+ size_t len = sv->skip_escaped_c(p) - p;
+ size_t n = sv->unescape_c(buf, p, len);
+ if (n != 1)
+ ShowDebug("parse_simpleexpr: unexpected length %d after unescape (\"%.*s\" -> %.*s)\n", (int)n, (int)len, p, (int)n, buf);
+ p += len;
+ VECTOR_ENSURE(script->parse_simpleexpr_strbuf, 1, 512);
+ VECTOR_PUSH(script->parse_simpleexpr_strbuf, buf[0]);
+ continue;
}
-
- if( !strdb_exists(script->syntax.strings,sbuf->ptr) ) {
- strdb_put(script->syntax.strings, sbuf->ptr, NULL);
- duplicate = false;
+ if (*p == '\n') {
+ disp_error_message("parse_simpleexpr: unexpected newline @ string", p);
}
+ VECTOR_ENSURE(script->parse_simpleexpr_strbuf, 1, 512);
+ VECTOR_PUSH(script->parse_simpleexpr_strbuf, *p++);
}
+ if (*p == '\0')
+ disp_error_message("parse_simpleexpr: unexpected end of file @ string", p);
+ p++; //'"'
+ p = script->skip_space(p);
+ } while (*p != '\0' && *p == '"');
- if( script->lang_export_fp && !duplicate &&
- ( ( ( script->syntax.last_func == script->buildin_mes_offset ||
- script->syntax.last_func == script->buildin_select_offset ) && !script->syntax.nested_call
- ) || script->syntax.lang_macro_active ) ) {
- const char *line_start = start_point;
- const char *line_end = start_point;
- struct script_string_buf *lbuf = &script->lang_export_line_buf;
- struct script_string_buf *ubuf = &script->lang_export_unescaped_buf;
- size_t line_length, cursor;
+ VECTOR_ENSURE(script->parse_simpleexpr_strbuf, 1, 512);
+ VECTOR_PUSH(script->parse_simpleexpr_strbuf, '\0');
- while( line_start > script->parser_current_src ) {
- if( *line_start != '\n' )
- line_start--;
- else
- break;
- }
+ script->add_translatable_string(&script->parse_simpleexpr_strbuf, start_point);
- while( *line_end != '\n' && *line_end != '\0' )
- line_end++;
+ VECTOR_TRUNCATE(script->parse_simpleexpr_strbuf);
- line_length = (size_t)(line_end - line_start);
- if( line_length > 0 ) {
- script_string_buf_ensure(lbuf,line_length + 1);
+ return p;
+}
- memcpy(lbuf->ptr, line_start, line_length);
- lbuf->pos = line_length;
- script_string_buf_addb(lbuf, 0);
+static const char *parse_simpleexpr_name(const char *p)
+{
+ int l;
+ const char *pv = NULL;
- normalize_name(lbuf->ptr, "\r\n\t ");
- }
+ // label , register , function etc
+ if (script->skip_word(p) == p)
+ disp_error_message("parse_simpleexpr: unexpected character", p);
- for(cursor = 0; cursor < sbuf->pos; cursor++) {
- if( sbuf->ptr[cursor] == '"' )
- script_string_buf_addb(ubuf, '\\');
- script_string_buf_addb(ubuf, sbuf->ptr[cursor]);
- }
- script_string_buf_addb(ubuf, 0);
-
- fprintf(script->lang_export_fp, "#: %s\n"
- "# %s\n"
- "msgctxt \"%s\"\n"
- "msgid \"%s\"\n"
- "msgstr \"\"\n",
- script->parser_current_file ? script->parser_current_file : "Unknown File",
- lbuf->ptr,
- script->parser_current_npc_name ? script->parser_current_npc_name : "Unknown NPC",
- ubuf->ptr
- );
- lbuf->pos = 0;
- ubuf->pos = 0;
+ l = script->add_word(p);
+ if (script->str_data[l].type == C_FUNC || script->str_data[l].type == C_USERFUNC || script->str_data[l].type == C_USERFUNC_POS) {
+ return script->parse_callfunc(p,1,0);
+#ifdef SCRIPT_CALLFUNC_CHECK
+ } else {
+ const char *name = script->get_str(l);
+ if (strdb_get(script->userfunc_db,name) != NULL) {
+ return script->parse_callfunc(p, 1, 1);
}
- sbuf->pos = 0;
+#endif
+ }
+
+ if ((pv = script->parse_variable(p)) != NULL) {
+ // successfully processed a variable assignment
+ return pv;
+ }
+
+ if (script->str_data[l].type == C_INT && script->str_data[l].deprecated) {
+ disp_warning_message("This constant is deprecated and it will be removed in a future version. Please see the script documentation and constants.conf for an alternative.\n", p);
+ }
+
+ p = script->skip_word(p);
+ if (*p == '[') {
+ // array(name[i] => getelementofarray(name,i) )
+ script->addl(script->buildin_getelementofarray_ref);
+ script->addc(C_ARG);
+ script->addl(l);
+
+ p = script->parse_subexpr(p + 1, -1);
+ p = script->skip_space(p);
+ if (*p != ']')
+ disp_error_message("parse_simpleexpr: unmatched ']'", p);
+ ++p;
+ script->addc(C_FUNC);
+ } else if (script->str_data[l].type == C_INT) {
+ script->addc(C_NAME);
+ script->addb(l);
+ script->addb(l >> 8);
+ script->addb(l >> 16);
} else {
- int l;
- const char* pv;
+ script->addl(l);
+ }
- // label , register , function etc
- if(script->skip_word(p)==p)
- disp_error_message("parse_simpleexpr: unexpected character",p);
+ return p;
+}
- l=script->add_word(p);
- if( script->str_data[l].type == C_FUNC || script->str_data[l].type == C_USERFUNC || script->str_data[l].type == C_USERFUNC_POS) {
- return script->parse_callfunc(p,1,0);
-#ifdef SCRIPT_CALLFUNC_CHECK
- } else {
- const char* name = script->get_str(l);
- if( strdb_get(script->userfunc_db,name) != NULL ) {
- return script->parse_callfunc(p,1,1);
- }
-#endif
- }
+static void script_add_translatable_string(const struct script_string_buf *string, const char *start_point)
+{
+ struct string_translation *st = NULL;
- if( (pv = script->parse_variable(p)) ) {
- // successfully processed a variable assignment
- return pv;
- }
+ nullpo_retv(string);
+ if (script->syntax.translation_db == NULL
+ || (st = strdb_get(script->syntax.translation_db, VECTOR_DATA(*string))) == NULL) {
+ script->addc(C_STR);
- if (script->str_data[l].type == C_INT && script->str_data[l].deprecated) {
- disp_warning_message("This constant is deprecated and it will be removed in a future version. Please see the script documentation and constants.conf for an alternative.\n", p);
- }
+ VECTOR_ENSURE(script->buf, VECTOR_LENGTH(*string), SCRIPT_BLOCK_SIZE);
- p=script->skip_word(p);
- if( *p == '[' ) {
- // array(name[i] => getelementofarray(name,i) )
- script->addl(script->buildin_getelementofarray_ref);
- script->addc(C_ARG);
- script->addl(l);
+ VECTOR_PUSHARRAY(script->buf, VECTOR_DATA(*string), VECTOR_LENGTH(*string));
+ } else {
+ unsigned char u;
+ int st_cursor = 0;
- p=script->parse_subexpr(p+1,-1);
- p=script->skip_space(p);
- if( *p != ']' )
- disp_error_message("parse_simpleexpr: unmatched ']'",p);
- ++p;
- script->addc(C_FUNC);
- } else {
- script->addl(l);
- }
+ script->addc(C_LSTR);
- }
+ VECTOR_ENSURE(script->buf, (int)(sizeof(st->string_id) + sizeof(st->translations)), SCRIPT_BLOCK_SIZE);
+ VECTOR_PUSHARRAY(script->buf, (void *)&st->string_id, sizeof(st->string_id));
+ VECTOR_PUSHARRAY(script->buf, (void *)&st->translations, sizeof(st->translations));
- return p;
+ for (u = 0; u != st->translations; u++) {
+ struct string_translation_entry *entry = (void *)(st->buf+st_cursor);
+ char *stringptr = &entry->string[0];
+ st_cursor += sizeof(*entry);
+ VECTOR_ENSURE(script->buf, (int)(sizeof(entry->lang_id) + sizeof(char *)), SCRIPT_BLOCK_SIZE);
+ VECTOR_PUSHARRAY(script->buf, (void *)&entry->lang_id, sizeof(entry->lang_id));
+ VECTOR_PUSHARRAY(script->buf, (void *)&stringptr, sizeof(stringptr));
+ st_cursor += sizeof(uint8); // FIXME: What are we skipping here?
+ while (st->buf[st_cursor++] != 0)
+ (void)0; // Skip string
+ st_cursor += sizeof(uint8); // FIXME: What are we skipping here?
+ }
+ }
}
/*==========================================
* Analysis of the expression
*------------------------------------------*/
-const char* script_parse_subexpr(const char* p,int limit)
+static const char *script_parse_subexpr(const char *p, int limit)
{
int op,opl,len;
+ nullpo_retr(NULL, p);
p=script->skip_space(p);
if( *p == '-' ) {
@@ -1435,8 +1458,9 @@ const char* script_parse_subexpr(const char* p,int limit)
p=script->skip_space(p);
while((
(op=C_OP3, opl=0, len=1,*p=='?') // ?:
- || (op=C_ADD, opl=9, len=1,*p=='+') // +
- || (op=C_SUB, opl=9, len=1,*p=='-') // -
+ || (op=C_ADD, opl=9, len=1,*p=='+' && p[1]!='+') // +
+ || (op=C_SUB, opl=9, len=1,*p=='-' && p[1]!='-') // -
+ || (op=C_POW, opl=11,len=2,*p=='*' && p[1]=='*') // **
|| (op=C_MUL, opl=10,len=1,*p=='*') // *
|| (op=C_DIV, opl=10,len=1,*p=='/') // /
|| (op=C_MOD, opl=10,len=1,*p=='%') // %
@@ -1476,8 +1500,9 @@ const char* script_parse_subexpr(const char* p,int limit)
/*==========================================
* Evaluation of the expression
*------------------------------------------*/
-const char* parse_expr(const char *p)
+static const char *parse_expr(const char *p)
{
+ nullpo_retr(NULL, p);
switch(*p) {
case ')': case ';': case ':': case '[': case ']':
case '}':
@@ -1490,10 +1515,11 @@ const char* parse_expr(const char *p)
/*==========================================
* Analysis of the line
*------------------------------------------*/
-const char* parse_line(const char* p)
+static const char *parse_line(const char *p)
{
const char* p2;
+ nullpo_retr(NULL, p);
p=script->skip_space(p);
if(*p==';') {
//Close decision for if(); for(); while();
@@ -1552,8 +1578,9 @@ const char* parse_line(const char* p)
}
// { ... } Closing process
-const char* parse_curly_close(const char* p)
+static const char *parse_curly_close(const char *p)
{
+ nullpo_retr(NULL, p);
if(script->syntax.curly_count <= 0) {
disp_error_message("parse_curly_close: unexpected string",p);
return p + 1;
@@ -1582,7 +1609,7 @@ const char* parse_curly_close(const char* p)
// You are here labeled
sprintf(label,"__SW%x_%x", (unsigned int)script->syntax.curly[pos].index, (unsigned int)script->syntax.curly[pos].count);
l=script->add_str(label);
- script->set_label(l,script->pos, p);
+ script->set_label(l, VECTOR_LENGTH(script->buf), p);
if(script->syntax.curly[pos].flag) {
//Exists default
@@ -1595,7 +1622,7 @@ const char* parse_curly_close(const char* p)
// Label end
sprintf(label,"__SW%x_FIN", (unsigned int)script->syntax.curly[pos].index);
l=script->add_str(label);
- script->set_label(l,script->pos, p);
+ script->set_label(l, VECTOR_LENGTH(script->buf), p);
linkdb_final(&script->syntax.curly[pos].case_label); // free the list of case label
script->syntax.curly_count--;
//Closing decision if, for , while
@@ -1610,10 +1637,11 @@ const char* parse_curly_close(const char* p)
// Syntax-related processing
// break, case, continue, default, do, for, function,
// if, switch, while ? will handle this internally.
-const char* parse_syntax(const char* p)
+static const char *parse_syntax(const char *p)
{
const char *p2 = script->skip_word(p);
+ nullpo_retr(NULL, p);
switch(*p) {
case 'B':
case 'b':
@@ -1674,7 +1702,7 @@ const char* parse_syntax(const char* p)
// You are here labeled
sprintf(label,"__SW%x_%x", (unsigned int)script->syntax.curly[pos].index, (unsigned int)script->syntax.curly[pos].count);
l=script->add_str(label);
- script->set_label(l,script->pos, p);
+ script->set_label(l, VECTOR_LENGTH(script->buf), p);
}
//Decision statement switch
p = script->skip_space(p2);
@@ -1714,7 +1742,7 @@ const char* parse_syntax(const char* p)
// Label after the completion of FALLTHRU
sprintf(label, "__SW%x_%xJ", (unsigned int)script->syntax.curly[pos].index, (unsigned int)script->syntax.curly[pos].count);
l=script->add_str(label);
- script->set_label(l,script->pos,p);
+ script->set_label(l, VECTOR_LENGTH(script->buf), p);
}
// check duplication of case label [Rayce]
if(linkdb_search(&script->syntax.curly[pos].case_label, (void*)h64BPTRSIZE(v)) != NULL)
@@ -1781,7 +1809,7 @@ const char* parse_syntax(const char* p)
}
sprintf(label, "__SW%x_%x", (unsigned int)script->syntax.curly[pos].index, (unsigned int)script->syntax.curly[pos].count);
l=script->add_str(label);
- script->set_label(l,script->pos,p);
+ script->set_label(l, VECTOR_LENGTH(script->buf), p);
// Skip to the next link w/o condition
sprintf(label, "goto __SW%x_%x;", (unsigned int)script->syntax.curly[pos].index, (unsigned int)script->syntax.curly[pos].count + 1);
@@ -1792,7 +1820,7 @@ const char* parse_syntax(const char* p)
// The default label
sprintf(label, "__SW%x_DEF", (unsigned int)script->syntax.curly[pos].index);
l=script->add_str(label);
- script->set_label(l,script->pos,p);
+ script->set_label(l, VECTOR_LENGTH(script->buf), p);
script->syntax.curly[script->syntax.curly_count - 1].flag = 1;
script->syntax.curly[pos].count++;
@@ -1810,7 +1838,7 @@ const char* parse_syntax(const char* p)
// Label of the (do) form here
sprintf(label, "__DO%x_BGN", (unsigned int)script->syntax.curly[script->syntax.curly_count].index);
l=script->add_str(label);
- script->set_label(l,script->pos,p);
+ script->set_label(l, VECTOR_LENGTH(script->buf), p);
script->syntax.curly_count++;
return p;
}
@@ -1841,7 +1869,7 @@ const char* parse_syntax(const char* p)
// Form the start of label decision
sprintf(label, "__FR%x_J", (unsigned int)script->syntax.curly[pos].index);
l=script->add_str(label);
- script->set_label(l,script->pos,p);
+ script->set_label(l, VECTOR_LENGTH(script->buf), p);
p=script->skip_space(p);
if(*p == ';') {
@@ -1870,7 +1898,7 @@ const char* parse_syntax(const char* p)
// Labels to form the next loop
sprintf(label, "__FR%x_NXT", (unsigned int)script->syntax.curly[pos].index);
l=script->add_str(label);
- script->set_label(l,script->pos,p);
+ script->set_label(l, VECTOR_LENGTH(script->buf), p);
// Process the next time you enter the loop
// A ')' last for; flag to be treated as'
@@ -1889,7 +1917,7 @@ const char* parse_syntax(const char* p)
// Loop start labeling
sprintf(label, "__FR%x_BGN", (unsigned int)script->syntax.curly[pos].index);
l=script->add_str(label);
- script->set_label(l,script->pos,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
@@ -1939,9 +1967,9 @@ const char* parse_syntax(const char* p)
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, script->pos, p);
+ script->set_label(l, VECTOR_LENGTH(script->buf), p);
if( script->parse_options&SCRIPT_USE_LABEL_DB )
- script->label_add(l,script->pos);
+ script->label_add(l, VECTOR_LENGTH(script->buf));
}
else
disp_error_message("parse_syntax:function: function name is invalid", func_name);
@@ -2021,7 +2049,7 @@ const char* parse_syntax(const char* p)
// Form the start of label decision
sprintf(label, "__WL%x_NXT", (unsigned int)script->syntax.curly[script->syntax.curly_count].index);
l=script->add_str(label);
- script->set_label(l,script->pos,p);
+ script->set_label(l, VECTOR_LENGTH(script->buf), p);
// Skip to the end point if the condition is false
sprintf(label, "__WL%x_FIN", (unsigned int)script->syntax.curly[script->syntax.curly_count].index);
@@ -2039,10 +2067,12 @@ const char* parse_syntax(const char* p)
return NULL;
}
-const char* parse_syntax_close(const char *p) {
+static const char *parse_syntax_close(const char *p)
+{
// If (...) for (...) hoge (); as to make sure closed closed once again
int flag;
+ nullpo_retr(NULL, p);
do {
p = script->parse_syntax_close_sub(p,&flag);
} while(flag);
@@ -2052,7 +2082,7 @@ const char* parse_syntax_close(const char *p) {
// Close judgment if, for, while, of do
// flag == 1 : closed
// flag == 0 : not closed
-const char* parse_syntax_close_sub(const char* p,int* flag)
+static const char *parse_syntax_close_sub(const char *p, int *flag)
{
char label[256];
int pos = script->syntax.curly_count - 1;
@@ -2078,7 +2108,7 @@ const char* parse_syntax_close_sub(const char* p,int* flag)
// Put the label of the location
sprintf(label, "__IF%x_%x", (unsigned int)script->syntax.curly[pos].index, (unsigned int)script->syntax.curly[pos].count);
l=script->add_str(label);
- script->set_label(l,script->pos,p);
+ script->set_label(l, VECTOR_LENGTH(script->buf), p);
script->syntax.curly[pos].count++;
p = script->skip_space(p);
@@ -2116,7 +2146,7 @@ const char* parse_syntax_close_sub(const char* p,int* flag)
// Put the label of the final location
sprintf(label, "__IF%x_FIN", (unsigned int)script->syntax.curly[pos].index);
l=script->add_str(label);
- script->set_label(l,script->pos,p);
+ script->set_label(l, VECTOR_LENGTH(script->buf), p);
if(script->syntax.curly[pos].flag == 1) {
// Because the position of the pointer is the same if not else for this
return bp;
@@ -2129,7 +2159,7 @@ const char* parse_syntax_close_sub(const char* p,int* flag)
// (Come here continue) to form the label here
sprintf(label, "__DO%x_NXT", (unsigned int)script->syntax.curly[pos].index);
l=script->add_str(label);
- script->set_label(l,script->pos,p);
+ script->set_label(l, VECTOR_LENGTH(script->buf), p);
}
// Skip to the end point if the condition is false
@@ -2164,7 +2194,7 @@ const char* parse_syntax_close_sub(const char* p,int* flag)
// Form label of the end point conditions
sprintf(label, "__DO%x_FIN", (unsigned int)script->syntax.curly[pos].index);
l=script->add_str(label);
- script->set_label(l,script->pos,p);
+ script->set_label(l, VECTOR_LENGTH(script->buf), p);
p = script->skip_space(p);
if(*p != ';') {
disp_error_message("parse_syntax: need ';'",p);
@@ -2186,7 +2216,7 @@ const char* parse_syntax_close_sub(const char* p,int* flag)
// End for labeling
sprintf(label, "__FR%x_FIN", (unsigned int)script->syntax.curly[pos].index);
l=script->add_str(label);
- script->set_label(l,script->pos,p);
+ script->set_label(l, VECTOR_LENGTH(script->buf), p);
script->syntax.curly_count--;
return p;
} else if(script->syntax.curly[pos].type == TYPE_WHILE) {
@@ -2202,7 +2232,7 @@ const char* parse_syntax_close_sub(const char* p,int* flag)
// End while labeling
sprintf(label, "__WL%x_FIN", (unsigned int)script->syntax.curly[pos].index);
l=script->add_str(label);
- script->set_label(l,script->pos,p);
+ script->set_label(l, VECTOR_LENGTH(script->buf), p);
script->syntax.curly_count--;
return p;
} else if(script->syntax.curly[pos].type == TYPE_USERFUNC) {
@@ -2215,7 +2245,7 @@ const char* parse_syntax_close_sub(const char* p,int* flag)
// Put the label of the location
sprintf(label, "__FN%x_FIN", (unsigned int)script->syntax.curly[pos].index);
l=script->add_str(label);
- script->set_label(l,script->pos,p);
+ script->set_label(l, VECTOR_LENGTH(script->buf), p);
script->syntax.curly_count--;
return p;
} else {
@@ -2225,10 +2255,11 @@ const char* parse_syntax_close_sub(const char* p,int* flag)
}
/// Retrieves the value of a constant.
-bool script_get_constant(const char* name, int* value)
+static bool script_get_constant(const char *name, int *value)
{
int n = script->search_str(name);
+ nullpo_retr(false, value);
if( n == -1 || script->str_data[n].type != C_INT )
{// not found or not a constant
return false;
@@ -2242,11 +2273,11 @@ bool script_get_constant(const char* name, int* value)
}
/// Creates new constant or parameter with given value.
-void script_set_constant(const char *name, int value, bool is_parameter, bool is_deprecated)
+static void script_set_constant(const char *name, int value, bool is_parameter, bool is_deprecated)
{
int n = script->add_str(name);
- if( script->str_data[n].type == C_NOP ) {// new
+ if (script->str_data[n].type == C_NOP) {
script->str_data[n].type = is_parameter ? C_PARAM : C_INT;
script->str_data[n].val = value;
script->str_data[n].deprecated = is_deprecated ? 1 : 0;
@@ -2257,7 +2288,7 @@ void script_set_constant(const char *name, int value, bool is_parameter, bool is
}
}
/* adds data to a existent constant in the database, inserted normally via parse */
-void script_set_constant2(const char *name, int value, bool is_parameter, bool is_deprecated)
+static void script_set_constant2(const char *name, int value, bool is_parameter, bool is_deprecated)
{
int n = script->add_str(name);
@@ -2290,7 +2321,7 @@ void script_set_constant2(const char *name, int value, bool is_parameter, bool i
/**
* Loads the constants database from constants.conf
*/
-void read_constdb(void)
+static void read_constdb(bool reload)
{
struct config_t constants_conf;
char filepath[256];
@@ -2298,7 +2329,7 @@ void read_constdb(void)
struct config_setting_t *t;
int i = 0;
- sprintf(filepath, "%s/constants.conf", map->db_path);
+ safesnprintf(filepath, 256, "%s/constants.conf", map->db_path);
if (!libconfig->load_file(&constants_conf, filepath))
return;
@@ -2309,7 +2340,6 @@ void read_constdb(void)
}
while ((t = libconfig->setting_get_elem(cdb, i++))) {
- bool is_parameter = false;
bool is_deprecated = false;
int value = 0;
const char *name = config_setting_name(t);
@@ -2340,10 +2370,6 @@ void read_constdb(void)
continue;
}
value = i32;
- if (libconfig->setting_lookup_bool(t, "Parameter", &i32)) {
- if (i32 != 0)
- is_parameter = true;
- }
if (libconfig->setting_lookup_bool(t, "Deprecated", &i32)) {
if (i32 != 0)
is_deprecated = true;
@@ -2351,9 +2377,13 @@ void read_constdb(void)
} else {
value = libconfig->setting_get_int(t);
}
- if (is_parameter)
- ShowWarning("read_constdb: Defining parameters in the constants configuration is deprecated and will no longer be possible in a future version. Parameters should be defined in source. (parameter = '%s')\n", name);
- script->set_constant(name, value, is_parameter, is_deprecated);
+
+ if (reload) {
+ int n = script->add_str(name);
+ script->str_data[n].type = C_NOP; // ensures it will be overwritten
+ }
+
+ script->set_constant(name, value, false, is_deprecated);
}
script->constdb_comment(NULL);
libconfig->destroy(&constants_conf);
@@ -2366,12 +2396,12 @@ void read_constdb(void)
*
* @param comment The comment to set (NULL to unset)
*/
-void script_constdb_comment(const char *comment)
+static void script_constdb_comment(const char *comment)
{
(void)comment;
}
-void script_load_parameters(void)
+static void script_load_parameters(void)
{
int i = 0;
struct {
@@ -2391,6 +2421,7 @@ void script_load_parameters(void)
{"SkillPoint", SP_SKILLPOINT},
{"Class", SP_CLASS},
{"Zeny", SP_ZENY},
+ {"BankVault", SP_BANKVAULT},
{"Sex", SP_SEX},
{"NextBaseExp", SP_NEXTBASEEXP},
{"NextJobExp", SP_NEXTJOBEXP},
@@ -2425,7 +2456,7 @@ void script_load_parameters(void)
/*==========================================
* Display emplacement line of script
*------------------------------------------*/
-const char* script_print_line(StringBuf* buf, const char* p, const char* mark, int line)
+static const char *script_print_line(StringBuf *buf, const char *p, const char *mark, int line)
{
int i, mark_pos = 0, tabstop = TAB_SIZE;
if( p == NULL || !p[0] ) return NULL;
@@ -2464,7 +2495,8 @@ const char* script_print_line(StringBuf* buf, const char* p, const char* mark, i
#undef update_tabstop
#define CONTEXTLINES 3
-void script_errorwarning_sub(StringBuf *buf, const char* src, const char* file, int start_line, const char* error_msg, const char* error_pos) {
+static void script_errorwarning_sub(StringBuf *buf, const char *src, const char *file, int start_line, const char *error_msg, const char *error_pos)
+{
// Find the line where the error occurred
int j;
int line = start_line;
@@ -2500,7 +2532,8 @@ void script_errorwarning_sub(StringBuf *buf, const char* src, const char* file,
}
#undef CONTEXTLINES
-void script_error(const char* src, const char* file, int start_line, const char* error_msg, const char* error_pos) {
+static void script_error(const char *src, const char *file, int start_line, const char *error_msg, const char *error_pos)
+{
StringBuf buf;
StrBuf->Init(&buf);
@@ -2512,7 +2545,8 @@ void script_error(const char* src, const char* file, int start_line, const char*
StrBuf->Destroy(&buf);
}
-void script_warning(const char* src, const char* file, int start_line, const char* error_msg, const char* error_pos) {
+static void script_warning(const char *src, const char *file, int start_line, const char *error_msg, const char *error_pos)
+{
StringBuf buf;
StrBuf->Init(&buf);
@@ -2526,7 +2560,8 @@ void script_warning(const char* src, const char* file, int start_line, const cha
/*==========================================
* Analysis of the script
*------------------------------------------*/
-struct script_code* parse_script(const char *src,const char *file,int line,int options, int *retval) {
+static struct script_code *parse_script(const char *src, const char *file, int line, int options, int *retval)
+{
const char *p,*tmpp;
int i;
struct script_code* code = NULL;
@@ -2544,9 +2579,6 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o
script->parse_cleanup_timer_id = timer->add(timer->gettick() + 10, script->parse_cleanup_timer, 0, 0);
}
- if( script->syntax.strings ) /* used only when generating translation file */
- db_destroy(script->syntax.strings);
-
memset(&script->syntax,0,sizeof(script->syntax));
script->syntax.last_func = -1;/* as valid values are >= 0 */
if( script->parser_current_npc_name ) {
@@ -2556,11 +2588,7 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o
script->syntax.translation_db = strdb_get(script->translation_db, script->parser_current_npc_name);
}
- if( !script->buf ) {
- script->buf = (unsigned char *)aMalloc(SCRIPT_BLOCK_SIZE*sizeof(unsigned char));
- script->size = SCRIPT_BLOCK_SIZE;
- }
- script->pos=0;
+ VECTOR_TRUNCATE(script->buf);
script->parse_nextline(true, NULL);
// who called parse_script is responsible for clearing the database after using it, but just in case... lets clear it here
@@ -2574,7 +2602,7 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o
if( script->error_report )
script->error(src,file,line,script->error_msg,script->error_pos);
aFree( script->error_msg );
- script->pos = 0;
+ VECTOR_TRUNCATE(script->buf);
for(i=LABEL_START;i<script->str_num;i++)
if(script->str_data[i].type == C_NOP) script->str_data[i].type = C_NAME;
for(i=0; i<size; i++)
@@ -2594,9 +2622,9 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o
p=script->skip_space(p);
if( options&SCRIPT_IGNORE_EXTERNAL_BRACKETS )
{// does not require brackets around the script
- if( *p == '\0' && !(options&SCRIPT_RETURN_EMPTY_SCRIPT) )
- {// empty script and can return NULL
- script->pos = 0;
+ if (*p == '\0' && !(options&SCRIPT_RETURN_EMPTY_SCRIPT)) {
+ // empty script and can return NULL
+ VECTOR_TRUNCATE(script->buf);
#ifdef ENABLE_CASE_CHECK
script->local_casecheck.clear();
script->parser_current_src = NULL;
@@ -2614,9 +2642,9 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o
if (retval) *retval = EXIT_FAILURE;
}
p = script->skip_space(p+1);
- if( *p == '}' && !(options&SCRIPT_RETURN_EMPTY_SCRIPT) )
- {// empty script and can return NULL
- script->pos = 0;
+ if (*p == '}' && !(options&SCRIPT_RETURN_EMPTY_SCRIPT)) {
+ // empty script and can return NULL
+ VECTOR_TRUNCATE(script->buf);
#ifdef ENABLE_CASE_CHECK
script->local_casecheck.clear();
script->parser_current_src = NULL;
@@ -2648,9 +2676,9 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o
tmpp=script->skip_space(script->skip_word(p));
if(*tmpp==':' && !(strncmp(p,"default:",8) == 0 && p + 7 == tmpp)) {
i=script->add_word(p);
- script->set_label(i,script->pos,p);
+ script->set_label(i, VECTOR_LENGTH(script->buf), p);
if( script->parse_options&SCRIPT_USE_LABEL_DB )
- script->label_add(i,script->pos);
+ script->label_add(i, VECTOR_LENGTH(script->buf));
p=tmpp+1;
p=script->skip_space(p);
continue;
@@ -2672,8 +2700,8 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o
script->str_data[i].type=C_NAME;
script->str_data[i].label=i;
for (j = script->str_data[i].backpatch; j >= 0 && j != 0x00ffffff; ) {
- int next = GETVALUE(script->buf,j);
- SETVALUE(script->buf,j,i);
+ int next = GETVALUE(&script->buf, j);
+ SETVALUE(&script->buf, j, i);
j = next;
}
} else if(script->str_data[i].type == C_USERFUNC) {
@@ -2690,37 +2718,39 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o
}
#ifdef SCRIPT_DEBUG_DISP
- for(i=0;i<script->pos;i++) {
- if((i&15)==0) ShowMessage("%04x : ",i);
- ShowMessage("%02x ",script->buf[i]);
- if((i&15)==15) ShowMessage("\n");
+ for (i = 0; i < VECTOR_LENGTH(script->buf); i++) {
+ if ((i&15) == 0)
+ ShowMessage("%04x : ",i);
+ ShowMessage("%02x ", VECTOR_INDEX(script->buf, i));
+ if ((i&15) == 15)
+ ShowMessage("\n");
}
ShowMessage("\n");
#endif
#ifdef SCRIPT_DEBUG_DISASM
i = 0;
- while(i < script->pos) {
- int j = i;
- c_op op = script->get_com(script->buf,&i);
+ while (i < VECTOR_LENGTH(script->buf)) {
+ c_op op = script->get_com(&script->buf, &i);
+ int j = i; // Note: i is modified in the line above.
ShowMessage("%06x %s", i, script->op2name(op));
- j = i;
- switch(op) {
+
+ switch (op) {
case C_INT:
- ShowMessage(" %d", script->get_num(script->buf,&i));
+ ShowMessage(" %d", script->get_num(&script->buf, &i));
break;
case C_POS:
- ShowMessage(" 0x%06x", *(int*)(script->buf+i)&0xffffff);
+ ShowMessage(" 0x%06x", *(int*)(&VECTOR_INDEX(script->buf, i))&0xffffff);
i += 3;
break;
case C_NAME:
- j = (*(int*)(script->buf+i)&0xffffff);
+ j = (*(int*)(&VECTOR_INDEX(script->buf, i))&0xffffff);
ShowMessage(" %s", ( j == 0xffffff ) ? "?? unknown ??" : script->get_str(j));
i += 3;
break;
case C_STR:
- j = (int)strlen((char*)script->buf + i);
- ShowMessage(" %s", script->buf + i);
+ j = (int)strlen((char*)&VECTOR_INDEX(script->buf, i));
+ ShowMessage(" %s", &VECTOR_INDEX(script->buf, i));
i += j+1;
break;
}
@@ -2729,9 +2759,9 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o
#endif
CREATE(code,struct script_code,1);
- code->script_buf = (unsigned char *)aMalloc(script->pos*sizeof(unsigned char));
- memcpy(code->script_buf, script->buf, script->pos);
- code->script_size = script->pos;
+ VECTOR_INIT(code->script_buf);
+ VECTOR_ENSURE(code->script_buf, VECTOR_LENGTH(script->buf), 1);
+ VECTOR_PUSHARRAY(code->script_buf, VECTOR_DATA(script->buf), VECTOR_LENGTH(script->buf));
code->local.vars = NULL;
code->local.arrays = NULL;
#ifdef ENABLE_CASE_CHECK
@@ -2745,9 +2775,10 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o
/// Returns the player attached to this script, identified by the rid.
/// If there is no player attached, the script is terminated.
-struct map_session_data *script_rid2sd(struct script_state *st)
+static struct map_session_data *script_rid2sd(struct script_state *st)
{
struct map_session_data *sd;
+ nullpo_retr(NULL, st);
if( !( sd = map->id2sd(st->rid) ) ) {
ShowError("script_rid2sd: fatal error ! player not attached!\n");
script->reportfunc(st);
@@ -2757,7 +2788,7 @@ struct map_session_data *script_rid2sd(struct script_state *st)
return sd;
}
-struct map_session_data *script_id2sd(struct script_state *st, int account_id)
+static struct map_session_data *script_id2sd(struct script_state *st, int account_id)
{
struct map_session_data *sd;
if ((sd = map->id2sd(account_id)) == NULL) {
@@ -2768,7 +2799,7 @@ struct map_session_data *script_id2sd(struct script_state *st, int account_id)
return sd;
}
-struct map_session_data *script_charid2sd(struct script_state *st, int char_id)
+static struct map_session_data *script_charid2sd(struct script_state *st, int char_id)
{
struct map_session_data *sd;
if ((sd = map->charid2sd(char_id)) == NULL) {
@@ -2779,10 +2810,10 @@ struct map_session_data *script_charid2sd(struct script_state *st, int char_id)
return sd;
}
-struct map_session_data *script_nick2sd(struct script_state *st, const char *name)
+static struct map_session_data *script_nick2sd(struct script_state *st, const char *name)
{
struct map_session_data *sd;
- if ((sd = map->nick2sd(name)) == NULL) {
+ if ((sd = map->nick2sd(name, false)) == NULL) {
ShowWarning("script_nick2sd: Player name '%s' not found!\n", name);
script->reportfunc(st);
script->reportsrc(st);
@@ -2790,14 +2821,26 @@ struct map_session_data *script_nick2sd(struct script_state *st, const char *nam
return sd;
}
-char *get_val_npcscope_str(struct script_state* st, struct reg_db *n, struct script_data* data) {
+static char *get_val_npcscope_str(struct script_state *st, struct reg_db *n, struct script_data *data)
+{
if (n)
return (char*)i64db_get(n->vars, reference_getuid(data));
else
return NULL;
}
-char *get_val_instance_str(struct script_state* st, const char* name, struct script_data* data) {
+static char *get_val_pc_ref_str(struct script_state *st, struct reg_db *n, struct script_data *data)
+{
+ struct script_reg_str *p = NULL;
+ nullpo_retr(NULL, n);
+
+ p = i64db_get(n->vars, reference_getuid(data));
+ return p ? p->value : NULL;
+}
+
+static char *get_val_instance_str(struct script_state *st, const char *name, struct script_data *data)
+{
+ nullpo_retr(NULL, st);
if (st->instance_id >= 0) {
return (char*)i64db_get(instance->list[st->instance_id].regs.vars, reference_getuid(data));
} else {
@@ -2806,14 +2849,25 @@ char *get_val_instance_str(struct script_state* st, const char* name, struct scr
}
}
-int get_val_npcscope_num(struct script_state* st, struct reg_db *n, struct script_data* data) {
+static int get_val_npcscope_num(struct script_state *st, struct reg_db *n, struct script_data *data)
+{
if (n)
return (int)i64db_iget(n->vars, reference_getuid(data));
else
return 0;
}
-int get_val_instance_num(struct script_state* st, const char* name, struct script_data* data) {
+static int get_val_pc_ref_num(struct script_state *st, struct reg_db *n, struct script_data *data)
+{
+ struct script_reg_num *p = NULL;
+ nullpo_retr(0, n);
+
+ p = i64db_get(n->vars, reference_getuid(data));
+ return p ? p->value : 0;
+}
+
+static int get_val_instance_num(struct script_state *st, const char *name, struct script_data *data)
+{
if (st->instance_id >= 0)
return (int)i64db_iget(instance->list[st->instance_id].regs.vars, reference_getuid(data));
else {
@@ -2829,13 +2883,14 @@ int get_val_instance_num(struct script_state* st, const char* name, struct scrip
* @param data[in,out] variable/constant.
* @return pointer to data, for convenience.
*/
-struct script_data *get_val(struct script_state* st, struct script_data* data) {
+static struct script_data *get_val(struct script_state *st, struct script_data *data)
+{
const char* name;
char prefix;
char postfix;
struct map_session_data *sd = NULL;
- if( !data_isreference(data) )
+ if (!data_isreference(data))
return data;// not a variable/constant
name = reference_getname(data);
@@ -2849,11 +2904,10 @@ struct script_data *get_val(struct script_state* st, struct script_data* data) {
return data;
}
- //##TODO use reference_tovariable(data) when it's confirmed that it works [FlavioJS]
- if( !reference_toconstant(data) && not_server_variable(prefix) ) {
+ if (((reference_tovariable(data) && not_server_variable(prefix)) || reference_toparam(data)) && reference_getref(data) == NULL) {
sd = script->rid2sd(st);
- if( sd == NULL ) {// needs player attached
- if( postfix == '$' ) {// string variable
+ if (sd == NULL) {// needs player attached
+ if (postfix == '$') {// string variable
ShowWarning("script_get_val: cannot access player variable '%s', defaulting to \"\"\n", name);
data->type = C_CONSTSTR;
data->u.str = "";
@@ -2871,32 +2925,44 @@ struct script_data *get_val(struct script_state* st, struct script_data* data) {
const char *str = NULL;
switch (prefix) {
- case '@':
+ case '@':
+ if (data->ref) {
+ str = script->get_val_ref_str(st, data->ref, data);
+ } else {
str = pc->readregstr(sd, data->u.num);
- break;
- case '$':
- str = mapreg->readregstr(data->u.num);
- break;
- case '#':
- if (name[1] == '#')
- str = pc_readaccountreg2str(sd, data->u.num);// global
- else
- str = pc_readaccountregstr(sd, data->u.num);// local
- break;
- case '.':
- if (data->ref)
- str = script->get_val_ref_str(st, data->ref, data);
- else if (name[1] == '@')
- str = script->get_val_scope_str(st, &st->stack->scope, data);
- else
- str = script->get_val_npc_str(st, &st->script->local, data);
- break;
- case '\'':
- str = script->get_val_instance_str(st, name, data);
- break;
- default:
+ }
+ break;
+ case '$':
+ str = mapreg->readregstr(data->u.num);
+ break;
+ case '#':
+ if (data->ref) {
+ str = script->get_val_pc_ref_str(st, data->ref, data);
+ } else if (name[1] == '#') {
+ str = pc_readaccountreg2str(sd, data->u.num);// global
+ } else {
+ str = pc_readaccountregstr(sd, data->u.num);// local
+ }
+ break;
+ case '.':
+ if (data->ref) {
+ str = script->get_val_ref_str(st, data->ref, data);
+ } else if (name[1] == '@') {
+ str = script->get_val_scope_str(st, &st->stack->scope, data);
+ } else {
+ str = script->get_val_npc_str(st, &st->script->local, data);
+ }
+ break;
+ case '\'':
+ str = script->get_val_instance_str(st, name, data);
+ break;
+ default:
+ if (data->ref) {
+ str = script->get_val_pc_ref_str(st, data->ref, data);
+ } else {
str = pc_readglobalreg_str(sd, data->u.num);
- break;
+ }
+ break;
}
if (str == NULL || str[0] == '\0') {
@@ -2916,36 +2982,48 @@ struct script_data *get_val(struct script_state* st, struct script_data* data) {
data->u.num = reference_getconstant(data);
} else if( reference_toparam(data) ) {
data->u.num = pc->readparam(sd, reference_getparamtype(data));
- } else
- switch( prefix ) {
- case '@':
+ } else {
+ switch (prefix) {
+ case '@':
+ if (data->ref) {
+ data->u.num = script->get_val_ref_num(st, data->ref, data);
+ } else {
data->u.num = pc->readreg(sd, data->u.num);
- break;
- case '$':
- data->u.num = mapreg->readreg(data->u.num);
- break;
- case '#':
- if( name[1] == '#' )
- data->u.num = pc_readaccountreg2(sd, data->u.num);// global
- else
- data->u.num = pc_readaccountreg(sd, data->u.num);// local
- break;
- case '.':
- if (data->ref)
- data->u.num = script->get_val_ref_num(st, data->ref, data);
- else if (name[1] == '@')
- data->u.num = script->get_val_scope_num(st, &st->stack->scope, data);
- else
- data->u.num = script->get_val_npc_num(st, &st->script->local, data);
- break;
- case '\'':
- data->u.num = script->get_val_instance_num(st, name, data);
- break;
- default:
+ }
+ break;
+ case '$':
+ data->u.num = mapreg->readreg(data->u.num);
+ break;
+ case '#':
+ if (data->ref) {
+ data->u.num = script->get_val_pc_ref_num(st, data->ref, data);
+ } else if (name[1] == '#') {
+ data->u.num = pc_readaccountreg2(sd, data->u.num);// global
+ } else {
+ data->u.num = pc_readaccountreg(sd, data->u.num);// local
+ }
+ break;
+ case '.':
+ if (data->ref) {
+ data->u.num = script->get_val_ref_num(st, data->ref, data);
+ } else if (name[1] == '@') {
+ data->u.num = script->get_val_scope_num(st, &st->stack->scope, data);
+ } else {
+ data->u.num = script->get_val_npc_num(st, &st->script->local, data);
+ }
+ break;
+ case '\'':
+ data->u.num = script->get_val_instance_num(st, name, data);
+ break;
+ default:
+ if (data->ref) {
+ data->u.num = script->get_val_pc_ref_num(st, data->ref, data);
+ } else {
data->u.num = pc_readglobalreg(sd, data->u.num);
- break;
+ }
+ break;
}
-
+ }
}
data->ref = NULL;
@@ -2962,14 +3040,19 @@ struct script_data *get_val(struct script_state* st, struct script_data* data) {
* @param ref[in] the container to look up the reference into.
* @return the retrieved value of the reference.
*/
-const void *get_val2(struct script_state *st, int64 uid, struct reg_db *ref)
+static const void *get_val2(struct script_state *st, int64 uid, struct reg_db *ref)
{
struct script_data* data;
+ nullpo_retr(NULL, st);
script->push_val(st->stack, C_NAME, uid, ref);
data = script_getdatatop(st, -1);
script->get_val(st, data);
if (data->type == C_INT) // u.num is int32 because it comes from script->get_val
return (const void *)h64BPTRSIZE((int32)data->u.num);
+ else if (data_isreference(data) && reference_toconstant(data))
+ return (const void *)h64BPTRSIZE((int32)reference_getconstant(data));
+ else if (data_isreference(data) && reference_toparam(data))
+ return (const void *)h64BPTRSIZE((int32)reference_getparamtype(data));
else
return (const void *)h64BPTRSIZE(data->u.str);
}
@@ -2977,16 +3060,21 @@ const void *get_val2(struct script_state *st, int64 uid, struct reg_db *ref)
* Because, currently, array members with key 0 are indifferenciable from normal variables, we should ensure its actually in
* Will be gone as soon as undefined var feature is implemented
**/
-void script_array_ensure_zero(struct script_state *st, struct map_session_data *sd, int64 uid, struct reg_db *ref) {
+static void script_array_ensure_zero(struct script_state *st, struct map_session_data *sd, int64 uid, struct reg_db *ref)
+{
const char *name = script->get_str(script_getvarid(uid));
- // is here st can be null pointer and st->rid is wrong?
- struct reg_db *src = script->array_src(st, sd ? sd : st->rid ? map->id2sd(st->rid) : NULL, name, ref);
+ struct reg_db *src = NULL;
bool insert = false;
- if (sd && !st) {
- /* when sd comes, st isn't available */
+ if (st == NULL) {
+ // Special case with no st available, only sd
+ nullpo_retv(sd);
+ src = script->array_src(NULL, sd, name, ref);
insert = true;
} else {
+ if (sd == NULL && st->rid != 0)
+ sd = map->id2sd(st->rid); // Retrieve the missing sd
+ src = script->array_src(st, sd, name, ref);
if( is_string_variable(name) ) {
const char *str = script->get_val2(st, uid, ref);
if (str != NULL && *str != '\0')
@@ -3020,7 +3108,8 @@ void script_array_ensure_zero(struct script_state *st, struct map_session_data *
/**
* Returns array size by ID
**/
-unsigned int script_array_size(struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref) {
+static unsigned int script_array_size(struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref)
+{
struct script_array *sa = NULL;
struct reg_db *src = script->array_src(st, sd, name, ref);
@@ -3032,7 +3121,8 @@ unsigned int script_array_size(struct script_state *st, struct map_session_data
/**
* Returns array's highest key (for that awful getarraysize implementation that doesn't really gets the array size)
**/
-unsigned int script_array_highest_key(struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref) {
+static unsigned int script_array_highest_key(struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref)
+{
struct script_array *sa = NULL;
struct reg_db *src = script->array_src(st, sd, name, ref);
@@ -3053,7 +3143,7 @@ unsigned int script_array_highest_key(struct script_state *st, struct map_sessio
}
return 0;
}
-int script_free_array_db(union DBKey key, struct DBData *data, va_list ap)
+static int script_free_array_db(union DBKey key, struct DBData *data, va_list ap)
{
struct script_array *sa = DB->data2ptr(data);
aFree(sa->members);
@@ -3063,7 +3153,10 @@ int script_free_array_db(union DBKey key, struct DBData *data, va_list ap)
/**
* Clears script_array and removes it from script->array_db
**/
-void script_array_delete(struct reg_db *src, struct script_array *sa) {
+static void script_array_delete(struct reg_db *src, struct script_array *sa)
+{
+ nullpo_retv(src);
+ nullpo_retv(sa);
aFree(sa->members);
idb_remove(src->arrays, sa->id);
ers_free(script->array_ers, sa);
@@ -3073,9 +3166,11 @@ void script_array_delete(struct reg_db *src, struct script_array *sa) {
*
* @param idx the index of the member in script_array struct list, not of the actual array member
**/
-void script_array_remove_member(struct reg_db *src, struct script_array *sa, unsigned int idx) {
+static void script_array_remove_member(struct reg_db *src, struct script_array *sa, unsigned int idx)
+{
unsigned int i, cursor;
+ nullpo_retv(sa);
/* its the only member left, no need to do anything other than delete the array data */
if( sa->size == 1 ) {
script->array_delete(src,sa);
@@ -3099,44 +3194,56 @@ void script_array_remove_member(struct reg_db *src, struct script_array *sa, uns
*
* @param idx the index of the array member being inserted
**/
-void script_array_add_member(struct script_array *sa, unsigned int idx) {
+static void script_array_add_member(struct script_array *sa, unsigned int idx)
+{
+ nullpo_retv(sa);
RECREATE(sa->members, unsigned int, ++sa->size);
-
sa->members[sa->size - 1] = idx;
}
/**
* Obtains the source of the array database for this type and scenario
* Initializes such database when not yet initialized.
**/
-struct reg_db *script_array_src(struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref) {
+static struct reg_db *script_array_src(struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref)
+{
struct reg_db *src = NULL;
+ nullpo_retr(NULL, name);
- switch( name[0] ) {
+ switch (name[0]) {
/* from player */
- default: /* char reg */
- case '@':/* temp char reg */
- case '#':/* account reg */
+ default: /* char reg */
+ case '@':/* temp char reg */
+ case '#':/* account reg */
+ if (ref != NULL) {
+ src = ref;
+ } else {
+ nullpo_retr(NULL, sd);
src = &sd->regs;
- break;
- case '$':/* map reg */
- src = &mapreg->regs;
- break;
- case '.':/* npc/script */
- if( ref )
- src = ref;
- else
- src = (name[1] == '@') ? &st->stack->scope : &st->script->local;
- break;
- case '\'':/* instance */
- if( st->instance_id >= 0 ) {
- src = &instance->list[st->instance_id].regs;
- }
- break;
+ }
+ break;
+ case '$':/* map reg */
+ src = &mapreg->regs;
+ break;
+ case '.':/* npc/script */
+ if (ref != NULL) {
+ src = ref;
+ } else {
+ nullpo_retr(NULL, st);
+ src = (name[1] == '@') ? &st->stack->scope : &st->script->local;
+ }
+ break;
+ case '\'':/* instance */
+ nullpo_retr(NULL, st);
+ if (st->instance_id >= 0) {
+ src = &instance->list[st->instance_id].regs;
+ }
+ break;
}
- if( src ) {
- if( !src->arrays )
+ if (src) {
+ if (!src->arrays) {
src->arrays = idb_alloc(DB_OPT_BASE);
+ }
return src;
}
return NULL;
@@ -3149,11 +3256,13 @@ struct reg_db *script_array_src(struct script_state *st, struct map_session_data
* @param num[in] Variable ID
* @param empty[in] Whether the modified member is empty (needs to be removed)
**/
-void script_array_update(struct reg_db *src, int64 num, bool empty) {
+static void script_array_update(struct reg_db *src, int64 num, bool empty)
+{
struct script_array *sa = NULL;
int id = script_getvarid(num);
unsigned int index = script_getvaridx(num);
+ nullpo_retv(src);
if (!src->arrays) {
src->arrays = idb_alloc(DB_OPT_BASE);
} else {
@@ -3189,10 +3298,11 @@ void script_array_update(struct reg_db *src, int64 num, bool empty) {
}
}
-void set_reg_npcscope_str(struct script_state* st, struct reg_db *n, int64 num, const char* name, const char *str)
+static void set_reg_npcscope_str(struct script_state *st, struct reg_db *n, int64 num, const char *name, const char *str)
{
if (n)
{
+ nullpo_retv(str);
if (str[0]) {
i64db_put(n->vars, num, aStrdup(str));
if (script_getvaridx(num))
@@ -3205,7 +3315,33 @@ void set_reg_npcscope_str(struct script_state* st, struct reg_db *n, int64 num,
}
}
-void set_reg_npcscope_num(struct script_state* st, struct reg_db *n, int64 num, const char* name, int val)
+static void set_reg_pc_ref_str(struct script_state *st, struct reg_db *n, int64 num, const char *name, const char *str)
+{
+ struct DBIterator *iter = db_iterator(map->pc_db);
+
+ for (struct map_session_data *sd = dbi_first(iter); dbi_exists(iter); sd = dbi_next(iter)) {
+ if (sd != NULL && n == &sd->regs) {
+ pc->setregistry_str(sd, num, str);
+ break;
+ }
+ }
+ dbi_destroy(iter);
+}
+
+static void set_reg_pc_ref_num(struct script_state *st, struct reg_db *n, int64 num, const char *name, int val)
+{
+ struct DBIterator *iter = db_iterator(map->pc_db);
+
+ for (struct map_session_data *sd = dbi_first(iter); dbi_exists(iter); sd = dbi_next(iter)) {
+ if (sd != NULL && n == &sd->regs) {
+ pc->setregistry(sd, num, val);
+ break;
+ }
+ }
+ dbi_destroy(iter);
+}
+
+static void set_reg_npcscope_num(struct script_state *st, struct reg_db *n, int64 num, const char *name, int val)
{
if (n) {
if (val != 0) {
@@ -3220,8 +3356,9 @@ void set_reg_npcscope_num(struct script_state* st, struct reg_db *n, int64 num,
}
}
-void set_reg_instance_str(struct script_state* st, int64 num, const char* name, const char *str)
+static void set_reg_instance_str(struct script_state *st, int64 num, const char *name, const char *str)
{
+ nullpo_retv(st);
if (st->instance_id >= 0) {
if (str[0]) {
i64db_put(instance->list[st->instance_id].regs.vars, num, aStrdup(str));
@@ -3238,8 +3375,9 @@ void set_reg_instance_str(struct script_state* st, int64 num, const char* name,
}
}
-void set_reg_instance_num(struct script_state* st, int64 num, const char* name, int val)
+static void set_reg_instance_num(struct script_state *st, int64 num, const char *name, int val)
{
+ nullpo_retv(st);
if (st->instance_id >= 0) {
if (val != 0) {
i64db_iput(instance->list[st->instance_id].regs.vars, num, val);
@@ -3270,59 +3408,93 @@ void set_reg_instance_num(struct script_state* st, int64 num, const char* name,
*
* TODO: return values are screwed up, have been for some time (reaad: years), e.g. some functions return 1 failure and success.
*------------------------------------------*/
-int set_reg(struct script_state *st, struct map_session_data *sd, int64 num, const char *name, const void *value, struct reg_db *ref)
+static int set_reg(struct script_state *st, struct map_session_data *sd, int64 num, const char *name, const void *value, struct reg_db *ref)
{
- char prefix = name[0];
+ char prefix;
+ nullpo_ret(name);
+ prefix = name[0];
+
+ if (script->str_data[script_getvarid(num)].type != C_NAME && script->str_data[script_getvarid(num)].type != C_PARAM) {
+ ShowError("script:set_reg: not a variable! '%s'\n", name);
+
+ // to avoid this don't do script->add_str(") without setting its type.
+ // either use script->add_variable() or manually set the type
+
+ if (st) {
+ script->reportsrc(st);
+ st->state = END;
+ }
+ return 0;
+ }
if (strlen(name) > SCRIPT_VARNAME_LENGTH) {
ShowError("script:set_reg: variable name too long. '%s'\n", name);
- script->reportsrc(st);
- st->state = END;
+ if (st) {
+ script->reportsrc(st);
+ st->state = END;
+ }
return 0;
}
- if( is_string_variable(name) ) {// string variable
+ if (is_string_variable(name)) {// string variable
const char *str = (const char*)value;
switch (prefix) {
- case '@':
+ case '@':
+ if (ref) {
+ script->set_reg_ref_str(st, ref, num, name, str);
+ } else {
pc->setregstr(sd, num, str);
- return 1;
- case '$':
- return mapreg->setregstr(num, str);
- case '#':
- return (name[1] == '#') ?
- pc_setaccountreg2str(sd, num, str) :
- pc_setaccountregstr(sd, num, str);
- case '.':
- if (ref)
- script->set_reg_ref_str(st, ref, num, name, str);
- else if (name[1] == '@')
- script->set_reg_scope_str(st, &st->stack->scope, num, name, str);
- else
- script->set_reg_npc_str(st, &st->script->local, num, name, str);
- return 1;
- case '\'':
- set_reg_instance_str(st, num, name, str);
- return 1;
- default:
- return pc_setglobalreg_str(sd, num, str);
+ }
+ return 1;
+ case '$':
+ mapreg->setregstr(num, str);
+ return 1;
+ case '#':
+ if (ref) {
+ script->set_reg_pc_ref_str(st, ref, num, name, str);
+ } else if (name[1] == '#') {
+ pc_setaccountreg2str(sd, num, str);
+ } else {
+ pc_setaccountregstr(sd, num, str);
+ }
+ return 1;
+ case '.':
+ if (ref) {
+ script->set_reg_ref_str(st, ref, num, name, str);
+ } else if (name[1] == '@') {
+ script->set_reg_scope_str(st, &st->stack->scope, num, name, str);
+ } else {
+ script->set_reg_npc_str(st, &st->script->local, num, name, str);
+ }
+ return 1;
+ case '\'':
+ set_reg_instance_str(st, num, name, str);
+ return 1;
+ default:
+ if (ref) {
+ script->set_reg_pc_ref_str(st, ref, num, name, str);
+ } else {
+ pc_setglobalreg_str(sd, num, str);
+ }
+ return 1;
}
} else {// integer variable
// FIXME: This isn't safe, in 32bits systems we're converting a 64bit pointer
// to a 32bit int, this will lead to overflows! [Panikon]
int val = (int)h64BPTRSIZE(value);
- if(script->str_data[script_getvarid(num)].type == C_PARAM) {
- if( pc->setparam(sd, script->str_data[script_getvarid(num)].val, val) == 0 ) {
- if( st != NULL ) {
+ if (script->str_data[script_getvarid(num)].type == C_PARAM) {
+ if (pc->setparam(sd, script->str_data[script_getvarid(num)].val, val) == 0) {
+ if (st != NULL) {
ShowError("script:set_reg: failed to set param '%s' to %d.\n", name, val);
script->reportsrc(st);
// Instead of just stop the script execution we let the character close
// the window if it was open.
st->state = (sd->state.dialog) ? CLOSE : END;
- if( st->state == CLOSE )
+ if(st->state == CLOSE) {
clif->scriptclose(sd, st->oid);
+ }
}
return 0;
}
@@ -3330,44 +3502,74 @@ int set_reg(struct script_state *st, struct map_session_data *sd, int64 num, con
}
switch (prefix) {
- case '@':
+ case '@':
+ if (ref) {
+ script->set_reg_ref_num(st, ref, num, name, val);
+ } else {
pc->setreg(sd, num, val);
- return 1;
- case '$':
- return mapreg->setreg(num, val);
- case '#':
- return (name[1] == '#') ?
- pc_setaccountreg2(sd, num, val) :
- pc_setaccountreg(sd, num, val);
- case '.':
- if (ref)
- script->set_reg_ref_num(st, ref, num, name, val);
- else if (name[1] == '@')
- script->set_reg_scope_num(st, &st->stack->scope, num, name, val);
- else
- script->set_reg_npc_num(st, &st->script->local, num, name, val);
- return 1;
- case '\'':
- set_reg_instance_num(st, num, name, val);
- return 1;
- default:
- return pc_setglobalreg(sd, num, val);
+ }
+ return 1;
+ case '$':
+ mapreg->setreg(num, val);
+ return 1;
+ case '#':
+ if (ref) {
+ script->set_reg_pc_ref_num(st, ref, num, name, val);
+ } else if (name[1] == '#') {
+ pc_setaccountreg2(sd, num, val);
+ } else {
+ pc_setaccountreg(sd, num, val);
+ }
+ return 1;
+ case '.':
+ if (ref) {
+ script->set_reg_ref_num(st, ref, num, name, val);
+ } else if (name[1] == '@') {
+ script->set_reg_scope_num(st, &st->stack->scope, num, name, val);
+ } else {
+ script->set_reg_npc_num(st, &st->script->local, num, name, val);
+ }
+ return 1;
+ case '\'':
+ set_reg_instance_num(st, num, name, val);
+ return 1;
+ default:
+ if (ref) {
+ script->set_reg_pc_ref_num(st, ref, num, name, val);
+ } else {
+ pc_setglobalreg(sd, num, val);
+ }
+ return 1;
}
}
}
-int set_var(struct map_session_data *sd, char *name, void *val)
+static int set_var(struct map_session_data *sd, char *name, void *val)
{
- return script->set_reg(NULL, sd, reference_uid(script->add_str(name),0), name, val, NULL);
+ int key = script->add_variable(name);
+
+ if (script->str_data[key].type != C_NAME) {
+ ShowError("script:setd_sub: `%s` is already used by something that is not a variable.\n", name);
+ return -1;
+ }
+
+ return script->set_reg(NULL, sd, reference_uid(key, 0), name, val, NULL);
}
-void setd_sub(struct script_state *st, struct map_session_data *sd, const char *varname, int elem, const void *value, struct reg_db *ref)
+static void setd_sub(struct script_state *st, struct map_session_data *sd, const char *varname, int elem, const void *value, struct reg_db *ref)
{
- script->set_reg(st, sd, reference_uid(script->add_str(varname),elem), varname, value, ref);
+ int key = script->add_variable(varname);
+
+ if (script->str_data[key].type != C_NAME) {
+ ShowError("script:setd_sub: `%s` is already used by something that is not a variable.\n", varname);
+ return;
+ }
+
+ script->set_reg(st, sd, reference_uid(key, elem), varname, value, ref);
}
/// Converts the data to a string
-const char *conv_str(struct script_state *st, struct script_data* data)
+static const char *conv_str(struct script_state *st, struct script_data *data)
{
script->get_val(st, data);
if (data_isstring(data)) {
@@ -3401,7 +3603,7 @@ const char *conv_str(struct script_state *st, struct script_data* data)
}
/// Converts the data to an int
-int conv_num(struct script_state *st, struct script_data *data)
+static int conv_num(struct script_state *st, struct script_data *data)
{
long num;
@@ -3459,7 +3661,9 @@ int conv_num(struct script_state *st, struct script_data *data)
//
/// Increases the size of the stack
-void stack_expand(struct script_stack* stack) {
+static void stack_expand(struct script_stack *stack)
+{
+ nullpo_retv(stack);
stack->sp_max += 64;
stack->stack_data = (struct script_data*)aRealloc(stack->stack_data,
stack->sp_max * sizeof(stack->stack_data[0]) );
@@ -3468,7 +3672,9 @@ void stack_expand(struct script_stack* stack) {
}
/// Pushes a value into the stack (with reference)
-struct script_data* push_val(struct script_stack* stack, enum c_op type, int64 val, struct reg_db *ref) {
+static struct script_data *push_val(struct script_stack *stack, enum c_op type, int64 val, struct reg_db *ref)
+{
+ nullpo_retr(NULL, stack);
if( stack->sp >= stack->sp_max )
script->stack_expand(stack);
stack->stack_data[stack->sp].type = type;
@@ -3479,8 +3685,9 @@ struct script_data* push_val(struct script_stack* stack, enum c_op type, int64 v
}
/// Pushes a string into the stack
-struct script_data *push_str(struct script_stack *stack, char *str)
+static struct script_data *push_str(struct script_stack *stack, char *str)
{
+ nullpo_retr(NULL, stack);
if( stack->sp >= stack->sp_max )
script->stack_expand(stack);
stack->stack_data[stack->sp].type = C_STR;
@@ -3491,8 +3698,9 @@ struct script_data *push_str(struct script_stack *stack, char *str)
}
/// Pushes a constant string into the stack
-struct script_data *push_conststr(struct script_stack *stack, const char *str)
+static struct script_data *push_conststr(struct script_stack *stack, const char *str)
{
+ nullpo_retr(NULL, stack);
if( stack->sp >= stack->sp_max )
script->stack_expand(stack);
stack->stack_data[stack->sp].type = C_CONSTSTR;
@@ -3503,7 +3711,9 @@ struct script_data *push_conststr(struct script_stack *stack, const char *str)
}
/// Pushes a retinfo into the stack
-struct script_data* push_retinfo(struct script_stack* stack, struct script_retinfo* ri, struct reg_db *ref) {
+static struct script_data *push_retinfo(struct script_stack *stack, struct script_retinfo *ri, struct reg_db *ref)
+{
+ nullpo_retr(NULL, stack);
if( stack->sp >= stack->sp_max )
script->stack_expand(stack);
stack->stack_data[stack->sp].type = C_RETINFO;
@@ -3514,7 +3724,9 @@ struct script_data* push_retinfo(struct script_stack* stack, struct script_retin
}
/// Pushes a copy of the target position into the stack
-struct script_data* push_copy(struct script_stack* stack, int pos) {
+static struct script_data *push_copy(struct script_stack *stack, int pos)
+{
+ nullpo_retr(NULL, stack);
switch( stack->stack_data[pos].type ) {
case C_CONSTSTR:
return script->push_conststr(stack, stack->stack_data[pos].u.str);
@@ -3538,11 +3750,15 @@ struct script_data* push_copy(struct script_stack* stack, int pos) {
/// Removes the values in indexes [start,end[ from the stack.
/// Adjusts all stack pointers.
-void pop_stack(struct script_state* st, int start, int end) {
- struct script_stack* stack = st->stack;
+static void pop_stack(struct script_state *st, int start, int end)
+{
+ struct script_stack* stack;
struct script_data* data;
int i;
+ nullpo_retv(st);
+ stack = st->stack;
+
if( start < 0 )
start = 0;
if( end > stack->sp )
@@ -3607,7 +3823,7 @@ void pop_stack(struct script_state* st, int start, int end) {
/*==========================================
* Release script dependent variable, dependent variable of function
*------------------------------------------*/
-void script_free_vars(struct DBMap *var_storage)
+static void script_free_vars(struct DBMap *var_storage)
{
if( var_storage ) {
// destroy the storage construct containing the variables
@@ -3615,7 +3831,7 @@ void script_free_vars(struct DBMap *var_storage)
}
}
-void script_free_code(struct script_code* code)
+static void script_free_code(struct script_code *code)
{
nullpo_retv(code);
@@ -3624,7 +3840,7 @@ void script_free_code(struct script_code* code)
script->free_vars(code->local.vars);
if (code->local.arrays)
code->local.arrays->destroy(code->local.arrays,script->array_free_db);
- aFree(code->script_buf);
+ VECTOR_CLEAR(code->script_buf);
aFree(code);
}
@@ -3635,7 +3851,8 @@ void script_free_code(struct script_code* code)
/// @param rid Who is running the script (attached player)
/// @param oid Where the code is being run (npc 'object')
/// @return Script state
-struct script_state* script_alloc_state(struct script_code* rootscript, int pos, int rid, int oid) {
+static struct script_state *script_alloc_state(struct script_code *rootscript, int pos, int rid, int oid)
+{
struct script_state* st;
st = ers_alloc(script->st_ers, struct script_state);
@@ -3677,7 +3894,9 @@ struct script_state* script_alloc_state(struct script_code* rootscript, int pos,
/// Frees a script state.
///
/// @param st Script state
-void script_free_state(struct script_state* st) {
+static void script_free_state(struct script_state *st)
+{
+ nullpo_retv(st);
if( idb_exists(script->st_db,st->id) ) {
struct map_session_data *sd = st->rid ? map->id2sd(st->rid) : NULL;
@@ -3738,7 +3957,9 @@ void script_free_state(struct script_state* st) {
* @param st[in] Script state.
* @param ref[in] Reference to be added.
*/
-void script_add_pending_ref(struct script_state *st, struct reg_db *ref) {
+static void script_add_pending_ref(struct script_state *st, struct reg_db *ref)
+{
+ nullpo_retv(st);
RECREATE(st->pending_refs, struct reg_db*, ++st->pending_ref_count);
st->pending_refs[st->pending_ref_count-1] = ref;
}
@@ -3749,37 +3970,37 @@ void script_add_pending_ref(struct script_state *st, struct reg_db *ref) {
/*==========================================
* Read command
*------------------------------------------*/
-c_op get_com(unsigned char *scriptbuf,int *pos)
+static c_op get_com(const struct script_buf *scriptbuf, int *pos)
{
int i = 0, j = 0;
- if(scriptbuf[*pos]>=0x80) {
+ if (VECTOR_INDEX(*scriptbuf, *pos) >= 0x80) {
return C_INT;
}
- while(scriptbuf[*pos]>=0x40) {
- i=scriptbuf[(*pos)++]<<j;
+ while (VECTOR_INDEX(*scriptbuf, *pos) >= 0x40) {
+ i = VECTOR_INDEX(*scriptbuf, (*pos)++) << j;
j+=6;
}
- return (c_op)(i+(scriptbuf[(*pos)++]<<j));
+ return (c_op)(i+(VECTOR_INDEX(*scriptbuf, (*pos)++)<<j));
}
/*==========================================
* Income figures
*------------------------------------------*/
-int get_num(unsigned char *scriptbuf,int *pos)
+static int get_num(const struct script_buf *scriptbuf, int *pos)
{
int i,j;
i=0; j=0;
- while(scriptbuf[*pos]>=0xc0) {
- i+=(scriptbuf[(*pos)++]&0x7f)<<j;
+ while (VECTOR_INDEX(*scriptbuf, *pos) >= 0xc0) {
+ i+= (VECTOR_INDEX(*scriptbuf, (*pos)++)&0x7f)<<j;
j+=6;
}
- return i+((scriptbuf[(*pos)++]&0x7f)<<j);
+ return i+((VECTOR_INDEX(*scriptbuf, (*pos)++)&0x7f)<<j);
}
/// Ternary operators
/// test ? if_true : if_false
-void op_3(struct script_state* st, int op)
+static void op_3(struct script_state *st, int op)
{
struct script_data* data;
int flag = 0;
@@ -3816,7 +4037,7 @@ void op_3(struct script_state* st, int op)
/// s1 RE_EQ s2 -> i
/// s1 RE_NE s2 -> i
/// s1 ADD s2 -> s
-void op_2str(struct script_state* st, int op, const char* s1, const char* s2)
+static void op_2str(struct script_state *st, int op, const char *s1, const char *s2)
{
int a = 0;
@@ -3834,7 +4055,7 @@ void op_2str(struct script_state* st, int op, const char* s1, const char* s2)
pcre *compiled_regex;
pcre_extra *extra_regex;
const char *pcre_error, *pcre_match;
- int pcre_erroroffset, offsetcount, i;
+ int pcre_erroroffset, offsetcount;
int offsets[256*3]; // (max_capturing_groups+1)*3
compiled_regex = libpcre->compile(s2, 0, &pcre_error, &pcre_erroroffset, NULL);
@@ -3875,13 +4096,14 @@ void op_2str(struct script_state* st, int op, const char* s1, const char* s2)
return;
}
- if( op == C_RE_EQ ) {
- for( i = 0; i < offsetcount; i++ ) {
+ if (op == C_RE_EQ) {
+ int i;
+ for (i = 0; i < offsetcount; i++) {
libpcre->get_substring(s1, offsets, offsetcount, i, &pcre_match);
- mapreg->setregstr(reference_uid(script->add_str("$@regexmatch$"), i), pcre_match);
+ mapreg->setregstr(reference_uid(script->add_variable("$@regexmatch$"), i), pcre_match);
libpcre->free_substring(pcre_match);
}
- mapreg->setreg(script->add_str("$@regexmatchcount"), i);
+ mapreg->setreg(script->add_variable("$@regexmatchcount"), i);
a = offsetcount;
} else { // C_RE_NE
a = (offsetcount == 0);
@@ -3912,7 +4134,7 @@ void op_2str(struct script_state* st, int op, const char* s1, const char* s2)
/// Binary number operators
/// i OP i -> i
-void op_2num(struct script_state* st, int op, int i1, int i2)
+static void op_2num(struct script_state *st, int op, int i1, int i2)
{
int ret;
int64 ret64;
@@ -3951,6 +4173,7 @@ void op_2num(struct script_state* st, int op, int i1, int i2)
case C_ADD: ret = i1 + i2; ret64 = (int64)i1 + i2; break;
case C_SUB: ret = i1 - i2; ret64 = (int64)i1 - i2; break;
case C_MUL: ret = i1 * i2; ret64 = (int64)i1 * i2; break;
+ case C_POW: ret = (int)pow((double)i1, (double)i2); ret64 = (int64)pow((double)i1, (double)i2); break;
default:
ShowError("script:op_2num: unexpected number operator %s i1=%d i2=%d\n", script->op2name(op), i1, i2);
script->reportsrc(st);
@@ -3971,7 +4194,7 @@ void op_2num(struct script_state* st, int op, int i1, int i2)
}
/// Binary operators
-void op_2(struct script_state *st, int op)
+static void op_2(struct script_state *st, int op)
{
struct script_data* left, leftref;
struct script_data* right;
@@ -4045,7 +4268,7 @@ void op_2(struct script_state *st, int op)
/// NEG i -> i
/// NOT i -> i
/// LNOT i -> i
-void op_1(struct script_state* st, int op)
+static void op_1(struct script_state *st, int op)
{
struct script_data* data;
int i1;
@@ -4083,10 +4306,17 @@ void op_1(struct script_state* st, int op)
///
/// @param st Script state whose stack arguments should be inspected.
/// @param func Built-in function for which the arguments are intended.
-void script_check_buildin_argtype(struct script_state* st, int func)
+static bool script_check_buildin_argtype(struct script_state *st, int func)
{
int idx, invalid = 0;
- char* sf = script->buildin[script->str_data[func].val];
+ char* sf;
+ if (script->str_data[func].val < 0 || script->str_data[func].val >= script->buildin_count) {
+ ShowDebug("Function: %s\n", script->get_str(func));
+ ShowError("Script data corruption detected!\n");
+ script->reportsrc(st);
+ return false;
+ }
+ sf = script->buildin[script->str_data[func].val];
for (idx = 2; script_hasdata(st, idx); idx++) {
struct script_data* data = script_getdata(st, idx);
@@ -4157,15 +4387,17 @@ void script_check_buildin_argtype(struct script_state* st, int func)
ShowDebug("Function: %s\n", script->get_str(func));
script->reportsrc(st);
}
+ return true;
}
/// Executes a buildin command.
/// Stack: C_NAME(<command>) C_ARG <arg0> <arg1> ... <argN>
-int run_func(struct script_state *st)
+static int run_func(struct script_state *st)
{
struct script_data* data;
int i,start_sp,end_sp,func;
+ nullpo_retr(1, st);
end_sp = st->stack->sp;// position after the last argument
for( i = end_sp-1; i > 0 ; --i )
if( st->stack->stack_data[i].type == C_ARG )
@@ -4194,7 +4426,11 @@ int run_func(struct script_state *st)
}
if( script->config.warn_func_mismatch_argtypes ) {
- script->check_buildin_argtype(st, func);
+ if (script->check_buildin_argtype(st, func) == false)
+ {
+ st->state = END;
+ return 1;
+ }
}
if(script->str_data[func].func) {
@@ -4249,7 +4485,8 @@ int run_func(struct script_state *st)
/*==========================================
* script execution
*------------------------------------------*/
-void run_script(struct script_code *rootscript, int pos, int rid, int oid) {
+static void run_script(struct script_code *rootscript, int pos, int rid, int oid)
+{
struct script_state *st;
if( rootscript == NULL || pos < 0 )
@@ -4263,7 +4500,7 @@ void run_script(struct script_code *rootscript, int pos, int rid, int oid) {
script->run_main(st);
}
-void script_stop_instances(struct script_code *code)
+static void script_stop_instances(struct script_code *code)
{
struct DBIterator *iter;
struct script_state* st;
@@ -4285,7 +4522,8 @@ void script_stop_instances(struct script_code *code)
/*==========================================
* Timer function for sleep
*------------------------------------------*/
-int run_script_timer(int tid, int64 tick, int id, intptr_t data) {
+static int run_script_timer(int tid, int64 tick, int id, intptr_t data)
+{
struct script_state *st = idb_get(script->st_db,(int)data);
if( st ) {
struct map_session_data *sd = map->id2sd(st->rid);
@@ -4306,9 +4544,11 @@ int run_script_timer(int tid, int64 tick, int id, intptr_t data) {
///
/// @param st Script state to detach.
/// @param dequeue_event Whether to schedule any queued events, when there was no previous script.
-void script_detach_state(struct script_state* st, bool dequeue_event) {
+static void script_detach_state(struct script_state *st, bool dequeue_event)
+{
struct map_session_data* sd;
+ nullpo_retv(st);
if(st->rid && (sd = map->id2sd(st->rid))!=NULL) {
sd->st = st->bk_st;
sd->npc_id = st->bk_npcid;
@@ -4339,9 +4579,11 @@ void script_detach_state(struct script_state* st, bool dequeue_event) {
/// Attaches script state to possibly attached character and backups it's previous script, if any.
///
/// @param st Script state to attach.
-void script_attach_state(struct script_state* st) {
+static void script_attach_state(struct script_state *st)
+{
struct map_session_data* sd;
+ nullpo_retv(st);
if(st->rid && (sd = map->id2sd(st->rid))!=NULL)
{
if(st!=sd->st)
@@ -4370,14 +4612,19 @@ void script_attach_state(struct script_state* st) {
/*==========================================
* The main part of the script execution
*------------------------------------------*/
-void run_script_main(struct script_state *st) {
+static void run_script_main(struct script_state *st)
+{
int cmdcount = script->config.check_cmdcount;
int gotocount = script->config.check_gotocount;
struct map_session_data *sd;
struct script_stack *stack = st->stack;
struct npc_data *nd;
+ nullpo_retv(st);
script->attach_state(st);
+ if (st->state != END && Assert_chk(st->state == RUN || st->state == STOP || st->state == RERUNLINE)) {
+ st->state = END;
+ }
nd = map->id2nd(st->oid);
if( nd && nd->bl.m >= 0 )
@@ -4393,7 +4640,7 @@ void run_script_main(struct script_state *st) {
st->state = RUN;
while( st->state == RUN ) {
- enum c_op c = script->get_com(st->script->script_buf,&st->pos);
+ enum c_op c = script->get_com(&st->script->script_buf, &st->pos);
switch(c) {
case C_EOL:
if( stack->defsp > stack->sp )
@@ -4402,27 +4649,29 @@ void run_script_main(struct script_state *st) {
script->pop_stack(st, stack->defsp, stack->sp);// pop unused stack data. (unused return value)
break;
case C_INT:
- script->push_val(stack,C_INT,script->get_num(st->script->script_buf,&st->pos),NULL);
+ script->push_val(stack,C_INT,script->get_num(&st->script->script_buf, &st->pos), NULL);
break;
case C_POS:
case C_NAME:
- script->push_val(stack,c,GETVALUE(st->script->script_buf,st->pos),NULL);
+ script->push_val(stack,c,GETVALUE(&st->script->script_buf, st->pos), NULL);
st->pos+=3;
break;
case C_ARG:
script->push_val(stack,c,0,NULL);
break;
case C_STR:
- script->push_conststr(stack, (const char *)(st->script->script_buf+st->pos));
- while(st->script->script_buf[st->pos++]);
+ script->push_conststr(stack, (const char *)&VECTOR_INDEX(st->script->script_buf, st->pos));
+ while (VECTOR_INDEX(st->script->script_buf, st->pos++) != 0)
+ (void)0; // Skip string
break;
case C_LSTR:
{
- int string_id = *((int *)(&st->script->script_buf[st->pos]));
- uint8 translations = *((uint8 *)(&st->script->script_buf[st->pos+sizeof(int)]));
struct map_session_data *lsd = NULL;
-
- st->pos += sizeof(int) + sizeof(uint8);
+ uint8 translations = 0;
+ int string_id = *((int *)(&VECTOR_INDEX(st->script->script_buf, st->pos)));
+ st->pos += sizeof(string_id);
+ translations = *((uint8 *)(&VECTOR_INDEX(st->script->script_buf, st->pos)));
+ st->pos += sizeof(translations);
if( (!st->rid || !(lsd = map->id2sd(st->rid)) || !lsd->lang_id) && !map->default_lang_id )
script->push_conststr(stack, script->string_list+string_id);
@@ -4431,7 +4680,7 @@ void run_script_main(struct script_state *st) {
int offset = st->pos;
for(k = 0; k < translations; k++) {
- uint8 lang_id = *(uint8 *)(&st->script->script_buf[offset]);
+ uint8 lang_id = *(uint8 *)(&VECTOR_INDEX(st->script->script_buf, offset));
offset += sizeof(uint8);
if( lang_id == wlang_id )
break;
@@ -4440,7 +4689,7 @@ void run_script_main(struct script_state *st) {
if (k == translations)
script->push_conststr(stack, script->string_list+string_id);
else
- script->push_conststr(stack, *(const char**)(&st->script->script_buf[offset]) );
+ script->push_conststr(stack, *(const char**)(&VECTOR_INDEX(st->script->script_buf, offset)));
}
st->pos += ( ( sizeof(char*) + sizeof(uint8) ) * translations );
}
@@ -4470,6 +4719,7 @@ void run_script_main(struct script_state *st) {
case C_ADD:
case C_SUB:
case C_MUL:
+ case C_POW:
case C_DIV:
case C_MOD:
case C_EQ:
@@ -4548,58 +4798,62 @@ void run_script_main(struct script_state *st) {
}
}
-int script_config_read(char *cfgName) {
- int i;
- char line[1024],w1[1024],w2[1024];
- FILE *fp;
+/**
+ * Reads 'script_configuration' and initializes required variables.
+ *
+ * @param filename Path to configuration file.
+ * @param imported Whether the current config is imported from another file.
+ *
+ * @retval false in case of error.
+ */
+static bool script_config_read(const char *filename, bool imported)
+{
+ struct config_t config;
+ struct config_setting_t * setting = NULL;
+ const char *import = NULL;
+ bool retval = true;
- if( !( fp = fopen(cfgName,"r") ) ) {
- ShowError("File not found: %s\n", cfgName);
- return 1;
+ nullpo_retr(false, filename);
+
+ if (!libconfig->load_file(&config, filename))
+ return false;
+
+ if ((setting = libconfig->lookup(&config, "script_configuration")) == NULL) {
+ libconfig->destroy(&config);
+ if (imported)
+ return true;
+ ShowError("script_config_read: script_configuration was not found in %s!\n", filename);
+ return false;
}
- while (fgets(line, sizeof(line), fp)) {
- if (line[0] == '/' && line[1] == '/')
- continue;
- i = sscanf(line,"%1023[^:]: %1023[^\r\n]", w1, w2);
- if(i!=2)
- continue;
- if(strcmpi(w1,"warn_func_mismatch_paramnum")==0) {
- script->config.warn_func_mismatch_paramnum = config_switch(w2);
- }
- else if(strcmpi(w1,"check_cmdcount")==0) {
- script->config.check_cmdcount = config_switch(w2);
- }
- else if(strcmpi(w1,"check_gotocount")==0) {
- script->config.check_gotocount = config_switch(w2);
- }
- else if(strcmpi(w1,"input_min_value")==0) {
- script->config.input_min_value = config_switch(w2);
- }
- else if(strcmpi(w1,"input_max_value")==0) {
- script->config.input_max_value = config_switch(w2);
- }
- else if(strcmpi(w1,"warn_func_mismatch_argtypes")==0) {
- script->config.warn_func_mismatch_argtypes = config_switch(w2);
- }
- else if(strcmpi(w1,"import")==0) {
- script->config_read(w2);
- }
- else if(HPM->parseConf(w1, w2, HPCT_SCRIPT)) {
- ; // handled by plugin
+ 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_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);
+ libconfig->setting_lookup_int(setting, "input_max_value", &script->config.input_max_value);
+
+ if (!HPM->parse_conf(&config, filename, HPCT_SCRIPT, imported))
+ retval = false;
+
+ // import should overwrite any previous configuration, so it should be called last
+ if (libconfig->lookup_string(&config, "import", &import) == CONFIG_TRUE) {
+ if (strcmp(import, filename) == 0 || strcmp(import, map->SCRIPT_CONF_NAME) == 0) {
+ ShowWarning("script_config_read: Loop detected! Skipping 'import'...\n");
} else {
- ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName);
+ if (!script->config_read(import, true))
+ retval = false;
}
}
- fclose(fp);
- return 0;
+ libconfig->destroy(&config);
+ return retval;
}
/**
* @see DBApply
*/
-int db_script_free_code_sub(union DBKey key, struct DBData *data, va_list ap)
+static int db_script_free_code_sub(union DBKey key, struct DBData *data, va_list ap)
{
struct script_code *code = DB->data2ptr(data);
if (code)
@@ -4607,7 +4861,7 @@ int db_script_free_code_sub(union DBKey key, struct DBData *data, va_list ap)
return 0;
}
-void script_run_autobonus(const char *autobonus, int id, int pos)
+static void script_run_autobonus(const char *autobonus, int id, int pos)
{
struct script_code *scriptroot = (struct script_code *)strdb_get(script->autobonus_db, autobonus);
@@ -4617,7 +4871,7 @@ void script_run_autobonus(const char *autobonus, int id, int pos)
}
}
-void script_add_autobonus(const char *autobonus)
+static void script_add_autobonus(const char *autobonus)
{
if( strdb_get(script->autobonus_db, autobonus) == NULL ) {
struct script_code *scriptroot = script->parse(autobonus, "autobonus", 0, 0, NULL);
@@ -4628,13 +4882,19 @@ void script_add_autobonus(const char *autobonus)
}
/// resets a temporary character array variable to given value
-void script_cleararray_pc(struct map_session_data* sd, const char* varname, void* value) {
+static void script_cleararray_pc(struct map_session_data *sd, const char *varname, void *value)
+{
struct script_array *sa = NULL;
struct reg_db *src = NULL;
unsigned int i, *list = NULL, size = 0;
int key;
- key = script->add_str(varname);
+ key = script->add_variable(varname);
+
+ if (script->str_data[key].type != C_NAME) {
+ ShowError("script:cleararray_pc: `%s` is already used by something that is not a variable.\n", varname);
+ return;
+ }
if( !(src = script->array_src(NULL,sd,varname,NULL) ) )
return;
@@ -4655,15 +4915,21 @@ void script_cleararray_pc(struct map_session_data* sd, const char* varname, void
/// sets a temporary character array variable element idx to given value
/// @param refcache Pointer to an int variable, which keeps a copy of the reference to varname and must be initialized to 0. Can be NULL if only one element is set.
-void script_setarray_pc(struct map_session_data* sd, const char* varname, uint32 idx, void* value, int* refcache) {
+static void script_setarray_pc(struct map_session_data *sd, const char *varname, uint32 idx, void *value, int *refcache)
+{
int key;
- if( idx >= SCRIPT_MAX_ARRAYSIZE ) {
+ if (idx > SCRIPT_MAX_ARRAYSIZE) {
ShowError("script_setarray_pc: Variable '%s' has invalid index '%u' (char_id=%d).\n", varname, idx, sd->status.char_id);
return;
}
- key = ( refcache && refcache[0] ) ? refcache[0] : script->add_str(varname);
+ key = ( refcache && refcache[0] ) ? refcache[0] : script->add_variable(varname);
+
+ if (script->str_data[key].type != C_NAME) {
+ ShowError("script:setarray_pc: `%s` is already used by something that is not a variable.\n", varname);
+ return;
+ }
script->set_reg(NULL,sd,reference_uid(key, idx),varname,value,NULL);
@@ -4675,10 +4941,11 @@ void script_setarray_pc(struct map_session_data* sd, const char* varname, uint32
/**
* Clears persistent variables from memory
**/
-int script_reg_destroy(union DBKey key, struct DBData *data, va_list ap)
+static int script_reg_destroy(union DBKey key, struct DBData *data, va_list ap)
{
struct script_reg_state *src;
+ nullpo_ret(data);
if( data->type != DB_DATA_PTR )/* got no need for those! */
return 0;
@@ -4699,7 +4966,10 @@ int script_reg_destroy(union DBKey key, struct DBData *data, va_list ap)
/**
* Clears a single persistent variable
**/
-void script_reg_destroy_single(struct map_session_data *sd, int64 reg, struct script_reg_state *data) {
+static void script_reg_destroy_single(struct map_session_data *sd, int64 reg, struct script_reg_state *data)
+{
+ nullpo_retv(sd);
+ nullpo_retv(data);
i64db_remove(sd->regs.vars, reg);
if( data->type ) {
@@ -4713,20 +4983,23 @@ void script_reg_destroy_single(struct map_session_data *sd, int64 reg, struct sc
ers_free(pc->num_reg_ers,(struct script_reg_num*)data);
}
}
-unsigned int *script_array_cpy_list(struct script_array *sa) {
+static unsigned int *script_array_cpy_list(struct script_array *sa)
+{
+ nullpo_retr(NULL, sa);
if( sa->size > script->generic_ui_array_size )
script->generic_ui_array_expand(sa->size);
memcpy(script->generic_ui_array, sa->members, sizeof(unsigned int)*sa->size);
return script->generic_ui_array;
}
-void script_generic_ui_array_expand (unsigned int plus) {
+static void script_generic_ui_array_expand(unsigned int plus)
+{
script->generic_ui_array_size += plus + 100;
RECREATE(script->generic_ui_array, unsigned int, script->generic_ui_array_size);
}
/*==========================================
* Destructor
*------------------------------------------*/
-void do_final_script(void)
+static void do_final_script(void)
{
int i;
struct DBIterator *iter;
@@ -4806,6 +5079,8 @@ void do_final_script(void)
aFree(script->str_buf);
for( i = 0; i < atcommand->binding_count; i++ ) {
+ aFree(atcommand->binding[i]->at_groups);
+ aFree(atcommand->binding[i]->char_groups);
aFree(atcommand->binding[i]);
}
@@ -4854,16 +5129,15 @@ void do_final_script(void)
script->clear_translations(false);
script->parser_clean_leftovers();
-
- if( script->lang_export_file )
- aFree(script->lang_export_file);
}
/**
*
**/
-uint8 script_add_language(const char *name) {
+static uint8 script_add_language(const char *name)
+{
uint8 lang_id = script->max_lang_id;
+ nullpo_ret(name);
RECREATE(script->languages, char *, ++script->max_lang_id);
script->languages[lang_id] = aStrdup(name);
@@ -4873,12 +5147,14 @@ uint8 script_add_language(const char *name) {
/**
* Goes thru db/translations.conf file
**/
-void script_load_translations(void) {
+static void script_load_translations(void)
+{
struct config_t translations_conf;
- const char *config_filename = "db/translations.conf"; // FIXME hardcoded name
+ char config_filename[256];
+ libconfig->format_db_path("translations.conf", config_filename, sizeof(config_filename));
struct config_setting_t *translations = NULL;
int i, size;
- uint32 total = 0;
+ int total = 0;
uint8 lang_id = 0, k;
if (map->minimal) // No translations in minimal mode
@@ -4914,25 +5190,23 @@ void script_load_translations(void) {
size = libconfig->setting_length(translations);
for(i = 0; i < size; i++) {
- const char *translation_file = libconfig->setting_get_string_elem(translations, i);
- script->load_translation(translation_file, ++lang_id, &total);
+ const char *translation_dir = libconfig->setting_get_string_elem(translations, i);
+ total += script->load_translation(translation_dir, ++lang_id);
}
libconfig->destroy(&translations_conf);
- if( total ) {
- struct DBIterator *main_iter, *sub_iter;
+ if (total != 0) {
+ struct DBIterator *main_iter;
struct DBMap *string_db;
struct string_translation *st = NULL;
- uint32 j = 0;
- CREATE(script->translation_buf, char *, total);
- script->translation_buf_size = total;
+ VECTOR_ENSURE(script->translation_buf, total, 1);
main_iter = db_iterator(script->translation_db);
- for( string_db = dbi_first(main_iter); dbi_exists(main_iter); string_db = dbi_next(main_iter) ) {
- sub_iter = db_iterator(string_db);
- for( st = dbi_first(sub_iter); dbi_exists(sub_iter); st = dbi_next(sub_iter) ) {
- script->translation_buf[j++] = st->buf;
+ for (string_db = dbi_first(main_iter); dbi_exists(main_iter); string_db = dbi_next(main_iter)) {
+ struct DBIterator *sub_iter = db_iterator(string_db);
+ for (st = dbi_first(sub_iter); dbi_exists(sub_iter); st = dbi_next(sub_iter)) {
+ VECTOR_PUSH(script->translation_buf, st->buf);
}
dbi_destroy(sub_iter);
}
@@ -4954,149 +5228,319 @@ void script_load_translations(void) {
}
/**
+ * Generates a language name from a translation directory name.
*
- **/
-const char * script_get_translation_file_name(const char *file) {
- static char file_name[200];
- int i, len = (int)strlen(file), last_bar = -1, last_dot = -1;
+ * @param directory The directory name.
+ * @return The corresponding translation name.
+ */
+static const char *script_get_translation_dir_name(const char *directory)
+{
+ const char *basename = NULL, *last_dot = NULL;
+
+ nullpo_retr("Unknown", directory);
- for(i = 0; i < len; i++) {
- if( file[i] == '/' || file[i] == '\\' )
- last_bar = i;
- else if ( file[i] == '.' )
- last_dot = i;
+ basename = strrchr(directory, '/');
+#ifdef WIN32
+ {
+ const char *basename_windows = strrchr(directory, '\\');
+ if (basename_windows > basename)
+ basename = basename_windows;
}
+#endif // WIN32
+ if (basename == NULL)
+ basename = directory;
+ else
+ basename++; // Skip slash
+ Assert_retr("Unknown", *basename != '\0');
+
+ last_dot = strrchr(basename, '.');
+ if (last_dot != NULL) {
+ static char dir_name[200];
+ if (last_dot == basename)
+ return basename + 1;
- if( last_bar != -1 || last_dot != -1 ) {
- if( last_bar != -1 && last_dot < last_bar )
- last_dot = -1;
- safestrncpy(file_name, file+(last_bar >= 0 ? last_bar+1 : 0), ( last_dot >= 0 ? ( last_bar >= 0 ? last_dot - last_bar : last_dot ) : sizeof(file_name) ));
- return file_name;
+ safestrncpy(dir_name, basename, last_dot - basename + 1);
+ return dir_name;
}
- return file;
+ return basename;
}
/**
- * Parses a individual translation file
- **/
-void script_load_translation(const char *file, uint8 lang_id, uint32 *total) {
- uint32 translations = 0;
+ * Parses and adds a translated string to the translations database.
+ *
+ * @param file Translations file being parsed (for error messages).
+ * @param lang_id Language ID being parsed.
+ * @param msgctxt Message context (i.e. NPC name)
+ * @param msgid Message ID (source string)
+ * @param msgstr Translated message
+ * @return success state
+ * @retval true if a new string was added.
+ */
+static bool script_load_translation_addstring(const char *file, uint8 lang_id, const char *msgctxt, const struct script_string_buf *msgid, const struct script_string_buf *msgstr)
+{
+ nullpo_retr(false, file);
+ nullpo_retr(false, msgctxt);
+ nullpo_retr(false, msgid);
+ nullpo_retr(false, msgstr);
+
+ if (VECTOR_LENGTH(*msgid) <= 1) {
+ // Empty ID (i.e. header) to be ignored
+ return false;
+ }
+
+ if (VECTOR_LENGTH(*msgstr) <= 1) {
+ // Empty (untranslated) string to be ignored
+ return false;
+ }
+
+ if (msgctxt[0] == '\0') {
+ // Missing context
+ ShowWarning("script_load_translation: Missing context for msgid '%s' in '%s'. Skipping.\n",
+ VECTOR_DATA(*msgid), file);
+ return false;
+ }
+
+ if (strcasecmp(msgctxt, "messages.conf") == 0) {
+ int i;
+ for (i = 0; i < MAX_MSG; i++) {
+ if (atcommand->msg_table[0][i] != NULL && strcmpi(atcommand->msg_table[0][i], VECTOR_DATA(*msgid)) == 0) {
+ if (atcommand->msg_table[lang_id][i] != NULL)
+ aFree(atcommand->msg_table[lang_id][i]);
+ atcommand->msg_table[lang_id][i] = aStrdup(VECTOR_DATA(*msgstr));
+ break;
+ }
+ }
+ } else {
+ int msgstr_len = VECTOR_LENGTH(*msgstr);
+ int inner_len = 1 + msgstr_len + 1; //uint8 lang_id + msgstr_len + '\0'
+ struct string_translation *st = NULL;
+ struct DBMap *string_db;
+
+ if ((string_db = strdb_get(script->translation_db, msgctxt)) == NULL) {
+ string_db = strdb_alloc(DB_OPT_DUP_KEY, 0);
+ strdb_put(script->translation_db, msgctxt, string_db);
+ }
+
+ if ((st = strdb_get(string_db, VECTOR_DATA(*msgid))) == NULL) {
+ CREATE(st, struct string_translation, 1);
+ st->string_id = script->string_dup(VECTOR_DATA(*msgid));
+ strdb_put(string_db, VECTOR_DATA(*msgid), st);
+ }
+ RECREATE(st->buf, uint8, st->len + inner_len);
+
+ WBUFB(st->buf, st->len) = lang_id;
+ safestrncpy(WBUFP(st->buf, st->len + 1), VECTOR_DATA(*msgstr), msgstr_len + 1);
+
+ st->translations++;
+ st->len += inner_len;
+ }
+ return true;
+}
+
+/**
+ * Parses an individual translation file.
+ *
+ * @param directory The directory structure to read.
+ * @param lang_id The language identifier.
+ * @return The amount of strings loaded.
+ */
+static int script_load_translation_file(const char *file, uint8 lang_id)
+{
char line[1024];
- char msgctxt[NAME_LENGTH*2+1] = { 0 };
- struct DBMap *string_db;
- size_t i;
+ char msgctxt[NAME_LENGTH*2+1] = "";
+ struct script_string_buf msgid, msgstr;
+ struct script_string_buf *msg_ptr;
+ int translations = 0;
+ int lineno = 0;
FILE *fp;
- struct script_string_buf msgid = { 0 }, msgstr = { 0 };
- if( !(fp = fopen(file,"rb")) ) {
+ nullpo_ret(file);
+
+ if ((fp = fopen(file,"rb")) == NULL) {
ShowError("load_translation: failed to open '%s' for reading\n",file);
- return;
+ return 0;
}
- script->add_language(script->get_translation_file_name(file));
- if( lang_id >= atcommand->max_message_table )
- atcommand->expand_message_table();
+ VECTOR_INIT(msgid);
+ VECTOR_INIT(msgstr);
+
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ int len = (int)strlen(line);
+ int i;
+ lineno++;
- while(fgets(line, sizeof(line), fp)) {
- size_t len = strlen(line), cursor = 0;
+ if (len <= 1) {
+ if (VECTOR_LENGTH(msgid) > 0 && VECTOR_LENGTH(msgstr) > 0) {
+ // Add string
+ if (script->load_translation_addstring(file, lang_id, msgctxt, &msgid, &msgstr))
+ translations++;
- if( len <= 1 )
+ msgctxt[0] = '\0';
+ VECTOR_TRUNCATE(msgid);
+ VECTOR_TRUNCATE(msgstr);
+ }
continue;
+ }
- if( line[0] == '#' )
+ if (line[0] == '#')
continue;
- if( strncasecmp(line,"msgctxt \"", 9) == 0 ) {
+ if (VECTOR_LENGTH(msgid) > 0) {
+ if (VECTOR_LENGTH(msgstr) > 0) {
+ msg_ptr = &msgstr;
+ } else {
+ msg_ptr = &msgid;
+ }
+ if (line[0] == '"') {
+ // Continuation line
+ (void)VECTOR_POP(*msg_ptr); // Pop final '\0'
+ for (i = 1; i < len - 2; i++) {
+ VECTOR_ENSURE(*msg_ptr, 1, 512);
+ if (line[i] == '\\' && line[i+1] == '"') {
+ VECTOR_PUSH(*msg_ptr, '"');
+ i++;
+ } else if (line[i] == '\\' && line[i+1] == 'r') {
+ VECTOR_PUSH(*msg_ptr, '\r');
+ i++;
+ } else {
+ VECTOR_PUSH(*msg_ptr, line[i]);
+ }
+ }
+ VECTOR_ENSURE(*msg_ptr, 1, 512);
+ VECTOR_PUSH(*msg_ptr, '\0');
+ continue;
+ }
+
+ }
+
+ if (strncasecmp(line,"msgctxt \"", 9) == 0) {
+ int cursor = 0;
msgctxt[0] = '\0';
- for(i = 9; i < len - 2; i++) {
- if( line[i] == '\\' && line[i+1] == '"' ) {
+ for (i = 9; i < len - 2; i++) {
+ if (line[i] == '\\' && line[i+1] == '"') {
msgctxt[cursor] = '"';
i++;
- } else
+ } else if (line[i] == '\\' && line[i+1] == 'r') {
+ msgctxt[cursor] = '\r';
+ i++;
+ } else {
msgctxt[cursor] = line[i];
- if( ++cursor >= sizeof(msgctxt) - 1 )
+ }
+ if (++cursor >= (int)sizeof(msgctxt) - 1)
break;
}
msgctxt[cursor] = '\0';
- } else if ( strncasecmp(line, "msgid \"", 7) == 0 ) {
- msgid.pos = 0;
- for(i = 7; i < len - 2; i++) {
- if( line[i] == '\\' && line[i+1] == '"' ) {
- script_string_buf_addb(&msgid, '"');
+
+ // New context, reset everything
+ VECTOR_TRUNCATE(msgid);
+ VECTOR_TRUNCATE(msgstr);
+ continue;
+ }
+
+ if (strncasecmp(line, "msgid \"", 7) == 0) {
+ VECTOR_TRUNCATE(msgid);
+ for (i = 7; i < len - 2; i++) {
+ VECTOR_ENSURE(msgid, 1, 512);
+ if (line[i] == '\\' && line[i+1] == '"') {
+ VECTOR_PUSH(msgid, '"');
+ i++;
+ } else if (line[i] == '\\' && line[i+1] == 'r') {
+ VECTOR_PUSH(msgid, '\r');
i++;
- } else
- script_string_buf_addb(&msgid, line[i]);
+ } else {
+ VECTOR_PUSH(msgid, line[i]);
+ }
}
- script_string_buf_addb(&msgid,0);
- } else if ( len > 9 && line[9] != '"' && strncasecmp(line, "msgstr \"",8) == 0 ) {
- msgstr.pos = 0;
- for(i = 8; i < len - 2; i++) {
- if( line[i] == '\\' && line[i+1] == '"' ) {
- script_string_buf_addb(&msgstr, '"');
+ VECTOR_ENSURE(msgid, 1, 512);
+ VECTOR_PUSH(msgid, '\0');
+
+ // New id, reset string if any
+ VECTOR_TRUNCATE(msgstr);
+ continue;
+ }
+
+ if (VECTOR_LENGTH(msgid) > 0 && strncasecmp(line, "msgstr \"", 8) == 0) {
+ VECTOR_TRUNCATE(msgstr);
+ for (i = 8; i < len - 2; i++) {
+ VECTOR_ENSURE(msgstr, 1, 512);
+ if (line[i] == '\\' && line[i+1] == '"') {
+ VECTOR_PUSH(msgstr, '"');
i++;
- } else
- script_string_buf_addb(&msgstr, line[i]);
+ } else if (line[i] == '\\' && line[i+1] == 'r') {
+ VECTOR_PUSH(msgstr, '\r');
+ i++;
+ } else {
+ VECTOR_PUSH(msgstr, line[i]);
+ }
}
- script_string_buf_addb(&msgstr,0);
+ VECTOR_ENSURE(msgstr, 1, 512);
+ VECTOR_PUSH(msgstr, '\0');
+
+ continue;
}
- if( msgctxt[0] && msgid.pos > 1 && msgstr.pos > 1 ) {
- size_t msgstr_len = msgstr.pos;
- unsigned int inner_len = 1 + (uint32)msgstr_len + 1; //uint8 lang_id + msgstr_len + '\0'
+ ShowWarning("script_load_translation: Unexpected input at '%s' in file '%s' line %d. Skipping.\n",
+ line, file, lineno);
+ }
- if( strcasecmp(msgctxt, "messages.conf") == 0 ) {
- int k;
+ // Add last string
+ if (VECTOR_LENGTH(msgid) > 0 && VECTOR_LENGTH(msgstr) > 0) {
+ if (script->load_translation_addstring(file, lang_id, msgctxt, &msgid, &msgstr))
+ translations++;
+ }
- for(k = 0; k < MAX_MSG; k++) {
- if( atcommand->msg_table[0][k] && strcmpi(atcommand->msg_table[0][k],msgid.ptr) == 0 ) {
- if( atcommand->msg_table[lang_id][k] )
- aFree(atcommand->msg_table[lang_id][k]);
- atcommand->msg_table[lang_id][k] = aStrdup(msgstr.ptr);
- break;
- }
- }
- } else {
- struct string_translation *st = NULL;
+ fclose(fp);
- if( !( string_db = strdb_get(script->translation_db, msgctxt) ) ) {
- string_db = strdb_alloc(DB_OPT_DUP_KEY, 0);
- strdb_put(script->translation_db, msgctxt, string_db);
- }
+ VECTOR_CLEAR(msgid);
+ VECTOR_CLEAR(msgstr);
- if( !(st = strdb_get(string_db, msgid.ptr) ) ) {
- CREATE(st, struct string_translation, 1);
- st->string_id = script->string_dup(msgid.ptr);
- strdb_put(string_db, msgid.ptr, st);
- }
- RECREATE(st->buf, char, st->len + inner_len);
+ return translations;
+}
- WBUFB(st->buf, st->len) = lang_id;
- safestrncpy(WBUFP(st->buf, st->len + 1), msgstr.ptr, msgstr_len + 1);
+struct load_translation_data {
+ uint8 lang_id;
+ int translation_count;
+};
- st->translations++;
- st->len += inner_len;
- }
- msgctxt[0] = '\0';
- msgid.pos = msgstr.pos = 0;
- translations++;
- }
- }
+static void script_load_translation_sub(const char *filename, void *context)
+{
+ nullpo_retv(context);
- *total += translations;
+ struct load_translation_data *data = context;
- fclose(fp);
+ data->translation_count += script->load_translation_file(filename, data->lang_id);
+}
- script_string_buf_destroy(&msgid);
- script_string_buf_destroy(&msgstr);
+/**
+ * Loads a translations directory
+ *
+ * @param directory The directory structure to read.
+ * @param lang_id The language identifier.
+ * @return The amount of strings loaded.
+ */
+static int script_load_translation(const char *directory, uint8 lang_id)
+{
+ struct load_translation_data data = { 0 };
+ data.lang_id = lang_id;
+
+ nullpo_ret(directory);
+
+ script->add_language(script->get_translation_dir_name(directory));
+ if (lang_id >= atcommand->max_message_table)
+ atcommand->expand_message_table();
- ShowStatus("Done reading '"CL_WHITE"%u"CL_RESET"' translations in '"CL_WHITE"%s"CL_RESET"'.\n", translations, file);
+ findfile(directory, ".po", script_load_translation_sub, &data);
+
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' translations in '"CL_WHITE"%s"CL_RESET"'.\n", data.translation_count, directory);
+ return data.translation_count;
}
/**
*
**/
-void script_clear_translations(bool reload) {
+static void script_clear_translations(bool reload)
+{
uint32 i;
if( script->string_list )
@@ -5106,15 +5550,10 @@ void script_clear_translations(bool reload) {
script->string_list_pos = 0;
script->string_list_size = 0;
- if( script->translation_buf ) {
- for(i = 0; i < script->translation_buf_size; i++) {
- aFree(script->translation_buf[i]);
- }
- aFree(script->translation_buf);
+ while (VECTOR_LENGTH(script->translation_buf) > 0) {
+ aFree(VECTOR_POP(script->translation_buf));
}
-
- script->translation_buf = NULL;
- script->translation_buf_size = 0;
+ VECTOR_CLEAR(script->translation_buf);
if( script->languages ) {
for(i = 0; i < script->max_lang_id; i++)
@@ -5135,7 +5574,7 @@ void script_clear_translations(bool reload) {
/**
*
**/
-int script_translation_db_destroyer(union DBKey key, struct DBData *data, va_list ap)
+static int script_translation_db_destroyer(union DBKey key, struct DBData *data, va_list ap)
{
struct DBMap *string_db = DB->data2ptr(data);
@@ -5156,32 +5595,23 @@ int script_translation_db_destroyer(union DBKey key, struct DBData *data, va_lis
/**
*
**/
-void script_parser_clean_leftovers(void) {
- if( script->buf )
- aFree(script->buf);
-
- script->buf = NULL;
- script->size = 0;
+static void script_parser_clean_leftovers(void)
+{
+ VECTOR_CLEAR(script->buf);
if( script->translation_db ) {
script->translation_db->destroy(script->translation_db,script->translation_db_destroyer);
script->translation_db = NULL;
}
- if( script->syntax.strings ) { /* used only when generating translation file */
- db_destroy(script->syntax.strings);
- script->syntax.strings = NULL;
- }
-
- script_string_buf_destroy(&script->parse_simpleexpr_str);
- script_string_buf_destroy(&script->lang_export_line_buf);
- script_string_buf_destroy(&script->lang_export_unescaped_buf);
+ VECTOR_CLEAR(script->parse_simpleexpr_strbuf);
}
/**
* Performs cleanup after all parsing is processed
**/
-int script_parse_cleanup_timer(int tid, int64 tick, int id, intptr_t data) {
+static int script_parse_cleanup_timer(int tid, int64 tick, int id, intptr_t data)
+{
script->parser_clean_leftovers();
script->parse_cleanup_timer_id = INVALID_TIMER;
@@ -5192,8 +5622,10 @@ int script_parse_cleanup_timer(int tid, int64 tick, int id, intptr_t data) {
/*==========================================
* Initialization
*------------------------------------------*/
-void do_init_script(bool minimal) {
+static void do_init_script(bool minimal)
+{
script->parse_cleanup_timer_id = INVALID_TIMER;
+ VECTOR_INIT(script->parse_simpleexpr_strbuf);
script->st_db = idb_alloc(DB_OPT_BASE);
script->userfunc_db = strdb_alloc(DB_OPT_DUP_KEY,0);
@@ -5210,7 +5642,7 @@ void do_init_script(bool minimal) {
VECTOR_INIT(script->hqi);
script->parse_builtin();
- script->read_constdb();
+ script->read_constdb(false);
script->load_parameters();
script->hardcoded_constants();
@@ -5221,7 +5653,7 @@ void do_init_script(bool minimal) {
script->load_translations();
}
-int script_reload(void)
+static int script_reload(void)
{
int i;
struct DBIterator *iter;
@@ -5243,6 +5675,8 @@ int script_reload(void)
script->label_count = 0;
for( i = 0; i < atcommand->binding_count; i++ ) {
+ aFree(atcommand->binding[i]->at_groups);
+ aFree(atcommand->binding[i]->char_groups);
aFree(atcommand->binding[i]);
}
@@ -5260,18 +5694,21 @@ int script_reload(void)
script->parse_cleanup_timer_id = INVALID_TIMER;
}
- mapreg->reload();
-
+ script->read_constdb(true);
itemdb->name_constants();
+ clan->set_constants();
+ mapreg->reload();
sysinfo->vcsrevision_reload();
return 0;
}
/* returns name of current function being run, from within the stack [Ind/Hercules] */
-const char *script_getfuncname(struct script_state *st) {
+static const char *script_getfuncname(struct script_state *st)
+{
struct script_data *data;
+ nullpo_retr(NULL, st);
data = &st->stack->stack_data[st->start];
if( data->type == C_NAME && script->str_data[data->u.num].type == C_FUNC )
@@ -5280,6 +5717,231 @@ const char *script_getfuncname(struct script_state *st) {
return NULL;
}
+/**
+ * Writes a string to a StringBuf by combining a format string and a set of
+ * arguments taken from the current script state (caller script function
+ * arguments).
+ *
+ * @param[in] st Script state (must have at least a string at index
+ * 'start').
+ * @param[in] start Index of the format string argument.
+ * @param[out] out Output string buffer (managed by the caller, must be
+ * already initialized)
+ * @retval false if an error occurs.
+ */
+static bool script_sprintf_helper(struct script_state *st, int start, struct StringBuf *out)
+{
+ const char *format = NULL;
+ const char *p = NULL, *np = NULL;
+ char *buf = NULL;
+ int buf_len = 0;
+ int lastarg = start;
+ int argc = script_lastdata(st) + 1;
+
+ nullpo_retr(-1, out);
+ Assert_retr(-1, start >= 2 && start <= argc);
+ Assert_retr(-1, script_hasdata(st, start));
+
+ p = format = script_getstr(st, start);
+
+ /*
+ * format-string = "" / *(text / placeholder)
+ * placeholder = "%%" / "%n" / std-placeholder
+ * std-placeholder = "%" [pos-parameter] [flags] [width] [precision] [length] type
+ * pos-parameter = number "$"
+ * flags = *("-" / "+" / "0" / SP)
+ * width = number / ("*" [pos-parameter])
+ * precision = "." (number / ("*" [pos-parameter]))
+ * length = "hh" / "h" / "l" / "ll" / "L" / "z" / "j" / "t"
+ * type = "d" / "i" / "u" / "f" / "F" / "e" / "E" / "g" / "G" / "x" / "X" / "o" / "s" / "c" / "p" / "a" / "A"
+ * number = digit-nonzero *DIGIT
+ * digit-nonzero = "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9"
+ */
+
+ while ((np = strchr(p, '%')) != NULL) {
+ bool flag_plus = false, flag_minus = false, flag_zero = false, flag_space = false;
+ bool positional_arg = false;
+ int width = 0, nextarg = lastarg + 1, thisarg = nextarg;
+
+ if (p != np) {
+ int len = (int)(np - p + 1);
+ if (buf_len < len) {
+ RECREATE(buf, char, len);
+ buf_len = len;
+ }
+ safestrncpy(buf, p, len);
+ StrBuf->AppendStr(out, buf);
+ }
+ np++;
+
+ // placeholder = "%%" ; (special case)
+ if (*np == '%') {
+ StrBuf->AppendStr(out, "%");
+ p = np + 1;
+ continue;
+ }
+ // placeholder = "%n" ; (ignored)
+ if (*np == 'n') {
+ ShowWarning("script_sprintf_helper: Format %%n not supported! Skipping...\n");
+ script->reportsrc(st);
+ lastarg = nextarg;
+ p = np + 1;
+ continue;
+ }
+
+ // std-placeholder = "%" [pos-parameter] [flags] [width] [precision] [length] type
+
+ // pos-parameter = number "$"
+ if (ISDIGIT(*np) && *np != '0') {
+ const char *pp = np;
+ while (ISDIGIT(*pp))
+ pp++;
+ if (*pp == '$') {
+ thisarg = atoi(np) + start;
+ positional_arg = true;
+ np = pp + 1;
+ }
+ }
+
+ if (thisarg >= argc) {
+ ShowError("buildin_sprintf: Not enough arguments passed!\n");
+ if (buf != NULL)
+ aFree(buf);
+ return false;
+ }
+
+ // flags = *("-" / "+" / "0" / SP)
+ while (true) {
+ if (*np == '-') {
+ flag_minus = true;
+ } else if (*np == '+') {
+ flag_plus = true;
+ } else if (*np == ' ') {
+ flag_space = true;
+ } else if (*np == '0') {
+ flag_zero = true;
+ } else {
+ break;
+ }
+ np++;
+ }
+
+ // width = number / ("*" [pos-parameter])
+ if (ISDIGIT(*np)) {
+ width = atoi(np);
+ while (ISDIGIT(*np))
+ np++;
+ } else if (*np == '*') {
+ bool positional_widtharg = false;
+ int width_arg;
+ np++;
+ // pos-parameter = number "$"
+ if (ISDIGIT(*np) && *np != '0') {
+ const char *pp = np;
+ while (ISDIGIT(*pp))
+ pp++;
+ if (*pp == '$') {
+ width_arg = atoi(np) + start;
+ positional_widtharg = true;
+ np = pp + 1;
+ }
+ }
+ if (!positional_widtharg) {
+ width_arg = nextarg;
+ nextarg++;
+ if (!positional_arg)
+ thisarg++;
+ }
+
+ if (width_arg >= argc || thisarg >= argc) {
+ ShowError("buildin_sprintf: Not enough arguments passed!\n");
+ if (buf != NULL)
+ aFree(buf);
+ return false;
+ }
+ width = script_getnum(st, width_arg);
+ }
+
+ // precision = "." (number / ("*" [pos-parameter])) ; (not needed/implemented)
+
+ // length = "hh" / "h" / "l" / "ll" / "L" / "z" / "j" / "t" ; (not needed/implemented)
+
+ // type = "d" / "i" / "u" / "f" / "F" / "e" / "E" / "g" / "G" / "x" / "X" / "o" / "s" / "c" / "p" / "a" / "A"
+ if (buf_len < 16) {
+ RECREATE(buf, char, 16);
+ buf_len = 16;
+ }
+ {
+ int i = 0;
+ memset(buf, '\0', buf_len);
+ buf[i++] = '%';
+ if (flag_minus)
+ buf[i++] = '-';
+ if (flag_plus)
+ buf[i++] = '+';
+ else if (flag_space) // ignored if '+' is specified
+ buf[i++] = ' ';
+ if (flag_zero)
+ buf[i++] = '0';
+ if (width > 0)
+ safesnprintf(buf + i, buf_len - i - 1, "%d", width);
+ }
+ buf[(int)strlen(buf)] = *np;
+ switch (*np) {
+ case 'd':
+ case 'i':
+ case 'u':
+ case 'x':
+ case 'X':
+ case 'o':
+ // Piggyback printf
+ StrBuf->Printf(out, buf, script_getnum(st, thisarg));
+ break;
+ case 's':
+ // Piggyback printf
+ StrBuf->Printf(out, buf, script_getstr(st, thisarg));
+ break;
+ case 'c':
+ {
+ const char *str = script_getstr(st, thisarg);
+ // Piggyback printf
+ StrBuf->Printf(out, buf, str[0]);
+ }
+ break;
+ case 'f':
+ case 'F':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ case 'p':
+ case 'a':
+ case 'A':
+ ShowWarning("buildin_sprintf: Format %%%c not supported! Skipping...\n", *np);
+ script->reportsrc(st);
+ lastarg = nextarg;
+ p = np + 1;
+ continue;
+ default:
+ ShowError("buildin_sprintf: Invalid format string.\n");
+ if (buf != NULL)
+ aFree(buf);
+ return false;
+ }
+ lastarg = nextarg;
+ p = np + 1;
+ }
+
+ // Append the remaining part
+ if (p != NULL)
+ StrBuf->AppendStr(out, p);
+
+ if (buf != NULL)
+ aFree(buf);
+
+ return true;
+}
+
//-----------------------------------------------------------------------------
// buildin functions
//
@@ -5292,23 +5954,49 @@ const char *script_getfuncname(struct script_state *st) {
/// If a dialog doesn't exist yet, one is created.
///
/// mes "<message>";
-BUILDIN(mes)
+static BUILDIN(mes)
{
struct map_session_data *sd = script->rid2sd(st);
- if( sd == NULL )
+
+ if (sd == NULL)
return true;
- if( !script_hasdata(st, 3) ) {// only a single line detected in the script
+ if (script_hasdata(st, 2))
clif->scriptmes(sd, st->oid, script_getstr(st, 2));
- } else {// parse multiple lines as they exist
- int i;
+ else
+ clif->scriptmes(sd, st->oid, "");
- for( i = 2; script_hasdata(st, i); i++ ) {
- // send the message to the client
- clif->scriptmes(sd, st->oid, script_getstr(st, i));
- }
+ return true;
+}
+
+/**
+ * Appends a message to the npc dialog, applying format string conversions (see
+ * sprintf).
+ *
+ * If a dialog doesn't exist yet, one is created.
+ *
+ * @code
+ * mes "<message>";
+ * @endcode
+ */
+static BUILDIN(mesf)
+{
+ struct map_session_data *sd = script->rid2sd(st);
+ struct StringBuf buf;
+
+ if (sd == NULL)
+ return true;
+
+ StrBuf->Init(&buf);
+
+ if (!script->sprintf_helper(st, 2, &buf)) {
+ StrBuf->Destroy(&buf);
+ return false;
}
+ clif->scriptmes(sd, st->oid, StrBuf->Value(&buf));
+ StrBuf->Destroy(&buf);
+
return true;
}
@@ -5316,7 +6004,7 @@ BUILDIN(mes)
/// The dialog text is cleared and the script continues when the button is pressed.
///
/// next;
-BUILDIN(next)
+static BUILDIN(next)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
@@ -5329,11 +6017,24 @@ BUILDIN(next)
return true;
}
+/// Clears the NPC dialog and continues the script without press next button.
+///
+/// mesclear();
+static BUILDIN(mesclear)
+{
+ struct map_session_data *sd = script->rid2sd(st);
+
+ if (sd != NULL)
+ clif->scriptclear(sd, st->oid);
+
+ return true;
+}
+
/// Ends the script and displays the button 'close' on the npc dialog.
/// The dialog is closed when the button is pressed.
///
/// close;
-BUILDIN(close)
+static BUILDIN(close)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
@@ -5348,7 +6049,7 @@ BUILDIN(close)
/// The dialog is closed and the script continues when the button is pressed.
///
/// close2;
-BUILDIN(close2)
+static BUILDIN(close2)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
@@ -5368,11 +6069,12 @@ BUILDIN(close2)
/// Counts the number of valid and total number of options in 'str'
/// If max_count > 0 the counting stops when that valid option is reached
/// total is incremented for each option (NULL is supported)
-int menu_countoptions(const char* str, int max_count, int* total)
+static int menu_countoptions(const char *str, int max_count, int *total)
{
int count = 0;
int bogus_total;
+ nullpo_ret(str);
if( total == NULL )
total = &bogus_total;
++(*total);
@@ -5417,7 +6119,7 @@ int menu_countoptions(const char* str, int max_count, int* total)
/// NOTE: the client closes the npc dialog when cancel is pressed
///
/// menu "<option_text>",<target_label>{,"<option_text>",<target_label>,...};
-BUILDIN(menu)
+static BUILDIN(menu)
{
int i;
const char* text;
@@ -5469,11 +6171,11 @@ BUILDIN(menu)
sd->state.menu_or_input = 1;
/* menus beyond this length crash the client (see bugreport:6402) */
- if( StrBuf->Length(&buf) >= 2047 ) {
+ if( StrBuf->Length(&buf) >= MAX_MENU_LENGTH - 1 ) {
struct npc_data * nd = map->id2nd(st->oid);
char* menu;
- CREATE(menu, char, 2048);
- safestrncpy(menu, StrBuf->Value(&buf), 2047);
+ CREATE(menu, char, MAX_MENU_LENGTH);
+ safestrncpy(menu, StrBuf->Value(&buf), MAX_MENU_LENGTH - 1);
ShowWarning("NPC Menu too long! (source:%s / length:%d)\n",nd?nd->name:"Unknown",StrBuf->Length(&buf));
clif->scriptmenu(sd, st->oid, menu);
aFree(menu);
@@ -5482,13 +6184,13 @@ BUILDIN(menu)
StrBuf->Destroy(&buf);
- if( sd->npc_menu >= 0xff )
+ if( sd->npc_menu >= MAX_MENU_OPTIONS )
{// client supports only up to 254 entries; 0 is not used and 255 is reserved for cancel; excess entries are displayed but cause 'uint8' overflow
- ShowWarning("buildin_menu: Too many options specified (current=%d, max=254).\n", sd->npc_menu);
+ ShowWarning("buildin_menu: Too many options specified (current=%d, max=%d).\n", sd->npc_menu, MAX_MENU_OPTIONS - 1);
script->reportsrc(st);
}
}
- else if( sd->npc_menu == 0xff )
+ else if( sd->npc_menu == MAX_MENU_OPTIONS )
{// Cancel was pressed
sd->state.menu_or_input = 0;
st->state = END;
@@ -5526,7 +6228,7 @@ BUILDIN(menu)
st->state = END;
return false;
}
- pc->setreg(sd, script->add_str("@menu"), menu);
+ pc->setreg(sd, script->add_variable("@menu"), menu);
st->pos = script_getnum(st, i + 1);
st->state = GOTO;
}
@@ -5539,7 +6241,7 @@ BUILDIN(menu)
/// select(<option_text>{,<option_text>,...}) -> <selected_option>
///
/// @see menu
-BUILDIN(select)
+static BUILDIN(select)
{
int i;
const char* text;
@@ -5570,11 +6272,11 @@ BUILDIN(select)
sd->state.menu_or_input = 1;
/* menus beyond this length crash the client (see bugreport:6402) */
- if( StrBuf->Length(&buf) >= 2047 ) {
+ if( StrBuf->Length(&buf) >= MAX_MENU_LENGTH - 1 ) {
struct npc_data * nd = map->id2nd(st->oid);
char* menu;
- CREATE(menu, char, 2048);
- safestrncpy(menu, StrBuf->Value(&buf), 2047);
+ CREATE(menu, char, MAX_MENU_LENGTH);
+ safestrncpy(menu, StrBuf->Value(&buf), MAX_MENU_LENGTH - 1);
ShowWarning("NPC Menu too long! (source:%s / length:%d)\n",nd?nd->name:"Unknown",StrBuf->Length(&buf));
clif->scriptmenu(sd, st->oid, menu);
aFree(menu);
@@ -5582,107 +6284,31 @@ BUILDIN(select)
clif->scriptmenu(sd, st->oid, StrBuf->Value(&buf));
StrBuf->Destroy(&buf);
- if( sd->npc_menu >= 0xff ) {
- ShowWarning("buildin_select: Too many options specified (current=%d, max=254).\n", sd->npc_menu);
+ if( sd->npc_menu >= MAX_MENU_OPTIONS ) {
+ ShowWarning("buildin_select: Too many options specified (current=%d, max=%d).\n", sd->npc_menu, MAX_MENU_OPTIONS - 1);
script->reportsrc(st);
}
- } else if( sd->npc_menu == 0xff ) {// Cancel was pressed
+ } else if(sd->npc_menu == MAX_MENU_OPTIONS) { // Cancel was pressed
sd->state.menu_or_input = 0;
- st->state = END;
- } else {// return selected option
- int menu = 0;
-
- sd->state.menu_or_input = 0;
- for( i = 2; i <= script_lastdata(st); ++i ) {
- text = script_getstr(st, i);
- sd->npc_menu -= script->menu_countoptions(text, sd->npc_menu, &menu);
- if( sd->npc_menu <= 0 )
- break;// entry found
- }
- pc->setreg(sd, script->add_str("@menu"), menu);
- script_pushint(st, menu);
- st->state = RUN;
- }
- return true;
-}
-
-/// Displays a menu with options and returns the selected option.
-/// Behaves like 'menu' without the target labels, except when cancel is
-/// pressed.
-/// When cancel is pressed, the script continues and 255 is returned.
-///
-/// prompt(<option_text>{,<option_text>,...}) -> <selected_option>
-///
-/// @see menu
-BUILDIN(prompt)
-{
- int i;
- const char *text;
- struct map_session_data *sd = script->rid2sd(st);
- if (sd == NULL)
- return true;
-
-#ifdef SECURE_NPCTIMEOUT
- sd->npc_idle_type = NPCT_MENU;
-#endif
-
- if( sd->state.menu_or_input == 0 )
- {
- struct StringBuf buf;
-
- StrBuf->Init(&buf);
- sd->npc_menu = 0;
- for( i = 2; i <= script_lastdata(st); ++i )
- {
- text = script_getstr(st, i);
- if( sd->npc_menu > 0 )
- StrBuf->AppendStr(&buf, ":");
- StrBuf->AppendStr(&buf, text);
- sd->npc_menu += script->menu_countoptions(text, 0, NULL);
- }
-
- st->state = RERUNLINE;
- sd->state.menu_or_input = 1;
-
- /* menus beyond this length crash the client (see bugreport:6402) */
- if( StrBuf->Length(&buf) >= 2047 ) {
- struct npc_data * nd = map->id2nd(st->oid);
- char* menu;
- CREATE(menu, char, 2048);
- safestrncpy(menu, StrBuf->Value(&buf), 2047);
- ShowWarning("NPC Menu too long! (source:%s / length:%d)\n",nd?nd->name:"Unknown",StrBuf->Length(&buf));
- clif->scriptmenu(sd, st->oid, menu);
- aFree(menu);
- } else
- clif->scriptmenu(sd, st->oid, StrBuf->Value(&buf));
- StrBuf->Destroy(&buf);
- if( sd->npc_menu >= 0xff )
- {
- ShowWarning("buildin_prompt: Too many options specified (current=%d, max=254).\n", sd->npc_menu);
- script->reportsrc(st);
+ if (strncmp(get_buildin_name(st), "prompt", 6) == 0) {
+ pc->setreg(sd, script->add_variable("@menu"), MAX_MENU_OPTIONS);
+ script_pushint(st, MAX_MENU_OPTIONS); // XXX: we should really be pushing -1 instead
+ st->state = RUN;
+ } else {
+ st->state = END;
}
- }
- else if( sd->npc_menu == 0xff )
- {// Cancel was pressed
- sd->state.menu_or_input = 0;
- pc->setreg(sd, script->add_str("@menu"), 0xff);
- script_pushint(st, 0xff);
- st->state = RUN;
- }
- else
- {// return selected option
+ } else {// return selected option
int menu = 0;
sd->state.menu_or_input = 0;
- for( i = 2; i <= script_lastdata(st); ++i )
- {
+ for( i = 2; i <= script_lastdata(st); ++i ) {
text = script_getstr(st, i);
sd->npc_menu -= script->menu_countoptions(text, sd->npc_menu, &menu);
if( sd->npc_menu <= 0 )
break;// entry found
}
- pc->setreg(sd, script->add_str("@menu"), menu);
+ pc->setreg(sd, script->add_variable("@menu"), menu); // TODO: throw a deprecation warning for scripts using @menu
script_pushint(st, menu);
st->state = RUN;
}
@@ -5696,7 +6322,7 @@ BUILDIN(prompt)
/// Jumps to the target script label.
///
/// goto <label>;
-BUILDIN(goto)
+static BUILDIN(goto)
{
if( !data_islabel(script_getdata(st,2)) )
{
@@ -5714,7 +6340,7 @@ BUILDIN(goto)
/*==========================================
* user-defined function call
*------------------------------------------*/
-BUILDIN(callfunc)
+static BUILDIN(callfunc)
{
int i, j;
struct script_retinfo* ri;
@@ -5774,7 +6400,7 @@ BUILDIN(callfunc)
/*==========================================
* subroutine call
*------------------------------------------*/
-BUILDIN(callsub)
+static BUILDIN(callsub)
{
int i,j;
struct script_retinfo* ri;
@@ -5827,7 +6453,7 @@ BUILDIN(callsub)
/// If the argument doesn't exist
///
/// getarg(<index>{,<default_value>}) -> <value>
-BUILDIN(getarg)
+static BUILDIN(getarg)
{
struct script_retinfo* ri;
int idx;
@@ -5861,7 +6487,8 @@ BUILDIN(getarg)
///
/// return;
/// return <value>;
-BUILDIN(return) {
+static BUILDIN(return)
+{
st->state = RETFUNC;
if( st->stack->defsp < 1 || st->stack->stack_data[st->stack->defsp-1].type != C_RETINFO ) {
@@ -5911,7 +6538,7 @@ BUILDIN(return) {
/// If <min> is greater than <max>, their numbers are switched.
/// rand(<range>) -> <int>
/// rand(<min>,<max>) -> <int>
-BUILDIN(rand)
+static BUILDIN(rand)
{
int range;
int min;
@@ -5940,7 +6567,7 @@ BUILDIN(rand)
/*==========================================
* Warp sd to str,x,y or Random or SavePoint/Save
*------------------------------------------*/
-BUILDIN(warp)
+static BUILDIN(warp)
{
int ret;
int x,y;
@@ -5976,7 +6603,7 @@ BUILDIN(warp)
/*==========================================
* Warp a specified area
*------------------------------------------*/
-int buildin_areawarp_sub(struct block_list *bl, va_list ap)
+static int buildin_areawarp_sub(struct block_list *bl, va_list ap)
{
int x2,y2,x3,y3;
unsigned int index;
@@ -5996,6 +6623,9 @@ int buildin_areawarp_sub(struct block_list *bl, va_list ap)
pc->randomwarp(sd, CLR_TELEPORT);
} else if (x3 != 0 && y3 != 0) {
int max, tx, ty, j = 0;
+ int16 m;
+
+ m = map->mapindex2mapid(index);
// choose a suitable max number of attempts
if( (max = (y3-y2+1)*(x3-x2+1)*3) > 1000 )
@@ -6006,7 +6636,7 @@ int buildin_areawarp_sub(struct block_list *bl, va_list ap)
tx = rnd()%(x3-x2+1)+x2;
ty = rnd()%(y3-y2+1)+y2;
j++;
- } while (map->getcell(index, bl, tx, ty, CELL_CHKNOPASS) && j < max);
+ } while (map->getcell(m, bl, tx, ty, CELL_CHKNOPASS) && j < max);
pc->setpos(sd, index, tx, ty, CLR_OUTSIGHT);
} else {
@@ -6014,7 +6644,7 @@ int buildin_areawarp_sub(struct block_list *bl, va_list ap)
}
return 0;
}
-BUILDIN(areawarp)
+static BUILDIN(areawarp)
{
int16 m, x0,y0,x1,y1, x2,y2,x3=0,y3=0;
unsigned int index;
@@ -6056,7 +6686,7 @@ BUILDIN(areawarp)
/*==========================================
* areapercentheal <map>,<x1>,<y1>,<x2>,<y2>,<hp>,<sp>
*------------------------------------------*/
-int buildin_areapercentheal_sub(struct block_list *bl, va_list ap)
+static int buildin_areapercentheal_sub(struct block_list *bl, va_list ap)
{
int hp = va_arg(ap, int);
int sp = va_arg(ap, int);
@@ -6070,7 +6700,8 @@ int buildin_areapercentheal_sub(struct block_list *bl, va_list ap)
return 0;
}
-BUILDIN(areapercentheal) {
+static BUILDIN(areapercentheal)
+{
int hp,sp,m;
const char *mapname;
int x0,y0,x1,y1;
@@ -6096,7 +6727,8 @@ BUILDIN(areapercentheal) {
* another player npc-session.
* Using: warpchar "mapname",x,y,Char_ID;
*------------------------------------------*/
-BUILDIN(warpchar) {
+static BUILDIN(warpchar)
+{
int x,y,a;
const char *str;
struct map_session_data *sd;
@@ -6120,160 +6752,209 @@ BUILDIN(warpchar) {
return true;
}
-/*==========================================
- * Warpparty - [Fredzilla] [Paradox924X]
- * Syntax: warpparty "to_mapname",x,y,Party_ID,{"from_mapname"};
- * If 'from_mapname' is specified, only the party members on that map will be warped
- *------------------------------------------*/
-BUILDIN(warpparty)
+
+/**
+ * Warps a party to a specific/random map or save point.
+ *
+ * @code{.herc}
+ * warpparty("<to map name>", <x>, <y>, <party id>{{, <ignore mapflags>}, "<from map name>"{, <include leader>}});
+ * @endcode
+ *
+ **/
+static BUILDIN(warpparty)
{
- struct map_session_data *sd = NULL;
- struct map_session_data *pl_sd;
- struct party_data* p;
- int type;
- int map_index;
- int i;
+ const int p_id = script_getnum(st, 5);
+ struct party_data *p = party->search(p_id);
- const char* str = script_getstr(st,2);
- int x = script_getnum(st,3);
- int y = script_getnum(st,4);
- int p_id = script_getnum(st,5);
- const char* str2 = NULL;
- if ( script_hasdata(st,6) )
- str2 = script_getstr(st,6);
+ if (p == NULL) {
+ ShowError("script:%s: Party not found! (%d)\n", script->getfuncname(st), p_id);
+ script_pushint(st, 0);
+ return false;
+ }
- p = party->search(p_id);
- if(!p)
- return true;
+ const char *m_name_to = script_getstr(st, 2);
+ const int type = (strcmp(m_name_to, "Random") == 0) ? 0 :
+ (strcmp(m_name_to, "SavePointAll") == 0) ? 1 :
+ (strcmp(m_name_to, "SavePoint") == 0) ? 2 :
+ (strcmp(m_name_to, "Leader") == 0) ? 3 : 4;
+ int map_index = 0;
- type = ( strcmp(str,"Random")==0 ) ? 0
- : ( strcmp(str,"SavePointAll")==0 ) ? 1
- : ( strcmp(str,"SavePoint")==0 ) ? 2
- : ( strcmp(str,"Leader")==0 ) ? 3
- : 4;
+ if (type == 4 && (map_index = script->mapindexname2id(st, m_name_to)) == 0) {
+ ShowError("script:%s: Target map not found! (%s)\n", script->getfuncname(st), m_name_to);
+ script_pushint(st, 0);
+ return false;
+ }
- switch (type)
- {
- case 3:
- for(i = 0; i < MAX_PARTY && !p->party.member[i].leader; i++);
- if (i == MAX_PARTY || !p->data[i].sd) //Leader not found / not online
- return true;
- pl_sd = p->data[i].sd;
- map_index = pl_sd->mapindex;
- x = pl_sd->bl.x;
- y = pl_sd->bl.y;
- break;
- case 4:
- map_index = script->mapindexname2id(st,str);
- break;
- case 2:
- //"SavePoint" uses save point of the currently attached player
- if (( sd = script->rid2sd(st) ) == NULL )
- return true;
- /* Fall through */
- default:
- map_index = 0;
- break;
+ int x = script_getnum(st, 3);
+ int y = script_getnum(st, 4);
+ struct map_session_data *p_sd;
+
+ if (type == 3) {
+ int idx;
+
+ ARR_FIND(0, MAX_PARTY, idx, p->party.member[idx].leader == 1);
+
+ if (idx == MAX_PARTY || (p_sd = p->data[idx].sd) == NULL) {
+ ShowError("script:%s: Party leader not found!\n", script->getfuncname(st));
+ script_pushint(st, 0);
+ return false;
+ }
+
+ map_index = p_sd->mapindex;
+ x = p_sd->bl.x;
+ y = p_sd->bl.y;
+ } else if (type == 2) {
+ struct map_session_data *sd = script->rid2sd(st);
+
+ if (sd == NULL) {
+ ShowError("script:%s: No character attached for warp to save point!\n",
+ script->getfuncname(st));
+ script_pushint(st, 0);
+ return false;
+ }
+
+ map_index = sd->status.save_point.map;
+ x = sd->status.save_point.x;
+ y = sd->status.save_point.y;
}
- for (i = 0; i < MAX_PARTY; i++) {
- if( !(pl_sd = p->data[i].sd) || pl_sd->status.party_id != p_id )
+ const int offset = (script_hasdata(st, 6) && script_isinttype(st, 6)) ? 1 : 0;
+ const bool ignore_mapflags = (offset == 1 && script_getnum(st, 6) != 0);
+ const char *m_name_from = script_hasdata(st, 6 + offset) ? script_getstr(st, 6 + offset) : NULL;
+ const bool include_leader = script_hasdata(st, 7 + offset) ? script_getnum(st, 7 + offset) : true;
+
+ if (m_name_from != NULL && script->mapindexname2id(st, m_name_from) == 0) {
+ ShowError("script:%s: Source map not found! (%s)\n", script->getfuncname(st), m_name_from);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ for (int i = 0; i < MAX_PARTY; i++) {
+ if ((p_sd = p->data[i].sd) == NULL || p_sd->status.party_id != p_id || pc_isdead(p_sd))
continue;
- if( str2 && strcmp(str2, map->list[pl_sd->bl.m].name) != 0 )
+ if (p->party.member[i].online == 0 || (!include_leader && p->party.member[i].leader == 1))
continue;
- if( pc_isdead(pl_sd) )
+ if (m_name_from != NULL && strcmp(m_name_from, map->list[p_sd->bl.m].name) != 0)
continue;
- switch( type )
- {
- case 0: // Random
- if(!map->list[pl_sd->bl.m].flag.nowarp)
- pc->randomwarp(pl_sd,CLR_TELEPORT);
- break;
- case 1: // SavePointAll
- if(!map->list[pl_sd->bl.m].flag.noreturn)
- pc->setpos(pl_sd,pl_sd->status.save_point.map,pl_sd->status.save_point.x,pl_sd->status.save_point.y,CLR_TELEPORT);
- break;
- case 2: // SavePoint
- if(!map->list[pl_sd->bl.m].flag.noreturn)
- pc->setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
- break;
- case 3: // Leader
- case 4: // m,x,y
- if(!map->list[pl_sd->bl.m].flag.noreturn && !map->list[pl_sd->bl.m].flag.nowarp)
- pc->setpos(pl_sd,map_index,x,y,CLR_TELEPORT);
- break;
+ if (!ignore_mapflags) {
+ if (((type == 0 || type > 2) && map->list[p_sd->bl.m].flag.nowarp == 1) ||
+ (type > 0 && map->list[p_sd->bl.m].flag.noreturn == 1))
+ continue;
+ }
+
+ if (type == 1) {
+ map_index = p_sd->status.save_point.map;
+ x = p_sd->status.save_point.x;
+ y = p_sd->status.save_point.y;
}
+
+ if (type > 0)
+ pc->setpos(p_sd, map_index, x, y, CLR_TELEPORT);
+ else
+ pc->randomwarp(p_sd, CLR_TELEPORT);
}
+ script_pushint(st, 1);
return true;
}
-/*==========================================
- * Warpguild - [Fredzilla]
- * Syntax: warpguild "mapname",x,y,Guild_ID;
- *------------------------------------------*/
-BUILDIN(warpguild)
+
+/**
+ * Warps a guild to a specific/random map or save point.
+ *
+ * @code{.herc}
+ * warpguild("<to map name>", <x>, <y>, <guild id>{{, <ignore mapflags>}, "<from map name>"});
+ * @endcode
+ *
+ **/
+static BUILDIN(warpguild)
{
- struct map_session_data *sd = NULL;
- struct map_session_data *pl_sd;
- struct guild* g;
- struct s_mapiterator* iter;
- int type;
+ const int g_id = script_getnum(st, 5);
+ struct guild *g = guild->search(g_id);
- const char* str = script_getstr(st,2);
- int x = script_getnum(st,3);
- int y = script_getnum(st,4);
- int gid = script_getnum(st,5);
+ if (g == NULL) {
+ ShowError("script:%s: Guild not found! (%d)\n", script->getfuncname(st), g_id);
+ script_pushint(st, 0);
+ return false;
+ }
- g = guild->search(gid);
- if( g == NULL )
- return true;
+ const char *m_name_to = script_getstr(st, 2);
+ const int type = (strcmp(m_name_to, "Random") == 0) ? 0 :
+ (strcmp(m_name_to, "SavePointAll") == 0) ? 1 :
+ (strcmp(m_name_to, "SavePoint") == 0) ? 2 : 3;
+ int map_index = 0;
- type = ( strcmp(str,"Random")==0 ) ? 0
- : ( strcmp(str,"SavePointAll")==0 ) ? 1
- : ( strcmp(str,"SavePoint")==0 ) ? 2
- : 3;
+ if (type == 3 && (map_index = script->mapindexname2id(st, m_name_to)) == 0) {
+ ShowError("script:%s: Target map not found! (%s)\n", script->getfuncname(st), m_name_to);
+ script_pushint(st, 0);
+ return false;
+ }
- if( type == 2 && ( sd = script->rid2sd(st) ) == NULL )
- {// "SavePoint" uses save point of the currently attached player
- return true;
+ int x = script_getnum(st, 3);
+ int y = script_getnum(st, 4);
+
+ if (type == 2) {
+ struct map_session_data *sd = script->rid2sd(st);
+
+ if (sd == NULL) {
+ ShowError("script:%s: No character attached for warp to save point!\n",
+ script->getfuncname(st));
+ script_pushint(st, 0);
+ return false;
+ }
+
+ map_index = sd->status.save_point.map;
+ x = sd->status.save_point.x;
+ y = sd->status.save_point.y;
}
- iter = mapit_getallusers();
- for (pl_sd = BL_UCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); pl_sd = BL_UCAST(BL_PC, mapit->next(iter))) {
- if( pl_sd->status.guild_id != gid )
+ const int offset = (script_hasdata(st, 6) && script_isinttype(st, 6)) ? 1 : 0;
+ const bool ignore_mapflags = (offset == 1 && script_getnum(st, 6) != 0);
+ const char *m_name_from = script_hasdata(st, 6 + offset) ? script_getstr(st, 6 + offset) : NULL;
+
+ if (m_name_from != NULL && script->mapindexname2id(st, m_name_from) == 0) {
+ ShowError("script:%s: Source map not found! (%s)\n", script->getfuncname(st), m_name_from);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ for (int i = 0; i < MAX_GUILD; i++) {
+ struct map_session_data *g_sd = g->member[i].sd;
+
+ if (g->member[i].online == 0 || g_sd == NULL || g_sd->status.guild_id != g_id || pc_isdead(g_sd))
continue;
- switch( type )
- {
- case 0: // Random
- if(!map->list[pl_sd->bl.m].flag.nowarp)
- pc->randomwarp(pl_sd,CLR_TELEPORT);
- break;
- case 1: // SavePointAll
- if(!map->list[pl_sd->bl.m].flag.noreturn)
- pc->setpos(pl_sd,pl_sd->status.save_point.map,pl_sd->status.save_point.x,pl_sd->status.save_point.y,CLR_TELEPORT);
- break;
- case 2: // SavePoint
- if(!map->list[pl_sd->bl.m].flag.noreturn)
- pc->setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
- break;
- case 3: // m,x,y
- if(!map->list[pl_sd->bl.m].flag.noreturn && !map->list[pl_sd->bl.m].flag.nowarp)
- pc->setpos(pl_sd,script->mapindexname2id(st,str),x,y,CLR_TELEPORT);
- break;
+ if (m_name_from != NULL && strcmp(m_name_from, map->list[g_sd->bl.m].name) != 0)
+ continue;
+
+ if (!ignore_mapflags) {
+ if (((type == 0 || type > 2) && map->list[g_sd->bl.m].flag.nowarp == 1) ||
+ (type > 0 && map->list[g_sd->bl.m].flag.noreturn == 1))
+ continue;
+ }
+
+ if (type == 1) {
+ map_index = g_sd->status.save_point.map;
+ x = g_sd->status.save_point.x;
+ y = g_sd->status.save_point.y;
}
+
+ if (type > 0)
+ pc->setpos(g_sd, map_index, x, y, CLR_TELEPORT);
+ else
+ pc->randomwarp(g_sd, CLR_TELEPORT);
}
- mapit->free(iter);
+ script_pushint(st, 1);
return true;
}
+
/*==========================================
* Force Heal a player (hp and sp)
*------------------------------------------*/
-BUILDIN(heal)
+static BUILDIN(heal)
{
int hp,sp;
struct map_session_data *sd = script->rid2sd(st);
@@ -6282,13 +6963,13 @@ BUILDIN(heal)
hp=script_getnum(st,2);
sp=script_getnum(st,3);
- status->heal(&sd->bl, hp, sp, 1);
+ status->heal(&sd->bl, hp, sp, STATUS_HEAL_FORCED);
return true;
}
/*==========================================
* Heal a player by item (get vit bonus etc)
*------------------------------------------*/
-BUILDIN(itemheal)
+static BUILDIN(itemheal)
{
struct map_session_data *sd;
int hp,sp;
@@ -6303,14 +6984,15 @@ BUILDIN(itemheal)
}
sd = script->rid2sd(st);
- if (!sd) return true;
+ if (sd == NULL)
+ return true;
pc->itemheal(sd,sd->itemid,hp,sp);
return true;
}
/*==========================================
*
*------------------------------------------*/
-BUILDIN(percentheal)
+static BUILDIN(percentheal)
{
int hp,sp;
struct map_session_data *sd;
@@ -6325,33 +7007,36 @@ BUILDIN(percentheal)
}
sd = script->rid2sd(st);
- if( sd == NULL )
+ if (sd == NULL)
return true;
#ifdef RENEWAL
if( sd->sc.data[SC_EXTREMITYFIST2] )
sp = 0;
#endif
- pc->percentheal(sd,hp,sp);
+ if (sd->sc.data[SC_BITESCAR]) {
+ hp = 0;
+ }
+ pc->percentheal(sd, hp, sp);
return true;
}
/*==========================================
*
*------------------------------------------*/
-BUILDIN(jobchange)
+static BUILDIN(jobchange)
{
- int job, upper=-1;
+ int class, upper=-1;
- job=script_getnum(st,2);
+ class = script_getnum(st,2);
if( script_hasdata(st,3) )
upper=script_getnum(st,3);
- if (pc->db_checkid(job)) {
+ if (pc->db_checkid(class)) {
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
return true;
- pc->jobchange(sd, job, upper);
+ pc->jobchange(sd, class, upper);
}
return true;
@@ -6360,66 +7045,67 @@ BUILDIN(jobchange)
/*==========================================
*
*------------------------------------------*/
-BUILDIN(jobname)
+static BUILDIN(jobname)
{
- int class_=script_getnum(st,2);
- script_pushconststr(st, pc->job_name(class_));
+ int class = script_getnum(st,2);
+ script_pushconststr(st, pc->job_name(class));
return true;
}
-/// Get input from the player.
-/// For numeric inputs the value is capped to the range [min,max]. Returns 1 if
-/// the value was higher than 'max', -1 if lower than 'min' and 0 otherwise.
-/// For string inputs it returns 1 if the string was longer than 'max', -1 is
-/// shorter than 'min' and 0 otherwise.
-///
-/// input(<var>{,<min>{,<max>}}) -> <int>
-BUILDIN(input)
+/*
+ * Get input from the player.
+ * For numeric inputs the value is capped to the range [min,max]. Returns 1 if
+ * the value was higher than 'max', -1 if lower than 'min' and 0 otherwise.
+ * For string inputs it returns 1 if the string was longer than 'max', -1 is
+ * shorter than 'min' and 0 otherwise.
+ *
+ * input(<var>{,<min>{,<max>}}) -> <int>
+ */
+static BUILDIN(input)
{
- struct script_data* data;
- int64 uid;
- const char* name;
- int min;
- int max;
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
return true;
- data = script_getdata(st,2);
- if( !data_isreference(data) ) {
+ struct script_data *data = script_getdata(st, 2);
+ if (!data_isreference(data)) {
ShowError("script:input: not a variable\n");
script->reportdata(data);
st->state = END;
return false;
}
- uid = reference_getuid(data);
- name = reference_getname(data);
- min = (script_hasdata(st,3) ? script_getnum(st,3) : script->config.input_min_value);
- max = (script_hasdata(st,4) ? script_getnum(st,4) : script->config.input_max_value);
+
+ int64 uid = reference_getuid(data);
+ const char *name = reference_getname(data);
+ int min = (script_hasdata(st, 3) ? script_getnum(st, 3) : script->config.input_min_value);
+ int max = (script_hasdata(st, 4) ? script_getnum(st, 4) : script->config.input_max_value);
#ifdef SECURE_NPCTIMEOUT
sd->npc_idle_type = NPCT_WAIT;
#endif
- if( !sd->state.menu_or_input ) {
+ if (!sd->state.menu_or_input) {
// first invocation, display npc input box
sd->state.menu_or_input = 1;
st->state = RERUNLINE;
- if( is_string_variable(name) )
- clif->scriptinputstr(sd,st->oid);
- else
- clif->scriptinput(sd,st->oid);
+ if (is_string_variable(name)) {
+ clif->scriptinputstr(sd, st->oid);
+ } else {
+ sd->npc_amount_min = min;
+ sd->npc_amount_max = max;
+ clif->scriptinput(sd, st->oid);
+ }
} else {
// take received text/value and store it in the designated variable
sd->state.menu_or_input = 0;
if (is_string_variable(name)) {
int len = (int)strlen(sd->npc_str);
- script->set_reg(st, sd, uid, name, sd->npc_str, script_getref(st,2));
+ script->set_reg(st, sd, uid, name, sd->npc_str, script_getref(st, 2));
script_pushint(st, (len > max ? 1 : len < min ? -1 : 0));
} else {
int amount = sd->npc_amount;
script->set_reg(st, sd, uid, name, (const void *)h64BPTRSIZE(cap_value(amount,min,max)), script_getref(st,2));
- script_pushint(st, (amount > max ? 1 : amount < min ? -1 : 0));
+ script_pushint(st, sd->npc_input_capped_range);
}
st->state = RUN;
}
@@ -6427,13 +7113,13 @@ BUILDIN(input)
}
// declare the copyarray method here for future reference
-BUILDIN(copyarray);
+static BUILDIN(copyarray);
/// Sets the value of a variable.
/// The value is converted to the type of the variable.
///
/// set(<variable>,<value>) -> <variable>
-BUILDIN(__setr)
+static BUILDIN(__setr)
{
struct map_session_data *sd = NULL;
struct script_data* data;
@@ -6441,6 +7127,7 @@ BUILDIN(__setr)
int64 num;
const char* name;
char prefix;
+ struct reg_db *ref;
data = script_getdata(st,2);
//datavalue = script_getdata(st,3);
@@ -6453,11 +7140,11 @@ BUILDIN(__setr)
num = reference_getuid(data);
name = reference_getname(data);
+ ref = reference_getref(data);
prefix = *name;
if (not_server_variable(prefix)) {
- sd = script->rid2sd(st);
- if (sd == NULL) {
+ if (ref == NULL && (sd = script->rid2sd(st)) == NULL) {
ShowError("script:set: no player attached for player variable '%s'\n", name);
return true;
}
@@ -6505,9 +7192,9 @@ BUILDIN(__setr)
}
if (is_string_variable(name))
- script->set_reg(st, sd, num, name, script_getstr(st, 3), script_getref(st, 2));
+ script->set_reg(st, sd, num, name, script_getstr(st, 3), ref);
else
- script->set_reg(st, sd, num, name, (const void *)h64BPTRSIZE(script_getnum(st, 3)), script_getref(st, 2));
+ script->set_reg(st, sd, num, name, (const void *)h64BPTRSIZE(script_getnum(st, 3)), ref);
return true;
}
@@ -6520,7 +7207,7 @@ BUILDIN(__setr)
/// ex: setarray arr[1],1,2,3;
///
/// setarray <array variable>,<value1>{,<value2>...};
-BUILDIN(setarray)
+static BUILDIN(setarray)
{
struct script_data* data;
const char* name;
@@ -6570,7 +7257,7 @@ BUILDIN(setarray)
/// ex: cleararray arr[0],0,1;
///
/// cleararray <array variable>,<value>,<count>;
-BUILDIN(cleararray)
+static BUILDIN(cleararray)
{
struct script_data* data;
const char* name;
@@ -6618,7 +7305,7 @@ BUILDIN(cleararray)
/// ex: copyarray arr[0],arr[2],2;
///
/// copyarray <destination array variable>,<source array variable>,<count>;
-BUILDIN(copyarray)
+static BUILDIN(copyarray)
{
struct script_data* data1;
struct script_data* data2;
@@ -6705,7 +7392,7 @@ BUILDIN(copyarray)
/// ex: getarraysize(arr[3])
///
/// getarraysize(<array variable>) -> <int>
-BUILDIN(getarraysize)
+static BUILDIN(getarraysize)
{
struct script_data* data;
@@ -6722,17 +7409,33 @@ BUILDIN(getarraysize)
script_pushint(st, script->array_highest_key(st,st->rid ? script->rid2sd(st) : NULL,reference_getname(data),reference_getref(data)));
return true;
}
-int script_array_index_cmp(const void *a, const void *b)
+static int script_array_index_cmp(const void *a, const void *b)
{
return (*(const unsigned int *)a - *(const unsigned int *)b); // FIXME: Is the unsigned difference really intended here?
}
+static BUILDIN(getarrayindex)
+{
+ struct script_data *data = script_getdata(st, 2);
+
+ if (!data_isreference(data) || reference_toconstant(data))
+ {
+ ShowError("script:getarrayindex: not a variable\n");
+ script->reportdata(data);
+ st->state = END;
+ return false;// not a variable
+ }
+
+ script_pushint(st, reference_getindex(data));
+ return true;
+}
+
/// Deletes count or all the elements in an array, from the starting index.
/// ex: deletearray arr[4],2;
///
/// deletearray <array variable>;
/// deletearray <array variable>,<count>;
-BUILDIN(deletearray)
+static BUILDIN(deletearray)
{
struct script_data* data;
const char* name;
@@ -6846,7 +7549,7 @@ BUILDIN(deletearray)
/// Equivalent to var[index].
///
/// getelementofarray(<array variable>,<index>) -> <variable reference>
-BUILDIN(getelementofarray)
+static BUILDIN(getelementofarray)
{
struct script_data* data;
int32 id;
@@ -6865,7 +7568,7 @@ BUILDIN(getelementofarray)
id = reference_getid(data);
i = script_getnum(st, 3);
- if (i < 0 || i >= SCRIPT_MAX_ARRAYSIZE) {
+ if (i < 0 || i > SCRIPT_MAX_ARRAYSIZE) {
ShowWarning("script:getelementofarray: index out of range (%"PRId64")\n", i);
script->reportdata(data);
script_pushnil(st);
@@ -6884,7 +7587,7 @@ BUILDIN(getelementofarray)
/*==========================================
*
*------------------------------------------*/
-BUILDIN(setlook)
+static BUILDIN(setlook)
{
int type,val;
struct map_session_data *sd;
@@ -6901,7 +7604,7 @@ BUILDIN(setlook)
return true;
}
-BUILDIN(changelook)
+static BUILDIN(changelook)
{ // As setlook but only client side
int type,val;
struct map_session_data *sd;
@@ -6921,7 +7624,7 @@ BUILDIN(changelook)
/*==========================================
*
*------------------------------------------*/
-BUILDIN(cutin)
+static BUILDIN(cutin)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
@@ -6934,7 +7637,7 @@ BUILDIN(cutin)
/*==========================================
*
*------------------------------------------*/
-BUILDIN(viewpoint)
+static BUILDIN(viewpoint)
{
int type,x,y,id,color;
struct map_session_data *sd;
@@ -6957,8 +7660,8 @@ BUILDIN(viewpoint)
/*==========================================
*
*------------------------------------------*/
-BUILDIN(countitem) {
- int nameid, i;
+static BUILDIN(countitem)
+{
int count = 0;
struct item_data* id = NULL;
@@ -6980,11 +7683,12 @@ BUILDIN(countitem) {
return false;
}
- nameid = id->nameid;
+ int nameid = id->nameid;
- for(i = 0; i < MAX_INVENTORY; i++)
- if(sd->status.inventory[i].nameid == nameid)
+ for (int i = 0; i < sd->status.inventorySize; i++) {
+ if (sd->status.inventory[i].nameid == nameid)
count += sd->status.inventory[i].amount;
+ }
script_pushint(st,count);
return true;
@@ -6994,10 +7698,10 @@ BUILDIN(countitem) {
* countitem2(nameID,Identified,Refine,Attribute,Card0,Card1,Card2,Card3) [Lupus]
* returns number of items that meet the conditions
*------------------------------------------*/
-BUILDIN(countitem2) {
+static BUILDIN(countitem2)
+{
int nameid, iden, ref, attr, c1, c2, c3, c4;
int count = 0;
- int i;
struct item_data* id = NULL;
struct map_session_data *sd = script->rid2sd(st);
@@ -7022,12 +7726,12 @@ BUILDIN(countitem2) {
iden = script_getnum(st,3);
ref = script_getnum(st,4);
attr = script_getnum(st,5);
- c1 = (short)script_getnum(st,6);
- c2 = (short)script_getnum(st,7);
- c3 = (short)script_getnum(st,8);
- c4 = (short)script_getnum(st,9);
+ c1 = script_getnum(st,6);
+ c2 = script_getnum(st,7);
+ c3 = script_getnum(st,8);
+ c4 = script_getnum(st,9);
- for(i = 0; i < MAX_INVENTORY; i++)
+ for (int i = 0; i < sd->status.inventorySize; i++)
if (sd->status.inventory[i].nameid > 0 && sd->inventory_data[i] != NULL &&
sd->status.inventory[i].amount > 0 && sd->status.inventory[i].nameid == nameid &&
sd->status.inventory[i].identify == iden && sd->status.inventory[i].refine == ref &&
@@ -7042,13 +7746,72 @@ BUILDIN(countitem2) {
}
/*==========================================
+ * countnameditem(item ID, { <Char Name / ID> })
+ * returns number of named items.
+ *------------------------------------------*/
+static BUILDIN(countnameditem)
+{
+ int count = 0;
+ struct item_data* id = NULL;
+ struct map_session_data *sd;
+
+ if (script_hasdata(st, 3)) {
+ if (script_isstringtype(st, 3)) {
+ // Character name was given
+ sd = script->nick2sd(st, script_getstr(st, 3));
+ } else {
+ // Character ID was given
+ sd = script->charid2sd(st, script_getnum(st, 3));
+ }
+ } else {
+ // Use RID by default if no name was provided
+ sd = script->rid2sd(st);
+ }
+
+ // Player not attached
+ if (sd == NULL) {
+ return true;
+ }
+
+ if (script_isstringtype(st, 2)) {
+ // Get item from DB via item name
+ id = itemdb->search_name(script_getstr(st, 2));
+ } else {
+ // Get item from DB via item ID
+ id = itemdb->exists(script_getnum(st, 2));
+ }
+
+ if (id == NULL) {
+ ShowError("buildin_countnameditem: Invalid item '%s'.\n", script_getstr(st, 2)); // returns string, regardless of what it was
+ script_pushint(st, 0);
+ return false;
+ }
+
+ for (int i = 0; i < MAX_INVENTORY; i++) {
+ if (sd->status.inventory[i].nameid > 0 &&
+ sd->inventory_data[i] != NULL &&
+ sd->status.inventory[i].amount > 0 &&
+ sd->status.inventory[i].nameid == id->nameid &&
+ sd->status.inventory[i].card[0] == CARD0_CREATE &&
+ sd->status.inventory[i].card[2] == sd->status.char_id &&
+ sd->status.inventory[i].card[3] == sd->status.char_id >> 16)
+ {
+ count += sd->status.inventory[i].amount;
+ }
+ }
+
+ script_pushint(st, count);
+ return true;
+}
+
+/*==========================================
* Check if item with this amount can fit in inventory
* Checking : weight, stack amount >32k, slots amount >(MAX_INVENTORY)
* Return
* 0 : fail
* 1 : success (npc side only)
*------------------------------------------*/
-BUILDIN(checkweight)
+static BUILDIN(checkweight)
{
int slots, amount2=0;
unsigned int weight=0, i, nbargs;
@@ -7130,7 +7893,7 @@ BUILDIN(checkweight)
return true;
}
-BUILDIN(checkweight2)
+static BUILDIN(checkweight2)
{
//variable sub checkweight
int i=0, amount2=0, slots=0, weight=0;
@@ -7234,7 +7997,8 @@ BUILDIN(checkweight2)
* getitembound <item id>,<amount>,<type>{,<account ID>};
* getitembound "<item id>",<amount>,<type>{,<account ID>};
*------------------------------------------*/
-BUILDIN(getitem) {
+static BUILDIN(getitem)
+{
int nameid,amount,get_count,i,flag = 0, offset = 0;
struct item it;
struct map_session_data *sd;
@@ -7308,7 +8072,7 @@ BUILDIN(getitem) {
if ((flag = pc->additem(sd, &it, get_count, LOG_TYPE_SCRIPT))) {
clif->additem(sd, 0, 0, flag);
if( pc->candrop(sd,&it) )
- map->addflooritem(&sd->bl, &it, get_count, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0);
+ map->addflooritem(&sd->bl, &it, get_count, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0, false);
}
}
}
@@ -7319,7 +8083,7 @@ BUILDIN(getitem) {
/*==========================================
*
*------------------------------------------*/
-BUILDIN(getitem2)
+static BUILDIN(getitem2)
{
int nameid,amount,flag = 0, offset = 0;
int iden,ref,attr,c1,c2,c3,c4, bound = 0;
@@ -7357,10 +8121,10 @@ BUILDIN(getitem2)
iden=script_getnum(st,4);
ref=script_getnum(st,5);
attr=script_getnum(st,6);
- c1=(short)script_getnum(st,7);
- c2=(short)script_getnum(st,8);
- c3=(short)script_getnum(st,9);
- c4=(short)script_getnum(st,10);
+ c1 = script_getnum(st,7);
+ c2 = script_getnum(st,8);
+ c3 = script_getnum(st,9);
+ c4 = script_getnum(st,10);
if (bound && (itemdb_type(nameid) == IT_PETEGG || itemdb_type(nameid) == IT_PETARMOR)) {
ShowError("script_getitembound2: can't bind a pet egg/armor! Type=%d\n",bound);
@@ -7399,10 +8163,10 @@ BUILDIN(getitem2)
item_tmp.refine=ref;
item_tmp.attribute=attr;
item_tmp.bound=(unsigned char)bound;
- item_tmp.card[0]=(short)c1;
- item_tmp.card[1]=(short)c2;
- item_tmp.card[2]=(short)c3;
- item_tmp.card[3]=(short)c4;
+ item_tmp.card[0] = c1;
+ item_tmp.card[1] = c2;
+ item_tmp.card[2] = c3;
+ item_tmp.card[3] = c4;
//Check if it's stackable.
if (!itemdb->isstackable(nameid))
@@ -7416,7 +8180,7 @@ BUILDIN(getitem2)
if ((flag = pc->additem(sd, &item_tmp, get_count, LOG_TYPE_SCRIPT))) {
clif->additem(sd, 0, 0, flag);
if( pc->candrop(sd,&item_tmp) )
- map->addflooritem(&sd->bl, &item_tmp, get_count, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0);
+ map->addflooritem(&sd->bl, &item_tmp, get_count, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0, false);
}
}
}
@@ -7429,7 +8193,8 @@ BUILDIN(getitem2)
* rentitem <item id>,<seconds>
* rentitem "<item name>",<seconds>
*------------------------------------------*/
-BUILDIN(rentitem) {
+static BUILDIN(rentitem)
+{
struct map_session_data *sd;
struct item it;
int seconds;
@@ -7477,7 +8242,8 @@ BUILDIN(rentitem) {
* Returned Qty is always 1, only works on equip-able
* equipment
*------------------------------------------*/
-BUILDIN(getnameditem) {
+static BUILDIN(getnameditem)
+{
int nameid;
struct item item_tmp;
struct map_session_data *sd, *tsd;
@@ -7517,12 +8283,12 @@ BUILDIN(getnameditem) {
}
memset(&item_tmp,0,sizeof(item_tmp));
- item_tmp.nameid=nameid;
- item_tmp.amount=1;
- item_tmp.identify=1;
- item_tmp.card[0]=CARD0_CREATE; //we don't use 255! because for example SIGNED WEAPON shouldn't get TOP10 BS Fame bonus [Lupus]
- item_tmp.card[2]=tsd->status.char_id;
- item_tmp.card[3]=tsd->status.char_id >> 16;
+ item_tmp.nameid = nameid;
+ item_tmp.amount = 1;
+ item_tmp.identify = 1;
+ item_tmp.card[0] = CARD0_CREATE; //we don't use 255! because for example SIGNED WEAPON shouldn't get TOP10 BS Fame bonus [Lupus]
+ item_tmp.card[2] = GetWord(tsd->status.char_id, 0);
+ item_tmp.card[3] = GetWord(tsd->status.char_id, 1);
if(pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT)) {
script_pushint(st,0);
return true; //Failed to add item, we will not drop if they don't fit
@@ -7536,7 +8302,8 @@ BUILDIN(getnameditem) {
* gets a random item ID from an item group [Skotlex]
* groupranditem group_num
*------------------------------------------*/
-BUILDIN(grouprandomitem) {
+static BUILDIN(grouprandomitem)
+{
struct item_data *data;
int nameid;
@@ -7566,7 +8333,7 @@ BUILDIN(grouprandomitem) {
/*==========================================
*
*------------------------------------------*/
-BUILDIN(makeitem)
+static BUILDIN(makeitem)
{
int nameid,amount;
int x,y,m;
@@ -7609,7 +8376,91 @@ BUILDIN(makeitem)
item_tmp.nameid = nameid;
item_tmp.identify=1;
- map->addflooritem(NULL, &item_tmp, amount, m, x, y, 0, 0, 0, 0);
+ map->addflooritem(NULL, &item_tmp, amount, m, x, y, 0, 0, 0, 0, false);
+
+ return true;
+}
+
+/*==========================================
+ * makeitem2 <item id>, <amount>, <identify>, <refine>, <attribute>, <card1>, <card2>, <card3>, <card4>, {"<map name>", <X>, <Y>, <range>};
+ *------------------------------------------*/
+static BUILDIN(makeitem2)
+{
+ struct map_session_data *sd = NULL;
+ struct item_data *i_data;
+ int nameid = 0, amount;
+ int16 x, y, m = -1, range;
+ struct item item_tmp;
+
+ if (script_isstringtype(st, 2)) {
+ const char *name = script_getstr(st, 2);
+ struct item_data *item_data = itemdb->search_name(name);
+ if (item_data != NULL)
+ nameid = item_data->nameid;
+ } else {
+ nameid = script_getnum(st, 2);
+ }
+
+ i_data = itemdb->exists(nameid);
+ if (i_data == NULL) {
+ ShowError("makeitem2: Unknown item %d requested.\n", nameid);
+ return true;
+ }
+
+ if (script_hasdata(st, 11)) {
+ m = map->mapname2mapid(script_getstr(st, 11));
+ } else {
+ sd = script->rid2sd(st);
+ if (sd == NULL)
+ return true;
+ m = sd->bl.m;
+ }
+
+ if (m == -1) {
+ ShowError("makeitem2: Nonexistant map requested.\n");
+ return true;
+ }
+
+ x = (script_hasdata(st, 12) ? script_getnum(st, 12) : 0);
+ y = (script_hasdata(st, 13) ? script_getnum(st, 13) : 0);
+
+ // pick random position on map
+ if (x <= 0 || x >= map->list[m].xs || y <= 0 || y >= map->list[m].ys) {
+ sd = map->id2sd(st->rid);
+ if ((x < 0 || y < 0) && sd == NULL) {
+ x = 0;
+ y = 0;
+ map->search_freecell(NULL, m, &x, &y, -1, -1, 1);
+ } else {
+ range = (script_hasdata(st, 14) ? cap_value(script_getnum(st, 14), 1, battle_config.area_size) : 3);
+ map->search_freecell(&sd->bl, sd->bl.m, &x, &y, range, range, 0); // Locate spot next to player.
+ }
+ }
+
+ // if equip or weapon or egg type only drop one.
+ switch (i_data->type) {
+ case IT_ARMOR:
+ case IT_WEAPON:
+ case IT_PETARMOR:
+ case IT_PETEGG:
+ amount = 1;
+ break;
+ default:
+ amount = cap_value(script_getnum(st, 3), 1, MAX_AMOUNT);
+ break;
+ }
+
+ memset(&item_tmp, 0, sizeof(item_tmp));
+ item_tmp.nameid = nameid;
+ item_tmp.identify = script_getnum(st, 4);
+ item_tmp.refine = cap_value(script_getnum(st, 5), 0, MAX_REFINE);
+ item_tmp.attribute = script_getnum(st, 6);
+ item_tmp.card[0] = script_getnum(st, 7);
+ item_tmp.card[1] = script_getnum(st, 8);
+ item_tmp.card[2] = script_getnum(st, 9);
+ item_tmp.card[3] = script_getnum(st, 10);
+
+ map->addflooritem(NULL, &item_tmp, amount, m, x, y, 0, 0, 0, 0, false);
return true;
}
@@ -7617,10 +8468,14 @@ BUILDIN(makeitem)
/// Counts / deletes the current item given by idx.
/// Used by buildin_delitem_search
/// Relies on all input data being already fully valid.
-void buildin_delitem_delete(struct map_session_data* sd, int idx, int* amount, bool delete_items)
+static void buildin_delitem_delete(struct map_session_data *sd, int idx, int *amount, bool delete_items)
{
int delamount;
- struct item* inv = &sd->status.inventory[idx];
+ struct item* inv;
+
+ nullpo_retv(sd);
+ nullpo_retv(amount);
+ inv = &sd->status.inventory[idx];
delamount = ( amount[0] < inv->amount ) ? amount[0] : inv->amount;
@@ -7641,12 +8496,14 @@ void buildin_delitem_delete(struct map_session_data* sd, int idx, int* amount, b
/// Relies on all input data being already fully valid.
/// @param exact_match will also match item attributes and cards, not just name id
/// @return true when all items could be deleted, false when there were not enough items to delete
-bool buildin_delitem_search(struct map_session_data* sd, struct item* it, bool exact_match)
+static bool buildin_delitem_search(struct map_session_data *sd, struct item *it, bool exact_match)
{
bool delete_items = false;
int i, amount;
struct item* inv;
+ nullpo_retr(false, sd);
+ nullpo_retr(false, it);
// prefer always non-equipped items
it->equip = 0;
@@ -7748,7 +8605,7 @@ bool buildin_delitem_search(struct map_session_data* sd, struct item* it, bool e
///
/// delitem <item id>,<amount>{,<account id>}
/// delitem "<item name>",<amount>{,<account id>}
-BUILDIN(delitem)
+static BUILDIN(delitem)
{
struct map_session_data *sd;
struct item it;
@@ -7805,7 +8662,7 @@ BUILDIN(delitem)
///
/// delitem2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
/// delitem2 "<Item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
-BUILDIN(delitem2)
+static BUILDIN(delitem2)
{
struct map_session_data *sd;
struct item it;
@@ -7846,10 +8703,10 @@ BUILDIN(delitem2)
it.identify=script_getnum(st,4);
it.refine=script_getnum(st,5);
it.attribute=script_getnum(st,6);
- it.card[0]=(short)script_getnum(st,7);
- it.card[1]=(short)script_getnum(st,8);
- it.card[2]=(short)script_getnum(st,9);
- it.card[3]=(short)script_getnum(st,10);
+ it.card[0] = script_getnum(st, 7);
+ it.card[1] = script_getnum(st, 8);
+ it.card[2] = script_getnum(st, 9);
+ it.card[3] = script_getnum(st, 10);
if( it.amount <= 0 )
return true;// nothing to do
@@ -7865,10 +8722,52 @@ BUILDIN(delitem2)
return false;
}
+/**
+ * Deletes item at given index.
+ * delitem(<index>{, <amount{, <account id>}});
+ */
+static BUILDIN(delitemidx)
+{
+ struct map_session_data *sd;
+
+ if (script_hasdata(st, 4)) {
+ if ((sd = script->id2sd(st, script_getnum(st, 4))) == NULL) {
+ st->state = END;
+ return true;
+ }
+ } else {
+ if ((sd = script->rid2sd(st)) == NULL)
+ return true;
+ }
+
+ int i = script_getnum(st, 2);
+ if (i < 0 || i >= sd->status.inventorySize) {
+ ShowError("buildin_delitemidx: Index (%d) should be from 0-%d.\n", i, sd->status.inventorySize - 1);
+ st->state = END;
+ return false;
+ }
+
+ if (itemdb->exists(sd->status.inventory[i].nameid) == NULL)
+ ShowWarning("buildin_delitemidx: Deleting invalid Item ID (%d).\n", sd->status.inventory[i].nameid);
+
+ int amount = 0;
+ if (script_hasdata(st, 3)) {
+ if ((amount = script_getnum(st, 3)) > sd->status.inventory[i].amount)
+ amount = sd->status.inventory[i].amount;
+ } else {
+ amount = sd->status.inventory[i].amount;
+ }
+
+ if (amount > 0)
+ script->buildin_delitem_delete(sd, i, &amount, true);
+
+ return true;
+}
+
/*==========================================
* Enables/Disables use of items while in an NPC [Skotlex]
*------------------------------------------*/
-BUILDIN(enableitemuse)
+static BUILDIN(enableitemuse)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd != NULL)
@@ -7876,7 +8775,7 @@ BUILDIN(enableitemuse)
return true;
}
-BUILDIN(disableitemuse)
+static BUILDIN(disableitemuse)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd != NULL)
@@ -7888,23 +8787,71 @@ BUILDIN(disableitemuse)
* return the basic stats of sd
* chk pc->readparam for available type
*------------------------------------------*/
-BUILDIN(readparam) {
+static BUILDIN(readparam)
+{
int type;
struct map_session_data *sd;
+ struct script_data *data = script_getdata(st, 2);
- type=script_getnum(st,2);
- if (script_hasdata(st,3))
- sd = script->nick2sd(st, script_getstr(st,3));
- else
- sd=script->rid2sd(st);
+ if (reference_toparam(data)) {
+ type = reference_getparamtype(data);
+ } else {
+ type = script->conv_num(st, data);
+ }
+
+ if (script_hasdata(st, 3)) {
+ if (script_isstringtype(st, 3)) {
+ sd = script->nick2sd(st, script_getstr(st, 3));
+ } else {
+ sd = script->id2sd(st, script_getnum(st, 3));
+ }
+ } else {
+ sd = script->rid2sd(st);
+ }
if (sd == NULL) {
- script_pushint(st,-1);
+ script_pushint(st, -1);
return true;
}
- script_pushint(st,pc->readparam(sd,type));
+ script_pushint(st, pc->readparam(sd, type));
+ return true;
+}
+
+static BUILDIN(setparam)
+{
+ int type;
+ struct map_session_data *sd;
+ struct script_data *data = script_getdata(st, 2);
+ int val = script_getnum(st, 3);
+
+ if (data_isreference(data) && reference_toparam(data)) {
+ type = reference_getparamtype(data);
+ } else {
+ type = script->conv_num(st, data);
+ }
+
+ if (script_hasdata(st, 4)) {
+ if (script_isstringtype(st, 4)) {
+ sd = script->nick2sd(st, script_getstr(st, 4));
+ } else {
+ sd = script->id2sd(st, script_getnum(st, 4));
+ }
+ } else {
+ sd = script->rid2sd(st);
+ }
+
+ if (sd == NULL) {
+ script_pushint(st, 0);
+ return true;
+ }
+ if (pc->setparam(sd, type, val) == 0) {
+ script_pushint(st, 0);
+ return false;
+ }
+
+ script_pushint(st, 1);
return true;
}
@@ -7916,62 +8863,67 @@ BUILDIN(readparam) {
* 2 : guild_id
* 3 : account_id
* 4 : bg_id
+ * 5 : clan_id
*------------------------------------------*/
-BUILDIN(getcharid) {
- int num;
+static BUILDIN(getcharid)
+{
+ int num = script_getnum(st, 2);
struct map_session_data *sd;
- num = script_getnum(st,2);
- if( script_hasdata(st,3) )
- sd=map->nick2sd(script_getstr(st,3));
+ if (script_hasdata(st, 3))
+ sd = map->nick2sd(script_getstr(st, 3), false);
else
- sd=script->rid2sd(st);
+ sd = script->rid2sd(st);
- if(sd==NULL) {
- script_pushint(st,0); //return 0, according docs
+ if (sd == NULL) {
+ script_pushint(st, 0); //return 0, according docs
return true;
}
- switch( num ) {
- case 0: script_pushint(st,sd->status.char_id); break;
- case 1: script_pushint(st,sd->status.party_id); break;
- case 2: script_pushint(st,sd->status.guild_id); break;
- case 3: script_pushint(st,sd->status.account_id); break;
- case 4: script_pushint(st,sd->bg_id); break;
- default:
- ShowError("buildin_getcharid: invalid parameter (%d).\n", num);
- script_pushint(st,0);
- break;
+ switch (num) {
+ case 0:
+ script_pushint(st, sd->status.char_id);
+ break;
+ case 1:
+ script_pushint(st, sd->status.party_id);
+ break;
+ case 2:
+ script_pushint(st, sd->status.guild_id);
+ break;
+ case 3:
+ script_pushint(st, sd->status.account_id);
+ break;
+ case 4:
+ script_pushint(st, sd->bg_id);
+ break;
+ case 5:
+ script_pushint(st, sd->status.clan_id);
+ break;
+ default:
+ ShowError("buildin_getcharid: invalid parameter (%d).\n", num);
+ script_pushint(st, 0);
+ break;
}
return true;
}
+
/*==========================================
* returns the GID of an NPC
*------------------------------------------*/
-BUILDIN(getnpcid)
+static BUILDIN(getnpcid)
{
- int num = script_getnum(st,2);
- struct npc_data* nd = NULL;
-
- if( script_hasdata(st,3) )
- {// unique npc name
- if( ( nd = npc->name2id(script_getstr(st,3)) ) == NULL )
- {
- ShowError("buildin_getnpcid: No such NPC '%s'.\n", script_getstr(st,3));
- script_pushint(st,0);
- return false;
+ if (script_hasdata(st, 2)) {
+ if (script_isinttype(st, 2)) {
+ // Deprecate old form - getnpcid(<type>{, <"npc name">})
+ ShowWarning("buildin_getnpcid: Use of type is deprecated. Format - getnpcid({<\"npc name\">})\n");
+ script_pushint(st, 0);
+ } else {
+ struct npc_data *nd = npc->name2id(script_getstr(st, 2));
+ script_pushint(st, (nd != NULL) ? nd->bl.id : 0);
}
- }
-
- switch (num) {
- case 0:
- script_pushint(st,nd ? nd->bl.id : st->oid);
- break;
- default:
- ShowError("buildin_getnpcid: invalid parameter (%d).\n", num);
- script_pushint(st,0);
- return false;
+ } else {
+ script_pushint(st, st->oid);
}
return true;
@@ -7981,7 +8933,7 @@ BUILDIN(getnpcid)
* Return the name of the party_id
* null if not found
*------------------------------------------*/
-BUILDIN(getpartyname)
+static BUILDIN(getpartyname)
{
int party_id;
struct party_data* p;
@@ -8007,7 +8959,7 @@ BUILDIN(getpartyname)
* 1 : char_id des membres
* 2 : account_id des membres
*------------------------------------------*/
-BUILDIN(getpartymember)
+static BUILDIN(getpartymember)
{
struct party_data *p;
int j=0,type=0;
@@ -8023,19 +8975,19 @@ BUILDIN(getpartymember)
if(p->party.member[i].account_id) {
switch (type) {
case 2:
- mapreg->setreg(reference_uid(script->add_str("$@partymemberaid"), j),p->party.member[i].account_id);
+ mapreg->setreg(reference_uid(script->add_variable("$@partymemberaid"), j),p->party.member[i].account_id);
break;
case 1:
- mapreg->setreg(reference_uid(script->add_str("$@partymembercid"), j),p->party.member[i].char_id);
+ mapreg->setreg(reference_uid(script->add_variable("$@partymembercid"), j),p->party.member[i].char_id);
break;
default:
- mapreg->setregstr(reference_uid(script->add_str("$@partymembername$"), j),p->party.member[i].name);
+ mapreg->setregstr(reference_uid(script->add_variable("$@partymembername$"), j),p->party.member[i].name);
}
j++;
}
}
}
- mapreg->setreg(script->add_str("$@partymembercount"),j);
+ mapreg->setreg(script->add_variable("$@partymembercount"),j);
return true;
}
@@ -8044,7 +8996,7 @@ BUILDIN(getpartymember)
* Retrieves party leader. if flag is specified,
* return some of the leader data. Otherwise, return name.
*------------------------------------------*/
-BUILDIN(getpartyleader)
+static BUILDIN(getpartyleader)
{
int party_id, type = 0, i=0;
struct party_data *p;
@@ -8069,7 +9021,7 @@ BUILDIN(getpartyleader)
switch (type) {
case 1: script_pushint(st,p->party.member[i].account_id); break;
case 2: script_pushint(st,p->party.member[i].char_id); break;
- case 3: script_pushint(st,p->party.member[i].class_); break;
+ case 3: script_pushint(st,p->party.member[i].class); break;
case 4: script_pushstrcopy(st,mapindex_id2name(p->party.member[i].map)); break;
case 5: script_pushint(st,p->party.member[i].lv); break;
default: script_pushstrcopy(st,p->party.member[i].name); break;
@@ -8077,11 +9029,98 @@ BUILDIN(getpartyleader)
return true;
}
+enum guildinfo_type {
+ GUILDINFO_NAME,
+ GUILDINFO_ID,
+ GUILDINFO_LEVEL,
+ GUILDINFO_ONLINE,
+ GUILDINFO_AV_LEVEL,
+ GUILDINFO_MAX_MEMBERS,
+ GUILDINFO_EXP,
+ GUILDINFO_NEXT_EXP,
+ GUILDINFO_SKILL_POINTS,
+ GUILDINFO_MASTER_NAME,
+ GUILDINFO_MASTER_CID,
+};
+
+static BUILDIN(getguildinfo)
+{
+ struct guild *g = NULL;
+
+ if (script_hasdata(st, 3)) {
+ if (script_isstringtype(st, 3)) {
+ const char *guild_name = script_getstr(st, 3);
+ g = guild->searchname(guild_name);
+ } else {
+ int guild_id = script_getnum(st, 3);
+ g = guild->search(guild_id);
+ }
+ } else {
+ struct map_session_data *sd = script->rid2sd(st);
+ g = sd ? sd->guild : NULL;
+ }
+
+ enum guildinfo_type type = script_getnum(st, 2);
+
+ if (g == NULL) {
+ // guild does not exist
+ switch (type) {
+ case GUILDINFO_NAME:
+ case GUILDINFO_MASTER_NAME:
+ script_pushconststr(st, "");
+ break;
+ default:
+ script_pushint(st, -1);
+ }
+ } else {
+ switch (type) {
+ case GUILDINFO_NAME:
+ script_pushstrcopy(st, g->name);
+ break;
+ case GUILDINFO_ID:
+ script_pushint(st, g->guild_id);
+ break;
+ case GUILDINFO_LEVEL:
+ script_pushint(st, g->guild_lv);
+ break;
+ case GUILDINFO_ONLINE:
+ script_pushint(st, g->connect_member);
+ break;
+ case GUILDINFO_AV_LEVEL:
+ script_pushint(st, g->average_lv);
+ break;
+ case GUILDINFO_MAX_MEMBERS:
+ script_pushint(st, g->max_member);
+ break;
+ case GUILDINFO_EXP:
+ script_pushint(st, g->exp);
+ break;
+ case GUILDINFO_NEXT_EXP:
+ script_pushint(st, g->next_exp);
+ break;
+ case GUILDINFO_SKILL_POINTS:
+ script_pushint(st, g->skill_point);
+ break;
+ case GUILDINFO_MASTER_NAME:
+ script_pushstrcopy(st, g->member[0].name);
+ break;
+ case GUILDINFO_MASTER_CID:
+ script_pushint(st, g->member[0].char_id);
+ break;
+ default:
+ ShowError("script:getguildinfo: unknown info type!\n");
+ st->state = END;
+ return false;
+ }
+ }
+ return true;
+}
+
/*==========================================
* Return the name of the @guild_id
* null if not found
*------------------------------------------*/
-BUILDIN(getguildname)
+static BUILDIN(getguildname)
{
int guild_id;
struct guild* g;
@@ -8103,7 +9142,7 @@ BUILDIN(getguildname)
* Return the name of the guild master of @guild_id
* null if not found
*------------------------------------------*/
-BUILDIN(getguildmaster)
+static BUILDIN(getguildmaster)
{
int guild_id;
struct guild* g;
@@ -8121,7 +9160,7 @@ BUILDIN(getguildmaster)
return true;
}
-BUILDIN(getguildmasterid)
+static BUILDIN(getguildmasterid)
{
int guild_id;
struct guild* g;
@@ -8148,7 +9187,7 @@ BUILDIN(getguildmasterid)
* 1 : character ID
* 2 : account ID
*------------------------------------------*/
-BUILDIN(getguildmember)
+static BUILDIN(getguildmember)
{
struct guild *g = NULL;
int j = 0;
@@ -8165,20 +9204,77 @@ BUILDIN(getguildmember)
if ( g->member[i].account_id ) {
switch (type) {
case 2:
- mapreg->setreg(reference_uid(script->add_str("$@guildmemberaid"), j),g->member[i].account_id);
+ mapreg->setreg(reference_uid(script->add_variable("$@guildmemberaid"), j),g->member[i].account_id);
break;
case 1:
- mapreg->setreg(reference_uid(script->add_str("$@guildmembercid"), j), g->member[i].char_id);
+ mapreg->setreg(reference_uid(script->add_variable("$@guildmembercid"), j), g->member[i].char_id);
break;
default:
- mapreg->setregstr(reference_uid(script->add_str("$@guildmembername$"), j), g->member[i].name);
+ mapreg->setregstr(reference_uid(script->add_variable("$@guildmembername$"), j), g->member[i].name);
break;
}
j++;
}
}
}
- mapreg->setreg(script->add_str("$@guildmembercount"), j);
+ mapreg->setreg(script->add_variable("$@guildmembercount"), j);
+ return true;
+}
+
+/**
+ * getguildonline(<Guild ID>{, type})
+ * Returns amount of guild members online.
+**/
+
+enum script_getguildonline_types {
+ GUILD_ONLINE_ALL = 0,
+ GUILD_ONLINE_VENDOR,
+ GUILD_ONLINE_NO_VENDOR
+};
+
+BUILDIN(getguildonline)
+{
+ struct guild *g;
+ int guild_id = script_getnum(st, 2);
+ int type = GUILD_ONLINE_ALL, j = 0;
+
+ if ((g = guild->search(guild_id)) == NULL) {
+ script_pushint(st, -1);
+ return true;
+ }
+
+ if (script_hasdata(st, 3)) {
+ type = script_getnum(st, 3);
+
+ if (type < GUILD_ONLINE_ALL || type > GUILD_ONLINE_NO_VENDOR) {
+ ShowWarning("buildin_getguildonline: Invalid type specified. Defaulting to GUILD_ONLINE_ALL.\n");
+ type = GUILD_ONLINE_ALL;
+ }
+ }
+
+ struct map_session_data *sd;
+ for (int i = 0; i < MAX_GUILD; i++) {
+ if (g->member[i].online && (sd = g->member[i].sd) != NULL) {
+ switch (type) {
+ case GUILD_ONLINE_VENDOR:
+ if (sd->state.vending > 0)
+ j++;
+ break;
+
+ case GUILD_ONLINE_NO_VENDOR:
+ if (sd->state.vending == 0)
+ j++;
+ break;
+
+ default:
+ j++;
+ break;
+ }
+ }
+ }
+
+ script_pushint(st, j);
+
return true;
}
@@ -8189,43 +9285,61 @@ BUILDIN(getguildmember)
* 1 : party_name or ""
* 2 : guild_name or ""
* 3 : map_name
+ * 4 : clan_name or ""
* - : ""
*------------------------------------------*/
-BUILDIN(strcharinfo)
+static BUILDIN(strcharinfo)
{
- int num;
+ struct clan *c;
struct guild* g;
struct party_data* p;
- struct map_session_data *sd = script->rid2sd(st);
- if (sd == NULL) //Avoid crashing....
+ struct map_session_data *sd;
+
+ if (script_hasdata(st, 4))
+ sd = map->id2sd(script_getnum(st, 4));
+ else
+ sd = script->rid2sd(st);
+
+ if (sd == NULL) {
+ if(script_hasdata(st, 3)) {
+ script_pushcopy(st, 3);
+ } else {
+ script_pushconststr(st, "");
+ }
return true;
+ }
- num=script_getnum(st,2);
- switch(num) {
- case 0:
- script_pushstrcopy(st,sd->status.name);
- break;
- case 1:
- if( ( p = party->search(sd->status.party_id) ) != NULL ) {
- script_pushstrcopy(st,p->party.name);
- } else {
- script_pushconststr(st,"");
- }
- break;
- case 2:
- if( ( g = sd->guild ) != NULL ) {
- script_pushstrcopy(st,g->name);
- } else {
- script_pushconststr(st,"");
- }
- break;
- case 3:
- script_pushconststr(st,map->list[sd->bl.m].name);
- break;
- default:
- ShowWarning("buildin_strcharinfo: unknown parameter.\n");
- script_pushconststr(st,"");
- break;
+ switch (script_getnum(st, 2)) {
+ case 0:
+ script_pushstrcopy(st, sd->status.name);
+ break;
+ case 1:
+ if ((p = party->search(sd->status.party_id)) != NULL) {
+ script_pushstrcopy(st, p->party.name);
+ } else {
+ script_pushconststr(st, "");
+ }
+ break;
+ case 2:
+ if ((g = sd->guild) != NULL) {
+ script_pushstrcopy(st, g->name);
+ } else {
+ script_pushconststr(st, "");
+ }
+ break;
+ case 3:
+ script_pushconststr(st, map->list[sd->bl.m].name);
+ break;
+ case 4:
+ if ((c = sd->clan) != NULL) {
+ script_pushstrcopy(st, c->name);
+ } else {
+ script_pushconststr(st, "");
+ }
+ break;
+ default:
+ ShowWarning("script:strcharinfo: unknown parameter.\n");
+ script_pushconststr(st, "");
}
return true;
@@ -8240,43 +9354,53 @@ BUILDIN(strcharinfo)
* 3 : ::str
* 4 : map name
*------------------------------------------*/
-BUILDIN(strnpcinfo)
+static BUILDIN(strnpcinfo)
{
- int num;
char *buf,*name=NULL;
- struct npc_data *nd = map->id2nd(st->oid);
+ struct npc_data *nd;
+
+ if (script_hasdata(st, 4))
+ nd = map->id2nd(script_getnum(st, 4));
+ else
+ nd = map->id2nd(st->oid);
+
if (nd == NULL) {
- script_pushconststr(st, "");
+ if (script_hasdata(st, 3)) {
+ script_pushcopy(st, 3);
+ } else {
+ script_pushconststr(st, "");
+ }
return true;
}
- num = script_getnum(st,2);
- switch(num) {
- case 0: // display name
+ switch (script_getnum(st,2)) {
+ case 0: // display name
+ name = aStrdup(nd->name);
+ break;
+ case 1: // visible part of display name
+ if ((buf = strchr(nd->name,'#')) != NULL) {
name = aStrdup(nd->name);
- break;
- case 1: // visible part of display name
- if((buf = strchr(nd->name,'#')) != NULL)
- {
- name = aStrdup(nd->name);
- name[buf - nd->name] = 0;
- } else // Return the name, there is no '#' present
- name = aStrdup(nd->name);
- break;
- case 2: // # fragment
- if((buf = strchr(nd->name,'#')) != NULL)
- name = aStrdup(buf+1);
- break;
- case 3: // unique name
- name = aStrdup(nd->exname);
- break;
- case 4: // map name
- if( nd->bl.m >= 0 ) // Only valid map indexes allowed (issue:8034)
- name = aStrdup(map->list[nd->bl.m].name);
- break;
+ name[buf - nd->name] = 0;
+ } else { // Return the name, there is no '#' present
+ name = aStrdup(nd->name);
+ }
+ break;
+ case 2: // # fragment
+ if ((buf = strchr(nd->name,'#')) != NULL) {
+ name = aStrdup(buf+1);
+ }
+ break;
+ case 3: // unique name
+ name = aStrdup(nd->exname);
+ break;
+ case 4: // map name
+ if (nd->bl.m >= 0) { // Only valid map indexes allowed (issue:8034)
+ name = aStrdup(map->list[nd->bl.m].name);
+ }
+ break;
}
- if(name)
+ if (name)
script_pushstr(st, name);
else
script_pushconststr(st, "");
@@ -8287,7 +9411,7 @@ BUILDIN(strnpcinfo)
/**
* charid2rid: Returns the RID associated to the given character ID
*/
-BUILDIN(charid2rid)
+static BUILDIN(charid2rid)
{
int cid = script_getnum(st, 2);
struct map_session_data *sd = map->charid2sd(cid);
@@ -8304,7 +9428,7 @@ BUILDIN(charid2rid)
/*==========================================
* GetEquipID(Pos); Pos: 1-SCRIPT_EQUIP_TABLE_SIZE
*------------------------------------------*/
-BUILDIN(getequipid)
+static BUILDIN(getequipid)
{
int i, num;
struct item_data* item;
@@ -8340,7 +9464,7 @@ BUILDIN(getequipid)
* Get the equipement name at pos
* return item jname or ""
*------------------------------------------*/
-BUILDIN(getequipname)
+static BUILDIN(getequipname)
{
int i, num;
struct item_data* item;
@@ -8375,16 +9499,18 @@ BUILDIN(getequipname)
/*==========================================
* getbrokenid [Valaris]
*------------------------------------------*/
-BUILDIN(getbrokenid)
+static BUILDIN(getbrokenid)
{
- int i,num,id=0,brokencounter=0;
+ int num,id=0,brokencounter=0;
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
return true;
num=script_getnum(st,2);
- for(i=0; i<MAX_INVENTORY; i++) {
- if(sd->status.inventory[i].attribute) {
+ for (int i = 0; i < sd->status.inventorySize; i++) {
+ if (sd->status.inventory[i].card[0] == CARD0_PET)
+ continue;
+ if ((sd->status.inventory[i].attribute & ATTR_BROKEN) != 0) {
brokencounter++;
if(num==brokencounter) {
id=sd->status.inventory[i].nameid;
@@ -8401,15 +9527,17 @@ BUILDIN(getbrokenid)
/*==========================================
* getbrokencount
*------------------------------------------*/
-BUILDIN(getbrokencount)
+static BUILDIN(getbrokencount)
{
int i, counter = 0;
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
return true;
- for (i = 0; i < MAX_INVENTORY; i++) {
- if (sd->status.inventory[i].attribute)
+ for (i = 0; i < sd->status.inventorySize; i++) {
+ if (sd->status.inventory[i].card[0] == CARD0_PET)
+ continue;
+ if ((sd->status.inventory[i].attribute & ATTR_BROKEN) != 0)
counter++;
}
@@ -8421,21 +9549,23 @@ BUILDIN(getbrokencount)
/*==========================================
* repair [Valaris]
*------------------------------------------*/
-BUILDIN(repair)
+static BUILDIN(repair)
{
- int i,num;
int repaircounter=0;
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
return true;
- num=script_getnum(st,2);
- for(i=0; i<MAX_INVENTORY; i++) {
- if(sd->status.inventory[i].attribute) {
+ int num = script_getnum(st, 2);
+ for(int i = 0; i < sd->status.inventorySize; i++) {
+ if (sd->status.inventory[i].card[0] == CARD0_PET)
+ continue;
+ if ((sd->status.inventory[i].attribute & ATTR_BROKEN) != 0) {
repaircounter++;
if(num==repaircounter) {
- sd->status.inventory[i].attribute=0;
- clif->equiplist(sd);
+ sd->status.inventory[i].attribute |= ATTR_BROKEN;
+ sd->status.inventory[i].attribute ^= ATTR_BROKEN;
+ clif->equipList(sd);
clif->produce_effect(sd, 0, sd->status.inventory[i].nameid);
clif->misceffect(&sd->bl, 3);
break;
@@ -8449,18 +9579,21 @@ BUILDIN(repair)
/*==========================================
* repairall
*------------------------------------------*/
-BUILDIN(repairall)
+static BUILDIN(repairall)
{
- int i, repaircounter = 0;
+ int repaircounter = 0;
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
return true;
- for(i = 0; i < MAX_INVENTORY; i++)
+ for (int i = 0; i < sd->status.inventorySize; i++)
{
- if(sd->status.inventory[i].nameid && sd->status.inventory[i].attribute)
+ if (sd->status.inventory[i].card[0] == CARD0_PET)
+ continue;
+ if (sd->status.inventory[i].nameid && (sd->status.inventory[i].attribute & ATTR_BROKEN) != 0)
{
- sd->status.inventory[i].attribute = 0;
+ sd->status.inventory[i].attribute |= ATTR_BROKEN;
+ sd->status.inventory[i].attribute ^= ATTR_BROKEN;
clif->produce_effect(sd,0,sd->status.inventory[i].nameid);
repaircounter++;
}
@@ -8469,7 +9602,7 @@ BUILDIN(repairall)
if(repaircounter)
{
clif->misceffect(&sd->bl, 3);
- clif->equiplist(sd);
+ clif->equipList(sd);
}
return true;
@@ -8478,7 +9611,7 @@ BUILDIN(repairall)
/*==========================================
* Chk if player have something equiped at pos
*------------------------------------------*/
-BUILDIN(getequipisequiped)
+static BUILDIN(getequipisequiped)
{
int i = -1,num;
struct map_session_data *sd;
@@ -8505,7 +9638,7 @@ BUILDIN(getequipisequiped)
* 1 : true
* 0 : false
*------------------------------------------*/
-BUILDIN(getequipisenableref)
+static BUILDIN(getequipisenableref)
{
int i = -1,num;
struct map_session_data *sd;
@@ -8525,13 +9658,42 @@ BUILDIN(getequipisenableref)
return true;
}
+/**
+ * Checks if the equipped item allows options.
+ * *getequipisenableopt(<equipment_index>);
+ *
+ * @param equipment_index as the inventory index of the equipment.
+ * @return 1 on enabled 0 on disabled.
+ */
+static BUILDIN(getequipisenableopt)
+{
+ int i = -1, index = script_getnum(st, 2);
+ struct map_session_data *sd = script->rid2sd(st);
+
+ if (sd == NULL) {
+ script_pushint(st, -1);
+ ShowError("buildin_getequipisenableopt: player is not attached!");
+ return false;
+ }
+
+ if (index > 0 && index <= ARRAYLENGTH(script->equip))
+ i = pc->checkequip(sd, script->equip[index - 1]);
+
+ if (i >=0 && sd->inventory_data[i] && !sd->inventory_data[i]->flag.no_options && !sd->status.inventory[i].expire_time)
+ script_pushint(st, 1);
+ else
+ script_pushint(st, 0);
+
+ return true;
+}
+
/*==========================================
* Chk if the item equiped at pos is identify (huh ?)
* return (npc)
* 1 : true
* 0 : false
*------------------------------------------*/
-BUILDIN(getequipisidentify)
+static BUILDIN(getequipisidentify)
{
int i = -1,num;
struct map_session_data *sd;
@@ -8552,27 +9714,29 @@ BUILDIN(getequipisidentify)
}
/*==========================================
- * Get the item refined value at pos
- * return (npc)
- * x : refine amount
- * 0 : false (not refined)
+ * Get the total refine amount of equip at given pos
+ * return total refine amount
*------------------------------------------*/
-BUILDIN(getequiprefinerycnt)
+static BUILDIN(getequiprefinerycnt)
{
- int i = -1,num;
- struct map_session_data *sd;
+ int total_refine = 0;
+ struct map_session_data* sd = script->rid2sd(st);
- num = script_getnum(st,2);
- sd = script->rid2sd(st);
- if( sd == NULL )
- return true;
+ if (sd != NULL)
+ {
+ int count = script_lastdata(st);
+ int script_equip_size = ARRAYLENGTH(script->equip);
+ for (int n = 2; n <= count; n++) {
+ int i = -1;
+ int num = script_getnum(st, n);
+ if (num > 0 && num <= script_equip_size)
+ i = pc->checkequip(sd, script->equip[num - 1]);
- if (num > 0 && num <= ARRAYLENGTH(script->equip))
- i=pc->checkequip(sd,script->equip[num-1]);
- if(i >= 0)
- script_pushint(st,sd->status.inventory[i].refine);
- else
- script_pushint(st,0);
+ if (i >= 0)
+ total_refine += sd->status.inventory[i].refine;
+ }
+ }
+ script_pushint(st, total_refine);
return true;
}
@@ -8584,7 +9748,7 @@ BUILDIN(getequiprefinerycnt)
* x : weapon level
* 0 : false
*------------------------------------------*/
-BUILDIN(getequipweaponlv)
+static BUILDIN(getequipweaponlv)
{
int i = -1,num;
struct map_session_data *sd;
@@ -8610,21 +9774,34 @@ BUILDIN(getequipweaponlv)
* x : refine chance
* 0 : false (max refine level or unequip..)
*------------------------------------------*/
-BUILDIN(getequippercentrefinery) {
- int i = -1,num;
+static BUILDIN(getequippercentrefinery)
+{
+ int i = -1, num;
struct map_session_data *sd;
+ int type = 0;
+
+ num = script_getnum(st, 2);
+ type = (script_hasdata(st, 3)) ? script_getnum(st, 3) : REFINE_CHANCE_TYPE_NORMAL;
- num = script_getnum(st,2);
sd = script->rid2sd(st);
- if( sd == NULL )
+ if (sd == NULL)
return true;
+ if (type < REFINE_CHANCE_TYPE_NORMAL || type >= REFINE_CHANCE_TYPE_MAX) {
+ ShowError("buildin_getequippercentrefinery: Invalid type (%d) provided!\n", type);
+ script_pushint(st, 0);
+ return false;
+ }
+
+
if (num > 0 && num <= ARRAYLENGTH(script->equip))
- i=pc->checkequip(sd,script->equip[num-1]);
- if(i >= 0 && sd->status.inventory[i].nameid && sd->status.inventory[i].refine < MAX_REFINE)
- script_pushint(st,status->get_refine_chance(itemdb_wlv(sd->status.inventory[i].nameid), (int)sd->status.inventory[i].refine));
+ i = pc->checkequip(sd, script->equip[num - 1]);
+
+ if (i >= 0 && sd->status.inventory[i].nameid != 0 && sd->status.inventory[i].refine < MAX_REFINE)
+ script_pushint(st,
+ refine->get_refine_chance(itemdb_wlv(sd->status.inventory[i].nameid), (int) sd->status.inventory[i].refine, (enum refine_chance_type) type));
else
- script_pushint(st,0);
+ script_pushint(st, 0);
return true;
}
@@ -8632,7 +9809,7 @@ BUILDIN(getequippercentrefinery) {
/*==========================================
* Refine +1 item at pos and log and display refine
*------------------------------------------*/
-BUILDIN(successrefitem)
+static BUILDIN(successrefitem)
{
int i = -1 , num, up = 1;
struct map_session_data *sd;
@@ -8669,20 +9846,25 @@ BUILDIN(successrefitem)
clif->additem(sd,i,1,0);
pc->equipitem(sd,i,ep);
clif->misceffect(&sd->bl,3);
+
+ achievement->validate_refine(sd, i, true); // Achievements [Smokexyz/Hercules]
+
+ /* The following check is exclusive to characters (possibly only whitesmiths)
+ * that create equipments and refine them to level 10. */
if(sd->status.inventory[i].refine == 10 &&
sd->status.inventory[i].card[0] == CARD0_FORGE &&
sd->status.char_id == (int)MakeDWord(sd->status.inventory[i].card[2],sd->status.inventory[i].card[3])
) { // Fame point system [DracoRPG]
switch (sd->inventory_data[i]->wlv) {
- case 1:
- pc->addfame(sd,1); // Success to refine to +10 a lv1 weapon you forged = +1 fame point
- break;
- case 2:
- pc->addfame(sd,25); // Success to refine to +10 a lv2 weapon you forged = +25 fame point
- break;
- case 3:
- pc->addfame(sd,1000); // Success to refine to +10 a lv3 weapon you forged = +1000 fame point
- break;
+ case 1:
+ pc->addfame(sd, RANKTYPE_BLACKSMITH, 1); // Success to refine to +10 a lv1 weapon you forged = +1 fame point
+ break;
+ case 2:
+ pc->addfame(sd, RANKTYPE_BLACKSMITH, 25); // Success to refine to +10 a lv2 weapon you forged = +25 fame point
+ break;
+ case 3:
+ pc->addfame(sd, RANKTYPE_BLACKSMITH, 1000); // Success to refine to +10 a lv3 weapon you forged = +1000 fame point
+ break;
}
}
}
@@ -8693,7 +9875,7 @@ BUILDIN(successrefitem)
/*==========================================
* Show a failed Refine +1 attempt
*------------------------------------------*/
-BUILDIN(failedrefitem)
+static BUILDIN(failedrefitem)
{
int i=-1,num;
struct map_session_data *sd;
@@ -8706,6 +9888,9 @@ BUILDIN(failedrefitem)
if (num > 0 && num <= ARRAYLENGTH(script->equip))
i=pc->checkequip(sd,script->equip[num-1]);
if(i >= 0) {
+ // Call before changing refine to 0.
+ achievement->validate_refine(sd, i, false);
+
sd->status.inventory[i].refine = 0;
pc->unequipitem(sd, i, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE); //recalculate bonus
clif->refine(sd->fd,1,i,sd->status.inventory[i].refine); //notify client of failure
@@ -8721,7 +9906,7 @@ BUILDIN(failedrefitem)
/*==========================================
* Downgrades an Equipment Part by -1 . [Masao]
*------------------------------------------*/
-BUILDIN(downrefitem)
+static BUILDIN(downrefitem)
{
int i = -1, num, down = 1;
struct map_session_data *sd;
@@ -8753,6 +9938,9 @@ BUILDIN(downrefitem)
clif->additem(sd,i,1,0);
pc->equipitem(sd,i,ep);
+
+ achievement->validate_refine(sd, i, false); // Achievements [Smokexyz/Hercules]
+
clif->misceffect(&sd->bl,2);
}
@@ -8762,7 +9950,7 @@ BUILDIN(downrefitem)
/*==========================================
* Delete the item equipped at pos.
*------------------------------------------*/
-BUILDIN(delequip)
+static BUILDIN(delequip)
{
int i=-1,num;
struct map_session_data *sd;
@@ -8790,7 +9978,8 @@ BUILDIN(delequip)
/*==========================================
*
*------------------------------------------*/
-BUILDIN(statusup) {
+static BUILDIN(statusup)
+{
int type;
struct map_session_data *sd;
@@ -8806,7 +9995,7 @@ BUILDIN(statusup) {
/*==========================================
*
*------------------------------------------*/
-BUILDIN(statusup2)
+static BUILDIN(statusup2)
{
int type,val;
struct map_session_data *sd;
@@ -8822,6 +10011,25 @@ BUILDIN(statusup2)
return true;
}
+
+/*==========================================
+* Returns the number of stat points needed to change the specified stat by val.
+* needed_status_point(<type>,<val>); [secretdataz]
+*------------------------------------------*/
+static BUILDIN(needed_status_point)
+{
+ int type = script_getnum(st, 2);
+ int val = script_getnum(st, 3);;
+ struct map_session_data *sd = script->rid2sd(st);
+
+ if (sd == NULL)
+ script_pushint(st, 0);
+ else
+ script_pushint(st, pc->need_status_point(sd, type, val));
+
+ return true;
+}
+
/// See 'doc/item_bonus.txt'
///
/// bonus <bonus type>,<val1>;
@@ -8829,7 +10037,8 @@ BUILDIN(statusup2)
/// bonus3 <bonus type>,<val1>,<val2>,<val3>;
/// bonus4 <bonus type>,<val1>,<val2>,<val3>,<val4>;
/// bonus5 <bonus type>,<val1>,<val2>,<val3>,<val4>,<val5>;
-BUILDIN(bonus) {
+static BUILDIN(bonus)
+{
int type;
int val1;
int val2 = 0;
@@ -8863,7 +10072,7 @@ BUILDIN(bonus) {
val1 = skill->name2id(script_getstr(st, 3));
break;
}
- // else fall through
+ FALLTHROUGH
default:
val1 = script_getnum(st,3);
break;
@@ -8911,7 +10120,8 @@ BUILDIN(bonus) {
return true;
}
-BUILDIN(autobonus) {
+static BUILDIN(autobonus)
+{
unsigned int dur;
short rate;
short atk_type = 0;
@@ -8920,7 +10130,7 @@ BUILDIN(autobonus) {
if (sd == NULL)
return true; // no player attached
- if( sd->state.autobonus&sd->status.inventory[status->current_equip_item_index].equip )
+ if (status->current_equip_item_index < 0 || sd->state.autobonus&sd->status.inventory[status->current_equip_item_index].equip)
return true;
rate = script_getnum(st,3);
@@ -8945,7 +10155,8 @@ BUILDIN(autobonus) {
return true;
}
-BUILDIN(autobonus2) {
+static BUILDIN(autobonus2)
+{
unsigned int dur;
short rate;
short atk_type = 0;
@@ -8954,7 +10165,7 @@ BUILDIN(autobonus2) {
if (sd == NULL)
return true; // no player attached
- if( sd->state.autobonus&sd->status.inventory[status->current_equip_item_index].equip )
+ if (status->current_equip_item_index < 0 || sd->state.autobonus&sd->status.inventory[status->current_equip_item_index].equip)
return true;
rate = script_getnum(st,3);
@@ -8979,7 +10190,8 @@ BUILDIN(autobonus2) {
return true;
}
-BUILDIN(autobonus3) {
+static BUILDIN(autobonus3)
+{
unsigned int dur;
short rate,atk_type;
const char *bonus_script, *other_script = NULL;
@@ -8987,7 +10199,7 @@ BUILDIN(autobonus3) {
if (sd == NULL)
return true; // no player attached
- if( sd->state.autobonus&sd->status.inventory[status->current_equip_item_index].equip )
+ if (status->current_equip_item_index < 0 || sd->state.autobonus&sd->status.inventory[status->current_equip_item_index].equip)
return true;
rate = script_getnum(st,3);
@@ -9021,7 +10233,8 @@ BUILDIN(autobonus3) {
/// skill <skill id>,<level>
/// skill "<skill name>",<level>,<flag>
/// skill "<skill name>",<level>
-BUILDIN(skill) {
+static BUILDIN(skill)
+{
int id;
int level;
int flag = SKILL_GRANT_TEMPORARY;
@@ -9047,7 +10260,8 @@ BUILDIN(skill) {
/// addtoskill "<skill name>",<amount>
///
/// @see skill
-BUILDIN(addtoskill) {
+static BUILDIN(addtoskill)
+{
int id;
int level;
int flag = SKILL_GRANT_TEMPSTACK;
@@ -9068,7 +10282,8 @@ BUILDIN(addtoskill) {
///
/// guildskill <skill id>,<amount>;
/// guildskill "<skill name>",<amount>;
-BUILDIN(guildskill) {
+static BUILDIN(guildskill)
+{
int skill_id, id, max_points;
int level;
@@ -9084,6 +10299,9 @@ BUILDIN(guildskill) {
skill_id = ( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) );
level = script_getnum(st,3);
+ if (skill_id < GD_SKILLBASE || skill_id >= GD_MAX)
+ return true; // not guild skill
+
id = skill_id - GD_SKILLBASE;
max_points = guild->skill_get_max(skill_id);
@@ -9104,7 +10322,7 @@ BUILDIN(guildskill) {
///
/// getskilllv(<skill id>) -> <level>
/// getskilllv("<skill name>") -> <level>
-BUILDIN(getskilllv)
+static BUILDIN(getskilllv)
{
int id;
struct map_session_data *sd = script->rid2sd(st);
@@ -9121,7 +10339,8 @@ BUILDIN(getskilllv)
///
/// getgdskilllv(<guild id>,<skill id>) -> <level>
/// getgdskilllv(<guild id>,"<skill name>") -> <level>
-BUILDIN(getgdskilllv) {
+static BUILDIN(getgdskilllv)
+{
int guild_id;
uint16 skill_id;
struct guild* g;
@@ -9142,7 +10361,7 @@ BUILDIN(getgdskilllv) {
/// before allowing the basic actions.
///
/// basicskillcheck() -> <bool>
-BUILDIN(basicskillcheck)
+static BUILDIN(basicskillcheck)
{
script_pushint(st, battle_config.basic_skill_check);
return true;
@@ -9151,7 +10370,7 @@ BUILDIN(basicskillcheck)
/// Returns the GM level of the player.
///
/// getgmlevel() -> <level>
-BUILDIN(getgmlevel)
+static BUILDIN(getgmlevel)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
@@ -9165,7 +10384,8 @@ BUILDIN(getgmlevel)
/// set the group ID of the player.
/// setgroupid(<new group id>{,"<character name>"|<account id>})
/// return 1 on success, 0 if failed.
-BUILDIN(setgroupid) {
+static BUILDIN(setgroupid)
+{
struct map_session_data* sd = NULL;
int new_group = script_getnum(st, 2);
@@ -9188,21 +10408,31 @@ BUILDIN(setgroupid) {
/// Returns the group ID of the player.
///
-/// getgroupid() -> <int>
-BUILDIN(getgroupid)
+/// getgroupid({<account id>}) -> <int>
+static BUILDIN(getgroupid)
{
- struct map_session_data *sd = script->rid2sd(st);
- if (sd == NULL)
+ struct map_session_data *sd = NULL;
+
+ if (script_hasdata(st, 2)) {
+ sd = map->id2sd(script_getnum(st, 2));
+ } else {
+ sd = script->rid2sd(st);
+ }
+
+ if (sd == NULL) {
+ script_pushint(st, -1);
return true; // no player attached, report source
- script_pushint(st, pc_get_group_id(sd));
+ }
+ script_pushint(st, pc_get_group_id(sd));
return true;
}
/// Terminates the execution of this script instance.
///
/// end
-BUILDIN(end) {
+static BUILDIN(end)
+{
st->state = END;
/* are we stopping inside a function? */
@@ -9222,10 +10452,16 @@ BUILDIN(end) {
/// Checks if the player has that effect state (option).
///
/// checkoption(<option>) -> <bool>
-BUILDIN(checkoption)
+static BUILDIN(checkoption)
{
int option;
- struct map_session_data *sd = script->rid2sd(st);
+ struct map_session_data *sd;
+
+ if (script_hasdata(st, 3))
+ sd = map->id2sd(script_getnum(st, 3));
+ else
+ sd = script->rid2sd(st);
+
if (sd == NULL)
return true;// no player attached, report source
@@ -9241,10 +10477,16 @@ BUILDIN(checkoption)
/// Checks if the player is in that body state (opt1).
///
/// checkoption1(<opt1>) -> <bool>
-BUILDIN(checkoption1)
+static BUILDIN(checkoption1)
{
int opt1;
- struct map_session_data *sd = script->rid2sd(st);
+ struct map_session_data *sd;
+
+ if (script_hasdata(st, 3))
+ sd = map->id2sd(script_getnum(st, 3));
+ else
+ sd = script->rid2sd(st);
+
if (sd == NULL)
return true;// no player attached, report source
@@ -9260,10 +10502,16 @@ BUILDIN(checkoption1)
/// Checks if the player has that health state (opt2).
///
/// checkoption2(<opt2>) -> <bool>
-BUILDIN(checkoption2)
+static BUILDIN(checkoption2)
{
int opt2;
- struct map_session_data *sd = script->rid2sd(st);
+ struct map_session_data *sd;
+
+ if (script_hasdata(st, 3))
+ sd = map->id2sd(script_getnum(st, 3));
+ else
+ sd = script->rid2sd(st);
+
if (sd == NULL)
return true;// no player attached, report source
@@ -9283,11 +10531,17 @@ BUILDIN(checkoption2)
///
/// setoption <option>,<flag>;
/// setoption <option>;
-BUILDIN(setoption)
+static BUILDIN(setoption)
{
int option;
int flag = 1;
- struct map_session_data *sd = script->rid2sd(st);
+ struct map_session_data *sd;
+
+ if (script_hasdata(st, 4))
+ sd = map->id2sd(script_getnum(st, 4));
+ else
+ sd = script->rid2sd(st);
+
if (sd == NULL)
return true;// no player attached, report source
@@ -9316,7 +10570,7 @@ BUILDIN(setoption)
/// checkcart() -> <bool>
///
/// @author Valaris
-BUILDIN(checkcart)
+static BUILDIN(checkcart)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
@@ -9341,7 +10595,7 @@ BUILDIN(checkcart)
///
/// setcart <type>;
/// setcart;
-BUILDIN(setcart)
+static BUILDIN(setcart)
{
int type = 1;
struct map_session_data *sd = script->rid2sd(st);
@@ -9360,7 +10614,7 @@ BUILDIN(setcart)
/// checkfalcon() -> <bool>
///
/// @author Valaris
-BUILDIN(checkfalcon)
+static BUILDIN(checkfalcon)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
@@ -9379,7 +10633,7 @@ BUILDIN(checkfalcon)
///
/// setfalcon <flag>;
/// setfalcon;
-BUILDIN(setfalcon)
+static BUILDIN(setfalcon)
{
bool flag = true;
struct map_session_data *sd = script->rid2sd(st);
@@ -9416,7 +10670,7 @@ enum setmount_type {
* The exact returned values are the same used as flag in setmount, except for
* dragons, where SETMOUNT_TYPE_DRAGON is returned, regardless of color.
*/
-BUILDIN(checkmount)
+static BUILDIN(checkmount)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
@@ -9440,6 +10694,7 @@ BUILDIN(checkmount)
/**
* Mounts or dismounts a combat mount.
*
+ * setmount <flag>, <mtype>;
* setmount <flag>;
* setmount;
*
@@ -9458,8 +10713,10 @@ BUILDIN(checkmount)
* If an invalid value or no flag is specified, the appropriate mount is
* auto-detected. As a result of this, there is no need to specify a flag at
* all, unless it is a dragon color other than green.
+ *
+ * In newer clients you can specify the mado gear type though the mtype argument.
*/
-BUILDIN(setmount)
+static BUILDIN(setmount)
{
int flag = SETMOUNT_TYPE_AUTODETECT;
struct map_session_data *sd = script->rid2sd(st);
@@ -9470,6 +10727,12 @@ BUILDIN(setmount)
if (script_hasdata(st,2))
flag = script_getnum(st,2);
+ enum mado_type mtype = script_hasdata(st, 3) ? script_getnum(st, 3) : MADO_ROBOT;
+ if (mtype < MADO_ROBOT || mtype >= MADO_MAX) {
+ ShowError("script_setmount: Invalid mado type has been passed (%d).\n", flag);
+ return false;
+ }
+
// Color variants for Rune Knight dragon mounts.
if (flag != SETMOUNT_TYPE_NONE) {
if (flag < SETMOUNT_TYPE_AUTODETECT || flag >= SETMOUNT_TYPE_MAX) {
@@ -9477,7 +10740,7 @@ BUILDIN(setmount)
flag = SETMOUNT_TYPE_AUTODETECT;
}
// Sanity checks and auto-detection
- if ((sd->class_&MAPID_THIRDMASK) == MAPID_RUNE_KNIGHT) {
+ if ((sd->job & MAPID_THIRDMASK) == MAPID_RUNE_KNIGHT) {
if (pc->checkskill(sd, RK_DRAGONTRAINING)) {
// Rune Knight (Dragon)
unsigned int option;
@@ -9489,14 +10752,14 @@ BUILDIN(setmount)
OPTION_DRAGON1); // default value
pc->setridingdragon(sd, option);
}
- } else if ((sd->class_&MAPID_THIRDMASK) == MAPID_RANGER) {
+ } else if ((sd->job & MAPID_THIRDMASK) == MAPID_RANGER) {
// Ranger (Warg)
if (pc->checkskill(sd, RA_WUGRIDER))
pc->setridingwug(sd, true);
- } else if ((sd->class_&MAPID_THIRDMASK) == MAPID_MECHANIC) {
+ } else if ((sd->job & MAPID_THIRDMASK) == MAPID_MECHANIC) {
// Mechanic (Mado Gear)
if (pc->checkskill(sd, NC_MADOLICENCE))
- pc->setmadogear(sd, true);
+ pc->setmadogear(sd, true, mtype);
} else {
// Knight / Crusader (Peco Peco)
if (pc->checkskill(sd, KN_RIDING))
@@ -9510,7 +10773,7 @@ BUILDIN(setmount)
pc->setridingwug(sd, false);
}
if (pc_ismadogear(sd)) {
- pc->setmadogear(sd, false);
+ pc->setmadogear(sd, false, mtype);
}
if (pc_isridingpeco(sd)) {
pc->setridingpeco(sd, false);
@@ -9524,7 +10787,7 @@ BUILDIN(setmount)
///
/// checkwug() -> <bool>
///
-BUILDIN(checkwug)
+static BUILDIN(checkwug)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
@@ -9542,7 +10805,8 @@ BUILDIN(checkwug)
///
/// save "<map name>",<x>,<y>
/// savepoint "<map name>",<x>,<y>
-BUILDIN(savepoint) {
+static BUILDIN(savepoint)
+{
int x;
int y;
short mapid;
@@ -9564,7 +10828,9 @@ BUILDIN(savepoint) {
/*==========================================
* GetTimeTick(0: System Tick, 1: Time Second Tick)
*------------------------------------------*/
-BUILDIN(gettimetick) { /* Asgard Version */
+/* Asgard Version */
+static BUILDIN(gettimetick)
+{
int type;
time_t clock;
struct tm *t;
@@ -9597,7 +10863,9 @@ BUILDIN(gettimetick) { /* Asgard Version */
* 4: WeekDay 5: MonthDay 6: Month
* 7: Year
*------------------------------------------*/
-BUILDIN(gettime) { /* Asgard Version */
+/* Asgard Version */
+static BUILDIN(gettime)
+{
int type;
time_t clock;
struct tm *t;
@@ -9639,83 +10907,131 @@ BUILDIN(gettime) { /* Asgard Version */
return true;
}
-/*==========================================
+/*
* GetTimeStr("TimeFMT", Length);
- *------------------------------------------*/
-BUILDIN(gettimestr)
+ */
+static BUILDIN(gettimestr)
{
char *tmpstr;
const char *fmtstr;
int maxlen;
- time_t now = time(NULL);
+ time_t now;
- fmtstr=script_getstr(st,2);
- maxlen=script_getnum(st,3);
+ fmtstr = script_getstr(st, 2);
+ maxlen = script_getnum(st, 3);
- tmpstr=(char *)aMalloc((maxlen+1)*sizeof(char));
- strftime(tmpstr,maxlen,fmtstr,localtime(&now));
- tmpstr[maxlen]='\0';
+ if (script_hasdata(st, 4)) {
+ int timestamp = script_getnum(st, 4);
+ if (timestamp < 0) {
+ ShowWarning("buildin_gettimestr: UNIX timestamp must be in positive value.\n");
+ return false;
+ }
+
+ now = (time_t)timestamp;
+ } else {
+ now = time(NULL);
+ }
+
+ tmpstr = (char *)aMalloc((maxlen +1)*sizeof(char));
+ strftime(tmpstr, maxlen, fmtstr, localtime(&now));
+ tmpstr[maxlen] = '\0';
- script_pushstr(st,tmpstr);
+ script_pushstr(st, tmpstr);
return true;
}
/*==========================================
* Open player storage
*------------------------------------------*/
-BUILDIN(openstorage)
+static BUILDIN(openstorage)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
+ return false;
+
+ if (sd->storage.received == false) {
+ script_pushint(st, 0);
+ ShowWarning("buildin_openstorage: Storage data for AID %d has not been loaded.\n", sd->bl.id);
+ return false;
+ }
+
+ // Mapflag preventing from openstorage here
+ if (!pc_has_permission(sd, PC_PERM_BYPASS_NOSTORAGE) && (map->list[sd->bl.m].flag.nostorage & 2)) {
+ script_pushint(st, 0);
return true;
+ }
storage->open(sd);
+
+ script_pushint(st, 1); // success flag.
return true;
}
-BUILDIN(guildopenstorage)
+static BUILDIN(guildopenstorage)
{
int ret;
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
return true;
+ // Mapflag preventing from openstorage here
+ if (!pc_has_permission(sd, PC_PERM_BYPASS_NOSTORAGE) && (map->list[sd->bl.m].flag.nogstorage & 2)) {
+ script_pushint(st, 1);
+ return true;
+ }
+
ret = gstorage->open(sd);
script_pushint(st,ret);
return true;
}
-/*==========================================
- * Make player use a skill trought item usage
- *------------------------------------------*/
-/// itemskill <skill id>,<level>{,flag
-/// itemskill "<skill name>",<level>{,flag
-BUILDIN(itemskill)
+/**
+ * Makes the attached character use a skill by using an item.
+ *
+ * @code{.herc}
+ * itemskill(<skill id>, <skill level>{, <flag>});
+ * itemskill("<skill name>", <skill level>{, <flag>});
+ * @endcode
+ *
+ */
+static BUILDIN(itemskill)
{
- int id;
- int lv;
struct map_session_data *sd = script->rid2sd(st);
+
if (sd == NULL || sd->ud.skilltimer != INVALID_TIMER)
return true;
- id = ( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) );
- lv = script_getnum(st,3);
-/* temporarily disabled, awaiting for kenpachi to detail this so we can make it work properly */
-#if 0
- if( !script_hasdata(st, 4) ) {
- if( !skill->check_condition_castbegin(sd,id,lv) || !skill->check_condition_castend(sd,id,lv) )
+ pc->autocast_clear(sd);
+ sd->autocast.type = AUTOCAST_ITEM;
+ sd->autocast.skill_id = script_isstringtype(st, 2) ? skill->name2id(script_getstr(st, 2)) : script_getnum(st, 2);
+ sd->autocast.skill_lv = script_getnum(st, 3);
+
+ int flag = script_hasdata(st, 4) ? script_getnum(st, 4) : ISF_NONE;
+
+ sd->autocast.itemskill_check_conditions = ((flag & ISF_CHECKCONDITIONS) == ISF_CHECKCONDITIONS);
+
+ if (sd->autocast.itemskill_check_conditions) {
+ if (skill->check_condition_castbegin(sd, sd->autocast.skill_id, sd->autocast.skill_lv) == 0
+ || skill->check_condition_castend(sd, sd->autocast.skill_id, sd->autocast.skill_lv) == 0) {
+ pc->autocast_clear(sd);
return true;
+ }
+
+ sd->autocast.itemskill_conditions_checked = true;
}
-#endif
- sd->skillitem=id;
- sd->skillitemlv=lv;
- clif->item_skill(sd,id,lv);
+
+ sd->autocast.itemskill_instant_cast = ((flag & ISF_INSTANTCAST) == ISF_INSTANTCAST);
+ sd->autocast.itemskill_cast_on_self = ((flag & ISF_CASTONSELF) == ISF_CASTONSELF);
+
+ clif->item_skill(sd, sd->autocast.skill_id, sd->autocast.skill_lv);
+
return true;
}
+
/*==========================================
* Attempt to create an item
*------------------------------------------*/
-BUILDIN(produce)
+static BUILDIN(produce)
{
int trigger;
struct map_session_data *sd = script->rid2sd(st);
@@ -9729,7 +11045,7 @@ BUILDIN(produce)
/*==========================================
*
*------------------------------------------*/
-BUILDIN(cooking)
+static BUILDIN(cooking)
{
int trigger;
struct map_session_data *sd = script->rid2sd(st);
@@ -9743,7 +11059,7 @@ BUILDIN(cooking)
/*==========================================
* Create a pet
*------------------------------------------*/
-BUILDIN(makepet)
+static BUILDIN(makepet)
{
struct map_session_data *sd;
int id,pet_id;
@@ -9760,8 +11076,8 @@ BUILDIN(makepet)
if (pet_id >= 0 && sd) {
sd->catch_target_class = pet->db[pet_id].class_;
intif->create_pet(sd->status.account_id, sd->status.char_id,
- (short)pet->db[pet_id].class_, (short)mob->db(pet->db[pet_id].class_)->lv,
- (short)pet->db[pet_id].EggID, 0, (short)pet->db[pet_id].intimate,
+ pet->db[pet_id].class_, mob->db(pet->db[pet_id].class_)->lv,
+ pet->db[pet_id].EggID, 0, (short)pet->db[pet_id].intimate,
100, 0, 1, pet->db[pet_id].jname);
}
@@ -9770,7 +11086,7 @@ BUILDIN(makepet)
/*==========================================
* Give player exp base,job * quest_exp_rate/100
*------------------------------------------*/
-BUILDIN(getexp)
+static BUILDIN(getexp)
{
int base=0,job=0;
struct map_session_data *sd = script->rid2sd(st);
@@ -9794,7 +11110,7 @@ BUILDIN(getexp)
/*==========================================
* Gain guild exp [Celest]
*------------------------------------------*/
-BUILDIN(guildgetexp)
+static BUILDIN(guildgetexp)
{
int exp;
struct map_session_data *sd = script->rid2sd(st);
@@ -9813,7 +11129,7 @@ BUILDIN(guildgetexp)
/*==========================================
* Changes the guild master of a guild [Skotlex]
*------------------------------------------*/
-BUILDIN(guildchangegm)
+static BUILDIN(guildchangegm)
{
struct map_session_data *sd;
int guild_id;
@@ -9826,7 +11142,7 @@ BUILDIN(guildchangegm)
if (sd == NULL)
script_pushint(st,0);
else
- script_pushint(st,guild->gm_change(guild_id, sd));
+ script_pushint(st, guild->gm_change(guild_id, sd->status.char_id));
return true;
}
@@ -9839,7 +11155,7 @@ BUILDIN(guildchangegm)
* @amount : nb to spawn
* @event : event to attach to mob
*------------------------------------------*/
-BUILDIN(monster)
+static BUILDIN(monster)
{
const char *mapn = script_getstr(st,2);
int x = script_getnum(st,3);
@@ -9911,7 +11227,7 @@ BUILDIN(monster)
/*==========================================
* Request List of Monster Drops
*------------------------------------------*/
-BUILDIN(getmobdrops)
+static BUILDIN(getmobdrops)
{
int class_ = script_getnum(st,2);
int i, j = 0;
@@ -9932,13 +11248,13 @@ BUILDIN(getmobdrops)
if( itemdb->exists(monster->dropitem[i].nameid) == NULL )
continue;
- mapreg->setreg(reference_uid(script->add_str("$@MobDrop_item"), j), monster->dropitem[i].nameid);
- mapreg->setreg(reference_uid(script->add_str("$@MobDrop_rate"), j), monster->dropitem[i].p);
+ mapreg->setreg(reference_uid(script->add_variable("$@MobDrop_item"), j), monster->dropitem[i].nameid);
+ mapreg->setreg(reference_uid(script->add_variable("$@MobDrop_rate"), j), monster->dropitem[i].p);
j++;
}
- mapreg->setreg(script->add_str("$@MobDrop_count"), j);
+ mapreg->setreg(script->add_variable("$@MobDrop_count"), j);
script_pushint(st, 1);
return true;
@@ -9946,7 +11262,8 @@ BUILDIN(getmobdrops)
/*==========================================
* Same as monster but randomize location in x0,x1,y0,y1 area
*------------------------------------------*/
-BUILDIN(areamonster) {
+static BUILDIN(areamonster)
+{
const char *mapn = script_getstr(st,2);
int x0 = script_getnum(st,3);
int y0 = script_getnum(st,4);
@@ -10009,7 +11326,7 @@ BUILDIN(areamonster) {
/*==========================================
* KillMonster subcheck, verify if mob to kill ain't got an even to handle, could be force kill by allflag
*------------------------------------------*/
-int buildin_killmonster_sub_strip(struct block_list *bl, va_list ap)
+static int buildin_killmonster_sub_strip(struct block_list *bl, va_list ap)
{
//same fix but with killmonster instead - stripping events from mobs.
struct mob_data *md = NULL;
@@ -10032,7 +11349,7 @@ int buildin_killmonster_sub_strip(struct block_list *bl, va_list ap)
md->state.npc_killmonster = 0;
return 0;
}
-int buildin_killmonster_sub(struct block_list *bl, va_list ap)
+static int buildin_killmonster_sub(struct block_list *bl, va_list ap)
{
struct mob_data *md = NULL;
char *event = va_arg(ap,char *);
@@ -10051,15 +11368,22 @@ int buildin_killmonster_sub(struct block_list *bl, va_list ap)
}
return 0;
}
-BUILDIN(killmonster) {
+static BUILDIN(killmonster)
+{
const char *mapname,*event;
int16 m,allflag=0;
mapname=script_getstr(st,2);
event=script_getstr(st,3);
- if(strcmp(event,"All")==0)
+
+ if (strcmpi(event, "all") == 0) {
+ if (strcmp(event, "all") != 0) {
+ ShowWarning("buildin_killmonster: \"%s\" deprecated! Please use \"all\" instead.\n", event);
+ script->reportsrc(st);
+ }
allflag = 1;
- else
+ } else {
script->check_event(st, event);
+ }
if( (m=map->mapname2mapid(mapname))<0 )
return true;
@@ -10080,23 +11404,25 @@ BUILDIN(killmonster) {
return true;
}
-int buildin_killmonsterall_sub_strip(struct block_list *bl,va_list ap)
+static int buildin_killmonsterall_sub_strip(struct block_list *bl, va_list ap)
{ //Strips the event from the mob if it's killed the old method.
struct mob_data *md;
md = BL_CAST(BL_MOB, bl);
+ nullpo_ret(md);
if (md->npc_event[0])
md->npc_event[0] = 0;
status_kill(bl);
return 0;
}
-int buildin_killmonsterall_sub(struct block_list *bl,va_list ap)
+static int buildin_killmonsterall_sub(struct block_list *bl, va_list ap)
{
status_kill(bl);
return 0;
}
-BUILDIN(killmonsterall) {
+static BUILDIN(killmonsterall)
+{
const char *mapname;
int16 m;
mapname=script_getstr(st,2);
@@ -10118,11 +11444,27 @@ BUILDIN(killmonsterall) {
return true;
}
+static BUILDIN(killmonstergid)
+{
+ int mobgid = script_getnum(st, 2);
+ struct mob_data *md = map->id2md(mobgid);
+
+ if (md == NULL) {
+ ShowWarning("buildin_killmonstergid: Error in finding monster GID '%d' or the target is not a monster.\n", mobgid);
+ return false;
+ }
+
+ md->state.npc_killmonster = 1;
+ status_kill(&md->bl);
+ return true;
+}
+
/*==========================================
* Creates a clone of a player.
* clone map, x, y, event, char_id, master_id, mode, flag, duration
*------------------------------------------*/
-BUILDIN(clone) {
+static BUILDIN(clone)
+{
struct map_session_data *sd, *msd = NULL;
int char_id, master_id = 0, x, y, flag = 0, m;
uint32 mode = 0;
@@ -10170,7 +11512,7 @@ BUILDIN(clone) {
}
/*==========================================
*------------------------------------------*/
-BUILDIN(doevent)
+static BUILDIN(doevent)
{
const char* event = script_getstr(st,2);
struct map_session_data* sd;
@@ -10186,7 +11528,7 @@ BUILDIN(doevent)
}
/*==========================================
*------------------------------------------*/
-BUILDIN(donpcevent)
+static BUILDIN(donpcevent)
{
const char* event = script_getstr(st,2);
script->check_event(st, event);
@@ -10201,61 +11543,311 @@ BUILDIN(donpcevent)
/*==========================================
*------------------------------------------*/
-BUILDIN(addtimer)
+static BUILDIN(addtimer)
{
- int tick = script_getnum(st,2);
+ int tick = script_getnum(st, 2);
const char* event = script_getstr(st, 3);
struct map_session_data *sd;
script->check_event(st, event);
- sd = script->rid2sd(st);
- if( sd == NULL )
- return true;
- if (!pc->addeventtimer(sd,tick,event)) {
- ShowWarning("buildin_addtimer: Event timer is full, can't add new event timer. (cid:%d timer:%s)\n",sd->status.char_id,event);
+ if (script_hasdata(st, 4))
+ sd = map->id2sd(script_getnum(st, 4));
+ else
+ sd = script->rid2sd(st);
+
+ if (sd == NULL) {
+ script_pushint(st, 0);
return false;
}
+
+ if (!pc->addeventtimer(sd, tick, event)) {
+ ShowWarning("script:addtimer: Event timer is full, can't add new event timer. (cid:%d timer:%s)\n", sd->status.char_id, event);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ script_pushint(st, 1);
return true;
}
/*==========================================
*------------------------------------------*/
-BUILDIN(deltimer)
+static BUILDIN(deltimer)
{
const char *event;
struct map_session_data *sd;
event=script_getstr(st, 2);
- sd = script->rid2sd(st);
- if( sd == NULL )
+
+ if (script_hasdata(st, 3))
+ sd = map->id2sd(script_getnum(st, 3));
+ else
+ sd = script->rid2sd(st);
+
+ if (sd == NULL)
return true;
script->check_event(st, event);
- pc->deleventtimer(sd,event);
+ pc->deleventtimer(sd, event);
return true;
}
/*==========================================
*------------------------------------------*/
-BUILDIN(addtimercount)
+static BUILDIN(addtimercount)
{
const char *event;
int tick;
struct map_session_data *sd;
- event=script_getstr(st, 2);
- tick=script_getnum(st,3);
- sd = script->rid2sd(st);
- if( sd == NULL )
+ event = script_getstr(st, 2);
+ tick = script_getnum(st, 3);
+
+ if (script_hasdata(st, 4))
+ sd = map->id2sd(script_getnum(st, 4));
+ else
+ sd = script->rid2sd(st);
+
+ if (sd == NULL)
return true;
script->check_event(st, event);
- pc->addeventtimercount(sd,event,tick);
+ pc->addeventtimercount(sd, event, tick);
+ return true;
+}
+
+enum gettimer_mode {
+ GETTIMER_COUNT = 0,
+ GETTIMER_TICK_NEXT = 1,
+ GETTIMER_TICK_LAST = 2,
+};
+
+static BUILDIN(gettimer)
+{
+ struct map_session_data *sd;
+ const struct TimerData *td;
+ int i;
+ int tick;
+ const char *event = NULL;
+ int val = 0;
+ bool first = true;
+ short mode = script_getnum(st, 2);
+
+ if (script_hasdata(st, 3))
+ sd = map->id2sd(script_getnum(st, 3));
+ else
+ sd = script->rid2sd(st);
+
+ if (script_hasdata(st, 4)) {
+ event = script_getstr(st, 4);
+ script->check_event(st, event);
+ }
+
+ if (sd == NULL) {
+ script_pushint(st, -1);
+ return true;
+ }
+
+ switch (mode) {
+ case GETTIMER_COUNT:
+ // get number of timers
+ for (i = 0; i < MAX_EVENTTIMER; i++) {
+ if (sd->eventtimer[i] != INVALID_TIMER) {
+ if (event != NULL) {
+ td = timer->get(sd->eventtimer[i]);
+ Assert_retr(false, td != NULL);
+
+ if (strcmp((char *)(td->data), event) == 0) {
+ val++;
+ }
+ } else {
+ val++;
+ }
+ }
+ }
+ break;
+ case GETTIMER_TICK_NEXT:
+ // get the number of tick before the next timer runs
+ for (i = 0; i < MAX_EVENTTIMER; i++) {
+ if (sd->eventtimer[i] != INVALID_TIMER) {
+ td = timer->get(sd->eventtimer[i]);
+ Assert_retr(false, td != NULL);
+ tick = max(0, DIFF_TICK32(td->tick, timer->gettick()));
+
+ if (event != NULL) {
+ if ((first == true || tick < val) && strcmp((char *)(td->data), event) == 0) {
+ val = tick;
+ first = false;
+ }
+ } else if (first == true || tick < val) {
+ val = tick;
+ first = false;
+ }
+ }
+ }
+ break;
+ case GETTIMER_TICK_LAST:
+ // get the number of ticks before the last timer runs
+ for (i = MAX_EVENTTIMER - 1; i >= 0; i--) {
+ if (sd->eventtimer[i] != INVALID_TIMER) {
+ td = timer->get(sd->eventtimer[i]);
+ Assert_retr(false, td != NULL);
+ tick = max(0, DIFF_TICK32(td->tick, timer->gettick()));
+
+ if (event != NULL) {
+ if (strcmp((char *)(td->data), event) == 0) {
+ val = max(val, tick);
+ }
+ } else {
+ val = max(val, tick);
+ }
+ }
+ }
+ break;
+ }
+
+ script_pushint(st, val);
+ return true;
+}
+
+static int buildin_getunits_sub(struct block_list *bl, va_list ap)
+{
+ struct script_state *st = va_arg(ap, struct script_state *);
+ struct map_session_data *sd = va_arg(ap, struct map_session_data *);
+ int32 id = va_arg(ap, int32);
+ uint32 start = va_arg(ap, uint32);
+ uint32 *count = va_arg(ap, uint32 *);
+ uint32 limit = va_arg(ap, uint32);
+ const char *name = va_arg(ap, const char *);
+ struct reg_db *ref = va_arg(ap, struct reg_db *);
+ enum bl_type type = va_arg(ap, enum bl_type);
+ uint32 index = start + *count;
+
+ if ((bl->type & type) == 0) {
+ return 0; // type mismatch => skip
+ }
+
+ if (index >= SCRIPT_MAX_ARRAYSIZE || *count >= limit) {
+ return -1;
+ }
+
+ script->set_reg(st, sd, reference_uid(id, index), name,
+ (const void *)h64BPTRSIZE(bl->id), ref);
+
+ (*count)++;
+ return 1;
+}
+
+static int buildin_getunits_sub_pc(struct map_session_data *sd, va_list ap)
+{
+ return buildin_getunits_sub(&sd->bl, ap);
+}
+
+static int buildin_getunits_sub_mob(struct mob_data *md, va_list ap)
+{
+ return buildin_getunits_sub(&md->bl, ap);
+}
+
+static int buildin_getunits_sub_npc(struct npc_data *nd, va_list ap)
+{
+ return buildin_getunits_sub(&nd->bl, ap);
+}
+
+static BUILDIN(getunits)
+{
+ const char *name;
+ int32 id;
+ uint32 start;
+ struct reg_db *ref;
+ enum bl_type type = script_getnum(st, 2);
+ struct script_data *data = script_getdata(st, 3);
+ uint32 count = 0;
+ uint32 limit = script_getnum(st, 4);
+ struct map_session_data *sd = NULL;
+
+ if (!data_isreference(data) || reference_toconstant(data)) {
+ ShowError("script:getunits: second argument must be a variable\n");
+ script->reportdata(data);
+ st->state = END;
+ return false;
+ }
+
+ id = reference_getid(data);
+ start = reference_getindex(data);
+ name = reference_getname(data);
+ ref = reference_getref(data);
+
+ if (not_server_variable(*name)) {
+ sd = script->rid2sd(st);
+
+ if (sd == NULL) {
+ script_pushint(st, 0);
+ return true; // player variable but no player attached
+ }
+ }
+
+ if (is_string_variable(name)) {
+ ShowError("script:getunits: second argument must be an integer variable\n");
+ script->reportdata(data);
+ st->state = END;
+ return false;
+ }
+
+ if (limit < 1 || limit > SCRIPT_MAX_ARRAYSIZE) {
+ limit = SCRIPT_MAX_ARRAYSIZE;
+ }
+
+ if (script_hasdata(st, 5)) {
+ const char *mapname = script_getstr(st, 5);
+ int16 m = map->mapname2mapid(mapname);
+
+ if (m == -1) {
+ ShowError("script:getunits: Invalid map(%s) provided.\n", mapname);
+ script->reportdata(data);
+ st->state = END;
+ return false;
+ }
+
+ if (script_hasdata(st, 9)) {
+ int16 x1 = script_getnum(st, 6);
+ int16 y1 = script_getnum(st, 7);
+ int16 x2 = script_getnum(st, 8);
+ int16 y2 = script_getnum(st, 9);
+
+ map->forcountinarea(buildin_getunits_sub, m, x1, y1, x2, y2, limit, type,
+ st, sd, id, start, &count, limit, name, ref, type);
+ } else {
+ map->forcountinmap(buildin_getunits_sub, m, limit, type,
+ st, sd, id, start, &count, limit, name, ref, type);
+ }
+ } else {
+ // for faster lookup we try to reduce the scope of the search if possible
+ switch (type) {
+ case BL_PC:
+ map->foreachpc(buildin_getunits_sub_pc,
+ st, sd, id, start, &count, limit, name, ref, type);
+ break;
+ case BL_MOB:
+ map->foreachmob(buildin_getunits_sub_mob,
+ st, sd, id, start, &count, limit, name, ref, type);
+ break;
+ case BL_NPC:
+ map->foreachnpc(buildin_getunits_sub_npc,
+ st, sd, id, start, &count, limit, name, ref, type);
+ break;
+ default:
+ // fallback to global lookup (slowest option)
+ map->foreachiddb(buildin_getunits_sub,
+ st, sd, id, start, &count, limit, name, ref, type);
+ }
+ }
+
+ script_pushint(st, count);
return true;
}
/*==========================================
*------------------------------------------*/
-BUILDIN(initnpctimer)
+static BUILDIN(initnpctimer)
{
struct npc_data *nd;
int flag = 0;
@@ -10300,7 +11892,7 @@ BUILDIN(initnpctimer)
}
/*==========================================
*------------------------------------------*/
-BUILDIN(startnpctimer)
+static BUILDIN(startnpctimer)
{
struct npc_data *nd;
int flag = 0;
@@ -10343,7 +11935,8 @@ BUILDIN(startnpctimer)
}
/*==========================================
*------------------------------------------*/
-BUILDIN(stopnpctimer) {
+static BUILDIN(stopnpctimer)
+{
struct npc_data *nd;
int flag = 0;
@@ -10381,7 +11974,7 @@ BUILDIN(stopnpctimer) {
}
/*==========================================
*------------------------------------------*/
-BUILDIN(getnpctimer)
+static BUILDIN(getnpctimer)
{
struct npc_data *nd;
struct map_session_data *sd;
@@ -10419,7 +12012,7 @@ BUILDIN(getnpctimer)
}
/*==========================================
*------------------------------------------*/
-BUILDIN(setnpctimer)
+static BUILDIN(setnpctimer)
{
int tick;
struct npc_data *nd;
@@ -10444,7 +12037,7 @@ BUILDIN(setnpctimer)
/*==========================================
* attaches the player rid to the timer [Celest]
*------------------------------------------*/
-BUILDIN(attachnpctimer)
+static BUILDIN(attachnpctimer)
{
struct map_session_data *sd;
struct npc_data *nd = map->id2nd(st->oid);
@@ -10473,7 +12066,8 @@ BUILDIN(attachnpctimer)
/*==========================================
* detaches a player rid from the timer [Celest]
*------------------------------------------*/
-BUILDIN(detachnpctimer) {
+static BUILDIN(detachnpctimer)
+{
struct npc_data *nd;
if( script_hasdata(st,2) )
@@ -10497,7 +12091,8 @@ BUILDIN(detachnpctimer) {
* it checks if there is a player attached to the current script. [Skotlex]
* If no, returns 0, if yes, returns the account_id of the attached player.
*------------------------------------------*/
-BUILDIN(playerattached) {
+static BUILDIN(playerattached)
+{
if(st->rid == 0 || map->id2sd(st->rid) == NULL)
script_pushint(st,0);
else
@@ -10506,8 +12101,21 @@ BUILDIN(playerattached) {
}
/*==========================================
+ * Used by OnTouchNPC: label to return monster GID
*------------------------------------------*/
-BUILDIN(announce) {
+static BUILDIN(mobattached)
+{
+ if (st->rid == 0 || map->id2md(st->rid) == NULL)
+ script_pushint(st, 0);
+ else
+ script_pushint(st, st->rid);
+ return true;
+}
+
+/*==========================================
+ *------------------------------------------*/
+static BUILDIN(announce)
+{
const char *mes = script_getstr(st,2);
int flag = script_getnum(st,3);
const char *fontColor = script_hasdata(st,4) ? script_getstr(st,4) : NULL;
@@ -10515,11 +12123,13 @@ BUILDIN(announce) {
int fontSize = script_hasdata(st,6) ? script_getnum(st,6) : 12; // default fontSize
int fontAlign = script_hasdata(st,7) ? script_getnum(st,7) : 0; // default fontAlign
int fontY = script_hasdata(st,8) ? script_getnum(st,8) : 0; // default fontY
+ size_t len = strlen(mes);
+ send_target target = ALL_CLIENT;
+ struct block_list *bl = NULL;
+ Assert_retr(false, len < INT_MAX);
if( flag&(BC_TARGET_MASK|BC_SOURCE_MASK) ) {
// Broadcast source or broadcast region defined
- send_target target;
- struct block_list *bl = NULL;
if (flag&BC_NPC) {
// If bc_npc flag is set, use NPC as broadcast source
bl = map->id2bl(st->oid);
@@ -10537,27 +12147,23 @@ BUILDIN(announce) {
case BC_SELF: target = SELF; break;
default: target = ALL_CLIENT; break; // BC_ALL
}
-
- if (fontColor)
- clif->broadcast2(bl, mes, (int)strlen(mes)+1, (unsigned int)strtoul(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY, target);
- else
- clif->broadcast(bl, mes, (int)strlen(mes)+1, flag&BC_COLOR_MASK, target);
- } else {
- if (fontColor)
- intif->broadcast2(mes, (int)strlen(mes)+1, (unsigned int)strtoul(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY);
- else
- intif->broadcast(mes, (int)strlen(mes)+1, flag&BC_COLOR_MASK);
}
+
+ if (fontColor)
+ clif->broadcast2(bl, mes, (int)len+1, (unsigned int)strtoul(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY, target);
+ else
+ clif->broadcast(bl, mes, (int)len+1, flag&BC_COLOR_MASK, target);
+
return true;
}
/*==========================================
*------------------------------------------*/
-int buildin_announce_sub(struct block_list *bl, va_list ap)
+static int buildin_announce_sub(struct block_list *bl, va_list ap)
{
- char *mes = va_arg(ap, char *);
+ const char *mes = va_arg(ap, const char *);
int len = va_arg(ap, int);
int type = va_arg(ap, int);
- char *fontColor = va_arg(ap, char *);
+ const char *fontColor = va_arg(ap, const char *);
short fontType = (short)va_arg(ap, int);
short fontSize = (short)va_arg(ap, int);
short fontAlign = (short)va_arg(ap, int);
@@ -10571,7 +12177,7 @@ int buildin_announce_sub(struct block_list *bl, va_list ap)
/* Runs item effect on attached character.
* itemeffect <item id>;
* itemeffect "<item name>"; */
-BUILDIN(itemeffect)
+static BUILDIN(itemeffect)
{
struct npc_data *nd;
struct item_data *item_data;
@@ -10604,7 +12210,8 @@ BUILDIN(itemeffect)
return true;
}
-BUILDIN(mapannounce) {
+static BUILDIN(mapannounce)
+{
const char *mapname = script_getstr(st,2);
const char *mes = script_getstr(st,3);
int flag = script_getnum(st,4);
@@ -10614,17 +12221,20 @@ BUILDIN(mapannounce) {
int fontAlign = script_hasdata(st,8) ? script_getnum(st,8) : 0; // default fontAlign
int fontY = script_hasdata(st,9) ? script_getnum(st,9) : 0; // default fontY
int16 m;
+ size_t len = strlen(mes);
+ Assert_retr(false, len < INT_MAX);
if ((m = map->mapname2mapid(mapname)) < 0)
return true;
map->foreachinmap(script->buildin_announce_sub, m, BL_PC,
- mes, strlen(mes)+1, flag&BC_COLOR_MASK, fontColor, fontType, fontSize, fontAlign, fontY);
+ mes, (int)len+1, flag&BC_COLOR_MASK, fontColor, fontType, fontSize, fontAlign, fontY);
return true;
}
/*==========================================
*------------------------------------------*/
-BUILDIN(areaannounce) {
+static BUILDIN(areaannounce)
+{
const char *mapname = script_getstr(st,2);
int x0 = script_getnum(st,3);
int y0 = script_getnum(st,4);
@@ -10638,18 +12248,21 @@ BUILDIN(areaannounce) {
int fontAlign = script_hasdata(st,12) ? script_getnum(st,12) : 0; // default fontAlign
int fontY = script_hasdata(st,13) ? script_getnum(st,13) : 0; // default fontY
int16 m;
+ size_t len = strlen(mes);
+ Assert_retr(false, len < INT_MAX);
if ((m = map->mapname2mapid(mapname)) < 0)
return true;
map->foreachinarea(script->buildin_announce_sub, m, x0, y0, x1, y1, BL_PC,
- mes, strlen(mes)+1, flag&BC_COLOR_MASK, fontColor, fontType, fontSize, fontAlign, fontY);
+ mes, (int)len+1, flag&BC_COLOR_MASK, fontColor, fontType, fontSize, fontAlign, fontY);
return true;
}
/*==========================================
*------------------------------------------*/
-BUILDIN(getusers) {
+static BUILDIN(getusers)
+{
int flag, val = 0;
struct map_session_data* sd;
struct block_list* bl = NULL;
@@ -10685,7 +12298,7 @@ BUILDIN(getusers) {
/*==========================================
* Works like @WHO - displays all online users names in window
*------------------------------------------*/
-BUILDIN(getusersname)
+static BUILDIN(getusersname)
{
struct map_session_data *sd;
const struct map_session_data *pl_sd;
@@ -10714,7 +12327,7 @@ BUILDIN(getusersname)
/*==========================================
* getmapguildusers("mapname",guild ID) Returns the number guild members present on a map [Reddozen]
*------------------------------------------*/
-BUILDIN(getmapguildusers)
+static BUILDIN(getmapguildusers)
{
const char *str;
int16 m;
@@ -10742,7 +12355,8 @@ BUILDIN(getmapguildusers)
}
/*==========================================
*------------------------------------------*/
-BUILDIN(getmapusers) {
+static BUILDIN(getmapusers)
+{
const char *str;
int16 m;
str=script_getstr(st,2);
@@ -10755,14 +12369,15 @@ BUILDIN(getmapusers) {
}
/*==========================================
*------------------------------------------*/
-int buildin_getareausers_sub(struct block_list *bl,va_list ap)
+static int buildin_getareausers_sub(struct block_list *bl, va_list ap)
{
int *users=va_arg(ap,int *);
+ nullpo_ret(users);
(*users)++;
return 0;
}
-BUILDIN(getareausers)
+static BUILDIN(getareausers)
{
int16 m = -1, x0, y0, x1, y1;
int users = 0;
@@ -10822,7 +12437,7 @@ BUILDIN(getareausers)
/*==========================================
*------------------------------------------*/
-int buildin_getareadropitem_sub(struct block_list *bl, va_list ap)
+static int buildin_getareadropitem_sub(struct block_list *bl, va_list ap)
{
int item = va_arg(ap, int);
int *amount = va_arg(ap, int *);
@@ -10838,7 +12453,8 @@ int buildin_getareadropitem_sub(struct block_list *bl, va_list ap)
return 0;
}
-BUILDIN(getareadropitem) {
+static BUILDIN(getareadropitem)
+{
const char *str;
int16 m,x0,y0,x1,y1;
int item,amount=0;
@@ -10870,7 +12486,7 @@ BUILDIN(getareadropitem) {
}
/*==========================================
*------------------------------------------*/
-BUILDIN(enablenpc)
+static BUILDIN(enablenpc)
{
const char *str;
str=script_getstr(st,2);
@@ -10879,7 +12495,7 @@ BUILDIN(enablenpc)
}
/*==========================================
*------------------------------------------*/
-BUILDIN(disablenpc)
+static BUILDIN(disablenpc)
{
const char *str;
str=script_getstr(st,2);
@@ -10889,7 +12505,7 @@ BUILDIN(disablenpc)
/*==========================================
*------------------------------------------*/
-BUILDIN(hideoffnpc)
+static BUILDIN(hideoffnpc)
{
const char *str;
str=script_getstr(st,2);
@@ -10898,13 +12514,63 @@ BUILDIN(hideoffnpc)
}
/*==========================================
*------------------------------------------*/
-BUILDIN(hideonnpc)
+static BUILDIN(hideonnpc)
{
const char *str;
str=script_getstr(st,2);
npc->enable(str,4);
return true;
}
+/*==========================================
+ *------------------------------------------*/
+static BUILDIN(cloakonnpc)
+{
+ struct npc_data *nd = npc->name2id(script_getstr(st, 2));
+ if (nd == NULL) {
+ ShowError("buildin_cloakonnpc: invalid npc name '%s'.\n", script_getstr(st, 2));
+ return false;
+ }
+
+ if (script_hasdata(st, 3)) {
+ struct map_session_data *sd = map->id2sd(script_getnum(st, 3));
+ if (sd == NULL)
+ return false;
+
+ uint32 val = nd->option;
+ nd->option |= OPTION_CLOAK;
+ clif->changeoption_target(&nd->bl, &sd->bl, SELF);
+ nd->option = val;
+ } else {
+ nd->option |= OPTION_CLOAK;
+ clif->changeoption(&nd->bl);
+ }
+ return true;
+}
+/*==========================================
+ *------------------------------------------*/
+static BUILDIN(cloakoffnpc)
+{
+ struct npc_data *nd = npc->name2id(script_getstr(st, 2));
+ if (nd == NULL) {
+ ShowError("buildin_cloakoffnpc: invalid npc name '%s'.\n", script_getstr(st, 2));
+ return false;
+ }
+
+ if (script_hasdata(st, 3)) {
+ struct map_session_data *sd = map->id2sd(script_getnum(st, 3));
+ if (sd == NULL)
+ return false;
+
+ uint32 val = nd->option;
+ nd->option &= ~OPTION_CLOAK;
+ clif->changeoption_target(&nd->bl, &sd->bl, SELF);
+ nd->option = val;
+ } else {
+ nd->option &= ~OPTION_CLOAK;
+ clif->changeoption(&nd->bl);
+ }
+ return true;
+}
/* Starts a status effect on the target unit or on the attached player.
*
@@ -10913,7 +12579,7 @@ BUILDIN(hideonnpc)
* sc_start4 <effect_id>,<duration>,<val1>,<val2>,<val3>,<val4>{,<rate,<flag>,{<unit_id>}};
* <flag>: @see enum scstart_flag
*/
-BUILDIN(sc_start)
+static BUILDIN(sc_start)
{
struct npc_data *nd = map->id2nd(st->oid);
struct block_list* bl;
@@ -10981,7 +12647,8 @@ BUILDIN(sc_start)
/// Ends one or all status effects on the target unit or on the attached player.
///
/// sc_end <effect_id>{,<unit_id>};
-BUILDIN(sc_end) {
+static BUILDIN(sc_end)
+{
struct block_list* bl;
int type;
@@ -11016,7 +12683,9 @@ BUILDIN(sc_end) {
}
//This should help status_change_end force disabling the SC in case it has no limit.
- sce->val1 = sce->val2 = sce->val3 = sce->val4 = 0;
+ if (type != SC_BERSERK)
+ sce->val1 = 0; // SC_BERSERK requires skill_lv that's stored in sce->val1 when being removed [KirieZ]
+ sce->val2 = sce->val3 = sce->val4 = 0;
status_change_end(bl, (sc_type)type, INVALID_TIMER);
}
else
@@ -11028,7 +12697,8 @@ BUILDIN(sc_end) {
/*==========================================
* @FIXME atm will return reduced tick, 0 immune, 1 no tick
*------------------------------------------*/
-BUILDIN(getscrate) {
+static BUILDIN(getscrate)
+{
struct block_list *bl;
int type,rate;
@@ -11049,7 +12719,7 @@ BUILDIN(getscrate) {
/*==========================================
* getstatus <type>{, <info>};
*------------------------------------------*/
-BUILDIN(getstatus)
+static BUILDIN(getstatus)
{
int id, type;
struct map_session_data* sd = script->rid2sd(st);
@@ -11080,14 +12750,16 @@ BUILDIN(getstatus)
case 3: script_pushint(st, sd->sc.data[id]->val3); break;
case 4: script_pushint(st, sd->sc.data[id]->val4); break;
case 5:
- {
- const struct TimerData *td = timer->get(sd->sc.data[id]->timer);
+ if (sd->sc.data[id]->infinite_duration) {
+ script_pushint(st, INFINITE_DURATION);
+ } else {
+ const struct TimerData *td = timer->get(sd->sc.data[id]->timer);
- if (td != NULL) {
- // return the amount of time remaining
- script_pushint(st, (int)(td->tick - timer->gettick())); // TODO: change this to int64 when we'll support 64 bit script values
+ if (td != NULL) {
+ // return the amount of time remaining
+ script_pushint(st, (int)(td->tick - timer->gettick())); // TODO: change this to int64 when we'll support 64 bit script values
+ }
}
- }
break;
default: script_pushint(st, 1); break;
}
@@ -11098,17 +12770,26 @@ BUILDIN(getstatus)
/*==========================================
*
*------------------------------------------*/
-BUILDIN(debugmes)
+static BUILDIN(debugmes)
{
- const char *str;
- str=script_getstr(st,2);
- ShowDebug("script debug : %d %d : %s\n",st->rid,st->oid,str);
+ struct StringBuf buf;
+ StrBuf->Init(&buf);
+
+ if (!script->sprintf_helper(st, 2, &buf)) {
+ StrBuf->Destroy(&buf);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ ShowDebug("script debug : %d %d : %s\n", st->rid, st->oid, StrBuf->Value(&buf));
+ StrBuf->Destroy(&buf);
+ script_pushint(st, 1);
return true;
}
/*==========================================
*------------------------------------------*/
-BUILDIN(catchpet)
+static BUILDIN(catchpet)
{
int pet_id;
struct map_session_data *sd;
@@ -11125,7 +12806,7 @@ BUILDIN(catchpet)
/*==========================================
* [orn]
*------------------------------------------*/
-BUILDIN(homunculus_evolution)
+static BUILDIN(homunculus_evolution)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
@@ -11145,7 +12826,7 @@ BUILDIN(homunculus_evolution)
* Checks for vaporized morph state
* and deletes ITEMID_STRANGE_EMBRYO.
*------------------------------------------*/
-BUILDIN(homunculus_mutate)
+static BUILDIN(homunculus_mutate)
{
bool success = false;
struct map_session_data *sd = script->rid2sd(st);
@@ -11159,7 +12840,7 @@ BUILDIN(homunculus_mutate)
if (script_hasdata(st,2))
homun_id = script_getnum(st,2);
else
- homun_id = 6048 + (rnd() % 4);
+ homun_id = HOMID_EIRA + (rnd() % 4);
m_class = homun->class2type(sd->hd->homunculus.class_);
m_id = homun->class2type(homun_id);
@@ -11186,7 +12867,7 @@ BUILDIN(homunculus_mutate)
* Puts homunculus into morph state
* and gives ITEMID_STRANGE_EMBRYO.
*------------------------------------------*/
-BUILDIN(homunculus_morphembryo)
+static BUILDIN(homunculus_morphembryo)
{
bool success = false;
struct map_session_data *sd = script->rid2sd(st);
@@ -11208,7 +12889,7 @@ BUILDIN(homunculus_morphembryo)
clif->additem(sd, 0, 0, i);
clif->emotion(&sd->hd->bl, E_SWT);
} else {
- homun->vaporize(sd, HOM_ST_MORPH);
+ homun->vaporize(sd, HOM_ST_MORPH, true);
success = true;
}
} else {
@@ -11229,7 +12910,7 @@ BUILDIN(homunculus_morphembryo)
* 1 = Homunculus is vaporized (rest)
* 2 = Homunculus is in morph state
*------------------------------------------*/
-BUILDIN(homunculus_checkcall)
+static BUILDIN(homunculus_checkcall)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL || sd->hd == NULL)
@@ -11241,7 +12922,7 @@ BUILDIN(homunculus_checkcall)
}
// [Zephyrus]
-BUILDIN(homunculus_shuffle)
+static BUILDIN(homunculus_shuffle)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
@@ -11254,24 +12935,24 @@ BUILDIN(homunculus_shuffle)
}
//These two functions bring the eA MAPID_* class functionality to scripts.
-BUILDIN(eaclass)
+static BUILDIN(eaclass)
{
- int class_;
+ int class;
if (script_hasdata(st,2)) {
- class_ = script_getnum(st,2);
+ class = script_getnum(st,2);
} else {
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
return true;
- class_ = sd->status.class_;
+ class = sd->status.class;
}
- script_pushint(st,pc->jobid2mapid(class_));
+ script_pushint(st,pc->jobid2mapid(class));
return true;
}
-BUILDIN(roclass)
+static BUILDIN(roclass)
{
- int class_ =script_getnum(st,2);
+ int job = script_getnum(st,2);
int sex;
if (script_hasdata(st,3)) {
sex = script_getnum(st,3);
@@ -11282,14 +12963,14 @@ BUILDIN(roclass)
else
sex = 1; //Just use male when not found.
}
- script_pushint(st,pc->mapid2jobid(class_, sex));
+ script_pushint(st,pc->mapid2jobid(job, sex));
return true;
}
/*==========================================
* Tells client to open a hatching window, used for pet incubator
*------------------------------------------*/
-BUILDIN(birthpet)
+static BUILDIN(birthpet)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
@@ -11312,7 +12993,7 @@ BUILDIN(birthpet)
* 3 : don't reset skill, blvl=1
* 4 : jlvl=0
*------------------------------------------*/
-BUILDIN(resetlvl)
+static BUILDIN(resetlvl)
{
int type=script_getnum(st,2);
struct map_session_data *sd = script->rid2sd(st);
@@ -11325,7 +13006,7 @@ BUILDIN(resetlvl)
/*==========================================
* Reset a player status point
*------------------------------------------*/
-BUILDIN(resetstatus)
+static BUILDIN(resetstatus)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
@@ -11337,7 +13018,7 @@ BUILDIN(resetstatus)
/*==========================================
* script command resetskill
*------------------------------------------*/
-BUILDIN(resetskill)
+static BUILDIN(resetskill)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
@@ -11349,7 +13030,7 @@ BUILDIN(resetskill)
/*==========================================
* Counts total amount of skill points.
*------------------------------------------*/
-BUILDIN(skillpointcount)
+static BUILDIN(skillpointcount)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
@@ -11361,7 +13042,7 @@ BUILDIN(skillpointcount)
/*==========================================
*
*------------------------------------------*/
-BUILDIN(changebase)
+static BUILDIN(changebase)
{
struct map_session_data *sd = NULL;
int vclass;
@@ -11378,12 +13059,12 @@ BUILDIN(changebase)
if(vclass == JOB_WEDDING)
{
if (!battle_config.wedding_modifydisplay || //Do not show the wedding sprites
- sd->class_&JOBL_BABY //Baby classes screw up when showing wedding sprites. [Skotlex] They don't seem to anymore.
+ sd->job & JOBL_BABY //Baby classes screw up when showing wedding sprites. [Skotlex] They don't seem to anymore.
)
return true;
}
- if(sd->disguise == -1 && vclass != sd->vd.class_)
+ if (sd->disguise == -1 && vclass != sd->vd.class)
pc->changelook(sd,LOOK_BASE,vclass); //Updated client view. Base, Weapon and Cloth Colors.
return true;
@@ -11407,7 +13088,7 @@ static struct map_session_data *prepareChangeSex(struct script_state *st)
/*==========================================
* Unequip all item and request for a changesex to char-serv
*------------------------------------------*/
-BUILDIN(changesex)
+static BUILDIN(changesex)
{
struct map_session_data *sd = prepareChangeSex(st);
if (sd == NULL)
@@ -11419,7 +13100,7 @@ BUILDIN(changesex)
/*==========================================
* Unequip all items and change character sex [4144]
*------------------------------------------*/
-BUILDIN(changecharsex)
+static BUILDIN(changecharsex)
{
struct map_session_data *sd = prepareChangeSex(st);
if (sd == NULL)
@@ -11431,7 +13112,7 @@ BUILDIN(changecharsex)
/*==========================================
* Works like 'announce' but outputs in the common chat window
*------------------------------------------*/
-BUILDIN(globalmes)
+static BUILDIN(globalmes)
{
const char *name=NULL,*mes;
@@ -11459,7 +13140,7 @@ BUILDIN(globalmes)
/// Creates a waiting room (chat room) for this npc.
///
/// waitingroom "<title>",<limit>{,"<event>"{,<trigger>{,<zeny>{,<minlvl>{,<maxlvl>}}}}};
-BUILDIN(waitingroom)
+static BUILDIN(waitingroom)
{
struct npc_data* nd;
const char* title = script_getstr(st, 2);
@@ -11483,7 +13164,8 @@ BUILDIN(waitingroom)
///
/// delwaitingroom "<npc_name>";
/// delwaitingroom;
-BUILDIN(delwaitingroom) {
+static BUILDIN(delwaitingroom)
+{
struct npc_data* nd;
if( script_hasdata(st,2) )
nd = npc->name2id(script_getstr(st, 2));
@@ -11498,7 +13180,8 @@ BUILDIN(delwaitingroom) {
///
/// kickwaitingroomall "<npc_name>";
/// kickwaitingroomall;
-BUILDIN(waitingroomkickall) {
+static BUILDIN(waitingroomkickall)
+{
struct npc_data* nd;
struct chat_data* cd;
@@ -11516,7 +13199,8 @@ BUILDIN(waitingroomkickall) {
///
/// enablewaitingroomevent "<npc_name>";
/// enablewaitingroomevent;
-BUILDIN(enablewaitingroomevent) {
+static BUILDIN(enablewaitingroomevent)
+{
struct npc_data* nd;
struct chat_data* cd;
@@ -11534,7 +13218,8 @@ BUILDIN(enablewaitingroomevent) {
///
/// disablewaitingroomevent "<npc_name>";
/// disablewaitingroomevent;
-BUILDIN(disablewaitingroomevent) {
+static BUILDIN(disablewaitingroomevent)
+{
struct npc_data *nd;
struct chat_data *cd;
@@ -11566,7 +13251,7 @@ BUILDIN(disablewaitingroomevent) {
///
/// getwaitingroomstate(<type>,"<npc_name>") -> <info>
/// getwaitingroomstate(<type>) -> <info>
-BUILDIN(getwaitingroomstate)
+static BUILDIN(getwaitingroomstate)
{
const struct npc_data *nd;
const struct chat_data *cd;
@@ -11588,7 +13273,8 @@ BUILDIN(getwaitingroomstate)
case 0:
for (i = 0; i < cd->users; i++) {
struct map_session_data *sd = cd->usersd[i];
- mapreg->setreg(reference_uid(script->add_str("$@chatmembers"), i), sd->bl.id);
+ nullpo_retr(false, sd);
+ mapreg->setreg(reference_uid(script->add_variable("$@chatmembers"), i), sd->bl.id);
}
script_pushint(st, cd->users);
break;
@@ -11601,8 +13287,8 @@ BUILDIN(getwaitingroomstate)
case 32: script_pushint(st, (cd->users >= cd->limit)); break;
case 33: script_pushint(st, (cd->users >= cd->trigger)); break;
- case 34: script_pushint(st, cd->minLvl); break;
- case 35: script_pushint(st, cd->maxLvl); break;
+ case 34: script_pushint(st, cd->min_level); break;
+ case 35: script_pushint(st, cd->max_level); break;
case 36: script_pushint(st, cd->zeny); break;
default: script_pushint(st, -1); break;
}
@@ -11621,7 +13307,7 @@ BUILDIN(getwaitingroomstate)
///
/// warpwaitingpc "<map name>",<x>,<y>,<number of players>;
/// warpwaitingpc "<map name>",<x>,<y>;
-BUILDIN(warpwaitingpc)
+static BUILDIN(warpwaitingpc)
{
int x, y, i, n;
const char* map_name;
@@ -11643,6 +13329,7 @@ BUILDIN(warpwaitingpc)
for (i = 0; i < n && cd->users > 0; i++) {
struct map_session_data *sd = cd->usersd[0];
+ nullpo_retr(false, sd);
if (strcmp(map_name,"SavePoint") == 0 && map->list[sd->bl.m].flag.noteleport) {
// can't teleport on this map
break;
@@ -11657,7 +13344,7 @@ BUILDIN(warpwaitingpc)
pc->payzeny(sd, cd->zeny, LOG_TYPE_NPC, NULL);
}
- mapreg->setreg(reference_uid(script->add_str("$@warpwaitingpc"), i), sd->bl.id);
+ mapreg->setreg(reference_uid(script->add_variable("$@warpwaitingpc"), i), sd->bl.id);
if( strcmp(map_name,"Random") == 0 )
pc->randomwarp(sd,CLR_TELEPORT);
@@ -11666,7 +13353,7 @@ BUILDIN(warpwaitingpc)
else
pc->setpos(sd, script->mapindexname2id(st,map_name), x, y, CLR_OUTSIGHT);
}
- mapreg->setreg(script->add_str("$@warpwaitingpcnum"), i);
+ mapreg->setreg(script->add_variable("$@warpwaitingpcnum"), i);
return true;
}
@@ -11677,7 +13364,8 @@ BUILDIN(warpwaitingpc)
/// Detaches a character from a script.
///
/// @param st Script state to detach the character from.
-void script_detach_rid(struct script_state* st) {
+static void script_detach_rid(struct script_state *st)
+{
if(st->rid) {
script->detach_state(st, false);
st->rid = 0;
@@ -11687,7 +13375,8 @@ void script_detach_rid(struct script_state* st) {
/*==========================================
* Attach sd char id to script and detach current one if any
*------------------------------------------*/
-BUILDIN(attachrid) {
+static BUILDIN(attachrid)
+{
int rid = script_getnum(st,2);
if (map->id2sd(rid) != NULL) {
@@ -11703,7 +13392,7 @@ BUILDIN(attachrid) {
/*==========================================
* Detach script to rid
*------------------------------------------*/
-BUILDIN(detachrid)
+static BUILDIN(detachrid)
{
script->detach_rid(st);
return true;
@@ -11711,7 +13400,7 @@ BUILDIN(detachrid)
/*==========================================
* Chk if account connected, (and charid from account if specified)
*------------------------------------------*/
-BUILDIN(isloggedin)
+static BUILDIN(isloggedin)
{
struct map_session_data *sd = map->id2sd(script_getnum(st,2));
if (script_hasdata(st,3) && sd != NULL
@@ -11724,7 +13413,8 @@ BUILDIN(isloggedin)
/*==========================================
*
*------------------------------------------*/
-BUILDIN(setmapflagnosave) {
+static BUILDIN(setmapflagnosave)
+{
int16 m,x,y;
unsigned short map_index;
const char *str,*str2;
@@ -11746,7 +13436,81 @@ BUILDIN(setmapflagnosave) {
return true;
}
-BUILDIN(getmapflag)
+enum mapinfo_info {
+ MAPINFO_NAME,
+ MAPINFO_ID,
+ MAPINFO_SIZE_X,
+ MAPINFO_SIZE_Y,
+ MAPINFO_ZONE,
+ MAPINFO_NPC_COUNT
+};
+
+static BUILDIN(getmapinfo)
+{
+ enum mapinfo_info mode = script_getnum(st, 2);
+ int16 m = -1;
+
+ if (script_hasdata(st, 3)) {
+ if (script_isstringtype(st, 3)) {
+ const char *str = script_getstr(st, 3);
+ m = map->mapindex2mapid(strdb_iget(mapindex->db, str));
+ } else {
+ m = script_getnum(st, 3);
+ }
+ } else {
+ struct block_list *bl = NULL;
+
+ if (st->oid) {
+ bl = map->id2bl(st->oid);
+ } else if (st->rid) {
+ bl = map->id2bl(st->rid);
+ }
+
+ if (bl == NULL) {
+ ShowError("buildin_getmapinfo: map not supplied and NPC/PC not attached!\n");
+ script_pushint(st, -3);
+ return false;
+ }
+
+ m = bl->m;
+ }
+
+ if (m < 0) {
+ // here we don't throw an error, so the command can be used
+ // to detect whether or not a map exists
+ script_pushint(st, -1);
+ return true;
+ }
+
+ switch (mode) {
+ case MAPINFO_NAME:
+ script_pushconststr(st, map->list[m].name);
+ break;
+ case MAPINFO_ID:
+ script_pushint(st, m);
+ break;
+ case MAPINFO_SIZE_X:
+ script_pushint(st, map->list[m].xs);
+ break;
+ case MAPINFO_SIZE_Y:
+ script_pushint(st, map->list[m].ys);
+ break;
+ case MAPINFO_ZONE:
+ script_pushstrcopy(st, map->list[m].zone->name);
+ break;
+ case MAPINFO_NPC_COUNT:
+ script_pushint(st, map->list[m].npc_num);
+ break;
+ default:
+ ShowError("buildin_getmapinfo: unknown option in second argument (%u).\n", mode);
+ script_pushint(st, -2);
+ return false;
+ }
+
+ return true;
+}
+
+static BUILDIN(getmapflag)
{
int16 m,i;
const char *str;
@@ -11808,14 +13572,19 @@ BUILDIN(getmapflag)
case MF_RESET: script_pushint(st,map->list[m].flag.reset); break;
case MF_NOTOMB: script_pushint(st,map->list[m].flag.notomb); break;
case MF_NOCASHSHOP: script_pushint(st,map->list[m].flag.nocashshop); break;
- case MF_NOVIEWID: script_pushint(st,map->list[m].flag.noviewid); break;
+ case MF_NOAUTOLOOT: script_pushint(st, map->list[m].flag.noautoloot); break;
+ case MF_NOVIEWID: script_pushint(st, map->list[m].flag.noviewid); break;
+ case MF_PAIRSHIP_STARTABLE: script_pushint(st, map->list[m].flag.pairship_startable); break;
+ case MF_PAIRSHIP_ENDABLE: script_pushint(st, map->list[m].flag.pairship_endable); break;
+ case MF_NOSTORAGE: script_pushint(st, map->list[m].flag.nostorage); break;
+ case MF_NOGSTORAGE: script_pushint(st, map->list[m].flag.nogstorage); break;
}
}
return true;
}
/* pvp timer handling */
-int script_mapflag_pvp_sub(struct block_list *bl, va_list ap)
+static int script_mapflag_pvp_sub(struct block_list *bl, va_list ap)
{
struct map_session_data *sd = NULL;
@@ -11824,7 +13593,8 @@ int script_mapflag_pvp_sub(struct block_list *bl, va_list ap)
sd = BL_UCAST(BL_PC, bl);
if (sd->pvp_timer == INVALID_TIMER) {
- sd->pvp_timer = timer->add(timer->gettick() + 200, pc->calc_pvprank_timer, sd->bl.id, 0);
+ if (!map->list[sd->bl.m].flag.pvp_nocalcrank)
+ sd->pvp_timer = timer->add(timer->gettick() + 200, pc->calc_pvprank_timer, sd->bl.id, 0);
sd->pvp_rank = 0;
sd->pvp_lastusers = 0;
sd->pvp_point = 5;
@@ -11836,7 +13606,8 @@ int script_mapflag_pvp_sub(struct block_list *bl, va_list ap)
return 0;
}
-BUILDIN(setmapflag) {
+static BUILDIN(setmapflag)
+{
int16 m,i;
const char *str, *val2 = NULL;
int val=0;
@@ -11875,6 +13646,7 @@ BUILDIN(setmapflag) {
case MF_PVP_NOGUILD: map->list[m].flag.pvp_noguild = 1; break;
case MF_GVG: {
struct block_list bl;
+ memset(&bl, 0, sizeof(bl));
map->list[m].flag.gvg = 1;
clif->map_property_mapall(m, MAPPROPERTY_AGITZONE);
bl.type = BL_NUL;
@@ -11932,14 +13704,20 @@ BUILDIN(setmapflag) {
case MF_RESET: map->list[m].flag.reset = 1; break;
case MF_NOTOMB: map->list[m].flag.notomb = 1; break;
case MF_NOCASHSHOP: map->list[m].flag.nocashshop = 1; break;
+ case MF_NOAUTOLOOT: map->list[m].flag.noautoloot = 1; break;
case MF_NOVIEWID: map->list[m].flag.noviewid = (val <= 0) ? EQP_NONE : val; break;
+ case MF_PAIRSHIP_STARTABLE: map->list[m].flag.pairship_startable = 1; break;
+ case MF_PAIRSHIP_ENDABLE: map->list[m].flag.pairship_endable = 1; break;
+ 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;
}
}
return true;
}
-BUILDIN(removemapflag) {
+static BUILDIN(removemapflag)
+{
int16 m,i;
const char *str;
@@ -11957,6 +13735,7 @@ BUILDIN(removemapflag) {
case MF_NOZENYPENALTY: map->list[m].flag.nozenypenalty = 0; break;
case MF_PVP: {
struct block_list bl;
+ memset(&bl, 0, sizeof(bl));
bl.type = BL_NUL;
bl.m = m;
map->list[m].flag.pvp = 0;
@@ -11968,6 +13747,7 @@ BUILDIN(removemapflag) {
case MF_PVP_NOGUILD: map->list[m].flag.pvp_noguild = 0; break;
case MF_GVG: {
struct block_list bl;
+ memset(&bl, 0, sizeof(bl));
bl.type = BL_NUL;
bl.m = m;
map->list[m].flag.gvg = 0;
@@ -12019,14 +13799,17 @@ BUILDIN(removemapflag) {
case MF_RESET: map->list[m].flag.reset = 0; break;
case MF_NOTOMB: map->list[m].flag.notomb = 0; break;
case MF_NOCASHSHOP: map->list[m].flag.nocashshop = 0; break;
+ case MF_NOAUTOLOOT: map->list[m].flag.noautoloot = 0; break;
case MF_NOVIEWID: map->list[m].flag.noviewid = EQP_NONE; break;
+ case MF_NOSTORAGE: map->list[m].flag.nostorage = 0; break;
+ case MF_NOGSTORAGE: map->list[m].flag.nogstorage = 0; break;
}
}
return true;
}
-BUILDIN(pvpon)
+static BUILDIN(pvpon)
{
int16 m;
const char *str;
@@ -12034,6 +13817,7 @@ BUILDIN(pvpon)
struct s_mapiterator* iter;
struct block_list bl;
+ memset(&bl, 0, sizeof(bl));
str = script_getstr(st,2);
m = map->mapname2mapid(str);
if( m < 0 || map->list[m].flag.pvp )
@@ -12059,7 +13843,8 @@ BUILDIN(pvpon)
if( sd->bl.m != m || sd->pvp_timer != INVALID_TIMER )
continue; // not applicable
- sd->pvp_timer = timer->add(timer->gettick()+200,pc->calc_pvprank_timer,sd->bl.id,0);
+ if (!map->list[m].flag.pvp_nocalcrank)
+ sd->pvp_timer = timer->add(timer->gettick()+200,pc->calc_pvprank_timer,sd->bl.id,0);
sd->pvp_rank = 0;
sd->pvp_lastusers = 0;
sd->pvp_point = 5;
@@ -12071,7 +13856,7 @@ BUILDIN(pvpon)
return true;
}
-int buildin_pvpoff_sub(struct block_list *bl, va_list ap)
+static int buildin_pvpoff_sub(struct block_list *bl, va_list ap)
{
struct map_session_data *sd = NULL;
@@ -12087,11 +13872,13 @@ int buildin_pvpoff_sub(struct block_list *bl, va_list ap)
return 0;
}
-BUILDIN(pvpoff) {
+static BUILDIN(pvpoff)
+{
int16 m;
const char *str;
struct block_list bl;
+ memset(&bl, 0, sizeof(bl));
str=script_getstr(st,2);
m = map->mapname2mapid(str);
if(m < 0 || !map->list[m].flag.pvp)
@@ -12111,7 +13898,8 @@ BUILDIN(pvpoff) {
return true;
}
-BUILDIN(gvgon) {
+static BUILDIN(gvgon)
+{
int16 m;
const char *str;
@@ -12120,6 +13908,7 @@ BUILDIN(gvgon) {
if(m >= 0 && !map->list[m].flag.gvg) {
struct block_list bl;
+ memset(&bl, 0, sizeof(bl));
if( !strdb_exists(map->zone_db,MAP_ZONE_GVG_NAME) ) {
ShowError("buildin_gvgon: zone_db missing '%s'\n",MAP_ZONE_GVG_NAME);
return true;
@@ -12135,7 +13924,8 @@ BUILDIN(gvgon) {
return true;
}
-BUILDIN(gvgoff) {
+static BUILDIN(gvgoff)
+{
int16 m;
const char *str;
@@ -12143,6 +13933,7 @@ BUILDIN(gvgoff) {
m = map->mapname2mapid(str);
if(m >= 0 && map->list[m].flag.gvg) {
struct block_list bl;
+ memset(&bl, 0, sizeof(bl));
map->zone_change2(m, map->list[m].prev_zone);
map->list[m].flag.gvg = 0;
clif->map_property_mapall(m, MAPPROPERTY_NOTHING);
@@ -12158,7 +13949,8 @@ BUILDIN(gvgoff) {
* emotion emotion#, <target: 0 - NPC, 1 - PC>, <NPC/PC name>
*------------------------------------------*/
//Optional second parameter added by [Skotlex]
-BUILDIN(emotion) {
+static BUILDIN(emotion)
+{
int type;
int player=0;
@@ -12187,7 +13979,7 @@ BUILDIN(emotion) {
return true;
}
-int buildin_maprespawnguildid_sub_pc(struct map_session_data* sd, va_list ap)
+static int buildin_maprespawnguildid_sub_pc(struct map_session_data *sd, va_list ap)
{
int16 m=va_arg(ap,int);
int g_id=va_arg(ap,int);
@@ -12204,7 +13996,7 @@ int buildin_maprespawnguildid_sub_pc(struct map_session_data* sd, va_list ap)
return 1;
}
-int buildin_maprespawnguildid_sub_mob(struct block_list *bl, va_list ap)
+static int buildin_maprespawnguildid_sub_mob(struct block_list *bl, va_list ap)
{
struct mob_data *md = NULL;
@@ -12218,7 +14010,8 @@ int buildin_maprespawnguildid_sub_mob(struct block_list *bl, va_list ap)
return 0;
}
-BUILDIN(maprespawnguildid) {
+static BUILDIN(maprespawnguildid)
+{
const char *mapname=script_getstr(st,2);
int g_id=script_getnum(st,3);
int flag=script_getnum(st,4);
@@ -12235,28 +14028,32 @@ BUILDIN(maprespawnguildid) {
return true;
}
-BUILDIN(agitstart) {
+static BUILDIN(agitstart)
+{
if(map->agit_flag==1) return true; // Agit already Start.
map->agit_flag=1;
guild->agit_start();
return true;
}
-BUILDIN(agitend) {
+static BUILDIN(agitend)
+{
if(map->agit_flag==0) return true; // Agit already End.
map->agit_flag=0;
guild->agit_end();
return true;
}
-BUILDIN(agitstart2) {
+static BUILDIN(agitstart2)
+{
if(map->agit2_flag==1) return true; // Agit2 already Start.
map->agit2_flag=1;
guild->agit2_start();
return true;
}
-BUILDIN(agitend2) {
+static BUILDIN(agitend2)
+{
if(map->agit2_flag==0) return true; // Agit2 already End.
map->agit2_flag=0;
guild->agit2_end();
@@ -12266,7 +14063,8 @@ BUILDIN(agitend2) {
/*==========================================
* Returns whether woe is on or off.
*------------------------------------------*/
-BUILDIN(agitcheck) {
+static BUILDIN(agitcheck)
+{
script_pushint(st,map->agit_flag);
return true;
}
@@ -12274,7 +14072,8 @@ BUILDIN(agitcheck) {
/*==========================================
* Returns whether woese is on or off.
*------------------------------------------*/
-BUILDIN(agitcheck2) {
+static BUILDIN(agitcheck2)
+{
script_pushint(st,map->agit2_flag);
return true;
}
@@ -12282,7 +14081,7 @@ BUILDIN(agitcheck2) {
/// Sets the guild_id of this npc.
///
/// flagemblem <guild_id>;
-BUILDIN(flagemblem)
+static BUILDIN(flagemblem)
{
struct npc_data *nd;
int g_id = script_getnum(st,2);
@@ -12307,7 +14106,7 @@ BUILDIN(flagemblem)
return true;
}
-BUILDIN(getcastlename)
+static BUILDIN(getcastlename)
{
const char* mapname = mapindex->getmapname(script_getstr(st,2),NULL);
struct guild_castle* gc = guild->mapname2gc(mapname);
@@ -12316,7 +14115,7 @@ BUILDIN(getcastlename)
return true;
}
-BUILDIN(getcastledata)
+static BUILDIN(getcastledata)
{
const char *mapname = mapindex->getmapname(script_getstr(st,2),NULL);
int index = script_getnum(st,3);
@@ -12359,7 +14158,7 @@ BUILDIN(getcastledata)
return true;
}
-BUILDIN(setcastledata)
+static BUILDIN(setcastledata)
{
const char *mapname = mapindex->getmapname(script_getstr(st,2),NULL);
int index = script_getnum(st,3);
@@ -12382,7 +14181,7 @@ BUILDIN(setcastledata)
/* =====================================================================
* ---------------------------------------------------------------------*/
-BUILDIN(requestguildinfo)
+static BUILDIN(requestguildinfo)
{
int guild_id=script_getnum(st,2);
const char *event=NULL;
@@ -12399,7 +14198,7 @@ BUILDIN(requestguildinfo)
/// Returns the number of cards that have been compounded onto the specified equipped item.
/// getequipcardcnt(<equipment slot>);
-BUILDIN(getequipcardcnt)
+static BUILDIN(getequipcardcnt)
{
int i=-1,j,num;
struct map_session_data *sd;
@@ -12436,149 +14235,116 @@ BUILDIN(getequipcardcnt)
/// Removes all cards from the item found in the specified equipment slot of the invoking character,
/// and give them to the character. If any cards were removed in this manner, it will also show a success effect.
-/// successremovecards <slot>;
-BUILDIN(successremovecards)
+/// successremovecards(<slot>);
+static BUILDIN(successremovecards)
{
- int i=-1,c,cardflag=0;
+ int i = -1, c, cardflag = 0;
struct map_session_data *sd = script->rid2sd(st);
- int num = script_getnum(st,2);
+ int num = script_getnum(st, 2);
if (sd == NULL)
return true;
if (num > 0 && num <= ARRAYLENGTH(script->equip))
- i=pc->checkequip(sd,script->equip[num-1]);
+ i = pc->checkequip(sd,script->equip[num - 1]);
- if (i < 0 || !sd->inventory_data[i]) {
+ if (i < 0 || sd->inventory_data[i] == NULL)
return true;
- }
- if(itemdb_isspecial(sd->status.inventory[i].card[0]))
+ if (itemdb_isspecial(sd->status.inventory[i].card[0]))
return true;
- for( c = sd->inventory_data[i]->slot - 1; c >= 0; --c ) {
- if( sd->status.inventory[i].card[c] && itemdb_type(sd->status.inventory[i].card[c]) == IT_CARD ) {// extract this card from the item
+ for (c = sd->inventory_data[i]->slot - 1; c >= 0; --c) {
+ if (sd->status.inventory[i].card[c] > 0 && itemdb_type(sd->status.inventory[i].card[c]) == IT_CARD) {
int flag;
struct item item_tmp;
- memset(&item_tmp,0,sizeof(item_tmp));
+
+ memset(&item_tmp, 0, sizeof(item_tmp));
+
cardflag = 1;
- item_tmp.nameid = sd->status.inventory[i].card[c];
+ item_tmp.nameid = sd->status.inventory[i].card[c];
item_tmp.identify = 1;
+ sd->status.inventory[i].card[c] = 0;
- if((flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))) {
- // get back the cart in inventory
- clif->additem(sd,0,0,flag);
- map->addflooritem(&sd->bl, &item_tmp, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0);
+ if ((flag = pc->additem(sd, &item_tmp, 1, LOG_TYPE_SCRIPT))) {
+ clif->additem(sd, 0, 0, flag);
+ map->addflooritem(&sd->bl, &item_tmp, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0, false);
}
}
}
if (cardflag == 1) {
- //if card was remove replace item with no card
- int flag, j;
- struct item item_tmp;
- memset(&item_tmp,0,sizeof(item_tmp));
-
- item_tmp.nameid = sd->status.inventory[i].nameid;
- item_tmp.identify = 1;
- item_tmp.refine = sd->status.inventory[i].refine;
- item_tmp.attribute = sd->status.inventory[i].attribute;
- item_tmp.expire_time = sd->status.inventory[i].expire_time;
- item_tmp.bound = sd->status.inventory[i].bound;
-
- for (j = sd->inventory_data[i]->slot; j < MAX_SLOTS; j++)
- item_tmp.card[j]=sd->status.inventory[i].card[j];
-
- pc->delitem(sd, i, 1, 0, DELITEM_MATERIALCHANGE, LOG_TYPE_SCRIPT);
- if ((flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))) {
- //chk if can be spawn in inventory otherwise put on floor
- clif->additem(sd,0,0,flag);
- map->addflooritem(&sd->bl, &item_tmp, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0);
- }
-
+ pc->unequipitem(sd, i, PCUNEQUIPITEM_FORCE);
+ clif->delitem(sd, i, 1, DELITEM_MATERIALCHANGE);
+ clif->additem(sd, i, 1, 0);
+ pc->equipitem(sd, i, sd->status.inventory[i].equip);
clif->misceffect(&sd->bl,3);
}
return true;
}
/// Removes all cards from the item found in the specified equipment slot of the invoking character.
-/// failedremovecards <slot>, <type>;
+/// failedremovecards(<slot>, <type>);
/// <type>=0 : will destroy both the item and the cards.
/// <type>=1 : will keep the item, but destroy the cards.
/// <type>=2 : will keep the cards, but destroy the item.
-/// <type>=? : will just display the failure effect.
-BUILDIN(failedremovecards)
+/// <type>=3 : will just display the failure effect.
+static BUILDIN(failedremovecards)
{
- int i=-1,c,cardflag=0;
+ int i = -1, c, cardflag = 0;
+ int num = script_getnum(st, 2);
+ int typefail = script_getnum(st, 3);
struct map_session_data *sd = script->rid2sd(st);
- int num = script_getnum(st,2);
- int typefail = script_getnum(st,3);
if (sd == NULL)
return true;
if (num > 0 && num <= ARRAYLENGTH(script->equip))
- i=pc->checkequip(sd,script->equip[num-1]);
+ i = pc->checkequip(sd, script->equip[num - 1]);
- if (i < 0 || !sd->inventory_data[i])
+ if (i < 0 || sd->inventory_data[i] == NULL)
return true;
- if(itemdb_isspecial(sd->status.inventory[i].card[0]))
+ if (itemdb_isspecial(sd->status.inventory[i].card[0]))
return true;
- for( c = sd->inventory_data[i]->slot - 1; c >= 0; --c ) {
- if( sd->status.inventory[i].card[c] && itemdb_type(sd->status.inventory[i].card[c]) == IT_CARD ) {
+ for (c = sd->inventory_data[i]->slot - 1; c >= 0; --c) {
+ if (sd->status.inventory[i].card[c] > 0 && itemdb_type(sd->status.inventory[i].card[c]) == IT_CARD) {
cardflag = 1;
- if(typefail == 2) {// add cards to inventory, clear
+ if (typefail == 1)
+ sd->status.inventory[i].card[c] = 0;
+
+ if (typefail == 2) { // add cards to inventory, clear
int flag;
struct item item_tmp;
- memset(&item_tmp,0,sizeof(item_tmp));
+ memset(&item_tmp, 0, sizeof(item_tmp));
- item_tmp.nameid = sd->status.inventory[i].card[c];
+ item_tmp.nameid = sd->status.inventory[i].card[c];
item_tmp.identify = 1;
- if((flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))) {
- clif->additem(sd,0,0,flag);
- map->addflooritem(&sd->bl, &item_tmp, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0);
+ if ((flag = pc->additem(sd, &item_tmp, 1, LOG_TYPE_SCRIPT))) {
+ clif->additem(sd, 0, 0, flag);
+ map->addflooritem(&sd->bl, &item_tmp, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0, false);
}
}
}
}
if (cardflag == 1) {
- if (typefail == 0 || typefail == 2) {
- // destroy the item
+ if (typefail == 0 || typefail == 2) { // destroy the item
pc->delitem(sd, i, 1, 0, DELITEM_FAILREFINE, LOG_TYPE_SCRIPT);
} else if (typefail == 1) {
- // destroy the card
- int flag, j;
- struct item item_tmp;
-
- memset(&item_tmp,0,sizeof(item_tmp));
-
- item_tmp.nameid = sd->status.inventory[i].nameid;
- item_tmp.identify = 1;
- item_tmp.refine = sd->status.inventory[i].refine;
- item_tmp.attribute = sd->status.inventory[i].attribute;
- item_tmp.expire_time = sd->status.inventory[i].expire_time;
- item_tmp.bound = sd->status.inventory[i].bound;
-
- for (j = sd->inventory_data[i]->slot; j < MAX_SLOTS; j++)
- item_tmp.card[j]=sd->status.inventory[i].card[j];
-
- pc->delitem(sd, i, 1, 0, DELITEM_FAILREFINE, LOG_TYPE_SCRIPT);
-
- if((flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))) {
- clif->additem(sd,0,0,flag);
- map->addflooritem(&sd->bl, &item_tmp, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0);
- }
+ pc->unequipitem(sd, i, PCUNEQUIPITEM_FORCE);
+ clif->delitem(sd, i, 1, DELITEM_MATERIALCHANGE);
+ clif->additem(sd, i, 1, 0);
+ pc->equipitem(sd, i, sd->status.inventory[i].equip);
}
- clif->misceffect(&sd->bl,2);
}
+ clif->misceffect(&sd->bl, 2);
return true;
}
@@ -12589,7 +14355,8 @@ BUILDIN(failedremovecards)
* improved by [Lance]
* ================================================================*/
// Added by RoVeRT
-BUILDIN(mapwarp) {
+static BUILDIN(mapwarp)
+{
int x,y,m,check_val=0,check_ID=0,i=0;
struct guild *g = NULL;
struct party_data *p = NULL;
@@ -12642,7 +14409,7 @@ BUILDIN(mapwarp) {
}
// Added by RoVeRT
-int buildin_mobcount_sub(struct block_list *bl, va_list ap)
+static int buildin_mobcount_sub(struct block_list *bl, va_list ap)
{
char *event = va_arg(ap,char *);
const struct mob_data *md = NULL;
@@ -12657,7 +14424,8 @@ int buildin_mobcount_sub(struct block_list *bl, va_list ap)
}
// Added by RoVeRT
-BUILDIN(mobcount) {
+static BUILDIN(mobcount)
+{
const char *mapname,*event;
int16 m;
mapname=script_getstr(st,2);
@@ -12690,7 +14458,8 @@ BUILDIN(mobcount) {
return true;
}
-BUILDIN(marriage) {
+static BUILDIN(marriage)
+{
const char *partner=script_getstr(st,2);
struct map_session_data *sd = script->rid2sd(st);
struct map_session_data *p_sd = script->nick2sd(st, partner);
@@ -12702,7 +14471,7 @@ BUILDIN(marriage) {
script_pushint(st,1);
return true;
}
-BUILDIN(wedding_effect)
+static BUILDIN(wedding_effect)
{
struct map_session_data *sd = script->rid2sd(st);
struct block_list *bl;
@@ -12714,7 +14483,7 @@ BUILDIN(wedding_effect)
clif->wedding_effect(bl);
return true;
}
-BUILDIN(divorce)
+static BUILDIN(divorce)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL || pc->divorce(sd) < 0) {
@@ -12725,7 +14494,8 @@ BUILDIN(divorce)
return true;
}
-BUILDIN(ispartneron) {
+static BUILDIN(ispartneron)
+{
struct map_session_data *sd = script->rid2sd(st);
if (sd==NULL || !pc->ismarried(sd)
@@ -12738,7 +14508,7 @@ BUILDIN(ispartneron) {
return true;
}
-BUILDIN(getpartnerid)
+static BUILDIN(getpartnerid)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
@@ -12748,7 +14518,7 @@ BUILDIN(getpartnerid)
return true;
}
-BUILDIN(getchildid)
+static BUILDIN(getchildid)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
@@ -12758,7 +14528,7 @@ BUILDIN(getchildid)
return true;
}
-BUILDIN(getmotherid)
+static BUILDIN(getmotherid)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
@@ -12768,7 +14538,8 @@ BUILDIN(getmotherid)
return true;
}
-BUILDIN(getfatherid) {
+static BUILDIN(getfatherid)
+{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
return true;
@@ -12777,7 +14548,7 @@ BUILDIN(getfatherid) {
return true;
}
-BUILDIN(warppartner)
+static BUILDIN(warppartner)
{
int x,y;
unsigned short map_index;
@@ -12807,7 +14578,7 @@ BUILDIN(warppartner)
/*================================================
* Script for Displaying MOB Information [Valaris]
*------------------------------------------------*/
-BUILDIN(strmobinfo)
+static BUILDIN(strmobinfo)
{
int num=script_getnum(st,2);
@@ -12837,52 +14608,60 @@ BUILDIN(strmobinfo)
return true;
}
-/*==========================================
- * Summon guardians [Valaris]
- * guardian("<map name>",<x>,<y>,"<name to show>",<mob id>{,"<event label>"}{,<guardian index>}) -> <id>
- *------------------------------------------*/
-BUILDIN(guardian) {
- int class_ = 0, x = 0, y = 0, guardian = 0;
- const char *str, *mapname, *evt="";
+/**
+ * Summons a castle guardian mob.
+ *
+ * @code{.herc}
+ * guardian("<map name>", <x>, <y>, "<name to show>", <mob id>{, <guardian index>});
+ * guardian("<map name>", <x>, <y>, "<name to show>", <mob id>{, "<event label>"{, <guardian index>}});
+ * @endcode
+ *
+ * @author Valaris
+ *
+ **/
+static BUILDIN(guardian)
+{
bool has_index = false;
+ int guardian = 0;
+ const char *event = "";
- mapname = script_getstr(st,2);
- x = script_getnum(st,3);
- y = script_getnum(st,4);
- str = script_getstr(st,5);
- class_ = script_getnum(st,6);
-
- if( script_hasdata(st,8) )
- {// "<event label>",<guardian index>
- evt=script_getstr(st,7);
- guardian=script_getnum(st,8);
+ if (script_hasdata(st, 8)) { /// "<event label>", <guardian index>
+ event = script_getstr(st, 7);
+ script->check_event(st, event);
+ guardian = script_getnum(st, 8);
has_index = true;
- } else if( script_hasdata(st,7) ) {
- struct script_data *data = script_getdata(st,7);
- script->get_val(st,data); // Dereference if it's a variable
- if( data_isstring(data) ) {
- // "<event label>"
- evt=script_getstr(st,7);
- } else if( data_isint(data) ) {
- // <guardian index>
- guardian=script_getnum(st,7);
+ } else if (script_hasdata(st, 7)) {
+ struct script_data *data = script_getdata(st, 7);
+
+ script->get_val(st, data); /// Dereference if it's a variable.
+
+ if (data_isstring(data)) { /// "<event label>"
+ event = script_getstr(st, 7);
+ script->check_event(st, event);
+ } else if (data_isint(data)) { /// <guardian index>
+ guardian = script_getnum(st, 7);
has_index = true;
} else {
- ShowError("script:guardian: invalid data type for argument #6 (from 1)\n");
+ ShowError("script:guardian: Invalid data type for argument #6!\n");
script->reportdata(data);
return false;
}
}
- script->check_event(st, evt);
- script_pushint(st, mob->spawn_guardian(mapname,x,y,str,class_,evt,guardian,has_index));
+ const char *mapname = script_getstr(st, 2);
+ const char *name = script_getstr(st, 5);
+ const int x = script_getnum(st, 3);
+ const int y = script_getnum(st, 4);
+ const int mob_id = script_getnum(st, 6);
+ script_pushint(st, mob->spawn_guardian(mapname, x, y, name, mob_id, event, guardian, has_index, st->oid));
return true;
}
/*==========================================
* Invisible Walls [Zephyrus]
*------------------------------------------*/
-BUILDIN(setwall) {
+static BUILDIN(setwall)
+{
const char *mapname, *name;
int x, y, m, size, dir;
bool shootable;
@@ -12901,9 +14680,15 @@ BUILDIN(setwall) {
map->iwall_set(m, x, y, size, dir, shootable, name);
return true;
}
-BUILDIN(delwall) {
+
+static BUILDIN(delwall)
+{
const char *name = script_getstr(st,2);
- map->iwall_remove(name);
+
+ if (!map->iwall_remove(name)) {
+ ShowWarning("buildin_delwall: Non-existent '%s' provided.\n", name);
+ return false;
+ }
return true;
}
@@ -12915,7 +14700,8 @@ BUILDIN(delwall) {
/// 1 - maximum hp
/// 2 - current hp
///
-BUILDIN(guardianinfo) {
+static BUILDIN(guardianinfo)
+{
const char* mapname = mapindex->getmapname(script_getstr(st,2),NULL);
int id = script_getnum(st,3);
int type = script_getnum(st,4);
@@ -12947,7 +14733,8 @@ BUILDIN(guardianinfo) {
/*==========================================
* Get the item name by item_id or null
*------------------------------------------*/
-BUILDIN(getitemname) {
+static BUILDIN(getitemname)
+{
int item_id=0;
struct item_data *i_data;
char *item_name;
@@ -12975,7 +14762,7 @@ BUILDIN(getitemname) {
/*==========================================
* Returns number of slots an item has. [Skotlex]
*------------------------------------------*/
-BUILDIN(getitemslots)
+static BUILDIN(getitemslots)
{
int item_id;
struct item_data *i_data;
@@ -12991,88 +14778,529 @@ BUILDIN(getitemslots)
return true;
}
-// TODO: add matk here if needed/once we get rid of RENEWAL
+/**
+ * Returns various information about an item.
+ *
+ * @code{.herc}
+ * getiteminfo(<item ID>, <type>);
+ * getiteminfo("<item name>", <type>);
+ * @endcode
+ *
+ **/
+static BUILDIN(getiteminfo)
+{
+ struct item_data *it;
-/*==========================================
- * Returns some values of an item [Lupus]
- * Price, Weight, etc...
- * getiteminfo(itemID,n), where n
- * 0 value_buy;
- * 1 value_sell;
- * 2 type;
- * 3 maxchance = Max drop chance of this item e.g. 1 = 0.01% , etc..
- * if = 0, then monsters don't drop it at all (rare or a quest item)
- * if = -1, then this item is sold in NPC shops only
- * 4 sex;
- * 5 equip;
- * 6 weight;
- * 7 atk;
- * 8 def;
- * 9 range;
- * 10 slot;
- * 11 look;
- * 12 elv;
- * 13 wlv;
- * 14 view id
- *------------------------------------------*/
-BUILDIN(getiteminfo)
+ 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;
+ }
+
+ int type = script_getnum(st, 3);
+
+ switch (type) {
+ case ITEMINFO_BUYPRICE:
+ script_pushint(st, it->value_buy);
+ break;
+ case ITEMINFO_SELLPRICE:
+ script_pushint(st, it->value_sell);
+ break;
+ case ITEMINFO_TYPE:
+ script_pushint(st, it->type);
+ break;
+ case ITEMINFO_MAXCHANCE:
+ script_pushint(st, it->maxchance);
+ break;
+ case ITEMINFO_SEX:
+ script_pushint(st, it->sex);
+ break;
+ case ITEMINFO_LOC:
+ script_pushint(st, it->equip);
+ break;
+ case ITEMINFO_WEIGHT:
+ script_pushint(st, it->weight);
+ break;
+ case ITEMINFO_ATK:
+ script_pushint(st, it->atk);
+ break;
+ case ITEMINFO_DEF:
+ script_pushint(st, it->def);
+ break;
+ case ITEMINFO_RANGE:
+ script_pushint(st, it->range);
+ break;
+ case ITEMINFO_SLOTS:
+ script_pushint(st, it->slot);
+ break;
+ case ITEMINFO_SUBTYPE:
+ script_pushint(st, it->subtype);
+ break;
+ case ITEMINFO_ELV:
+ script_pushint(st, it->elv);
+ break;
+ case ITEMINFO_WLV:
+ script_pushint(st, it->wlv);
+ break;
+ case ITEMINFO_VIEWID:
+ script_pushint(st, it->view_id);
+ break;
+ case ITEMINFO_MATK:
+ script_pushint(st, it->matk);
+ break;
+ case ITEMINFO_VIEWSPRITE:
+ script_pushint(st, it->view_sprite);
+ break;
+ case ITEMINFO_TRADE:
+ script_pushint(st, it->flag.trade_restriction);
+ break;
+ case ITEMINFO_ELV_MAX:
+ script_pushint(st, it->elvmax);
+ break;
+ case ITEMINFO_DROPEFFECT_MODE:
+ script_pushint(st, it->dropeffectmode);
+ break;
+ case ITEMINFO_DELAY:
+ script_pushint(st, it->delay);
+ break;
+ case ITEMINFO_CLASS_BASE_1:
+ script_pushint(st, it->class_base[0]);
+ break;
+ case ITEMINFO_CLASS_BASE_2:
+ script_pushint(st, it->class_base[1]);
+ break;
+ case ITEMINFO_CLASS_BASE_3:
+ script_pushint(st, it->class_base[2]);
+ break;
+ case ITEMINFO_CLASS_UPPER:
+ script_pushint(st, it->class_upper);
+ break;
+ case ITEMINFO_FLAG_NO_REFINE:
+ script_pushint(st, it->flag.no_refine);
+ break;
+ case ITEMINFO_FLAG_DELAY_CONSUME:
+ script_pushint(st, it->flag.delay_consume);
+ break;
+ case ITEMINFO_FLAG_AUTOEQUIP:
+ script_pushint(st, it->flag.autoequip);
+ break;
+ case ITEMINFO_FLAG_AUTO_FAVORITE:
+ script_pushint(st, it->flag.auto_favorite);
+ break;
+ case ITEMINFO_FLAG_BUYINGSTORE:
+ script_pushint(st, it->flag.buyingstore);
+ break;
+ case ITEMINFO_FLAG_BINDONEQUIP:
+ script_pushint(st, it->flag.bindonequip);
+ break;
+ case ITEMINFO_FLAG_KEEPAFTERUSE:
+ script_pushint(st, it->flag.keepafteruse);
+ break;
+ case ITEMINFO_FLAG_FORCE_SERIAL:
+ script_pushint(st, it->flag.force_serial);
+ break;
+ case ITEMINFO_FLAG_NO_OPTIONS:
+ script_pushint(st, it->flag.no_options);
+ break;
+ case ITEMINFO_FLAG_DROP_ANNOUNCE:
+ script_pushint(st, it->flag.drop_announce);
+ break;
+ case ITEMINFO_FLAG_SHOWDROPEFFECT:
+ script_pushint(st, it->flag.showdropeffect);
+ break;
+ 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);
+ break;
+ }
+ case ITEMINFO_ITEM_USAGE_FLAG:
+ script_pushint(st, it->item_usage.flag);
+ break;
+ case ITEMINFO_ITEM_USAGE_OVERRIDE:
+ script_pushint(st, it->item_usage.override);
+ break;
+ 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 info type %d.\n", type);
+ script_pushint(st, -1);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Returns the value of the current equipment being parsed using static variables -
+ * current_equip_item_index and current_equip_option_index.
+ * !!Designed to be used with item_options.conf only!!
+ * *getequippedoptioninfo(<info_type>);
+ *
+ * @param (int) Types -
+ * IT_OPT_INDEX ID of the item option.
+ * IT_OPT_VALUE Amount of the bonus to be added.
+ * @return value of the type or -1.
+ */
+static BUILDIN(getequippedoptioninfo)
{
- int item_id,n;
- struct item_data *i_data;
+ int val = 0, type = script_getnum(st, 2);
+ struct map_session_data *sd = NULL;
+
+ if ((sd = script->rid2sd(st)) == NULL || status->current_equip_item_index == -1 || status->current_equip_option_index == -1
+ || !sd->status.inventory[status->current_equip_item_index].option[status->current_equip_option_index].index) {
+ script_pushint(st, -1);
+ return false;
+ }
+
+ switch (type) {
+ case IT_OPT_INDEX:
+ val = sd->status.inventory[status->current_equip_item_index].option[status->current_equip_option_index].index;
+ break;
+ case IT_OPT_VALUE:
+ val = sd->status.inventory[status->current_equip_item_index].option[status->current_equip_option_index].value;
+ break;
+ default:
+ ShowError("buildin_getequippedoptioninfo: Invalid option data type %d (Max %d).\n", type, IT_OPT_MAX-1);
+ script_pushint(st, -1);
+ return false;
+ }
+
+ script_pushint(st, val);
+
+ return true;
+}
- item_id = script_getnum(st,2);
- n = script_getnum(st,3);
- i_data = itemdb->exists(item_id);
+/**
+ * Gets the option information of an equipment.
+ * *getequipoption(<equip_index>,<slot>,<type>);
+ *
+ * @param equip_index as the Index of the Equipment.
+ * @param slot as the slot# of the Item Option (1 to MAX_ITEM_OPTIONS)
+ * @param type IT_OPT_INDEX or IT_OPT_VALUE.
+ * @return (int) value or -1 on failure.
+ */
+static BUILDIN(getequipoption)
+{
+ int val = 0, equip_index = script_getnum(st, 2);
+ int slot = script_getnum(st, 3);
+ int opt_type = script_getnum(st, 4);
+ int i = -1;
+ struct map_session_data *sd = script->rid2sd(st);
- if (i_data && n>=0 && n<=14) {
- int *item_arr = (int*)&i_data->value_buy;
- script_pushint(st,item_arr[n]);
+ if (sd == NULL) {
+ script_pushint(st, -1);
+ ShowError("buildin_getequipoption: Player not attached!\n");
+ return false;
+ }
+
+ if (slot <= 0 || slot > MAX_ITEM_OPTIONS) {
+ script_pushint(st, -1);
+ ShowError("buildin_getequipoption: Invalid option slot %d (Min: 1, Max: %d) provided.\n", slot, MAX_ITEM_OPTIONS);
+ return false;
+ }
+
+ if (equip_index > 0 && equip_index <= ARRAYLENGTH(script->equip)) {
+ if ((i = pc->checkequip(sd, script->equip[equip_index - 1])) == -1) {
+ ShowError("buildin_getequipoption: No equipment is equipped in the given index %d.\n", equip_index);
+ script_pushint(st, -1);
+ return false;
+ }
} else {
- script_pushint(st,-1);
+ ShowError("buildin_getequipoption: Invalid equipment index %d provided.\n", equip_index);
+ script_pushint(st, 0);
+ return false;
}
+
+ if (sd->status.inventory[i].nameid != 0) {
+ switch (opt_type) {
+ case IT_OPT_INDEX:
+ val = sd->status.inventory[i].option[slot-1].index;
+ break;
+ case IT_OPT_VALUE:
+ val = sd->status.inventory[i].option[slot-1].value;
+ break;
+ default:
+ ShowError("buildin_getequipoption: Invalid option data type %d provided.\n", opt_type);
+ script_pushint(st, -1);
+ break;
+ }
+ }
+
+ script_pushint(st, val);
+
return true;
}
+/**
+ * Set an equipment's option value.
+ * *setequipoption(<equip_index>,<slot>,<opt_index>,<value>);
+ *
+ * @param equip_index as the inventory index of the equipment.
+ * @param slot as the slot of the item option (1 to MAX_ITEM_OPTIONS)
+ * @param opt_index as the index of the option available as "Id" in db/item_options.conf.
+ * @param value as the value of the option type.
+ * For IT_OPT_INDEX see "Name" in item_options.conf
+ * For IT_OPT_VALUE, the value of the script bonus.
+ * @return 0 on failure, 1 on success.
+ */
+static BUILDIN(setequipoption)
+{
+ int equip_index = script_getnum(st, 2);
+ int slot = script_getnum(st, 3);
+ int opt_index = script_getnum(st, 4);
+ int value = script_getnum(st, 5);
+ int i = -1;
+
+ struct map_session_data *sd = script->rid2sd(st);
+ struct itemdb_option *ito = NULL;
+
+ if (sd == NULL) {
+ script_pushint(st, 0);
+ ShowError("buildin_setequipoption: Player not attached!\n");
+ return false;
+ }
+
+ if (slot <= 0 || slot > MAX_ITEM_OPTIONS) {
+ script_pushint(st, 0);
+ ShowError("buildin_setequipoption: Invalid option index %d (Min: 1, Max: %d) provided.\n", slot, MAX_ITEM_OPTIONS);
+ return false;
+ }
+
+ if (equip_index > 0 && equip_index <= ARRAYLENGTH(script->equip)) {
+ if ((i = pc->checkequip(sd, script->equip[equip_index - 1])) == -1) {
+ ShowError("buildin_setequipoption: No equipment is equipped in the given index %d.\n", equip_index);
+ script_pushint(st, 0);
+ return false;
+ }
+ } else {
+ ShowError("buildin_setequipoption: Invalid equipment index %d provided.\n", equip_index);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ if (sd->status.inventory[i].nameid != 0) {
+ if (opt_index == 0) {
+ // Remove the option
+ sd->status.inventory[i].option[slot-1].index = 0;
+ sd->status.inventory[i].option[slot-1].value = 0;
+ } else {
+ if ((ito = itemdb->option_exists(opt_index)) == NULL) {
+ script_pushint(st, 0);
+ ShowError("buildin_setequipotion: Option index %d does not exist!\n", opt_index);
+ return false;
+ } else if (value < -INT16_MAX || value > INT16_MAX) {
+ script_pushint(st, 0);
+ ShowError("buildin_setequipotion: Option value %d exceeds maximum limit (%d to %d) for type!\n", value, -INT16_MAX, INT16_MAX);
+ return false;
+ }
+ /* Add Option Index */
+ sd->status.inventory[i].option[slot-1].index = ito->index;
+ /* Add Option Value */
+ sd->status.inventory[i].option[slot-1].value = value;
+ }
+
+ /* Unequip and simulate deletion of the item. */
+ pc->unequipitem(sd, i, PCUNEQUIPITEM_FORCE); // status calc will happen in pc->equipitem() below
+ clif->refine(sd->fd, 0, i, sd->status.inventory[i].refine); // notify client of a refine.
+ clif->delitem(sd, i, 1, DELITEM_MATERIALCHANGE); // notify client to simulate item deletion.
+ /* Log deletion of the item. */
+ logs->pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->status.inventory[i],sd->inventory_data[i]);
+ /* Equip and simulate addition of the item. */
+ clif->additem(sd, i, 1, 0); // notify client to simulate item addition.
+ /* Log addition of the item. */
+ logs->pick_pc(sd, LOG_TYPE_SCRIPT, 1, &sd->status.inventory[i], sd->inventory_data[i]);
+ pc->equipitem(sd, i, sd->status.inventory[i].equip); // force equip the item at the original position.
+ clif->misceffect(&sd->bl, 2); // show effect
+ }
+
+ script_pushint(st, 1);
+
+ return true;
+
+}
+
/*==========================================
* Set some values of an item [Lupus]
* Price, Weight, etc...
- * setiteminfo(itemID,n,Value), where n
- * 0 value_buy;
- * 1 value_sell;
- * 2 type;
- * 3 maxchance = Max drop chance of this item e.g. 1 = 0.01% , etc..
- * if = 0, then monsters don't drop it at all (rare or a quest item)
- * if = -1, then this item is sold in NPC shops only
- * 4 sex;
- * 5 equip;
- * 6 weight;
- * 7 atk;
- * 8 def;
- * 9 range;
- * 10 slot;
- * 11 look;
- * 12 elv;
- * 13 wlv;
- * 14 view id
- * Returns Value or -1 if the wrong field's been set
*------------------------------------------*/
-BUILDIN(setiteminfo)
+static BUILDIN(setiteminfo)
{
- int item_id,n,value;
- struct item_data *i_data;
+ // TODO: Validate data in a similar way as during database load
+ int item_id = script_getnum(st, 2);
+ int n = script_getnum(st, 3);
+ int value = script_getnum(st,4);
+ struct item_data *it = itemdb->exists(item_id);
- item_id = script_getnum(st,2);
- n = script_getnum(st,3);
- value = script_getnum(st,4);
- i_data = itemdb->exists(item_id);
+ if (it == NULL) {
+ script_pushint(st, -1);
+ return true;
+ }
- if (i_data && n>=0 && n<=14) {
- int *item_arr = (int*)&i_data->value_buy;
- item_arr[n] = value;
- script_pushint(st,value);
- } else {
+ switch (n) {
+ case ITEMINFO_BUYPRICE:
+ it->value_buy = value;
+ break;
+ case ITEMINFO_SELLPRICE:
+ it->value_sell = value;
+ break;
+ case ITEMINFO_TYPE:
+ it->type = value;
+ break;
+ case ITEMINFO_MAXCHANCE:
+ it->maxchance = value;
+ break;
+ case ITEMINFO_SEX:
+ it->sex = value;
+ break;
+ case ITEMINFO_LOC:
+ it->equip = value;
+ break;
+ case ITEMINFO_WEIGHT:
+ it->weight = value;
+ break;
+ case ITEMINFO_ATK:
+ it->atk = value;
+ break;
+ case ITEMINFO_DEF:
+ it->def = value;
+ break;
+ case ITEMINFO_RANGE:
+ it->range = value;
+ break;
+ case ITEMINFO_SLOTS:
+ it->slot = value;
+ break;
+ case ITEMINFO_SUBTYPE:
+ it->subtype = value;
+ break;
+ case ITEMINFO_ELV:
+ it->elv = value;
+ break;
+ case ITEMINFO_WLV:
+ it->wlv = value;
+ break;
+ case ITEMINFO_VIEWID:
+ it->view_id = value;
+ break;
+ case ITEMINFO_MATK:
+ it->matk = value;
+ break;
+ case ITEMINFO_VIEWSPRITE:
+ it->view_sprite = value;
+ break;
+ case ITEMINFO_TRADE:
+ it->flag.trade_restriction = value;
+ break;
+ case ITEMINFO_ELV_MAX:
+ it->elvmax = cap_value(value, 0, MAX_LEVEL);
+ break;
+ case ITEMINFO_DROPEFFECT_MODE:
+ it->dropeffectmode = value;
+ break;
+ case ITEMINFO_DELAY:
+ it->delay = value;
+ break;
+ case ITEMINFO_CLASS_BASE_1:
+ it->class_base[0] = value;
+ break;
+ case ITEMINFO_CLASS_BASE_2:
+ it->class_base[1] = value;
+ break;
+ case ITEMINFO_CLASS_BASE_3:
+ it->class_base[2] = value;
+ break;
+ case ITEMINFO_CLASS_UPPER:
+ it->class_upper = value;
+ break;
+ case ITEMINFO_FLAG_NO_REFINE:
+ it->flag.no_refine = cap_value(value, 0, MAX_REFINE);
+ break;
+ case ITEMINFO_FLAG_DELAY_CONSUME:
+ it->flag.delay_consume = value;
+ break;
+ case ITEMINFO_FLAG_AUTOEQUIP:
+ it->flag.autoequip = cap_value(value, 0, 1);
+ break;
+ case ITEMINFO_FLAG_AUTO_FAVORITE:
+ it->flag.auto_favorite = cap_value(value, 0, 1);
+ break;
+ case ITEMINFO_FLAG_BUYINGSTORE:
+ it->flag.buyingstore = cap_value(value, 0, 1);
+ break;
+ case ITEMINFO_FLAG_BINDONEQUIP:
+ it->flag.bindonequip = cap_value(value, 0, 1);
+ break;
+ case ITEMINFO_FLAG_KEEPAFTERUSE:
+ it->flag.keepafteruse = cap_value(value, 0, 1);
+ break;
+ case ITEMINFO_FLAG_FORCE_SERIAL:
+ it->flag.force_serial = cap_value(value, 0, 1);
+ break;
+ case ITEMINFO_FLAG_NO_OPTIONS:
+ it->flag.no_options = cap_value(value, 0, 1);
+ break;
+ case ITEMINFO_FLAG_DROP_ANNOUNCE:
+ it->flag.drop_announce = cap_value(value, 0, 1);
+ break;
+ case ITEMINFO_FLAG_SHOWDROPEFFECT:
+ it->flag.showdropeffect = cap_value(value, 0, 1);
+ break;
+ case ITEMINFO_STACK_AMOUNT:
+ it->stack.amount = cap_value(value, 0, USHRT_MAX);
+ break;
+ case ITEMINFO_STACK_FLAG:
+ it->stack.inventory = ((value & 1) != 0);
+ it->stack.cart = ((value & 2) != 0);
+ it->stack.storage = ((value & 4) != 0);
+ it->stack.guildstorage = ((value & 8) != 0);
+ break;
+ case ITEMINFO_ITEM_USAGE_FLAG:
+ it->item_usage.flag = cap_value(value, 0, 1);
+ break;
+ case ITEMINFO_ITEM_USAGE_OVERRIDE:
+ it->item_usage.override = value;
+ break;
+ case ITEMINFO_GM_LV_TRADE_OVERRIDE:
+ it->gm_lv_trade_override = value;
+ break;
+ default:
+ ShowError("buildin_setiteminfo: invalid type %d.\n", n);
script_pushint(st,-1);
+ return false;
}
+ script_pushint(st,value);
return true;
}
@@ -13088,7 +15316,7 @@ BUILDIN(setiteminfo)
* Useful for such quests as "Sign this refined item with players name" etc
* Hat[0] +4 -> Player's Hat[0] +4
*------------------------------------------*/
-BUILDIN(getequipcardid)
+static BUILDIN(getequipcardid)
{
int i=-1,num,slot;
struct map_session_data *sd;
@@ -13113,7 +15341,7 @@ BUILDIN(getequipcardid)
/*==========================================
* petskillbonus [Valaris] //Rewritten by [Skotlex]
*------------------------------------------*/
-BUILDIN(petskillbonus)
+static BUILDIN(petskillbonus)
{
struct pet_data *pd;
@@ -13150,7 +15378,7 @@ BUILDIN(petskillbonus)
/*==========================================
* pet looting [Valaris] //Rewritten by [Skotlex]
*------------------------------------------*/
-BUILDIN(petloot)
+static BUILDIN(petloot)
{
int max;
struct pet_data *pd;
@@ -13187,96 +15415,119 @@ BUILDIN(petloot)
* Set arrays with info of all sd inventory :
* @inventorylist_id, @inventorylist_amount, @inventorylist_equip,
* @inventorylist_refine, @inventorylist_identify, @inventorylist_attribute,
- * @inventorylist_card(0..3), @inventorylist_expire
+ * @inventorylist_card(0..3),
+ * @inventorylist_opt_id(0..MAX_ITEM_OPTIONS),
+ * @inventorylist_opt_val(0..MAX_ITEM_OPTIONS),
+ * @inventorylist_opt_param(0..MAX_ITEM_OPTIONS),
+ * @inventorylist_expire, @inventorylist_bound, @inventorylist_favorite,
+ * @inventorylist_idx
* @inventorylist_count = scalar
*------------------------------------------*/
-BUILDIN(getinventorylist)
+static BUILDIN(getinventorylist)
{
struct map_session_data *sd = script->rid2sd(st);
- char card_var[NAME_LENGTH];
+ char script_var[SCRIPT_VARNAME_LENGTH];
+ int j = 0, k = 0;
- int i,j=0,k;
- if(!sd) return true;
+ if (sd == NULL)
+ return true;
- for(i=0;i<MAX_INVENTORY;i++) {
- if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount > 0) {
- pc->setreg(sd,reference_uid(script->add_str("@inventorylist_id"), j),sd->status.inventory[i].nameid);
- pc->setreg(sd,reference_uid(script->add_str("@inventorylist_amount"), j),sd->status.inventory[i].amount);
- if(sd->status.inventory[i].equip) {
- pc->setreg(sd,reference_uid(script->add_str("@inventorylist_equip"), j),pc->equippoint(sd,i));
+ for (int i = 0; i < sd->status.inventorySize; i++) {
+ if (sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount > 0) {
+ pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_id"), j), sd->status.inventory[i].nameid);
+ pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_amount"), j), sd->status.inventory[i].amount);
+ if (sd->status.inventory[i].equip != 0) {
+ pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_equip"), j), pc->equippoint(sd, i));
} else {
- pc->setreg(sd,reference_uid(script->add_str("@inventorylist_equip"), j),0);
+ pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_equip"), j), 0);
}
- pc->setreg(sd,reference_uid(script->add_str("@inventorylist_refine"), j),sd->status.inventory[i].refine);
- pc->setreg(sd,reference_uid(script->add_str("@inventorylist_identify"), j),sd->status.inventory[i].identify);
- pc->setreg(sd,reference_uid(script->add_str("@inventorylist_attribute"), j),sd->status.inventory[i].attribute);
+ pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_refine"), j), sd->status.inventory[i].refine);
+ pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_identify"), j), sd->status.inventory[i].identify);
+ pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_attribute"), j), sd->status.inventory[i].attribute);
for (k = 0; k < MAX_SLOTS; k++) {
- sprintf(card_var, "@inventorylist_card%d",k+1);
- pc->setreg(sd,reference_uid(script->add_str(card_var), j),sd->status.inventory[i].card[k]);
+ sprintf(script_var, "@inventorylist_card%d", k + 1);
+ pc->setreg(sd, reference_uid(script->add_variable(script_var), j), sd->status.inventory[i].card[k]);
}
- pc->setreg(sd,reference_uid(script->add_str("@inventorylist_expire"), j),sd->status.inventory[i].expire_time);
- pc->setreg(sd,reference_uid(script->add_str("@inventorylist_bound"), j),sd->status.inventory[i].bound);
+ for (k = 0; k < MAX_ITEM_OPTIONS; k++) {
+ sprintf(script_var, "@inventorylist_opt_id%d", k + 1);
+ pc->setreg(sd, reference_uid(script->add_variable(script_var), j), sd->status.inventory[i].option[k].index);
+ sprintf(script_var, "@inventorylist_opt_val%d", k + 1);
+ pc->setreg(sd, reference_uid(script->add_variable(script_var), j), sd->status.inventory[i].option[k].value);
+ sprintf(script_var, "@inventorylist_opt_param%d", k + 1);
+ pc->setreg(sd, reference_uid(script->add_variable(script_var), j), sd->status.inventory[i].option[k].param);
+ }
+ pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_expire"), j), sd->status.inventory[i].expire_time);
+ pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_bound"), j), sd->status.inventory[i].bound);
+ pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_favorite"), j), sd->status.inventory[i].favorite);
+ pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_idx"), j), i);
j++;
}
}
- pc->setreg(sd,script->add_str("@inventorylist_count"),j);
+ pc->setreg(sd, script->add_variable("@inventorylist_count"), j);
return true;
}
-BUILDIN(getcartinventorylist)
+static BUILDIN(getcartinventorylist)
{
struct map_session_data *sd = script->rid2sd(st);
- char card_var[26];
+ char card_var[SCRIPT_VARNAME_LENGTH];
int i,j=0,k;
if(!sd) return true;
for(i=0;i<MAX_CART;i++) {
if(sd->status.cart[i].nameid > 0 && sd->status.cart[i].amount > 0) {
- pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_id"), j),sd->status.cart[i].nameid);
- pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_amount"), j),sd->status.cart[i].amount);
- pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_equip"), j),sd->status.cart[i].equip);
- pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_refine"), j),sd->status.cart[i].refine);
- pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_identify"), j),sd->status.cart[i].identify);
- pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_attribute"), j),sd->status.cart[i].attribute);
+ pc->setreg(sd,reference_uid(script->add_variable("@cartinventorylist_id"), j),sd->status.cart[i].nameid);
+ pc->setreg(sd,reference_uid(script->add_variable("@cartinventorylist_amount"), j),sd->status.cart[i].amount);
+ pc->setreg(sd,reference_uid(script->add_variable("@cartinventorylist_equip"), j),sd->status.cart[i].equip);
+ pc->setreg(sd,reference_uid(script->add_variable("@cartinventorylist_refine"), j),sd->status.cart[i].refine);
+ pc->setreg(sd,reference_uid(script->add_variable("@cartinventorylist_identify"), j),sd->status.cart[i].identify);
+ pc->setreg(sd,reference_uid(script->add_variable("@cartinventorylist_attribute"), j),sd->status.cart[i].attribute);
for (k = 0; k < MAX_SLOTS; k++) {
sprintf(card_var, "@cartinventorylist_card%d",k+1);
- pc->setreg(sd,reference_uid(script->add_str(card_var), j),sd->status.cart[i].card[k]);
+ pc->setreg(sd,reference_uid(script->add_variable(card_var), j),sd->status.cart[i].card[k]);
+ }
+ for (k = 0; k < MAX_ITEM_OPTIONS; k++) {
+ sprintf(card_var, "@cartinventorylist_opt_id%d", k + 1);
+ pc->setreg(sd, reference_uid(script->add_variable(card_var), j), sd->status.cart[i].option[k].index);
+ sprintf(card_var, "@cartinventorylist_opt_val%d", k + 1);
+ pc->setreg(sd, reference_uid(script->add_variable(card_var), j), sd->status.cart[i].option[k].value);
+ sprintf(card_var, "@cartinventorylist_opt_param%d", k + 1);
+ pc->setreg(sd, reference_uid(script->add_variable(card_var), j), sd->status.cart[i].option[k].param);
}
- pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_expire"), j),sd->status.cart[i].expire_time);
- pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_bound"), j),sd->status.cart[i].bound);
+ pc->setreg(sd,reference_uid(script->add_variable("@cartinventorylist_expire"), j),sd->status.cart[i].expire_time);
+ pc->setreg(sd,reference_uid(script->add_variable("@cartinventorylist_bound"), j),sd->status.cart[i].bound);
j++;
}
}
- pc->setreg(sd,script->add_str("@cartinventorylist_count"),j);
+ pc->setreg(sd,script->add_variable("@cartinventorylist_count"),j);
return true;
}
-BUILDIN(getskilllist)
+static BUILDIN(getskilllist)
{
struct map_session_data *sd = script->rid2sd(st);
int i,j=0;
if (sd == NULL)
return true;
- for(i=0;i<MAX_SKILL;i++) {
+ for (i = 0; i < MAX_SKILL_DB; i++) {
if(sd->status.skill[i].id > 0 && sd->status.skill[i].lv > 0) {
- pc->setreg(sd,reference_uid(script->add_str("@skilllist_id"), j),sd->status.skill[i].id);
- pc->setreg(sd,reference_uid(script->add_str("@skilllist_lv"), j),sd->status.skill[i].lv);
- pc->setreg(sd,reference_uid(script->add_str("@skilllist_flag"), j),sd->status.skill[i].flag);
+ pc->setreg(sd,reference_uid(script->add_variable("@skilllist_id"), j),sd->status.skill[i].id);
+ pc->setreg(sd,reference_uid(script->add_variable("@skilllist_lv"), j),sd->status.skill[i].lv);
+ pc->setreg(sd,reference_uid(script->add_variable("@skilllist_flag"), j),sd->status.skill[i].flag);
j++;
}
}
- pc->setreg(sd,script->add_str("@skilllist_count"),j);
+ pc->setreg(sd,script->add_variable("@skilllist_count"),j);
return true;
}
-BUILDIN(clearitem)
+static BUILDIN(clearitem)
{
struct map_session_data *sd = script->rid2sd(st);
- int i;
if (sd == NULL)
return true;
- for (i=0; i<MAX_INVENTORY; i++) {
+ for (int i = 0; i < sd->status.inventorySize; i++) {
if (sd->status.inventory[i].amount) {
pc->delitem(sd, i, sd->status.inventory[i].amount, 0, DELITEM_NORMAL, LOG_TYPE_SCRIPT);
}
@@ -13287,7 +15538,7 @@ BUILDIN(clearitem)
/*==========================================
* Disguise Player (returns Mob/NPC ID if success, 0 on fail)
*------------------------------------------*/
-BUILDIN(disguise)
+static BUILDIN(disguise)
{
int id;
struct map_session_data *sd = script->rid2sd(st);
@@ -13308,7 +15559,7 @@ BUILDIN(disguise)
/*==========================================
* Undisguise Player (returns 1 if success, 0 on fail)
*------------------------------------------*/
-BUILDIN(undisguise)
+static BUILDIN(undisguise)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
@@ -13327,22 +15578,33 @@ BUILDIN(undisguise)
* Transform a bl to another class,
* @type unused
*------------------------------------------*/
-BUILDIN(classchange) {
- int class_,type;
- struct block_list *bl=map->id2bl(st->oid);
+static BUILDIN(classchange)
+{
+ int class, type, target;
+ struct block_list *bl = map->id2bl(st->oid);
+
+ if (bl == NULL)
+ return true;
- if(bl==NULL) return true;
+ class = script_getnum(st, 2);
+ type = script_getnum(st, 3);
+ target = script_hasdata(st, 4) ? script_getnum(st, 4) : 0;
- class_=script_getnum(st,2);
- type=script_getnum(st,3);
- clif->class_change(bl,class_,type);
+ if (target > 0) {
+ struct map_session_data *sd = script->charid2sd(st, target);
+ if (sd != NULL) {
+ clif->class_change(bl, class, type, sd);
+ }
+ } else {
+ clif->class_change(bl, class, type, NULL);
+ }
return true;
}
/*==========================================
* Display an effect
*------------------------------------------*/
-BUILDIN(misceffect)
+static BUILDIN(misceffect)
{
int type;
@@ -13361,7 +15623,7 @@ BUILDIN(misceffect)
/*==========================================
* Play a BGM on a single client [Rikter/Yommy]
*------------------------------------------*/
-BUILDIN(playbgm)
+static BUILDIN(playbgm)
{
struct map_session_data* sd = script->rid2sd(st);
@@ -13374,7 +15636,7 @@ BUILDIN(playbgm)
return true;
}
-int playbgm_sub(struct block_list* bl,va_list ap)
+static int playbgm_sub(struct block_list *bl, va_list ap)
{
const char* name = va_arg(ap,const char*);
@@ -13383,10 +15645,11 @@ int playbgm_sub(struct block_list* bl,va_list ap)
return 0;
}
-int playbgm_foreachpc_sub(struct map_session_data* sd, va_list args)
+static int playbgm_foreachpc_sub(struct map_session_data *sd, va_list args)
{
const char* name = va_arg(args, const char*);
+ nullpo_ret(name);
clif->playBGM(sd, name);
return 0;
}
@@ -13394,7 +15657,8 @@ int playbgm_foreachpc_sub(struct map_session_data* sd, va_list args)
/*==========================================
* Play a BGM on multiple client [Rikter/Yommy]
*------------------------------------------*/
-BUILDIN(playbgmall) {
+static BUILDIN(playbgmall)
+{
const char* name;
name = script_getstr(st,2);
@@ -13436,7 +15700,7 @@ BUILDIN(playbgmall) {
/*==========================================
* Play a .wav sound for sd
*------------------------------------------*/
-BUILDIN(soundeffect)
+static BUILDIN(soundeffect)
{
struct map_session_data *sd = script->rid2sd(st);
const char* name = script_getstr(st,2);
@@ -13448,7 +15712,7 @@ BUILDIN(soundeffect)
return true;
}
-int soundeffect_sub(struct block_list *bl, va_list ap)
+static int soundeffect_sub(struct block_list *bl, va_list ap)
{
struct map_session_data *sd = NULL;
char *name = va_arg(ap, char *);
@@ -13467,7 +15731,8 @@ int soundeffect_sub(struct block_list *bl, va_list ap)
* Play a sound effect (.wav) on multiple clients
* soundeffectall "<filepath>",<type>{,"<map name>"}{,<x0>,<y0>,<x1>,<y1>};
*------------------------------------------*/
-BUILDIN(soundeffectall) {
+static BUILDIN(soundeffectall)
+{
struct block_list* bl;
const char* name;
int type;
@@ -13518,7 +15783,7 @@ BUILDIN(soundeffectall) {
/*==========================================
* pet status recovery [Valaris] / Rewritten by [Skotlex]
*------------------------------------------*/
-BUILDIN(petrecovery)
+static BUILDIN(petrecovery)
{
struct pet_data *pd;
struct map_session_data *sd = script->rid2sd(st);
@@ -13547,7 +15812,7 @@ BUILDIN(petrecovery)
*------------------------------------------*/
/// petskillattack <skill id>,<level>,<div>,<rate>,<bonusrate>
/// petskillattack "<skill name>",<level>,<div>,<rate>,<bonusrate>
-BUILDIN(petskillattack)
+static BUILDIN(petskillattack)
{
struct pet_data *pd;
struct map_session_data *sd = script->rid2sd(st);
@@ -13573,7 +15838,7 @@ BUILDIN(petskillattack)
*------------------------------------------*/
/// petskillsupport <skill id>,<level>,<delay>,<hp>,<sp>
/// petskillsupport "<skill name>",<level>,<delay>,<hp>,<sp>
-BUILDIN(petskillsupport)
+static BUILDIN(petskillsupport)
{
struct pet_data *pd;
struct map_session_data *sd = script->rid2sd(st);
@@ -13612,7 +15877,7 @@ BUILDIN(petskillsupport)
*------------------------------------------*/
/// skilleffect <skill id>,<level>
/// skilleffect "<skill name>",<level>
-BUILDIN(skilleffect)
+static BUILDIN(skilleffect)
{
struct map_session_data *sd;
@@ -13640,7 +15905,8 @@ BUILDIN(skilleffect)
*------------------------------------------*/
/// npcskilleffect <skill id>,<level>,<x>,<y>
/// npcskilleffect "<skill name>",<level>,<x>,<y>
-BUILDIN(npcskilleffect) {
+static BUILDIN(npcskilleffect)
+{
struct block_list *bl= map->id2bl(st->oid);
uint16 skill_id=( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) );
@@ -13657,26 +15923,43 @@ BUILDIN(npcskilleffect) {
/*==========================================
* Special effects [Valaris]
*------------------------------------------*/
-BUILDIN(specialeffect) {
+static BUILDIN(specialeffect)
+{
struct block_list *bl = NULL;
- int type = script_getnum(st,2);
- enum send_target target = script_hasdata(st,3) ? (send_target)script_getnum(st,3) : AREA;
+ int type = script_getnum(st, 2);
+ enum send_target target = AREA;
- if (script_hasdata(st,4)) {
- struct npc_data *nd = npc->name2id(script_getstr(st,4));
- if (nd != NULL)
- bl = &nd->bl;
+ if (script_hasdata(st, 3)) {
+ target = script_getnum(st, 3);
+ }
+
+ if (script_hasdata(st, 4)) {
+ if (script_isstringtype(st, 4)) {
+ struct npc_data *nd = npc->name2id(script_getstr(st, 4));
+ if (nd != NULL) {
+ bl = &nd->bl;
+ }
+ } else {
+ bl = map->id2bl(script_getnum(st, 4));
+ }
} else {
bl = map->id2bl(st->oid);
}
- if (bl == NULL)
+ if (bl == NULL) {
return true;
+ }
if (target == SELF) {
- struct map_session_data *sd = script->rid2sd(st);
- if (sd != NULL)
+ struct map_session_data *sd;
+ if (script_hasdata(st, 5)) {
+ sd = map->id2sd(script_getnum(st, 5));
+ } else {
+ sd = script->rid2sd(st);
+ }
+ if (sd != NULL) {
clif->specialeffect_single(bl, type, sd->fd);
+ }
} else {
clif->specialeffect(bl, type, target);
}
@@ -13684,7 +15967,58 @@ BUILDIN(specialeffect) {
return true;
}
-BUILDIN(specialeffect2) {
+/*==========================================
+ * Special effects with num [4144]
+ *------------------------------------------*/
+static BUILDIN(specialeffectnum)
+{
+ struct block_list *bl = NULL;
+ int type = script_getnum(st, 2);
+ int num = script_getnum(st, 3);
+ int num2 = script_getnum(st, 4);
+ enum send_target target = AREA;
+
+ if (script_hasdata(st, 5)) {
+ target = script_getnum(st, 5);
+ }
+
+ if (script_hasdata(st, 6)) {
+ if (script_isstringtype(st, 6)) {
+ struct npc_data *nd = npc->name2id(script_getstr(st, 6));
+ if (nd != NULL) {
+ bl = &nd->bl;
+ }
+ } else {
+ bl = map->id2bl(script_getnum(st, 6));
+ }
+ } else {
+ bl = map->id2bl(st->oid);
+ }
+
+ if (bl == NULL) {
+ return true;
+ }
+
+ uint64 bigNum = ((uint64)num2) * 0xffffffff + num;
+ if (target == SELF) {
+ struct map_session_data *sd;
+ if (script_hasdata(st, 7)) {
+ sd = map->id2sd(script_getnum(st, 7));
+ } else {
+ sd = script->rid2sd(st);
+ }
+ if (sd != NULL) {
+ clif->specialeffect_value_single(bl, type, bigNum, sd->fd);
+ }
+ } else {
+ clif->specialeffect_value(bl, type, bigNum, target);
+ }
+
+ return true;
+}
+
+static BUILDIN(specialeffect2)
+{
struct map_session_data *sd;
int type = script_getnum(st,2);
enum send_target target = script_hasdata(st,3) ? (send_target)script_getnum(st,3) : AREA;
@@ -13700,10 +16034,54 @@ BUILDIN(specialeffect2) {
return true;
}
+static BUILDIN(removespecialeffect)
+{
+ struct block_list *bl = NULL;
+ int type = script_getnum(st, 2);
+ enum send_target target = AREA;
+
+ if (script_hasdata(st, 3)) {
+ target = script_getnum(st, 3);
+ }
+
+ if (script_hasdata(st, 4)) {
+ if (script_isstringtype(st, 4)) {
+ struct npc_data *nd = npc->name2id(script_getstr(st, 4));
+ if (nd != NULL) {
+ bl = &nd->bl;
+ }
+ } else {
+ bl = map->id2bl(script_getnum(st, 4));
+ }
+ } else {
+ bl = map->id2bl(st->oid);
+ }
+
+ if (bl == NULL) {
+ return true;
+ }
+
+ if (target == SELF) {
+ struct map_session_data *sd;
+ if (script_hasdata(st, 5)) {
+ sd = map->id2sd(script_getnum(st, 5));
+ } else {
+ sd = script->rid2sd(st);
+ }
+ if (sd != NULL) {
+ clif->removeSpecialEffect_single(bl, type, &sd->bl);
+ }
+ } else {
+ clif->removeSpecialEffect(bl, type, target);
+ }
+
+ return true;
+}
+
/*==========================================
* Nude [Valaris]
*------------------------------------------*/
-BUILDIN(nude)
+static BUILDIN(nude)
{
struct map_session_data *sd = script->rid2sd(st);
int i, calcflag = 0;
@@ -13728,12 +16106,11 @@ BUILDIN(nude)
/*==========================================
* gmcommand [MouseJstr]
*------------------------------------------*/
-BUILDIN(atcommand)
+static BUILDIN(atcommand)
{
struct map_session_data *sd, *dummy_sd = NULL;
int fd;
const char* cmd;
- bool ret = true;
cmd = script_getstr(st,2);
@@ -13756,11 +16133,12 @@ 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;
}
/**
@@ -13770,7 +16148,7 @@ BUILDIN(atcommand)
* dispbottom "<message>"{,<color>};
* @endcode
*/
-BUILDIN(dispbottom)
+static BUILDIN(dispbottom)
{
struct map_session_data *sd = script->rid2sd(st);
const char *message = script_getstr(st,2);
@@ -13782,7 +16160,7 @@ BUILDIN(dispbottom)
int color = script_getnum(st,3);
clif->messagecolor_self(sd->fd, color, message);
} else {
- clif_disp_onlyself(sd, message, (int)strlen(message));
+ clif_disp_onlyself(sd, message);
}
return true;
@@ -13792,52 +16170,130 @@ BUILDIN(dispbottom)
* All The Players Full Recovery
* (HP/SP full restore and resurrect if need)
*------------------------------------------*/
-BUILDIN(recovery)
+static int buildin_recovery_sub(struct map_session_data *sd)
{
- struct map_session_data *sd;
- struct s_mapiterator* iter;
+ nullpo_retr(0, sd);
- iter = mapit_getallusers();
- for (sd = BL_UCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); sd = BL_UCAST(BL_PC, mapit->next(iter))) {
- if(pc_isdead(sd))
- status->revive(&sd->bl, 100, 100);
- else
- status_percent_heal(&sd->bl, 100, 100);
- clif->message(sd->fd,msg_sd(sd,880)); // "You have been recovered!"
+ if (pc_isdead(sd)) {
+ status->revive(&sd->bl, 100, 100);
+ } else {
+ status_percent_heal(&sd->bl, 100, 100);
+ }
+
+ return 0;
+}
+
+static int buildin_recovery_pc_sub(struct map_session_data *sd, va_list ap)
+{
+ return script->buildin_recovery_sub(sd);
+}
+
+static int buildin_recovery_bl_sub(struct block_list *bl, va_list ap)
+{
+ return script->buildin_recovery_sub(BL_CAST(BL_PC, bl));
+}
+
+static BUILDIN(recovery)
+{
+ if (script_hasdata(st, 2)) {
+ if (script_isstringtype(st, 2)) {
+ int16 m = map->mapname2mapid(script_getstr(st, 2));
+
+ if (m == -1) {
+ ShowWarning("script:recovery: invalid map!\n");
+ return false;
+ }
+
+ if (script_hasdata(st, 6)) {
+ int16 x1 = script_getnum(st, 3);
+ int16 y1 = script_getnum(st, 4);
+ int16 x2 = script_getnum(st, 5);
+ int16 y2 = script_getnum(st, 6);
+ map->foreachinarea(script->buildin_recovery_bl_sub, m, x1, y1, x2, y2, BL_PC);
+ } else {
+ map->foreachinmap(script->buildin_recovery_bl_sub, m, BL_PC);
+ }
+ } else {
+ struct map_session_data *sd = script->id2sd(st, script_getnum(st, 2));
+
+ if (sd != NULL) {
+ script->buildin_recovery_sub(sd);
+ }
+ }
+ } else {
+ map->foreachpc(script->buildin_recovery_pc_sub);
}
- mapit->free(iter);
return true;
}
-/*==========================================
- * Get your pet info: getpetinfo(n)
- * n -> 0:pet_id 1:pet_class 2:pet_name
- * 3:friendly 4:hungry, 5: rename flag.
- *------------------------------------------*/
-BUILDIN(getpetinfo)
+
+/*
+ * Get your current pet information
+ */
+static BUILDIN(getpetinfo)
{
struct map_session_data *sd = script->rid2sd(st);
- struct pet_data *pd;
- int type=script_getnum(st,2);
+ if (sd == NULL)
+ return true;
- if (sd == NULL || sd->pd == NULL) {
- if (type == 2)
- script_pushconststr(st,"null");
+ struct pet_data *pd = sd->pd;
+ int type = script_getnum(st, 2);
+ if (pd == NULL) {
+ if (type == PETINFO_NAME)
+ script_pushconststr(st, "null");
else
- script_pushint(st,0);
+ script_pushint(st, 0);
return true;
}
- pd = sd->pd;
+
switch(type) {
- case 0: script_pushint(st,pd->pet.pet_id); break;
- case 1: script_pushint(st,pd->pet.class_); break;
- case 2: script_pushstrcopy(st,pd->pet.name); break;
- case 3: script_pushint(st,pd->pet.intimate); break;
- case 4: script_pushint(st,pd->pet.hungry); break;
- case 5: script_pushint(st,pd->pet.rename_flag); break;
- default:
- script_pushint(st,0);
- break;
+ case PETINFO_ID:
+ script_pushint(st, pd->pet.pet_id);
+ break;
+ case PETINFO_CLASS:
+ script_pushint(st, pd->pet.class_);
+ break;
+ case PETINFO_NAME:
+ script_pushstrcopy(st, pd->pet.name);
+ break;
+ case PETINFO_INTIMACY:
+ script_pushint(st, pd->pet.intimate);
+ break;
+ case PETINFO_HUNGRY:
+ script_pushint(st, pd->pet.hungry);
+ break;
+ case PETINFO_RENAME:
+ script_pushint(st, pd->pet.rename_flag);
+ break;
+ case PETINFO_GID:
+ script_pushint(st, pd->bl.id);
+ break;
+ case PETINFO_EGGITEM:
+ script_pushint(st, pd->pet.egg_id);
+ break;
+ case PETINFO_FOODITEM:
+ script_pushint(st, pd->petDB->FoodID);
+ break;
+ case PETINFO_ACCESSORYITEM:
+ script_pushint(st, pd->petDB->AcceID);
+ break;
+ case PETINFO_ACCESSORYFLAG:
+ script_pushint(st, (pd->pet.equip != 0)? 1:0);
+ break;
+ case PETINFO_EVO_EGGID:
+ if (VECTOR_DATA(pd->petDB->evolve_data) != NULL)
+ script_pushint(st, VECTOR_DATA(pd->petDB->evolve_data)->petEggId);
+ else
+ script_pushint(st, 0);
+ break;
+ case PETINFO_AUTOFEED:
+ script_pushint(st, pd->pet.autofeed);
+ break;
+ default:
+ ShowWarning("buildin_getpetinfo: Invalid type %d.\n", type);
+ script_pushint(st, 0);
+ return false;
}
+
return true;
}
@@ -13847,7 +16303,7 @@ BUILDIN(getpetinfo)
* 3:friendly 4:hungry, 5: rename flag.
* 6: level
*------------------------------------------*/
-BUILDIN(gethominfo)
+static BUILDIN(gethominfo)
{
struct map_session_data *sd = script->rid2sd(st);
int type = script_getnum(st,2);
@@ -13875,20 +16331,15 @@ BUILDIN(gethominfo)
return true;
}
-/// Retrieves information about character's mercenary
-/// getmercinfo <type>[,<char id>];
-BUILDIN(getmercinfo)
+/*
+ * Retrieves information about character's mercenary
+ * getmercinfo <type>{, <char id> };
+ */
+static BUILDIN(getmercinfo)
{
- int type;
- struct map_session_data* sd;
- struct mercenary_data* md;
-
- type = script_getnum(st,2);
-
- if (script_hasdata(st,3)) {
- int char_id = script_getnum(st,3);
-
- if ((sd = script->charid2sd(st, char_id)) == NULL) {
+ struct map_session_data *sd;
+ if (script_hasdata(st, 3)) {
+ if ((sd = script->charid2sd(st, script_getnum(st, 3))) == NULL) {
script_pushnil(st);
return true;
}
@@ -13897,27 +16348,48 @@ BUILDIN(getmercinfo)
return true;
}
- md = ( sd->status.mer_id && sd->md ) ? sd->md : NULL;
+ struct mercenary_data *md = (sd->status.mer_id && sd->md)? sd->md : NULL;
+ int type = script_getnum(st, 2);
+ if (md == NULL) {
+ if (type == MERCINFO_NAME)
+ script_pushconststr(st, "");
+ else
+ script_pushint(st, 0);
+ return true;
+ }
- switch( type )
- {
- case 0: script_pushint(st,md ? md->mercenary.mercenary_id : 0); break;
- case 1: script_pushint(st,md ? md->mercenary.class_ : 0); break;
- case 2:
- if( md )
- script_pushstrcopy(st,md->db->name);
- else
- script_pushconststr(st,"");
- break;
- case 3: script_pushint(st,md ? mercenary->get_faith(md) : 0); break;
- case 4: script_pushint(st,md ? mercenary->get_calls(md) : 0); break;
- case 5: script_pushint(st,md ? md->mercenary.kill_count : 0); break;
- case 6: script_pushint(st,md ? mercenary->get_lifetime(md) : 0); break;
- case 7: script_pushint(st,md ? md->db->lv : 0); break;
- default:
- ShowError("buildin_getmercinfo: Invalid type %d (char_id=%d).\n", type, sd->status.char_id);
- script_pushnil(st);
- return false;
+ switch (type) {
+ case MERCINFO_ID:
+ script_pushint(st, md->mercenary.mercenary_id);
+ break;
+ case MERCINFO_CLASS:
+ script_pushint(st, md->mercenary.class_);
+ break;
+ case MERCINFO_NAME:
+ script_pushstrcopy(st, md->db->name);
+ break;
+ case MERCINFO_FAITH:
+ script_pushint(st, mercenary->get_faith(md));
+ break;
+ case MERCINFO_CALLS:
+ script_pushint(st, mercenary->get_calls(md));
+ break;
+ case MERCINFO_KILLCOUNT:
+ script_pushint(st, md->mercenary.kill_count);
+ break;
+ case MERCINFO_LIFETIME:
+ script_pushint(st, mercenary->get_lifetime(md));
+ break;
+ case MERCINFO_LEVEL:
+ script_pushint(st, md->db->lv);
+ break;
+ case MERCINFO_GID:
+ script_pushint(st, md->bl.id);
+ break;
+ default:
+ ShowError("buildin_getmercinfo: Invalid type %d (char_id=%d).\n", type, sd->status.char_id);
+ script_pushnil(st);
+ return false;
}
return true;
@@ -13928,21 +16400,20 @@ BUILDIN(getmercinfo)
* selected card or not.
* checkequipedcard(4001);
*------------------------------------------*/
-BUILDIN(checkequipedcard)
+static BUILDIN(checkequipedcard)
{
- int n,i,c=0;
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
return true;
- c = script_getnum(st,2);
+ int c = script_getnum(st,2);
- for( i=0; i<MAX_INVENTORY; i++) {
+ for (int i = 0; i < sd->status.inventorySize; i++) {
if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount && sd->inventory_data[i]) {
if (itemdb_isspecial(sd->status.inventory[i].card[0]))
continue;
- for(n=0;n<sd->inventory_data[i]->slot;n++) {
+ for (int n = 0; n < sd->inventory_data[i]->slot; n++) {
if(sd->status.inventory[i].card[n]==c) {
script_pushint(st,1);
return true;
@@ -13955,7 +16426,7 @@ BUILDIN(checkequipedcard)
return true;
}
-BUILDIN(__jump_zero)
+static BUILDIN(__jump_zero)
{
int sel;
sel=script_getnum(st,2);
@@ -13977,7 +16448,7 @@ BUILDIN(__jump_zero)
/*==========================================
* movenpc [MouseJstr]
*------------------------------------------*/
-BUILDIN(movenpc)
+static BUILDIN(movenpc)
{
struct npc_data *nd = NULL;
const char *npc_name;
@@ -13999,7 +16470,7 @@ BUILDIN(movenpc)
/*==========================================
* message [MouseJstr]
*------------------------------------------*/
-BUILDIN(message)
+static BUILDIN(message)
{
const char *message;
struct map_session_data *sd = NULL;
@@ -14018,14 +16489,38 @@ BUILDIN(message)
return true;
}
+static BUILDIN(servicemessage)
+{
+ struct map_session_data *sd = NULL;
+
+ if (script_hasdata(st, 4)) {
+ if (script_isstringtype(st, 4))
+ sd = script->nick2sd(st, script_getstr(st, 4));
+ else
+ sd = script->id2sd(st, script_getnum(st, 4));
+ } else {
+ sd = script->rid2sd(st);
+ }
+
+ if (sd == NULL)
+ return true;
+
+ const char *message = script_getstr(st, 2);
+ const int color = script_getnum(st, 3);
+ clif->serviceMessageColor(sd, color, message);
+
+ return true;
+}
+
/*==========================================
* npctalk (sends message to surrounding area)
- * usage: npctalk "<message>"{,"<npc name>"};
+ * usage: npctalk("<message>"{, "<npc name>"{, <show_name>}});
*------------------------------------------*/
-BUILDIN(npctalk)
+static BUILDIN(npctalk)
{
struct npc_data* nd;
const char *str = script_getstr(st,2);
+ bool show_name = true;
if (script_hasdata(st, 3)) {
nd = npc->name2id(script_getstr(st, 3));
@@ -14033,61 +16528,78 @@ BUILDIN(npctalk)
nd = map->id2nd(st->oid);
}
+ if (script_hasdata(st, 4)) {
+ show_name = (script_getnum(st, 4) != 0) ? true : false;
+ }
+
if (nd != NULL) {
char name[NAME_LENGTH], message[256];
safestrncpy(name, nd->name, sizeof(name));
strtok(name, "#"); // discard extra name identifier if present
- safesnprintf(message, sizeof(message), "%s : %s", name, str);
- clif->disp_overhead(&nd->bl, message);
+ if (show_name) {
+ safesnprintf(message, sizeof(message), "%s : %s", name, str);
+ } else {
+ safesnprintf(message, sizeof(message), "%s", str);
+ }
+ clif->disp_overhead(&nd->bl, message, AREA_CHAT_WOC, NULL);
}
return true;
}
// change npc walkspeed [Valaris]
-BUILDIN(npcspeed) {
- struct npc_data* nd;
- int speed;
-
- speed = script_getnum(st,2);
- nd = map->id2nd(st->oid);
+static BUILDIN(npcspeed)
+{
+ struct npc_data *nd = map->id2nd(st->oid);
+ int speed = script_getnum(st, 2);
if (nd != NULL) {
unit->bl2ud2(&nd->bl); // ensure nd->ud is safe to edit
+ if (nd->ud == NULL) {
+ ShowWarning("buildin_npcspeed: floating NPC don't have unit data.\n");
+ return false;
+ }
nd->speed = speed;
nd->ud->state.speed_changed = 1;
}
return true;
}
+
// make an npc walk to a position [Valaris]
-BUILDIN(npcwalkto)
+static BUILDIN(npcwalkto)
{
struct npc_data *nd = map->id2nd(st->oid);
- int x=0,y=0;
-
- x=script_getnum(st,2);
- y=script_getnum(st,3);
+ int x = script_getnum(st, 2);
+ int y = script_getnum(st, 3);
if (nd != NULL) {
unit->bl2ud2(&nd->bl); // ensure nd->ud is safe to edit
+ if (nd->ud == NULL) {
+ ShowWarning("buildin_npcwalkto: floating NPC don't have unit data.\n");
+ return false;
+ }
if (!nd->status.hp) {
status_calc_npc(nd, SCO_FIRST);
} else {
status_calc_npc(nd, SCO_NONE);
}
- unit->walktoxy(&nd->bl,x,y,0);
+ unit->walk_toxy(&nd->bl, x, y, 0);
}
return true;
}
// stop an npc's movement [Valaris]
-BUILDIN(npcstop)
+static BUILDIN(npcstop)
{
struct npc_data *nd = map->id2nd(st->oid);
if (nd != NULL) {
unit->bl2ud2(&nd->bl); // ensure nd->ud is safe to edit
+ if (nd->ud == NULL) {
+ ShowWarning("buildin_npcstop: floating NPC don't have unit data.\n");
+ return false;
+ }
unit->stop_walking(&nd->bl, STOPWALKING_FLAG_FIXPOS|STOPWALKING_FLAG_NEXTCELL);
}
@@ -14095,7 +16607,7 @@ BUILDIN(npcstop)
}
// set click npc distance [4144]
-BUILDIN(setnpcdistance)
+static BUILDIN(setnpcdistance)
{
struct npc_data *nd = map->id2nd(st->oid);
if (nd == NULL)
@@ -14107,7 +16619,7 @@ BUILDIN(setnpcdistance)
}
// return current npc direction [4144]
-BUILDIN(getnpcdir)
+static BUILDIN(getnpcdir)
{
const struct npc_data *nd = NULL;
@@ -14133,7 +16645,7 @@ BUILDIN(getnpcdir)
}
// set npc direction [4144]
-BUILDIN(setnpcdir)
+static BUILDIN(setnpcdir)
{
int newdir;
struct npc_data *nd = NULL;
@@ -14167,7 +16679,7 @@ BUILDIN(setnpcdir)
}
// return npc class [4144]
-BUILDIN(getnpcclass)
+static BUILDIN(getnpcclass)
{
const struct npc_data *nd = NULL;
@@ -14195,7 +16707,7 @@ BUILDIN(getnpcclass)
/*==========================================
* getlook char info. getlook(arg)
*------------------------------------------*/
-BUILDIN(getlook)
+static BUILDIN(getlook)
{
int type,val = -1;
struct map_session_data *sd = script->rid2sd(st);
@@ -14205,15 +16717,15 @@ BUILDIN(getlook)
type=script_getnum(st,2);
switch(type) {
case LOOK_HAIR: val = sd->status.hair; break; //1
- case LOOK_WEAPON: val = sd->status.weapon; break; //2
- case LOOK_HEAD_BOTTOM: val = sd->status.head_bottom; break; //3
- case LOOK_HEAD_TOP: val = sd->status.head_top; break; //4
- case LOOK_HEAD_MID: val = sd->status.head_mid; break; //5
+ case LOOK_WEAPON: val = sd->status.look.weapon; break; //2
+ case LOOK_HEAD_BOTTOM: val = sd->status.look.head_bottom; break; //3
+ case LOOK_HEAD_TOP: val = sd->status.look.head_top; break; //4
+ case LOOK_HEAD_MID: val = sd->status.look.head_mid; break; //5
case LOOK_HAIR_COLOR: val = sd->status.hair_color; break; //6
case LOOK_CLOTHES_COLOR: val = sd->status.clothes_color; break; //7
- case LOOK_SHIELD: val = sd->status.shield; break; //8
+ case LOOK_SHIELD: val = sd->status.look.shield; break; //8
case LOOK_SHOES: break; //9
- case LOOK_ROBE: val = sd->status.robe; break; //12
+ case LOOK_ROBE: val = sd->status.look.robe; break; //12
case LOOK_BODY2: val=sd->status.body; break; //13
}
@@ -14224,7 +16736,7 @@ BUILDIN(getlook)
/*==========================================
* get char save point. argument: 0- map name, 1- x, 2- y
*------------------------------------------*/
-BUILDIN(getsavepoint)
+static BUILDIN(getsavepoint)
{
int type;
struct map_session_data *sd = script->rid2sd(st);
@@ -14267,7 +16779,7 @@ BUILDIN(getsavepoint)
* 0 - success
* -1 - some error, MapName$,MapX,MapY contains unknown value.
*------------------------------------------*/
-BUILDIN(getmapxy)
+static BUILDIN(getmapxy)
{
struct block_list *bl = NULL;
struct map_session_data *sd = NULL;
@@ -14320,7 +16832,7 @@ BUILDIN(getmapxy)
case 0: //Get Character Position
if (script_hasdata(st,6)) {
if (script_isstringtype(st,6))
- sd = map->nick2sd(script_getstr(st,6));
+ sd = map->nick2sd(script_getstr(st,6), false);
else
sd = map->id2sd(script_getnum(st,6));
} else {
@@ -14347,7 +16859,7 @@ BUILDIN(getmapxy)
case 2: //Get Pet Position
if (script_hasdata(st,6)) {
if (script_isstringtype(st,6))
- sd = map->nick2sd(script_getstr(st,6));
+ sd = map->nick2sd(script_getstr(st,6), false);
else {
bl = map->id2bl(script_getnum(st,6));
break;
@@ -14369,7 +16881,7 @@ BUILDIN(getmapxy)
case 4: //Get Homun Position
if (script_hasdata(st,6)) {
if (script_isstringtype(st,6)) {
- sd = map->nick2sd(script_getstr(st,6));
+ sd = map->nick2sd(script_getstr(st,6), false);
} else {
bl = map->id2bl(script_getnum(st,6));
break;
@@ -14384,7 +16896,7 @@ BUILDIN(getmapxy)
case 5: //Get Mercenary Position
if (script_hasdata(st,6)) {
if (script_isstringtype(st,6)) {
- sd = map->nick2sd(script_getstr(st,6));
+ sd = map->nick2sd(script_getstr(st,6), false);
} else {
bl = map->id2bl(script_getnum(st,6));
break;
@@ -14399,7 +16911,7 @@ BUILDIN(getmapxy)
case 6: //Get Elemental Position
if (script_hasdata(st,6)) {
if (script_isstringtype(st,6)) {
- sd = map->nick2sd(script_getstr(st,6));
+ sd = map->nick2sd(script_getstr(st,6), false);
} else {
bl = map->id2bl(script_getnum(st,6));
break;
@@ -14463,61 +16975,97 @@ BUILDIN(getmapxy)
return true;
}
+enum logmes_type {
+ LOGMES_NPC,
+ LOGMES_ATCOMMAND
+};
+
/*==========================================
- * Allows player to write NPC logs (i.e. Bank NPC, etc) [Lupus]
+ * Allows player to write logs (i.e. Bank NPC, etc) [Lupus]
*------------------------------------------*/
-BUILDIN(logmes)
+static BUILDIN(logmes)
{
- const char *str;
+ const char *str = script_getstr(st, 2);
struct map_session_data *sd = script->rid2sd(st);
+ enum logmes_type type = LOGMES_NPC;
+ nullpo_retr(false, sd);
- if (sd == NULL)
- return true;
+ if (script_hasdata(st, 3)) {
+ type = script_getnum(st, 3);
+ }
+
+ switch (type) {
+ case LOGMES_ATCOMMAND:
+ logs->atcommand(sd, str);
+ break;
+ case LOGMES_NPC:
+ logs->npc(sd, str);
+ break;
+ default:
+ ShowError("script:logmes: Unknown log type!\n");
+ st->state = END;
+ return false;
+ }
- str = script_getstr(st,2);
- logs->npc(sd,str);
return true;
}
-BUILDIN(summon)
+/**
+ * Summons a mob which will act as a slave for the invoking character.
+ *
+ * @code{.herc}
+ * summon("mob name", <mob id>{, <timeout>{, "event label"}});
+ * @endcode
+ *
+ * @author Celest
+ *
+ **/
+static BUILDIN(summon)
{
- int class_, timeout=0;
- const char *str,*event="";
- struct mob_data *md;
- int64 tick = timer->gettick();
struct map_session_data *sd = script->rid2sd(st);
+
if (sd == NULL)
return true;
- str = script_getstr(st,2);
- class_ = script_getnum(st,3);
- if( script_hasdata(st,4) )
- timeout=script_getnum(st,4);
- if( script_hasdata(st,5) ) {
- event=script_getstr(st,5);
+ const int64 tick = timer->gettick();
+
+ clif->skill_poseffect(&sd->bl, AM_CALLHOMUN, 1, sd->bl.x, sd->bl.y, tick);
+
+ const char *event = "";
+
+ if (script_hasdata(st, 5)) {
+ event = script_getstr(st, 5);
script->check_event(st, event);
}
- clif->skill_poseffect(&sd->bl,AM_CALLHOMUN,1,sd->bl.x,sd->bl.y,tick);
+ const char *name = script_getstr(st, 2);
+ const int mob_id = script_getnum(st, 3);
+ struct mob_data *md = mob->once_spawn_sub(&sd->bl, sd->bl.m, sd->bl.x, sd->bl.y, name, mob_id, event,
+ SZ_SMALL, AI_NONE, 0);
- md = mob->once_spawn_sub(&sd->bl, sd->bl.m, sd->bl.x, sd->bl.y, str, class_, event, SZ_SMALL, AI_NONE);
- if (md) {
- md->master_id=sd->bl.id;
+ if (md != NULL) {
+ md->master_id = sd->bl.id;
md->special_state.ai = AI_ATTACK;
- if( md->deletetimer != INVALID_TIMER )
+
+ if (md->deletetimer != INVALID_TIMER)
timer->delete(md->deletetimer, mob->timer_delete);
- md->deletetimer = timer->add(tick+(timeout>0?timeout*1000:60000),mob->timer_delete,md->bl.id,0);
- mob->spawn (md); //Now it is ready for spawning.
- clif->specialeffect(&md->bl,344,AREA);
+
+ const int timeout = script_hasdata(st, 4) ? script_getnum(st, 4) * 1000 : 60000;
+
+ md->deletetimer = timer->add(tick + ((timeout == 0) ? 60000 : timeout), mob->timer_delete, md->bl.id, 0);
+ mob->spawn(md);
+ clif->specialeffect(&md->bl, 344, AREA);
sc_start4(NULL, &md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, 60000);
}
+
return true;
}
/*==========================================
* Checks whether it is daytime/nighttime
*------------------------------------------*/
-BUILDIN(isnight) {
+static BUILDIN(isnight)
+{
script_pushint(st,(map->night_flag == 1));
return true;
}
@@ -14526,7 +17074,7 @@ BUILDIN(isnight) {
* Check how many items/cards in the list are
* equipped - used for 2/15's cards patch [celest]
*------------------------------------------------*/
-BUILDIN(isequippedcnt)
+static BUILDIN(isequippedcnt)
{
int i, j, k, id = 1;
int ret = 0;
@@ -14547,6 +17095,8 @@ BUILDIN(isequippedcnt)
if(j == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == index) continue;
if(j == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == index) continue;
if(j == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == index || sd->equip_index[EQI_HEAD_LOW] == index)) continue;
+ if(j == EQI_COSTUME_MID && sd->equip_index[EQI_COSTUME_LOW] == index) continue;
+ if(j == EQI_COSTUME_TOP && (sd->equip_index[EQI_COSTUME_MID] == index || sd->equip_index[EQI_COSTUME_LOW] == index)) continue;
if(!sd->inventory_data[index])
continue;
@@ -14575,7 +17125,7 @@ BUILDIN(isequippedcnt)
* -- Items checked cannot be reused in another
* card set to prevent exploits
*------------------------------------------------*/
-BUILDIN(isequipped)
+static BUILDIN(isequipped)
{
int i, j, k, id = 1;
int index, flag;
@@ -14600,6 +17150,8 @@ BUILDIN(isequipped)
if(j == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == index) continue;
if(j == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == index) continue;
if(j == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == index || sd->equip_index[EQI_HEAD_LOW] == index)) continue;
+ if(j == EQI_COSTUME_MID && sd->equip_index[EQI_COSTUME_LOW] == index) continue;
+ if(j == EQI_COSTUME_TOP && (sd->equip_index[EQI_COSTUME_MID] == index || sd->equip_index[EQI_COSTUME_LOW] == index)) continue;
if(!sd->inventory_data[index])
continue;
@@ -14655,7 +17207,7 @@ BUILDIN(isequipped)
* Check how many given inserted cards in the CURRENT
* weapon - used for 2/15's cards patch [Lupus]
*------------------------------------------------*/
-BUILDIN(cardscnt)
+static BUILDIN(cardscnt)
{
int i, k, id = 1;
int ret = 0;
@@ -14697,25 +17249,30 @@ BUILDIN(cardscnt)
* Returns the refined number of the current item, or an
* item with inventory index specified
*-------------------------------------------------------*/
-BUILDIN(getrefine)
+static BUILDIN(getrefine)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
return true;
- script_pushint(st,sd->status.inventory[status->current_equip_item_index].refine);
+ if (status->current_equip_item_index < 0)
+ script_pushint(st, 0);
+ else
+ script_pushint(st, sd->status.inventory[status->current_equip_item_index].refine);
return true;
}
/*=======================================================
* Day/Night controls
*-------------------------------------------------------*/
-BUILDIN(night) {
+static BUILDIN(night)
+{
if (map->night_flag != 1) pc->map_night_timer(pc->night_timer_tid, 0, 0, 1);
return true;
}
-BUILDIN(day) {
+static BUILDIN(day)
+{
if (map->night_flag != 0) pc->map_day_timer(pc->day_timer_tid, 0, 0, 1);
return true;
}
@@ -14723,7 +17280,7 @@ BUILDIN(day) {
//=======================================================
// Unequip [Spectre]
//-------------------------------------------------------
-BUILDIN(unequip)
+static BUILDIN(unequip)
{
size_t num;
struct map_session_data *sd;
@@ -14738,7 +17295,7 @@ BUILDIN(unequip)
return true;
}
-BUILDIN(equip)
+static BUILDIN(equip)
{
int nameid=0,i;
struct item_data *item_data;
@@ -14749,17 +17306,17 @@ BUILDIN(equip)
nameid=script_getnum(st,2);
if((item_data = itemdb->exists(nameid)) == NULL)
{
- ShowError("wrong item ID : equipitem(%i)\n",nameid);
+ ShowError("wrong item ID : equipitem(%d)\n",nameid);
return false;
}
- ARR_FIND( 0, MAX_INVENTORY, i, sd->status.inventory[i].nameid == nameid && sd->status.inventory[i].equip == 0 );
- if( i < MAX_INVENTORY )
- pc->equipitem(sd,i,item_data->equip);
+ ARR_FIND(0, sd->status.inventorySize, i, sd->status.inventory[i].nameid == nameid && sd->status.inventory[i].equip == 0);
+ if (i < sd->status.inventorySize)
+ pc->equipitem(sd, i, item_data->equip);
return true;
}
-BUILDIN(autoequip)
+static BUILDIN(autoequip)
{
int nameid, flag;
struct item_data *item_data;
@@ -14786,7 +17343,7 @@ BUILDIN(autoequip)
* Equip2
* equip2 <item id>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>;
*-------------------------------------------------------*/
-BUILDIN(equip2)
+static BUILDIN(equip2)
{
int i,nameid,ref,attr,c0,c1,c2,c3;
struct item_data *item_data;
@@ -14805,33 +17362,33 @@ BUILDIN(equip2)
return false;
}
- ref = script_getnum(st,3);
- attr = script_getnum(st,4);
- c0 = (short)script_getnum(st,5);
- c1 = (short)script_getnum(st,6);
- c2 = (short)script_getnum(st,7);
- c3 = (short)script_getnum(st,8);
+ ref = script_getnum(st, 3);
+ attr = script_getnum(st, 4);
+ c0 = script_getnum(st, 5);
+ c1 = script_getnum(st, 6);
+ c2 = script_getnum(st, 7);
+ c3 = script_getnum(st, 8);
- ARR_FIND( 0, MAX_INVENTORY, i,( sd->status.inventory[i].equip == 0 &&
+ ARR_FIND(0, sd->status.inventorySize, i, (sd->status.inventory[i].equip == 0 &&
sd->status.inventory[i].nameid == nameid &&
sd->status.inventory[i].refine == ref &&
sd->status.inventory[i].attribute == attr &&
sd->status.inventory[i].card[0] == c0 &&
sd->status.inventory[i].card[1] == c1 &&
sd->status.inventory[i].card[2] == c2 &&
- sd->status.inventory[i].card[3] == c3 ) );
+ sd->status.inventory[i].card[3] == c3));
- if( i < MAX_INVENTORY ) {
+ if (i < sd->status.inventorySize) {
script_pushint(st,1);
pc->equipitem(sd,i,item_data->equip);
- }
- else
+ } else {
script_pushint(st,0);
+ }
return true;
}
-BUILDIN(setbattleflag)
+static BUILDIN(setbattleflag)
{
const char *flag, *value;
@@ -14846,7 +17403,7 @@ BUILDIN(setbattleflag)
return true;
}
-BUILDIN(getbattleflag)
+static BUILDIN(getbattleflag)
{
const char *flag;
int value;
@@ -14868,7 +17425,7 @@ BUILDIN(getbattleflag)
//=======================================================
// strlen [Valaris]
//-------------------------------------------------------
-BUILDIN(getstrlen)
+static BUILDIN(getstrlen)
{
const char *str = script_getstr(st,2);
@@ -14881,7 +17438,7 @@ BUILDIN(getstrlen)
//=======================================================
// isalpha [Valaris]
//-------------------------------------------------------
-BUILDIN(charisalpha)
+static BUILDIN(charisalpha)
{
const char *str=script_getstr(st,2);
int pos=script_getnum(st,3);
@@ -14895,7 +17452,7 @@ BUILDIN(charisalpha)
//=======================================================
// charisupper <str>, <index>
//-------------------------------------------------------
-BUILDIN(charisupper)
+static BUILDIN(charisupper)
{
const char *str = script_getstr(st,2);
int pos = script_getnum(st,3);
@@ -14909,7 +17466,7 @@ BUILDIN(charisupper)
//=======================================================
// charislower <str>, <index>
//-------------------------------------------------------
-BUILDIN(charislower)
+static BUILDIN(charislower)
{
const char *str = script_getstr(st,2);
int pos = script_getnum(st,3);
@@ -14923,7 +17480,8 @@ BUILDIN(charislower)
//=======================================================
// charat <str>, <index>
//-------------------------------------------------------
-BUILDIN(charat) {
+static BUILDIN(charat)
+{
const char *str = script_getstr(st,2);
int pos = script_getnum(st,3);
@@ -14938,9 +17496,164 @@ BUILDIN(charat) {
}
//=======================================================
+// isstr <argument>
+//
+// returns type:
+// 0 - int
+// 1 - string
+// 2 - other
+//-------------------------------------------------------
+static BUILDIN(isstr)
+{
+ if (script_isinttype(st, 2)) {
+ script_pushint(st, 0);
+ } else if (script_isstringtype(st, 2)) {
+ script_pushint(st, 1);
+ } else {
+ script_pushint(st, 2);
+ }
+ return true;
+}
+
+enum datatype {
+ DATATYPE_NIL = 1 << 7, // we don't start at 1, to leave room for primitives
+ DATATYPE_STR = 1 << 8,
+ DATATYPE_INT = 1 << 9,
+ DATATYPE_CONST = 1 << 10,
+ DATATYPE_PARAM = 1 << 11,
+ DATATYPE_VAR = 1 << 12,
+ DATATYPE_LABEL = 1 << 13,
+};
+
+static BUILDIN(getdatatype)
+{
+ int type;
+
+ if (script_hasdata(st, 2)) {
+ struct script_data *data = script_getdata(st, 2);
+
+ if (data_isstring(data)) {
+ type = DATATYPE_STR;
+ if (data->type == C_CONSTSTR) {
+ type |= DATATYPE_CONST;
+ }
+ } else if (data_isint(data)) {
+ type = DATATYPE_INT;
+ } else if (data_islabel(data)) {
+ type = DATATYPE_LABEL;
+ } else if (data_isreference(data)) {
+ if (reference_toconstant(data)) {
+ type = DATATYPE_CONST | DATATYPE_INT;
+ } else if (reference_toparam(data)) {
+ type = DATATYPE_PARAM | DATATYPE_INT;
+ } else if (reference_tovariable(data)) {
+ type = DATATYPE_VAR;
+ if (is_string_variable(reference_getname(data))) {
+ type |= DATATYPE_STR;
+ } else {
+ type |= DATATYPE_INT;
+ }
+ } else {
+ ShowError("script:getdatatype: Unknown reference type!\n");
+ script->reportdata(data);
+ st->state = END;
+ return false;
+ }
+ } else {
+ type = data->type; // fallback to primitive type if unknown
+ }
+ } else {
+ type = DATATYPE_NIL; // nothing was passed
+ }
+
+ script_pushint(st, type);
+ return true;
+}
+
+static BUILDIN(data_to_string)
+{
+ if (script_hasdata(st, 2)) {
+ struct script_data *data = script_getdata(st, 2);
+
+ if (data_isstring(data)) {
+ script_pushcopy(st, 2);
+ } else if (data_isint(data)) {
+ char *str = NULL;
+
+ CREATE(str, char, 20);
+ safesnprintf(str, 20, "%"PRId64"", data->u.num);
+ script_pushstr(st, str);
+ } else if (data_islabel(data)) {
+ const char *str = "";
+
+ // XXX: because all we have is the label pos we can't be sure which
+ // one is the correct label if more than one has the same pos.
+ // We might want to store both the pos and str_data index in
+ // data->u.num, similar to how C_NAME stores both the array
+ // index and str_data index in u.num with bitmasking. This
+ // would also avoid the awkward for() loops as we could
+ // directly access the string with script->get_str().
+
+ if (st->oid) {
+ struct npc_data *nd = map->id2nd(st->oid);
+
+ for (int i = 0; i < nd->u.scr.label_list_num; ++i) {
+ if (nd->u.scr.label_list[i].pos == data->u.num) {
+ str = nd->u.scr.label_list[i].name;
+ break;
+ }
+ }
+ } else {
+ for (int i = LABEL_START; script->str_data[i].next != 0; i = script->str_data[i].next) {
+ if (script->str_data[i].label == data->u.num) {
+ str = script->get_str(i);
+ break;
+ }
+ }
+ }
+
+ script_pushconststr(st, str);
+ } else if (data_isreference(data)) {
+ script_pushstrcopy(st, reference_getname(data));
+ } else {
+ ShowWarning("script:data_to_string: unknown data type!\n");
+ script->reportdata(data);
+ script_pushconststr(st, "");
+ }
+ } else {
+ script_pushconststr(st, ""); // NIL
+ }
+
+ return true;
+}
+
+//=======================================================
+// chr <int>
+//-------------------------------------------------------
+static BUILDIN(chr)
+{
+ char output[2];
+ output[0] = script_getnum(st, 2);
+ output[1] = '\0';
+
+ script_pushstrcopy(st, output);
+ return true;
+}
+
+//=======================================================
+// ord <chr>
+//-------------------------------------------------------
+static BUILDIN(ord)
+{
+ const char *chr = script_getstr(st, 2);
+ script_pushint(st, *chr);
+ return true;
+}
+
+//=======================================================
// setchar <string>, <char>, <index>
//-------------------------------------------------------
-BUILDIN(setchar)
+static BUILDIN(setchar)
{
const char *str = script_getstr(st,2);
const char *c = script_getstr(st,3);
@@ -14957,7 +17670,7 @@ BUILDIN(setchar)
//=======================================================
// insertchar <string>, <char>, <index>
//-------------------------------------------------------
-BUILDIN(insertchar)
+static BUILDIN(insertchar)
{
const char *str = script_getstr(st,2);
const char *c = script_getstr(st,3);
@@ -14984,7 +17697,7 @@ BUILDIN(insertchar)
//=======================================================
// delchar <string>, <index>
//-------------------------------------------------------
-BUILDIN(delchar)
+static BUILDIN(delchar)
{
const char *str = script_getstr(st,2);
int index = script_getnum(st,3);
@@ -15010,7 +17723,7 @@ BUILDIN(delchar)
//=======================================================
// strtoupper <str>
//-------------------------------------------------------
-BUILDIN(strtoupper)
+static BUILDIN(strtoupper)
{
const char *str = script_getstr(st,2);
char *output = aStrdup(str);
@@ -15028,7 +17741,7 @@ BUILDIN(strtoupper)
//=======================================================
// strtolower <str>
//-------------------------------------------------------
-BUILDIN(strtolower)
+static BUILDIN(strtolower)
{
const char *str = script_getstr(st,2);
char *output = aStrdup(str);
@@ -15046,7 +17759,7 @@ BUILDIN(strtolower)
//=======================================================
// substr <str>, <start>, <end>
//-------------------------------------------------------
-BUILDIN(substr)
+static BUILDIN(substr)
{
const char *str = script_getstr(st,2);
char *output;
@@ -15072,7 +17785,7 @@ BUILDIN(substr)
// explode <dest_string_array>, <str>, <delimiter>
// Note: delimiter is limited to 1 char
//-------------------------------------------------------
-BUILDIN(explode)
+static BUILDIN(explode)
{
struct script_data* data = script_getdata(st, 2);
const char *str = script_getstr(st,3);
@@ -15137,7 +17850,7 @@ BUILDIN(explode)
// implode <string_array>
// implode <string_array>, <glue>
//-------------------------------------------------------
-BUILDIN(implode)
+static BUILDIN(implode)
{
struct script_data* data = script_getdata(st, 2);
const char *name;
@@ -15229,130 +17942,19 @@ BUILDIN(implode)
// Implements C sprintf, except format %n. The resulting string is
// returned, instead of being saved in variable by reference.
//-------------------------------------------------------
-BUILDIN(sprintf) {
- unsigned int argc = 0, arg = 0;
- const char* format;
- char* p;
- char* q;
- char* buf = NULL;
- char* buf2 = NULL;
- struct script_data* data;
- size_t len, buf2_len = 0;
- StringBuf final_buf;
-
- // Fetch init data
- format = script_getstr(st, 2);
- argc = script_lastdata(st)-2;
- len = strlen(format);
-
- // Skip parsing, where no parsing is required.
- if(len==0) {
- script_pushconststr(st,"");
- return true;
- }
-
- // Pessimistic alloc
- CREATE(buf, char, len+1);
-
- // Need not be parsed, just solve stuff like %%.
- if(argc==0) {
- memcpy(buf,format,len+1);
- script_pushstrcopy(st, buf);
- aFree(buf);
- return true;
- }
-
- safestrncpy(buf, format, len+1);
-
- // Issue sprintf for each parameter
- StrBuf->Init(&final_buf);
- q = buf;
- while((p = strchr(q, '%'))!=NULL) {
- if(p!=q) {
- len = p-q+1;
- if(buf2_len<len) {
- RECREATE(buf2, char, len);
- buf2_len = len;
- }
- safestrncpy(buf2, q, len);
- StrBuf->AppendStr(&final_buf, buf2);
- q = p;
- }
- p = q+1;
- if(*p=='%') { // %%
- StrBuf->AppendStr(&final_buf, "%");
- q+=2;
- continue;
- }
- if(*p=='n') { // %n
- ShowWarning("buildin_sprintf: Format %%n not supported! Skipping...\n");
- script->reportsrc(st);
- q+=2;
- continue;
- }
- if(arg>=argc) {
- ShowError("buildin_sprintf: Not enough arguments passed!\n");
- aFree(buf);
- if(buf2) aFree(buf2);
- StrBuf->Destroy(&final_buf);
- script_pushconststr(st,"");
- return false;
- }
- if((p = strchr(q+1, '%'))==NULL) {
- p = strchr(q, 0); // EOS
- }
- len = p-q+1;
- if(buf2_len<len) {
- RECREATE(buf2, char, len);
- buf2_len = len;
- }
- safestrncpy(buf2, q, len);
- q = p;
-
- // Note: This assumes the passed value being the correct
- // type to the current format specifier. If not, the server
- // probably crashes or returns anything else, than expected,
- // but it would behave in normal code the same way so it's
- // the scripter's responsibility.
- data = script_getdata(st, arg+3);
- if(data_isstring(data)) { // String
- StrBuf->Printf(&final_buf, buf2, script_getstr(st, arg+3));
- } else if(data_isint(data)) { // Number
- StrBuf->Printf(&final_buf, buf2, script_getnum(st, arg+3));
- } else if(data_isreference(data)) { // Variable
- char* name = reference_getname(data);
- if(name[strlen(name)-1]=='$') { // var Str
- StrBuf->Printf(&final_buf, buf2, script_getstr(st, arg+3));
- } else { // var Int
- StrBuf->Printf(&final_buf, buf2, script_getnum(st, arg+3));
- }
- } else { // Unsupported type
- ShowError("buildin_sprintf: Unknown argument type!\n");
- aFree(buf);
- if(buf2) aFree(buf2);
- StrBuf->Destroy(&final_buf);
- script_pushconststr(st,"");
- return false;
- }
- arg++;
- }
-
- // Append anything left
- if(*q) {
- StrBuf->AppendStr(&final_buf, q);
- }
+static BUILDIN(sprintf)
+{
+ struct StringBuf buf;
+ StrBuf->Init(&buf);
- // Passed more, than needed
- if(arg<argc) {
- ShowWarning("buildin_sprintf: Unused arguments passed.\n");
- script->reportsrc(st);
+ if (!script->sprintf_helper(st, 2, &buf)) {
+ StrBuf->Destroy(&buf);
+ script_pushconststr(st, "");
+ return false;
}
- script_pushstrcopy(st, StrBuf->Value(&final_buf));
-
- aFree(buf);
- if(buf2) aFree(buf2);
- StrBuf->Destroy(&final_buf);
+ script_pushstrcopy(st, StrBuf->Value(&buf));
+ StrBuf->Destroy(&buf);
return true;
}
@@ -15361,7 +17963,8 @@ BUILDIN(sprintf) {
// sscanf(<str>, <format>, ...);
// Implements C sscanf.
//-------------------------------------------------------
-BUILDIN(sscanf) {
+static BUILDIN(sscanf)
+{
unsigned int argc, arg = 0;
struct script_data* data;
struct map_session_data* sd = NULL;
@@ -15474,7 +18077,8 @@ BUILDIN(sscanf) {
// Implements PHP style strpos. Adapted from code from
// http://www.daniweb.com/code/snippet313.html, Dave Sinkula
//-------------------------------------------------------
-BUILDIN(strpos) {
+static BUILDIN(strpos)
+{
const char *haystack = script_getstr(st,2);
const char *needle = script_getstr(st,3);
int i;
@@ -15518,7 +18122,7 @@ BUILDIN(strpos) {
// instances as specified in <count>. By default will be case
// sensitive.
//---------------------------------------------------------------
-BUILDIN(replacestr)
+static BUILDIN(replacestr)
{
const char *input = script_getstr(st, 2);
const char *find = script_getstr(st, 3);
@@ -15601,7 +18205,7 @@ BUILDIN(replacestr)
// Note: Counts the number of times <search> occurs in
// <input>. By default will be case sensitive.
//--------------------------------------------------------
-BUILDIN(countstr)
+static BUILDIN(countstr)
{
const char *input = script_getstr(st, 2);
const char *find = script_getstr(st, 3);
@@ -15658,7 +18262,8 @@ BUILDIN(countstr)
/// setnpcdisplay("<npc name>", "<new display name>", <new class id>) -> <int>
/// setnpcdisplay("<npc name>", "<new display name>") -> <int>
/// setnpcdisplay("<npc name>", <new class id>) -> <int>
-BUILDIN(setnpcdisplay) {
+static BUILDIN(setnpcdisplay)
+{
const char* name;
const char* newname = NULL;
int class_ = -1, size = -1;
@@ -15704,14 +18309,16 @@ BUILDIN(setnpcdisplay) {
return true;
}
-BUILDIN(atoi) {
+static BUILDIN(atoi)
+{
const char *value;
value = script_getstr(st,2);
script_pushint(st,atoi(value));
return true;
}
-BUILDIN(axtoi) {
+static BUILDIN(axtoi)
+{
const char *hex = script_getstr(st,2);
long value = strtol(hex, NULL, 16);
#if LONG_MAX > INT_MAX || LONG_MIN < INT_MIN
@@ -15721,7 +18328,8 @@ BUILDIN(axtoi) {
return true;
}
-BUILDIN(strtol) {
+static BUILDIN(strtol)
+{
const char *string = script_getstr(st, 2);
int base = script_getnum(st, 3);
long value = strtol(string, NULL, base);
@@ -15733,7 +18341,7 @@ BUILDIN(strtol) {
}
// case-insensitive substring search [lordalfa]
-BUILDIN(compare)
+static BUILDIN(compare)
{
const char *message;
const char *cmpstring;
@@ -15743,7 +18351,7 @@ BUILDIN(compare)
return true;
}
-BUILDIN(strcmp)
+static BUILDIN(strcmp)
{
const char *str1 = script_getstr(st,2);
const char *str2 = script_getstr(st,3);
@@ -15753,7 +18361,7 @@ BUILDIN(strcmp)
// List of mathematics commands --->
-BUILDIN(log10)
+static BUILDIN(log10)
{
double i, a;
i = script_getnum(st,2);
@@ -15762,16 +18370,20 @@ BUILDIN(log10)
return true;
}
-BUILDIN(sqrt) //[zBuffer]
+static BUILDIN(sqrt) //[zBuffer]
{
double i, a;
i = script_getnum(st,2);
+ if (i < 0) {
+ ShowError("sqrt from negative value\n");
+ return false;
+ }
a = sqrt(i);
script_pushint(st,(int)a);
return true;
}
-BUILDIN(pow) //[zBuffer]
+static BUILDIN(pow) //[zBuffer]
{
double i, a, b;
a = script_getnum(st,2);
@@ -15781,7 +18393,7 @@ BUILDIN(pow) //[zBuffer]
return true;
}
-BUILDIN(distance) //[zBuffer]
+static BUILDIN(distance) //[zBuffer]
{
int x0, y0, x1, y1;
@@ -15796,7 +18408,7 @@ BUILDIN(distance) //[zBuffer]
// <--- List of mathematics commands
-BUILDIN(min)
+static BUILDIN(min)
{
int i, min;
@@ -15811,7 +18423,7 @@ BUILDIN(min)
return true;
}
-BUILDIN(max)
+static BUILDIN(max)
{
int i, max;
@@ -15826,22 +18438,34 @@ BUILDIN(max)
return true;
}
-BUILDIN(md5)
+static BUILDIN(cap_value)
+{
+ int value = script_getnum(st, 2);
+ int min = script_getnum(st, 3);
+ int max = script_getnum(st, 4);
+
+ script_pushint(st, (int)cap_value(value, min, max));
+
+ return true;
+}
+
+static BUILDIN(md5)
{
const char *tmpstr;
char *md5str;
tmpstr = script_getstr(st,2);
md5str = (char *)aMalloc((32+1)*sizeof(char));
- MD5_String(tmpstr, md5str);
+ md5->string(tmpstr, md5str);
script_pushstr(st, md5str);
return true;
}
-BUILDIN(swap)
+static BUILDIN(swap)
{
struct map_session_data *sd = NULL;
struct script_data *data1, *data2;
+ struct reg_db *ref1, *ref2;
const char *varname1, *varname2;
int64 uid1, uid2;
@@ -15882,6 +18506,8 @@ BUILDIN(swap)
uid1 = reference_getuid(data1);
uid2 = reference_getuid(data2);
+ ref1 = reference_getref(data1);
+ ref2 = reference_getref(data2);
if (is_string_variable(varname1)) {
const char *value1, *value2;
@@ -15890,8 +18516,8 @@ BUILDIN(swap)
value2 = script_getstr(st,3);
if (strcmpi(value1, value2)) {
- script->set_reg(st, sd, uid1, varname1, value2, script_getref(st,3));
- script->set_reg(st, sd, uid2, varname2, value1, script_getref(st,2));
+ script->set_reg(st, sd, uid1, varname1, value2, ref1);
+ script->set_reg(st, sd, uid2, varname2, value1, ref2);
}
}
else {
@@ -15901,8 +18527,8 @@ BUILDIN(swap)
value2 = script_getnum(st,3);
if (value1 != value2) {
- script->set_reg(st, sd, uid1, varname1, (const void *)h64BPTRSIZE(value2), script_getref(st,3));
- script->set_reg(st, sd, uid2, varname2, (const void *)h64BPTRSIZE(value1), script_getref(st,2));
+ script->set_reg(st, sd, uid1, varname1, (const void *)h64BPTRSIZE(value2), ref1);
+ script->set_reg(st, sd, uid2, varname2, (const void *)h64BPTRSIZE(value1), ref2);
}
}
return true;
@@ -15910,7 +18536,7 @@ BUILDIN(swap)
// [zBuffer] List of dynamic var commands --->
-BUILDIN(setd)
+static BUILDIN(setd)
{
struct map_session_data *sd = NULL;
char varname[100];
@@ -15940,7 +18566,7 @@ BUILDIN(setd)
return true;
}
-int buildin_query_sql_sub(struct script_state *st, struct Sql *handle)
+static int buildin_query_sql_sub(struct script_state *st, struct Sql *handle)
{
int i, j;
struct map_session_data *sd = NULL;
@@ -16022,11 +18648,13 @@ int buildin_query_sql_sub(struct script_state *st, struct Sql *handle)
return true;
}
-BUILDIN(query_sql) {
+static BUILDIN(query_sql)
+{
return script->buildin_query_sql_sub(st, map->mysql_handle);
}
-BUILDIN(query_logsql) {
+static BUILDIN(query_logsql)
+{
if( !logs->config.sql_logs ) {// logs->mysql_handle == NULL
ShowWarning("buildin_query_logsql: SQL logs are disabled, query '%s' will not be executed.\n", script_getstr(st,2));
script_pushint(st,-1);
@@ -16036,7 +18664,7 @@ BUILDIN(query_logsql) {
}
//Allows escaping of a given string.
-BUILDIN(escape_sql)
+static BUILDIN(escape_sql)
{
const char *str;
char *esc_str;
@@ -16050,25 +18678,37 @@ BUILDIN(escape_sql)
return true;
}
-BUILDIN(getd) {
+static BUILDIN(getd)
+{
char varname[100];
const char *buffer;
int elem;
+ int id;
buffer = script_getstr(st, 2);
if (sscanf(buffer, "%99[^[][%d]", varname, &elem) < 2)
elem = 0;
+ id = script->add_variable(varname);
+
+ if (script->str_data[id].type != C_NAME && // variable
+ script->str_data[id].type != C_PARAM && // param
+ script->str_data[id].type != C_INT) { // constant
+ ShowError("script:getd: `%s` is already used by something that is not a variable.\n", varname);
+ st->state = END;
+ return false;
+ }
+
// Push the 'pointer' so it's more flexible [Lance]
- script->push_val(st->stack, C_NAME, reference_uid(script->add_str(varname), elem),NULL);
+ script->push_val(st->stack, C_NAME, reference_uid(id, elem),NULL);
return true;
}
// <--- [zBuffer] List of dynamic var commands
// Pet stat [Lance]
-BUILDIN(petstat)
+static BUILDIN(petstat)
{
struct pet_data *pd;
int flag = script_getnum(st,2);
@@ -16094,7 +18734,7 @@ BUILDIN(petstat)
return true;
}
-BUILDIN(callshop)
+static BUILDIN(callshop)
{
struct npc_data *nd;
const char *shopname;
@@ -16134,7 +18774,7 @@ BUILDIN(callshop)
return true;
}
-BUILDIN(npcshopitem)
+static BUILDIN(npcshopitem)
{
const char* npcname = script_getstr(st, 2);
struct npc_data* nd = npc->name2id(npcname);
@@ -16163,7 +18803,7 @@ BUILDIN(npcshopitem)
return true;
}
-BUILDIN(npcshopadditem)
+static BUILDIN(npcshopadditem)
{
const char* npcname = script_getstr(st,2);
struct npc_data* nd = npc->name2id(npcname);
@@ -16192,7 +18832,7 @@ BUILDIN(npcshopadditem)
return true;
}
-BUILDIN(npcshopdelitem)
+static BUILDIN(npcshopdelitem)
{
const char* npcname = script_getstr(st,2);
struct npc_data* nd = npc->name2id(npcname);
@@ -16214,10 +18854,12 @@ BUILDIN(npcshopdelitem)
unsigned int nameid = script_getnum(st,i);
ARR_FIND(0, size, n, nd->u.shop.shop_item[n].nameid == nameid);
- if (n < size) {
- memmove(&nd->u.shop.shop_item[n], &nd->u.shop.shop_item[n+1], sizeof(nd->u.shop.shop_item[0])*(size-n));
- size--;
+ if (n == size) {
+ continue;
+ } else if (n < size - 1) {
+ memmove(&nd->u.shop.shop_item[n], &nd->u.shop.shop_item[n+1], sizeof(nd->u.shop.shop_item[0]) * (size - n - 1));
}
+ size--;
}
RECREATE(nd->u.shop.shop_item, struct npc_item_list, size);
@@ -16228,7 +18870,8 @@ BUILDIN(npcshopdelitem)
}
//Sets a script to attach to a shop npc.
-BUILDIN(npcshopattach) {
+static BUILDIN(npcshopattach)
+{
const char* npcname = script_getstr(st,2);
struct npc_data* nd = npc->name2id(npcname);
int flag = 1;
@@ -16260,7 +18903,7 @@ BUILDIN(npcshopattach) {
* 1 - Equip script
* 2 - Unequip script
*------------------------------------------*/
-BUILDIN(setitemscript)
+static BUILDIN(setitemscript)
{
int item_id,n=0;
const char *new_bonus_script;
@@ -16306,7 +18949,8 @@ BUILDIN(setitemscript)
* is updated to the new rate. Rate must be in the range [1:10000]
* Returns 1 if succeeded (added/updated a mob drop)
*-------------------------------------------------------*/
-BUILDIN(addmonsterdrop) {
+static BUILDIN(addmonsterdrop)
+{
struct mob_db *monster;
int item_id, rate, i, c = MAX_MOB_DROP;
@@ -16366,7 +19010,8 @@ BUILDIN(addmonsterdrop) {
*
* Returns 1 if succeeded (deleted a mob drop)
*-------------------------------------------------------*/
-BUILDIN(delmonsterdrop) {
+static BUILDIN(delmonsterdrop)
+{
struct mob_db *monster;
int item_id, i;
@@ -16408,7 +19053,7 @@ BUILDIN(delmonsterdrop) {
* Name, Level, race, size, etc...
* getmonsterinfo(monsterID,queryIndex);
*------------------------------------------*/
-BUILDIN(getmonsterinfo)
+static BUILDIN(getmonsterinfo)
{
struct mob_db *monster;
int mob_id;
@@ -16447,12 +19092,13 @@ BUILDIN(getmonsterinfo)
case 20: script_pushint(st,monster->status.def_ele); break;
case 21: script_pushint(st,monster->status.mode); break;
case 22: script_pushint(st,monster->mexp); break;
+ case 23: script_pushint(st, monster->dmg_taken_rate); break;
default: script_pushint(st,-1); //wrong Index
}
return true;
}
-BUILDIN(checkvending) // check vending [Nab4]
+static BUILDIN(checkvending) // check vending [Nab4]
{
struct map_session_data *sd = NULL;
@@ -16470,7 +19116,8 @@ BUILDIN(checkvending) // check vending [Nab4]
}
// check chatting [Marka]
-BUILDIN(checkchatting) {
+static BUILDIN(checkchatting)
+{
struct map_session_data *sd = NULL;
if (script_hasdata(st,2))
@@ -16479,14 +19126,15 @@ BUILDIN(checkchatting) {
sd = script->rid2sd(st);
if (sd != NULL)
- script_pushint(st,(sd->chatID != 0));
+ script_pushint(st, (sd->chat_id != 0));
else
script_pushint(st,0);
return true;
}
-BUILDIN(checkidle) {
+static BUILDIN(checkidle)
+{
struct map_session_data *sd = NULL;
if (script_hasdata(st, 2))
@@ -16502,7 +19150,7 @@ BUILDIN(checkidle) {
return true;
}
-BUILDIN(searchitem)
+static BUILDIN(searchitem)
{
struct script_data* data = script_getdata(st, 2);
const char *itemname = script_getstr(st,3);
@@ -16518,7 +19166,7 @@ BUILDIN(searchitem)
if ((items[0] = itemdb->exists(atoi(itemname)))) {
count = 1;
} else {
- count = itemdb->search_name_array(items, ARRAYLENGTH(items), itemname, 0);
+ count = itemdb->search_name_array(items, ARRAYLENGTH(items), itemname, IT_SEARCH_NAME_PARTIAL);
if (count > MAX_SEARCH) count = MAX_SEARCH;
}
@@ -16565,7 +19213,7 @@ BUILDIN(searchitem)
}
// [zBuffer] List of player cont commands --->
-BUILDIN(rid2name)
+static BUILDIN(rid2name)
{
struct block_list *bl = NULL;
int rid = script_getnum(st,2);
@@ -16589,7 +19237,8 @@ BUILDIN(rid2name)
return true;
}
-BUILDIN(pcblockmove) {
+static BUILDIN(pcblockmove)
+{
int id, flag;
struct map_session_data *sd = NULL;
@@ -16601,13 +19250,101 @@ BUILDIN(pcblockmove) {
else
sd = script->rid2sd(st);
- if (sd != NULL)
- sd->state.blockedmove = flag > 0;
+ if (!sd)
+ return true;
+
+ if (flag)
+ sd->block_action.move = 1;
+ else
+ sd->block_action.move = 0;
+
+ return true;
+}
+
+static BUILDIN(setpcblock)
+{
+ struct map_session_data *sd = script_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) {
+ script_pushint(st, 0);
+ return true;
+ }
+
+ if ((type & PCBLOCK_MOVE) != 0)
+ sd->block_action.move = state;
+
+ if ((type & PCBLOCK_ATTACK) != 0)
+ sd->block_action.attack = state;
+
+ if ((type & PCBLOCK_SKILL) != 0)
+ sd->block_action.skill = state;
+ if ((type & PCBLOCK_USEITEM) != 0)
+ sd->block_action.useitem = state;
+
+ if ((type & PCBLOCK_CHAT) != 0)
+ sd->block_action.chat = state;
+
+ if ((type & PCBLOCK_IMMUNE) != 0)
+ sd->block_action.immune = state;
+
+ if ((type & PCBLOCK_SITSTAND) != 0)
+ sd->block_action.sitstand = state;
+
+ if ((type & PCBLOCK_COMMANDS) != 0)
+ sd->block_action.commands = state;
+
+ if ((type & PCBLOCK_NPC) != 0)
+ sd->block_action.npc = state;
+
+ script_pushint(st, 1);
return true;
}
-BUILDIN(pcfollow)
+static BUILDIN(checkpcblock)
+{
+ 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) {
+ script_pushint(st, PCBLOCK_NONE);
+ return true;
+ }
+
+ if (sd->block_action.move != 0)
+ retval |= PCBLOCK_MOVE;
+
+ if (sd->block_action.attack != 0)
+ retval |= PCBLOCK_ATTACK;
+
+ if (sd->block_action.skill != 0)
+ retval |= PCBLOCK_SKILL;
+
+ if (sd->block_action.useitem != 0)
+ retval |= PCBLOCK_USEITEM;
+
+ if (sd->block_action.chat != 0)
+ retval |= PCBLOCK_CHAT;
+
+ if (sd->block_action.immune != 0)
+ retval |= PCBLOCK_IMMUNE;
+
+ if (sd->block_action.sitstand != 0)
+ retval |= PCBLOCK_SITSTAND;
+
+ if (sd->block_action.commands != 0)
+ retval |= PCBLOCK_COMMANDS;
+
+ if (sd->block_action.npc != 0)
+ retval |= PCBLOCK_NPC;
+
+ script_pushint(st, retval);
+ return true;
+}
+
+static BUILDIN(pcfollow)
{
int id, targetid;
struct map_session_data *sd = NULL;
@@ -16626,7 +19363,7 @@ BUILDIN(pcfollow)
return true;
}
-BUILDIN(pcstopfollow)
+static BUILDIN(pcstopfollow)
{
int id;
struct map_session_data *sd = NULL;
@@ -16647,7 +19384,8 @@ BUILDIN(pcstopfollow)
// [zBuffer] List of mob control commands --->
//## TODO always return if the request/whatever was successfull [FlavioJS]
-BUILDIN(getunittype) {
+static BUILDIN(getunittype)
+{
struct block_list* bl;
int value;
@@ -16674,39 +19412,1852 @@ BUILDIN(getunittype) {
return true;
}
+/**
+ * Sets real-time unit data for a game object.
+ *
+ * @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.
+ *
+ **/
+static BUILDIN(setunitdata)
+{
+ 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));
+ script_pushint(st, 0);
+ return false;
+ }
+
+ int type = script_getnum(st, 3);
+
+ // Type bounds.
+ if (type < UDT_SIZE || type >= UDT_MAX) { // Note: UDT_TYPE is not valid here
+ ShowError("buildin_setunitdata: Invalid unit data type %d provided.\n", type);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ 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)) {
+ ShowError("buildin_setunitdata: Invalid data type for argument #3.\n");
+ script_pushint(st, 0);
+ return false;
+ }
+
+ val = script_getnum(st, 4);
+ }
+
+/****************************************************************************************************
+ * 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)); \
+ script_pushint(st, 0); \
+ return false; \
+ } \
+ } while(0);
+
+// 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)); \
+ script_pushint(st, 0); \
+ return false; \
+ } \
+ } while(0);
+
+// Checks if the argument doesn't exist, if required. Also checks if the argument exists, if not required.
+#define setunitdata_assert_arg(arg, required) \
+ do { \
+ if (required && !script_hasdata(st, (arg))) { \
+ ShowError("buildin_setunitdata: Type %d reqires argument #%d.\n", type, (arg) - 1); \
+ script_pushint(st, 0); \
+ return false; \
+ } else if (!required && script_hasdata(st, arg)) { \
+ ShowError("buildin_setunitdata: Argument %d is not required for type %d.\n", (arg) - 1, type); \
+ script_pushint(st, 0); \
+ return false; \
+ } \
+ } while (0);
+
+// Checks if the data is an integer.
+#define setunitdata_check_int(arg) \
+ do { \
+ setunitdata_assert_arg((arg), true); \
+ if (script_isstringtype(st, (arg))) { \
+ ShowError("buildin_setunitdata: Argument #%d expects integer, string given.\n", (arg) - 1); \
+ script_pushint(st, 0); \
+ return false; \
+ } \
+ } while(0);
+
+// Checks if the data is a string.
+#define setunitdata_check_string(arg) \
+ do { \
+ setunitdata_assert_arg((arg), true); \
+ if (script_isinttype(st, (arg))) { \
+ ShowError("buildin_setunitdata: Argument #%d expects string, integer given.\n", (arg) - 1); \
+ script_pushint(st, 0); \
+ return false; \
+ } \
+ } while(0);
+
+/****************************************************************************************************
+ * Define temporary macros. [END]
+ ****************************************************************************************************/
+
+ if (type != UDT_MAPIDXY && type != UDT_WALKTOXY) {
+ setunitdata_assert_arg(5, false);
+ setunitdata_assert_arg(6, false);
+ }
+
+ 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;
+ case UDT_LEVEL:
+ case UDT_HP:
+ case UDT_MAXHP:
+ case UDT_SP:
+ case UDT_MAXSP:
+ case UDT_CLASS:
+ case UDT_HEADBOTTOM:
+ case UDT_HEADMIDDLE:
+ case UDT_HEADTOP:
+ case UDT_CLOTHCOLOR:
+ case UDT_SHIELD:
+ case UDT_WEAPON:
+ case UDT_INTIMACY:
+ case UDT_LIFETIME:
+ case UDT_MERC_KILLCOUNT:
+ case UDT_ROBE:
+ case UDT_BODY2:
+ setunitdata_check_min(4, 0);
+ break;
+ case UDT_MASTERAID:
+ setunitdata_check_min(4, 0);
+ tsd = map->id2sd(val);
+
+ if (tsd == NULL) {
+ ShowWarning("buildin_setunitdata: Account ID %d not found for master change!\n", val);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ break;
+ case UDT_MASTERCID:
+ setunitdata_check_min(4, 0);
+ tsd = map->charid2sd(val);
+
+ if (tsd == NULL) {
+ ShowWarning("buildin_setunitdata: Character ID %d not found for master change!\n", val);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ break;
+ case UDT_MAPIDXY:
+ if ((val = map->mapname2mapid(mapname)) == 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);
+ val2 = script_getnum(st, 5);
+ val3 = script_getnum(st, 6);
+ break;
+ case UDT_WALKTOXY:
+ setunitdata_assert_arg(6, false);
+ setunitdata_check_int(5);
+ val2 = script_getnum(st, 5);
+ setunitdata_check_bounds(4, 0, MAX_MAP_SIZE / 2);
+ setunitdata_check_bounds(5, 0, MAX_MAP_SIZE / 2);
+ break;
+ case UDT_SPEED:
+ setunitdata_check_bounds(4, 0, MAX_WALK_SPEED);
+ break;
+ case UDT_MODE:
+ setunitdata_check_bounds(4, MD_NONE, MD_MASK);
+ break;
+ case UDT_AI:
+ setunitdata_check_bounds(4, AI_NONE, AI_MAX-1);
+ break;
+ case UDT_SCOPTION:
+ setunitdata_check_bounds(4, OPTION_NOTHING, OPTION_COSTUME);
+ break;
+ case UDT_SEX:
+ setunitdata_check_bounds(4, SEX_FEMALE, SEX_MALE);
+ break;
+ case UDT_HAIRSTYLE:
+ setunitdata_check_bounds(4, 0, battle->bc->max_hair_style);
+ break;
+ case UDT_HAIRCOLOR:
+ setunitdata_check_bounds(4, 0, battle->bc->max_hair_color);
+ break;
+ case UDT_LOOKDIR:
+ setunitdata_check_bounds(4, 0, 7);
+ break;
+ case UDT_CANMOVETICK:
+ setunitdata_check_min(4, 0);
+ break;
+ case UDT_STR:
+ case UDT_AGI:
+ case UDT_VIT:
+ case UDT_INT:
+ case UDT_DEX:
+ case UDT_LUK:
+ case UDT_STATPOINT:
+ case UDT_ATKRANGE:
+ case UDT_ATKMIN:
+ case UDT_ATKMAX:
+ case UDT_MATKMIN:
+ case UDT_MATKMAX:
+ case UDT_AMOTION:
+ case UDT_ADELAY:
+ case UDT_DMOTION:
+ setunitdata_check_bounds(4, 0, USHRT_MAX);
+ break;
+ case UDT_DEF:
+ case UDT_MDEF:
+ case UDT_HIT:
+ case UDT_FLEE:
+ case UDT_PDODGE:
+ case UDT_CRIT:
+ setunitdata_check_bounds(4, 0, SHRT_MAX);
+ break;
+ case UDT_HUNGER:
+ setunitdata_check_bounds(4, PET_HUNGER_STARVING, PET_HUNGER_STUFFED); // Pets and Homunculi have the same hunger value bounds.
+ break;
+ case UDT_RACE:
+ case UDT_ELETYPE:
+ case UDT_ELELEVEL:
+ 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;
+ default:
+ 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
+
+/****************************************************************************************************
+ * Undefine temporary macros. [END]
+ ****************************************************************************************************/
+
+ // Set the values.
+ switch (bl->type) {
+ case BL_MOB: {
+ struct mob_data *md = BL_UCAST(BL_MOB, bl);
+
+ 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;
+ break;
+ case UDT_LEVEL:
+ md->level = val;
+
+ 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);
+ clif->blname_ack(0, &md->bl);
+ break;
+ case UDT_MAXHP:
+ 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);
+ break;
+ case UDT_MAXSP:
+ md->status.max_sp = (unsigned int)val;
+ break;
+ case UDT_MASTERAID:
+ md->master_id = val;
+ break;
+ case UDT_MAPIDXY:
+ unit->warp(bl, (short)val, (short)val2, (short)val3, CLR_TELEPORT);
+ break;
+ case UDT_WALKTOXY:
+ if (unit->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;
+ status->calc_misc(bl, &md->status, md->level);
+ break;
+ case UDT_MODE:
+ md->status.mode = (enum e_mode)val;
+ break;
+ case UDT_AI:
+ md->special_state.ai = (enum ai)val;
+ break;
+ case UDT_SCOPTION:
+ md->sc.option = (unsigned int)val;
+ break;
+ case UDT_SEX:
+ md->vd->sex = (char)val;
+ break;
+ case UDT_CLASS:
+ mob->class_change(md, val);
+ break;
+ case UDT_HAIRSTYLE:
+ clif->changelook(bl, LOOK_HAIR, val);
+ break;
+ case UDT_HAIRCOLOR:
+ clif->changelook(bl, LOOK_HAIR_COLOR, val);
+ break;
+ case UDT_HEADBOTTOM:
+ clif->changelook(bl, LOOK_HEAD_BOTTOM, val);
+ break;
+ case UDT_HEADMIDDLE:
+ clif->changelook(bl, LOOK_HEAD_MID, val);
+ break;
+ case UDT_HEADTOP:
+ clif->changelook(bl, LOOK_HEAD_TOP, val);
+ break;
+ case UDT_CLOTHCOLOR:
+ clif->changelook(bl, LOOK_CLOTHES_COLOR, val);
+ break;
+ case UDT_SHIELD:
+ clif->changelook(bl, LOOK_SHIELD, val);
+ break;
+ case UDT_WEAPON:
+ clif->changelook(bl, LOOK_WEAPON, val);
+ break;
+ case UDT_LOOKDIR:
+ unit->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;
+ status->calc_misc(bl, &md->status, md->level);
+ break;
+ case UDT_AGI:
+ md->status.agi = (unsigned short)val;
+ status->calc_misc(bl, &md->status, md->level);
+ break;
+ case UDT_VIT:
+ md->status.vit = (unsigned short)val;
+ status->calc_misc(bl, &md->status, md->level);
+ break;
+ case UDT_INT:
+ md->status.int_ = (unsigned short)val;
+ status->calc_misc(bl, &md->status, md->level);
+ break;
+ case UDT_DEX:
+ md->status.dex = (unsigned short)val;
+ status->calc_misc(bl, &md->status, md->level);
+ break;
+ case UDT_LUK:
+ md->status.luk = (unsigned short)val;
+ status->calc_misc(bl, &md->status, md->level);
+ break;
+ case UDT_ATKRANGE:
+ md->status.rhw.range = (unsigned short)val;
+ break;
+ case UDT_ATKMIN:
+ md->status.rhw.atk = (unsigned short)val;
+ break;
+ case UDT_ATKMAX:
+ md->status.rhw.atk2 = (unsigned short)val;
+ break;
+ case UDT_MATKMIN:
+ md->status.matk_min = (unsigned short)val;
+ break;
+ case UDT_MATKMAX:
+ md->status.matk_max = (unsigned short)val;
+ break;
+ case UDT_DEF:
+ md->status.def = (defType)val;
+ break;
+ case UDT_MDEF:
+ md->status.mdef = (defType)val;
+ break;
+ case UDT_HIT:
+ md->status.hit = (short)val;
+ break;
+ case UDT_FLEE:
+ md->status.flee = (short)val;
+ break;
+ case UDT_PDODGE:
+ md->status.flee2 = (short)val;
+ break;
+ case UDT_CRIT:
+ md->status.cri = (short)val;
+ break;
+ case UDT_RACE:
+ md->status.race = (unsigned char)val;
+ break;
+ case UDT_ELETYPE:
+ md->status.def_ele = (unsigned char)val;
+ break;
+ case UDT_ELELEVEL:
+ md->status.ele_lv = (unsigned char)val;
+ break;
+ case UDT_AMOTION:
+ md->status.amotion = (unsigned short)val;
+ break;
+ case UDT_ADELAY:
+ md->status.adelay = (unsigned short)val;
+ break;
+ case UDT_DMOTION:
+ md->status.dmotion = (unsigned short)val;
+ break;
+ case UDT_DAMAGE_TAKEN_RATE:
+ md->dmg_taken_rate = (int)val;
+ break;
+ default:
+ ShowWarning("buildin_setunitdata: Invalid data type '%d' for mob unit.\n", type);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ break;
+ }
+ case BL_HOM: {
+ struct homun_data *hd = BL_UCAST(BL_HOM, bl);
+
+ 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) {
+ case UDT_SIZE:
+ hd->base_status.size = (unsigned char)val;
+ break;
+ case UDT_LEVEL:
+ hd->homunculus.level = (short)val;
+ break;
+ case UDT_HP:
+ status->set_hp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
+ break;
+ case UDT_MAXHP:
+ hd->homunculus.max_hp = val;
+ break;
+ case UDT_SP:
+ status->set_sp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
+ break;
+ case UDT_MAXSP:
+ hd->homunculus.max_sp = val;
+ break;
+ case UDT_MASTERCID:
+ hd->homunculus.char_id = val;
+ hd->master = tsd;
+ break;
+ case UDT_MAPIDXY:
+ unit->warp(bl, (short)val, (short)val2, (short)val3, CLR_TELEPORT);
+ break;
+ case UDT_WALKTOXY:
+ if (unit->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;
+ status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
+ break;
+ case UDT_LOOKDIR:
+ 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;
+ status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
+ break;
+ case UDT_AGI:
+ hd->base_status.agi = (unsigned short)val;
+ status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
+ break;
+ case UDT_VIT:
+ hd->base_status.vit = (unsigned short)val;
+ status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
+ break;
+ case UDT_INT:
+ hd->base_status.int_ = (unsigned short)val;
+ status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
+ break;
+ case UDT_DEX:
+ hd->base_status.dex = (unsigned short)val;
+ status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
+ break;
+ case UDT_LUK:
+ hd->base_status.luk = (unsigned short)val;
+ status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
+ break;
+ case UDT_ATKRANGE:
+ hd->base_status.rhw.range = (unsigned short)val;
+ break;
+ case UDT_ATKMIN:
+ hd->base_status.rhw.atk = (unsigned short)val;
+ break;
+ case UDT_ATKMAX:
+ hd->base_status.rhw.atk2 = (unsigned short)val;
+ break;
+ case UDT_MATKMIN:
+ hd->base_status.matk_min = (unsigned short)val;
+ break;
+ case UDT_MATKMAX:
+ hd->base_status.matk_max = (unsigned short)val;
+ break;
+ case UDT_DEF:
+ hd->base_status.def = (defType)val;
+ break;
+ case UDT_MDEF:
+ hd->base_status.mdef = (defType)val;
+ break;
+ case UDT_HIT:
+ hd->base_status.hit = (short)val;
+ break;
+ case UDT_FLEE:
+ hd->base_status.flee = (short)val;
+ break;
+ case UDT_PDODGE:
+ hd->base_status.flee2 = (short)val;
+ break;
+ case UDT_CRIT:
+ hd->base_status.cri = (short)val;
+ break;
+ case UDT_RACE:
+ hd->base_status.race = (unsigned char)val;
+ break;
+ case UDT_ELETYPE:
+ hd->base_status.def_ele = (unsigned char)val;
+ break;
+ case UDT_ELELEVEL:
+ hd->base_status.ele_lv = (unsigned char)val;
+ break;
+ case UDT_AMOTION:
+ hd->base_status.amotion = (unsigned short)val;
+ break;
+ case UDT_ADELAY:
+ hd->base_status.adelay = (unsigned short)val;
+ break;
+ case UDT_DMOTION:
+ hd->base_status.dmotion = (unsigned short)val;
+ break;
+ case UDT_HUNGER:
+ hd->homunculus.hunger = (short)val;
+ clif->send_homdata(hd->master, SP_HUNGRY, hd->homunculus.hunger);
+ break;
+ case UDT_INTIMACY:
+ homun->add_intimacy(hd, (unsigned int)val);
+ clif->send_homdata(hd->master, SP_INTIMATE, hd->homunculus.intimacy / 100);
+ break;
+ default:
+ ShowWarning("buildin_setunitdata: Invalid data type '%d' for homunculus unit.\n", type);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ clif->send_homdata(hd->master, SP_ACK, 0); // Send Homunculus data.
+ break;
+ }
+ case BL_PET: {
+ struct pet_data *pd = BL_UCAST(BL_PET, bl);
+
+ 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) {
+ case UDT_SIZE:
+ pd->status.size = (unsigned char)val;
+ break;
+ case UDT_LEVEL:
+ pd->pet.level = (short)val;
+ break;
+ case UDT_HP:
+ status->set_hp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
+ break;
+ case UDT_MAXHP:
+ pd->status.max_hp = (unsigned int)val;
+ break;
+ case UDT_SP:
+ status->set_sp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
+ break;
+ case UDT_MAXSP:
+ pd->status.max_sp = (unsigned int)val;
+ break;
+ case UDT_MASTERAID:
+ pd->pet.account_id = val;
+ pd->msd = tsd;
+ break;
+ case UDT_MAPIDXY:
+ unit->warp(bl, (short)val, (short)val2, (short)val3, CLR_TELEPORT);
+ break;
+ case UDT_WALKTOXY:
+ if (unit->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;
+ status->calc_misc(bl, &pd->status, pd->pet.level);
+ break;
+ case UDT_LOOKDIR:
+ 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;
+ status->calc_misc(bl, &pd->status, pd->pet.level);
+ break;
+ case UDT_AGI:
+ pd->status.agi = (unsigned short)val;
+ status->calc_misc(bl, &pd->status, pd->pet.level);
+ break;
+ case UDT_VIT:
+ pd->status.vit = (unsigned short)val;
+ status->calc_misc(bl, &pd->status, pd->pet.level);
+ break;
+ case UDT_INT:
+ pd->status.int_ = (unsigned short)val;
+ status->calc_misc(bl, &pd->status, pd->pet.level);
+ break;
+ case UDT_DEX:
+ pd->status.dex = (unsigned short)val;
+ status->calc_misc(bl, &pd->status, pd->pet.level);
+ break;
+ case UDT_LUK:
+ pd->status.luk = (unsigned short)val;
+ status->calc_misc(bl, &pd->status, pd->pet.level);
+ break;
+ case UDT_ATKRANGE:
+ pd->status.rhw.range = (unsigned short)val;
+ break;
+ case UDT_ATKMIN:
+ pd->status.rhw.atk = (unsigned short)val;
+ break;
+ case UDT_ATKMAX:
+ pd->status.rhw.atk2 = (unsigned short)val;
+ break;
+ case UDT_MATKMIN:
+ pd->status.matk_min = (unsigned short)val;
+ break;
+ case UDT_MATKMAX:
+ pd->status.matk_max = (unsigned short)val;
+ break;
+ case UDT_DEF:
+ pd->status.def = (defType)val;
+ break;
+ case UDT_MDEF:
+ pd->status.mdef = (defType)val;
+ break;
+ case UDT_HIT:
+ pd->status.hit = (short)val;
+ break;
+ case UDT_FLEE:
+ pd->status.flee = (short)val;
+ break;
+ case UDT_PDODGE:
+ pd->status.flee2 = (short)val;
+ break;
+ case UDT_CRIT:
+ pd->status.cri = (short)val;
+ break;
+ case UDT_RACE:
+ pd->status.race = (unsigned char)val;
+ break;
+ case UDT_ELETYPE:
+ pd->status.def_ele = (unsigned char)val;
+ break;
+ case UDT_ELELEVEL:
+ pd->status.ele_lv = (unsigned char)val;
+ break;
+ case UDT_AMOTION:
+ pd->status.amotion = (unsigned short)val;
+ break;
+ case UDT_ADELAY:
+ pd->status.adelay = (unsigned short)val;
+ break;
+ case UDT_DMOTION:
+ pd->status.dmotion = (unsigned short)val;
+ break;
+ case UDT_INTIMACY:
+ pet->set_intimate(pd, val);
+ clif->send_petdata(pd->msd, pd, 1, pd->pet.intimate);
+ break;
+ case UDT_HUNGER:
+ pet->set_hunger(pd, val);
+ break;
+ default:
+ 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: {
+ struct mercenary_data *mc = BL_UCAST(BL_MER, bl);
+
+ 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) {
+ case UDT_SIZE:
+ mc->base_status.size = (unsigned char)val;
+ break;
+ case UDT_HP:
+ status->set_hp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
+ break;
+ case UDT_MAXHP:
+ mc->base_status.max_hp = (unsigned int)val;
+ break;
+ case UDT_SP:
+ status->set_sp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
+ break;
+ case UDT_MAXSP:
+ mc->base_status.max_sp = (unsigned int)val;
+ break;
+ case UDT_MASTERCID:
+ mc->mercenary.char_id = val;
+ break;
+ case UDT_MAPIDXY:
+ unit->warp(bl, (short)val, (short)val2, (short)val3, CLR_TELEPORT);
+ break;
+ case UDT_WALKTOXY:
+ if (unit->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;
+ status->calc_misc(bl, &mc->base_status, mc->db->lv);
+ break;
+ case UDT_LOOKDIR:
+ 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;
+ status->calc_misc(bl, &mc->base_status, mc->db->lv);
+ break;
+ case UDT_AGI:
+ mc->base_status.agi = (unsigned short)val;
+ status->calc_misc(bl, &mc->base_status, mc->db->lv);
+ break;
+ case UDT_VIT:
+ mc->base_status.vit = (unsigned short)val;
+ status->calc_misc(bl, &mc->base_status, mc->db->lv);
+ break;
+ case UDT_INT:
+ mc->base_status.int_ = (unsigned short)val;
+ status->calc_misc(bl, &mc->base_status, mc->db->lv);
+ break;
+ case UDT_DEX:
+ mc->base_status.dex = (unsigned short)val;
+ status->calc_misc(bl, &mc->base_status, mc->db->lv);
+ break;
+ case UDT_LUK:
+ mc->base_status.luk = (unsigned short)val;
+ status->calc_misc(bl, &mc->base_status, mc->db->lv);
+ break;
+ case UDT_ATKRANGE:
+ mc->base_status.rhw.range = (unsigned short)val;
+ break;
+ case UDT_ATKMIN:
+ mc->base_status.rhw.atk = (unsigned short)val;
+ break;
+ case UDT_ATKMAX:
+ mc->base_status.rhw.atk2 = (unsigned short)val;
+ break;
+ case UDT_MATKMIN:
+ mc->base_status.matk_min = (unsigned short)val;
+ break;
+ case UDT_MATKMAX:
+ mc->base_status.matk_max = (unsigned short)val;
+ break;
+ case UDT_DEF:
+ mc->base_status.def = (defType)val;
+ break;
+ case UDT_MDEF:
+ mc->base_status.mdef = (defType)val;
+ break;
+ case UDT_HIT:
+ mc->base_status.hit = (short)val;
+ break;
+ case UDT_FLEE:
+ mc->base_status.flee = (short)val;
+ break;
+ case UDT_PDODGE:
+ mc->base_status.flee2 = (short)val;
+ break;
+ case UDT_CRIT:
+ mc->base_status.cri = (short)val;
+ break;
+ case UDT_RACE:
+ mc->base_status.race = (unsigned char)val;
+ break;
+ case UDT_ELETYPE:
+ mc->base_status.def_ele = (unsigned char)val;
+ break;
+ case UDT_ELELEVEL:
+ mc->base_status.ele_lv = (unsigned char)val;
+ break;
+ case UDT_AMOTION:
+ mc->base_status.amotion = (unsigned short)val;
+ break;
+ case UDT_ADELAY:
+ mc->base_status.adelay = (unsigned short)val;
+ break;
+ case UDT_DMOTION:
+ mc->base_status.dmotion = (unsigned short)val;
+ break;
+ case UDT_MERC_KILLCOUNT:
+ mc->mercenary.kill_count = (unsigned int)val;
+ break;
+ case UDT_LIFETIME:
+ mc->mercenary.life_time = (unsigned int)val;
+ break;
+ default:
+ ShowWarning("buildin_setunitdata: Invalid data type '%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: {
+ struct elemental_data *ed = BL_UCAST(BL_ELEM, bl);
+
+ 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) {
+ case UDT_SIZE:
+ ed->base_status.size = (unsigned char)val;
+ break;
+ case UDT_HP:
+ status->set_hp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
+ break;
+ case UDT_MAXHP:
+ ed->base_status.max_hp = (unsigned int)val;
+ break;
+ case UDT_SP:
+ status->set_sp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
+ break;
+ case UDT_MAXSP:
+ ed->base_status.max_sp = (unsigned int)val;
+ break;
+ case UDT_MASTERCID:
+ ed->elemental.char_id = val;
+ break;
+ case UDT_MAPIDXY:
+ unit->warp(bl, (short)val, (short)val2, (short)val3, CLR_TELEPORT);
+ break;
+ case UDT_WALKTOXY:
+ if (unit->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;
+ status->calc_misc(bl, &ed->base_status, ed->db->lv);
+ break;
+ case UDT_LOOKDIR:
+ 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;
+ status->calc_misc(bl, &ed->base_status, ed->db->lv);
+ break;
+ case UDT_AGI:
+ ed->base_status.agi = (unsigned short)val;
+ status->calc_misc(bl, &ed->base_status, ed->db->lv);
+ break;
+ case UDT_VIT:
+ ed->base_status.vit = (unsigned short)val;
+ status->calc_misc(bl, &ed->base_status, ed->db->lv);
+ break;
+ case UDT_INT:
+ ed->base_status.int_ = (unsigned short)val;
+ status->calc_misc(bl, &ed->base_status, ed->db->lv);
+ break;
+ case UDT_DEX:
+ ed->base_status.dex = (unsigned short)val;
+ status->calc_misc(bl, &ed->base_status, ed->db->lv);
+ break;
+ case UDT_LUK:
+ ed->base_status.luk = (unsigned short)val;
+ status->calc_misc(bl, &ed->base_status, ed->db->lv);
+ break;
+ case UDT_ATKRANGE:
+ ed->base_status.rhw.range = (unsigned short)val;
+ break;
+ case UDT_ATKMIN:
+ ed->base_status.rhw.atk = (unsigned short)val;
+ break;
+ case UDT_ATKMAX:
+ ed->base_status.rhw.atk2 = (unsigned short)val;
+ break;
+ case UDT_MATKMIN:
+ ed->base_status.matk_min = (unsigned short)val;
+ break;
+ case UDT_MATKMAX:
+ ed->base_status.matk_max = (unsigned short)val;
+ break;
+ case UDT_DEF:
+ ed->base_status.def = (defType)val;
+ break;
+ case UDT_MDEF:
+ ed->base_status.mdef = (defType)val;
+ break;
+ case UDT_HIT:
+ ed->base_status.hit = (short)val;
+ break;
+ case UDT_FLEE:
+ ed->base_status.flee = (short)val;
+ break;
+ case UDT_PDODGE:
+ ed->base_status.flee2 = (short)val;
+ break;
+ case UDT_CRIT:
+ ed->base_status.cri = (short)val;
+ break;
+ case UDT_RACE:
+ ed->base_status.race = (unsigned char)val;
+ break;
+ case UDT_ELETYPE:
+ ed->base_status.def_ele = (unsigned char)val;
+ break;
+ case UDT_ELELEVEL:
+ ed->base_status.ele_lv = (unsigned char)val;
+ break;
+ case UDT_AMOTION:
+ ed->base_status.amotion = (unsigned short)val;
+ break;
+ case UDT_ADELAY:
+ ed->base_status.adelay = (unsigned short)val;
+ break;
+ case UDT_DMOTION:
+ ed->base_status.dmotion = (unsigned short)val;
+ break;
+ case UDT_LIFETIME:
+ ed->elemental.life_time = val;
+ break;
+ default:
+ ShowWarning("buildin_setunitdata: Invalid data type '%d' for elemental unit.\n", type);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ clif->elemental_info(ed->master); // Send Elemental data.
+ break;
+ }
+ case BL_NPC: {
+ struct npc_data *nd = BL_UCAST(BL_NPC, bl);
+
+ 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) {
+ case UDT_SIZE:
+ nd->status.size = (unsigned char)val;
+ break;
+ case UDT_LEVEL:
+ nd->level = (unsigned short)val;
+ break;
+ case UDT_HP:
+ status->set_hp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
+ break;
+ case UDT_MAXHP:
+ nd->status.max_hp = (unsigned int)val;
+ break;
+ case UDT_SP:
+ status->set_sp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
+ break;
+ case UDT_MAXSP:
+ nd->status.max_sp = (unsigned int)val;
+ break;
+ case UDT_MAPIDXY:
+ unit->warp(bl, (short)val, (short)val2, (short)val3, CLR_TELEPORT);
+ break;
+ case UDT_WALKTOXY:
+ if (unit->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);
+ break;
+ case UDT_SPEED:
+ nd->speed = (short)val;
+ status->calc_misc(bl, &nd->status, nd->level);
+ break;
+ case UDT_LOOKDIR:
+ unit->set_dir(bl, (enum unit_dir)val);
+ break;
+ case UDT_STR:
+ nd->status.str = (unsigned short)val;
+ status->calc_misc(bl, &nd->status, nd->level);
+ break;
+ case UDT_AGI:
+ nd->status.agi = (unsigned short)val;
+ status->calc_misc(bl, &nd->status, nd->level);
+ break;
+ case UDT_VIT:
+ nd->status.vit = (unsigned short)val;
+ status->calc_misc(bl, &nd->status, nd->level);
+ break;
+ case UDT_INT:
+ nd->status.int_ = (unsigned short)val;
+ status->calc_misc(bl, &nd->status, nd->level);
+ break;
+ case UDT_DEX:
+ nd->status.dex = (unsigned short)val;
+ status->calc_misc(bl, &nd->status, nd->level);
+ break;
+ case UDT_LUK:
+ nd->status.luk = (unsigned short)val;
+ status->calc_misc(bl, &nd->status, nd->level);
+ break;
+ case UDT_STATPOINT:
+ nd->stat_point = (unsigned short)val;
+ break;
+ case UDT_ATKRANGE:
+ nd->status.rhw.range = (unsigned short)val;
+ break;
+ case UDT_ATKMIN:
+ nd->status.rhw.atk = (unsigned short)val;
+ break;
+ case UDT_ATKMAX:
+ nd->status.rhw.atk2 = (unsigned short)val;
+ break;
+ case UDT_MATKMIN:
+ nd->status.matk_min = (unsigned short)val;
+ break;
+ case UDT_MATKMAX:
+ nd->status.matk_max = (unsigned short)val;
+ break;
+ case UDT_DEF:
+ nd->status.def = (defType)val;
+ break;
+ case UDT_MDEF:
+ nd->status.mdef = (defType)val;
+ break;
+ case UDT_HIT:
+ nd->status.hit = (short)val;
+ break;
+ case UDT_FLEE:
+ nd->status.flee = (short)val;
+ break;
+ case UDT_PDODGE:
+ nd->status.flee2 = (short)val;
+ break;
+ case UDT_CRIT:
+ nd->status.cri = (short)val;
+ break;
+ case UDT_RACE:
+ nd->status.race = (unsigned char)val;
+ break;
+ case UDT_ELETYPE:
+ nd->status.def_ele = (unsigned char)val;
+ break;
+ case UDT_ELELEVEL:
+ nd->status.ele_lv = (unsigned char)val;
+ break;
+ case UDT_AMOTION:
+ nd->status.amotion = (unsigned short)val;
+ break;
+ case UDT_ADELAY:
+ nd->status.adelay = (unsigned short)val;
+ break;
+ case UDT_DMOTION:
+ nd->status.dmotion = (unsigned short)val;
+ break;
+ case UDT_SEX:
+ nd->vd.sex = (char)val;
+ npc->refresh(nd);
+ break;
+ case UDT_HAIRSTYLE:
+ clif->changelook(bl, LOOK_HAIR, val);
+ break;
+ case UDT_HAIRCOLOR:
+ clif->changelook(bl, LOOK_HAIR_COLOR, val);
+ break;
+ case UDT_HEADBOTTOM:
+ clif->changelook(bl, LOOK_HEAD_BOTTOM, val);
+ break;
+ case UDT_HEADMIDDLE:
+ clif->changelook(bl, LOOK_HEAD_MID, val);
+ break;
+ case UDT_HEADTOP:
+ clif->changelook(bl, LOOK_HEAD_TOP, val);
+ break;
+ case UDT_CLOTHCOLOR:
+ clif->changelook(bl, LOOK_CLOTHES_COLOR, val);
+ break;
+ case UDT_SHIELD:
+ clif->changelook(bl, LOOK_SHIELD, val);
+ break;
+ case UDT_WEAPON:
+ clif->changelook(bl, LOOK_WEAPON, val);
+ break;
+ case UDT_ROBE:
+ clif->changelook(bl, LOOK_ROBE, val);
+ break;
+ case UDT_BODY2:
+ clif->changelook(bl, LOOK_BODY2, val);
+ break;
+ default:
+ ShowWarning("buildin_setunitdata: Invalid data type '%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.
+
+ script_pushint(st, 1);
+
+ return true;
+}
+
+/**
+ * Retrieves real-time data for a game object.
+ * Getunitdata <GUID>,<DataType>{,<Variable>}
+ * @param1 GUID Game object unique Id.
+ * @param2 DataType Type of Data to be set for the unit.
+ * @param3 Variable array reference to store data into. (used for UDT_MAPIDXY)
+ * @return 0 on failure, <value> on success
+
+ Note: Please make this script command only return ONE INTEGER value.
+ If the unit data having multiple arguments, or need to return in array,
+ please introduce a new script command.
+ */
+static BUILDIN(getunitdata)
+{
+ struct block_list *bl;
+ const char *udtype = NULL;
+ const struct map_session_data *sd = NULL;
+ int type = 0;
+ char* name = NULL;
+ struct script_data *data = script_hasdata(st,4)?script_getdata(st, 4):NULL;
+
+ bl = map->id2bl(script_getnum(st, 2));
+
+ if (bl == NULL) {
+ ShowWarning("buildin_getunitdata: Error in finding object with given GID %d!\n", script_getnum(st, 2));
+ script_pushint(st, -1);
+ return false;
+ }
+
+ type = script_getnum(st, 3);
+
+ /* Type check */
+ if (type < UDT_TYPE || type >= UDT_MAX) {
+ ShowError("buildin_getunitdata: Invalid unit data type %d provided.\n", type);
+ script_pushint(st, -1);
+ return false;
+ }
+
+ /* Argument checks. Subject to deprecate */
+ if (type == UDT_MAPIDXY) {
+ if (data == NULL || !data_isreference(data)) {
+ ShowWarning("buildin_getunitdata: Error in argument 3. Please provide a reference variable to store values in.\n");
+ script_pushint(st, -1);
+ return false;
+ }
+
+ name = reference_getname(data);
+
+ if (not_server_variable(*name)) {
+ sd = script->rid2sd(st);
+ if (sd == NULL) {
+ ShowWarning("buildin_getunitdata: Player not attached! Cannot use player variable %s.\n",name);
+ script_pushint(st, -1);
+ return true;// no player attached
+ }
+ }
+ } else if (type == UDT_GROUP) {
+ struct unit_data *ud = unit->bl2ud(bl);
+ if (ud == NULL) {
+ ShowError("buildin_setunitdata: ud is NULL!\n");
+ script_pushint(st, -1);
+ return false;
+ }
+ script_pushint(st, ud->groupId);
+ return true;
+ }
+
+#define getunitdata_sub(idx__,var__) script->setd_sub(st,NULL,name,(idx__),(void *)h64BPTRSIZE((int)(var__)),data->ref);
+
+ switch (bl->type) {
+ case BL_MOB:
+ {
+ const struct mob_data *md = BL_UCAST(BL_MOB, bl);
+
+ nullpo_retr(false, md);
+
+ switch (type)
+ {
+ case UDT_TYPE: script_pushint(st, BL_MOB); break;
+ case UDT_SIZE: script_pushint(st, md->status.size); break;
+ case UDT_LEVEL: script_pushint(st, md->level); break;
+ case UDT_HP: script_pushint(st, md->status.hp); break;
+ case UDT_MAXHP: script_pushint(st, md->status.max_hp); break;
+ case UDT_SP: script_pushint(st, md->status.sp); break;
+ case UDT_MAXSP: script_pushint(st, md->status.max_sp); break;
+ case UDT_MAPIDXY:
+ getunitdata_sub(0, md->bl.m);
+ getunitdata_sub(1, md->bl.x);
+ getunitdata_sub(2, md->bl.y);
+ break;
+ case UDT_SPEED: script_pushint(st, md->status.speed); break;
+ case UDT_MODE: script_pushint(st, md->status.mode); break;
+ case UDT_AI: script_pushint(st, md->special_state.ai); break;
+ case UDT_SCOPTION: script_pushint(st, md->sc.option); break;
+ case UDT_SEX: script_pushint(st, md->vd->sex); break;
+ case UDT_CLASS: script_pushint(st, md->vd->class); break;
+ case UDT_HAIRSTYLE: script_pushint(st, md->vd->hair_style); break;
+ case UDT_HAIRCOLOR: script_pushint(st, md->vd->hair_color); break;
+ case UDT_HEADBOTTOM: script_pushint(st, md->vd->head_bottom); break;
+ case UDT_HEADMIDDLE: script_pushint(st, md->vd->head_mid); break;
+ case UDT_HEADTOP: script_pushint(st, md->vd->head_top); break;
+ case UDT_CLOTHCOLOR: script_pushint(st, md->vd->cloth_color); break;
+ case UDT_SHIELD: script_pushint(st, md->vd->shield); break;
+ case UDT_WEAPON: script_pushint(st, md->vd->weapon); break;
+ case UDT_LOOKDIR: script_pushint(st, md->ud.dir); break;
+ case UDT_CANMOVETICK: script_pushint(st, md->ud.canmove_tick); break;
+ case UDT_STR: script_pushint(st, md->status.str); break;
+ case UDT_AGI: script_pushint(st, md->status.agi); break;
+ case UDT_VIT: script_pushint(st, md->status.vit); break;
+ case UDT_INT: script_pushint(st, md->status.int_); break;
+ case UDT_DEX: script_pushint(st, md->status.dex); break;
+ case UDT_LUK: script_pushint(st, md->status.luk); break;
+ case UDT_ATKRANGE: script_pushint(st, md->status.rhw.range); break;
+ case UDT_ATKMIN: script_pushint(st, md->status.rhw.atk); break;
+ case UDT_ATKMAX: script_pushint(st, md->status.rhw.atk2); break;
+ case UDT_MATKMIN: script_pushint(st, md->status.matk_min); break;
+ case UDT_MATKMAX: script_pushint(st, md->status.matk_max); break;
+ case UDT_DEF: script_pushint(st, md->status.def); break;
+ case UDT_MDEF: script_pushint(st, md->status.mdef); break;
+ case UDT_HIT: script_pushint(st, md->status.hit); break;
+ case UDT_FLEE: script_pushint(st, md->status.flee); break;
+ case UDT_PDODGE: script_pushint(st, md->status.flee2); break;
+ case UDT_CRIT: script_pushint(st, md->status.cri); break;
+ case UDT_RACE: script_pushint(st, md->status.race); break;
+ case UDT_ELETYPE: script_pushint(st, md->status.def_ele); break;
+ case UDT_ELELEVEL: script_pushint(st, md->status.ele_lv); break;
+ case UDT_AMOTION: script_pushint(st, md->status.amotion); break;
+ case UDT_ADELAY: script_pushint(st, md->status.adelay); break;
+ case UDT_DMOTION: script_pushint(st, md->status.dmotion); break;
+ case UDT_DAMAGE_TAKEN_RATE: script_pushint(st, md->dmg_taken_rate); break;
+ default:
+ ShowWarning("buildin_getunitdata: Invalid data type '%s' for Mob unit.\n", udtype);
+ script_pushint(st, -1);
+ return false;
+ }
+ }
+ break;
+ case BL_HOM:
+ {
+ const struct homun_data *hd = BL_UCAST(BL_HOM, bl);
+
+ nullpo_retr(false, hd);
+
+ switch (type)
+ {
+ case UDT_TYPE: script_pushint(st, BL_HOM); break;
+ case UDT_SIZE: script_pushint(st, hd->base_status.size); break;
+ case UDT_LEVEL: script_pushint(st, hd->homunculus.level); break;
+ case UDT_HP: script_pushint(st, hd->base_status.hp); break;
+ case UDT_MAXHP: script_pushint(st, hd->base_status.max_hp); break;
+ case UDT_SP: script_pushint(st, hd->base_status.sp); break;
+ case UDT_MAXSP: script_pushint(st, hd->base_status.max_sp); break;
+ case UDT_MAPIDXY:
+ getunitdata_sub(0, hd->bl.m);
+ getunitdata_sub(1, hd->bl.x);
+ getunitdata_sub(2, hd->bl.y);
+ break;
+ case UDT_SPEED: script_pushint(st, hd->base_status.speed); break;
+ case UDT_LOOKDIR: script_pushint(st, hd->ud.dir); break;
+ case UDT_CANMOVETICK: script_pushint(st, hd->ud.canmove_tick); break;
+ case UDT_MODE: script_pushint(st, hd->base_status.mode); break;
+ case UDT_STR: script_pushint(st, hd->base_status.str); break;
+ case UDT_AGI: script_pushint(st, hd->base_status.agi); break;
+ case UDT_VIT: script_pushint(st, hd->base_status.vit); break;
+ case UDT_INT: script_pushint(st, hd->base_status.int_); break;
+ case UDT_DEX: script_pushint(st, hd->base_status.dex); break;
+ case UDT_LUK: script_pushint(st, hd->base_status.luk); break;
+ case UDT_ATKRANGE: script_pushint(st, hd->base_status.rhw.range); break;
+ case UDT_ATKMIN: script_pushint(st, hd->base_status.rhw.atk); break;
+ case UDT_ATKMAX: script_pushint(st, hd->base_status.rhw.atk2); break;
+ case UDT_MATKMIN: script_pushint(st, hd->base_status.matk_min); break;
+ case UDT_MATKMAX: script_pushint(st, hd->base_status.matk_max); break;
+ case UDT_DEF: script_pushint(st, hd->base_status.def); break;
+ case UDT_MDEF: script_pushint(st, hd->base_status.mdef); break;
+ case UDT_HIT: script_pushint(st, hd->base_status.hit); break;
+ case UDT_FLEE: script_pushint(st, hd->base_status.flee); break;
+ case UDT_PDODGE: script_pushint(st, hd->base_status.flee2); break;
+ case UDT_CRIT: script_pushint(st, hd->base_status.cri); break;
+ case UDT_RACE: script_pushint(st, hd->base_status.race); break;
+ case UDT_ELETYPE: script_pushint(st, hd->base_status.def_ele); break;
+ case UDT_ELELEVEL: script_pushint(st, hd->base_status.ele_lv); break;
+ case UDT_AMOTION: script_pushint(st, hd->base_status.amotion); break;
+ case UDT_ADELAY: script_pushint(st, hd->base_status.adelay); break;
+ case UDT_DMOTION: script_pushint(st, hd->base_status.dmotion); break;
+ case UDT_MASTERCID: script_pushint(st, hd->homunculus.char_id); break;
+ case UDT_HUNGER: script_pushint(st, hd->homunculus.hunger); break;
+ case UDT_INTIMACY: script_pushint(st, hd->homunculus.intimacy); break;
+ default:
+ ShowWarning("buildin_getunitdata: Invalid data type '%s' for Homunculus unit.\n", udtype);
+ script_pushint(st, -1);
+ return false;
+ }
+ }
+ break;
+ case BL_PET:
+ {
+ const struct pet_data *pd = BL_UCAST(BL_PET, bl);
+
+ nullpo_retr(false, pd);
+
+ switch (type)
+ {
+ case UDT_TYPE: script_pushint(st, BL_PET); break;
+ case UDT_SIZE: script_pushint(st, pd->status.size); break;
+ case UDT_LEVEL: script_pushint(st, pd->pet.level); break;
+ case UDT_HP: script_pushint(st, pd->status.hp); break;
+ case UDT_MAXHP: script_pushint(st, pd->status.max_hp); break;
+ case UDT_SP: script_pushint(st, pd->status.sp); break;
+ case UDT_MAXSP: script_pushint(st, pd->status.max_sp); break;
+ case UDT_MAPIDXY:
+ getunitdata_sub(0, pd->bl.m);
+ getunitdata_sub(1, pd->bl.x);
+ getunitdata_sub(2, pd->bl.y);
+ break;
+ case UDT_SPEED: script_pushint(st, pd->status.speed); break;
+ case UDT_LOOKDIR: script_pushint(st, pd->ud.dir); break;
+ case UDT_CANMOVETICK: script_pushint(st, pd->ud.canmove_tick); break;
+ case UDT_MODE: script_pushint(st, pd->status.mode); break;
+ case UDT_STR: script_pushint(st, pd->status.str); break;
+ case UDT_AGI: script_pushint(st, pd->status.agi); break;
+ case UDT_VIT: script_pushint(st, pd->status.vit); break;
+ case UDT_INT: script_pushint(st, pd->status.int_); break;
+ case UDT_DEX: script_pushint(st, pd->status.dex); break;
+ case UDT_LUK: script_pushint(st, pd->status.luk); break;
+ case UDT_ATKRANGE: script_pushint(st, pd->status.rhw.range); break;
+ case UDT_ATKMIN: script_pushint(st, pd->status.rhw.atk); break;
+ case UDT_ATKMAX: script_pushint(st, pd->status.rhw.atk2); break;
+ case UDT_MATKMIN: script_pushint(st, pd->status.matk_min); break;
+ case UDT_MATKMAX: script_pushint(st, pd->status.matk_max); break;
+ case UDT_DEF: script_pushint(st, pd->status.def); break;
+ case UDT_MDEF: script_pushint(st, pd->status.mdef); break;
+ case UDT_HIT: script_pushint(st, pd->status.hit); break;
+ case UDT_FLEE: script_pushint(st, pd->status.flee); break;
+ case UDT_PDODGE: script_pushint(st, pd->status.flee2); break;
+ case UDT_CRIT: script_pushint(st, pd->status.cri); break;
+ case UDT_RACE: script_pushint(st, pd->status.race); break;
+ case UDT_ELETYPE: script_pushint(st, pd->status.def_ele); break;
+ case UDT_ELELEVEL: script_pushint(st, pd->status.ele_lv); break;
+ case UDT_AMOTION: script_pushint(st, pd->status.amotion); break;
+ case UDT_ADELAY: script_pushint(st, pd->status.adelay); break;
+ case UDT_DMOTION: script_pushint(st, pd->status.dmotion); break;
+ case UDT_MASTERAID: script_pushint(st, pd->pet.account_id); break;
+ case UDT_HUNGER: script_pushint(st, pd->pet.hungry); break;
+ case UDT_INTIMACY: script_pushint(st, pd->pet.intimate); break;
+ default:
+ ShowWarning("buildin_getunitdata: Invalid data type '%s' for Pet unit.\n", udtype);
+ script_pushint(st, -1);
+ return false;
+ }
+ }
+ break;
+ case BL_MER:
+ {
+ const struct mercenary_data *mc = BL_UCAST(BL_MER, bl);
+
+ nullpo_retr(false, mc);
+
+ switch (type)
+ {
+ case UDT_TYPE: script_pushint(st, BL_MER); break;
+ case UDT_SIZE: script_pushint(st, mc->base_status.size); break;
+ case UDT_HP: script_pushint(st, mc->base_status.hp); break;
+ case UDT_MAXHP: script_pushint(st, mc->base_status.max_hp); break;
+ case UDT_SP: script_pushint(st, mc->base_status.sp); break;
+ case UDT_MAXSP: script_pushint(st, mc->base_status.max_sp); break;
+ case UDT_MAPIDXY:
+ getunitdata_sub(0, mc->bl.m);
+ getunitdata_sub(1, mc->bl.x);
+ getunitdata_sub(2, mc->bl.y);
+ break;
+ case UDT_SPEED: script_pushint(st, mc->base_status.speed); break;
+ case UDT_LOOKDIR: script_pushint(st, mc->ud.dir); break;
+ case UDT_CANMOVETICK: script_pushint(st, mc->ud.canmove_tick); break;
+ case UDT_MODE: script_pushint(st, mc->base_status.mode); break;
+ case UDT_STR: script_pushint(st, mc->base_status.str); break;
+ case UDT_AGI: script_pushint(st, mc->base_status.agi); break;
+ case UDT_VIT: script_pushint(st, mc->base_status.vit); break;
+ case UDT_INT: script_pushint(st, mc->base_status.int_); break;
+ case UDT_DEX: script_pushint(st, mc->base_status.dex); break;
+ case UDT_LUK: script_pushint(st, mc->base_status.luk); break;
+ case UDT_ATKRANGE: script_pushint(st, mc->base_status.rhw.range); break;
+ case UDT_ATKMIN: script_pushint(st, mc->base_status.rhw.atk); break;
+ case UDT_ATKMAX: script_pushint(st, mc->base_status.rhw.atk2); break;
+ case UDT_MATKMIN: script_pushint(st, mc->base_status.matk_min); break;
+ case UDT_MATKMAX: script_pushint(st, mc->base_status.matk_max); break;
+ case UDT_DEF: script_pushint(st, mc->base_status.def); break;
+ case UDT_MDEF: script_pushint(st, mc->base_status.mdef); break;
+ case UDT_HIT: script_pushint(st, mc->base_status.hit); break;
+ case UDT_FLEE: script_pushint(st, mc->base_status.flee); break;
+ case UDT_PDODGE: script_pushint(st, mc->base_status.flee2); break;
+ case UDT_CRIT: script_pushint(st, mc->base_status.cri); break;
+ case UDT_RACE: script_pushint(st, mc->base_status.race); break;
+ case UDT_ELETYPE: script_pushint(st, mc->base_status.def_ele); break;
+ case UDT_ELELEVEL: script_pushint(st, mc->base_status.ele_lv); break;
+ case UDT_AMOTION: script_pushint(st, mc->base_status.amotion); break;
+ case UDT_ADELAY: script_pushint(st, mc->base_status.adelay); break;
+ case UDT_DMOTION: script_pushint(st, mc->base_status.dmotion); break;
+ case UDT_MASTERCID: script_pushint(st, mc->mercenary.char_id); break;
+ case UDT_MERC_KILLCOUNT: script_pushint(st, mc->mercenary.kill_count); break;
+ case UDT_LIFETIME: script_pushint(st, mc->mercenary.life_time); break;
+ default:
+ ShowWarning("buildin_getunitdata: Invalid data type '%s' for Mercenary unit.\n", udtype);
+ script_pushint(st, -1);
+ return false;
+ }
+ }
+ break;
+ case BL_ELEM:
+ {
+ const struct elemental_data *ed = BL_UCAST(BL_ELEM, bl);
+
+ nullpo_retr(false, ed);
+
+ switch (type)
+ {
+ case UDT_TYPE: script_pushint(st, BL_ELEM); break;
+ case UDT_SIZE: script_pushint(st, ed->base_status.size); break;
+ case UDT_HP: script_pushint(st, ed->base_status.hp); break;
+ case UDT_MAXHP: script_pushint(st, ed->base_status.max_hp); break;
+ case UDT_SP: script_pushint(st, ed->base_status.sp); break;
+ case UDT_MAXSP: script_pushint(st, ed->base_status.max_sp); break;
+ case UDT_MAPIDXY:
+ getunitdata_sub(0, ed->bl.m);
+ getunitdata_sub(1, ed->bl.x);
+ getunitdata_sub(2, ed->bl.y);
+ break;
+ case UDT_SPEED: script_pushint(st, ed->base_status.speed); break;
+ case UDT_LOOKDIR: script_pushint(st, ed->ud.dir); break;
+ case UDT_CANMOVETICK: script_pushint(st, ed->ud.canmove_tick); break;
+ case UDT_MODE: script_pushint(st, ed->base_status.mode); break;
+ case UDT_STR: script_pushint(st, ed->base_status.str); break;
+ case UDT_AGI: script_pushint(st, ed->base_status.agi); break;
+ case UDT_VIT: script_pushint(st, ed->base_status.vit); break;
+ case UDT_INT: script_pushint(st, ed->base_status.int_); break;
+ case UDT_DEX: script_pushint(st, ed->base_status.dex); break;
+ case UDT_LUK: script_pushint(st, ed->base_status.luk); break;
+ case UDT_ATKRANGE: script_pushint(st, ed->base_status.rhw.range); break;
+ case UDT_ATKMIN: script_pushint(st, ed->base_status.rhw.atk); break;
+ case UDT_ATKMAX: script_pushint(st, ed->base_status.rhw.atk2); break;
+ case UDT_MATKMIN: script_pushint(st, ed->base_status.matk_min); break;
+ case UDT_MATKMAX: script_pushint(st, ed->base_status.matk_max); break;
+ case UDT_DEF: script_pushint(st, ed->base_status.def); break;
+ case UDT_MDEF: script_pushint(st, ed->base_status.mdef); break;
+ case UDT_HIT: script_pushint(st, ed->base_status.hit); break;
+ case UDT_FLEE: script_pushint(st, ed->base_status.flee); break;
+ case UDT_PDODGE: script_pushint(st, ed->base_status.flee2); break;
+ case UDT_CRIT: script_pushint(st, ed->base_status.cri); break;
+ case UDT_RACE: script_pushint(st, ed->base_status.race); break;
+ case UDT_ELETYPE: script_pushint(st, ed->base_status.def_ele); break;
+ case UDT_ELELEVEL: script_pushint(st, ed->base_status.ele_lv); break;
+ case UDT_AMOTION: script_pushint(st, ed->base_status.amotion); break;
+ case UDT_ADELAY: script_pushint(st, ed->base_status.adelay); break;
+ case UDT_DMOTION: script_pushint(st, ed->base_status.dmotion); break;
+ case UDT_MASTERCID: script_pushint(st, ed->elemental.char_id); break;
+ default:
+ ShowWarning("buildin_getunitdata: Invalid data type '%s' for Elemental unit.\n", udtype);
+ script_pushint(st, -1);
+ return false;
+ }
+ }
+ break;
+ case BL_NPC:
+ {
+ const struct npc_data *nd = BL_UCAST(BL_NPC, bl);
+
+ nullpo_retr(false, nd);
+
+ switch (type)
+ {
+ case UDT_TYPE: script_pushint(st, BL_NPC); break;
+ case UDT_SIZE: script_pushint(st, nd->status.size); break;
+ case UDT_HP: script_pushint(st, nd->status.hp); break;
+ case UDT_MAXHP: script_pushint(st, nd->status.max_hp); break;
+ case UDT_SP: script_pushint(st, nd->status.sp); break;
+ case UDT_MAXSP: script_pushint(st, nd->status.max_sp); break;
+ case UDT_MAPIDXY:
+ getunitdata_sub(0, bl->m);
+ getunitdata_sub(1, bl->x);
+ getunitdata_sub(2, bl->y);
+ break;
+ case UDT_SPEED: script_pushint(st, nd->status.speed); break;
+ case UDT_LOOKDIR: script_pushint(st, nd->ud->dir); break;
+ case UDT_CANMOVETICK: script_pushint(st, nd->ud->canmove_tick); break;
+ case UDT_MODE: script_pushint(st, nd->status.mode); break;
+ case UDT_STR: script_pushint(st, nd->status.str); break;
+ case UDT_AGI: script_pushint(st, nd->status.agi); break;
+ case UDT_VIT: script_pushint(st, nd->status.vit); break;
+ case UDT_INT: script_pushint(st, nd->status.int_); break;
+ case UDT_DEX: script_pushint(st, nd->status.dex); break;
+ case UDT_LUK: script_pushint(st, nd->status.luk); break;
+ case UDT_ATKRANGE: script_pushint(st, nd->status.rhw.range); break;
+ case UDT_ATKMIN: script_pushint(st, nd->status.rhw.atk); break;
+ case UDT_ATKMAX: script_pushint(st, nd->status.rhw.atk2); break;
+ case UDT_MATKMIN: script_pushint(st, nd->status.matk_min); break;
+ case UDT_MATKMAX: script_pushint(st, nd->status.matk_max); break;
+ case UDT_DEF: script_pushint(st, nd->status.def); break;
+ case UDT_MDEF: script_pushint(st, nd->status.mdef); break;
+ case UDT_HIT: script_pushint(st, nd->status.hit); break;
+ case UDT_FLEE: script_pushint(st, nd->status.flee); break;
+ case UDT_PDODGE: script_pushint(st, nd->status.flee2); break;
+ case UDT_CRIT: script_pushint(st, nd->status.cri); break;
+ case UDT_RACE: script_pushint(st, nd->status.race); break;
+ case UDT_ELETYPE: script_pushint(st, nd->status.def_ele); break;
+ case UDT_ELELEVEL: script_pushint(st, nd->status.ele_lv); break;
+ case UDT_AMOTION: script_pushint(st, nd->status.amotion); break;
+ case UDT_ADELAY: script_pushint(st, nd->status.adelay); break;
+ case UDT_DMOTION: script_pushint(st, nd->status.dmotion); break;
+ case UDT_SEX: script_pushint(st, nd->vd.sex); break;
+ case UDT_CLASS: script_pushint(st, nd->vd.class); break;
+ case UDT_HAIRSTYLE: script_pushint(st, nd->vd.hair_style); break;
+ case UDT_HAIRCOLOR: script_pushint(st, nd->vd.hair_color); break;
+ case UDT_HEADBOTTOM: script_pushint(st, nd->vd.head_bottom); break;
+ case UDT_HEADMIDDLE: script_pushint(st, nd->vd.head_mid); break;
+ case UDT_HEADTOP: script_pushint(st, nd->vd.head_top); break;
+ case UDT_CLOTHCOLOR: script_pushint(st, nd->vd.cloth_color); break;
+ case UDT_SHIELD: script_pushint(st, nd->vd.shield); break;
+ case UDT_WEAPON: script_pushint(st, nd->vd.weapon); break;
+ case UDT_ROBE: script_pushint(st, nd->vd.robe); break;
+ case UDT_BODY2: script_pushint(st, nd->vd.body_style); break;
+ default:
+ ShowWarning("buildin_getunitdata: Invalid data type '%s' for NPC unit.\n", udtype);
+ script_pushint(st, -1);
+ return false;
+ }
+ }
+ break;
+ default:
+ ShowError("buildin_getunitdata: Unknown object!\n");
+ script_pushint(st, -1);
+ return false;
+ } // end of bl->type switch
+
+#undef getunitdata_sub
+
+ return true;
+}
+
+/**
+ * Gets the name of a Unit.
+ * Supported types are [MOB|HOM|PET|NPC].
+ * MER and ELEM don't support custom names.
+ *
+ * @command getunitname <GUID>;
+ * @param GUID Game Object Unique ID.
+ * @return boolean or Name of the game object.
+ */
+static BUILDIN(getunitname)
+{
+ const struct block_list* bl = NULL;
+
+ bl = map->id2bl(script_getnum(st, 2));
+
+ if (bl == NULL) {
+ ShowWarning("buildin_getunitname: Error in finding object with given game ID %d!\n", script_getnum(st, 2));
+ script_pushconststr(st, "Unknown");
+ return false;
+ }
+
+ script_pushstrcopy(st, status->get_name(bl));
+
+ return true;
+}
+
+/**
+ * Changes the name of a bl.
+ * Supported types are [MOB|HOM|PET].
+ * For NPC see 'setnpcdisplay', MER and ELEM don't support custom names.
+ *
+ * @command setunitname <GUID>,<name>;
+ * @param GUID Game object unique ID.
+ * @param Name as string.
+ * @return boolean.
+ */
+static BUILDIN(setunitname)
+{
+ struct block_list* bl = map->id2bl(script_getnum(st, 2));
+
+ if (bl == NULL) {
+ ShowWarning("buildin_setunitname: Game object with ID %d was not found!\n", script_getnum(st, 2));
+ script_pushint(st, 0);
+ return false;
+ }
+
+ switch (bl->type) {
+ case BL_MOB:
+ {
+ struct mob_data *md = BL_UCAST(BL_MOB, bl);
+ if (md == NULL) {
+ ShowWarning("buildin_setunitname: Error in finding object BL_MOB!\n");
+ script_pushint(st, 0);
+ return false;
+ }
+ safestrncpy(md->name, script_getstr(st, 3), NAME_LENGTH);
+ }
+ break;
+ case BL_HOM:
+ {
+ struct homun_data *hd = BL_UCAST(BL_HOM, bl);
+ if (hd == NULL) {
+ ShowWarning("buildin_setunitname: Error in finding object BL_HOM!\n");
+ script_pushint(st, 0);
+ return false;
+ }
+ safestrncpy(hd->homunculus.name, script_getstr(st, 3), NAME_LENGTH);
+ }
+ break;
+ case BL_PET:
+ {
+ struct pet_data *pd = BL_UCAST(BL_PET, bl);
+ if (pd == NULL) {
+ ShowWarning("buildin_setunitname: Error in finding object BL_PET!\n");
+ script_pushint(st, 0);
+ return false;
+ }
+ safestrncpy(pd->pet.name, script_getstr(st, 3), NAME_LENGTH);
+ }
+ break;
+ default:
+ script_pushint(st, 0);
+ ShowWarning("buildin_setunitname: Unknown object type!\n");
+ return false;
+ }
+
+ script_pushint(st, 1);
+ clif->blname_ack(0, bl); // Send update to client.
+
+ return true;
+}
+
+static BUILDIN(setunittitle)
+{
+ struct block_list *bl = map->id2bl(script_getnum(st, 2));
+ if (bl == NULL) {
+ ShowWarning("buildin_setunittitle: Error in finding object with given game ID %d!\n", script_getnum(st, 2));
+ return false;
+ }
+
+ struct unit_data *ud = unit->bl2ud2(bl);
+ if (ud == NULL) {
+ ShowWarning("buildin_setunittitle: Error in finding unit_data for given game ID %d!\n", script_getnum(st, 2));
+ return false;
+ }
+
+ safestrncpy(ud->title, script_getstr(st, 3), NAME_LENGTH);
+ clif->blname_ack(0, bl); // Send update to client.
+
+ return true;
+}
+
+static BUILDIN(getunittitle)
+{
+ struct block_list *bl = map->id2bl(script_getnum(st, 2));
+ if (bl == NULL) {
+ ShowWarning("buildin_getunitname: Error in finding object with given game ID %d!\n", script_getnum(st, 2));
+ script_pushconststr(st, "Unknown");
+ return false;
+ }
+
+ struct unit_data *ud = unit->bl2ud(bl);
+ if (ud == NULL) {
+ ShowWarning("buildin_setunittitle: Error in finding unit_data for given game ID %d!\n", script_getnum(st, 2));
+ return false;
+ }
+
+ script_pushstrcopy(st, ud->title);
+
+ return true;
+}
+
/// Makes the unit walk to target position or target id
/// Returns if it was successfull
///
/// unitwalk(<unit_id>,<x>,<y>) -> <bool>
/// unitwalk(<unit_id>,<target_id>) -> <bool>
-BUILDIN(unitwalk) {
- struct block_list* bl;
+static BUILDIN(unitwalk)
+{
+ struct block_list *bl = map->id2bl(script_getnum(st, 2));
- bl = map->id2bl(script_getnum(st,2));
- if( bl == NULL ) {
+ if (bl == NULL) {
script_pushint(st, 0);
return true;
}
- if( bl->type == BL_NPC ) {
- unit->bl2ud2(bl); // ensure the ((struct npc_data*)bl)->ud is safe to edit
+ if (bl->type == BL_NPC) {
+ struct unit_data *ud = unit->bl2ud2(bl); // ensure the ((struct npc_data*)bl)->ud is safe to edit
+ if (ud == NULL) {
+ ShowWarning("buildin_unitwalk: floating NPC don't have unit data.\n");
+ return false;
+ }
}
- 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.
- } else {
- int target_id = script_getnum(st,3);
- script_pushint(st, unit->walktobl(bl,map->id2bl(target_id),1,1));
+ if (script_hasdata(st, 4)) {
+ int x = script_getnum(st, 3);
+ int y = script_getnum(st, 4);
+ 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);
+ script_pushint(st, unit->walktobl(bl, map->id2bl(target_id), 1, 1));
+ }
+
+ 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>;
-BUILDIN(unitkill)
+static BUILDIN(unitkill)
{
struct block_list* bl = map->id2bl(script_getnum(st,2));
if( bl != NULL )
@@ -16719,33 +21270,36 @@ BUILDIN(unitkill)
/// Returns if it was successfull
///
/// unitwarp(<unit_id>,"<map name>",<x>,<y>) -> <bool>
-BUILDIN(unitwarp) {
- int unit_id;
+static BUILDIN(unitwarp)
+{
+ int unit_id = script_getnum(st, 2);
+ const char *mapname = script_getstr(st, 3);
+ short x = (short)script_getnum(st, 4);
+ short y = (short)script_getnum(st, 5);
int mapid;
- short x;
- short y;
- struct block_list* bl;
- const char *mapname;
-
- unit_id = script_getnum(st,2);
- mapname = script_getstr(st, 3);
- x = (short)script_getnum(st,4);
- y = (short)script_getnum(st,5);
+ struct block_list *bl;
if (!unit_id) //Warp the script's runner
bl = map->id2bl(st->rid);
else
bl = map->id2bl(unit_id);
- if( strcmp(mapname,"this") == 0 )
- mapid = bl?bl->m:-1;
+ if (strcmp(mapname, "this") == 0)
+ mapid = bl ? bl->m : -1;
else
mapid = map->mapname2mapid(mapname);
- if( mapid >= 0 && bl != NULL ) {
- unit->bl2ud2(bl); // ensure ((struct npc_data *)bl)->ud is safe to edit
- script_pushint(st, unit->warp(bl,mapid,x,y,CLR_OUTSIGHT));
- } else {
+ if (mapid >= 0 && bl != NULL) {
+ struct unit_data *ud = unit->bl2ud2(bl); // ensure ((struct npc_data *)bl)->ud is safe to edit
+ if (bl->type == BL_NPC) {
+ if (ud == NULL) {
+ ShowWarning("buildin_unitwarp: floating NPC don't have unit data.\n");
+ return false;
+ }
+ }
+ script_pushint(st, unit->warp(bl, mapid, x, y, CLR_OUTSIGHT));
+ }
+ else {
script_pushint(st, 0);
}
@@ -16759,7 +21313,8 @@ BUILDIN(unitwarp) {
///
/// unitattack(<unit_id>,"<target name>"{,<action type>}) -> <bool>
/// unitattack(<unit_id>,<target_id>{,<action type>}) -> <bool>
-BUILDIN(unitattack) {
+static BUILDIN(unitattack)
+{
struct block_list* unit_bl;
struct block_list* target_bl = NULL;
int actiontype = 0;
@@ -16813,18 +21368,21 @@ BUILDIN(unitattack) {
/// Makes the unit stop attacking and moving
///
/// unitstop <unit_id>;
-BUILDIN(unitstop) {
- int unit_id;
- struct block_list* bl;
-
- unit_id = script_getnum(st,2);
+static BUILDIN(unitstop)
+{
+ struct block_list *bl = map->id2bl(script_getnum(st, 2));
- bl = map->id2bl(unit_id);
- if( bl != NULL ) {
- unit->bl2ud2(bl); // ensure ((struct npc_data *)bl)->ud is safe to edit
+ if (bl != NULL) {
+ struct unit_data *ud = unit->bl2ud2(bl); // ensure ((struct npc_data *)bl)->ud is safe to edit
+ if (bl->type == BL_NPC) {
+ if (ud == NULL) {
+ ShowWarning("buildin_unitstop: floating NPC don't have unit data.\n");
+ return false;
+ }
+ }
unit->stop_attack(bl);
unit->stop_walking(bl, STOPWALKING_FLAG_NEXTCELL);
- if( bl->type == BL_MOB )
+ if (bl->type == BL_MOB)
BL_UCAST(BL_MOB, bl)->target_id = 0;
}
@@ -16833,15 +21391,30 @@ BUILDIN(unitstop) {
/// Makes the unit say the message
///
-/// unittalk <unit_id>,"<message>";
-BUILDIN(unittalk) {
+/// unittalk(<unit_id>,"<message>"{, show_name{, <send_target>{, <target_id>}}});
+static BUILDIN(unittalk)
+{
int unit_id;
const char* message;
- struct block_list* bl;
+ struct block_list *bl, *target_bl = NULL;
+ bool show_name = true;
+ enum send_target target = AREA_CHAT_WOC;
unit_id = script_getnum(st,2);
message = script_getstr(st, 3);
+ if (script_hasdata(st, 4)) {
+ show_name = (script_getnum(st, 4) != 0) ? true : false;
+ }
+
+ if (script_hasdata(st, 5)) {
+ target = script_getnum(st, 5);
+ }
+
+ if (script_hasdata(st, 6)) {
+ target_bl = map->id2bl(script_getnum(st, 6));
+ }
+
bl = map->id2bl(unit_id);
if( bl != NULL ) {
struct StringBuf sbuf;
@@ -16850,8 +21423,17 @@ BUILDIN(unittalk) {
safestrncpy(blname, clif->get_bl_name(bl), sizeof(blname));
if(bl->type == BL_NPC)
strtok(blname, "#");
- StrBuf->Printf(&sbuf, "%s : %s", blname, message);
- clif->disp_overhead(bl, StrBuf->Value(&sbuf));
+ if (show_name) {
+ StrBuf->Printf(&sbuf, "%s : %s", blname, message);
+ } else {
+ StrBuf->Printf(&sbuf, "%s", message);
+ }
+
+ if (bl->type == BL_PC && target == SELF && (target_bl == NULL || bl == target_bl)) {
+ clif->notify_playerchat(bl, StrBuf->Value(&sbuf));
+ } else {
+ clif->disp_overhead(bl, StrBuf->Value(&sbuf), target, target_bl);
+ }
StrBuf->Destroy(&sbuf);
}
@@ -16863,7 +21445,8 @@ BUILDIN(unittalk) {
/// unitemote <unit_id>,<emotion>;
///
/// @see e_* in const.txt
-BUILDIN(unitemote) {
+static BUILDIN(unitemote)
+{
int unit_id;
int emotion;
struct block_list* bl;
@@ -16881,7 +21464,8 @@ BUILDIN(unitemote) {
///
/// unitskilluseid <unit_id>,<skill_id>,<skill_lv>{,<target_id>};
/// unitskilluseid <unit_id>,"<skill name>",<skill_lv>{,<target_id>};
-BUILDIN(unitskilluseid) {
+static BUILDIN(unitskilluseid)
+{
int unit_id;
uint16 skill_id;
uint16 skill_lv;
@@ -16903,7 +21487,10 @@ 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);
}
@@ -16914,7 +21501,8 @@ BUILDIN(unitskilluseid) {
///
/// unitskillusepos <unit_id>,<skill_id>,<skill_lv>,<target_x>,<target_y>;
/// unitskillusepos <unit_id>,"<skill name>",<skill_lv>,<target_x>,<target_y>;
-BUILDIN(unitskillusepos) {
+static BUILDIN(unitskillusepos)
+{
int unit_id;
uint16 skill_id;
uint16 skill_lv;
@@ -16938,7 +21526,10 @@ 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);
}
@@ -16950,7 +21541,7 @@ BUILDIN(unitskillusepos) {
/// Pauses the execution of the script, detaching the player
///
/// sleep <mili seconds>;
-BUILDIN(sleep)
+static BUILDIN(sleep)
{
int ticks;
@@ -16979,7 +21570,8 @@ BUILDIN(sleep)
/// Returns if a player is still attached
///
/// sleep2(<mili secconds>) -> <bool>
-BUILDIN(sleep2) {
+static BUILDIN(sleep2)
+{
int ticks;
ticks = script_getnum(st,2);
@@ -17003,7 +21595,7 @@ BUILDIN(sleep2) {
/// Awakes all the sleep timers of the target npc
///
/// awake "<npc name>";
-BUILDIN(awake)
+static BUILDIN(awake)
{
struct DBIterator *iter;
struct script_state *tst;
@@ -17046,7 +21638,7 @@ BUILDIN(awake)
/// Returns 0 if an error occurs.
///
/// getvariableofnpc(<variable>, "<npc name>") -> <reference>
-BUILDIN(getvariableofnpc)
+static BUILDIN(getvariableofnpc)
{
struct script_data* data;
const char* name;
@@ -17088,13 +21680,62 @@ BUILDIN(getvariableofnpc)
return true;
}
+static BUILDIN(getvariableofpc)
+{
+ const char* name;
+ struct script_data* data = script_getdata(st, 2);
+ struct map_session_data *sd = map->id2sd(script_getnum(st, 3));
+
+ if (!data_isreference(data)) {
+ ShowError("script:getvariableofpc: not a variable\n");
+ script->reportdata(data);
+ script_pushnil(st);
+ st->state = END;
+ return false;
+ }
+
+ name = reference_getname(data);
+
+ switch (*name)
+ {
+ case '$':
+ case '.':
+ case '\'':
+ ShowError("script:getvariableofpc: illegal scope (not pc variable)\n");
+ script->reportdata(data);
+ script_pushnil(st);
+ st->state = END;
+ return false;
+ }
+
+ if (sd == NULL)
+ {
+ // player not found, return default value
+ if (script_hasdata(st, 4)) {
+ script_pushcopy(st, 4);
+ } else if (is_string_variable(name)) {
+ script_pushconststr(st, "");
+ } else {
+ script_pushint(st, 0);
+ }
+ return true;
+ }
+
+ if (!sd->regs.vars)
+ sd->regs.vars = i64db_alloc(DB_OPT_BASE);
+
+ script->push_val(st->stack, C_NAME, reference_getuid(data), &sd->regs);
+ return true;
+}
+
/// Opens a warp portal.
/// Has no "portal opening" effect/sound, it opens the portal immediately.
///
/// warpportal <source x>,<source y>,"<target map>",<target x>,<target y>;
///
/// @author blackhole89
-BUILDIN(warpportal) {
+static BUILDIN(warpportal)
+{
int spx;
int spy;
unsigned short map_index;
@@ -17131,7 +21772,7 @@ BUILDIN(warpportal) {
return true;
}
-BUILDIN(openmail)
+static BUILDIN(openmail)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
@@ -17142,7 +21783,7 @@ BUILDIN(openmail)
return true;
}
-BUILDIN(openauction)
+static BUILDIN(openauction)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
@@ -17158,7 +21799,8 @@ BUILDIN(openauction)
/// checkcell("<map name>",<x>,<y>,<type>) -> <bool>
///
/// @see cell_chk* constants in const.txt for the types
-BUILDIN(checkcell) {
+static BUILDIN(checkcell)
+{
int16 m = map->mapname2mapid(script_getstr(st,2));
int16 x = script_getnum(st,3);
int16 y = script_getnum(st,4);
@@ -17179,7 +21821,8 @@ BUILDIN(checkcell) {
/// setcell "<map name>",<x1>,<y1>,<x2>,<y2>,<type>,<flag>;
///
/// @see cell_* constants in const.txt for the types
-BUILDIN(setcell) {
+static BUILDIN(setcell)
+{
int16 m = map->mapname2mapid(script_getstr(st,2));
int16 x1 = script_getnum(st,3);
int16 y1 = script_getnum(st,4);
@@ -17208,7 +21851,7 @@ BUILDIN(setcell) {
/*==========================================
* Mercenary Commands
*------------------------------------------*/
-BUILDIN(mercenary_create)
+static BUILDIN(mercenary_create)
{
struct map_session_data *sd;
int class_, contract_time;
@@ -17226,7 +21869,8 @@ BUILDIN(mercenary_create)
return true;
}
-BUILDIN(mercenary_heal) {
+static BUILDIN(mercenary_heal)
+{
struct map_session_data *sd = script->rid2sd(st);
int hp, sp;
@@ -17235,11 +21879,12 @@ BUILDIN(mercenary_heal) {
hp = script_getnum(st,2);
sp = script_getnum(st,3);
- status->heal(&sd->md->bl, hp, sp, 0);
+ status->heal(&sd->md->bl, hp, sp, STATUS_HEAL_DEFAULT);
return true;
}
-BUILDIN(mercenary_sc_start) {
+static BUILDIN(mercenary_sc_start)
+{
struct map_session_data *sd = script->rid2sd(st);
enum sc_type type;
int tick, val1;
@@ -17255,7 +21900,8 @@ BUILDIN(mercenary_sc_start) {
return true;
}
-BUILDIN(mercenary_get_calls) {
+static BUILDIN(mercenary_get_calls)
+{
struct map_session_data *sd = script->rid2sd(st);
int guild_id;
@@ -17281,7 +21927,8 @@ BUILDIN(mercenary_get_calls) {
return true;
}
-BUILDIN(mercenary_set_calls) {
+static BUILDIN(mercenary_set_calls)
+{
struct map_session_data *sd = script->rid2sd(st);
int guild_id, value, *calls;
@@ -17311,7 +21958,8 @@ BUILDIN(mercenary_set_calls) {
return true;
}
-BUILDIN(mercenary_get_faith) {
+static BUILDIN(mercenary_get_faith)
+{
struct map_session_data *sd = script->rid2sd(st);
int guild_id;
@@ -17337,7 +21985,8 @@ BUILDIN(mercenary_get_faith) {
return true;
}
-BUILDIN(mercenary_set_faith) {
+static BUILDIN(mercenary_set_faith)
+{
struct map_session_data *sd = script->rid2sd(st);
int guild_id, value, *calls;
@@ -17372,7 +22021,7 @@ BUILDIN(mercenary_set_faith) {
/*------------------------------------------
* Book Reading
*------------------------------------------*/
-BUILDIN(readbook)
+static BUILDIN(readbook)
{
struct map_session_data *sd;
int book_id, page;
@@ -17391,89 +22040,214 @@ BUILDIN(readbook)
* Questlog script commands *
****************************/
-BUILDIN(questinfo)
+static BUILDIN(questinfo)
{
struct npc_data *nd = map->id2nd(st->oid);
- int quest_id, icon;
- struct questinfo qi;
+ struct questinfo qi = { 0 };
+ int icon = script_getnum(st, 2);
- if( nd == NULL || nd->bl.m == -1 )
+ if (nd == NULL)
return true;
- quest_id = script_getnum(st, 2);
- icon = script_getnum(st, 3);
-
- #if PACKETVER >= 20120410
- if(icon < 0 || (icon > 8 && icon != 9999) || icon == 7)
- icon = 9999; // Default to nothing if icon id is invalid.
- #else
- if(icon < 0 || icon > 7)
- icon = 0;
- else
- icon = icon + 1;
- #endif
-
- qi.quest_id = quest_id;
- qi.icon = (unsigned char)icon;
- qi.nd = nd;
+ if (nd->bl.m == -1) {
+ ShowWarning("buildin_questinfo: questinfo cannot be set for an npc with no valid map.\n");
+ return false;
+ }
- if (script_hasdata(st, 4)) {
- int color = script_getnum(st, 4);
+ qi.icon = quest->questinfo_validate_icon(icon);
+ if (script_hasdata(st, 3)) {
+ int color = script_getnum(st, 3);
if (color < 0 || color > 3) {
- ShowWarning("buildin_questinfo: invalid color '%d', changing to 0\n",color);
+ ShowWarning("buildin_questinfo: invalid color '%d', defaulting to 0.\n", color);
script->reportfunc(st);
color = 0;
}
qi.color = (unsigned char)color;
}
- qi.hasJob = false;
+ VECTOR_ENSURE(nd->qi_data, 1, 1);
+ VECTOR_PUSH(nd->qi_data, qi);
+ map->add_questinfo(nd->bl.m, nd);
+ return true;
+}
- if (script_hasdata(st, 5)) {
- int job = script_getnum(st, 5);
+static BUILDIN(setquestinfo)
+{
+ struct npc_data *nd = map->id2nd(st->oid);
+ struct questinfo *qi = NULL;
+ uint32 type = script_getnum(st, 2);
- if (!pc->db_checkid(job)) {
- ShowError("buildin_questinfo: Nonexistant Job Class.\n");
- } else {
- qi.hasJob = true;
- qi.job = (unsigned short)job;
+ if (nd == NULL)
+ return true;
+
+ if (nd->bl.m == -1) {
+ ShowWarning("buildin_setquestinfo: questinfo cannot be set for an npc with no valid map.\n");
+ return false;
+ }
+
+ 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:
+ {
+ int jobid = script_getnum(st, 3);
+ if (!pc->db_checkid(jobid)) {
+ ShowWarning("buildin_setquestinfo: invalid job id given (%d).\n", jobid);
+ return false;
+ }
+ qi->hasJob = true;
+ qi->job = jobid;
+ break;
+ }
+ case QINFO_SEX:
+ {
+ int sex = script_getnum(st, 3);
+ if (sex != SEX_MALE && sex != SEX_FEMALE) {
+ ShowWarning("buildin_setquestinfo: unsupported sex has been given (%d).\n", sex);
+ return false;
}
+ qi->sex_enabled = true;
+ qi->sex = sex;
+ break;
+ }
+ case QINFO_BASE_LEVEL:
+ {
+ int min = script_getnum(st, 3);
+ int max = script_getnum(st, 4);
+ if (min > max) {
+ ShowWarning("buildin_setquestinfo: minimal level (%d) is bigger than the maximal level (%d).\n", min, max);
+ return false;
+ }
+ qi->base_level.min = min;
+ qi->base_level.max = max;
+ break;
}
+ case QINFO_JOB_LEVEL:
+ {
+ int min = script_getnum(st, 3);
+ int max = script_getnum(st, 4);
+ if (min > max) {
+ ShowWarning("buildin_setquestinfo: minimal level (%d) is bigger than the maximal level (%d).\n", min, max);
+ return false;
+ }
+ qi->job_level.min = min;
+ qi->job_level.max = max;
+ break;
+ }
+ case QINFO_ITEM:
+ {
+ struct questinfo_itemreq item = { 0 };
- map->add_questinfo(nd->bl.m,&qi);
+ item.nameid = script_getnum(st, 3);
+ item.min = script_hasdata(st, 4) ? script_getnum(st, 4) : 0;
+ item.max = script_hasdata(st, 5) ? script_getnum(st, 5) : 0;
+ if (itemdb->exists(item.nameid) == NULL) {
+ ShowWarning("buildin_setquestinfo: non existing item (%d) have been given.\n", item.nameid);
+ return false;
+ }
+ if (item.min > item.max) {
+ ShowWarning("buildin_setquestinfo: minimal amount (%d) is bigger than the maximal amount (%d).\n", item.min, item.max);
+ return false;
+ }
+ if (item.min < 0 || item.min > MAX_AMOUNT) {
+ ShowWarning("buildin_setquestinfo: given amount (%d) must be bigger than or equal to 0 and smaller than %d.\n", item.min, MAX_AMOUNT + 1);
+ return false;
+ }
+ if (item.max < 0 || item.max > MAX_AMOUNT) {
+ ShowWarning("buildin_setquestinfo: given amount (%d) must be bigger than or equal to 0 and smaller than %d.\n", item.max, MAX_AMOUNT + 1);
+ return false;
+ }
+ if (VECTOR_LENGTH(qi->items) == 0)
+ VECTOR_INIT(qi->items);
+ VECTOR_ENSURE(qi->items, 1, 1);
+ VECTOR_PUSH(qi->items, item);
+ break;
+ }
+ case QINFO_HOMUN_LEVEL:
+ {
+ int min = script_getnum(st, 3);
+ if (min > battle_config.hom_max_level && min > battle_config.hom_S_max_level) {
+ ShowWarning("buildin_setquestinfo: minimum homunculus level given (%d) is bigger than the max possible level.\n", min);
+ return false;
+ }
+ qi->homunculus.level = min;
+ break;
+ }
+ case QINFO_HOMUN_TYPE:
+ {
+ int hom_type = script_getnum(st, 3);
+ if (hom_type < HT_REG || hom_type > HT_S) {
+ ShowWarning("buildin_setquestinfo: invalid homunculus type (%d).\n", hom_type);
+ return false;
+ }
+ qi->homunculus_type = hom_type;
+ break;
+ }
+ case QINFO_QUEST:
+ {
+ struct questinfo_qreq quest_req = { 0 };
+ struct quest_db *quest_data = NULL;
+
+ quest_req.id = script_getnum(st, 3);
+ quest_req.state = script_getnum(st, 4);
+
+ quest_data = quest->db(quest_req.id);
+ if (quest_data == &quest->dummy) {
+ ShowWarning("buildin_setquestinfo: invalid quest given (%d).\n", quest_req.id);
+ return false;
+ }
+ if (quest_req.state < Q_INACTIVE || quest_req.state > Q_COMPLETE) {
+ ShowWarning("buildin_setquestinfo: invalid quest state given (%d).\n", quest_req.state);
+ return false;
+ }
+
+ if (VECTOR_LENGTH(qi->quest_requirement) == 0)
+ VECTOR_INIT(qi->quest_requirement);
+ VECTOR_ENSURE(qi->quest_requirement, 1, 1);
+ VECTOR_PUSH(qi->quest_requirement, quest_req);
+ break;
+ }
+ case QINFO_MERCENARY_CLASS:
+ {
+ int mer_class = script_getnum(st, 3);
+
+ if (!mercenary->class(mer_class)) {
+ ShowWarning("buildin_setquestinfo: invalid mercenary class given (%d).\n", mer_class);
+ return false;
+ }
+ qi->mercenary_class = mer_class;
+ break;
+ }
+ default:
+ ShowWarning("buildin_setquestinfo: invalid type given (%u).\n", type);
+ return false;
+ }
return true;
}
-BUILDIN(setquest)
+static BUILDIN(setquest)
{
- unsigned short i;
int quest_id;
+ unsigned int time_limit;
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
return true;
quest_id = script_getnum(st, 2);
+ time_limit = script_hasdata(st, 3) ? script_getnum(st, 3) : 0;
- quest->add(sd, quest_id);
-
- // If questinfo is set, remove quest bubble once quest is set.
- for(i = 0; i < map->list[sd->bl.m].qi_count; i++) {
- struct questinfo *qi = &map->list[sd->bl.m].qi_data[i];
- if( qi->quest_id == quest_id ) {
-#if PACKETVER >= 20120410
- clif->quest_show_event(sd, &qi->nd->bl, 9999, 0);
-#else
- clif->quest_show_event(sd, &qi->nd->bl, 0, 0);
-#endif
- }
- }
-
+ quest->add(sd, quest_id, time_limit);
return true;
}
-BUILDIN(erasequest)
+static BUILDIN(erasequest)
{
struct map_session_data *sd = script->rid2sd(st);
@@ -17496,7 +22270,7 @@ BUILDIN(erasequest)
return true;
}
-BUILDIN(completequest)
+static BUILDIN(completequest)
{
struct map_session_data *sd = script->rid2sd(st);
@@ -17519,7 +22293,7 @@ BUILDIN(completequest)
return true;
}
-BUILDIN(changequest)
+static BUILDIN(changequest)
{
struct map_session_data *sd = script->rid2sd(st);
@@ -17530,7 +22304,7 @@ BUILDIN(changequest)
return true;
}
-BUILDIN(questactive)
+static BUILDIN(questactive)
{
struct map_session_data *sd = script->rid2sd(st);
int qid, i;
@@ -17556,7 +22330,7 @@ BUILDIN(questactive)
return true;
}
-BUILDIN(questprogress)
+static BUILDIN(questprogress)
{
struct map_session_data *sd = script->rid2sd(st);
enum quest_check_type type = HAVEQUEST;
@@ -17584,7 +22358,7 @@ BUILDIN(questprogress)
return true;
}
-BUILDIN(showevent)
+static BUILDIN(showevent)
{
struct map_session_data *sd = script->rid2sd(st);
struct npc_data *nd = map->id2nd(st->oid);
@@ -17603,24 +22377,106 @@ BUILDIN(showevent)
}
}
- #if PACKETVER >= 20120410
- if(icon < 0 || (icon > 8 && icon != 9999) || icon == 7)
- icon = 9999; // Default to nothing if icon id is invalid.
- #else
- if(icon < 0 || icon > 7)
- icon = 0;
- else
- icon = icon + 1;
- #endif
+ icon = quest->questinfo_validate_icon(icon);
clif->quest_show_event(sd, &nd->bl, icon, color);
return true;
}
/*==========================================
+ * Achievement System [Smokexyz/Hercules]
+ *-----------------------------------------*/
+/**
+ * Validates an objective index for the given achievement.
+ * Can be used for any achievement type.
+ * @command achievement_progress(<ach_id>,<obj_idx>,<progress>,<incremental?>{,<char_id>});
+ * @param aid - achievement ID
+ * @param obj_idx - achievement objective index.
+ * @param progress - objective progress towards goal.
+ * @Param incremental - (boolean) true to add the progress towards the goal,
+ * false to use the progress only as a comparand.
+ * @param account_id - (optional) character ID to perform on.
+ * @return true on success, false on failure.
+ * @push 1 on success, 0 on failure.
+ */
+static BUILDIN(achievement_progress)
+{
+ struct map_session_data *sd = script->rid2sd(st);
+ int aid = script_getnum(st, 2);
+ int obj_idx = script_getnum(st, 3);
+ int progress = script_getnum(st, 4);
+ int incremental = script_getnum(st, 5);
+ int account_id = script_hasdata(st, 6) ? script_getnum(st, 6) : 0;
+ const struct achievement_data *ad = NULL;
+
+ if ((ad = achievement->get(aid)) == NULL) {
+ ShowError("buildin_achievement_progress: Invalid achievement ID %d received.\n", aid);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ if (obj_idx <= 0 || obj_idx > VECTOR_LENGTH(ad->objective)) {
+ ShowError("buildin_achievement_progress: Invalid objective index %d received. (min: %d, max: %d)\n", obj_idx, 0, VECTOR_LENGTH(ad->objective));
+ script_pushint(st, 0);
+ return false;
+ }
+
+ obj_idx--; // convert to array index.
+
+ if (progress <= 0 || progress > VECTOR_INDEX(ad->objective, obj_idx).goal) {
+ ShowError("buildin_achievement_progress: Progress exceeds goal limit for achievement id %d.\n", aid);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ if (incremental < 0 || incremental > 1) {
+ ShowError("buildin_achievement_progress: Argument 4 expects boolean (0/1). provided value: %d\n", incremental);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ if (script_hasdata(st, 6)) {
+ if (account_id <= 0) {
+ ShowError("buildin_achievement_progress: Invalid Account id %d provided.\n", account_id);
+ script_pushint(st, 0);
+ return false;
+ } else if ((sd = map->id2sd(account_id)) == NULL) {
+ ShowError("buildin_achievement_progress: Account with id %d was not found.\n", account_id);
+ script_pushint(st, 0);
+ return false;
+ }
+ }
+
+ if (achievement->validate(sd, aid, obj_idx, progress, incremental ? true : false))
+ script_pushint(st, progress);
+ else
+ script_pushint(st, 0);
+
+ return true;
+}
+
+static BUILDIN(achievement_iscompleted)
+{
+ struct map_session_data *sd = script_hasdata(st, 3) ? map->id2sd(script_getnum(st, 3)) : script->rid2sd(st);
+ if (sd == NULL)
+ return false;
+
+ int aid = script_getnum(st, 2);
+ const struct achievement_data *ad = achievement->get(aid);
+ if (ad == NULL) {
+ ShowError("buildin_achievement_iscompleted: Invalid Achievement %d provided.\n", aid);
+ return false;
+ }
+
+ script_pushint(st, achievement->check_complete(sd, ad));
+ return true;
+}
+
+/*==========================================
* BattleGround System
*------------------------------------------*/
-BUILDIN(waitingroom2bg) {
+static BUILDIN(waitingroom2bg)
+{
struct npc_data *nd;
struct chat_data *cd;
const char *map_name, *ev = "", *dev = "";
@@ -17664,17 +22520,18 @@ BUILDIN(waitingroom2bg) {
for (i = 0; i < n && i < MAX_BG_MEMBERS; i++) {
struct map_session_data *sd = cd->usersd[i];
if (sd != NULL && bg->team_join(bg_id, sd))
- mapreg->setreg(reference_uid(script->add_str("$@arenamembers"), i), sd->bl.id);
+ mapreg->setreg(reference_uid(script->add_variable("$@arenamembers"), i), sd->bl.id);
else
- mapreg->setreg(reference_uid(script->add_str("$@arenamembers"), i), 0);
+ mapreg->setreg(reference_uid(script->add_variable("$@arenamembers"), i), 0);
}
- mapreg->setreg(script->add_str("$@arenamembersnum"), i);
+ mapreg->setreg(script->add_variable("$@arenamembersnum"), i);
script_pushint(st,bg_id);
return true;
}
-BUILDIN(waitingroom2bg_single) {
+static BUILDIN(waitingroom2bg_single)
+{
const char* map_name;
struct npc_data *nd;
struct chat_data *cd;
@@ -17707,7 +22564,7 @@ BUILDIN(waitingroom2bg_single) {
return true;
}
-BUILDIN(bg_team_setxy)
+static BUILDIN(bg_team_setxy)
{
struct battleground_data *bgd;
int bg_id;
@@ -17721,7 +22578,7 @@ BUILDIN(bg_team_setxy)
return true;
}
-BUILDIN(bg_warp)
+static BUILDIN(bg_warp)
{
int x, y, map_index, bg_id;
const char* map_name;
@@ -17736,24 +22593,35 @@ BUILDIN(bg_warp)
return true;
}
-BUILDIN(bg_monster)
+/**
+ * Spawns a mob with allegiance to the given battle group.
+ *
+ * @code{.herc}
+ * bg_monster(<battle group>, "<map name>", <x>, <y>, "<name to show>", <mob id>{, "<event label>"});
+ * @endcode
+ *
+ **/
+static BUILDIN(bg_monster)
{
- int class_ = 0, x = 0, y = 0, bg_id = 0;
- const char *str, *mapname, *evt="";
+ const char *event = "";
+
+ if (script_hasdata(st, 8)) {
+ event = script_getstr(st, 8);
+ script->check_event(st, event);
+ }
- bg_id = script_getnum(st,2);
- mapname = script_getstr(st,3);
- x = script_getnum(st,4);
- y = script_getnum(st,5);
- str = script_getstr(st,6);
- class_ = script_getnum(st,7);
- if( script_hasdata(st,8) ) evt = script_getstr(st,8);
- script->check_event(st, evt);
- script_pushint(st, mob->spawn_bg(mapname,x,y,str,class_,evt,bg_id));
+ const char *mapname = script_getstr(st, 3);
+ const char *name = script_getstr(st, 6);
+ const int bg_id = script_getnum(st, 2);
+ const int x = script_getnum(st, 4);
+ const int y = script_getnum(st, 5);
+ const int mob_id = script_getnum(st, 7);
+
+ script_pushint(st, mob->spawn_bg(mapname, x, y, name, mob_id, event, bg_id, st->oid));
return true;
}
-BUILDIN(bg_monster_set_team)
+static BUILDIN(bg_monster_set_team)
{
int id = script_getnum(st,2),
bg_id = script_getnum(st,3);
@@ -17767,12 +22635,12 @@ BUILDIN(bg_monster_set_team)
mob_stop_attack(md);
mob_stop_walking(md, STOPWALKING_FLAG_NONE);
md->target_id = md->attacked_id = 0;
- clif->charnameack(0, &md->bl);
+ clif->blname_ack(0, &md->bl);
return true;
}
-BUILDIN(bg_leave)
+static BUILDIN(bg_leave)
{
struct map_session_data *sd = script->rid2sd(st);
if( sd == NULL || !sd->bg_id )
@@ -17782,14 +22650,14 @@ BUILDIN(bg_leave)
return true;
}
-BUILDIN(bg_destroy)
+static BUILDIN(bg_destroy)
{
int bg_id = script_getnum(st,2);
bg->team_delete(bg_id);
return true;
}
-BUILDIN(bg_getareausers)
+static BUILDIN(bg_getareausers)
{
const char *str;
int16 m, x0, y0, x1, y1;
@@ -17823,7 +22691,8 @@ BUILDIN(bg_getareausers)
return true;
}
-BUILDIN(bg_updatescore) {
+static BUILDIN(bg_updatescore)
+{
const char *str;
int16 m;
@@ -17838,7 +22707,7 @@ BUILDIN(bg_updatescore) {
return true;
}
-BUILDIN(bg_get_data)
+static BUILDIN(bg_get_data)
{
struct battleground_data *bgd;
int bg_id = script_getnum(st,2),
@@ -17865,10 +22734,12 @@ BUILDIN(bg_get_data)
* Instancing Script Commands
*------------------------------------------*/
-BUILDIN(instance_create) {
+static BUILDIN(instance_create)
+{
const char *name;
int owner_id, res;
int type = IOT_PARTY;
+ struct map_session_data *sd = map->id2sd(st->rid);
name = script_getstr(st, 2);
owner_id = script_getnum(st, 3);
@@ -17881,27 +22752,49 @@ BUILDIN(instance_create) {
}
res = instance->create(owner_id, name, (enum instance_owner_type) type);
- if( res == -4 ) { // Already exists
- script_pushint(st, -1);
- return true;
- } else if( res < 0 ) {
+ if (sd != NULL) {
+ switch (res) {
+ case -4: // Already exists
+ clif->msgtable_str(sd, MSG_MDUNGEON_SUBSCRIPTION_ERROR_DUPLICATE, name);
+ break;
+ case -3: // No free instances
+ clif->msgtable_str(sd, MSG_MDUNGEON_SUBSCRIPTION_ERROR_EXIST, name);
+ break;
+ case -2: // Invalid type
+ clif->msgtable_str(sd, MSG_MDUNGEON_SUBSCRIPTION_ERROR_RIGHT, name);
+ break;
+ case -1: // Unknown
+ clif->msgtable_str(sd, MSG_MDUNGEON_SUBSCRIPTION_ERROR_UNKNOWN, name);
+ break;
+ default:
+ if (res < 0)
+ ShowError("buildin_instance_create: failed to unknown reason [%d].\n", res);
+ }
+ } else {
const char *err;
- switch(res) {
- case -3: err = "No free instances"; break;
- case -2: err = "Invalid party ID"; break;
- case -1: err = "Invalid type"; break;
- default: err = "Unknown"; break;
+ switch (res) {
+ case -3:
+ err = "No free instances";
+ break;
+ case -2:
+ err = "Invalid party ID";
+ break;
+ case -1:
+ err = "Invalid type";
+ break;
+ default:
+ err = "Unknown";
+ break;
}
- ShowError("buildin_instance_create: %s [%d].\n", err, res);
- script_pushint(st, -2);
- return true;
+ if (res < 0)
+ ShowError("buildin_instance_create: %s [%d].\n", err, res);
}
-
script_pushint(st, res);
return true;
}
-BUILDIN(instance_destroy) {
+static BUILDIN(instance_destroy)
+{
int instance_id = -1;
if( script_hasdata(st, 2) )
@@ -17919,7 +22812,7 @@ BUILDIN(instance_destroy) {
return true;
}
-BUILDIN(instance_attachmap)
+static BUILDIN(instance_attachmap)
{
const char *map_name = NULL;
int16 m;
@@ -17943,7 +22836,8 @@ BUILDIN(instance_attachmap)
return true;
}
-BUILDIN(instance_detachmap) {
+static BUILDIN(instance_detachmap)
+{
const char *str;
int16 m;
int instance_id = -1;
@@ -17964,7 +22858,7 @@ BUILDIN(instance_detachmap) {
return true;
}
-BUILDIN(instance_attach)
+static BUILDIN(instance_attach)
{
int instance_id = script_getnum(st, 2);
@@ -17975,12 +22869,13 @@ BUILDIN(instance_attach)
return true;
}
-BUILDIN(instance_id) {
+static BUILDIN(instance_id)
+{
script_pushint(st, st->instance_id);
return true;
}
-BUILDIN(instance_set_timeout)
+static BUILDIN(instance_set_timeout)
{
int progress_timeout, idle_timeout;
int instance_id = -1;
@@ -18000,7 +22895,8 @@ BUILDIN(instance_set_timeout)
return true;
}
-BUILDIN(instance_init) {
+static BUILDIN(instance_init)
+{
int instance_id = script_getnum(st, 2);
if( !instance->valid(instance_id) ) {
@@ -18017,7 +22913,8 @@ BUILDIN(instance_init) {
return true;
}
-BUILDIN(instance_announce) {
+static BUILDIN(instance_announce)
+{
int instance_id = script_getnum(st,2);
const char *mes = script_getstr(st,3);
int flag = script_getnum(st,4);
@@ -18026,8 +22923,9 @@ BUILDIN(instance_announce) {
int fontSize = script_hasdata(st,7) ? script_getnum(st,7) : 12; // default fontSize
int fontAlign = script_hasdata(st,8) ? script_getnum(st,8) : 0; // default fontAlign
int fontY = script_hasdata(st,9) ? script_getnum(st,9) : 0; // default fontY
-
int i;
+ size_t len = strlen(mes);
+ Assert_retr(false, len < INT_MAX);
if( instance_id == -1 ) {
if( st->instance_id >= 0 )
@@ -18041,12 +22939,13 @@ BUILDIN(instance_announce) {
for( i = 0; i < instance->list[instance_id].num_map; i++ )
map->foreachinmap(script->buildin_announce_sub, instance->list[instance_id].map[i], BL_PC,
- mes, strlen(mes)+1, flag&BC_COLOR_MASK, fontColor, fontType, fontSize, fontAlign, fontY);
+ mes, (int)len+1, flag&BC_COLOR_MASK, fontColor, fontType, fontSize, fontAlign, fontY);
return true;
}
-BUILDIN(instance_npcname) {
+static BUILDIN(instance_npcname)
+{
const char *str;
int instance_id = -1;
struct npc_data *nd;
@@ -18070,81 +22969,100 @@ BUILDIN(instance_npcname) {
return true;
}
-BUILDIN(has_instance) {
+static BUILDIN(has_instance)
+{
struct map_session_data *sd;
const char *str;
int16 m;
int instance_id = -1;
+ int i = 0, j = 0;
bool type = strcmp(script->getfuncname(st),"has_instance2") == 0 ? true : false;
str = script_getstr(st, 2);
- if( (m = map->mapname2mapid(str)) < 0 ) {
- if( type )
+ if ((m = map->mapname2mapid(str)) < 0) {
+ if (type) {
script_pushint(st, -1);
- else
+ } else {
script_pushconststr(st, "");
+ }
return true;
}
- if( script_hasdata(st, 3) )
+ if (script_hasdata(st, 3))
instance_id = script_getnum(st, 3);
- else if( st->instance_id >= 0 )
+ else if (st->instance_id >= 0)
instance_id = st->instance_id;
- else if( (sd = script->rid2sd(st)) != NULL ) {
+ else if ((sd = script->rid2sd(st)) != NULL) {
struct party_data *p;
- int i = 0, j = 0;
- if( sd->instances ) {
- for( i = 0; i < sd->instances; i++ ) {
- if( sd->instance[i] >= 0 ) {
+ if (sd->instances) {
+ for (i = 0; i < sd->instances; i++) {
+ if (sd->instance[i] >= 0) {
ARR_FIND(0, instance->list[sd->instance[i]].num_map, j, map->list[instance->list[sd->instance[i]].map[j]].instance_src_map == m);
- if( j != instance->list[sd->instance[i]].num_map )
+ if (j != instance->list[sd->instance[i]].num_map)
break;
}
}
- if( i != sd->instances )
+ if (i != sd->instances) {
instance_id = sd->instance[i];
+ }
}
if (instance_id == -1 && sd->status.party_id && (p = party->search(sd->status.party_id)) != NULL && p->instances) {
- for( i = 0; i < p->instances; i++ ) {
- if( p->instance[i] >= 0 ) {
+ for (i = 0; i < p->instances; i++) {
+ if (p->instance[i] >= 0) {
ARR_FIND(0, instance->list[p->instance[i]].num_map, j, map->list[instance->list[p->instance[i]].map[j]].instance_src_map == m);
- if( j != instance->list[p->instance[i]].num_map )
+ if (j != instance->list[p->instance[i]].num_map)
break;
}
}
- if( i != p->instances )
+ if (i != p->instances) {
instance_id = p->instance[i];
+ }
}
- if( instance_id == -1 && sd->guild && sd->guild->instances ) {
- for( i = 0; i < sd->guild->instances; i++ ) {
- if( sd->guild->instance[i] >= 0 ) {
+ if (instance_id == -1 && sd->guild && sd->guild->instances) {
+ for (i = 0; i < sd->guild->instances; i++) {
+ if (sd->guild->instance[i] >= 0) {
ARR_FIND(0, instance->list[sd->guild->instance[i]].num_map, j, map->list[instance->list[sd->guild->instance[i]].map[j]].instance_src_map == m);
- if( j != instance->list[sd->guild->instance[i]].num_map )
+ if (j != instance->list[sd->guild->instance[i]].num_map)
break;
}
}
- if( i != sd->guild->instances )
+ if (i != sd->guild->instances)
instance_id = sd->guild->instance[i];
}
}
- if( !instance->valid(instance_id) || (m = instance->map2imap(m, instance_id)) < 0 ) {
- if( type )
+ if (instance_id == -1) {
+ for (i = 0; i < instance->instances; i++) {
+ if (instance->list[i].state != INSTANCE_FREE && instance->list[i].owner_type == IOT_NONE && instance->list[i].num_map > 0) {
+ ARR_FIND(0, instance->list[i].num_map, j, map->list[instance->list[i].map[j]].instance_src_map == m);
+ if (j != instance->list[i].num_map)
+ break;
+ }
+ }
+ if (i != instance->instances) {
+ instance_id = instance->list[i].id;
+ }
+ }
+
+ if (!instance->valid(instance_id) || (m = instance->map2imap(m, instance_id)) < 0) {
+ if (type) {
script_pushint(st, -1);
- else
+ } else {
script_pushconststr(st, "");
+ }
return true;
}
- if( type )
+ if (type) {
script_pushint(st, instance_id);
- else
+ } else {
script_pushconststr(st, map->list[m].name);
+ }
return true;
}
-int buildin_instance_warpall_sub(struct block_list *bl, va_list ap)
+static int buildin_instance_warpall_sub(struct block_list *bl, va_list ap)
{
struct map_session_data *sd = NULL;
int map_index = va_arg(ap,int);
@@ -18159,7 +23077,9 @@ int buildin_instance_warpall_sub(struct block_list *bl, va_list ap)
return 0;
}
-BUILDIN(instance_warpall) {
+
+static BUILDIN(instance_warpall)
+{
int16 m;
int instance_id = -1;
const char *mapn;
@@ -18197,7 +23117,7 @@ BUILDIN(instance_warpall) {
* Example: instance_check_party (getcharid(1){,amount}{,min}{,max});
* Example 2: instance_check_party (getcharid(1),1,1,99);
*------------------------------------------*/
-BUILDIN(instance_check_party)
+static BUILDIN(instance_check_party)
{
int amount, min, max, i, party_id, c = 0;
struct party_data *p = NULL;
@@ -18256,7 +23176,7 @@ BUILDIN(instance_check_party)
* Example: instance_check_guild (getcharid(2){,amount}{,min}{,max});
* Example 2: instance_check_guild (getcharid(2),1,1,99);
*------------------------------------------*/
-BUILDIN(instance_check_guild)
+static BUILDIN(instance_check_guild)
{
int amount, min, max, i, guild_id, c = 0;
struct guild *g = NULL;
@@ -18308,7 +23228,7 @@ BUILDIN(instance_check_guild)
/*==========================================
* Custom Fonts
*------------------------------------------*/
-BUILDIN(setfont)
+static BUILDIN(setfont)
{
struct map_session_data *sd = script->rid2sd(st);
int font = script_getnum(st,2);
@@ -18324,7 +23244,20 @@ BUILDIN(setfont)
return true;
}
-int buildin_mobuseskill_sub(struct block_list *bl, va_list ap)
+static BUILDIN(getfont)
+{
+ struct map_session_data *sd = script->rid2sd(st);
+
+ if (sd == NULL) {
+ script_pushint(st, 0);
+ return true;
+ }
+
+ script_pushint(st, sd->status.font);
+ return true;
+}
+
+static int buildin_mobuseskill_sub(struct block_list *bl, va_list ap)
{
struct mob_data *md = NULL;
struct block_list *tbl;
@@ -18367,10 +23300,12 @@ int buildin_mobuseskill_sub(struct block_list *bl, va_list ap)
return 0;
}
+
/*==========================================
* areamobuseskill "Map Name",<x>,<y>,<range>,<Mob ID>,"Skill Name"/<Skill ID>,<Skill Lv>,<Cast Time>,<Cancelable>,<Emotion>,<Target Type>;
*------------------------------------------*/
-BUILDIN(areamobuseskill) {
+static BUILDIN(areamobuseskill)
+{
struct block_list center;
int16 m;
int range,mobid,skill_id,skill_lv,casttime,emotion,target,cancel;
@@ -18399,7 +23334,7 @@ BUILDIN(areamobuseskill) {
return true;
}
-BUILDIN(progressbar)
+static BUILDIN(progressbar)
{
struct map_session_data * sd = script->rid2sd(st);
const char * color;
@@ -18420,10 +23355,31 @@ BUILDIN(progressbar)
clif->progressbar(sd, (unsigned int)strtoul(color, (char **)NULL, 0), second);
return true;
}
+static BUILDIN(progressbar_unit)
+{
+ const char *color = script_getstr(st, 2);
+ uint32 second = script_getnum(st, 3);
+
+ if (script_hasdata(st, 4)) {
+ struct block_list *bl = map->id2bl(script_getnum(st, 4));
-BUILDIN(pushpc)
+ if (bl == NULL) {
+ ShowWarning("buildin_progressbar_unit: Error in finding object with given GID %d!\n", script_getnum(st, 4));
+ return true;
+ }
+ clif->progressbar_unit(bl, (unsigned int)strtoul(color, (char **)NULL, 0), second);
+ } else {
+ struct map_session_data *sd = script->rid2sd(st);
+
+ if (sd == NULL)
+ return false;
+
+ clif->progressbar_unit(&sd->bl, (unsigned int)strtoul(color, (char **)NULL, 0), second);
+ }
+ return true;
+}
+static BUILDIN(pushpc)
{
- uint8 dir;
int cells, dx, dy;
struct map_session_data* sd;
@@ -18432,15 +23388,14 @@ 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)
@@ -18449,10 +23404,11 @@ 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];
@@ -18462,7 +23418,7 @@ BUILDIN(pushpc)
/// Invokes buying store preparation window
/// buyingstore <slots>;
-BUILDIN(buyingstore)
+static BUILDIN(buyingstore)
{
struct map_session_data* sd;
@@ -18476,7 +23432,7 @@ BUILDIN(buyingstore)
/// Invokes search store info window
/// searchstores <uses>,<effect>;
-BUILDIN(searchstores)
+static BUILDIN(searchstores)
{
unsigned short effect;
unsigned int uses;
@@ -18507,7 +23463,7 @@ BUILDIN(searchstores)
}
/// Displays a number as large digital clock.
/// showdigit <value>[,<type>];
-BUILDIN(showdigit)
+static BUILDIN(showdigit)
{
unsigned int type = 0;
int value;
@@ -18537,7 +23493,7 @@ BUILDIN(showdigit)
/**
* Rune Knight
**/
-BUILDIN(makerune)
+static BUILDIN(makerune)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
@@ -18550,15 +23506,19 @@ BUILDIN(makerune)
/**
* hascashmount() returns 1 if mounting a cash mount or 0 otherwise
**/
-BUILDIN(hascashmount)
+static BUILDIN(hascashmount)
{
struct map_session_data *sd = script->rid2sd(st);
+
if (sd == NULL)
return true;
- if( sd->sc.data[SC_ALL_RIDING] )
- script_pushint(st,1);
- else
- script_pushint(st,0);
+
+ if (sd->sc.data[SC_ALL_RIDING]) {
+ script_pushint(st, 1);
+ } else {
+ script_pushint(st, 0);
+ }
+
return true;
}
@@ -18569,21 +23529,27 @@ BUILDIN(hascashmount)
* - Will fail if the player is already riding a standard mount e.g. dragon, peco, wug, mado, etc.
* - Will unmount the player is he is already mounting a cash mount
**/
-BUILDIN(setcashmount)
+static BUILDIN(setcashmount)
{
struct map_session_data *sd = script->rid2sd(st);
+
if (sd == NULL)
return true;
+
if (pc_hasmount(sd)) {
- clif->msgtable(sd, MSG_REINS_CANT_USE_MOUNTED);
- script_pushint(st,0);//can't mount with one of these
+#if PACKETVER >= 20110531
+ clif->msgtable(sd, MSG_FAIELD_RIDING_OVERLAPPED);
+#endif
+ script_pushint(st, 0); // Can't mount with one of these
} else {
- if (sd->sc.data[SC_ALL_RIDING])
+ if (sd->sc.data[SC_ALL_RIDING]) {
status_change_end(&sd->bl, SC_ALL_RIDING, INVALID_TIMER);
- else
- sc_start(NULL, &sd->bl, SC_ALL_RIDING, 100, 25, INFINITE_DURATION);
- script_pushint(st,1);//in both cases, return 1.
+ } else {
+ sc_start(NULL, &sd->bl, SC_ALL_RIDING, 100, battle_config.boarding_halter_speed, INFINITE_DURATION);
+ }
+ script_pushint(st, 1); // In both cases, return 1.
}
+
return true;
}
@@ -18591,7 +23557,8 @@ BUILDIN(setcashmount)
* Retrieves quantity of arguments provided to callfunc/callsub.
* getargcount() -> amount of arguments received in a function
**/
-BUILDIN(getargcount) {
+static BUILDIN(getargcount)
+{
struct script_retinfo* ri;
if( st->stack->defsp < 1 || st->stack->stack_data[st->stack->defsp - 1].type != C_RETINFO ) {
@@ -18605,16 +23572,18 @@ BUILDIN(getargcount) {
return true;
}
+
/**
* getcharip(<account ID>/<character ID>/<character name>)
**/
-BUILDIN(getcharip) {
+static BUILDIN(getcharip)
+{
struct map_session_data* sd = NULL;
/* check if a character name is specified */
if (script_hasdata(st, 2)) {
if (script_isstringtype(st, 2)) {
- sd = map->nick2sd(script_getstr(st, 2));
+ sd = map->nick2sd(script_getstr(st, 2), false);
} else {
int id = script_getnum(st, 2);
sd = (map->id2sd(id) ? map->id2sd(id) : map->charid2sd(id));
@@ -18631,45 +23600,71 @@ BUILDIN(getcharip) {
return false;
}
- /* check for IP */
- if (!sockt->session[sd->fd]->client_addr) {
+ if (sd->fd <= 0 || sockt->session[sd->fd] == NULL || sockt->session[sd->fd]->client_addr == 0) {
script_pushconststr(st, "");
- return true;
- }
-
- /* return the client ip_addr converted for output */
- if (sd && sd->fd && sockt->session[sd->fd])
- {
- /* initiliaze */
- const char *ip_addr = NULL;
- uint32 ip;
-
- /* set ip, ip_addr and convert to ip and push str */
- ip = sockt->session[sd->fd]->client_addr;
- ip_addr = sockt->ip2str(ip, NULL);
+ } else {
+ uint32 ip = sockt->session[sd->fd]->client_addr;
+ const char *ip_addr = sockt->ip2str(ip, NULL);
script_pushstrcopy(st, ip_addr);
}
return true;
}
+
+enum function_type {
+ FUNCTION_IS_NONE = 0,
+ FUNCTION_IS_COMMAND,
+ FUNCTION_IS_GLOBAL,
+ FUNCTION_IS_LOCAL,
+ FUNCTION_IS_LABEL,
+};
+
/**
- * is_function(<function name>) -> 1 if function exists, 0 otherwise
+ * is_function(<function name>)
**/
-BUILDIN(is_function) {
- const char* str = script_getstr(st,2);
+static BUILDIN(is_function)
+{
+ const char *str = script_getstr(st, 2);
+ enum function_type type = FUNCTION_IS_NONE;
- if( strdb_exists(script->userfunc_db, str) )
- script_pushint(st,1);
- else
- script_pushint(st,0);
+ // TODO: add support for exported functions (#2142)
+
+ if (strdb_exists(script->userfunc_db, str)) {
+ type = FUNCTION_IS_GLOBAL;
+ } else {
+ int n = script->search_str(str);
+ if (n >= 0) {
+ switch (script->str_data[n].type) {
+ case C_FUNC:
+ type = FUNCTION_IS_COMMAND;
+ break;
+ case C_USERFUNC:
+ case C_USERFUNC_POS:
+ type = FUNCTION_IS_LOCAL;
+ break;
+ case C_POS:
+ type = FUNCTION_IS_LABEL;
+ break;
+ case C_NAME:
+ if (script->str_data[n].label >= 0) {
+ // WTF... ?
+ // for some reason local functions can have type C_NAME
+ type = FUNCTION_IS_LOCAL;
+ }
+ }
+ }
+ }
+
+ script_pushint(st, type);
return true;
}
+
/**
* freeloop(<toggle>) -> toggles this script instance's looping-check ability
**/
-BUILDIN(freeloop) {
-
+static BUILDIN(freeloop)
+{
if( script_getnum(st,2) )
st->freeloop = 1;
else
@@ -18680,7 +23675,8 @@ BUILDIN(freeloop) {
return true;
}
-BUILDIN(sit) {
+static BUILDIN(sit)
+{
struct map_session_data *sd = NULL;
if (script_hasdata(st, 2))
@@ -18700,7 +23696,8 @@ BUILDIN(sit) {
return true;
}
-BUILDIN(stand) {
+static BUILDIN(stand)
+{
struct map_session_data *sd = NULL;
if (script_hasdata(st, 2))
@@ -18720,7 +23717,8 @@ BUILDIN(stand) {
return true;
}
-BUILDIN(issit) {
+static BUILDIN(issit)
+{
struct map_session_data *sd = NULL;
if (script_hasdata(st, 2))
@@ -18738,10 +23736,48 @@ BUILDIN(issit) {
return true;
}
+static BUILDIN(add_group_command)
+{
+ AtCommandInfo *acmd_d;
+ struct atcmd_binding_data *bcmd_d;
+ GroupSettings *group;
+ int group_index;
+ const char *atcmd = script_getstr(st, 2);
+ int group_id = script_getnum(st, 3);
+ bool self_perm = (script_getnum(st, 4) == 1);
+ bool char_perm = (script_getnum(st, 5) == 1);
+
+ if (!pcg->exists(group_id)) {
+ ShowWarning("script:add_group_command: group does not exist: %i\n", group_id);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ group = pcg->id2group(group_id);
+ group_index = pcg->get_idx(group);
+
+ if ((bcmd_d = atcommand->get_bind_byname(atcmd)) != NULL) {
+ bcmd_d->at_groups[group_index] = self_perm;
+ bcmd_d->char_groups[group_index] = char_perm;
+ script_pushint(st, 1);
+ return true;
+ } else if ((acmd_d = atcommand->get_info_byname(atcmd)) != NULL) {
+ acmd_d->at_groups[group_index] = self_perm;
+ acmd_d->char_groups[group_index] = char_perm;
+ script_pushint(st, 1);
+ return true;
+ }
+
+ ShowWarning("script:add_group_command: command does not exist: %s\n", atcmd);
+ script_pushint(st, 0);
+ return false;
+}
+
/**
* @commands (script based)
**/
-BUILDIN(bindatcmd) {
+static BUILDIN(bindatcmd)
+{
const char* atcmd;
const char* eventName;
int i, group_lv = 0, group_lv_char = 99;
@@ -18786,12 +23822,15 @@ BUILDIN(bindatcmd) {
atcommand->binding[i]->group_lv = group_lv;
atcommand->binding[i]->group_lv_char = group_lv_char;
atcommand->binding[i]->log = log;
+ CREATE(atcommand->binding[i]->at_groups, char, db_size(pcg->db));
+ CREATE(atcommand->binding[i]->char_groups, char, db_size(pcg->db));
}
return true;
}
-BUILDIN(unbindatcmd) {
+static BUILDIN(unbindatcmd)
+{
const char* atcmd;
int i = 0;
@@ -18808,6 +23847,8 @@ BUILDIN(unbindatcmd) {
ARR_FIND(0, atcommand->binding_count, i, strcmp(atcommand->binding[i]->command, atcmd) == 0);
if( i < atcommand->binding_count ) {
int cursor = 0;
+ aFree(atcommand->binding[i]->at_groups);
+ aFree(atcommand->binding[i]->char_groups);
aFree(atcommand->binding[i]);
atcommand->binding[i] = NULL;
/* compact the list now that we freed a slot somewhere */
@@ -18832,7 +23873,8 @@ BUILDIN(unbindatcmd) {
return true;
}
-BUILDIN(useatcmd) {
+static BUILDIN(useatcmd)
+{
struct map_session_data *sd, *dummy_sd = NULL;
int fd;
const char* cmd;
@@ -18869,70 +23911,70 @@ BUILDIN(useatcmd) {
return true;
}
-BUILDIN(checkre)
+static BUILDIN(has_permission)
{
- int num;
+ struct map_session_data *sd;
+ enum e_pc_permission perm;
- num=script_getnum(st,2);
- switch(num) {
- case 0:
-#ifdef RENEWAL
- script_pushint(st, 1);
-#else
- script_pushint(st, 0);
-#endif
- break;
- case 1:
-#ifdef RENEWAL_CAST
- script_pushint(st, 1);
-#else
- script_pushint(st, 0);
-#endif
- break;
- case 2:
-#ifdef RENEWAL_DROP
- script_pushint(st, 1);
-#else
- script_pushint(st, 0);
-#endif
- break;
- case 3:
-#ifdef RENEWAL_EXP
- script_pushint(st, 1);
-#else
- script_pushint(st, 0);
-#endif
- break;
- case 4:
-#ifdef RENEWAL_LVDMG
- script_pushint(st, 1);
-#else
- script_pushint(st, 0);
-#endif
- break;
- case 5:
-#ifdef RENEWAL_EDP
- script_pushint(st, 1);
-#else
- script_pushint(st, 0);
-#endif
- break;
- case 6:
-#ifdef RENEWAL_ASPD
- script_pushint(st, 1);
-#else
+ if (script_hasdata(st, 3)) {
+ sd = map->id2sd(script_getnum(st, 3));
+ } else {
+ sd = script->rid2sd(st);
+ }
+
+ if (sd == NULL) {
+ script_pushint(st, 0);
+ return false;
+ }
+
+ if (script_isstringtype(st, 2)) {
+ // to check for plugin permissions
+ int i = 0, j = -1;
+ const char *name = script_getstr(st, 2);
+ for (; i < pcg->permission_count; ++i) {
+ if (strcmp(pcg->permissions[i].name, name) == 0) {
+ j = i;
+ break;
+ }
+ }
+ if (j < 0) {
+ ShowError("script:has_permission: unknown permission: %s\n", name);
script_pushint(st, 0);
-#endif
- break;
- default:
- ShowWarning("buildin_checkre: unknown parameter.\n");
- break;
+ return false;
+ }
+ script_pushint(st, pc_has_permission(sd, pcg->permissions[j].permission));
+ return true;
}
+
+ // to ckeck for built-in permission
+ perm = script_getnum(st, 2);
+ script_pushint(st, pc_has_permission(sd, perm));
+ return true;
+}
+
+static BUILDIN(can_use_command)
+{
+ struct map_session_data *sd;
+ const char *cmd = script_getstr(st, 2);
+
+ if (script_hasdata(st, 3)) {
+ sd = map->id2sd(script_getnum(st, 3));
+ } else {
+ sd = script->rid2sd(st);
+ }
+
+ if (sd == NULL) {
+ script_pushint(st, 0);
+ return false;
+ }
+
+ script_pushint(st, pc->can_use_command(sd, cmd));
return true;
}
/* getrandgroupitem <container_item_id>,<quantity> */
-BUILDIN(getrandgroupitem) {
+static BUILDIN(getrandgroupitem)
+{
struct item_data *data = NULL;
struct map_session_data *sd = NULL;
int nameid = script_getnum(st, 2);
@@ -18972,7 +24014,7 @@ BUILDIN(getrandgroupitem) {
if ((flag = pc->additem(sd, &it, get_count, LOG_TYPE_SCRIPT))) {
clif->additem(sd, 0, 0, flag);
if( pc->candrop(sd,&it) )
- map->addflooritem(&sd->bl, &it, get_count, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0);
+ map->addflooritem(&sd->bl, &it, get_count, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0, false);
}
}
}
@@ -18985,14 +24027,14 @@ BUILDIN(getrandgroupitem) {
/* cleanmap <map_name>;
* cleanarea <map_name>, <x0>, <y0>, <x1>, <y1>; */
-int script_cleanfloor_sub(struct block_list *bl, va_list ap) {
- nullpo_ret(bl);
+static int script_cleanfloor_sub(struct block_list *bl, va_list ap)
+{
map->clearflooritem(bl);
return 0;
}
-BUILDIN(cleanmap)
+static BUILDIN(cleanmap)
{
const char *mapname = script_getstr(st, 2);
int16 m = map->mapname2mapid(mapname);
@@ -19017,10 +24059,11 @@ BUILDIN(cleanmap)
return true;
}
+
/* Cast a skill on the attached player.
* npcskill <skill id>, <skill lvl>, <stat point>, <NPC level>;
* npcskill "<skill name>", <skill lvl>, <stat point>, <NPC level>; */
-BUILDIN(npcskill)
+static BUILDIN(npcskill)
{
struct npc_data *nd;
uint16 skill_id = script_isstringtype(st, 2) ? skill->name2id(script_getstr(st, 2)) : script_getnum(st, 2);
@@ -19066,7 +24109,8 @@ BUILDIN(npcskill)
/* Turns a player into a monster and grants SC attribute effect. [malufett/Hercules]
* montransform <monster name/id>, <duration>, <sc type>, <val1>, <val2>, <val3>, <val4>; */
-BUILDIN(montransform) {
+static BUILDIN(montransform)
+{
int tick;
enum sc_type type;
struct block_list* bl;
@@ -19149,7 +24193,7 @@ BUILDIN(montransform) {
*
* @return The queue, or NULL if it doesn't exist.
*/
-struct script_queue *script_hqueue_get(int idx)
+static struct script_queue *script_hqueue_get(int idx)
{
if (idx < 0 || idx >= VECTOR_LENGTH(script->hq) || !VECTOR_INDEX(script->hq, idx).valid)
return NULL;
@@ -19161,7 +24205,7 @@ struct script_queue *script_hqueue_get(int idx)
*
* @return The index of the created queue.
*/
-int script_hqueue_create(void)
+static int script_hqueue_create(void)
{
struct script_queue *queue = NULL;
int i;
@@ -19188,7 +24232,7 @@ int script_hqueue_create(void)
* .@queue_id = queue();
* @endcode
*/
-BUILDIN(queue)
+static BUILDIN(queue)
{
script_pushint(st,script->queue_create());
return true;
@@ -19203,7 +24247,7 @@ BUILDIN(queue)
* .@size = queuesize(<queue id>);
* \endcode
*/
-BUILDIN(queuesize)
+static BUILDIN(queuesize)
{
int idx = script_getnum(st, 2);
@@ -19225,7 +24269,7 @@ BUILDIN(queuesize)
* @retval false if the queue is invalid or the entry is already in the queue.
* @retval true in case of success.
*/
-bool script_hqueue_add(int idx, int var)
+static bool script_hqueue_add(int idx, int var)
{
int i;
struct map_session_data *sd = NULL;
@@ -19263,7 +24307,7 @@ bool script_hqueue_add(int idx, int var)
* .@size = queuesize(.@queue_id);
* @endcode
*/
-BUILDIN(queueadd)
+static BUILDIN(queueadd)
{
int idx = script_getnum(st, 2);
int var = script_getnum(st, 3);
@@ -19284,7 +24328,7 @@ BUILDIN(queueadd)
* @retval true if the entry was removed.
* @retval false if the entry wasn't in queue.
*/
-bool script_hqueue_remove(int idx, int var)
+static bool script_hqueue_remove(int idx, int var)
{
int i;
struct map_session_data *sd = NULL;
@@ -19321,7 +24365,7 @@ bool script_hqueue_remove(int idx, int var)
* queueremove(.@queue_id, .@value);
* @endcode
*/
-BUILDIN(queueremove)
+static BUILDIN(queueremove)
{
int idx = script_getnum(st, 2);
int var = script_getnum(st, 3);
@@ -19337,7 +24381,7 @@ BUILDIN(queueremove)
/**
* Script command queueopt: Modifies the options of a queue.
*
- * When the option value isn't provided, the option is removed.
+ * When the <event label> isn't provided, the option is removed.
*
* Returns 1 (true) on success, 0 (false) on failure.
*
@@ -19347,13 +24391,13 @@ BUILDIN(queueremove)
* - QUEUEOPT_MAPCHANGE
*
* When the QUEUEOPT_MAPCHANGE event is triggered, it sets a temporary
- * character variable \c @Queue_Destination_Map$ with the destination map name.
+ * character variable @Queue_Destination_Map$ with the destination map name.
*
* @code{.herc}
- * queueopt(.@queue_id, optionType, <optional val>);
+ * queueopt(.@queue_id, optionType{, <event label>});
* @endcode
*/
-BUILDIN(queueopt)
+static BUILDIN(queueopt)
{
int idx = script_getnum(st, 2);
int var = script_getnum(st, 3);
@@ -19403,7 +24447,7 @@ BUILDIN(queueopt)
* @retval true if the queue was correctly deleted.
* @retval false if the queue didn't exist.
*/
-bool script_hqueue_del(int idx)
+static bool script_hqueue_del(int idx)
{
if (!script->queue_clear(idx))
return false;
@@ -19422,7 +24466,7 @@ bool script_hqueue_del(int idx)
* queuedel(.@queue_id);
* @endcode
*/
-BUILDIN(queuedel)
+static BUILDIN(queuedel)
{
int idx = script_getnum(st, 2);
@@ -19442,7 +24486,7 @@ BUILDIN(queuedel)
* @retval true if the queue was correctly cleared.
* @retval false if the queue didn't exist.
*/
-bool script_hqueue_clear(int idx)
+static bool script_hqueue_clear(int idx)
{
struct script_queue *queue = NULL;
@@ -19479,7 +24523,7 @@ bool script_hqueue_clear(int idx)
* .@id = queueiterator(.@queue_id);
* @endcode
*/
-BUILDIN(queueiterator)
+static BUILDIN(queueiterator)
{
int qid = script_getnum(st, 2);
struct script_queue *queue = NULL;
@@ -19522,7 +24566,7 @@ BUILDIN(queueiterator)
* }
* @endcode
*/
-BUILDIN(qiget)
+static BUILDIN(qiget)
{
int idx = script_getnum(st, 2);
struct script_queue_iterator *it = NULL;
@@ -19556,7 +24600,7 @@ BUILDIN(qiget)
* }
* @endcode
*/
-BUILDIN(qicheck)
+static BUILDIN(qicheck)
{
int idx = script_getnum(st, 2);
struct script_queue_iterator *it = NULL;
@@ -19587,7 +24631,7 @@ BUILDIN(qicheck)
* qiclear(.@iter);
* @endcode
*/
-BUILDIN(qiclear)
+static BUILDIN(qiclear)
{
int idx = script_getnum(st, 2);
struct script_queue_iterator *it = NULL;
@@ -19612,7 +24656,8 @@ BUILDIN(qiclear)
* packageitem({<optional container_item_id>})
* when no item id is provided it tries to assume it comes from the current item id being processed (if any)
**/
-BUILDIN(packageitem) {
+static BUILDIN(packageitem)
+{
struct item_data *data = NULL;
struct map_session_data *sd = NULL;
int nameid;
@@ -19646,7 +24691,8 @@ BUILDIN(packageitem) {
/* New Battlegrounds Stuff */
/* bg_team_create(map_name,respawn_x,respawn_y) */
/* returns created team id or -1 when fails */
-BUILDIN(bg_create_team) {
+static BUILDIN(bg_create_team)
+{
const char *map_name, *ev = "", *dev = "";//ev and dev will be dropped.
int x, y, map_index = 0, bg_id;
@@ -19654,7 +24700,7 @@ BUILDIN(bg_create_team) {
if( strcmp(map_name,"-") != 0 ) {
map_index = script->mapindexname2id(st,map_name);
if( map_index == 0 ) { // Invalid Map
- script_pushint(st,0);
+ script_pushint(st, -1);
return true;
}
}
@@ -19673,7 +24719,8 @@ BUILDIN(bg_create_team) {
/* bg_join_team(team_id{,optional account id}) */
/* when account id is not present it tries to autodetect from the attached player (if any) */
/* returns 0 when successful, 1 otherwise */
-BUILDIN(bg_join_team) {
+static BUILDIN(bg_join_team)
+{
struct map_session_data *sd;
int team_id = script_getnum(st, 2);
@@ -19699,9 +24746,9 @@ BUILDIN(bg_join_team) {
* 3 - Party Bound
* 4 - Character Bound
*------------------------------------------*/
-BUILDIN(countbound)
+static BUILDIN(countbound)
{
- int i, type, j=0, k=0;
+ int type, j=0, k=0;
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
@@ -19709,12 +24756,12 @@ BUILDIN(countbound)
type = script_hasdata(st,2)?script_getnum(st,2):0;
- for(i=0;i<MAX_INVENTORY;i++) {
+ for (int i = 0; i < sd->status.inventorySize; i++) {
if(sd->status.inventory[i].nameid > 0 && (
(!type && sd->status.inventory[i].bound > 0) ||
(type && sd->status.inventory[i].bound == type)
)) {
- pc->setreg(sd,reference_uid(script->add_str("@bound_items"), k),sd->status.inventory[i].nameid);
+ pc->setreg(sd,reference_uid(script->add_variable("@bound_items"), k),sd->status.inventory[i].nameid);
k++;
j += sd->status.inventory[i].amount;
}
@@ -19734,7 +24781,7 @@ BUILDIN(countbound)
* 3 - Party Bound
* 4 - Character Bound
*------------------------------------------*/
-BUILDIN(checkbound)
+static BUILDIN(checkbound)
{
int i, nameid = script_getnum(st,2);
int bound_type = 0;
@@ -19755,27 +24802,28 @@ BUILDIN(checkbound)
ShowError("script_checkbound: Not a valid bind type! Type=%d\n", bound_type);
}
- ARR_FIND( 0, MAX_INVENTORY, i, (sd->status.inventory[i].nameid == nameid &&
+ ARR_FIND(0, sd->status.inventorySize, i, (sd->status.inventory[i].nameid == nameid &&
( sd->status.inventory[i].refine == (script_hasdata(st,4)? script_getnum(st,4) : sd->status.inventory[i].refine) ) &&
( sd->status.inventory[i].attribute == (script_hasdata(st,5)? script_getnum(st,5) : sd->status.inventory[i].attribute) ) &&
( sd->status.inventory[i].card[0] == (script_hasdata(st,6)? script_getnum(st,6) : sd->status.inventory[i].card[0]) ) &&
( sd->status.inventory[i].card[1] == (script_hasdata(st,7)? script_getnum(st,7) : sd->status.inventory[i].card[1]) ) &&
( sd->status.inventory[i].card[2] == (script_hasdata(st,8)? script_getnum(st,8) : sd->status.inventory[i].card[2]) ) &&
( sd->status.inventory[i].card[3] == (script_hasdata(st,9)? script_getnum(st,9) : sd->status.inventory[i].card[3]) ) &&
- ((sd->status.inventory[i].bound > 0 && !bound_type) || sd->status.inventory[i].bound == bound_type )) );
+ ((sd->status.inventory[i].bound > 0 && !bound_type) || sd->status.inventory[i].bound == bound_type)));
- if( i < MAX_INVENTORY ){
+ if (i < sd->status.inventorySize) {
script_pushint(st, sd->status.inventory[i].bound);
return true;
- } else
+ } else {
script_pushint(st,0);
+ }
return true;
}
/* bg_match_over( arena_name {, optional canceled } ) */
/* returns 0 when successful, 1 otherwise */
-BUILDIN(bg_match_over)
+static BUILDIN(bg_match_over)
{
bool canceled = script_hasdata(st,3) ? true : false;
struct bg_arena *arena = bg->name2arena(script_getstr(st, 2));
@@ -19789,7 +24837,8 @@ BUILDIN(bg_match_over)
return true;
}
-BUILDIN(instance_mapname) {
+static BUILDIN(instance_mapname)
+{
const char *map_name;
int m;
short instance_id = -1;
@@ -19809,10 +24858,12 @@ BUILDIN(instance_mapname) {
return true;
}
+
/* modify an instances' reload-spawn point */
/* instance_set_respawn <map_name>,<x>,<y>{,<instance_id>} */
/* returns 1 when successful, 0 otherwise. */
-BUILDIN(instance_set_respawn) {
+static BUILDIN(instance_set_respawn)
+{
const char *map_name;
short instance_id = -1;
short mid;
@@ -19853,12 +24904,13 @@ BUILDIN(instance_set_respawn) {
}
return true;
}
+
/**
* @call openshop({NPC Name});
*
* @return 1 on success, 0 otherwise.
**/
-BUILDIN(openshop)
+static BUILDIN(openshop)
{
struct npc_data *nd;
struct map_session_data *sd;
@@ -19888,17 +24940,147 @@ BUILDIN(openshop)
return true;
}
+
+static bool script_sellitemcurrency_add(struct npc_data *nd, struct script_state* st, int argIndex)
+{
+ nullpo_retr(false, nd);
+ nullpo_retr(false, st);
+
+ if (!script_hasdata(st, argIndex + 1))
+ return false;
+
+ int id = script_getnum(st, argIndex);
+ struct item_data *it;
+ if (!(it = itemdb->exists(id))) {
+ ShowWarning("buildin_sellitemcurrency: unknown item id '%d'!\n", id);
+ return false;
+ }
+ int qty = 0;
+ if ((qty = script_getnum(st, argIndex + 1)) <= 0) {
+ ShowError("buildin_sellitemcurrency: invalid 'qty'!\n");
+ return false;
+ }
+ int refine_level = -1;
+ if (script_hasdata(st, argIndex + 2)) {
+ refine_level = script_getnum(st, argIndex + 2);
+ }
+ int items = nd->u.scr.shop->items;
+ if (nd->u.scr.shop == NULL || items == 0) {
+ ShowWarning("buildin_sellitemcurrency: shop not have items!\n");
+ return false;
+ }
+ if (nd->u.scr.shop->shop_last_index >= items || nd->u.scr.shop->shop_last_index < 0) {
+ ShowWarning("buildin_sellitemcurrency: wrong selected shop index!\n");
+ return false;
+ }
+
+ struct npc_item_list *item_list = &nd->u.scr.shop->item[nd->u.scr.shop->shop_last_index];
+ int index = item_list->value2;
+ if (item_list->currency == NULL) {
+ CREATE(item_list->currency, struct npc_barter_currency, 1);
+ item_list->value2 ++;
+ } else {
+ RECREATE(item_list->currency, struct npc_barter_currency, ++item_list->value2);
+ }
+ struct npc_barter_currency *currency = &item_list->currency[index];
+ currency->nameid = id;
+ currency->refine = refine_level;
+ currency->amount = qty;
+ return true;
+}
+
+/**
+ * @call sellitemcurrency <Item_ID>,qty{,refine}};
+ *
+ * adds <Item_ID> to last item in expanded barter shop
+ **/
+static BUILDIN(sellitemcurrency)
+{
+ struct npc_data *nd;
+ if ((nd = map->id2nd(st->oid)) == NULL) {
+ ShowWarning("buildin_sellitemcurrency: trying to run without a proper NPC!\n");
+ return false;
+ }
+ if (nd->u.scr.shop == NULL || nd->u.scr.shop->type != NST_EXPANDED_BARTER) {
+ ShowWarning("buildin_sellitemcurrency: this command can be used only with expanded barter shops!\n");
+ return false;
+ }
+
+ script->sellitemcurrency_add(nd, st, 2);
+ return true;
+}
+
+/**
+ * @call endsellitem;
+ *
+ * complete sell item in expanded barter shop (NST_EXPANDED_BARTER)
+ **/
+static BUILDIN(endsellitem)
+{
+ struct npc_data *nd;
+ if ((nd = map->id2nd(st->oid)) == NULL) {
+ ShowWarning("buildin_endsellitem: trying to run without a proper NPC!\n");
+ return false;
+ }
+ if (nd->u.scr.shop == NULL || nd->u.scr.shop->type != NST_EXPANDED_BARTER) {
+ ShowWarning("buildin_endsellitem: this command can be used only with expanded barter shops!\n");
+ return false;
+ }
+
+ int newIndex = nd->u.scr.shop->shop_last_index;
+ const struct npc_item_list *const newItem = &nd->u.scr.shop->item[newIndex];
+ int i = 0;
+ for (i = 0; i < nd->u.scr.shop->items - 1; i++) {
+ const struct npc_item_list *const item = &nd->u.scr.shop->item[i];
+ if (item->nameid != newItem->nameid || item->value != newItem->value)
+ continue;
+ if (item->value2 != newItem->value2)
+ continue;
+ bool found = true;
+ for (int k = 0; k < item->value2; k ++) {
+ struct npc_barter_currency *currency = &item->currency[k];
+ struct npc_barter_currency *newCurrency = &newItem->currency[k];
+ if (currency->nameid != newCurrency->nameid ||
+ currency->amount != newCurrency->amount ||
+ currency->refine != newCurrency->refine) {
+ found = false;
+ break;
+ }
+ }
+ if (!found)
+ continue;
+ break;
+ }
+
+ if (i != nd->u.scr.shop->items - 1) {
+ if (nd->u.scr.shop->item[i].qty != -1) {
+ nd->u.scr.shop->item[i].qty += nd->u.scr.shop->item[newIndex].qty;
+ npc->expanded_barter_tosql(nd, i);
+ }
+ nd->u.scr.shop->shop_last_index --;
+ nd->u.scr.shop->items--;
+ if (nd->u.scr.shop->item[newIndex].currency != NULL) {
+ aFree(nd->u.scr.shop->item[newIndex].currency);
+ nd->u.scr.shop->item[newIndex].currency = NULL;
+ }
+ }
+
+ return true;
+}
+
/**
* @call sellitem <Item_ID>,{,price{,qty}};
*
* adds <Item_ID> (or modifies if present) to shop
* if price not provided (or -1) uses the item's value_sell
**/
-BUILDIN(sellitem) {
+static BUILDIN(sellitem)
+{
struct npc_data *nd;
struct item_data *it;
int i = 0, id = script_getnum(st,2);
int value = 0;
+ int value2 = 0;
int qty = 0;
if( !(nd = map->id2nd(st->oid)) ) {
@@ -19909,16 +25091,71 @@ BUILDIN(sellitem) {
return false;
}
- value = script_hasdata(st,3) ? script_getnum(st, 3) : it->value_buy;
- if( value == -1 )
- value = it->value_buy;
+ const bool have_shop = (nd->u.scr.shop != NULL);
+ if (!have_shop) {
+ npc->trader_update(nd->src_id ? nd->src_id : nd->bl.id);
+ }
- if( !nd->u.scr.shop )
- npc->trader_update(nd->src_id?nd->src_id:nd->bl.id);
- else {/* no need to run this if its empty */
- for( i = 0; i < nd->u.scr.shop->items; i++ ) {
- if( nd->u.scr.shop->item[i].nameid == id )
+ if (nd->u.scr.shop->type != NST_BARTER) {
+ value = script_hasdata(st, 3) ? script_getnum(st, 3) : it->value_buy;
+ if (value == -1)
+ value = it->value_buy;
+ }
+
+ if (nd->u.scr.shop->type == NST_BARTER) {
+ if (!script_hasdata(st, 5)) {
+ ShowError("buildin_sellitem: invalid number of parameters for barter-type shop!\n");
+ return false;
+ }
+ value = script_getnum(st, 4);
+ value2 = script_getnum(st, 5);
+ } else if (nd->u.scr.shop->type == NST_EXPANDED_BARTER) {
+ if (!script_hasdata(st, 4)) {
+ ShowError("buildin_sellitem: invalid number of parameters for expanded barter type shop!\n");
+ return false;
+ }
+ if ((qty = script_getnum(st, 4)) <= 0 && qty != -1) {
+ ShowError("buildin_sellitem: invalid 'qty' for expanded barter type shop!\n");
+ return false;
+ }
+ }
+
+ if (have_shop) {
+ if (nd->u.scr.shop->type == NST_BARTER) {
+ for (i = 0; i < nd->u.scr.shop->items; i++) {
+ const struct npc_item_list *const item = &nd->u.scr.shop->item[i];
+ if (item->nameid == id && item->value == value && item->value2 == value2) {
+ break;
+ }
+ }
+ } else if (nd->u.scr.shop->type == NST_EXPANDED_BARTER) {
+ for (i = 0; i < nd->u.scr.shop->items; i++) {
+ const struct npc_item_list *const item = &nd->u.scr.shop->item[i];
+ if (item->nameid != id || item->value != value)
+ continue;
+ if (item->value2 != (script_lastdata(st) - 4) / 3)
+ continue;
+ bool found = true;
+ for (int k = 0; k < item->value2; k ++) {
+ const int scriptOffset = k * 3 + 5;
+ struct npc_barter_currency *currency = &item->currency[k];
+ if (currency->nameid != script_getnum(st, scriptOffset) ||
+ currency->amount != script_getnum(st, scriptOffset + 1) ||
+ currency->refine != script_getnum(st, scriptOffset + 2)) {
+ found = false;
+ break;
+ }
+ }
+ if (!found)
+ continue;
break;
+ }
+ } else {
+ for (i = 0; i < nd->u.scr.shop->items; i++) {
+ if (nd->u.scr.shop->item[i].nameid == id) {
+ break;
+ }
+ }
}
}
@@ -19934,19 +25171,30 @@ BUILDIN(sellitem) {
it->name, id, value, (int)(value*0.75), it->value_sell, (int)(it->value_sell*1.24), nd->exname, nd->path);
}
- if( i != nd->u.scr.shop->items ) {
+ if (nd->u.scr.shop->type == NST_BARTER) {
+ qty = script_getnum(st, 3);
+ if (qty < -1 || value <= 0 || value2 <= 0) {
+ ShowError("buildin_sellitem: invalid parameters for barter-type shop!\n");
+ return false;
+ }
+ }
+
+ bool foundInShop = (i != nd->u.scr.shop->items);
+ if (foundInShop) {
nd->u.scr.shop->item[i].value = value;
nd->u.scr.shop->item[i].qty = qty;
- if( nd->u.scr.shop->type == NST_MARKET ) /* has been manually updated, make it reflect on sql */
- npc->market_tosql(nd,i);
+ if (nd->u.scr.shop->type == NST_MARKET) /* has been manually updated, make it reflect on sql */
+ npc->market_tosql(nd, i);
+ else if (nd->u.scr.shop->type == NST_BARTER) /* has been manually updated, make it reflect on sql */
+ npc->barter_tosql(nd, i);
} else {
- for( i = 0; i < nd->u.scr.shop->items; i++ ) {
- if( nd->u.scr.shop->item[i].nameid == 0 )
+ for (i = 0; i < nd->u.scr.shop->items; i++) {
+ if (nd->u.scr.shop->item[i].nameid == 0)
break;
}
- if( i == nd->u.scr.shop->items ) {
- if( nd->u.scr.shop->items == USHRT_MAX ) {
+ if (i == nd->u.scr.shop->items) {
+ if (nd->u.scr.shop->items == USHRT_MAX) {
ShowWarning("buildin_sellitem: Can't add %s (%s/%s), shop list is full!\n", it->name, nd->exname, nd->path);
return false;
}
@@ -19956,11 +25204,89 @@ BUILDIN(sellitem) {
nd->u.scr.shop->item[i].nameid = it->nameid;
nd->u.scr.shop->item[i].value = value;
+ nd->u.scr.shop->item[i].value2 = value2;
nd->u.scr.shop->item[i].qty = qty;
+ nd->u.scr.shop->item[i].currency = NULL;
+ }
+ nd->u.scr.shop->shop_last_index = i;
+
+ if (!foundInShop) {
+ for (int k = 5; k <= script_lastdata(st); k += 3) {
+ script->sellitemcurrency_add(nd, st, k);
+ }
}
+ if (foundInShop) {
+ if (nd->u.scr.shop->type == NST_EXPANDED_BARTER) { /* has been manually updated, make it reflect on sql */
+ npc->expanded_barter_tosql(nd, i);
+ }
+ }
return true;
}
+
+/**
+ * @call startsellitem <Item_ID>,{,price{,qty}};
+ *
+ * Starts adding item into expanded barter shop (NST_EXPANDED_BARTER)
+ **/
+static BUILDIN(startsellitem)
+{
+ struct npc_data *nd;
+ struct item_data *it;
+ int i = 0, id = script_getnum(st,2);
+ int value2 = 0;
+ int qty = 0;
+
+ if (!(nd = map->id2nd(st->oid))) {
+ ShowWarning("buildin_startsellitem: trying to run without a proper NPC!\n");
+ return false;
+ } else if (!(it = itemdb->exists(id))) {
+ ShowWarning("buildin_startsellitem: unknown item id '%d'!\n", id);
+ return false;
+ }
+
+ const bool have_shop = (nd->u.scr.shop != NULL);
+ if (!have_shop) {
+ npc->trader_update(nd->src_id ? nd->src_id : nd->bl.id);
+ }
+
+ if (nd->u.scr.shop->type != NST_EXPANDED_BARTER) {
+ ShowWarning("script_startsellitem: can works only for NST_EXPANDED_BARTER shops");
+ return false;
+ }
+
+ int value = script_hasdata(st, 3) ? script_getnum(st, 3) : it->value_buy;
+ if (value == -1)
+ value = it->value_buy;
+
+ if ((qty = script_getnum(st, 4)) <= 0 && qty != -1) {
+ ShowError("buildin_startsellitem: invalid 'qty' for expanded barter type shop!\n");
+ return false;
+ }
+
+ for (i = 0; i < nd->u.scr.shop->items; i++) {
+ if (nd->u.scr.shop->item[i].nameid == 0)
+ break;
+ }
+
+ if (i == nd->u.scr.shop->items) {
+ if (nd->u.scr.shop->items == USHRT_MAX) {
+ ShowWarning("buildin_startsellitem: Can't add %s (%s/%s), shop list is full!\n", it->name, nd->exname, nd->path);
+ return false;
+ }
+ i = nd->u.scr.shop->items;
+ RECREATE(nd->u.scr.shop->item, struct npc_item_list, ++nd->u.scr.shop->items);
+ }
+
+ nd->u.scr.shop->item[i].nameid = it->nameid;
+ nd->u.scr.shop->item[i].value = value;
+ nd->u.scr.shop->item[i].value2 = value2;
+ nd->u.scr.shop->item[i].qty = qty;
+ nd->u.scr.shop->item[i].currency = NULL;
+ nd->u.scr.shop->shop_last_index = i;
+ return true;
+}
+
/**
* @call stopselling <Item_ID>;
*
@@ -19968,56 +25294,100 @@ BUILDIN(sellitem) {
*
* @return 1 on success, 0 otherwise
**/
-BUILDIN(stopselling) {
+static BUILDIN(stopselling)
+{
struct npc_data *nd;
- int i, id = script_getnum(st,2);
+ int i, id = script_getnum(st, 2);
- if( !(nd = map->id2nd(st->oid)) || !nd->u.scr.shop ) {
+ if (!(nd = map->id2nd(st->oid)) || !nd->u.scr.shop) {
ShowWarning("buildin_stopselling: trying to run without a proper NPC!\n");
return false;
}
- for( i = 0; i < nd->u.scr.shop->items; i++ ) {
- if( nd->u.scr.shop->item[i].nameid == id )
- break;
+ if (nd->u.scr.shop->type == NST_BARTER) {
+ if (!script_hasdata(st, 4)) {
+ ShowError("buildin_stopselling: called with wrong number of arguments\n");
+ return false;
+ }
+ const int id2 = script_getnum(st, 3);
+ const int amount2 = script_getnum(st, 4);
+ for (i = 0; i < nd->u.scr.shop->items; i++) {
+ const struct npc_item_list *const item = &nd->u.scr.shop->item[i];
+ if (item->nameid == id && item->value == id2 && item->value2 == amount2) {
+ break;
+ }
+ }
+ } else if (nd->u.scr.shop->type == NST_EXPANDED_BARTER) {
+ if (!script_hasdata(st, 3)) {
+ ShowError("buildin_stopselling: called with wrong number of arguments\n");
+ return false;
+ }
+ const int price = script_getnum(st, 3);
+ for (i = 0; i < nd->u.scr.shop->items; i++) {
+ const struct npc_item_list *const item = &nd->u.scr.shop->item[i];
+ if (item->nameid == id && item->value == price) {
+ break;
+ }
+ }
+ } else {
+ for (i = 0; i < nd->u.scr.shop->items; i++) {
+ if (nd->u.scr.shop->item[i].nameid == id) {
+ break;
+ }
+ }
}
- if( i != nd->u.scr.shop->items ) {
+ if (i != nd->u.scr.shop->items) {
int cursor;
- if( nd->u.scr.shop->type == NST_MARKET )
- npc->market_delfromsql(nd,i);
+ if (nd->u.scr.shop->type == NST_MARKET)
+ npc->market_delfromsql(nd, i);
+ else if (nd->u.scr.shop->type == NST_BARTER)
+ npc->barter_delfromsql(nd, i);
+ else if (nd->u.scr.shop->type == NST_EXPANDED_BARTER)
+ npc->expanded_barter_delfromsql(nd, i);
nd->u.scr.shop->item[i].nameid = 0;
nd->u.scr.shop->item[i].value = 0;
+ nd->u.scr.shop->item[i].value2 = 0;
nd->u.scr.shop->item[i].qty = 0;
+ if (nd->u.scr.shop->item[i].currency != NULL) {
+ aFree(nd->u.scr.shop->item[i].currency);
+ nd->u.scr.shop->item[i].currency = NULL;
+ }
- for( i = 0, cursor = 0; i < nd->u.scr.shop->items; i++ ) {
- if( nd->u.scr.shop->item[i].nameid == 0 )
+ for (i = 0, cursor = 0; i < nd->u.scr.shop->items; i++) {
+ if (nd->u.scr.shop->item[i].nameid == 0)
continue;
- if( cursor != i ) {
+ if (cursor != i) {
nd->u.scr.shop->item[cursor].nameid = nd->u.scr.shop->item[i].nameid;
nd->u.scr.shop->item[cursor].value = nd->u.scr.shop->item[i].value;
+ nd->u.scr.shop->item[cursor].value2 = nd->u.scr.shop->item[i].value2;
nd->u.scr.shop->item[cursor].qty = nd->u.scr.shop->item[i].qty;
+ nd->u.scr.shop->item[cursor].currency = nd->u.scr.shop->item[i].currency;
}
cursor++;
}
+ nd->u.scr.shop->items--;
+ nd->u.scr.shop->item[nd->u.scr.shop->items].currency = NULL;
script_pushint(st, 1);
- } else
+ } else {
script_pushint(st, 0);
+ }
return true;
}
+
/**
* @call setcurrency <Val1>{,<Val2>};
*
* updates currently-attached player shop currency
**/
/* setcurrency(<Val1>,{<Val2>}) */
-BUILDIN(setcurrency)
+static BUILDIN(setcurrency)
{
int val1 = script_getnum(st,2),
val2 = script_hasdata(st, 3) ? script_getnum(st,3) : 0;
@@ -20033,6 +25403,7 @@ BUILDIN(setcurrency)
return true;
}
+
/**
* @call tradertype(<type>);
*
@@ -20040,7 +25411,8 @@ BUILDIN(setcurrency)
* check enum npc_shop_types for list
* cleans shop list on use
**/
-BUILDIN(tradertype) {
+static BUILDIN(tradertype)
+{
int type = script_getnum(st, 2);
struct npc_data *nd;
@@ -20061,7 +25433,9 @@ BUILDIN(tradertype) {
nd->u.scr.shop->item[i].value = 0;
nd->u.scr.shop->item[i].qty = 0;
}
- npc->market_delfromsql(nd,USHRT_MAX);
+ npc->market_delfromsql(nd, INT_MAX);
+ npc->barter_delfromsql(nd, INT_MAX);
+ npc->expanded_barter_delfromsql(nd, INT_MAX);
}
#if PACKETVER < 20131223
@@ -20070,18 +25444,32 @@ BUILDIN(tradertype) {
script->reportsrc(st);
}
#endif
+#if PACKETVER_MAIN_NUM < 20190116 && PACKETVER_RE_NUM < 20190116 && PACKETVER_ZERO_NUM < 20181226
+ if (type == NST_BARTER) {
+ ShowWarning("buildin_tradertype: NST_BARTER is only available with PACKETVER_ZERO_NUM 20181226 or PACKETVER_MAIN_NUM 20190116 or PACKETVER_RE_NUM 20190116 or newer!\n");
+ script->reportsrc(st);
+ }
+#endif
+#if PACKETVER_MAIN_NUM < 20191120 && PACKETVER_RE_NUM < 20191106 && PACKETVER_ZERO_NUM < 20191127
+ if (type == NST_EXPANDED_BARTER) {
+ ShowWarning("buildin_tradertype: NST_EXPANDED_BARTER is only available with PACKETVER_ZERO_NUM 20191127 or PACKETVER_MAIN_NUM 20191120 or PACKETVER_RE_NUM 20191106 or newer!\n");
+ script->reportsrc(st);
+ }
+#endif
if( nd->u.scr.shop )
nd->u.scr.shop->type = type;
return true;
}
+
/**
* @call purchaseok();
*
* signs the transaction can proceed
**/
-BUILDIN(purchaseok) {
+static BUILDIN(purchaseok)
+{
struct npc_data *nd;
if( !(nd = map->id2nd(st->oid)) || !nd->u.scr.shop ) {
@@ -20093,12 +25481,14 @@ BUILDIN(purchaseok) {
return true;
}
+
/**
* @call shopcount(<Item_ID>);
*
* @return number of available items in the script's attached shop
**/
-BUILDIN(shopcount) {
+static BUILDIN(shopcount)
+{
struct npc_data *nd;
int id = script_getnum(st, 2);
unsigned short i;
@@ -20109,8 +25499,8 @@ BUILDIN(shopcount) {
} else if ( !nd->u.scr.shop || !nd->u.scr.shop->items ) {
ShowWarning("buildin_shopcount(%d): trying to use without any items!\n",id);
return false;
- } else if ( nd->u.scr.shop->type != NST_MARKET ) {
- ShowWarning("buildin_shopcount(%d): trying to use on a non-NST_MARKET shop!\n",id);
+ } else if (nd->u.scr.shop->type != NST_MARKET && nd->u.scr.shop->type != NST_BARTER && nd->u.scr.shop->type != NST_EXPANDED_BARTER) {
+ ShowWarning("buildin_shopcount(%d): trying to use on a non-NST_MARKET and non-NST_BARTER and non-NST_EXPANDED_BARTER shop!\n",id);
return false;
}
@@ -20135,9 +25525,9 @@ BUILDIN(shopcount) {
* Sends a message through the specified chat channel.
*
*/
-BUILDIN(channelmes)
+static BUILDIN(channelmes)
{
- struct map_session_data *sd = script->rid2sd(st);
+ struct map_session_data *sd = map->id2sd(st->rid);
const char *channelname = script_getstr(st, 2);
struct channel_data *chan = channel->search(channelname, sd);
@@ -20152,14 +25542,66 @@ BUILDIN(channelmes)
return true;
}
+static BUILDIN(addchannelhandler)
+{
+ int i;
+ struct map_session_data *sd = map->id2sd(st->rid);
+ const char *channelname = script_getstr(st, 2);
+ const char *eventname = script_getstr(st, 3);
+ struct channel_data *chan = channel->search(channelname, sd);
+
+ if (!chan) {
+ script_pushint(st, 0);
+ return true;
+ }
+
+ ARR_FIND(0, MAX_EVENTQUEUE, i, chan->handlers[i][0] == '\0');
+
+ if (i < MAX_EVENTQUEUE) {
+ safestrncpy(chan->handlers[i], eventname, EVENT_NAME_LENGTH); //Event enqueued.
+ script_pushint(st, 1);
+ return true;
+ }
+
+ ShowWarning("script:addchannelhandler: too many handlers for channel %s.\n", channelname);
+ script_pushint(st, 0);
+ return true;
+}
+
+static BUILDIN(removechannelhandler)
+{
+ int i;
+ struct map_session_data *sd = map->id2sd(st->rid);
+ const char *channelname = script_getstr(st, 2);
+ const char *eventname = script_getstr(st, 3);
+ struct channel_data *chan = channel->search(channelname, sd);
+
+ if (!chan) {
+ script_pushint(st, 0);
+ return true;
+ }
+
+ for (i = 0; i < MAX_EVENTQUEUE; i++) {
+ if (strcmp(chan->handlers[i], eventname) == 0) {
+ chan->handlers[i][0] = '\0';
+ script_pushint(st, 1);
+ return true;
+ }
+ }
+
+ script_pushint(st, 0);
+ return true;
+}
+
/** By Cydh
-Display script message
-showscript "<message>"{,<GID>};
-*/
-BUILDIN(showscript) {
+ * Display script message
+ * showscript "<message>"{, <GID>};
+ */
+static BUILDIN(showscript)
+{
struct block_list *bl = NULL;
const char *msg = script_getstr(st, 2);
- int id = 0;
+ int id = 0, flag = AREA;
if (script_hasdata(st, 3)) {
id = script_getnum(st, 3);
@@ -20171,18 +25613,18 @@ BUILDIN(showscript) {
if (!bl) {
ShowError("buildin_showscript: Script not attached. (id=%d, rid=%d, oid=%d)\n", id, st->rid, st->oid);
- script_pushint(st, 0);
return false;
}
- clif->ShowScript(bl, msg);
-
- script_pushint(st, 1);
+ if (script_hasdata(st, 4))
+ if (script_getnum(st, 4) == SELF)
+ flag = SELF;
+ clif->ShowScript(bl, msg, flag);
return true;
}
-BUILDIN(mergeitem)
+static BUILDIN(mergeitem)
{
struct map_session_data *sd = script->rid2sd(st);
@@ -20193,8 +25635,198 @@ BUILDIN(mergeitem)
return true;
}
+
+// getcalendartime(<day of month>, <day of week>{, <hour>{, <minute>}});
+// Returns the UNIX Timestamp of next ocurrency of given time
+static BUILDIN(getcalendartime)
+{
+ struct tm info = { 0 };
+ int day_of_month = script_hasdata(st, 4) ? script_getnum(st, 4) : -1;
+ int day_of_week = script_hasdata(st, 5) ? script_getnum(st, 5) : -1;
+ int year = date_get_year();
+ int month = date_get_month();
+ int day = date_get_day();
+ int cur_hour = date_get_hour();
+ int cur_min = date_get_min();
+ int hour = script_getnum(st, 2);
+ int minute = script_getnum(st, 3);
+
+ info.tm_sec = 0;
+ info.tm_min = minute;
+ info.tm_hour = hour;
+ info.tm_mday = day;
+ info.tm_mon = month - 1;
+ info.tm_year = year - 1900;
+
+ if (day_of_month > -1 && day_of_week > -1) {
+ ShowError("script:getcalendartime: You must only specify a day_of_week or a day_of_month, not both\n");
+ script_pushint(st, -1);
+ return false;
+ }
+ if (day_of_month > -1 && (day_of_month < 1 || day_of_month > 31)) {
+ ShowError("script:getcalendartime: Day of Month in invalid range. Must be between 1 and 31.\n");
+ script_pushint(st, -1);
+ return false;
+ }
+ if (day_of_week > -1 && (day_of_week < 0 || day_of_week > 6)) {
+ ShowError("script:getcalendartime: Day of Week in invalid range. Must be between 0 and 6.\n");
+ script_pushint(st, -1);
+ return false;
+ }
+ if (hour > -1 && (hour > 23)) {
+ ShowError("script:getcalendartime: Hour in invalid range. Must be between 0 and 23.\n");
+ script_pushint(st, -1);
+ return false;
+ }
+ if (minute > -1 && (minute > 59)) {
+ ShowError("script:getcalendartime: Minute in invalid range. Must be between 0 and 59.\n");
+ script_pushint(st, -1);
+ return false;
+ }
+ if (hour == -1 || minute == -1) {
+ ShowError("script:getcalendartime: Minutes and Hours are required\n");
+ script_pushint(st, -1);
+ return false;
+ }
+
+ if (day_of_month > -1) {
+ if (day_of_month < day) { // Next Month
+ info.tm_mon++;
+ } else if (day_of_month == day) { // Today
+ if (hour < cur_hour || (hour == cur_hour && minute < cur_min)) { // But past time, next month
+ info.tm_mon++;
+ }
+ }
+
+ // Loops until month has finding a month that has day_of_month
+ do {
+ time_t t;
+ struct tm *lt;
+ info.tm_mday = day_of_month;
+ t = mktime(&info);
+ lt = localtime(&t);
+ info = *lt;
+ } while (info.tm_mday != day_of_month);
+ } else if (day_of_week > -1) {
+ int cur_wday = date_get_dayofweek();
+
+ if (day_of_week > cur_wday) { // This week
+ info.tm_mday += (day_of_week - cur_wday);
+ } else if (day_of_week == cur_wday) { // Today
+ if (hour < cur_hour || (hour == cur_hour && minute <= cur_min)) {
+ info.tm_mday += 7; // Next week
+ }
+ } else if (day_of_week < cur_wday) { // Next week
+ info.tm_mday += (7 - cur_wday + day_of_week);
+ }
+ } else if (day_of_week == -1 && day_of_month == -1) { // Next occurence of hour/min
+ if (hour < cur_hour || (hour == cur_hour && minute < cur_min)) {
+ info.tm_mday++;
+ }
+ }
+
+ script_pushint(st, mktime(&info));
+
+ return true;
+}
+
+enum consolemes_type {
+ CONSOLEMES_DEBUG = 0,
+ CONSOLEMES_ERROR = 1,
+ CONSOLEMES_WARNING = 2,
+ CONSOLEMES_INFO = 3,
+ CONSOLEMES_STATUS = 4,
+ CONSOLEMES_NOTICE = 5,
+};
+
+/*==========================================
+* consolemes(<type>, "text")
+*------------------------------------------*/
+static BUILDIN(consolemes)
+{
+ struct StringBuf buf;
+ StrBuf->Init(&buf);
+ int type = script_hasdata(st, 2) ? script_getnum(st, 2) : 0;
+
+ if (!script->sprintf_helper(st, 3, &buf)) {
+ StrBuf->Destroy(&buf);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ switch (type) {
+ default:
+ case CONSOLEMES_DEBUG:
+ ShowDebug("consolemes: %s\n", StrBuf->Value(&buf));
+ break;
+ case CONSOLEMES_ERROR:
+ ShowError("consolemes: (st->rid: %d) (st->oid: %d) %s\n", st->rid, st->oid, StrBuf->Value(&buf));
+ break;
+ case CONSOLEMES_WARNING:
+ ShowWarning("consolemes: (st->rid: %d) (st->oid: %d) %s\n", st->rid, st->oid, StrBuf->Value(&buf));
+ break;
+ case CONSOLEMES_INFO:
+ ShowInfo("consolemes: %s\n", StrBuf->Value(&buf));
+ break;
+ case CONSOLEMES_STATUS:
+ ShowStatus("consolemes: %s\n", StrBuf->Value(&buf));
+ break;
+ case CONSOLEMES_NOTICE:
+ ShowNotice("consolemes: %s\n", StrBuf->Value(&buf));
+ break;
+ }
+
+ StrBuf->Destroy(&buf);
+ script_pushint(st, 1);
+ return true;
+}
+
+static BUILDIN(setfavoriteitemidx)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+ int idx = script_getnum(st, 2);
+ int value = script_getnum(st, 3);
+
+ if (sd == NULL) {
+ ShowError("buildin_setfavoriteitemidx: No player attached.\n");
+ return false;
+ }
+
+ if (idx < 0 || idx >= sd->status.inventorySize) {
+ ShowError("buildin_setfavoriteitemidx: Invalid inventory index %d (min: %d, max: %d).\n", idx, 0, (sd->status.inventorySize - 1));
+ return false;
+ } else if (sd->inventory_data[idx] == NULL || sd->inventory_data[idx]->nameid <= 0) {
+ ShowWarning("buildin_setfavoriteitemidx: Current inventory index %d has no data.\n", idx);
+ return false;
+ } else if (sd->status.inventory[idx].equip > 0) {
+ ShowWarning("buildin_setfavoriteitemidx: Cant change favorite flag of an equipped item.\n");
+ return false;
+ } else {
+ sd->status.inventory[idx].favorite = cap_value(value, 0, 1);
+ clif->favorite_item(sd, idx);
+ }
+
+ return true;
+}
+
+static BUILDIN(autofavoriteitem)
+{
+ int nameid = script_getnum(st, 2);
+ int flag = script_getnum(st, 3);
+ struct item_data *item_data;
+
+ if ((item_data = itemdb->exists(nameid)) == NULL) {
+ ShowError("buildin_autofavoriteitem: Invalid item '%d'.\n", nameid);
+ return false;
+ }
+
+ item_data->flag.auto_favorite = cap_value(flag, 0, 1);
+ return true;
+}
+
/** place holder for the translation macro **/
-BUILDIN(_) {
+static BUILDIN(_)
+{
return true;
}
@@ -20204,7 +25836,52 @@ BUILDIN(activatepset);
BUILDIN(deactivatepset);
BUILDIN(deletepset);
-BUILDIN(pcre_match) {
+enum dressroom_mode {
+ DRESSROOM_CLOSE = 0,
+ DRESSROOM_OPEN = 1
+};
+
+/**
+ * dressroom({<enum dressroom_mode>});
+ */
+static BUILDIN(dressroom)
+{
+#if PACKETVER >= 20150513
+ struct map_session_data *sd = script->rid2sd(st);
+ enum dressroom_mode mode = DRESSROOM_OPEN;
+
+ if (sd == NULL) {
+ return false;
+ }
+
+ if (script_hasdata(st, 2)) {
+ mode = script_getnum(st, 2);
+ }
+
+ switch (mode) {
+ case DRESSROOM_OPEN:
+ clif->dressroom_open(sd, 1);
+ break;
+ case DRESSROOM_CLOSE:
+ clif->dressroom_open(sd, 0);
+ break;
+ default:
+ ShowWarning("script:dressroom: unknown mode (%u).\n", mode);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ script_pushint(st, 1);
+ return true;
+#else
+ ShowError("The dressing room works only with packet version >= 20150513");
+ script_pushint(st, 0);
+ return false;
+#endif
+}
+
+static BUILDIN(pcre_match)
+{
const char *input = script_getstr(st, 2);
const char *regex = script_getstr(st, 3);
@@ -20213,6 +25890,685 @@ BUILDIN(pcre_match) {
}
/**
+ * navigateto("<map>"{,<x>,<y>,<flag>,<hide_window>,<monster_id>,<char_id>});
+ */
+static BUILDIN(navigateto)
+{
+#if PACKETVER >= 20111010
+ struct map_session_data* sd;
+ const char *mapname;
+ uint16 x = 0;
+ uint16 y = 0;
+ uint16 monster_id = 0;
+ uint8 flag = NAV_KAFRA_AND_AIRSHIP;
+ bool hideWindow = true;
+
+ mapname = script_getstr(st, 2);
+
+ if (script_hasdata(st, 3))
+ x = script_getnum(st, 3);
+ if (script_hasdata(st, 4))
+ y = script_getnum(st, 4);
+ if (script_hasdata(st, 5))
+ flag = (uint8)script_getnum(st, 5);
+ if (script_hasdata(st, 6))
+ hideWindow = script_getnum(st, 6) ? true : false;
+ if (script_hasdata(st, 7))
+ monster_id = script_getnum(st, 7);
+
+ if (script_hasdata(st, 8)) {
+ sd = map->charid2sd(script_getnum(st, 8));
+ } else {
+ sd = script->rid2sd(st);
+ }
+
+ clif->navigate_to(sd, mapname, x, y, flag, hideWindow, monster_id);
+
+ return true;
+#else
+ ShowError("Navigation system works only with packet version >= 20111010");
+ return false;
+#endif
+}
+
+static bool rodex_sendmail_sub(struct script_state *st, struct rodex_message *msg)
+{
+ const char *sender_name, *title, *body;
+
+ if (strcmp(script->getfuncname(st), "rodex_sendmail_acc") == 0 || strcmp(script->getfuncname(st), "rodex_sendmail_acc2") == 0)
+ msg->receiver_accountid = script_getnum(st, 2);
+ else
+ msg->receiver_id = script_getnum(st, 2);
+
+ sender_name = script_getstr(st, 3);
+ if (strlen(sender_name) >= NAME_LENGTH) {
+ ShowError("script:rodex_sendmail: Sender name must not be bigger than %d!\n", NAME_LENGTH - 1);
+ return false;
+ }
+ safestrncpy(msg->sender_name, sender_name, NAME_LENGTH);
+
+ title = script_getstr(st, 4);
+ if (strlen(title) >= RODEX_TITLE_LENGTH) {
+ ShowError("script:rodex_sendmail: Mail Title must not be bigger than %d!\n", RODEX_TITLE_LENGTH - 1);
+ return false;
+ }
+ safestrncpy(msg->title, title, RODEX_TITLE_LENGTH);
+
+ body = script_getstr(st, 5);
+ if (strlen(body) >= MAIL_BODY_LENGTH) {
+ ShowError("script:rodex_sendmail: Mail Message must not be bigger than %d!\n", RODEX_BODY_LENGTH - 1);
+ return false;
+ }
+ safestrncpy(msg->body, body, MAIL_BODY_LENGTH);
+
+ if (script_hasdata(st, 6)) {
+ msg->zeny = script_getnum(st, 6);
+ if (msg->zeny < 0 || msg->zeny > MAX_ZENY) {
+ ShowError("script:rodex_sendmail: Invalid Zeny value %"PRId64"!\n", msg->zeny);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static BUILDIN(rodex_sendmail)
+{
+ struct rodex_message msg = { 0 };
+ int item_count = 0, i = 0, param = 7;
+
+ // Common parameters - sender/message/zeny
+ if (rodex_sendmail_sub(st, &msg) == false)
+ return false;
+
+ // Item list
+ while (i < RODEX_MAX_ITEM && script_hasdata(st, param)) {
+ struct item_data *idata;
+
+ if (!script_hasdata(st, param + 1)) {
+ ShowError("script:rodex_sendmail: Missing Item %d amount!\n", (i + 1));
+ return false;
+ }
+
+ ++item_count;
+ if (data_isstring(script_getdata(st, param)) == false) {
+ int itemid = script_getnum(st, param);
+
+ if (itemdb->exists(itemid) == false) {
+ ShowError("script:rodex_sendmail: Unknown item ID %d.\n", itemid);
+ return false;
+ }
+
+ idata = itemdb->search(itemid);
+ }
+ else {
+ ShowError("script:rodex_sendmail: Item %d must be passed as Number.\n", (i + 1));
+ return false;
+ }
+
+ msg.items[i].item.nameid = idata->nameid;
+ msg.items[i].item.amount = script_getnum(st, (param + 1));
+ msg.items[i].item.identify = 1;
+
+ ++i;
+ param += 2;
+ }
+ msg.items_count = item_count;
+
+ msg.type = MAIL_TYPE_NPC;
+ if (msg.zeny > 0)
+ msg.type |= MAIL_TYPE_ZENY;
+ if (msg.items_count > 0)
+ msg.type |= MAIL_TYPE_ITEM;
+ msg.send_date = (int)time(NULL);
+ msg.expire_date = (int)time(NULL) + RODEX_EXPIRE;
+
+ intif->rodex_sendmail(&msg);
+
+ return true;
+}
+
+static BUILDIN(rodex_sendmail2)
+{
+ struct rodex_message msg = { 0 };
+ int item_count = 0, i = 0, param = 7;
+
+ // Common parameters - sender/message/zeny
+ if (rodex_sendmail_sub(st, &msg) == false)
+ return false;
+
+ // Item list
+ while (i < RODEX_MAX_ITEM && script_hasdata(st, param)) {
+ struct item_data *idata;
+ int j;
+
+ // Tests
+ if (!script_hasdata(st, param + 1)) {
+ ShowError("script:rodex_sendmail: Missing Item %d amount!\n", (i + 1));
+ return false;
+ }
+ if (!script_hasdata(st, param + 2)) {
+ ShowError("script:rodex_sendmail: Missing Item %d refine!\n", (i + 1));
+ return false;
+ }
+ if (!script_hasdata(st, param + 3)) {
+ ShowError("script:rodex_sendmail: Missing Item %d attribute!\n", (i + 1));
+ return false;
+ }
+ for (j = 0; j < MAX_SLOTS; ++j) {
+ if (!script_hasdata(st, param + 4 + j)) {
+ ShowError("script:rodex_sendmail: Missing Item %d card %d!\n", (i + 1), j);
+ return false;
+ }
+ }
+
+ // Set data to message
+ ++item_count;
+ if (data_isstring(script_getdata(st, param)) == false) {
+ int itemid = script_getnum(st, param);
+
+ if (itemdb->exists(itemid) == false) {
+ ShowError("script:rodex_sendmail: Unknown item ID %d.\n", itemid);
+ return false;
+ }
+
+ idata = itemdb->search(itemid);
+ } else {
+ ShowError("script:rodex_sendmail: Item %d must be passed as Number.\n", (i + 1));
+ return false;
+ }
+
+ msg.items[i].item.nameid = idata->nameid;
+ msg.items[i].item.amount = script_getnum(st, (param + 1));
+ msg.items[i].item.refine = script_getnum(st, (param + 2));
+ msg.items[i].item.attribute = script_getnum(st, (param + 3));
+ msg.items[i].item.identify = 1;
+
+ for (j = 0; j < MAX_SLOTS; ++j) {
+ msg.items[i].item.card[j] = script_getnum(st, param + 4 + j);
+ }
+
+ ++i;
+ param += 4 + MAX_SLOTS;
+ }
+ msg.items_count = item_count;
+
+ msg.type = MAIL_TYPE_NPC;
+ if (msg.zeny > 0)
+ msg.type |= MAIL_TYPE_ZENY;
+ if (msg.items_count > 0)
+ msg.type |= MAIL_TYPE_ITEM;
+ msg.send_date = (int)time(NULL);
+ msg.expire_date = (int)time(NULL) + RODEX_EXPIRE;
+
+ intif->rodex_sendmail(&msg);
+
+ return true;
+}
+
+/**
+ * Clan System: Add a player to a clan
+ */
+static BUILDIN(clan_join)
+{
+ struct map_session_data *sd = NULL;
+ int clan_id = script_getnum(st, 2);
+
+ if (script_hasdata(st, 3))
+ sd = map->id2sd(script_getnum(st, 3));
+ else
+ sd = map->id2sd(st->rid);
+
+ if (sd == NULL) {
+ script_pushint(st, false);
+ return false;
+ }
+
+ if (clan->join(sd, clan_id))
+ script_pushint(st, true);
+ else
+ script_pushint(st, false);
+
+ return true;
+}
+
+/**
+ * Clan System: Remove a player from clan
+ */
+static BUILDIN(clan_leave)
+{
+ struct map_session_data *sd = NULL;
+
+ if (script_hasdata(st, 2))
+ sd = map->id2sd(script_getnum(st, 2));
+ else
+ sd = map->id2sd(st->rid);
+
+ if (sd == NULL) {
+ script_pushint(st, false);
+ return false;
+ }
+
+ if (clan->leave(sd, false))
+ script_pushint(st, true);
+ else
+ script_pushint(st, false);
+
+ return true;
+}
+
+/**
+ * Clan System: Show clan emblem next to npc name
+ */
+static BUILDIN(clan_master)
+{
+ struct npc_data *nd = map->id2nd(st->oid);
+ int clan_id = script_getnum(st, 2);
+
+ if (nd == NULL) {
+ script_pushint(st, false);
+ return false;
+ } else if (clan_id <= 0) {
+ script_pushint(st, false);
+ ShowError("buildin_clan_master: Received Invalid Clan ID %d\n", clan_id);
+ return false;
+ } else if (clan->search(clan_id) == NULL) {
+ script_pushint(st, false);
+ ShowError("buildin_clan_master: Received Id of a nonexistent Clan. Id: %d\n", clan_id);
+ return false;
+ }
+
+ nd->clan_id = clan_id;
+ clif->sc_load(&nd->bl, nd->bl.id, AREA, status->get_sc_icon(SC_CLAN_INFO), 0, clan_id, 0);
+
+ script_pushint(st, true);
+ return true;
+}
+
+static BUILDIN(airship_respond)
+{
+ struct map_session_data *sd = map->id2sd(st->rid);
+ int32 flag = script_getnum(st, 2);
+
+ if (sd == NULL)
+ return false;
+
+ if (flag < P_AIRSHIP_NONE || flag > P_AIRSHIP_ITEM_INVALID) {
+ ShowWarning("buildin_airship_respond: invalid flag %d has been given.", flag);
+ return false;
+ }
+
+ clif->PrivateAirshipResponse(sd, flag);
+ return true;
+}
+
+/**
+ * hateffect(EffectID, Enable_State)
+ */
+static BUILDIN(hateffect)
+{
+#if PACKETVER >= 20150422
+ struct map_session_data *sd = script_rid2sd(st);
+ int effectId, enabled = 0;
+ int i;
+
+ if (sd == NULL)
+ return false;
+
+ effectId = script_getnum(st, 2);
+ enabled = script_getnum(st, 3);
+
+ for (i = 0; i < VECTOR_LENGTH(sd->hatEffectId); ++i) {
+ if (VECTOR_INDEX(sd->hatEffectId, i) == effectId) {
+ if (enabled == 1) { // Already Enabled
+ return true;
+ } else { // Remove
+ VECTOR_ERASE(sd->hatEffectId, i);
+ clif->hat_effect_single(&sd->bl, effectId, enabled);
+ return true;
+ }
+ }
+ }
+
+ VECTOR_ENSURE(sd->hatEffectId, 1, 1);
+ VECTOR_PUSH(sd->hatEffectId, effectId);
+
+ clif->hat_effect_single(&sd->bl, effectId, enabled);
+#endif
+ return true;
+}
+
+static BUILDIN(openstylist)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+
+ if (sd == NULL)
+ return false;
+
+#if PACKETVER >= 20150128
+ clif->open_ui(sd, CZ_STYLIST_UI);
+#endif
+ return true;
+}
+
+static BUILDIN(msgtable)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+ if (sd == NULL)
+ return false;
+
+ const enum clif_messages msgId = script_getnum(st, 2);
+ if (script_hasdata(st, 3)) {
+ clif->msgtable_color(sd, msgId, script_getnum(st, 3));
+ } else {
+ clif->msgtable(sd, msgId);
+ }
+
+ return true;
+}
+
+static BUILDIN(msgtable2)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+ if (sd == NULL)
+ return false;
+
+ const enum clif_messages msgId = script_getnum(st, 2);
+ if (script_isstringtype(st, 3)) {
+ const char *value = script_getstr(st, 3);
+ if (script_hasdata(st, 4)) {
+ clif->msgtable_str_color(sd, msgId, value, script_getnum(st, 4));
+ } else {
+ clif->msgtable_str(sd, msgId, value);
+ }
+ } else {
+ const int value = script_getnum(st, 3);
+ clif->msgtable_num(sd, msgId, value);
+ }
+
+ return true;
+}
+
+// show/hide camera info
+static BUILDIN(camerainfo)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+ if (sd == NULL)
+ return false;
+
+ clif->camera_showWindow(sd);
+ return true;
+}
+
+// allow change some camera parameters
+static BUILDIN(changecamera)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+ if (sd == NULL)
+ return false;
+
+ enum send_target target = SELF;
+ if (script_hasdata(st, 5)) {
+ target = script_getnum(st, 5);
+ }
+ clif->camera_change(sd, (float)script_getnum(st, 2), (float)script_getnum(st, 3), (float)script_getnum(st, 4), target);
+ return true;
+}
+
+// update preview window to given item
+static BUILDIN(itempreview)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+ if (sd == NULL)
+ return false;
+ clif->item_preview(sd, script_getnum(st, 2));
+ return true;
+}
+
+// insert or remove card into equipped item
+static BUILDIN(enchantitem)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+ if (sd == NULL)
+ return false;
+ const int pos = script_getnum(st, 2);
+ if ((pos < EQI_ACC_L || pos > EQI_HAND_R) && pos != EQI_AMMO) {
+ ShowError("Wrong equip position: %d\n", pos);
+ script->reportfunc(st);
+ script->reportsrc(st);
+ script_pushint(st, false);
+ return true;
+ }
+ const int cardId = script_getnum(st, 4);
+ struct item_data *it = itemdb->exists(cardId);
+ if (it == NULL || it->type != IT_CARD) {
+ ShowError("Item id is not card or not exists: %d\n", cardId);
+ script->reportfunc(st);
+ script->reportsrc(st);
+ script_pushint(st, false);
+ return true;
+ }
+ const int n = sd->equip_index[pos];
+ if (n < 0) {
+ ShowError("Item in equipment slot %d is not equipped\n", pos);
+ script->reportfunc(st);
+ script->reportsrc(st);
+ script_pushint(st, false);
+ return true;
+ }
+ const int cardSlot = script_getnum(st, 3);
+ if (cardSlot < 0 || cardSlot >= MAX_SLOTS) {
+ ShowError("Wrong card slot %d. Must be in range 0-3.\n", cardSlot);
+ script->reportfunc(st);
+ script->reportsrc(st);
+ script_pushint(st, false);
+ return true;
+ }
+ const bool res = clif->enchant_equipment(sd, pc->equip_pos[pos], cardSlot, cardId);
+ if (res) {
+ logs->pick_pc(sd, LOG_TYPE_CARD, -1, &sd->status.inventory[n],sd->inventory_data[n]);
+ sd->status.inventory[n].card[cardSlot] = cardId;
+ logs->pick_pc(sd, LOG_TYPE_CARD, 1, &sd->status.inventory[n],sd->inventory_data[n]);
+ status_calc_pc(sd, SCO_NONE);
+ }
+ script_pushint(st, res);
+ return true;
+}
+
+// send ack to inventory expand request
+static BUILDIN(expandinventoryack)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+ if (sd == NULL)
+ return false;
+ int itemId = 0;
+ if (script_hasdata(st, 3)) {
+ itemId = script_getnum(st, 3);
+ }
+ clif->inventoryExpandAck(sd, script_getnum(st, 2), itemId);
+ return true;
+}
+
+// send final ack to inventory expand request
+static BUILDIN(expandinventoryresult)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+ if (sd == NULL)
+ return false;
+ clif->inventoryExpandResult(sd, script_getnum(st, 2));
+ return true;
+}
+
+// adjust player inventory size to given value positive or negative
+static BUILDIN(expandinventory)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+ if (sd == NULL)
+ return false;
+ script_pushint(st, pc->expandInventory(sd, script_getnum(st, 2)));
+ return true;
+}
+
+// return current player inventory size
+static BUILDIN(getinventorysize)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+ if (sd == NULL)
+ return false;
+ script_pushint(st, sd->status.inventorySize);
+ return true;
+}
+
+// force close roulette window if it opened
+static BUILDIN(closeroulette)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+ if (sd == NULL)
+ return false;
+ clif->roulette_close(sd);
+ return true;
+}
+
+static BUILDIN(openrefineryui)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+
+ if (sd == NULL) {
+ script_pushint(st, 0);
+ return true;
+ }
+
+ if (battle_config.enable_refinery_ui == 0) {
+ script_pushint(st, 0);
+ return true;
+ }
+
+ clif->OpenRefineryUI(sd);
+ script_pushint(st, 1);
+ return true;
+}
+
+/**
+ * identify(<item id>)
+ * Identifies the first unidentified <item id> item on player's inventory.
+ * Returns -2 on error, -1 if no item to identify was found, identified idx otherwise.
+ */
+static BUILDIN(identify)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+
+ if (sd == NULL) {
+ script_pushint(st, -2);
+ return true;
+ }
+
+ int itemid = script_getnum(st, 2);
+ if (itemdb->exists(itemid) == NULL) {
+ ShowError("buildin_identify: Invalid item ID (%d)\n", itemid);
+ script_pushint(st, -2);
+ return true;
+ }
+
+ int idx = -1;
+ ARR_FIND(0, sd->status.inventorySize, idx, (sd->status.inventory[idx].nameid == itemid && sd->status.inventory[idx].identify == 0));
+
+ if (idx < 0 || idx >= sd->status.inventorySize) {
+ script_pushint(st, -1);
+ return true;
+ }
+
+ sd->status.inventory[idx].identify = 1;
+ clif->item_identified(sd, idx, 0);
+ script_pushint(st, idx);
+
+ return true;
+}
+
+/**
+ * identifyidx(idx)
+ * Identifies item at idx.
+ * Returns true if item is identified, false otherwise.
+ */
+static BUILDIN(identifyidx)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+
+ if (sd == NULL) {
+ script_pushint(st, false);
+ return true;
+ }
+
+ int idx = script_getnum(st, 2);
+ if (idx < 0 || idx >= sd->status.inventorySize) {
+ ShowError("buildin_identifyidx: Invalid inventory index (%d), expected a value between 0 and %d\n", idx, sd->status.inventorySize);
+ script_pushint(st, false);
+ return true;
+ }
+
+ if (sd->status.inventory[idx].nameid <= 0 || sd->status.inventory[idx].identify != 0) {
+ script_pushint(st, false);
+ return true;
+ }
+
+ sd->status.inventory[idx].identify = 1;
+ clif->item_identified(sd, idx, 0);
+ script_pushint(st, true);
+
+ return true;
+}
+
+static BUILDIN(openlapineddukddakboxui)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+ if (sd == NULL)
+ return false;
+ const int item_id = script_getnum(st, 2);
+ struct item_data *it = itemdb->exists(item_id);
+ if (it == NULL) {
+ ShowError("buildin_openlapineddukddakboxui: Item %d is not valid\n", item_id);
+ script->reportfunc(st);
+ script->reportsrc(st);
+ script_pushint(st, false);
+ return true;
+ }
+ clif->lapineDdukDdak_open(sd, item_id);
+ script_pushint(st, true);
+ return true;
+}
+
+// Reset 'Feeling' maps.
+BUILDIN(resetfeel)
+{
+ struct map_session_data *sd;
+
+ if (script_hasdata(st, 2))
+ sd = script->id2sd(st, script_getnum(st, 2));
+ else
+ sd = script->rid2sd(st);
+
+ if (sd != NULL)
+ pc->resetfeel(sd);
+
+ return true;
+}
+
+// Reset hatred target marks.
+BUILDIN(resethate)
+{
+ struct map_session_data *sd;
+
+ if (script_hasdata(st, 2))
+ sd = script->id2sd(st, script_getnum(st, 2));
+ else
+ sd = script->rid2sd(st);
+
+ if (sd != NULL)
+ pc->resethate(sd);
+
+ return true;
+}
+
+/**
* Adds a built-in script function.
*
* @param buildin Script function data
@@ -20220,7 +26576,8 @@ BUILDIN(pcre_match) {
* (i.e. a plugin overriding a built-in function)
* @return Whether the function was successfully added.
*/
-bool script_add_builtin(const struct script_function *buildin, bool override) {
+static bool script_add_builtin(const struct script_function *buildin, bool override)
+{
int n = 0, offset = 0;
size_t slen;
if( !buildin ) {
@@ -20272,8 +26629,10 @@ bool script_add_builtin(const struct script_function *buildin, bool override) {
else if( strcmp(buildin->name, "callfunc") == 0 ) script->buildin_callfunc_ref = n;
else if( strcmp(buildin->name, "getelementofarray") == 0 ) script->buildin_getelementofarray_ref = n;
else if( strcmp(buildin->name, "mes") == 0 ) script->buildin_mes_offset = script->buildin_count;
+ else if( strcmp(buildin->name, "mesf") == 0 ) script->buildin_mesf_offset = script->buildin_count;
else if( strcmp(buildin->name, "select") == 0 ) script->buildin_select_offset = script->buildin_count;
else if( strcmp(buildin->name, "_") == 0 ) script->buildin_lang_macro_offset = script->buildin_count;
+ else if( strcmp(buildin->name, "_$") == 0 ) script->buildin_lang_macro_fmtstring_offset = script->buildin_count;
offset = script->buildin_count;
@@ -20299,7 +26658,8 @@ bool script_add_builtin(const struct script_function *buildin, bool override) {
return true;
}
-bool script_hp_add(char *name, char *args, bool (*func)(struct script_state *st), bool isDeprecated) {
+static bool script_hp_add(char *name, char *args, bool (*func)(struct script_state *st), bool isDeprecated)
+{
struct script_function buildin;
buildin.name = name;
buildin.arg = args;
@@ -20308,7 +26668,7 @@ bool script_hp_add(char *name, char *args, bool (*func)(struct script_state *st)
return script->add_builtin(&buildin, true);
}
-void script_run_use_script(struct map_session_data *sd, struct item_data *data, int oid) __attribute__((nonnull (1)));
+static void script_run_use_script(struct map_session_data *sd, struct item_data *data, int oid) __attribute__((nonnull (1)));
/**
* Run use script for item.
@@ -20317,14 +26677,15 @@ void script_run_use_script(struct map_session_data *sd, struct item_data *data,
* @param n item index in inventory. Must be correct and checked before.
* @param oid npc id. Can be also 0 or fake npc id.
*/
-void script_run_use_script(struct map_session_data *sd, struct item_data *data, int oid)
+static void script_run_use_script(struct map_session_data *sd, struct item_data *data, int oid)
{
+ nullpo_retv(data);
script->current_item_id = data->nameid;
script->run(data->script, 0, sd->bl.id, oid);
script->current_item_id = 0;
}
-void script_run_item_equip_script(struct map_session_data *sd, struct item_data *data, int oid) __attribute__((nonnull (1, 2)));
+static void script_run_item_equip_script(struct map_session_data *sd, struct item_data *data, int oid) __attribute__((nonnull (1, 2)));
/**
* Run item equip script for item.
@@ -20333,14 +26694,14 @@ void script_run_item_equip_script(struct map_session_data *sd, struct item_data
* @param data equipped item data. Must be correct and checked before.
* @param oid npc id. Can be also 0 or fake npc id.
*/
-void script_run_item_equip_script(struct map_session_data *sd, struct item_data *data, int oid)
+static void script_run_item_equip_script(struct map_session_data *sd, struct item_data *data, int oid)
{
script->current_item_id = data->nameid;
script->run(data->equip_script, 0, sd->bl.id, oid);
script->current_item_id = 0;
}
-void script_run_item_unequip_script(struct map_session_data *sd, struct item_data *data, int oid) __attribute__((nonnull (1, 2)));
+static void script_run_item_unequip_script(struct map_session_data *sd, struct item_data *data, int oid) __attribute__((nonnull (1, 2)));
/**
* Run item unequip script for item.
@@ -20349,31 +26710,80 @@ void script_run_item_unequip_script(struct map_session_data *sd, struct item_dat
* @param data unequipped item data. Must be correct and checked before.
* @param oid npc id. Can be also 0 or fake npc id.
*/
-void script_run_item_unequip_script(struct map_session_data *sd, struct item_data *data, int oid)
+static void script_run_item_unequip_script(struct map_session_data *sd, struct item_data *data, int oid)
{
script->current_item_id = data->nameid;
script->run(data->unequip_script, 0, sd->bl.id, oid);
script->current_item_id = 0;
}
+static void script_run_item_rental_start_script(struct map_session_data *sd, struct item_data *data, int oid) __attribute__((nonnull(1, 2)));
+
+/**
+ * Run item rental start script
+ * @param sd player session data. Must be correct and checked before.
+ * @param data rental item data. Must be correct and checked before.
+ * @param oid npc id. Can be also 0 or fake npc id.
+ **/
+static void script_run_item_rental_start_script(struct map_session_data *sd, struct item_data *data, int oid)
+{
+ script->current_item_id = data->nameid;
+ script->run(data->rental_start_script, 0, sd->bl.id, oid);
+ script->current_item_id = 0;
+}
+
+static void script_run_item_rental_end_script(struct map_session_data *sd, struct item_data *data, int oid) __attribute__((nonnull(1, 2)));
+
+/**
+* Run item rental end script
+* @param sd player session data. Must be correct and checked before.
+* @param data rental item data. Must be correct and checked before.
+* @param oid npc id. Can be also 0 or fake npc id.
+**/
+static void script_run_item_rental_end_script(struct map_session_data *sd, struct item_data *data, int oid)
+{
+ script->current_item_id = data->nameid;
+ script->run(data->rental_end_script, 0, sd->bl.id, oid);
+ script->current_item_id = 0;
+}
+
+static void script_run_item_lapineddukddak_script(struct map_session_data *sd, struct item_data *data, int oid) __attribute__((nonnull (1, 2)));
+
+/**
+ * Run item lapineddukddak script for item.
+ *
+ * @param sd player session data. Must be correct and checked before.
+ * @param data unequipped item data. Must be correct and checked before.
+ * @param oid npc id. Can be also 0 or fake npc id.
+ */
+static void script_run_item_lapineddukddak_script(struct map_session_data *sd, struct item_data *data, int oid)
+{
+ script->current_item_id = data->nameid;
+ script->run(data->lapineddukddak->script, 0, sd->bl.id, oid);
+ script->current_item_id = 0;
+}
+
#define BUILDIN_DEF(x,args) { buildin_ ## x , #x , args, false }
#define BUILDIN_DEF2(x,x2,args) { buildin_ ## x , x2 , args, false }
#define BUILDIN_DEF_DEPRECATED(x,args) { buildin_ ## x , #x , args, true }
#define BUILDIN_DEF2_DEPRECATED(x,x2,args) { buildin_ ## x , x2 , args, true }
-void script_parse_builtin(void) {
+static void script_parse_builtin(void)
+{
struct script_function BUILDIN[] = {
/* Commands for internal use by the script engine */
BUILDIN_DEF(__jump_zero,"il"),
BUILDIN_DEF(__setr,"rv?"),
// NPC interaction
- BUILDIN_DEF(mes,"s*"),
+ BUILDIN_DEF(mes, "?"),
+ BUILDIN_DEF(mesf, "s*"),
BUILDIN_DEF(next,""),
+ BUILDIN_DEF(mesclear,""),
BUILDIN_DEF(close,""),
BUILDIN_DEF(close2,""),
BUILDIN_DEF(menu,"sl*"),
BUILDIN_DEF(select,"s*"), //for future jA script compatibility
- BUILDIN_DEF(prompt,"s*"),
+ BUILDIN_DEF2(select, "prompt", "s*"),
//
BUILDIN_DEF(goto,"l"),
BUILDIN_DEF(callsub,"l*"),
@@ -20386,8 +26796,8 @@ void script_parse_builtin(void) {
BUILDIN_DEF(warp,"sii?"),
BUILDIN_DEF(areawarp,"siiiisii??"),
BUILDIN_DEF(warpchar,"siii"), // [LuzZza]
- BUILDIN_DEF(warpparty,"siii?"), // [Fredzilla] [Paradox924X]
- BUILDIN_DEF(warpguild,"siii"), // [Fredzilla]
+ BUILDIN_DEF(warpparty,"siii???"), // [Fredzilla] [Paradox924X] [Jedzkie] [Dastgir]
+ BUILDIN_DEF(warpguild,"siii??"), // [Fredzilla]
BUILDIN_DEF(setlook,"ii"),
BUILDIN_DEF(changelook,"ii"), // Simulates but don't Store it
BUILDIN_DEF2(__setr,"set","rv"),
@@ -20395,6 +26805,7 @@ void script_parse_builtin(void) {
BUILDIN_DEF(cleararray,"rvi"),
BUILDIN_DEF(copyarray,"rri"),
BUILDIN_DEF(getarraysize,"r"),
+ BUILDIN_DEF(getarrayindex,"r"),
BUILDIN_DEF(deletearray,"r?"),
BUILDIN_DEF(getelementofarray,"ri"),
BUILDIN_DEF(getitem,"vi?"),
@@ -20403,8 +26814,10 @@ void script_parse_builtin(void) {
BUILDIN_DEF(getnameditem,"vv"),
BUILDIN_DEF2(grouprandomitem,"groupranditem","i"),
BUILDIN_DEF(makeitem,"visii"),
+ BUILDIN_DEF(makeitem2,"viiiiiiii????"),
BUILDIN_DEF(delitem,"vi?"),
BUILDIN_DEF(delitem2,"viiiiiiii?"),
+ BUILDIN_DEF(delitemidx, "i??"),
BUILDIN_DEF2(enableitemuse,"enable_items",""),
BUILDIN_DEF2(disableitemuse,"disable_items",""),
BUILDIN_DEF(cutin,"si"),
@@ -20415,20 +26828,24 @@ void script_parse_builtin(void) {
BUILDIN_DEF(rand,"i?"),
BUILDIN_DEF(countitem,"v"),
BUILDIN_DEF(countitem2,"viiiiiii"),
+ BUILDIN_DEF(countnameditem,"v?"),
BUILDIN_DEF(checkweight,"vi*"),
BUILDIN_DEF(checkweight2,"rr"),
BUILDIN_DEF(readparam,"i?"),
+ BUILDIN_DEF(setparam,"ii?"),
BUILDIN_DEF(getcharid,"i?"),
- BUILDIN_DEF(getnpcid,"i?"),
+ BUILDIN_DEF(getnpcid, "?"),
BUILDIN_DEF(getpartyname,"i"),
BUILDIN_DEF(getpartymember,"i?"),
BUILDIN_DEF(getpartyleader,"i?"),
- BUILDIN_DEF(getguildname,"i"),
- BUILDIN_DEF(getguildmaster,"i"),
- BUILDIN_DEF(getguildmasterid,"i"),
+ BUILDIN_DEF_DEPRECATED(getguildname,"i"),
+ BUILDIN_DEF_DEPRECATED(getguildmaster,"i"),
+ BUILDIN_DEF_DEPRECATED(getguildmasterid,"i"),
BUILDIN_DEF(getguildmember,"i?"),
- BUILDIN_DEF(strcharinfo,"i"),
- BUILDIN_DEF(strnpcinfo,"i"),
+ BUILDIN_DEF(getguildinfo,"i?"),
+ BUILDIN_DEF(getguildonline, "i?"),
+ BUILDIN_DEF(strcharinfo,"i??"),
+ BUILDIN_DEF(strnpcinfo,"i??"),
BUILDIN_DEF(charid2rid,"i"),
BUILDIN_DEF(getequipid,"i"),
BUILDIN_DEF(getequipname,"i"),
@@ -20439,14 +26856,15 @@ void script_parse_builtin(void) {
BUILDIN_DEF(getequipisequiped,"i"),
BUILDIN_DEF(getequipisenableref,"i"),
BUILDIN_DEF(getequipisidentify,"i"),
- BUILDIN_DEF(getequiprefinerycnt,"i"),
+ BUILDIN_DEF(getequiprefinerycnt,"i*"),
BUILDIN_DEF(getequipweaponlv,"i"),
- BUILDIN_DEF(getequippercentrefinery,"i"),
+ BUILDIN_DEF(getequippercentrefinery,"i?"),
BUILDIN_DEF(successrefitem,"i?"),
BUILDIN_DEF(failedrefitem,"i"),
BUILDIN_DEF(downrefitem,"i?"),
BUILDIN_DEF(statusup,"i"),
BUILDIN_DEF(statusup2,"ii"),
+ BUILDIN_DEF(needed_status_point, "ii"),
BUILDIN_DEF(bonus,"iv"),
BUILDIN_DEF2(bonus,"bonus2","ivi"),
BUILDIN_DEF2(bonus,"bonus3","ivii"),
@@ -20463,21 +26881,21 @@ void script_parse_builtin(void) {
BUILDIN_DEF(basicskillcheck,""),
BUILDIN_DEF(getgmlevel,""),
BUILDIN_DEF(setgroupid, "i?"),
- BUILDIN_DEF(getgroupid,""),
+ BUILDIN_DEF(getgroupid,"?"),
BUILDIN_DEF(end,""),
- BUILDIN_DEF(checkoption,"i"),
- BUILDIN_DEF(setoption,"i?"),
+ BUILDIN_DEF(checkoption,"i?"),
+ BUILDIN_DEF(setoption,"i??"),
BUILDIN_DEF(setcart,"?"),
BUILDIN_DEF(checkcart,""),
BUILDIN_DEF(setfalcon,"?"),
BUILDIN_DEF(checkfalcon,""),
- BUILDIN_DEF(setmount,"?"),
+ BUILDIN_DEF(setmount,"??"),
BUILDIN_DEF(checkmount,""),
BUILDIN_DEF(checkwug,""),
BUILDIN_DEF(savepoint,"sii"),
BUILDIN_DEF(gettimetick,"i"),
BUILDIN_DEF(gettime,"i"),
- BUILDIN_DEF(gettimestr,"si"),
+ BUILDIN_DEF(gettimestr, "si?"),
BUILDIN_DEF(openstorage,""),
BUILDIN_DEF(guildopenstorage,""),
BUILDIN_DEF(itemskill,"vi?"),
@@ -20488,12 +26906,15 @@ void script_parse_builtin(void) {
BUILDIN_DEF(areamonster,"siiiisii???"),
BUILDIN_DEF(killmonster,"ss?"),
BUILDIN_DEF(killmonsterall,"s?"),
+ BUILDIN_DEF(killmonstergid, "i"),
BUILDIN_DEF(clone,"siisi????"),
BUILDIN_DEF(doevent,"s"),
BUILDIN_DEF(donpcevent,"s"),
- BUILDIN_DEF(addtimer,"is"),
- BUILDIN_DEF(deltimer,"s"),
- BUILDIN_DEF(addtimercount,"si"),
+ BUILDIN_DEF(addtimer,"is?"),
+ BUILDIN_DEF(deltimer,"s?"),
+ BUILDIN_DEF(addtimercount,"si?"),
+ BUILDIN_DEF(gettimer,"i??"),
+ BUILDIN_DEF(getunits,"iri?????"),
BUILDIN_DEF(initnpctimer,"??"),
BUILDIN_DEF(stopnpctimer,"??"),
BUILDIN_DEF(startnpctimer,"??"),
@@ -20502,6 +26923,7 @@ void script_parse_builtin(void) {
BUILDIN_DEF(attachnpctimer,"?"), // attached the player id to the npc timer [Celest]
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(announce,"si?????"),
BUILDIN_DEF(mapannounce,"ssi?????"),
BUILDIN_DEF(areaannounce,"siiiisi?????"),
@@ -20514,18 +26936,23 @@ void script_parse_builtin(void) {
BUILDIN_DEF(disablenpc,"s"),
BUILDIN_DEF(hideoffnpc,"s"),
BUILDIN_DEF(hideonnpc,"s"),
+ BUILDIN_DEF(cloakonnpc,"s?"),
+ BUILDIN_DEF(cloakoffnpc,"s?"),
BUILDIN_DEF(sc_start,"iii???"),
BUILDIN_DEF2(sc_start,"sc_start2","iiii???"),
BUILDIN_DEF2(sc_start,"sc_start4","iiiiii???"),
BUILDIN_DEF(sc_end,"i?"),
BUILDIN_DEF(getstatus, "i?"),
BUILDIN_DEF(getscrate,"ii?"),
- BUILDIN_DEF(debugmes,"v"),
+ BUILDIN_DEF_DEPRECATED(debugmes,"v*"),
+ BUILDIN_DEF(consolemes,"iv*"),
BUILDIN_DEF2(catchpet,"pet","i"),
BUILDIN_DEF2(birthpet,"bpet",""),
BUILDIN_DEF(resetlvl,"i"),
BUILDIN_DEF(resetstatus,""),
BUILDIN_DEF(resetskill,""),
+ BUILDIN_DEF(resetfeel, "?"),
+ BUILDIN_DEF(resethate, "?"),
BUILDIN_DEF(skillpointcount,""),
BUILDIN_DEF(changebase,"i?"),
BUILDIN_DEF(changesex,""),
@@ -20542,6 +26969,7 @@ void script_parse_builtin(void) {
BUILDIN_DEF(isloggedin,"i?"),
BUILDIN_DEF(setmapflagnosave,"ssii"),
BUILDIN_DEF(getmapflag,"si"),
+ BUILDIN_DEF(getmapinfo,"i?"),
BUILDIN_DEF(setmapflag,"si?"),
BUILDIN_DEF(removemapflag,"si"),
BUILDIN_DEF(pvpon,"s"),
@@ -20578,8 +27006,8 @@ void script_parse_builtin(void) {
BUILDIN_DEF(getcartinventorylist,""),
BUILDIN_DEF(getskilllist,""),
BUILDIN_DEF(clearitem,""),
- BUILDIN_DEF(classchange,"ii"),
- BUILDIN_DEF(misceffect,"i"),
+ BUILDIN_DEF(classchange,"ii?"),
+ BUILDIN_DEF_DEPRECATED(misceffect,"i"),
BUILDIN_DEF(playbgm,"s"),
BUILDIN_DEF(playbgmall,"s?????"),
BUILDIN_DEF(soundeffect,"si"),
@@ -20594,15 +27022,18 @@ void script_parse_builtin(void) {
BUILDIN_DEF(petskillsupport,"viiii"), // [Skotlex]
BUILDIN_DEF(skilleffect,"vi"), // skill effect [Celest]
BUILDIN_DEF(npcskilleffect,"viii"), // npc skill effect [Valaris]
- BUILDIN_DEF(specialeffect,"i??"), // npc skill effect [Valaris]
- BUILDIN_DEF(specialeffect2,"i??"), // skill effect on players[Valaris]
+ BUILDIN_DEF(specialeffect,"i???"), // npc skill effect [Valaris]
+ BUILDIN_DEF(specialeffectnum,"iii???"), // npc skill effect with num [4144]
+ BUILDIN_DEF(removespecialeffect,"i???"),
+ BUILDIN_DEF_DEPRECATED(specialeffect2,"i??"), // skill effect on players[Valaris]
BUILDIN_DEF(nude,""), // nude command [Valaris]
BUILDIN_DEF(mapwarp,"ssii??"), // Added by RoVeRT
BUILDIN_DEF(atcommand,"s"), // [MouseJstr]
BUILDIN_DEF2(atcommand,"charcommand","s"), // [MouseJstr]
BUILDIN_DEF(movenpc,"sii?"), // [MouseJstr]
BUILDIN_DEF(message,"vs"), // [MouseJstr]
- BUILDIN_DEF(npctalk,"s?"), // [Valaris]
+ BUILDIN_DEF(servicemessage, "si?"),
+ BUILDIN_DEF(npctalk,"s??"), // [Valaris][Murilo BiO]
BUILDIN_DEF(mobcount,"ss"),
BUILDIN_DEF(getlook,"i"),
BUILDIN_DEF(getsavepoint,"i"),
@@ -20614,11 +27045,11 @@ void script_parse_builtin(void) {
BUILDIN_DEF(setnpcdir,"*"), // [4144]
BUILDIN_DEF(getnpcclass,"?"), // [4144]
BUILDIN_DEF(getmapxy,"rrri?"), //by Lorky [Lupus]
- BUILDIN_DEF(checkoption1,"i"),
- BUILDIN_DEF(checkoption2,"i"),
+ BUILDIN_DEF(checkoption1,"i?"),
+ BUILDIN_DEF(checkoption2,"i?"),
BUILDIN_DEF(guildgetexp,"i"),
BUILDIN_DEF(guildchangegm,"is"),
- BUILDIN_DEF(logmes,"s"), //this command actls as MES but rints info into LOG file either SQL/TXT [Lupus]
+ BUILDIN_DEF(logmes,"s?"), //this command actls as MES but rints info into LOG file either SQL/TXT [Lupus]
BUILDIN_DEF(summon,"si??"), // summons a slave monster [Celest]
BUILDIN_DEF(isnight,""), // check whether it is night time [Celest]
BUILDIN_DEF(isequipped,"i*"), // check whether another item/card has been equipped [Celest]
@@ -20631,10 +27062,11 @@ void script_parse_builtin(void) {
BUILDIN_DEF(activatepset,"i"), // Activate a pattern set [MouseJstr]
BUILDIN_DEF(deactivatepset,"i"), // Deactive a pattern set [MouseJstr]
BUILDIN_DEF(deletepset,"i"), // Delete a pattern set [MouseJstr]
+ BUILDIN_DEF(dressroom,"?"),
BUILDIN_DEF(pcre_match,"ss"),
BUILDIN_DEF(dispbottom,"s?"), //added from jA [Lupus]
BUILDIN_DEF(getusersname,""),
- BUILDIN_DEF(recovery,""),
+ BUILDIN_DEF(recovery,"?????"),
BUILDIN_DEF(getpetinfo,"i"),
BUILDIN_DEF(gethominfo,"i"),
BUILDIN_DEF(getmercinfo,"i?"),
@@ -20644,6 +27076,12 @@ void script_parse_builtin(void) {
BUILDIN_DEF(getstrlen,"s"), //strlen [Valaris]
BUILDIN_DEF(charisalpha,"si"), //isalpha [Valaris]
BUILDIN_DEF(charat,"si"),
+ BUILDIN_DEF(isstr,"v"),
+ BUILDIN_DEF(getdatatype, "?"),
+ BUILDIN_DEF(data_to_string, "?"),
+ BUILDIN_DEF2(getd, "string_to_data", "?"),
+ BUILDIN_DEF(chr,"i"),
+ BUILDIN_DEF(ord,"s"),
BUILDIN_DEF(setchar,"ssi"),
BUILDIN_DEF(insertchar,"ssi"),
BUILDIN_DEF(delchar,"si"),
@@ -20662,24 +27100,29 @@ 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"),
+ BUILDIN_DEF(getequipoption, "iii"),
+ BUILDIN_DEF(setequipoption, "iiii"),
+ BUILDIN_DEF(getequipisenableopt, "i"),
// List of mathematics commands --->
BUILDIN_DEF(log10,"i"),
BUILDIN_DEF(sqrt,"i"), //[zBuffer]
- BUILDIN_DEF(pow,"ii"), //[zBuffer]
+ BUILDIN_DEF_DEPRECATED(pow,"ii"), //[zBuffer]
BUILDIN_DEF(distance,"iiii"), //[zBuffer]
// <--- List of mathematics commands
BUILDIN_DEF(min, "i*"),
BUILDIN_DEF(max, "i*"),
+ BUILDIN_DEF(cap_value, "iii"),
BUILDIN_DEF(md5,"s"),
BUILDIN_DEF(swap,"rr"),
// [zBuffer] List of dynamic var commands --->
BUILDIN_DEF(getd,"s"),
BUILDIN_DEF(setd,"sv"),
// <--- [zBuffer] List of dynamic var commands
- BUILDIN_DEF(petstat,"i"),
+ BUILDIN_DEF_DEPRECATED(petstat, "i"), // Deprecated 2019-03-11
BUILDIN_DEF(callshop,"s?"), // [Skotlex]
BUILDIN_DEF(npcshopitem,"sii*"), // [Lance]
BUILDIN_DEF(npcshopadditem,"sii*"),
@@ -20706,16 +27149,26 @@ void script_parse_builtin(void) {
BUILDIN_DEF(rid2name,"i"),
BUILDIN_DEF(pcfollow,"ii"),
BUILDIN_DEF(pcstopfollow,"i"),
- BUILDIN_DEF(pcblockmove,"ii"),
+ BUILDIN_DEF_DEPRECATED(pcblockmove,"ii"), // Deprecated 2018-05-04
+ BUILDIN_DEF(setpcblock, "ii?"),
+ BUILDIN_DEF(checkpcblock, "?"),
// <--- [zBuffer] List of player cont commands
// [zBuffer] List of mob control commands --->
BUILDIN_DEF(getunittype,"i"),
+ /* Unit Data */
+ BUILDIN_DEF(setunitdata,"iiv??"),
+ BUILDIN_DEF(getunitdata,"ii?"),
+ BUILDIN_DEF(getunitname,"i"),
+ BUILDIN_DEF(setunitname,"is"),
+ BUILDIN_DEF(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?"),
BUILDIN_DEF(unitstop,"i"),
- BUILDIN_DEF(unittalk,"is"),
+ BUILDIN_DEF(unittalk,"is???"),
BUILDIN_DEF(unitemote,"ii"),
BUILDIN_DEF(unitskilluseid,"ivi?"), // originally by Qamera [Celest]
BUILDIN_DEF(unitskillusepos,"iviii"), // [Celest]
@@ -20724,6 +27177,7 @@ void script_parse_builtin(void) {
BUILDIN_DEF(sleep2,"i"),
BUILDIN_DEF(awake,"s"),
BUILDIN_DEF(getvariableofnpc,"rs"),
+ BUILDIN_DEF(getvariableofpc,"ri?"),
BUILDIN_DEF(warpportal,"iisii"),
BUILDIN_DEF2(homunculus_evolution,"homevolution",""), //[orn]
BUILDIN_DEF2(homunculus_mutate,"hommutate","?"),
@@ -20751,16 +27205,23 @@ void script_parse_builtin(void) {
BUILDIN_DEF(mercenary_set_faith,"ii"),
BUILDIN_DEF(readbook,"ii"),
BUILDIN_DEF(setfont,"i"),
+ BUILDIN_DEF(getfont, ""),
BUILDIN_DEF(areamobuseskill,"siiiiviiiii"),
BUILDIN_DEF(progressbar,"si"),
+ BUILDIN_DEF(progressbar_unit,"si?"),
BUILDIN_DEF(pushpc,"ii"),
BUILDIN_DEF(buyingstore,"i"),
BUILDIN_DEF(searchstores,"ii"),
BUILDIN_DEF(showdigit,"i?"),
+ BUILDIN_DEF(msgtable, "i?"),
+ BUILDIN_DEF(msgtable2, "iv?"),
// WoE SE
BUILDIN_DEF(agitstart2,""),
BUILDIN_DEF(agitend2,""),
BUILDIN_DEF(agitcheck2,""),
+ // Achievements [Smokexyz/Hercules]
+ BUILDIN_DEF(achievement_progress, "iiii?"),
+ BUILDIN_DEF(achievement_iscompleted, "i?"),
// BattleGround
BUILDIN_DEF(waitingroom2bg,"siiss?"),
BUILDIN_DEF(waitingroom2bg_single,"isiis"),
@@ -20819,7 +27280,10 @@ void script_parse_builtin(void) {
**/
BUILDIN_DEF(bindatcmd, "ss???"),
BUILDIN_DEF(unbindatcmd, "s"),
- BUILDIN_DEF(useatcmd, "s"),
+ BUILDIN_DEF_DEPRECATED(useatcmd, "s"),
+ BUILDIN_DEF(has_permission, "v?"),
+ BUILDIN_DEF(can_use_command, "s?"),
+ BUILDIN_DEF(add_group_command, "siii"),
/**
* Item bound [Xantara] [Akinari] [Mhalicot/Hercules]
@@ -20830,8 +27294,9 @@ void script_parse_builtin(void) {
BUILDIN_DEF(checkbound, "i???????"),
//Quest Log System [Inkfish]
- BUILDIN_DEF(questinfo, "ii??"),
- BUILDIN_DEF(setquest, "i"),
+ BUILDIN_DEF(questinfo, "i?"),
+ BUILDIN_DEF(setquestinfo, "i???"),
+ BUILDIN_DEF(setquest, "i?"),
BUILDIN_DEF(erasequest, "i?"),
BUILDIN_DEF(completequest, "i?"),
BUILDIN_DEF(questprogress, "i?"),
@@ -20868,17 +27333,63 @@ void script_parse_builtin(void) {
/* New Shop Support */
BUILDIN_DEF(openshop,"?"),
- BUILDIN_DEF(sellitem,"i??"),
- BUILDIN_DEF(stopselling,"i"),
+ BUILDIN_DEF(sellitem, "i???*"),
+ BUILDIN_DEF(sellitemcurrency, "ii?"),
+ BUILDIN_DEF(startsellitem, "iii"),
+ BUILDIN_DEF(endsellitem, ""),
+ BUILDIN_DEF(stopselling,"i??"),
BUILDIN_DEF(setcurrency,"i?"),
BUILDIN_DEF(tradertype,"i"),
BUILDIN_DEF(purchaseok,""),
BUILDIN_DEF(shopcount, "i"),
+ /* Navigation */
+ BUILDIN_DEF(navigateto, "s??????"),
+
+ /* Clan System */
+ BUILDIN_DEF(clan_join,"i?"),
+ BUILDIN_DEF(clan_leave,"?"),
+ BUILDIN_DEF(clan_master,"i"),
+
BUILDIN_DEF(channelmes, "ss"),
- BUILDIN_DEF(showscript, "s?"),
+ BUILDIN_DEF(addchannelhandler, "ss"),
+ BUILDIN_DEF(removechannelhandler, "ss"),
+ BUILDIN_DEF(showscript, "s??"),
BUILDIN_DEF(mergeitem,""),
+ BUILDIN_DEF(getcalendartime, "ii??"),
+
+ // -- RoDEX
+ BUILDIN_DEF(rodex_sendmail, "isss???????????"),
+ BUILDIN_DEF2(rodex_sendmail, "rodex_sendmail_acc", "isss???????????"),
+ BUILDIN_DEF(rodex_sendmail2, "isss?????????????????????????????????????????"),
+ BUILDIN_DEF2(rodex_sendmail2, "rodex_sendmail_acc2", "isss?????????????????????????????????????????"),
+ BUILDIN_DEF(airship_respond, "i"),
+ BUILDIN_DEF(openstylist,""),
BUILDIN_DEF(_,"s"),
+ BUILDIN_DEF2(_, "_$", "s"),
+
+ // -- HatEffect
+ BUILDIN_DEF(hateffect, "ii"),
+
+ // camera
+ BUILDIN_DEF(camerainfo, ""),
+ BUILDIN_DEF(changecamera, "iii?"),
+
+ BUILDIN_DEF(itempreview, "i"),
+ BUILDIN_DEF(enchantitem, "iii"),
+ BUILDIN_DEF(expandinventoryack, "i?"),
+ BUILDIN_DEF(expandinventoryresult, "i"),
+ BUILDIN_DEF(expandinventory, "i"),
+ BUILDIN_DEF(getinventorysize, ""),
+
+ BUILDIN_DEF(closeroulette, ""),
+ BUILDIN_DEF(openrefineryui, ""),
+ BUILDIN_DEF(setfavoriteitemidx, "ii"),
+ BUILDIN_DEF(autofavoriteitem, "ii"),
+
+ BUILDIN_DEF(identify, "i"),
+ BUILDIN_DEF(identifyidx, "i"),
+ BUILDIN_DEF(openlapineddukddakboxui, "i"),
};
int i, len = ARRAYLENGTH(BUILDIN);
RECREATE(script->buildin, char *, script->buildin_count + len); // Pre-alloc to speed up
@@ -20890,7 +27401,8 @@ void script_parse_builtin(void) {
#undef BUILDIN_DEF
#undef BUILDIN_DEF2
-void script_label_add(int key, int pos) {
+static void script_label_add(int key, int pos)
+{
int idx = script->label_count;
if( script->labels_size == script->label_count ) {
@@ -20906,7 +27418,7 @@ void script_label_add(int key, int pos) {
/**
* Sets source-end constants for scripts to play with
**/
-void script_hardcoded_constants(void)
+static void script_hardcoded_constants(void)
{
script->constdb_comment("Boolean");
script->set_constant("true", 1, false, false);
@@ -20917,12 +27429,20 @@ void script_hardcoded_constants(void)
script->set_constant("MAX_LEVEL",MAX_LEVEL,false, false);
script->set_constant("MAX_STORAGE",MAX_STORAGE,false, false);
script->set_constant("MAX_GUILD_STORAGE",MAX_GUILD_STORAGE,false, false);
- script->set_constant("MAX_CART",MAX_INVENTORY,false, false);
+ script->set_constant("MAX_CART", MAX_CART, false, false);
script->set_constant("MAX_INVENTORY",MAX_INVENTORY,false, false);
+ script->set_constant("FIXED_INVENTORY_SIZE", FIXED_INVENTORY_SIZE, false, false);
script->set_constant("MAX_ZENY",MAX_ZENY,false, false);
+ script->set_constant("MAX_BANK_ZENY", MAX_BANK_ZENY, false, false);
script->set_constant("MAX_BG_MEMBERS",MAX_BG_MEMBERS,false, false);
script->set_constant("MAX_CHAT_USERS",MAX_CHAT_USERS,false, false);
script->set_constant("MAX_REFINE",MAX_REFINE,false, false);
+ script->set_constant("MAX_ITEM_ID",MAX_ITEM_ID,false, false);
+ script->set_constant("MAX_MENU_OPTIONS", MAX_MENU_OPTIONS, false, false);
+ script->set_constant("MAX_MENU_LENGTH", MAX_MENU_LENGTH, false, false);
+ script->set_constant("MOB_CLONE_START", MOB_CLONE_START, false, false);
+ script->set_constant("MOB_CLONE_END", MOB_CLONE_END, false, false);
+ script->set_constant("MAX_NPC_PER_MAP", MAX_NPC_PER_MAP, false, false);
script->constdb_comment("status options");
script->set_constant("Option_Nothing",OPTION_NOTHING,false, false);
@@ -20949,6 +27469,7 @@ void script_hardcoded_constants(void)
script->set_constant("Option_Dragon5",OPTION_DRAGON5,false, false);
script->set_constant("Option_Hanbok",OPTION_HANBOK,false, false);
script->set_constant("Option_Oktoberfest",OPTION_OKTOBERFEST,false, false);
+ script->set_constant("Option_Summer2", OPTION_SUMMER2, false, false);
script->constdb_comment("status option compounds");
script->set_constant("Option_Dragon",OPTION_DRAGON,false, false);
@@ -21026,6 +27547,483 @@ void script_hardcoded_constants(void)
script->set_constant("EQP_SHADOW_SHOES", EQP_SHADOW_SHOES, false, false);
script->set_constant("EQP_SHADOW_ACC_R", EQP_SHADOW_ACC_R, false, false);
script->set_constant("EQP_SHADOW_ACC_L", EQP_SHADOW_ACC_L, false, false);
+ // Synonyms and combined values
+ script->set_constant("EQP_WEAPON", EQP_WEAPON, false, false);
+ script->set_constant("EQP_SHIELD", EQP_SHIELD, false, false);
+ script->set_constant("EQP_ARMS", EQP_ARMS, false, false);
+ script->set_constant("EQP_HELM", EQP_HELM, false, false);
+ script->set_constant("EQP_ACC", EQP_ACC, false, false);
+ script->set_constant("EQP_COSTUME", EQP_COSTUME, false, false);
+ script->set_constant("EQP_SHADOW_ACC", EQP_SHADOW_ACC, false, false);
+ script->set_constant("EQP_SHADOW_ARMS", EQP_SHADOW_ARMS, false, false);
+
+ script->constdb_comment("Item Option Types");
+ script->set_constant("IT_OPT_INDEX", IT_OPT_INDEX, false, false);
+ script->set_constant("IT_OPT_VALUE", IT_OPT_VALUE, false, false);
+ script->set_constant("IT_OPT_PARAM", IT_OPT_PARAM, false, false);
+
+ script->constdb_comment("Maximum Item Options");
+ script->set_constant("MAX_ITEM_OPTIONS", MAX_ITEM_OPTIONS, false, false);
+
+ script->constdb_comment("Navigation constants, use with *navigateto*");
+ script->set_constant("NAV_NONE", NAV_NONE, false, false);
+ script->set_constant("NAV_AIRSHIP_ONLY", NAV_AIRSHIP_ONLY, false, false);
+ script->set_constant("NAV_SCROLL_ONLY", NAV_SCROLL_ONLY, false, false);
+ script->set_constant("NAV_AIRSHIP_AND_SCROLL", NAV_AIRSHIP_AND_SCROLL, false, false);
+ script->set_constant("NAV_KAFRA_ONLY", NAV_KAFRA_ONLY, false, false);
+ script->set_constant("NAV_KAFRA_AND_AIRSHIP", NAV_KAFRA_AND_AIRSHIP, false, false);
+ script->set_constant("NAV_KAFRA_AND_SCROLL", NAV_KAFRA_AND_SCROLL, false, false);
+ script->set_constant("NAV_ALL", NAV_ALL, false, false);
+
+ script->constdb_comment("BL types");
+ script->set_constant("BL_PC",BL_PC,false, false);
+ script->set_constant("BL_MOB",BL_MOB,false, false);
+ script->set_constant("BL_PET",BL_PET,false, false);
+ script->set_constant("BL_HOM",BL_HOM,false, false);
+ script->set_constant("BL_MER",BL_MER,false, false);
+ script->set_constant("BL_ITEM",BL_ITEM,false, false);
+ script->set_constant("BL_SKILL",BL_SKILL,false, false);
+ script->set_constant("BL_NPC",BL_NPC,false, false);
+ script->set_constant("BL_CHAT",BL_CHAT,false, false);
+ script->set_constant("BL_ELEM",BL_ELEM,false, false);
+ script->set_constant("BL_CHAR",BL_CHAR,false, false);
+ script->set_constant("BL_ALL",BL_ALL,false, false);
+
+ script->constdb_comment("Refine Chance Types");
+ script->set_constant("REFINE_CHANCE_TYPE_NORMAL", REFINE_CHANCE_TYPE_NORMAL, false, false);
+ script->set_constant("REFINE_CHANCE_TYPE_ENRICHED", REFINE_CHANCE_TYPE_ENRICHED, false, false);
+ script->set_constant("REFINE_CHANCE_TYPE_E_NORMAL", REFINE_CHANCE_TYPE_E_NORMAL, false, false);
+ script->set_constant("REFINE_CHANCE_TYPE_E_ENRICHED", REFINE_CHANCE_TYPE_E_ENRICHED, false, false);
+
+ script->constdb_comment("Player permissions");
+ script->set_constant("PERM_TRADE", PC_PERM_TRADE, false, false);
+ script->set_constant("PERM_PARTY", PC_PERM_PARTY, false, false);
+ script->set_constant("PERM_ALL_SKILL", PC_PERM_ALL_SKILL, false, false);
+ script->set_constant("PERM_USE_ALL_EQUIPMENT", PC_PERM_USE_ALL_EQUIPMENT, false, false);
+ script->set_constant("PERM_SKILL_UNCONDITIONAL", PC_PERM_SKILL_UNCONDITIONAL, false, false);
+ script->set_constant("PERM_JOIN_ALL_CHAT", PC_PERM_JOIN_ALL_CHAT, false, false);
+ script->set_constant("PERM_NO_CHAT_KICK", PC_PERM_NO_CHAT_KICK, false, false);
+ script->set_constant("PERM_HIDE_SESSION", PC_PERM_HIDE_SESSION, false, false);
+ script->set_constant("PERM_RECEIVE_HACK_INFO", PC_PERM_RECEIVE_HACK_INFO, false, false);
+ script->set_constant("PERM_WARP_ANYWHERE", PC_PERM_WARP_ANYWHERE, false, false);
+ script->set_constant("PERM_VIEW_HPMETER", PC_PERM_VIEW_HPMETER, false, false);
+ script->set_constant("PERM_VIEW_EQUIPMENT", PC_PERM_VIEW_EQUIPMENT, false, false);
+ script->set_constant("PERM_USE_CHECK", PC_PERM_USE_CHECK, false, false);
+ script->set_constant("PERM_USE_CHANGEMAPTYPE", PC_PERM_USE_CHANGEMAPTYPE, false, false);
+ script->set_constant("PERM_USE_ALL_COMMANDS", PC_PERM_USE_ALL_COMMANDS, false, false);
+ script->set_constant("PERM_RECEIVE_REQUESTS", PC_PERM_RECEIVE_REQUESTS, false, false);
+ script->set_constant("PERM_SHOW_BOSS", PC_PERM_SHOW_BOSS, false, false);
+ script->set_constant("PERM_DISABLE_PVM", PC_PERM_DISABLE_PVM, false, false);
+ script->set_constant("PERM_DISABLE_PVP", PC_PERM_DISABLE_PVP, false, false);
+ script->set_constant("PERM_DISABLE_CMD_DEAD", PC_PERM_DISABLE_CMD_DEAD, false, false);
+ script->set_constant("PERM_HCHSYS_ADMIN", PC_PERM_HCHSYS_ADMIN, false, false);
+ script->set_constant("PERM_TRADE_BOUND", PC_PERM_TRADE_BOUND, false, false);
+ script->set_constant("PERM_DISABLE_PICK_UP", PC_PERM_DISABLE_PICK_UP, false, false);
+ script->set_constant("PERM_DISABLE_STORE", PC_PERM_DISABLE_STORE, false, false);
+ script->set_constant("PERM_DISABLE_EXP", PC_PERM_DISABLE_EXP, false, false);
+ script->set_constant("PERM_DISABLE_SKILL_USAGE", PC_PERM_DISABLE_SKILL_USAGE, false, false);
+ script->set_constant("PERM_BYPASS_NOSTORAGE", PC_PERM_BYPASS_NOSTORAGE, false, false);
+
+ script->constdb_comment("Data types");
+ script->set_constant("DATATYPE_NIL", DATATYPE_NIL, false, false);
+ script->set_constant("DATATYPE_STR", DATATYPE_STR, false, false);
+ script->set_constant("DATATYPE_INT", DATATYPE_INT, false, false);
+ script->set_constant("DATATYPE_CONST", DATATYPE_CONST, false, false);
+ script->set_constant("DATATYPE_PARAM", DATATYPE_PARAM, false, false);
+ script->set_constant("DATATYPE_VAR", DATATYPE_VAR, false, false);
+ script->set_constant("DATATYPE_LABEL", DATATYPE_LABEL, false, false);
+
+ script->constdb_comment("Logmes types");
+ script->set_constant("LOGMES_NPC", LOGMES_NPC, false, false);
+ script->set_constant("LOGMES_ATCOMMAND", LOGMES_ATCOMMAND, false, false);
+
+ script->constdb_comment("Item Subtypes (Weapon types)");
+ script->set_constant("W_FIST", W_FIST, false, false);
+ script->set_constant("W_DAGGER", W_DAGGER, false, false);
+ script->set_constant("W_1HSWORD", W_1HSWORD, false, false);
+ script->set_constant("W_2HSWORD", W_2HSWORD, false, false);
+ script->set_constant("W_1HSPEAR", W_1HSPEAR, false, false);
+ script->set_constant("W_2HSPEAR", W_2HSPEAR, false, false);
+ script->set_constant("W_1HAXE", W_1HAXE, false, false);
+ script->set_constant("W_2HAXE", W_2HAXE, false, false);
+ script->set_constant("W_MACE", W_MACE, false, false);
+ script->set_constant("W_2HMACE", W_2HMACE, false, false);
+ script->set_constant("W_STAFF", W_STAFF, false, false);
+ script->set_constant("W_BOW", W_BOW, false, false);
+ script->set_constant("W_KNUCKLE", W_KNUCKLE, false, false);
+ script->set_constant("W_MUSICAL", W_MUSICAL, false, false);
+ script->set_constant("W_WHIP", W_WHIP, false, false);
+ script->set_constant("W_BOOK", W_BOOK, false, false);
+ script->set_constant("W_KATAR", W_KATAR, false, false);
+ script->set_constant("W_REVOLVER", W_REVOLVER, false, false);
+ script->set_constant("W_RIFLE", W_RIFLE, false, false);
+ script->set_constant("W_GATLING", W_GATLING, false, false);
+ script->set_constant("W_SHOTGUN", W_SHOTGUN, false, false);
+ script->set_constant("W_GRENADE", W_GRENADE, false, false);
+ script->set_constant("W_HUUMA", W_HUUMA, false, false);
+ script->set_constant("W_2HSTAFF", W_2HSTAFF, false, false);
+
+ script->constdb_comment("Item Subtypes (Ammunition types)");
+ script->set_constant("A_ARROW", A_ARROW, false, false);
+ script->set_constant("A_DAGGER", A_DAGGER, false, false);
+ script->set_constant("A_BULLET", A_BULLET, false, false);
+ script->set_constant("A_SHELL", A_SHELL, false, false);
+ script->set_constant("A_GRENADE", A_GRENADE, false, false);
+ script->set_constant("A_SHURIKEN", A_SHURIKEN, false, false);
+ script->set_constant("A_KUNAI", A_KUNAI, false, false);
+ script->set_constant("A_CANNONBALL", A_CANNONBALL, false, false);
+ script->set_constant("A_THROWWEAPON", A_THROWWEAPON, false, false);
+
+ script->constdb_comment("Item Upper Masks");
+ script->set_constant("ITEMUPPER_NONE", ITEMUPPER_NONE, false, false);
+ script->set_constant("ITEMUPPER_NORMAL", ITEMUPPER_NORMAL, false, false);
+ script->set_constant("ITEMUPPER_UPPER", ITEMUPPER_UPPER, false, false);
+ script->set_constant("ITEMUPPER_BABY", ITEMUPPER_BABY, false, false);
+ script->set_constant("ITEMUPPER_THIRD", ITEMUPPER_THIRD, false, false);
+ script->set_constant("ITEMUPPER_THIRDUPPER", ITEMUPPER_THIRDUPPER, false, false);
+ script->set_constant("ITEMUPPER_THIRDBABY", ITEMUPPER_THIRDBABY, false, false);
+ script->set_constant("ITEMUPPER_ALL", ITEMUPPER_ALL, false, false);
+
+ script->constdb_comment("dressroom modes");
+ script->set_constant("DRESSROOM_OPEN", DRESSROOM_OPEN, false, false);
+ script->set_constant("DRESSROOM_CLOSE", DRESSROOM_CLOSE, false, false);
+
+ script->constdb_comment("getmapinfo options");
+ script->set_constant("MAPINFO_NAME", MAPINFO_NAME, false, false);
+ script->set_constant("MAPINFO_ID", MAPINFO_ID, false, false);
+ script->set_constant("MAPINFO_SIZE_X", MAPINFO_SIZE_X, false, false);
+ script->set_constant("MAPINFO_SIZE_Y", MAPINFO_SIZE_Y, false, false);
+ script->set_constant("MAPINFO_ZONE", MAPINFO_ZONE, false, false);
+ script->set_constant("MAPINFO_NPC_COUNT", MAPINFO_NPC_COUNT, false, false);
+
+ script->constdb_comment("consolemes options");
+ script->set_constant("CONSOLEMES_DEBUG", CONSOLEMES_DEBUG, false, false);
+ script->set_constant("CONSOLEMES_ERROR", CONSOLEMES_ERROR, false, false);
+ script->set_constant("CONSOLEMES_WARNING", CONSOLEMES_WARNING, false, false);
+ script->set_constant("CONSOLEMES_INFO", CONSOLEMES_INFO, false, false);
+ script->set_constant("CONSOLEMES_STATUS", CONSOLEMES_STATUS, false, false);
+ script->set_constant("CONSOLEMES_NOTICE", CONSOLEMES_NOTICE, false, false);
+
+ script->constdb_comment("set/getiteminfo options");
+ script->set_constant("ITEMINFO_BUYPRICE", ITEMINFO_BUYPRICE, false, false);
+ script->set_constant("ITEMINFO_SELLPRICE", ITEMINFO_SELLPRICE, false, false);
+ script->set_constant("ITEMINFO_TYPE", ITEMINFO_TYPE, false, false);
+ script->set_constant("ITEMINFO_MAXCHANCE", ITEMINFO_MAXCHANCE, false, false);
+ script->set_constant("ITEMINFO_SEX", ITEMINFO_SEX, false, false);
+ script->set_constant("ITEMINFO_LOC", ITEMINFO_LOC, false, false);
+ script->set_constant("ITEMINFO_WEIGHT", ITEMINFO_WEIGHT, false, false);
+ script->set_constant("ITEMINFO_ATK", ITEMINFO_ATK, false, false);
+ script->set_constant("ITEMINFO_DEF", ITEMINFO_DEF, false, false);
+ script->set_constant("ITEMINFO_RANGE", ITEMINFO_RANGE, false, false);
+ script->set_constant("ITEMINFO_SLOTS", ITEMINFO_SLOTS, false, false);
+ script->set_constant("ITEMINFO_SUBTYPE", ITEMINFO_SUBTYPE, false, false);
+ script->set_constant("ITEMINFO_ELV", ITEMINFO_ELV, false, false);
+ script->set_constant("ITEMINFO_WLV", ITEMINFO_WLV, false, false);
+ script->set_constant("ITEMINFO_VIEWID", ITEMINFO_VIEWID, false, false);
+ script->set_constant("ITEMINFO_MATK", ITEMINFO_MATK, false, false);
+ script->set_constant("ITEMINFO_VIEWSPRITE", ITEMINFO_VIEWSPRITE, false, false);
+ script->set_constant("ITEMINFO_TRADE", ITEMINFO_TRADE, false, false);
+ script->set_constant("ITEMINFO_ELV_MAX", ITEMINFO_ELV_MAX, false, false);
+ script->set_constant("ITEMINFO_DROPEFFECT_MODE", ITEMINFO_DROPEFFECT_MODE, false, false);
+ script->set_constant("ITEMINFO_DELAY", ITEMINFO_DELAY, false, false);
+ script->set_constant("ITEMINFO_CLASS_BASE_1", ITEMINFO_CLASS_BASE_1, false, false);
+ script->set_constant("ITEMINFO_CLASS_BASE_2", ITEMINFO_CLASS_BASE_2, false, false);
+ script->set_constant("ITEMINFO_CLASS_BASE_3", ITEMINFO_CLASS_BASE_3, false, false);
+ script->set_constant("ITEMINFO_CLASS_UPPER", ITEMINFO_CLASS_UPPER, false, false);
+ script->set_constant("ITEMINFO_FLAG_NO_REFINE", ITEMINFO_FLAG_NO_REFINE, false, false);
+ script->set_constant("ITEMINFO_FLAG_DELAY_CONSUME", ITEMINFO_FLAG_DELAY_CONSUME, false, false);
+ script->set_constant("ITEMINFO_FLAG_AUTOEQUIP", ITEMINFO_FLAG_AUTOEQUIP, false, false);
+ script->set_constant("ITEMINFO_FLAG_AUTO_FAVORITE", ITEMINFO_FLAG_AUTO_FAVORITE, false, false);
+ script->set_constant("ITEMINFO_FLAG_BUYINGSTORE", ITEMINFO_FLAG_BUYINGSTORE, false, false);
+ script->set_constant("ITEMINFO_FLAG_BINDONEQUIP", ITEMINFO_FLAG_BINDONEQUIP, false, false);
+ script->set_constant("ITEMINFO_FLAG_KEEPAFTERUSE", ITEMINFO_FLAG_KEEPAFTERUSE, false, false);
+ script->set_constant("ITEMINFO_FLAG_FORCE_SERIAL", ITEMINFO_FLAG_FORCE_SERIAL, false, false);
+ script->set_constant("ITEMINFO_FLAG_NO_OPTIONS", ITEMINFO_FLAG_NO_OPTIONS, false, false);
+ script->set_constant("ITEMINFO_FLAG_DROP_ANNOUNCE", ITEMINFO_FLAG_DROP_ANNOUNCE, false, false);
+ script->set_constant("ITEMINFO_FLAG_SHOWDROPEFFECT", ITEMINFO_FLAG_SHOWDROPEFFECT, false, false);
+ script->set_constant("ITEMINFO_STACK_AMOUNT", ITEMINFO_STACK_AMOUNT, false, false);
+ script->set_constant("ITEMINFO_STACK_FLAG", ITEMINFO_STACK_FLAG, false, false);
+ 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);
+ script->set_constant("MERCINFO_CLASS", MERCINFO_CLASS, false, false);
+ script->set_constant("MERCINFO_NAME", MERCINFO_NAME, false, false);
+ script->set_constant("MERCINFO_FAITH", MERCINFO_FAITH, false, false);
+ script->set_constant("MERCINFO_CALLS", MERCINFO_CALLS, false, false);
+ script->set_constant("MERCINFO_KILLCOUNT", MERCINFO_KILLCOUNT, false, false);
+ script->set_constant("MERCINFO_LIFETIME", MERCINFO_LIFETIME, false, false);
+ script->set_constant("MERCINFO_LEVEL", MERCINFO_LEVEL, false, false);
+ script->set_constant("MERCINFO_GID", MERCINFO_GID, false, false);
+
+ script->constdb_comment("getpetinfo options");
+ script->set_constant("PETINFO_ID", PETINFO_ID, false, false);
+ script->set_constant("PETINFO_CLASS", PETINFO_CLASS, false, false);
+ script->set_constant("PETINFO_NAME", PETINFO_NAME, false, false);
+ script->set_constant("PETINFO_INTIMACY", PETINFO_INTIMACY, false, false);
+ script->set_constant("PETINFO_HUNGRY", PETINFO_HUNGRY, false, false);
+ script->set_constant("PETINFO_RENAME", PETINFO_RENAME, false, false);
+ script->set_constant("PETINFO_GID", PETINFO_GID, false, false);
+ script->set_constant("PETINFO_EGGITEM", PETINFO_EGGITEM, false, false);
+ script->set_constant("PETINFO_FOODITEM", PETINFO_FOODITEM, false, false);
+ script->set_constant("PETINFO_ACCESSORYITEM", PETINFO_ACCESSORYITEM, false, false);
+ script->set_constant("PETINFO_ACCESSORYFLAG", PETINFO_ACCESSORYFLAG, false, false);
+ 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);
+ script->set_constant("MSS_WALK", MSS_WALK, false, false);
+ script->set_constant("MSS_LOOT", MSS_LOOT, false, false);
+ script->set_constant("MSS_DEAD", MSS_DEAD, false, false);
+ script->set_constant("MSS_BERSERK", MSS_BERSERK, false, false);
+ script->set_constant("MSS_ANGRY", MSS_ANGRY, false, false);
+ script->set_constant("MSS_RUSH", MSS_RUSH, false, false);
+ script->set_constant("MSS_FOLLOW", MSS_FOLLOW, false, false);
+ script->set_constant("MSS_ANYTARGET", MSS_ANYTARGET, false, false);
+
+ script->constdb_comment("monster skill conditions");
+ script->set_constant("MSC_ANY", -1, false, false);
+ script->set_constant("MSC_ALWAYS", MSC_ALWAYS, false, false);
+ script->set_constant("MSC_MYHPLTMAXRATE", MSC_MYHPLTMAXRATE, false, false);
+ script->set_constant("MSC_MYHPINRATE", MSC_MYHPINRATE, false, false);
+ script->set_constant("MSC_FRIENDHPLTMAXRATE", MSC_FRIENDHPLTMAXRATE, false, false);
+ script->set_constant("MSC_FRIENDHPINRATE", MSC_FRIENDHPINRATE, false, false);
+ script->set_constant("MSC_MYSTATUSON", MSC_MYSTATUSON, false, false);
+ script->set_constant("MSC_MYSTATUSOFF", MSC_MYSTATUSOFF, false, false);
+ script->set_constant("MSC_FRIENDSTATUSON", MSC_FRIENDSTATUSON, false, false);
+ script->set_constant("MSC_FRIENDSTATUSOFF", MSC_FRIENDSTATUSOFF, false, false);
+ script->set_constant("MSC_ATTACKPCGT", MSC_ATTACKPCGT, false, false);
+ script->set_constant("MSC_ATTACKPCGE", MSC_ATTACKPCGE, false, false);
+ script->set_constant("MSC_SLAVELT", MSC_SLAVELT, false, false);
+ script->set_constant("MSC_SLAVELE", MSC_SLAVELE, false, false);
+ script->set_constant("MSC_CLOSEDATTACKED", MSC_CLOSEDATTACKED, false, false);
+ script->set_constant("MSC_LONGRANGEATTACKED", MSC_LONGRANGEATTACKED, false, false);
+ script->set_constant("MSC_SKILLUSED", MSC_SKILLUSED, false, false);
+ script->set_constant("MSC_AFTERSKILL", MSC_AFTERSKILL, false, false);
+ script->set_constant("MSC_CASTTARGETED", MSC_CASTTARGETED, false, false);
+ script->set_constant("MSC_RUDEATTACKED", MSC_RUDEATTACKED, false, false);
+ script->set_constant("MSC_MASTERHPLTMAXRATE", MSC_MASTERHPLTMAXRATE, false, false);
+ script->set_constant("MSC_MASTERATTACKED", MSC_MASTERATTACKED, false, false);
+ script->set_constant("MSC_ALCHEMIST", MSC_ALCHEMIST, false, false);
+ script->set_constant("MSC_SPAWN", MSC_SPAWN, false, false);
+
+ script->constdb_comment("monster skill targets");
+ script->set_constant("MST_TARGET", MST_TARGET, false, false);
+ script->set_constant("MST_RANDOM", MST_RANDOM , false, false);
+ script->set_constant("MST_SELF", MST_SELF, false, false);
+ script->set_constant("MST_FRIEND", MST_FRIEND , false, false);
+ script->set_constant("MST_MASTER", MST_MASTER , false, false);
+ script->set_constant("MST_AROUND5", MST_AROUND5, false, false);
+ script->set_constant("MST_AROUND6", MST_AROUND6, false, false);
+ script->set_constant("MST_AROUND7", MST_AROUND7, false, false);
+ script->set_constant("MST_AROUND8", MST_AROUND8, false, false);
+ script->set_constant("MST_AROUND1", MST_AROUND1, false, false);
+ script->set_constant("MST_AROUND2", MST_AROUND2, false, false);
+ script->set_constant("MST_AROUND3", MST_AROUND3, false, false);
+ script->set_constant("MST_AROUND4", MST_AROUND4, false, false);
+ script->set_constant("MST_AROUND", MST_AROUND , false, false);
+
+ script->constdb_comment("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);
+ script->set_constant("PCBLOCK_ATTACK", PCBLOCK_ATTACK, false, false);
+ script->set_constant("PCBLOCK_SKILL", PCBLOCK_SKILL, false, false);
+ script->set_constant("PCBLOCK_USEITEM", PCBLOCK_USEITEM, false, false);
+ script->set_constant("PCBLOCK_CHAT", PCBLOCK_CHAT, false, false);
+ script->set_constant("PCBLOCK_IMMUNE", PCBLOCK_IMMUNE, false, false);
+ script->set_constant("PCBLOCK_SITSTAND", PCBLOCK_SITSTAND, false, false);
+ script->set_constant("PCBLOCK_COMMANDS", PCBLOCK_COMMANDS, false, false);
+ script->set_constant("PCBLOCK_NPC", PCBLOCK_NPC, false, false);
+
+ script->constdb_comment("private airship responds");
+ script->set_constant("P_AIRSHIP_NONE", P_AIRSHIP_NONE, false, false);
+ script->set_constant("P_AIRSHIP_RETRY", P_AIRSHIP_RETRY, false, false);
+ script->set_constant("P_AIRSHIP_INVALID_START_MAP", P_AIRSHIP_INVALID_START_MAP, false, false);
+ script->set_constant("P_AIRSHIP_INVALID_END_MAP", P_AIRSHIP_INVALID_END_MAP, false, false);
+ script->set_constant("P_AIRSHIP_ITEM_NOT_ENOUGH", P_AIRSHIP_ITEM_NOT_ENOUGH, false, false);
+ script->set_constant("P_AIRSHIP_ITEM_INVALID", P_AIRSHIP_ITEM_INVALID, false, false);
+
+ script->constdb_comment("questinfo types");
+ script->set_constant("QINFO_JOB", QINFO_JOB, false, false);
+ script->set_constant("QINFO_SEX", QINFO_SEX, false, false);
+ script->set_constant("QINFO_BASE_LEVEL", QINFO_BASE_LEVEL, false, false);
+ script->set_constant("QINFO_JOB_LEVEL", QINFO_JOB_LEVEL, false, false);
+ script->set_constant("QINFO_ITEM", QINFO_ITEM, false, false);
+ script->set_constant("QINFO_HOMUN_LEVEL", QINFO_HOMUN_LEVEL, false, false);
+ script->set_constant("QINFO_HOMUN_TYPE", QINFO_HOMUN_TYPE, false, false);
+ script->set_constant("QINFO_QUEST", QINFO_QUEST, false, false);
+ script->set_constant("QINFO_MERCENARY_CLASS", QINFO_MERCENARY_CLASS, false, false);
+
+ script->constdb_comment("function types");
+ script->set_constant("FUNCTION_IS_COMMAND", FUNCTION_IS_COMMAND, false, false);
+ script->set_constant("FUNCTION_IS_GLOBAL", FUNCTION_IS_GLOBAL, false, false);
+ script->set_constant("FUNCTION_IS_LOCAL", FUNCTION_IS_LOCAL, false, false);
+ script->set_constant("FUNCTION_IS_LABEL", FUNCTION_IS_LABEL, false, false);
+
+ script->constdb_comment("item trade restrictions");
+ script->set_constant("ITR_NONE", ITR_NONE, false, false);
+ script->set_constant("ITR_NODROP", ITR_NODROP, false, false);
+ script->set_constant("ITR_NOTRADE", ITR_NOTRADE, false, false);
+ script->set_constant("ITR_PARTNEROVERRIDE", ITR_PARTNEROVERRIDE, false, false);
+ script->set_constant("ITR_NOSELLTONPC", ITR_NOSELLTONPC, false, false);
+ script->set_constant("ITR_NOCART", ITR_NOCART, false, false);
+ script->set_constant("ITR_NOSTORAGE", ITR_NOSTORAGE, false, false);
+ script->set_constant("ITR_NOGSTORAGE", ITR_NOGSTORAGE, false, false);
+ script->set_constant("ITR_NOMAIL", ITR_NOMAIL, false, false);
+ script->set_constant("ITR_NOAUCTION", ITR_NOAUCTION, false, false);
+ script->set_constant("ITR_ALL", ITR_ALL, false, false);
+
+ script->constdb_comment("inventory expand ack responds");
+ script->set_constant("EXPAND_INV_ASK_CONFIRMATION", EXPAND_INVENTORY_ASK_CONFIRMATION, false, false);
+ script->set_constant("EXPAND_INV_FAILED", EXPAND_INVENTORY_FAILED, false, false);
+ script->set_constant("EXPAND_INV_OTHER_WORK", EXPAND_INVENTORY_OTHER_WORK, false, false);
+ script->set_constant("EXPAND_INV_MISSING_ITEM", EXPAND_INVENTORY_MISSING_ITEM, false, false);
+ script->set_constant("EXPAND_INV_MAX_SIZE", EXPAND_INVENTORY_MAX_SIZE, false, false);
+
+ script->constdb_comment("inventory expand final responds");
+ script->set_constant("EXPAND_INV_RESULT_SUCCESS", EXPAND_INVENTORY_RESULT_SUCCESS, false, false);
+ script->set_constant("EXPAND_INV_RESULT_FAILED", EXPAND_INVENTORY_RESULT_FAILED, false, false);
+ script->set_constant("EXPAND_INV_RESULT_OTHER_WORK", EXPAND_INVENTORY_RESULT_OTHER_WORK, false, false);
+ script->set_constant("EXPAND_INV_RESULT_MISSING_ITEM", EXPAND_INVENTORY_RESULT_MISSING_ITEM, false, false);
+ script->set_constant("EXPAND_INV_RESULT_MAX_SIZE", EXPAND_INVENTORY_RESULT_MAX_SIZE, false, false);
+
+ script->constdb_comment("trader type");
+ script->set_constant("NST_ZENY", NST_ZENY, false, false);
+ script->set_constant("NST_CASH", NST_CASH, false, false);
+ script->set_constant("NST_MARKET", NST_MARKET, false, false);
+ script->set_constant("NST_CUSTOM", NST_CUSTOM, false, false);
+ script->set_constant("NST_BARTER", NST_BARTER, false, false);
+ script->set_constant("NST_EXPANDED_BARTER", NST_EXPANDED_BARTER, false, false);
+
+ script->constdb_comment("script unit data types");
+ script->set_constant("UDT_TYPE", UDT_TYPE, false, false);
+ script->set_constant("UDT_SIZE", UDT_SIZE, false, false);
+ script->set_constant("UDT_LEVEL", UDT_LEVEL, false, false);
+ script->set_constant("UDT_HP", UDT_HP, false, false);
+ script->set_constant("UDT_MAXHP", UDT_MAXHP, false, false);
+ script->set_constant("UDT_SP", UDT_SP, false, false);
+ script->set_constant("UDT_MAXSP", UDT_MAXSP, false, false);
+ script->set_constant("UDT_MASTERAID", UDT_MASTERAID, false, false);
+ script->set_constant("UDT_MASTERCID", UDT_MASTERCID, false, false);
+ script->set_constant("UDT_MAPIDXY", UDT_MAPIDXY, false, true); // for setunitdata use *unitwarp, for getunitdata use *getmapxy
+ script->set_constant("UDT_WALKTOXY", UDT_WALKTOXY, false, true); // use *unitwalk
+ script->set_constant("UDT_SPEED", UDT_SPEED, false, false);
+ script->set_constant("UDT_MODE", UDT_MODE, false, false);
+ script->set_constant("UDT_AI", UDT_AI, false, false);
+ script->set_constant("UDT_SCOPTION", UDT_SCOPTION, false, false);
+ script->set_constant("UDT_SEX", UDT_SEX, false, false);
+ script->set_constant("UDT_CLASS", UDT_CLASS, false, false);
+ script->set_constant("UDT_HAIRSTYLE", UDT_HAIRSTYLE, false, false);
+ script->set_constant("UDT_HAIRCOLOR", UDT_HAIRCOLOR, false, false);
+ script->set_constant("UDT_HEADBOTTOM", UDT_HEADBOTTOM, false, false);
+ script->set_constant("UDT_HEADMIDDLE", UDT_HEADMIDDLE, false, false);
+ script->set_constant("UDT_HEADTOP", UDT_HEADTOP, false, false);
+ script->set_constant("UDT_CLOTHCOLOR", UDT_CLOTHCOLOR, false, false);
+ script->set_constant("UDT_SHIELD", UDT_SHIELD, false, false);
+ script->set_constant("UDT_WEAPON", UDT_WEAPON, false, false);
+ script->set_constant("UDT_LOOKDIR", UDT_LOOKDIR, false, false);
+ script->set_constant("UDT_CANMOVETICK", UDT_CANMOVETICK, false, false);
+ script->set_constant("UDT_STR", UDT_STR, false, false);
+ script->set_constant("UDT_AGI", UDT_AGI, false, false);
+ script->set_constant("UDT_VIT", UDT_VIT, false, false);
+ script->set_constant("UDT_INT", UDT_INT, false, false);
+ script->set_constant("UDT_DEX", UDT_DEX, false, false);
+ script->set_constant("UDT_LUK", UDT_LUK, false, false);
+ script->set_constant("UDT_ATKRANGE", UDT_ATKRANGE, false, false);
+ script->set_constant("UDT_ATKMIN", UDT_ATKMIN, false, false);
+ script->set_constant("UDT_ATKMAX", UDT_ATKMAX, false, false);
+ script->set_constant("UDT_MATKMIN", UDT_MATKMIN, false, false);
+ script->set_constant("UDT_MATKMAX", UDT_MATKMAX, false, false);
+ script->set_constant("UDT_DEF", UDT_DEF, false, false);
+ script->set_constant("UDT_MDEF", UDT_MDEF, false, false);
+ script->set_constant("UDT_HIT", UDT_HIT, false, false);
+ script->set_constant("UDT_FLEE", UDT_FLEE, false, false);
+ script->set_constant("UDT_PDODGE", UDT_PDODGE, false, false);
+ script->set_constant("UDT_CRIT", UDT_CRIT, false, false);
+ script->set_constant("UDT_RACE", UDT_RACE, false, false);
+ script->set_constant("UDT_ELETYPE", UDT_ELETYPE, false, false);
+ script->set_constant("UDT_ELELEVEL", UDT_ELELEVEL, false, false);
+ script->set_constant("UDT_AMOTION", UDT_AMOTION, false, false);
+ script->set_constant("UDT_ADELAY", UDT_ADELAY, false, false);
+ script->set_constant("UDT_DMOTION", UDT_DMOTION, false, false);
+ script->set_constant("UDT_HUNGER", UDT_HUNGER, false, false);
+ script->set_constant("UDT_INTIMACY", UDT_INTIMACY, false, false);
+ script->set_constant("UDT_LIFETIME", UDT_LIFETIME, false, false);
+ script->set_constant("UDT_MERC_KILLCOUNT", UDT_MERC_KILLCOUNT, false, false);
+ script->set_constant("UDT_STATPOINT", UDT_STATPOINT, false, false);
+ script->set_constant("UDT_ROBE", UDT_ROBE, false, false);
+ script->set_constant("UDT_BODY2", UDT_BODY2, false, false);
+ script->set_constant("UDT_GROUP", UDT_GROUP, false, false);
+ script->set_constant("UDT_DAMAGE_TAKEN_RATE", UDT_DAMAGE_TAKEN_RATE, false, false);
+
+ script->constdb_comment("getguildonline types");
+ script->set_constant("GUILD_ONLINE_ALL", GUILD_ONLINE_ALL, false, false);
+ script->set_constant("GUILD_ONLINE_VENDOR", GUILD_ONLINE_VENDOR, false, false);
+ script->set_constant("GUILD_ONLINE_NO_VENDOR", GUILD_ONLINE_NO_VENDOR, false, false);
+
+ script->constdb_comment("Siege Types");
+ script->set_constant("SIEGE_TYPE_FE", SIEGE_TYPE_FE, false, false);
+ script->set_constant("SIEGE_TYPE_SE", SIEGE_TYPE_SE, false, false);
+ script->set_constant("SIEGE_TYPE_TE", SIEGE_TYPE_TE, false, false);
+
+ script->constdb_comment("guildinfo types");
+ script->set_constant("GUILDINFO_NAME", GUILDINFO_NAME, false, false);
+ script->set_constant("GUILDINFO_ID", GUILDINFO_ID, false, false);
+ script->set_constant("GUILDINFO_LEVEL", GUILDINFO_LEVEL, false, false);
+ script->set_constant("GUILDINFO_ONLINE", GUILDINFO_ONLINE, false, false);
+ script->set_constant("GUILDINFO_AV_LEVEL", GUILDINFO_AV_LEVEL, false, false);
+ script->set_constant("GUILDINFO_MAX_MEMBERS", GUILDINFO_MAX_MEMBERS, false, false);
+ script->set_constant("GUILDINFO_EXP", GUILDINFO_EXP, false, false);
+ script->set_constant("GUILDINFO_NEXT_EXP", GUILDINFO_NEXT_EXP, false, false);
+ script->set_constant("GUILDINFO_SKILL_POINTS", GUILDINFO_SKILL_POINTS, false, false);
+ script->set_constant("GUILDINFO_MASTER_NAME", GUILDINFO_MASTER_NAME, false, false);
+ script->set_constant("GUILDINFO_MASTER_CID", GUILDINFO_MASTER_CID, false, false);
+
+ script->constdb_comment("madogear types");
+ script->set_constant("MADO_ROBOT", MADO_ROBOT, false, false);
+ script->set_constant("MADO_SUITE", MADO_SUITE, false, false);
+
+ script->constdb_comment("itemskill option flags");
+ script->set_constant("ISF_NONE", ISF_NONE, 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
@@ -21069,7 +28067,8 @@ void script_hardcoded_constants(void)
/**
* a mapindex_name2id wrapper meant to help with invalid name handling
**/
-unsigned short script_mapindexname2id (struct script_state *st, const char* name) {
+static unsigned short script_mapindexname2id(struct script_state *st, const char *name)
+{
unsigned short index;
if( !(index=mapindex->name2id(name)) ) {
@@ -21079,7 +28078,8 @@ unsigned short script_mapindexname2id (struct script_state *st, const char* name
return index;
}
-void script_defaults(void) {
+void script_defaults(void)
+{
// aegis->athena slot position conversion table
unsigned int equip[SCRIPT_EQUIP_TABLE_SIZE] = {EQP_HEAD_TOP,EQP_ARMOR,EQP_HAND_L,EQP_HAND_R,EQP_GARMENT,EQP_SHOES,EQP_ACC_L,EQP_ACC_R,EQP_HEAD_MID,EQP_HEAD_LOW,EQP_COSTUME_HEAD_LOW,EQP_COSTUME_HEAD_MID,EQP_COSTUME_HEAD_TOP,EQP_COSTUME_GARMENT,EQP_SHADOW_ARMOR, EQP_SHADOW_WEAPON, EQP_SHADOW_SHIELD, EQP_SHADOW_SHOES, EQP_SHADOW_ACC_R, EQP_SHADOW_ACC_L};
@@ -21112,8 +28112,8 @@ void script_defaults(void) {
script->label_count = 0;
script->labels_size = 0;
- script->buf = NULL;
- script->pos = 0, script->size = 0;
+ VECTOR_INIT(script->buf);
+ VECTOR_INIT(script->translation_buf);
script->parse_options = 0;
script->buildin_set_ref = 0;
@@ -21171,10 +28171,12 @@ void script_defaults(void) {
script->get_val = get_val;
script->get_val2 = get_val2;
script->get_val_ref_str = get_val_npcscope_str;
+ script->get_val_pc_ref_str = get_val_pc_ref_str;
script->get_val_scope_str = get_val_npcscope_str;
script->get_val_npc_str = get_val_npcscope_str;
script->get_val_instance_str = get_val_instance_str;
script->get_val_ref_num = get_val_npcscope_num;
+ script->get_val_pc_ref_num = get_val_pc_ref_num;
script->get_val_scope_num = get_val_npcscope_num;
script->get_val_npc_num = get_val_npcscope_num;
script->get_val_instance_num = get_val_instance_num;
@@ -21203,10 +28205,12 @@ void script_defaults(void) {
script->setarray_pc = script_setarray_pc;
script->config_read = script_config_read;
script->add_str = script_add_str;
+ script->add_variable = script_add_variable;
script->get_str = script_get_str;
script->search_str = script_search_str;
script->setd_sub = setd_sub;
script->attach_state = script_attach_state;
+ script->sprintf_helper = script_sprintf_helper;
script->queue = script_hqueue_get;
script->queue_add = script_hqueue_add;
@@ -21239,6 +28243,11 @@ void script_defaults(void) {
script->parse_nextline = parse_nextline;
script->parse_variable = parse_variable;
script->parse_simpleexpr = parse_simpleexpr;
+ script->parse_simpleexpr_paren = parse_simpleexpr_paren;
+ script->parse_simpleexpr_number = parse_simpleexpr_number;
+ script->parse_simpleexpr_string = parse_simpleexpr_string;
+ script->parse_simpleexpr_name = parse_simpleexpr_name;
+ script->add_translatable_string = script_add_translatable_string;
script->parse_expr = parse_expr;
script->parse_line = parse_line;
script->read_constdb = read_constdb;
@@ -21248,10 +28257,12 @@ void script_defaults(void) {
script->errorwarning_sub = script_errorwarning_sub;
script->set_reg = set_reg;
script->set_reg_ref_str = set_reg_npcscope_str;
+ script->set_reg_pc_ref_str = set_reg_pc_ref_str;
script->set_reg_scope_str = set_reg_npcscope_str;
script->set_reg_npc_str = set_reg_npcscope_str;
script->set_reg_instance_str = set_reg_instance_str;
script->set_reg_ref_num = set_reg_npcscope_num;
+ script->set_reg_pc_ref_num = set_reg_pc_ref_num;
script->set_reg_scope_num = set_reg_npcscope_num;
script->set_reg_npc_num = set_reg_npcscope_num;
script->set_reg_instance_num = set_reg_instance_num;
@@ -21268,6 +28279,9 @@ void script_defaults(void) {
script->db_free_code_sub = db_script_free_code_sub;
script->add_autobonus = script_add_autobonus;
script->menu_countoptions = menu_countoptions;
+ script->buildin_recovery_sub = buildin_recovery_sub;
+ script->buildin_recovery_pc_sub = buildin_recovery_pc_sub;
+ script->buildin_recovery_bl_sub = buildin_recovery_bl_sub;
script->buildin_areawarp_sub = buildin_areawarp_sub;
script->buildin_areapercentheal_sub = buildin_areapercentheal_sub;
script->buildin_delitem_delete = buildin_delitem_delete;
@@ -21295,8 +28309,8 @@ void script_defaults(void) {
script->getfuncname = script_getfuncname;
/* script_config base */
- script->config.warn_func_mismatch_argtypes = 1;
- script->config.warn_func_mismatch_paramnum = 1;
+ script->config.warn_func_mismatch_argtypes = true;
+ script->config.warn_func_mismatch_paramnum = true;
script->config.check_cmdcount = 65535;
script->config.check_gotocount = 2048;
script->config.input_min_value = 0;
@@ -21358,15 +28372,22 @@ void script_defaults(void) {
script->mapindexname2id = script_mapindexname2id;
script->string_dup = script_string_dup;
script->load_translations = script_load_translations;
+ script->load_translation_addstring = script_load_translation_addstring;
+ script->load_translation_file = script_load_translation_file;
script->load_translation = script_load_translation;
script->translation_db_destroyer = script_translation_db_destroyer;
script->clear_translations = script_clear_translations;
script->parse_cleanup_timer = script_parse_cleanup_timer;
script->add_language = script_add_language;
- script->get_translation_file_name = script_get_translation_file_name;
+ script->get_translation_dir_name = script_get_translation_dir_name;
script->parser_clean_leftovers = script_parser_clean_leftovers;
script->run_use_script = script_run_use_script;
script->run_item_equip_script = script_run_item_equip_script;
script->run_item_unequip_script = script_run_item_unequip_script;
+ script->run_item_rental_start_script = script_run_item_rental_start_script;
+ script->run_item_rental_end_script = script_run_item_rental_end_script;
+ script->run_item_lapineddukddak_script = script_run_item_lapineddukddak_script;
+
+ script->sellitemcurrency_add = script_sellitemcurrency_add;
}