1 // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
2 // For more information, see LICENCE in the main folder
8 //#define DEBUG_DUMP_STACK
11 #include "../../3rdparty/pcre/include/pcre.h" // preg_match
14 #include "../common/cbasetypes.h"
15 #include "../common/malloc.h"
16 #include "../common/md5calc.h"
17 #include "../common/nullpo.h"
18 #include "../common/random.h"
19 #include "../common/showmsg.h"
20 #include "../common/socket.h"
21 #include "../common/strlib.h"
22 #include "../common/timer.h"
23 #include "../common/utils.h"
24 #ifdef BETA_THREAD_TEST
25 #include "../common/atomic.h"
26 #include "../common/spinlock.h"
27 #include "../common/thread.h"
28 #include "../common/mutex.h"
36 #include "date.h" // date type enum, date_get()
42 #include "homunculus.h"
44 #include "mercenary.h"
47 #include "battleground.h"
51 #include "elemental.h"
53 #include "achievement.h"
56 #include <stdlib.h> // atoi, strtol, strtoll, exit
64 struct eri *array_ers;
66 unsigned int active_scripts;
69 struct eri *stack_ers;
71 static bool script_rid2sd_( struct script_state *st, struct map_session_data** sd, const char *func );
74 * Get `sd` from a account id in `loc` param instead of attached rid
76 * @param loc Location to look account id in script parameter
77 * @param sd Variable that will be assigned
78 * @return True if `sd` is assigned, false otherwise
80 static bool script_accid2sd_(struct script_state *st, uint8 loc, struct map_session_data **sd, const char *func) {
81 if (script_hasdata(st, loc)) {
82 int id_ = script_getnum(st, loc);
83 if (!(*sd = map_id2sd(id_))){
84 ShowError("%s: Player with account id '%d' is not found.\n", func, id_);
91 return script_rid2sd_(st,sd,func);
95 * Get `sd` from a char id in `loc` param instead of attached rid
97 * @param loc Location to look char id in script parameter
98 * @param sd Variable that will be assigned
99 * @return True if `sd` is assigned, false otherwise
101 static bool script_charid2sd_(struct script_state *st, uint8 loc, struct map_session_data **sd, const char *func) {
102 if (script_hasdata(st, loc)) {
103 int id_ = script_getnum(st, loc);
104 if (!(*sd = map_charid2sd(id_))){
105 ShowError("%s: Player with char id '%d' is not found.\n", func, id_);
112 return script_rid2sd_(st,sd,func);
116 * Get `sd` from a nick in `loc` param instead of attached rid
118 * @param loc Location to look nick in script parameter
119 * @param sd Variable that will be assigned
120 * @return True if `sd` is assigned, false otherwise
122 static bool script_nick2sd_(struct script_state *st, uint8 loc, struct map_session_data **sd, const char *func) {
123 if (script_hasdata(st, loc)) {
124 const char *name_ = script_getstr(st, loc);
125 if (!(*sd = map_nick2sd(name_,false))){
126 ShowError("%s: Player with nick '%s' is not found.\n", func, name_);
133 return script_rid2sd_(st,sd,func);
137 * Get `sd` from a mapid in `loc` param instead of attached rid
139 * @param loc Location to look mapid in script parameter
140 * @param sd Variable that will be assigned
141 * @return True if `sd` is assigned, false otherwise
143 static bool script_mapid2sd_(struct script_state *st, uint8 loc, struct map_session_data **sd, const char *func) {
144 if (script_hasdata(st, loc)) {
145 int id_ = script_getnum(st, loc);
146 if (!(*sd = map_id2sd(id_))){
147 ShowError("%s: Player with map id '%d' is not found.\n", func, id_);
154 return script_rid2sd_(st,sd,func);
158 * Get `bl` from an ID in `loc` param, if ID is 0 will return the `bl` of the script's activator.
160 * @param loc Location to look for ID in script parameter
161 * @param bl Variable that will be assigned
162 * @return True if `bl` is assigned, false otherwise
164 static bool script_rid2bl_(struct script_state *st, uint8 loc, struct block_list **bl, const char *func) {
167 if ( !script_hasdata(st, loc) || ( unit_id = script_getnum(st, loc) ) == 0)
170 *bl = map_id2bl(unit_id);
175 ShowError("%s: Unit with ID '%d' is not found.\n", func, unit_id);
180 #define script_accid2sd(loc,sd) script_accid2sd_(st,(loc),&(sd),__FUNCTION__)
181 #define script_charid2sd(loc,sd) script_charid2sd_(st,(loc),&(sd),__FUNCTION__)
182 #define script_nick2sd(loc,sd) script_nick2sd_(st,(loc),&(sd),__FUNCTION__)
183 #define script_mapid2sd(loc,sd) script_mapid2sd_(st,(loc),&(sd),__FUNCTION__)
184 #define script_rid2sd(sd) script_rid2sd_(st,&(sd),__FUNCTION__)
185 #define script_rid2bl(loc,bl) script_rid2bl_(st,(loc),&(bl),__FUNCTION__)
187 /// temporary buffer for passing around compiled bytecode
188 /// @see add_scriptb, set_label, parse_script
189 static unsigned char* script_buf = NULL;
190 static int script_pos = 0, script_size = 0;
192 static inline int GETVALUE(const unsigned char* buf, int i)
194 return (int)MakeDWord(MakeWord(buf[i], buf[i+1]), MakeWord(buf[i+2], 0));
196 static inline void SETVALUE(unsigned char* buf, int i, int n)
198 buf[i] = GetByte(n, 0);
199 buf[i+1] = GetByte(n, 1);
200 buf[i+2] = GetByte(n, 2);
203 // String buffer structures.
204 // str_data stores string information
205 static struct str_data_struct {
210 int (*func)(struct script_state *st);
215 static int str_data_size = 0; // size of the data
216 static int str_num = LABEL_START; // next id to be assigned
218 // str_buf holds the strings themselves
219 static char *str_buf;
220 static int str_size = 0; // size of the buffer
221 static int str_pos = 0; // next position to be assigned
224 // Using a prime number for SCRIPT_HASH_SIZE should give better distributions
225 #define SCRIPT_HASH_SIZE 1021
226 int str_hash[SCRIPT_HASH_SIZE];
227 // Specifies which string hashing method to use
228 //#define SCRIPT_HASH_DJB2
229 //#define SCRIPT_HASH_SDBM
230 #define SCRIPT_HASH_ELF
232 static DBMap* scriptlabel_db = NULL; // const char* label_name -> int script_pos
233 static DBMap* userfunc_db = NULL; // const char* func_name -> struct script_code*
234 static int parse_options = 0;
235 DBMap* script_get_label_db(void) { return scriptlabel_db; }
236 DBMap* script_get_userfunc_db(void) { return userfunc_db; }
238 // important buildin function references for usage in scripts
239 static int buildin_set_ref = 0;
240 static int buildin_callsub_ref = 0;
241 static int buildin_callfunc_ref = 0;
242 static int buildin_getelementofarray_ref = 0;
244 // Caches compiled autoscript item code.
245 // Note: This is not cleared when reloading itemdb.
246 static DBMap* autobonus_db = NULL; // char* script -> char* bytecode
248 struct Script_Config script_config = {
249 1, // warn_func_mismatch_argtypes
250 1, 65535, 2048, //warn_func_mismatch_paramnum/check_cmdcount/check_gotocount
251 0, INT_MAX, // input_min_value/input_max_value
252 // NOTE: None of these event labels should be longer than <EVENT_NAME_LENGTH> characters
254 "OnPCDieEvent", //die_event_name
255 "OnPCKillEvent", //kill_pc_event_name
256 "OnNPCKillEvent", //kill_mob_event_name
257 "OnPCLoginEvent", //login_event_name
258 "OnPCLogoutEvent", //logout_event_name
259 "OnPCLoadMapEvent", //loadmap_event_name
260 "OnPCBaseLvUpEvent", //baselvup_event_name
261 "OnPCJobLvUpEvent", //joblvup_event_name
262 "OnPCStatCalcEvent", //stat_calc_event_name
264 "OnTouch_", //ontouch_event_name (runs on first visible char to enter area, picks another char if the first char leaves)
265 "OnTouch", //ontouch2_event_name (run whenever a char walks into the OnTouch area)
266 "OnTouchNPC", //ontouchnpc_event_name (run whenever a monster walks into the OnTouch area)
267 "OnWhisperGlobal", //onwhisper_event_name (is executed when a player sends a whisper message to the NPC)
268 "OnCommand", //oncommand_event_name (is executed by script command cmdothernpc)
270 "OnInit", //init_event_name (is executed on all npcs when all npcs were loaded)
271 "OnInterIfInit", //inter_init_event_name (is executed on inter server connection)
272 "OnInterIfInitOnce", //inter_init_once_event_name (is only executed on the first inter server connection)
274 "OnGuildBreak", //guild_break_event_name (is executed on all castles of the guild that is broken)
275 "OnAgitStart", //agit_start_event_name (is executed when WoE FE is started)
276 "OnAgitInit", //agit_init_event_name (is executed after all castle owning guilds have been loaded)
277 "OnAgitEnd", //agit_end_event_name (is executed when WoE FE has ended)
278 "OnAgitStart2", //agit_start2_event_name (is executed when WoE SE is started)
279 "OnAgitInit2", //agit_init2_event_name (is executed after all castle owning guilds have been loaded)
280 "OnAgitEnd2", //agit_end2_event_name (is executed when WoE SE has ended)
281 "OnAgitStart3", //agit_start3_event_name (is executed when WoE TE is started)
282 "OnAgitInit3", //agit_init3_event_name (is executed after all castle owning guilds have been loaded)
283 "OnAgitEnd3", //agit_end3_event_name (is executed when WoE TE has ended)
285 "OnTimer", //timer_event_name (is executed by a timer at the specific second)
286 "OnMinute", //timer_minute_event_name (is executed by a timer at the specific minute)
287 "OnHour", //timer_hour_event_name (is executed by a timer at the specific hour)
288 "OnClock", //timer_clock_event_name (is executed by a timer at the specific hour and minute)
289 "OnDay", //timer_day_event_name (is executed by a timer at the specific month and day)
290 "OnSun", //timer_sunday_event_name (is executed by a timer on sunday at the specific hour and minute)
291 "OnMon", //timer_monday_event_name (is executed by a timer on monday at the specific hour and minute)
292 "OnTue", //timer_tuesday_event_name (is executed by a timer on tuesday at the specific hour and minute)
293 "OnWed", //timer_wednesday_event_name (is executed by a timer on wednesday at the specific hour and minute)
294 "OnThu", //timer_thursday_event_name (is executed by a timer on thursday at the specific hour and minute)
295 "OnFri", //timer_friday_event_name (is executed by a timer on friday at the specific hour and minute)
296 "OnSat", //timer_saturday_event_name (is executed by a timer on saturday at the specific hour and minute)
298 "OnInstanceInit", //instance_init_event_name (is executed right after instance creation)
299 "OnInstanceDestroy", //instance_destroy_event_name (is executed right before instance destruction)
302 static jmp_buf error_jump;
303 static char* error_msg;
304 static const char* error_pos;
305 static int error_report; // if the error should produce output
306 // Used by disp_warning_message
307 static const char* parser_current_src;
308 static const char* parser_current_file;
309 static int parser_current_line;
311 // for advanced scripting support ( nested if, switch, while, for, do-while, function, etc )
312 // [Eoe / jA 1080, 1081, 1094, 1164]
321 TYPE_ARGLIST // function argument list
326 ARGLIST_UNDEFINED = 0,
327 ARGLIST_NO_PAREN = 1,
333 enum curly_type type;
337 struct linkdb_node *case_label;
338 } curly[256]; // Information right parenthesis
339 int curly_count; // The number of right brackets
340 int index; // Number of the syntax used in the script
343 const char* parse_curly_close(const char* p);
344 const char* parse_syntax_close(const char* p);
345 const char* parse_syntax_close_sub(const char* p,int* flag);
346 const char* parse_syntax(const char* p);
347 static int parse_syntax_for_flag = 0;
349 extern short current_equip_item_index; //for New CARDS Scripts. It contains Inventory Index of the EQUIP_SCRIPT caller item. [Lupus]
350 extern unsigned int current_equip_combo_pos;
352 int potion_flag=0; //For use on Alchemist improved potions/Potion Pitcher. [Skotlex]
353 int potion_hp=0, potion_per_hp=0, potion_sp=0, potion_per_sp=0;
354 int potion_target = 0;
355 unsigned int *generic_ui_array = NULL;
356 unsigned int generic_ui_array_size = 0;
359 c_op get_com(unsigned char *script,int *pos);
360 int get_num(unsigned char *script,int *pos);
362 typedef struct script_function {
363 int (*func)(struct script_state *st);
366 const char *deprecated;
369 extern script_function buildin_func[];
371 static struct linkdb_node *sleep_db; // int oid -> struct script_state *
373 #ifdef BETA_THREAD_TEST
377 static SPIN_LOCK queryThreadLock;
378 static rAthread queryThread = NULL;
379 static ramutex queryThreadMutex = NULL;
380 static racond queryThreadCond = NULL;
381 static volatile int32 queryThreadTerminate = 0;
383 struct queryThreadEntry {
385 bool type; /* main db or log db? */
386 struct script_state *st;
389 /* Ladies and Gentleman the Manager! */
391 struct queryThreadEntry **entry;/* array of structs */
393 int timer;/* used to receive processed entries */
397 /*==========================================
398 * (Only those needed) local declaration prototype
399 *------------------------------------------*/
400 const char* parse_subexpr(const char* p,int limit);
401 int run_func(struct script_state *st);
402 unsigned short script_instancegetid(struct script_state *st);
426 * No longer available, keeping here just in case it's back someday. [Ind]
457 MF_MONSTER_NOTELEPORT,
458 MF_PVP_NOCALCRANK, //50
463 MF_NOITEMCONSUMPTION,
468 MF_SKILL_DAMAGE, //60
475 const char* script_op2name(int op)
477 #define RETURN_OP_NAME(type) case type: return #type
480 RETURN_OP_NAME(C_NOP);
481 RETURN_OP_NAME(C_POS);
482 RETURN_OP_NAME(C_INT);
483 RETURN_OP_NAME(C_PARAM);
484 RETURN_OP_NAME(C_FUNC);
485 RETURN_OP_NAME(C_STR);
486 RETURN_OP_NAME(C_CONSTSTR);
487 RETURN_OP_NAME(C_ARG);
488 RETURN_OP_NAME(C_NAME);
489 RETURN_OP_NAME(C_EOL);
490 RETURN_OP_NAME(C_RETINFO);
491 RETURN_OP_NAME(C_USERFUNC);
492 RETURN_OP_NAME(C_USERFUNC_POS);
494 RETURN_OP_NAME(C_REF);
497 RETURN_OP_NAME(C_OP3);
498 RETURN_OP_NAME(C_LOR);
499 RETURN_OP_NAME(C_LAND);
500 RETURN_OP_NAME(C_LE);
501 RETURN_OP_NAME(C_LT);
502 RETURN_OP_NAME(C_GE);
503 RETURN_OP_NAME(C_GT);
504 RETURN_OP_NAME(C_EQ);
505 RETURN_OP_NAME(C_NE);
506 RETURN_OP_NAME(C_XOR);
507 RETURN_OP_NAME(C_OR);
508 RETURN_OP_NAME(C_AND);
509 RETURN_OP_NAME(C_ADD);
510 RETURN_OP_NAME(C_SUB);
511 RETURN_OP_NAME(C_MUL);
512 RETURN_OP_NAME(C_DIV);
513 RETURN_OP_NAME(C_MOD);
514 RETURN_OP_NAME(C_NEG);
515 RETURN_OP_NAME(C_LNOT);
516 RETURN_OP_NAME(C_NOT);
517 RETURN_OP_NAME(C_R_SHIFT);
518 RETURN_OP_NAME(C_L_SHIFT);
519 RETURN_OP_NAME(C_ADD_POST);
520 RETURN_OP_NAME(C_SUB_POST);
521 RETURN_OP_NAME(C_ADD_PRE);
522 RETURN_OP_NAME(C_SUB_PRE);
525 ShowDebug("script_op2name: unexpected op=%d\n", op);
528 #undef RETURN_OP_NAME
531 #ifdef DEBUG_DUMP_STACK
532 static void script_dump_stack(struct script_state* st)
535 ShowMessage("\tstart = %d\n", st->start);
536 ShowMessage("\tend = %d\n", st->end);
537 ShowMessage("\tdefsp = %d\n", st->stack->defsp);
538 ShowMessage("\tsp = %d\n", st->stack->sp);
539 for( i = 0; i < st->stack->sp; ++i )
541 struct script_data* data = &st->stack->stack_data[i];
542 ShowMessage("\t[%d] %s", i, script_op2name(data->type));
547 ShowMessage(" %d\n", data->u.num);
552 ShowMessage(" \"%s\"\n", data->u.str);
556 ShowMessage(" \"%s\" (id=%d ref=%p subtype=%s)\n", reference_getname(data), data->u.num, data->ref, script_op2name(str_data[data->u.num].type));
561 struct script_retinfo* ri = data->u.ri;
562 ShowMessage(" %p {scope.vars=%p, scope.arrays=%p, script=%p, pos=%d, nargs=%d, defsp=%d}\n", ri, ri->scope.vars, ri->scope.arrays, ri->script, ri->pos, ri->nargs, ri->defsp);
573 /// Reports on the console the src of a script error.
574 static void script_reportsrc(struct script_state *st)
576 struct block_list* bl;
579 return; //Can't report source.
581 bl = map_id2bl(st->oid);
588 ShowDebug("Source (NPC): %s at %s (%d,%d)\n", ((struct npc_data *)bl)->name, map[bl->m].name, bl->x, bl->y);
590 ShowDebug("Source (NPC): %s (invisible/not on a map)\n", ((struct npc_data *)bl)->name);
594 ShowDebug("Source (Non-NPC type %d): name %s at %s (%d,%d)\n", bl->type, status_get_name(bl), map[bl->m].name, bl->x, bl->y);
596 ShowDebug("Source (Non-NPC type %d): name %s (invisible/not on a map)\n", bl->type, status_get_name(bl));
601 /// Reports on the console information about the script data.
602 static void script_reportdata(struct script_data* data)
606 switch( data->type ) {
607 case C_NOP:// no value
608 ShowDebug("Data: nothing (nil)\n");
611 ShowDebug("Data: number value=%" PRId64 "\n", data->u.num);
614 case C_CONSTSTR:// string
616 ShowDebug("Data: string value=\"%s\"\n", data->u.str);
618 ShowDebug("Data: string value=NULL\n");
621 case C_NAME:// reference
622 if( reference_tovariable(data) ) {// variable
623 const char* name = reference_getname(data);
624 ShowDebug("Data: variable name='%s' index=%d\n", name, reference_getindex(data));
625 } else if( reference_toconstant(data) ) {// constant
626 ShowDebug("Data: constant name='%s' value=%d\n", reference_getname(data), reference_getconstant(data));
627 } else if( reference_toparam(data) ) {// param
628 ShowDebug("Data: param name='%s' type=%d\n", reference_getname(data), reference_getparamtype(data));
630 ShowDebug("Data: reference name='%s' type=%s\n", reference_getname(data), script_op2name(data->type));
631 ShowDebug("Please report this!!! - script->str_data.type=%s\n", script_op2name(str_data[reference_getid(data)].type));
635 ShowDebug("Data: label pos=%" PRId64 "\n", data->u.num);
638 ShowDebug("Data: %s\n", script_op2name(data->type));
644 /// Reports on the console information about the current built-in function.
645 static void script_reportfunc(struct script_state* st)
648 struct script_data* data;
650 if( !script_hasdata(st,0) )
655 data = script_getdata(st,0);
657 if( !data_isreference(data) || str_data[reference_getid(data)].type != C_FUNC )
658 {// script currently not executing a built-in function or corrupt stack
662 id = reference_getid(data);
663 params = script_lastdata(st)-1;
668 ShowDebug("Function: %s (%d parameter%s):\n", get_str(id), params, ( params == 1 ) ? "" : "s");
670 for( i = 2; i <= script_lastdata(st); i++ )
672 script_reportdata(script_getdata(st,i));
677 ShowDebug("Function: %s (no parameters)\n", get_str(id));
680 /*==========================================
681 * Output error message
682 *------------------------------------------*/
683 static void disp_error_message2(const char *mes,const char *pos,int report)
685 error_msg = aStrdup(mes);
687 error_report = report;
688 longjmp( error_jump, 1 );
690 #define disp_error_message(mes,pos) disp_error_message2(mes,pos,1)
692 static void disp_warning_message(const char *mes, const char *pos) {
693 script_warning(parser_current_src,parser_current_file,parser_current_line,mes,pos);
696 /// Checks event parameter validity
697 static void check_event(struct script_state *st, const char *evt)
699 if( evt && evt[0] && !stristr(evt, "::On") )
701 ShowWarning("NPC event parameter deprecated! Please use 'NPCNAME::OnEVENT' instead of '%s'.\n", evt);
702 script_reportsrc(st);
706 /*==========================================
707 * Hashes the input string
708 *------------------------------------------*/
709 static unsigned int calc_hash(const char* p)
713 #if defined(SCRIPT_HASH_DJB2)
715 while( *p ) // hash*33 + c
716 h = ( h << 5 ) + h + ((unsigned char)TOLOWER(*p++));
717 #elif defined(SCRIPT_HASH_SDBM)
719 while( *p ) // hash*65599 + c
720 h = ( h << 6 ) + ( h << 16 ) - h + ((unsigned char)TOLOWER(*p++));
721 #elif defined(SCRIPT_HASH_ELF) // UNIX ELF hash
725 h = ( h << 4 ) + ((unsigned char)TOLOWER(*p++));
736 h = ( h << 1 ) + ( h >> 3 ) + ( h >> 5 ) + ( h >> 8 ) + (unsigned char)TOLOWER(*p++);
739 return h % SCRIPT_HASH_SIZE;
743 /*==========================================
744 * str_data manipulation functions
745 *------------------------------------------*/
747 /// Looks up string using the provided id.
748 const char* get_str(int id)
750 Assert( id >= LABEL_START && id < str_size );
751 return str_buf+str_data[id].str;
754 /// Returns the uid of the string, or -1.
755 static int search_str(const char* p)
759 for( i = str_hash[calc_hash(p)]; i != 0; i = str_data[i].next )
760 if( strcasecmp(get_str(i),p) == 0 )
766 /// Stores a copy of the string and returns its id.
767 /// If an identical string is already present, returns its id instead.
768 int add_str(const char* p)
775 if( str_hash[h] == 0 )
776 {// empty bucket, add new node here
777 str_hash[h] = str_num;
780 {// scan for end of list, or occurence of identical string
782 for( i = str_hash[h]; ; i = str_data[i].next )
784 if( strcasecmp(get_str(i),p) == 0 )
785 return i; // string already in list
786 if( str_data[i].next == 0 )
787 break; // reached the end
790 // append node to end of list
791 str_data[i].next = str_num;
794 // grow list if neccessary
795 if( str_num >= str_data_size )
797 str_data_size += 128;
798 RECREATE(str_data,struct str_data_struct,str_data_size);
799 memset(str_data + (str_data_size - 128), '\0', 128);
804 // grow string buffer if neccessary
805 while( str_pos+len+1 >= str_size )
808 RECREATE(str_buf,char,str_size);
809 memset(str_buf + (str_size - 256), '\0', 256);
812 safestrncpy(str_buf+str_pos, p, len+1);
813 str_data[str_num].type = C_NOP;
814 str_data[str_num].str = str_pos;
815 str_data[str_num].next = 0;
816 str_data[str_num].func = NULL;
817 str_data[str_num].backpatch = -1;
818 str_data[str_num].label = -1;
825 /// Appends 1 byte to the script buffer.
826 static void add_scriptb(int a)
828 if( script_pos+1 >= script_size )
830 script_size += SCRIPT_BLOCK_SIZE;
831 RECREATE(script_buf,unsigned char,script_size);
833 script_buf[script_pos++] = (uint8)(a);
836 /// Appends a c_op value to the script buffer.
837 /// The value is variable-length encoded into 8-bit blocks.
838 /// The encoding scheme is ( 01?????? )* 00??????, LSB first.
839 /// All blocks but the last hold 7 bits of data, topmost bit is always 1 (carries).
840 static void add_scriptc(int a)
844 add_scriptb((a&0x3f)|0x40);
851 /// Appends an integer value to the script buffer.
852 /// The value is variable-length encoded into 8-bit blocks.
853 /// The encoding scheme is ( 11?????? )* 10??????, LSB first.
854 /// All blocks but the last hold 7 bits of data, topmost bit is always 1 (carries).
855 static void add_scripti(int a)
859 add_scriptb((a&0x3f)|0xc0);
865 /// Appends a str_data object (label/function/variable/integer) to the script buffer.
868 /// @param l The id of the str_data entry
870 static void add_scriptl(int l)
872 int backpatch = str_data[l].backpatch;
874 switch(str_data[l].type){
878 add_scriptb(str_data[l].label);
879 add_scriptb(str_data[l].label>>8);
880 add_scriptb(str_data[l].label>>16);
884 // Embedded data backpatch there is a possibility of label
886 str_data[l].backpatch = script_pos;
887 add_scriptb(backpatch);
888 add_scriptb(backpatch>>8);
889 add_scriptb(backpatch>>16);
892 add_scripti(abs(str_data[l].val));
893 if( str_data[l].val < 0 ) //Notice that this is negative, from jA (Rayce)
896 default: // assume C_NAME
905 /*==========================================
907 *------------------------------------------*/
908 void set_label(int l,int pos, const char* script_pos_cur)
912 if(str_data[l].type==C_INT || str_data[l].type==C_PARAM || str_data[l].type==C_FUNC)
913 { //Prevent overwriting constants values, parameters and built-in functions [Skotlex]
914 disp_error_message("set_label: invalid label name",script_pos_cur);
917 if(str_data[l].label!=-1){
918 disp_error_message("set_label: dup label ",script_pos_cur);
921 str_data[l].type=(str_data[l].type == C_USERFUNC ? C_USERFUNC_POS : C_POS);
922 str_data[l].label=pos;
923 for(i=str_data[l].backpatch;i>=0 && i!=0x00ffffff;){
924 int next=GETVALUE(script_buf,i);
925 script_buf[i-1]=(str_data[l].type == C_USERFUNC ? C_USERFUNC_POS : C_POS);
926 SETVALUE(script_buf,i,pos);
931 /// Skips spaces and/or comments.
932 const char* skip_space(const char* p)
940 if( *p == '/' && p[1] == '/' )
942 while(*p && *p!='\n')
945 else if( *p == '/' && p[1] == '*' )
951 disp_warning_message("script:script->skip_space: end of file while parsing block comment. expected " CL_BOLD "*/" CL_NORM, p);
954 if( *p == '*' && p[1] == '/' )
955 {// end of block comment
969 /// A word consists of undercores and/or alphanumeric characters,
970 /// and valid variable prefixes/postfixes.
971 static const char* skip_word(const char* p)
975 case '@':// temporary char variable
977 case '#':// account variable
978 p += ( p[1] == '#' ? 2 : 1 ); break;
979 case '\'':// instance variable
981 case '.':// npc variable
982 p += ( p[1] == '@' ? 2 : 1 ); break;
983 case '$':// global variable
984 p += ( p[1] == '@' ? 2 : 1 ); break;
987 while( ISALNUM(*p) || *p == '_' )
991 if( *p == '$' )// string
997 /// Adds a word to str_data.
1000 static int add_word(const char* p)
1007 len = skip_word(p) - p;
1009 disp_error_message("script:add_word: invalid word. A word consists of undercores and/or alphanumeric characters, and valid variable prefixes/postfixes.", p);
1011 // Duplicate the word
1012 word = (char*)aMalloc(len+1);
1013 memcpy(word, p, len);
1022 /// Parses a function call.
1023 /// The argument list can have parenthesis or not.
1024 /// The number of arguments is checked.
1026 const char* parse_callfunc(const char* p, int require_paren, int is_custom)
1029 const char* arg=NULL;
1033 if( str_data[func].type == C_FUNC ){
1037 arg = buildin_func[str_data[func].val].arg;
1038 #if defined(SCRIPT_COMMAND_DEPRECATION)
1039 if( str_data[func].deprecated ){
1040 ShowWarning( "Usage of deprecated script function '%s'.\n", get_str(func) );
1041 ShowWarning( "This function was deprecated on '%s' and could become unavailable anytime soon.\n", buildin_func[str_data[func].val].deprecated );
1044 } else if( str_data[func].type == C_USERFUNC || str_data[func].type == C_USERFUNC_POS ){
1045 // script defined function
1046 add_scriptl(buildin_callsub_ref);
1049 arg = buildin_func[str_data[buildin_callsub_ref].val].arg;
1051 disp_error_message("parse_callfunc: callsub has no arguments, please review its definition",p);
1053 ++arg; // count func as argument
1055 const char* name = get_str(func);
1056 if( !is_custom && strdb_get(userfunc_db, name) == NULL ) {
1057 disp_error_message("parse_line: expect command, missing function name or calling undeclared function",p);
1059 add_scriptl(buildin_callfunc_ref);
1062 while( *name ) add_scriptb(*name ++);
1064 arg = buildin_func[str_data[buildin_callfunc_ref].val].arg;
1065 if( *arg != '*' ) ++ arg;
1071 syntax.curly[syntax.curly_count].type = TYPE_ARGLIST;
1072 syntax.curly[syntax.curly_count].count = 0;
1075 syntax.curly[syntax.curly_count].flag = ARGLIST_NO_PAREN;
1076 } else if( *p == '(' && *(p2=skip_space(p+1)) == ')' )
1077 {// <func name> '(' ')'
1078 syntax.curly[syntax.curly_count].flag = ARGLIST_PAREN;
1081 } else if( 0 && require_paren && *p != '(' )
1083 syntax.curly[syntax.curly_count].flag = ARGLIST_NO_PAREN;
1086 {// <func name> <arg list>
1087 if( require_paren ){
1089 disp_error_message("need '('",p);
1091 syntax.curly[syntax.curly_count].flag = ARGLIST_PAREN;
1092 } else if( *p == '(' ){
1093 syntax.curly[syntax.curly_count].flag = ARGLIST_UNDEFINED;
1095 syntax.curly[syntax.curly_count].flag = ARGLIST_NO_PAREN;
1097 ++syntax.curly_count;
1099 p2=parse_subexpr(p,-1);
1101 break; // not an argument
1103 ++arg; // next argument
1106 if( *arg == 0 || *p != ',' )
1107 break; // no more arguments
1110 --syntax.curly_count;
1112 if( *arg && *arg != '?' && *arg != '*' )
1113 disp_error_message2("parse_callfunc: not enough arguments, expected ','", p, script_config.warn_func_mismatch_paramnum);
1114 if( syntax.curly[syntax.curly_count].type != TYPE_ARGLIST )
1115 disp_error_message("parse_callfunc: DEBUG last curly is not an argument list",p);
1116 if( syntax.curly[syntax.curly_count].flag == ARGLIST_PAREN ){
1118 disp_error_message("parse_callfunc: expected ')' to close argument list",p);
1121 add_scriptc(C_FUNC);
1125 /// Processes end of logical script line.
1126 /// @param first When true, only fix up scheduling data is initialized
1127 /// @param p Script position for error reporting in set_label
1128 static void parse_nextline(bool first, const char* p)
1132 add_scriptc(C_EOL); // mark end of line for stack cleanup
1133 set_label(LABEL_NEXTLINE, script_pos, p); // fix up '-' labels
1136 // initialize data for new '-' label fix up scheduling
1137 str_data[LABEL_NEXTLINE].type = C_NOP;
1138 str_data[LABEL_NEXTLINE].backpatch = -1;
1139 str_data[LABEL_NEXTLINE].label = -1;
1143 * Pushes a variable into stack, processing its array index if needed.
1144 * @see parse_variable
1146 void parse_variable_sub_push(int word, const char *p2)
1148 if( p2 ) { // Process the variable index
1149 const char *p3 = NULL;
1151 // Push the getelementofarray method into the stack
1152 add_scriptl(buildin_getelementofarray_ref);
1156 // Process the sub-expression for this assignment
1157 p3 = parse_subexpr(p2 + 1, 1);
1158 p3 = skip_space(p3);
1160 if( *p3 != ']' ) // Closing parenthesis is required for this script
1161 disp_error_message("Missing closing ']' parenthesis for the variable assignment.", p3);
1163 // Push the closing function stack operator onto the stack
1164 add_scriptc(C_FUNC);
1166 } else // No array index, simply push the variable or value onto the stack
1170 /// Parse a variable assignment using the direct equals operator
1171 /// @param p script position where the function should run from
1172 /// @return NULL if not a variable assignment, the new position otherwise
1173 const char* parse_variable(const char* p) {
1176 const char *p2 = NULL;
1177 const char *var = p;
1179 if ((p[0] == '+' && p[1] == '+' && (type = C_ADD_PRE)) // pre ++
1180 || (p[0] == '-' && p[1] == '-' && (type = C_SUB_PRE))) // pre --
1181 var = p = skip_space(&p[2]);
1183 // skip the variable where applicable
1187 if( p == NULL ) {// end of the line or invalid buffer
1191 if( *p == '[' ) {// array variable so process the array as appropriate
1193 for( p2 = p, i = 0, j = 1; p; ++ i ) {
1194 if( *p ++ == ']' && --(j) == 0 ) break;
1195 if( *p == '[' ) ++ j;
1198 if( !(p = skip_space(p)) ) {// end of line or invalid characters remaining
1199 disp_error_message("Missing right expression or closing bracket for variable.", p);
1203 if( type == C_NOP &&
1204 !( ( p[0] == '=' && p[1] != '=' && (type = C_EQ) ) // =
1205 || ( p[0] == '+' && p[1] == '=' && (type = C_ADD) ) // +=
1206 || ( p[0] == '-' && p[1] == '=' && (type = C_SUB) ) // -=
1207 || ( p[0] == '^' && p[1] == '=' && (type = C_XOR) ) // ^=
1208 || ( p[0] == '|' && p[1] == '=' && (type = C_OR ) ) // |=
1209 || ( p[0] == '&' && p[1] == '=' && (type = C_AND) ) // &=
1210 || ( p[0] == '*' && p[1] == '=' && (type = C_MUL) ) // *=
1211 || ( p[0] == '/' && p[1] == '=' && (type = C_DIV) ) // /=
1212 || ( p[0] == '%' && p[1] == '=' && (type = C_MOD) ) // %=
1213 || ( p[0] == '~' && p[1] == '=' && (type = C_NOT) ) // ~=
1214 || ( p[0] == '+' && p[1] == '+' && (type = C_ADD_POST) ) // post ++
1215 || ( p[0] == '-' && p[1] == '-' && (type = C_SUB_POST) ) // post --
1216 || ( p[0] == '<' && p[1] == '<' && p[2] == '=' && (type = C_L_SHIFT) ) // <<=
1217 || ( p[0] == '>' && p[1] == '>' && p[2] == '=' && (type = C_R_SHIFT) ) // >>=
1219 {// failed to find a matching operator combination so invalid
1224 case C_ADD_PRE: // pre ++
1225 case C_SUB_PRE: // pre --
1226 // Nothing more to skip
1229 case C_EQ: {// incremental modifier
1230 p = skip_space( &p[1] );
1235 case C_R_SHIFT: {// left or right shift modifier
1236 p = skip_space( &p[3] );
1240 default: {// normal incremental command
1241 p = skip_space( &p[2] );
1245 if( p == NULL ) {// end of line or invalid buffer
1249 // push the set function onto the stack
1250 add_scriptl(buildin_set_ref);
1253 // always append parenthesis to avoid errors
1254 syntax.curly[syntax.curly_count].type = TYPE_ARGLIST;
1255 syntax.curly[syntax.curly_count].count = 0;
1256 syntax.curly[syntax.curly_count].flag = ARGLIST_PAREN;
1258 // increment the total curly count for the position in the script
1259 ++ syntax.curly_count;
1261 // parse the variable currently being modified
1262 word = add_word(var);
1264 if( str_data[word].type == C_FUNC || str_data[word].type == C_USERFUNC || str_data[word].type == C_USERFUNC_POS ) // cannot assign a variable which exists as a function or label
1265 disp_error_message("Cannot modify a variable which has the same name as a function or label.", p);
1267 parse_variable_sub_push(word, p2); // Push variable onto the stack
1270 parse_variable_sub_push(word, p2); // Push variable onto the stack once again (first argument of setr)
1272 if( type == C_ADD_POST || type == C_SUB_POST ) { // post ++ / --
1274 add_scriptc(type == C_ADD_POST ? C_ADD : C_SUB);
1275 parse_variable_sub_push(word, p2); // Push variable onto the stack (third argument of setr)
1276 } else if( type == C_ADD_PRE || type == C_SUB_PRE ) { // pre ++ / --
1278 add_scriptc(type == C_ADD_PRE ? C_ADD : C_SUB);
1279 } else { // Process the value as an expression
1280 p = parse_subexpr(p, -1);
1283 {// push the type of modifier onto the stack
1288 // decrement the curly count for the position within the script
1289 -- syntax.curly_count;
1291 // close the script by appending the function operator
1292 add_scriptc(C_FUNC);
1294 // push the buffer from the method
1299 * Checks whether the gives string is a number literal
1301 * Mainly necessary to differentiate between number literals and NPC name
1302 * constants, since several of those start with a digit.
1304 * All this does is to check if the string begins with an optional + or - sign,
1305 * followed by a hexadecimal or decimal number literal literal and is NOT
1306 * followed by a underscore or letter.
1308 * @author : Hercules.ws
1309 * @param p Pointer to the string to check
1310 * @return Whether the string is a number literal
1312 bool is_number(const char *p) {
1316 if (*p == '-' || *p == '+')
1319 if (*p == '0' && p[1] == 'x') {
1323 while (ISXDIGIT(*np))
1327 while (ISDIGIT(*np))
1330 if (p != np && *np != '_' && !ISALPHA(*np)) // At least one digit, and next isn't a letter or _
1335 /*==========================================
1337 *------------------------------------------*/
1338 const char* parse_simpleexpr(const char *p)
1343 if(*p==';' || *p==',')
1344 disp_error_message("parse_simpleexpr: unexpected end of expression",p);
1346 if( (i=syntax.curly_count-1) >= 0 && syntax.curly[i].type == TYPE_ARGLIST )
1347 ++syntax.curly[i].count;
1348 p=parse_subexpr(p+1,-1);
1350 if( (i=syntax.curly_count-1) >= 0 && syntax.curly[i].type == TYPE_ARGLIST &&
1351 syntax.curly[i].flag == ARGLIST_UNDEFINED && --syntax.curly[i].count == 0
1354 syntax.curly[i].flag = ARGLIST_PAREN;
1357 syntax.curly[i].flag = ARGLIST_NO_PAREN;
1360 disp_error_message("parse_simpleexpr: unmatched ')'",p);
1362 } else if(is_number(p)) {
1364 while(*p == '0' && ISDIGIT(p[1])) p++;
1368 disp_warning_message("parse_simpleexpr: underflow detected, capping value to INT_MIN",p);
1369 } else if( i > INT_MAX ) {
1371 disp_warning_message("parse_simpleexpr: overflow detected, capping value to INT_MAX",p);
1373 add_scripti((int)i);
1378 while( *p && *p != '"' ){
1379 if( (unsigned char)p[-1] <= 0x7e && *p == '\\' )
1382 size_t len = skip_escaped_c(p) - p;
1383 size_t n = sv_unescape_c(buf, p, len);
1385 ShowDebug("parse_simpleexpr: unexpected length %d after unescape (\"%.*s\" -> %.*s)\n", (int)n, (int)len, p, (int)n, buf);
1390 else if( *p == '\n' )
1391 disp_error_message("parse_simpleexpr: unexpected newline @ string",p);
1395 disp_error_message("parse_simpleexpr: unexpected eof @ string",p);
1402 // label , register , function etc
1404 disp_error_message("parse_simpleexpr: unexpected character",p);
1407 if( str_data[l].type == C_FUNC || str_data[l].type == C_USERFUNC || str_data[l].type == C_USERFUNC_POS)
1408 return parse_callfunc(p,1,0);
1410 const char* name = get_str(l);
1411 if( strdb_get(userfunc_db,name) != NULL ) {
1412 return parse_callfunc(p,1,1);
1416 if( (pv = parse_variable(p)) )
1417 {// successfully processed a variable assignment
1421 #if defined(SCRIPT_CONSTANT_DEPRECATION)
1422 if( str_data[l].type == C_INT && str_data[l].deprecated ){
1423 ShowWarning( "Usage of deprecated constant '%s'.\n", get_str(l) );
1424 ShowWarning( "This constant was deprecated and could become unavailable anytime soon.\n" );
1430 // array(name[i] => getelementofarray(name,i) )
1431 add_scriptl(buildin_getelementofarray_ref);
1435 p=parse_subexpr(p+1,-1);
1438 disp_error_message("parse_simpleexpr: unmatched ']'",p);
1440 add_scriptc(C_FUNC);
1449 /*==========================================
1450 * Analysis of the expression
1451 *------------------------------------------*/
1452 const char* parse_subexpr(const char* p,int limit)
1459 const char* tmpp = skip_space(p+1);
1460 if( *tmpp == ';' || *tmpp == ',' ){
1461 add_scriptl(LABEL_NEXTLINE);
1467 if( (op = C_ADD_PRE, p[0] == '+' && p[1] == '+') || (op = C_SUB_PRE, p[0] == '-' && p[1] == '-') ) // Pre ++ -- operators
1468 p = parse_variable(p);
1469 else if( (op = C_NEG, *p == '-') || (op = C_LNOT, *p == '!') || (op = C_NOT, *p == '~') ) { // Unary - ! ~ operators
1470 p = parse_subexpr(p + 1, 11);
1473 p = parse_simpleexpr(p);
1476 (op=C_OP3,opl=0,len=1,*p=='?') ||
1477 ((op=C_ADD,opl=9,len=1,*p=='+') && p[1]!='+') ||
1478 ((op=C_SUB,opl=9,len=1,*p=='-') && p[1]!='-') ||
1479 (op=C_MUL,opl=10,len=1,*p=='*') ||
1480 (op=C_DIV,opl=10,len=1,*p=='/') ||
1481 (op=C_MOD,opl=10,len=1,*p=='%') ||
1482 (op=C_LAND,opl=2,len=2,*p=='&' && p[1]=='&') ||
1483 (op=C_AND,opl=5,len=1,*p=='&') ||
1484 (op=C_LOR,opl=1,len=2,*p=='|' && p[1]=='|') ||
1485 (op=C_OR,opl=3,len=1,*p=='|') ||
1486 (op=C_XOR,opl=4,len=1,*p=='^') ||
1487 (op=C_EQ,opl=6,len=2,*p=='=' && p[1]=='=') ||
1488 (op=C_NE,opl=6,len=2,*p=='!' && p[1]=='=') ||
1489 (op=C_R_SHIFT,opl=8,len=2,*p=='>' && p[1]=='>') ||
1490 (op=C_GE,opl=7,len=2,*p=='>' && p[1]=='=') ||
1491 (op=C_GT,opl=7,len=1,*p=='>') ||
1492 (op=C_L_SHIFT,opl=8,len=2,*p=='<' && p[1]=='<') ||
1493 (op=C_LE,opl=7,len=2,*p=='<' && p[1]=='=') ||
1494 (op=C_LT,opl=7,len=1,*p=='<')) && opl>limit){
1497 p=parse_subexpr(p,-1);
1500 disp_error_message("parse_subexpr: expected ':'", p-1);
1501 p=parse_subexpr(p,-1);
1503 p=parse_subexpr(p,opl);
1509 return p; /* return first untreated operator */
1512 /*==========================================
1513 * Evaluation of the expression
1514 *------------------------------------------*/
1515 const char* parse_expr(const char *p)
1518 case ')': case ';': case ':': case '[': case ']':
1520 disp_error_message("parse_expr: unexpected character",p);
1522 p=parse_subexpr(p,-1);
1526 /*==========================================
1527 * Analysis of the line
1528 *------------------------------------------*/
1529 const char* parse_line(const char* p)
1535 //Close decision for if(); for(); while();
1536 p = parse_syntax_close(p + 1);
1539 if(*p==')' && parse_syntax_for_flag)
1544 syntax.curly[syntax.curly_count].type = TYPE_NULL;
1545 syntax.curly[syntax.curly_count].count = -1;
1546 syntax.curly[syntax.curly_count].index = -1;
1547 syntax.curly_count++;
1549 } else if(p[0] == '}') {
1550 return parse_curly_close(p);
1553 // Syntax-related processing
1554 p2 = parse_syntax(p);
1558 // attempt to process a variable assignment
1559 p2 = parse_variable(p);
1562 {// variable assignment processed so leave the method
1563 return parse_syntax_close(p2 + 1);
1566 p = parse_callfunc(p,0,0);
1569 if(parse_syntax_for_flag) {
1571 disp_error_message("parse_line: expected ')'",p);
1574 disp_error_message("parse_line: expected ';'",p);
1577 //Binding decision for if(), for(), while()
1578 p = parse_syntax_close(p+1);
1583 // { ... } Closing process
1584 const char* parse_curly_close(const char* p)
1586 if(syntax.curly_count <= 0) {
1587 disp_error_message("parse_curly_close: unexpected string",p);
1589 } else if(syntax.curly[syntax.curly_count-1].type == TYPE_NULL) {
1590 syntax.curly_count--;
1591 //Close decision if, for , while
1592 p = parse_syntax_close(p + 1);
1594 } else if(syntax.curly[syntax.curly_count-1].type == TYPE_SWITCH) {
1596 int pos = syntax.curly_count-1;
1599 // Remove temporary variables
1600 sprintf(label,"set $@__SW%x_VAL,0;",syntax.curly[pos].index);
1601 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1603 syntax.curly_count--;
1605 // Go to the end pointer unconditionally
1606 sprintf(label,"goto __SW%x_FIN;",syntax.curly[pos].index);
1607 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1609 syntax.curly_count--;
1611 // You are here labeled
1612 sprintf(label,"__SW%x_%x",syntax.curly[pos].index,syntax.curly[pos].count);
1614 set_label(l,script_pos, p);
1616 if(syntax.curly[pos].flag) {
1618 sprintf(label,"goto __SW%x_DEF;",syntax.curly[pos].index);
1619 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1621 syntax.curly_count--;
1625 sprintf(label,"__SW%x_FIN",syntax.curly[pos].index);
1627 set_label(l,script_pos, p);
1628 linkdb_final(&syntax.curly[pos].case_label); // free the list of case label
1629 syntax.curly_count--;
1630 //Closing decision if, for , while
1631 p = parse_syntax_close(p + 1);
1634 disp_error_message("parse_curly_close: unexpected string",p);
1639 // Syntax-related processing
1640 // break, case, continue, default, do, for, function,
1641 // if, switch, while ? will handle this internally.
1642 const char* parse_syntax(const char* p)
1644 const char *p2 = skip_word(p);
1649 if(p2 - p == 5 && !strncasecmp(p,"break",5)) {
1652 int pos = syntax.curly_count - 1;
1654 if(syntax.curly[pos].type == TYPE_DO) {
1655 sprintf(label,"goto __DO%x_FIN;",syntax.curly[pos].index);
1657 } else if(syntax.curly[pos].type == TYPE_FOR) {
1658 sprintf(label,"goto __FR%x_FIN;",syntax.curly[pos].index);
1660 } else if(syntax.curly[pos].type == TYPE_WHILE) {
1661 sprintf(label,"goto __WL%x_FIN;",syntax.curly[pos].index);
1663 } else if(syntax.curly[pos].type == TYPE_SWITCH) {
1664 sprintf(label,"goto __SW%x_FIN;",syntax.curly[pos].index);
1670 disp_error_message("parse_syntax: unexpected 'break'",p);
1672 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1674 syntax.curly_count--;
1678 disp_error_message("parse_syntax: expected ';'",p);
1679 // Closing decision if, for , while
1680 p = parse_syntax_close(p + 1);
1686 if(p2 - p == 4 && !strncasecmp(p,"case",4)) {
1688 int pos = syntax.curly_count-1;
1689 if(pos < 0 || syntax.curly[pos].type != TYPE_SWITCH) {
1690 disp_error_message("parse_syntax: unexpected 'case' ",p);
1696 if(syntax.curly[pos].count != 1) {
1698 sprintf(label,"goto __SW%x_%xJ;",syntax.curly[pos].index,syntax.curly[pos].count);
1699 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1701 syntax.curly_count--;
1703 // You are here labeled
1704 sprintf(label,"__SW%x_%x",syntax.curly[pos].index,syntax.curly[pos].count);
1706 set_label(l,script_pos, p);
1708 //Decision statement switch
1711 disp_error_message("parse_syntax: expected a space ' '",p);
1713 // check whether case label is integer or not
1716 v = (int)strtol(p,&np,0);
1717 if((*p == '-' || *p == '+') && ISDIGIT(p[1])) // pre-skip because '-' can not skip_word
1721 disp_error_message("parse_syntax: 'case' label is not an integer",np);
1723 //Check for constants
1725 v = (int)(size_t) (p2-p); // length of word at p2
1728 if( !script_get_constant(label, &v) )
1729 disp_error_message("parse_syntax: 'case' label is not an integer",p);
1734 disp_error_message("parse_syntax: expect ':'",p);
1735 sprintf(label,"if(%d != $@__SW%x_VAL) goto __SW%x_%x;",
1736 v,syntax.curly[pos].index,syntax.curly[pos].index,syntax.curly[pos].count+1);
1737 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1738 // Bad I do not parse twice
1739 p2 = parse_line(label);
1741 syntax.curly_count--;
1742 if(syntax.curly[pos].count != 1) {
1743 // Label after the completion of FALLTHRU
1744 sprintf(label,"__SW%x_%xJ",syntax.curly[pos].index,syntax.curly[pos].count);
1746 set_label(l,script_pos,p);
1748 // check duplication of case label [Rayce]
1749 if(linkdb_search(&syntax.curly[pos].case_label, (void*)__64BPRTSIZE(v)) != NULL)
1750 disp_error_message("parse_syntax: dup 'case'",p);
1751 linkdb_insert(&syntax.curly[pos].case_label, (void*)__64BPRTSIZE(v), (void*)1);
1753 sprintf(label,"set $@__SW%x_VAL,0;",syntax.curly[pos].index);
1754 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1757 syntax.curly_count--;
1758 syntax.curly[pos].count++;
1761 } else if(p2 - p == 8 && !strncasecmp(p,"continue",8)) {
1762 // Processing continue
1764 int pos = syntax.curly_count - 1;
1766 if(syntax.curly[pos].type == TYPE_DO) {
1767 sprintf(label,"goto __DO%x_NXT;",syntax.curly[pos].index);
1768 syntax.curly[pos].flag = 1; //Flag put the link for continue
1770 } else if(syntax.curly[pos].type == TYPE_FOR) {
1771 sprintf(label,"goto __FR%x_NXT;",syntax.curly[pos].index);
1773 } else if(syntax.curly[pos].type == TYPE_WHILE) {
1774 sprintf(label,"goto __WL%x_NXT;",syntax.curly[pos].index);
1780 disp_error_message("parse_syntax: unexpected 'continue'",p);
1782 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1784 syntax.curly_count--;
1788 disp_error_message("parse_syntax: expected ';'",p);
1789 //Closing decision if, for , while
1790 p = parse_syntax_close(p + 1);
1796 if(p2 - p == 7 && !strncasecmp(p,"default",7)) {
1797 // Switch - default processing
1798 int pos = syntax.curly_count-1;
1799 if(pos < 0 || syntax.curly[pos].type != TYPE_SWITCH) {
1800 disp_error_message("parse_syntax: unexpected 'default'",p);
1801 } else if(syntax.curly[pos].flag) {
1802 disp_error_message("parse_syntax: dup 'default'",p);
1806 // Put the label location
1809 disp_error_message("parse_syntax: expected ':'",p);
1811 sprintf(label,"__SW%x_%x",syntax.curly[pos].index,syntax.curly[pos].count);
1813 set_label(l,script_pos,p);
1815 // Skip to the next link w/o condition
1816 sprintf(label,"goto __SW%x_%x;",syntax.curly[pos].index,syntax.curly[pos].count+1);
1817 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1819 syntax.curly_count--;
1821 // The default label
1822 sprintf(label,"__SW%x_DEF",syntax.curly[pos].index);
1824 set_label(l,script_pos,p);
1826 syntax.curly[syntax.curly_count - 1].flag = 1;
1827 syntax.curly[pos].count++;
1830 } else if(p2 - p == 2 && !strncasecmp(p,"do",2)) {
1835 syntax.curly[syntax.curly_count].type = TYPE_DO;
1836 syntax.curly[syntax.curly_count].count = 1;
1837 syntax.curly[syntax.curly_count].index = syntax.index++;
1838 syntax.curly[syntax.curly_count].flag = 0;
1839 // Label of the (do) form here
1840 sprintf(label,"__DO%x_BGN",syntax.curly[syntax.curly_count].index);
1842 set_label(l,script_pos,p);
1843 syntax.curly_count++;
1849 if(p2 - p == 3 && !strncasecmp(p,"for",3)) {
1852 int pos = syntax.curly_count;
1853 syntax.curly[syntax.curly_count].type = TYPE_FOR;
1854 syntax.curly[syntax.curly_count].count = 1;
1855 syntax.curly[syntax.curly_count].index = syntax.index++;
1856 syntax.curly[syntax.curly_count].flag = 0;
1857 syntax.curly_count++;
1862 disp_error_message("parse_syntax: expected '('",p);
1865 // Execute the initialization statement
1866 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1868 syntax.curly_count--;
1870 // Form the start of label decision
1871 sprintf(label,"__FR%x_J",syntax.curly[pos].index);
1873 set_label(l,script_pos,p);
1877 // For (; Because the pattern of always true ;)
1880 // Skip to the end point if the condition is false
1881 sprintf(label,"__FR%x_FIN",syntax.curly[pos].index);
1882 add_scriptl(add_str("jump_zero"));
1886 add_scriptl(add_str(label));
1887 add_scriptc(C_FUNC);
1890 disp_error_message("parse_syntax: expected ';'",p);
1893 // Skip to the beginning of the loop
1894 sprintf(label,"goto __FR%x_BGN;",syntax.curly[pos].index);
1895 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1897 syntax.curly_count--;
1899 // Labels to form the next loop
1900 sprintf(label,"__FR%x_NXT",syntax.curly[pos].index);
1902 set_label(l,script_pos,p);
1904 // Process the next time you enter the loop
1905 // A ')' last for; flag to be treated as'
1906 parse_syntax_for_flag = 1;
1907 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1909 syntax.curly_count--;
1910 parse_syntax_for_flag = 0;
1912 // Skip to the determination process conditions
1913 sprintf(label,"goto __FR%x_J;",syntax.curly[pos].index);
1914 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1916 syntax.curly_count--;
1918 // Loop start labeling
1919 sprintf(label,"__FR%x_BGN",syntax.curly[pos].index);
1921 set_label(l,script_pos,p);
1924 else if( p2 - p == 8 && strncasecmp(p,"function",8) == 0 )
1925 {// internal script function
1926 const char *func_name;
1928 func_name = skip_space(p2);
1929 p = skip_word(func_name);
1930 if( p == func_name )
1931 disp_error_message("parse_syntax:function: function name is missing or invalid", p);
1934 {// function <name> ;
1935 // function declaration - just register the name
1937 l = add_word(func_name);
1938 if( str_data[l].type == C_NOP )// register only, if the name was not used by something else
1939 str_data[l].type = C_USERFUNC;
1940 else if( str_data[l].type == C_USERFUNC )
1941 ; // already registered
1943 disp_error_message("parse_syntax:function: function name is invalid", func_name);
1945 // Close condition of if, for, while
1946 p = parse_syntax_close(p2 + 1);
1950 {// function <name> <line/block of code>
1954 syntax.curly[syntax.curly_count].type = TYPE_USERFUNC;
1955 syntax.curly[syntax.curly_count].count = 1;
1956 syntax.curly[syntax.curly_count].index = syntax.index++;
1957 syntax.curly[syntax.curly_count].flag = 0;
1958 ++syntax.curly_count;
1960 // Jump over the function code
1961 sprintf(label, "goto __FN%x_FIN;", syntax.curly[syntax.curly_count-1].index);
1962 syntax.curly[syntax.curly_count].type = TYPE_NULL;
1963 ++syntax.curly_count;
1965 --syntax.curly_count;
1967 // Set the position of the function (label)
1968 l=add_word(func_name);
1969 if( str_data[l].type == C_NOP || str_data[l].type == C_USERFUNC )// register only, if the name was not used by something else
1971 str_data[l].type = C_USERFUNC;
1972 set_label(l, script_pos, p);
1973 if( parse_options&SCRIPT_USE_LABEL_DB )
1974 strdb_iput(scriptlabel_db, get_str(l), script_pos);
1977 disp_error_message("parse_syntax:function: function name is invalid", func_name);
1979 return skip_space(p);
1983 disp_error_message("expect ';' or '{' at function syntax",p);
1989 if(p2 - p == 2 && !strncasecmp(p,"if",2)) {
1993 if(*p != '(') { //Prevent if this {} non-c syntax. from Rayce (jA)
1994 disp_error_message("need '('",p);
1996 syntax.curly[syntax.curly_count].type = TYPE_IF;
1997 syntax.curly[syntax.curly_count].count = 1;
1998 syntax.curly[syntax.curly_count].index = syntax.index++;
1999 syntax.curly[syntax.curly_count].flag = 0;
2000 sprintf(label,"__IF%x_%x",syntax.curly[syntax.curly_count].index,syntax.curly[syntax.curly_count].count);
2001 syntax.curly_count++;
2002 add_scriptl(add_str("jump_zero"));
2006 add_scriptl(add_str(label));
2007 add_scriptc(C_FUNC);
2013 if(p2 - p == 6 && !strncasecmp(p,"switch",6)) {
2014 // Processing of switch ()
2018 disp_error_message("need '('",p);
2020 syntax.curly[syntax.curly_count].type = TYPE_SWITCH;
2021 syntax.curly[syntax.curly_count].count = 1;
2022 syntax.curly[syntax.curly_count].index = syntax.index++;
2023 syntax.curly[syntax.curly_count].flag = 0;
2024 sprintf(label,"$@__SW%x_VAL",syntax.curly[syntax.curly_count].index);
2025 syntax.curly_count++;
2026 add_scriptl(add_str("set"));
2028 add_scriptl(add_str(label));
2032 disp_error_message("parse_syntax: expected '{'",p);
2034 add_scriptc(C_FUNC);
2040 if(p2 - p == 5 && !strncasecmp(p,"while",5)) {
2045 disp_error_message("need '('",p);
2047 syntax.curly[syntax.curly_count].type = TYPE_WHILE;
2048 syntax.curly[syntax.curly_count].count = 1;
2049 syntax.curly[syntax.curly_count].index = syntax.index++;
2050 syntax.curly[syntax.curly_count].flag = 0;
2051 // Form the start of label decision
2052 sprintf(label,"__WL%x_NXT",syntax.curly[syntax.curly_count].index);
2054 set_label(l,script_pos,p);
2056 // Skip to the end point if the condition is false
2057 sprintf(label,"__WL%x_FIN",syntax.curly[syntax.curly_count].index);
2058 syntax.curly_count++;
2059 add_scriptl(add_str("jump_zero"));
2063 add_scriptl(add_str(label));
2064 add_scriptc(C_FUNC);
2072 const char* parse_syntax_close(const char *p) {
2073 // If (...) for (...) hoge (); as to make sure closed closed once again
2077 p = parse_syntax_close_sub(p,&flag);
2082 // Close judgment if, for, while, of do
2083 // flag == 1 : closed
2084 // flag == 0 : not closed
2085 const char* parse_syntax_close_sub(const char* p,int* flag)
2088 int pos = syntax.curly_count - 1;
2092 if(syntax.curly_count <= 0) {
2095 } else if(syntax.curly[pos].type == TYPE_IF) {
2099 // if-block and else-block end is a new line
2100 parse_nextline(false, p);
2102 // Skip to the last location if
2103 sprintf(label,"goto __IF%x_FIN;",syntax.curly[pos].index);
2104 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
2106 syntax.curly_count--;
2108 // Put the label of the location
2109 sprintf(label,"__IF%x_%x",syntax.curly[pos].index,syntax.curly[pos].count);
2111 set_label(l,script_pos,p);
2113 syntax.curly[pos].count++;
2116 if(!syntax.curly[pos].flag && p2 - p == 4 && !strncasecmp(p,"else",4)) {
2117 // else or else - if
2120 if(p2 - p == 2 && !strncasecmp(p,"if",2)) {
2124 disp_error_message("need '('",p);
2126 sprintf(label,"__IF%x_%x",syntax.curly[pos].index,syntax.curly[pos].count);
2127 add_scriptl(add_str("jump_zero"));
2131 add_scriptl(add_str(label));
2132 add_scriptc(C_FUNC);
2137 if(!syntax.curly[pos].flag) {
2138 syntax.curly[pos].flag = 1;
2145 syntax.curly_count--;
2146 // Put the label of the final location
2147 sprintf(label,"__IF%x_FIN",syntax.curly[pos].index);
2149 set_label(l,script_pos,p);
2150 if(syntax.curly[pos].flag == 1) {
2151 // Because the position of the pointer is the same if not else for this
2155 } else if(syntax.curly[pos].type == TYPE_DO) {
2160 if(syntax.curly[pos].flag) {
2161 // (Come here continue) to form the label here
2162 sprintf(label2,"__DO%x_NXT",syntax.curly[pos].index);
2164 set_label(l2,script_pos,p);
2167 // Skip to the end point if the condition is false
2170 if(p2 - p != 5 || strncasecmp(p,"while",5))
2171 disp_error_message("parse_syntax: expected 'while'",p);
2175 disp_error_message("need '('",p);
2178 // do-block end is a new line
2179 parse_nextline(false, p);
2181 sprintf(label2,"__DO%x_FIN",syntax.curly[pos].index);
2182 add_scriptl(add_str("jump_zero"));
2186 add_scriptl(add_str(label2));
2187 add_scriptc(C_FUNC);
2189 // Skip to the starting point
2190 sprintf(label2,"goto __DO%x_BGN;",syntax.curly[pos].index);
2191 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
2193 syntax.curly_count--;
2195 // Form label of the end point conditions
2196 sprintf(label2,"__DO%x_FIN",syntax.curly[pos].index);
2198 set_label(l2,script_pos,p);
2201 disp_error_message("parse_syntax: expected ';'",p);
2205 syntax.curly_count--;
2207 } else if(syntax.curly[pos].type == TYPE_FOR) {
2208 // for-block end is a new line
2209 parse_nextline(false, p);
2211 // Skip to the next loop
2212 sprintf(label,"goto __FR%x_NXT;",syntax.curly[pos].index);
2213 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
2215 syntax.curly_count--;
2218 sprintf(label,"__FR%x_FIN",syntax.curly[pos].index);
2220 set_label(l,script_pos,p);
2221 syntax.curly_count--;
2223 } else if(syntax.curly[pos].type == TYPE_WHILE) {
2224 // while-block end is a new line
2225 parse_nextline(false, p);
2227 // Skip to the decision while
2228 sprintf(label,"goto __WL%x_NXT;",syntax.curly[pos].index);
2229 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
2231 syntax.curly_count--;
2233 // End while labeling
2234 sprintf(label,"__WL%x_FIN",syntax.curly[pos].index);
2236 set_label(l,script_pos,p);
2237 syntax.curly_count--;
2239 } else if(syntax.curly[syntax.curly_count-1].type == TYPE_USERFUNC) {
2240 int pos2 = syntax.curly_count-1;
2244 sprintf(label2,"return;");
2245 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
2247 syntax.curly_count--;
2249 // Put the label of the location
2250 sprintf(label2,"__FN%x_FIN",syntax.curly[pos2].index);
2252 set_label(l2,script_pos,p);
2253 syntax.curly_count--;
2261 /*==========================================
2262 * Added built-in functions
2263 *------------------------------------------*/
2264 static void add_buildin_func(void)
2267 for( i = 0; buildin_func[i].func; i++ )
2269 // arg must follow the pattern: (v|s|i|r|l)*\?*\*?
2270 // 'v' - value (either string or int or reference)
2273 // 'r' - reference (of a variable)
2275 // '?' - one optional parameter
2276 // '*' - unknown number of optional parameters
2277 const char* p = buildin_func[i].arg;
2278 while( *p == 'v' || *p == 's' || *p == 'i' || *p == 'r' || *p == 'l' ) ++p;
2279 while( *p == '?' ) ++p;
2280 if( *p == '*' ) ++p;
2282 ShowWarning("add_buildin_func: ignoring function \"%s\" with invalid arg \"%s\".\n", buildin_func[i].name, buildin_func[i].arg);
2283 } else if( *skip_word(buildin_func[i].name) != 0 ){
2284 ShowWarning("add_buildin_func: ignoring function with invalid name \"%s\" (must be a word).\n", buildin_func[i].name);
2286 int n = add_str(buildin_func[i].name);
2287 str_data[n].type = C_FUNC;
2288 str_data[n].val = i;
2289 str_data[n].func = buildin_func[i].func;
2290 str_data[n].deprecated = (buildin_func[i].deprecated != NULL);
2292 if (!strcmp(buildin_func[i].name, "setr")) buildin_set_ref = n;
2293 else if (!strcmp(buildin_func[i].name, "callsub")) buildin_callsub_ref = n;
2294 else if (!strcmp(buildin_func[i].name, "callfunc")) buildin_callfunc_ref = n;
2295 else if( !strcmp(buildin_func[i].name, "getelementofarray") ) buildin_getelementofarray_ref = n;
2300 /// Retrieves the value of a constant parameter.
2301 bool script_get_parameter(const char* name, int* value)
2303 int n = search_str(name);
2305 if (n == -1 || str_data[n].type != C_PARAM)
2306 {// not found or not a parameter
2309 value[0] = str_data[n].val;
2314 /// Retrieves the value of a constant.
2315 bool script_get_constant(const char* name, int* value)
2317 int n = search_str(name);
2319 if( n == -1 || str_data[n].type != C_INT )
2320 {// not found or not a constant
2323 value[0] = str_data[n].val;
2325 #if defined(SCRIPT_CONSTANT_DEPRECATION)
2326 if( str_data[n].deprecated ){
2327 ShowWarning( "Usage of deprecated constant '%s'.\n", name );
2328 ShowWarning( "This constant was deprecated and could become unavailable anytime soon.\n" );
2335 /// Creates new constant or parameter with given value.
2336 void script_set_constant(const char* name, int value, bool isparameter, bool deprecated)
2338 int n = add_str(name);
2340 if( str_data[n].type == C_NOP )
2342 str_data[n].type = isparameter ? C_PARAM : C_INT;
2343 str_data[n].val = value;
2344 str_data[n].deprecated = deprecated;
2346 else if( str_data[n].type == C_PARAM || str_data[n].type == C_INT )
2347 {// existing parameter or constant
2348 ShowError("script_set_constant: Attempted to overwrite existing %s '%s' (old value=%d, new value=%d).\n", ( str_data[n].type == C_PARAM ) ? "parameter" : "constant", name, str_data[n].val, value);
2352 ShowError("script_set_constant: Invalid name for %s '%s' (already defined as %s).\n", isparameter ? "parameter" : "constant", name, script_op2name(str_data[n].type));
2356 /*==========================================
2357 * Reading constant databases
2359 *------------------------------------------*/
2360 static void read_constdb(void)
2363 char line[1024],name[1024],val[1024];
2365 int entries=0, skipped=0, linenum=0;
2367 sprintf(line, "%s/const.txt", db_path);
2368 fp=fopen(line, "r");
2370 ShowError("can't read %s\n", line);
2373 while(fgets(line, sizeof(line), fp))
2376 if( line[0] == '\0' || line[0] == '\n' || line[0] == '\r') //ignore empty line
2378 if(line[0]=='/' && line[1]=='/') //ignore commented line
2382 if(sscanf(line,"%1023[A-Za-z0-9/_],%1023[A-Za-z0-9/_-],%11d",name,val,&type)>=2 ||
2383 sscanf(line,"%1023[A-Za-z0-9/_] %1023[A-Za-z0-9/_-] %11d",name,val,&type)>=2){
2385 script_set_constant(name, (int)strtol(val, NULL, 0), (type != 0), false);
2389 ShowWarning("Skipping line '" CL_WHITE "%d" CL_RESET "', invalid constant definition\n",linenum);
2393 ShowStatus("Done reading '" CL_WHITE "%d" CL_RESET "' entries in '" CL_WHITE "%s/const.txt" CL_RESET "'.\n", entries, db_path);
2395 ShowWarning("Skipped '" CL_WHITE "%d" CL_RESET "', entries\n",skipped);
2400 * Sets source-end constants for NPC scripts to access.
2402 void script_hardcoded_constants(void) {
2403 #include "script_constants.h"
2406 /*==========================================
2407 * Display emplacement line of script
2408 *------------------------------------------*/
2409 static const char* script_print_line(StringBuf* buf, const char* p, const char* mark, int line)
2412 if( p == NULL || !p[0] ) return NULL;
2414 StringBuf_Printf(buf, "*% 5d : ", -line);
2416 StringBuf_Printf(buf, " % 5d : ", line);
2417 for(i=0;p[i] && p[i] != '\n';i++){
2419 StringBuf_Printf(buf, "%c", p[i]);
2421 StringBuf_Printf(buf, "\'%c\'", p[i]);
2423 StringBuf_AppendStr(buf, "\n");
2424 return p+i+(p[i] == '\n' ? 1 : 0);
2427 void script_errorwarning_sub(StringBuf *buf, const char* src, const char* file, int start_line, const char* error_msg_cur, const char* error_pos_cur) {
2428 // Find the line where the error occurred
2430 int line = start_line;
2432 const char *linestart[5] = { NULL, NULL, NULL, NULL, NULL };
2434 for(p=src;p && *p;line++){
2435 const char *lineend=strchr(p,'\n');
2436 if(lineend==NULL || error_pos_cur<lineend){
2439 for( j = 0; j < 4; j++ ) {
2440 linestart[j] = linestart[j+1];
2446 StringBuf_Printf(buf, "script error on %s line %d\n", file, line);
2447 StringBuf_Printf(buf, " %s\n", error_msg_cur);
2448 for(j = 0; j < 5; j++ ) {
2449 script_print_line(buf, linestart[j], NULL, line + j - 5);
2451 p = script_print_line(buf, p, error_pos_cur, -line);
2452 for(j = 0; j < 5; j++) {
2453 p = script_print_line(buf, p, NULL, line + j + 1 );
2457 void script_error(const char* src, const char* file, int start_line, const char* error_msg_cur, const char* error_pos_cur) {
2460 StringBuf_Init(&buf);
2461 StringBuf_AppendStr(&buf, "\a\n");
2463 script_errorwarning_sub(&buf, src, file, start_line, error_msg_cur, error_pos_cur);
2465 ShowError("%s", StringBuf_Value(&buf));
2466 StringBuf_Destroy(&buf);
2469 void script_warning(const char* src, const char* file, int start_line, const char* error_msg_cur, const char* error_pos_cur) {
2472 StringBuf_Init(&buf);
2474 script_errorwarning_sub(&buf, src, file, start_line, error_msg_cur, error_pos_cur);
2476 ShowWarning("%s", StringBuf_Value(&buf));
2477 StringBuf_Destroy(&buf);
2480 /*==========================================
2481 * Analysis of the script
2482 *------------------------------------------*/
2483 struct script_code* parse_script(const char *src,const char *file,int line,int options)
2485 const char *p,*tmpp;
2487 struct script_code* code = NULL;
2490 bool unresolved_names = false;
2492 parser_current_src = src;
2493 parser_current_file = file;
2494 parser_current_line = line;
2497 return NULL;// empty script
2499 memset(&syntax,0,sizeof(syntax));
2503 script_hardcoded_constants();
2507 script_buf=(unsigned char *)aMalloc(SCRIPT_BLOCK_SIZE*sizeof(unsigned char));
2509 script_size=SCRIPT_BLOCK_SIZE;
2510 parse_nextline(true, NULL);
2512 // who called parse_script is responsible for clearing the database after using it, but just in case... lets clear it here
2513 if( options&SCRIPT_USE_LABEL_DB )
2514 db_clear(scriptlabel_db);
2515 parse_options = options;
2517 if( setjmp( error_jump ) != 0 ) {
2518 //Restore program state when script has problems. [from jA]
2520 const int size = ARRAYLENGTH(syntax.curly);
2522 script_error(src,file,line,error_msg,error_pos);
2524 aFree( script_buf );
2528 for(j=LABEL_START;j<str_num;j++)
2529 if(str_data[j].type == C_NOP) str_data[j].type = C_NAME;
2530 for(j=0; j<size; j++)
2531 linkdb_final(&syntax.curly[j].case_label);
2535 parse_syntax_for_flag=0;
2538 if( options&SCRIPT_IGNORE_EXTERNAL_BRACKETS )
2539 {// does not require brackets around the script
2540 if( *p == '\0' && !(options&SCRIPT_RETURN_EMPTY_SCRIPT) )
2541 {// empty script and can return NULL
2542 aFree( script_buf );
2551 {// requires brackets around the script
2553 disp_error_message("not found '{'",p);
2554 p = skip_space(p+1);
2555 if( *p == '}' && !(options&SCRIPT_RETURN_EMPTY_SCRIPT) )
2556 {// empty script and can return NULL
2557 aFree( script_buf );
2566 // clear references of labels, variables and internal functions
2567 for(i=LABEL_START;i<str_num;i++){
2569 str_data[i].type==C_POS || str_data[i].type==C_NAME ||
2570 str_data[i].type==C_USERFUNC || str_data[i].type == C_USERFUNC_POS
2572 str_data[i].type=C_NOP;
2573 str_data[i].backpatch=-1;
2574 str_data[i].label=-1;
2578 while( syntax.curly_count != 0 || *p != end )
2581 disp_error_message("unexpected end of script",p);
2582 // Special handling only label
2583 tmpp=skip_space(skip_word(p));
2584 if(*tmpp==':' && !(!strncasecmp(p,"default:",8) && p + 7 == tmpp)){
2586 set_label(i,script_pos,p);
2587 if( parse_options&SCRIPT_USE_LABEL_DB )
2588 strdb_iput(scriptlabel_db, get_str(i), script_pos);
2598 parse_nextline(false, p);
2603 // trim code to size
2604 script_size = script_pos;
2605 RECREATE(script_buf,unsigned char,script_pos);
2607 // default unknown references to variables
2608 for(i=LABEL_START;i<str_num;i++){
2609 if(str_data[i].type==C_NOP){
2611 str_data[i].type=C_NAME;
2612 str_data[i].label=i;
2613 for(j=str_data[i].backpatch;j>=0 && j!=0x00ffffff;){
2614 int next=GETVALUE(script_buf,j);
2615 SETVALUE(script_buf,j,i);
2619 else if( str_data[i].type == C_USERFUNC )
2620 {// 'function name;' without follow-up code
2621 ShowError("parse_script: function '%s' declared but not defined.\n", str_buf+str_data[i].str);
2622 unresolved_names = true;
2626 if( unresolved_names )
2628 disp_error_message("parse_script: unresolved function references", p);
2632 for(i=0;i<script_pos;i++){
2633 if((i&15)==0) ShowMessage("%04x : ",i);
2634 ShowMessage("%02x ",script_buf[i]);
2635 if((i&15)==15) ShowMessage("\n");
2642 while(i < script_pos) {
2643 c_op op = get_com(script_buf,&i);
2645 ShowMessage("%06x %s", i, script_op2name(op));
2649 ShowMessage(" %d", get_num(script_buf,&i));
2652 ShowMessage(" 0x%06x", *(int*)(script_buf+i)&0xffffff);
2656 j = (*(int*)(script_buf+i)&0xffffff);
2657 ShowMessage(" %s", ( j == 0xffffff ) ? "?? unknown ??" : get_str(j));
2661 j = strlen(script_buf + i);
2662 ShowMessage(" %s", script_buf + i);
2666 ShowMessage(CL_CLL"\n");
2671 CREATE(code,struct script_code,1);
2672 code->script_buf = script_buf;
2673 code->script_size = script_size;
2674 code->local.vars = NULL;
2675 code->local.arrays = NULL;
2679 /// Returns the player attached to this script, identified by the rid.
2680 /// If there is no player attached, the script is terminated.
2681 static bool script_rid2sd_( struct script_state *st, struct map_session_data** sd, const char *func ){
2682 *sd = map_id2sd( st->rid );
2687 ShowError("%s: fatal error ! player not attached!\n",func);
2688 script_reportfunc(st);
2689 script_reportsrc(st);
2696 * Dereferences a variable/constant, replacing it with a copy of the value.
2697 * @param st Script state
2698 * @param data Variable/constant
2699 * @param sd If NULL, will try to use sd from st->rid (for player's variables)
2701 void get_val_(struct script_state* st, struct script_data* data, struct map_session_data *sd)
2707 if( !data_isreference(data) )
2708 return;// not a variable/constant
2710 name = reference_getname(data);
2712 postfix = name[strlen(name) - 1];
2714 //##TODO use reference_tovariable(data) when it's confirmed that it works [FlavioJS]
2715 if( !reference_toconstant(data) && not_server_variable(prefix) ) {
2716 if( sd == NULL && !script_rid2sd(sd) ) {// needs player attached
2717 if( postfix == '$' ) {// string variable
2718 ShowWarning("script:get_val: cannot access player variable '%s', defaulting to \"\"\n", name);
2719 data->type = C_CONSTSTR;
2720 data->u.str = const_cast<char *>("");
2721 } else {// integer variable
2722 ShowWarning("script:get_val: cannot access player variable '%s', defaulting to 0\n", name);
2730 if( postfix == '$' ) {// string variable
2734 data->u.str = pc_readregstr(sd, data->u.num);
2737 data->u.str = mapreg_readregstr(data->u.num);
2740 if( name[1] == '#' )
2741 data->u.str = pc_readaccountreg2str(sd, data->u.num);// global
2743 data->u.str = pc_readaccountregstr(sd, data->u.num);// local
2747 struct DBMap* n = data->ref ?
2748 data->ref->vars : name[1] == '@' ?
2749 st->stack->scope.vars : // instance/scope variable
2750 st->script->local.vars; // npc variable
2752 data->u.str = (char*)i64db_get(n,reference_getuid(data));
2759 unsigned short instance_id = script_instancegetid(st);
2761 data->u.str = (char*)i64db_get(instance_data[instance_id].regs.vars,reference_getuid(data));
2763 ShowWarning("script:get_val: cannot access instance variable '%s', defaulting to \"\"\n", name);
2769 data->u.str = pc_readglobalreg_str(sd, data->u.num);
2773 if( data->u.str == NULL || data->u.str[0] == '\0' ) {// empty string
2774 data->type = C_CONSTSTR;
2775 data->u.str = const_cast<char *>("");
2776 } else {// duplicate string
2778 data->u.str = aStrdup(data->u.str);
2781 } else {// integer variable
2785 if( reference_toconstant(data) ) {
2786 data->u.num = reference_getconstant(data);
2787 } else if( reference_toparam(data) ) {
2788 data->u.num = pc_readparam(sd, reference_getparamtype(data));
2792 data->u.num = pc_readreg(sd, data->u.num);
2795 data->u.num = mapreg_readreg(data->u.num);
2798 if( name[1] == '#' )
2799 data->u.num = pc_readaccountreg2(sd, data->u.num);// global
2801 data->u.num = pc_readaccountreg(sd, data->u.num);// local
2805 struct DBMap* n = data->ref ?
2806 data->ref->vars : name[1] == '@' ?
2807 st->stack->scope.vars : // instance/scope variable
2808 st->script->local.vars; // npc variable
2810 data->u.num = (int)i64db_iget(n,reference_getuid(data));
2817 unsigned short instance_id = script_instancegetid(st);
2819 data->u.num = (int)i64db_iget(instance_data[instance_id].regs.vars,reference_getuid(data));
2821 ShowWarning("script:get_val: cannot access instance variable '%s', defaulting to 0\n", name);
2827 data->u.num = pc_readglobalreg(sd, data->u.num);
2837 void get_val(struct script_state* st, struct script_data* data)
2839 get_val_(st,data,NULL);
2842 struct script_data* push_val2(struct script_stack* stack, enum c_op type, int64 val, struct reg_db* ref);
2844 /// Retrieves the value of a reference identified by uid (variable, constant, param)
2845 /// The value is left in the top of the stack and needs to be removed manually.
2846 /// @param st[in]: script state.
2847 /// @param uid[in]: reference identifier.
2848 /// @param ref[in]: the container to look up the reference into.
2849 /// @return: the retrieved value of the reference.
2850 void* get_val2(struct script_state* st, int64 uid, struct reg_db *ref)
2852 struct script_data* data;
2853 push_val2(st->stack, C_NAME, uid, ref);
2854 data = script_getdatatop(st, -1);
2856 //! TODO: Support data->u.num as int64 instead cast it to int? (in get_val, it was casted to int).
2857 return (data->type == C_INT ? (void*)__64BPRTSIZE((int)data->u.num) : (void*)__64BPRTSIZE(data->u.str));
2861 * Because, currently, array members with key 0 are indifferenciable from normal variables, we should ensure its actually in
2862 * Will be gone as soon as undefined var feature is implemented
2864 void script_array_ensure_zero(struct script_state *st, struct map_session_data *sd, int64 uid, struct reg_db *ref)
2866 const char *name = get_str(script_getvarid(uid));
2867 // is here st can be null pointer and st->rid is wrong?
2868 struct reg_db *src = script_array_src(st, sd ? sd : st->rid ? map_id2sd(st->rid) : NULL, name, ref);
2869 bool insert = false;
2872 // when sd comes, st isn't available
2875 if( is_string_variable(name) ) {
2876 char* str = (char*)get_val2(st, uid, ref);
2879 script_removetop(st, -1, 0);
2881 int32 num = (int32)__64BPRTSIZE(get_val2(st, uid, ref));
2884 script_removetop(st, -1, 0);
2888 if (src && src->arrays) {
2889 struct script_array *sa = static_cast<script_array *>(idb_get(src->arrays, script_getvarid(uid)));
2893 ARR_FIND(0, sa->size, i, sa->members[i] == 0);
2894 if( i != sa->size ) {
2896 script_array_remove_member(src,sa,i);
2900 script_array_add_member(sa,0);
2901 } else if (insert) {
2902 script_array_update(src,reference_uid(script_getvarid(uid), 0),false);
2908 * Returns array size by ID
2910 unsigned int script_array_size(struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref)
2912 struct script_array *sa = NULL;
2913 struct reg_db *src = script_array_src(st, sd, name, ref);
2915 if (src && src->arrays)
2916 sa = static_cast<script_array *>(idb_get(src->arrays, search_str(name)));
2918 return sa ? sa->size : 0;
2922 * Returns array's highest key (for that awful getarraysize implementation that doesn't really gets the array size)
2924 unsigned int script_array_highest_key(struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref)
2926 struct script_array *sa = NULL;
2927 struct reg_db *src = script_array_src(st, sd, name, ref);
2929 if (src && src->arrays) {
2930 int key = add_word(name);
2932 script_array_ensure_zero(st,sd,reference_uid(key, 0), ref);
2934 if( ( sa = static_cast<script_array *>(idb_get(src->arrays, key)) ) ) {
2935 unsigned int i, highest_key = 0;
2937 for(i = 0; i < sa->size; i++) {
2938 if( sa->members[i] > highest_key )
2939 highest_key = sa->members[i];
2942 return sa->size ? highest_key + 1 : 0;
2946 return SCRIPT_CMD_SUCCESS;
2949 int script_free_array_db(DBKey key, DBData *data, va_list ap)
2951 struct script_array *sa = static_cast<script_array *>(db_data2ptr(data));
2953 ers_free(array_ers, sa);
2954 return SCRIPT_CMD_SUCCESS;
2958 * Clears script_array and removes it from script->array_db
2960 void script_array_delete(struct reg_db *src, struct script_array *sa)
2963 idb_remove(src->arrays, sa->id);
2964 ers_free(array_ers, sa);
2968 * Removes a member from a script_array list
2970 * @param idx the index of the member in script_array struct list, not of the actual array member
2972 void script_array_remove_member(struct reg_db *src, struct script_array *sa, unsigned int idx)
2974 unsigned int i, cursor;
2976 // it's the only member left, no need to do anything other than delete the array data
2977 if( sa->size == 1 ) {
2978 script_array_delete(src,sa);
2982 sa->members[idx] = UINT_MAX;
2984 for(i = 0, cursor = 0; i < sa->size; i++) {
2985 if( sa->members[i] == UINT_MAX )
2988 sa->members[cursor] = sa->members[i];
2996 * Appends a new array index to the list in script_array
2998 * @param idx the index of the array member being inserted
3000 void script_array_add_member(struct script_array *sa, unsigned int idx)
3002 RECREATE(sa->members, unsigned int, ++sa->size);
3004 sa->members[sa->size - 1] = idx;
3008 * Obtains the source of the array database for this type and scenario
3009 * Initializes such database when not yet initialized.
3011 struct reg_db *script_array_src(struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref)
3013 struct reg_db *src = NULL;
3017 default: // char reg
3018 case '@': // temp char reg
3019 case '#': // account reg
3022 case '$': // map reg
3025 case '.': // npc/script
3029 src = (name[1] == '@') ? &st->stack->scope : &st->script->local;
3031 case '\'': // instance
3033 unsigned short instance_id = script_instancegetid(st);
3036 src = &instance_data[instance_id].regs;
3044 src->arrays = idb_alloc(DB_OPT_BASE);
3052 * Processes a array member modification, and update data accordingly
3054 * @param src[in,out] Variable source database. If the array database doesn't exist, it is created.
3055 * @param num[in] Variable ID
3056 * @param empty[in] Whether the modified member is empty (needs to be removed)
3058 void script_array_update(struct reg_db *src, int64 num, bool empty)
3060 struct script_array *sa = NULL;
3061 int id = script_getvarid(num);
3062 unsigned int index = script_getvaridx(num);
3065 src->arrays = idb_alloc(DB_OPT_BASE);
3067 sa = static_cast<script_array *>(idb_get(src->arrays, id));
3074 for(i = 0; i < sa->size; i++) {
3075 if( sa->members[i] == index )
3080 if( i != sa->size ) {
3081 // if empty, we gotta remove it
3083 script_array_remove_member(src, sa, i);
3085 } else if( !empty ) { /* new entry */
3086 script_array_add_member(sa,index);
3087 // we do nothing if its empty, no point in modifying array data for a new empty member
3089 } else if ( !empty ) { // we only move to create if not empty
3090 sa = ers_alloc(array_ers, struct script_array);
3094 script_array_add_member(sa,index);
3095 idb_put(src->arrays, id, sa);
3100 * Stores the value of a script variable
3102 * @param st: current script state.
3103 * @param sd: current character data.
3104 * @param num: variable identifier.
3105 * @param name: variable name.
3106 * @param value: new value.
3107 * @param ref: variable container, in case of a npc/scope variable reference outside the current scope.
3108 * @return: 0 failure, 1 success.
3110 * TODO: return values are screwed up, have been for some time (reaad: years), e.g. some functions return 1 failure and success.
3111 *------------------------------------------*/
3112 int set_reg(struct script_state* st, TBL_PC* sd, int64 num, const char* name, const void* value, struct reg_db *ref)
3114 char prefix = name[0];
3116 if( is_string_variable(name) ) {// string variable
3117 const char *str = (const char*)value;
3121 pc_setregstr(sd, num, str);
3124 return mapreg_setregstr(num, str);
3126 return (name[1] == '#') ?
3127 pc_setaccountreg2str(sd, num, str) :
3128 pc_setaccountregstr(sd, num, str);
3131 struct reg_db *n = (ref) ? ref : (name[1] == '@') ? &st->stack->scope : &st->script->local;
3134 i64db_put(n->vars, num, aStrdup(str));
3135 if( script_getvaridx(num) )
3136 script_array_update(n, num, false);
3138 i64db_remove(n->vars, num);
3139 if( script_getvaridx(num) )
3140 script_array_update(n, num, true);
3147 unsigned short instance_id = script_instancegetid(st);
3150 i64db_put(instance_data[instance_id].regs.vars, num, aStrdup(str));
3151 if( script_getvaridx(num) )
3152 script_array_update(&instance_data[instance_id].regs, num, false);
3154 i64db_remove(instance_data[instance_id].regs.vars, num);
3155 if (script_getvaridx(num))
3156 script_array_update(&instance_data[instance_id].regs, num, true);
3159 ShowError("script_set_reg: cannot write instance variable '%s', NPC not in a instance!\n", name);
3160 script_reportsrc(st);
3165 return pc_setglobalreg_str(sd, num, str);
3167 } else {// integer variable
3168 int val = (int)__64BPRTSIZE(value);
3170 if(str_data[script_getvarid(num)].type == C_PARAM) {
3171 if( pc_setparam(sd, str_data[script_getvarid(num)].val, val) == 0 ) {
3173 ShowError("script_set_reg: failed to set param '%s' to %d.\n", name, val);
3174 script_reportsrc(st);
3184 pc_setreg(sd, num, val);
3187 return mapreg_setreg(num, val);
3189 return (name[1] == '#') ?
3190 pc_setaccountreg2(sd, num, val) :
3191 pc_setaccountreg(sd, num, val);
3194 struct reg_db *n = (ref) ? ref : (name[1] == '@') ? &st->stack->scope : &st->script->local;
3197 i64db_iput(n->vars, num, val);
3198 if( script_getvaridx(num) )
3199 script_array_update(n, num, false);
3201 i64db_remove(n->vars, num);
3202 if( script_getvaridx(num) )
3203 script_array_update(n, num, true);
3210 unsigned short instance_id = script_instancegetid(st);
3213 i64db_iput(instance_data[instance_id].regs.vars, num, val);
3214 if( script_getvaridx(num) )
3215 script_array_update(&instance_data[instance_id].regs, num, false);
3217 i64db_remove(instance_data[instance_id].regs.vars, num);
3218 if (script_getvaridx(num))
3219 script_array_update(&instance_data[instance_id].regs, num, true);
3222 ShowError("script_set_reg: cannot write instance variable '%s', NPC not in a instance!\n", name);
3223 script_reportsrc(st);
3228 return pc_setglobalreg(sd, num, val);
3233 int set_var(struct map_session_data* sd, char* name, void* val)
3235 return set_reg(NULL, sd, reference_uid(add_str(name),0), name, val, NULL);
3238 void setd_sub(struct script_state *st, TBL_PC *sd, const char *varname, int elem, void *value, struct reg_db *ref)
3240 set_reg(st, sd, reference_uid(add_str(varname),elem), varname, value, ref);
3244 * Converts the data to a string
3249 const char* conv_str_(struct script_state* st, struct script_data* data, struct map_session_data *sd)
3253 get_val_(st, data, sd);
3254 if( data_isstring(data) )
3255 {// nothing to convert
3257 else if( data_isint(data) )
3259 CREATE(p, char, ITEM_NAME_LENGTH);
3260 snprintf(p, ITEM_NAME_LENGTH, "%" PRId64 "", data->u.num);
3261 p[ITEM_NAME_LENGTH-1] = '\0';
3265 else if( data_isreference(data) )
3266 {// reference -> string
3267 //##TODO when does this happen (check get_val) [FlavioJS]
3268 data->type = C_CONSTSTR;
3269 data->u.str = reference_getname(data);
3272 {// unsupported data type
3273 ShowError("script:conv_str: cannot convert to string, defaulting to \"\"\n");
3274 script_reportdata(data);
3275 script_reportsrc(st);
3276 data->type = C_CONSTSTR;
3277 data->u.str = const_cast<char *>("");
3282 const char* conv_str(struct script_state* st, struct script_data* data)
3284 return conv_str_(st, data, NULL);
3288 * Converts the data to an int
3293 int conv_num_(struct script_state* st, struct script_data* data, struct map_session_data *sd)
3295 get_val_(st, data, sd);
3296 if( data_isint(data) )
3297 {// nothing to convert
3299 else if( data_isstring(data) )
3301 // the result does not overflow or underflow, it is capped instead
3302 // ex: 999999999999 is capped to INT_MAX (2147483647)
3303 char* p = data->u.str;
3307 num = strtol(data->u.str, NULL, 10);// change radix to 0 to support octal numbers "o377" and hex numbers "0xFF"
3309 #if LONG_MAX > INT_MAX
3310 || num < INT_MIN || num > INT_MAX
3314 if( num <= INT_MIN )
3317 ShowError("script:conv_num: underflow detected, capping to %ld\n", num);
3319 else//if( num >= INT_MAX )
3322 ShowError("script:conv_num: overflow detected, capping to %ld\n", num);
3324 script_reportdata(data);
3325 script_reportsrc(st);
3327 if( data->type == C_STR )
3330 data->u.num = (int)num;
3333 // FIXME this function is being used to retrieve the position of labels and
3334 // probably other stuff [FlavioJS]
3336 {// unsupported data type
3337 ShowError("script:conv_num: cannot convert to number, defaulting to 0\n");
3338 script_reportdata(data);
3339 script_reportsrc(st);
3344 return (int)data->u.num;
3347 int conv_num(struct script_state* st, struct script_data* data)
3349 return conv_num_(st, data, NULL);
3356 /// Increases the size of the stack
3357 void stack_expand(struct script_stack* stack)
3359 stack->sp_max += 64;
3360 stack->stack_data = (struct script_data*)aRealloc(stack->stack_data,
3361 stack->sp_max * sizeof(stack->stack_data[0]) );
3362 memset(stack->stack_data + (stack->sp_max - 64), 0,
3363 64 * sizeof(stack->stack_data[0]) );
3366 /// Pushes a value into the stack
3367 #define push_val(stack,type,val) push_val2(stack, type, val, NULL)
3369 /// Pushes a value into the stack (with reference)
3370 struct script_data* push_val2(struct script_stack* stack, enum c_op type, int64 val, struct reg_db *ref)
3372 if( stack->sp >= stack->sp_max )
3373 stack_expand(stack);
3374 stack->stack_data[stack->sp].type = type;
3375 stack->stack_data[stack->sp].u.num = val;
3376 stack->stack_data[stack->sp].ref = ref;
3378 return &stack->stack_data[stack->sp-1];
3381 /// Pushes a string into the stack
3382 struct script_data* push_str(struct script_stack* stack, enum c_op type, char* str)
3384 if( stack->sp >= stack->sp_max )
3385 stack_expand(stack);
3386 stack->stack_data[stack->sp].type = type;
3387 stack->stack_data[stack->sp].u.str = str;
3388 stack->stack_data[stack->sp].ref = NULL;
3390 return &stack->stack_data[stack->sp-1];
3393 /// Pushes a retinfo into the stack
3394 struct script_data* push_retinfo(struct script_stack* stack, struct script_retinfo* ri, struct reg_db *ref)
3396 if( stack->sp >= stack->sp_max )
3397 stack_expand(stack);
3398 stack->stack_data[stack->sp].type = C_RETINFO;
3399 stack->stack_data[stack->sp].u.ri = ri;
3400 stack->stack_data[stack->sp].ref = ref;
3402 return &stack->stack_data[stack->sp-1];
3405 /// Pushes a copy of the target position into the stack
3406 struct script_data* push_copy(struct script_stack* stack, int pos)
3408 switch( stack->stack_data[pos].type ) {
3410 return push_str(stack, C_CONSTSTR, stack->stack_data[pos].u.str);
3413 return push_str(stack, C_STR, aStrdup(stack->stack_data[pos].u.str));
3416 ShowFatalError("script:push_copy: can't create copies of C_RETINFO. Exiting...\n");
3421 stack,stack->stack_data[pos].type,
3422 stack->stack_data[pos].u.num,
3423 stack->stack_data[pos].ref
3429 /// Removes the values in indexes [start,end] from the stack.
3430 /// Adjusts all stack pointers.
3431 void pop_stack(struct script_state* st, int start, int end)
3433 struct script_stack* stack = st->stack;
3434 struct script_data* data;
3439 if( end > stack->sp )
3442 return;// nothing to pop
3444 // free stack elements
3445 for( i = start; i < end; i++ )
3447 data = &stack->stack_data[i];
3448 if( data->type == C_STR )
3450 if( data->type == C_RETINFO ) {
3451 struct script_retinfo* ri = data->u.ri;
3453 if (ri->scope.vars) {
3454 script_free_vars(ri->scope.vars);
3455 ri->scope.vars = NULL;
3457 if (ri->scope.arrays) {
3458 ri->scope.arrays->destroy(ri->scope.arrays, script_free_array_db);
3459 ri->scope.arrays = NULL;
3468 // move the rest of the elements
3469 if( stack->sp > end )
3471 memmove(&stack->stack_data[start], &stack->stack_data[end], sizeof(stack->stack_data[0])*(stack->sp - end));
3472 for( i = start + stack->sp - end; i < stack->sp; ++i )
3473 stack->stack_data[i].type = C_NOP;
3476 // adjust stack pointers
3477 if( st->start > end ){
3478 st->start -= end - start;
3479 }else if( st->start > start ){
3483 if( st->end > end ){
3484 st->end -= end - start;
3485 }else if( st->end > start ){
3489 if( stack->defsp > end ){
3490 stack->defsp -= end - start;
3491 }else if( stack->defsp > start ){
3492 stack->defsp = start;
3495 stack->sp -= end - start;
3502 /*==========================================
3503 * Release script dependent variable, dependent variable of function
3504 *------------------------------------------*/
3505 void script_free_vars(struct DBMap* storage)
3508 // destroy the storage construct containing the variables
3509 db_destroy(storage);
3513 void script_free_code(struct script_code* code)
3517 if (code->instances)
3518 script_stop_scriptinstances(code);
3519 script_free_vars(code->local.vars);
3520 if (code->local.arrays)
3521 code->local.arrays->destroy(code->local.arrays, script_free_array_db);
3522 aFree(code->script_buf);
3526 /// Creates a new script state.
3528 /// @param script Script code
3529 /// @param pos Position in the code
3530 /// @param rid Who is running the script (attached player)
3531 /// @param oid Where the code is being run (npc 'object')
3532 /// @return Script state
3533 struct script_state* script_alloc_state(struct script_code* rootscript, int pos, int rid, int oid)
3535 struct script_state* st;
3537 st = ers_alloc(st_ers, struct script_state);
3538 st->stack = ers_alloc(stack_ers, struct script_stack);
3540 st->stack->sp_max = 64;
3541 CREATE(st->stack->stack_data, struct script_data, st->stack->sp_max);
3542 st->stack->defsp = st->stack->sp;
3543 st->stack->scope.vars = i64db_alloc(DB_OPT_RELEASE_DATA);
3544 st->stack->scope.arrays = NULL;
3546 st->script = rootscript;
3550 st->sleep.timer = INVALID_TIMER;
3551 st->npc_item_flag = battle_config.item_enabled_npc;
3553 if( st->script->instances != USHRT_MAX )
3554 st->script->instances++;
3556 struct npc_data *nd = map_id2nd(oid);
3558 ShowError("Over 65k instances of '%s' script are being run!\n",nd ? nd->name : "unknown");
3561 if (!st->script->local.vars)
3562 st->script->local.vars = i64db_alloc(DB_OPT_RELEASE_DATA);
3567 idb_put(st_db, st->id, st);
3572 /// Frees a script state.
3574 /// @param st Script state
3575 void script_free_state(struct script_state* st)
3577 if (idb_exists(st_db, st->id)) {
3578 struct map_session_data *sd = st->rid ? map_id2sd(st->rid) : NULL;
3580 if (st->bk_st) // backup was not restored
3581 ShowDebug("script_free_state: Previous script state lost (rid=%d, oid=%d, state=%d, bk_npcid=%d).\n", st->bk_st->rid, st->bk_st->oid, st->bk_st->state, st->bk_npcid);
3583 if (sd && sd->st == st) { // Current script is aborted.
3584 if(sd->state.using_fake_npc) {
3585 clif_clearunit_single(sd->npc_id, CLR_OUTSIGHT, sd->fd);
3586 sd->state.using_fake_npc = 0;
3592 if (st->sleep.timer != INVALID_TIMER)
3593 delete_timer(st->sleep.timer, run_script_timer);
3595 script_free_vars(st->stack->scope.vars);
3596 if (st->stack->scope.arrays)
3597 st->stack->scope.arrays->destroy(st->stack->scope.arrays, script_free_array_db);
3598 pop_stack(st, 0, st->stack->sp);
3599 aFree(st->stack->stack_data);
3600 ers_free(stack_ers, st->stack);
3603 if (st->script && st->script->instances != USHRT_MAX && --st->script->instances == 0) {
3604 if (st->script->local.vars && !db_size(st->script->local.vars)) {
3605 script_free_vars(st->script->local.vars);
3606 st->script->local.vars = NULL;
3608 if (st->script->local.arrays && !db_size(st->script->local.arrays)) {
3609 st->script->local.arrays->destroy(st->script->local.arrays, script_free_array_db);
3610 st->script->local.arrays = NULL;
3615 idb_remove(st_db, st->id);
3616 ers_free(st_ers, st);
3617 if (--active_scripts == 0)
3623 // Main execution unit
3625 /*==========================================
3627 *------------------------------------------*/
3628 c_op get_com(unsigned char *script,int *pos)
3632 if(script[*pos]>=0x80){
3635 while(script[*pos]>=0x40){
3636 i=script[(*pos)++]<<j;
3639 return (c_op)(i+(script[(*pos)++]<<j));
3642 /*==========================================
3644 *------------------------------------------*/
3645 int get_num(unsigned char *script,int *pos)
3649 while(script[*pos]>=0xc0){
3650 i+=(script[(*pos)++]&0x7f)<<j;
3653 return i+((script[(*pos)++]&0x7f)<<j);
3656 /// Ternary operators
3657 /// test ? if_true : if_false
3658 void op_3(struct script_state* st, int op)
3660 struct script_data* data;
3663 data = script_getdatatop(st, -3);
3666 if( data_isstring(data) )
3667 flag = data->u.str[0];// "" -> false
3668 else if( data_isint(data) )
3669 flag = data->u.num == 0 ? 0 : 1;// 0 -> false
3672 ShowError("script:op_3: invalid data for the ternary operator test\n");
3673 script_reportdata(data);
3674 script_reportsrc(st);
3675 script_removetop(st, -3, 0);
3680 script_pushcopytop(st, -2);
3682 script_pushcopytop(st, -1);
3683 script_removetop(st, -4, -1);
3686 /// Binary string operators
3694 void op_2str(struct script_state* st, int op, const char* s1, const char* s2)
3699 case C_EQ: a = (strcmp(s1,s2) == 0); break;
3700 case C_NE: a = (strcmp(s1,s2) != 0); break;
3701 case C_GT: a = (strcmp(s1,s2) > 0); break;
3702 case C_GE: a = (strcmp(s1,s2) >= 0); break;
3703 case C_LT: a = (strcmp(s1,s2) < 0); break;
3704 case C_LE: a = (strcmp(s1,s2) <= 0); break;
3707 char* buf = (char *)aMalloc((strlen(s1)+strlen(s2)+1)*sizeof(char));
3710 script_pushstr(st, buf);
3714 ShowError("script:op2_str: unexpected string operator %s\n", script_op2name(op));
3715 script_reportsrc(st);
3721 script_pushint(st,a);
3724 /// Binary number operators
3726 void op_2num(struct script_state* st, int op, int i1, int i2)
3732 case C_AND: ret = i1 & i2; break;
3733 case C_OR: ret = i1 | i2; break;
3734 case C_XOR: ret = i1 ^ i2; break;
3735 case C_LAND: ret = (i1 && i2); break;
3736 case C_LOR: ret = (i1 || i2); break;
3737 case C_EQ: ret = (i1 == i2); break;
3738 case C_NE: ret = (i1 != i2); break;
3739 case C_GT: ret = (i1 > i2); break;
3740 case C_GE: ret = (i1 >= i2); break;
3741 case C_LT: ret = (i1 < i2); break;
3742 case C_LE: ret = (i1 <= i2); break;
3743 case C_R_SHIFT: ret = i1>>i2; break;
3744 case C_L_SHIFT: ret = i1<<i2; break;
3749 ShowError("script:op_2num: division by zero detected op=%s i1=%d i2=%d\n", script_op2name(op), i1, i2);
3750 script_reportsrc(st);
3755 else if( op == C_DIV )
3757 else//if( op == C_MOD )
3761 switch( op ) {// operators that can overflow/underflow
3762 case C_ADD: ret = i1 + i2; ret_double = (double)i1 + (double)i2; break;
3763 case C_SUB: ret = i1 - i2; ret_double = (double)i1 - (double)i2; break;
3764 case C_MUL: ret = i1 * i2; ret_double = (double)i1 * (double)i2; break;
3766 ShowError("script:op_2num: unexpected number operator %s i1=%d i2=%d\n", script_op2name(op), i1, i2);
3767 script_reportsrc(st);
3771 if( ret_double < (double)INT_MIN ) {
3772 ShowWarning("script:op_2num: underflow detected op=%s i1=%d i2=%d\n", script_op2name(op), i1, i2);
3773 script_reportsrc(st);
3776 else if( ret_double > (double)INT_MAX ) {
3777 ShowWarning("script:op_2num: overflow detected op=%s i1=%d i2=%d\n", script_op2name(op), i1, i2);
3778 script_reportsrc(st);
3782 script_pushint(st, ret);
3785 /// Binary operators
3786 void op_2(struct script_state *st, int op)
3788 struct script_data* left, leftref;
3789 struct script_data* right;
3791 leftref.type = C_NOP;
3793 left = script_getdatatop(st, -2);
3794 right = script_getdatatop(st, -1);
3797 if (data_isreference(left)) {
3807 // automatic conversions
3811 if( data_isint(left) && data_isstring(right) )
3812 {// convert int-string to string-string
3815 else if( data_isstring(left) && data_isint(right) )
3816 {// convert string-int to string-string
3817 conv_str(st, right);
3822 if( data_isstring(left) && data_isstring(right) )
3824 op_2str(st, op, left->u.str, right->u.str);
3825 script_removetop(st, leftref.type == C_NOP ? -3 : -2, -1);// pop the two values before the top one
3827 if (leftref.type != C_NOP)
3829 if (left->type == C_STR) // don't free C_CONSTSTR
3834 else if( data_isint(left) && data_isint(right) )
3836 int i1 = (int)left->u.num;
3837 int i2 = (int)right->u.num;
3839 script_removetop(st, leftref.type == C_NOP ? -2 : -1, 0);
3840 op_2num(st, op, i1, i2);
3842 if (leftref.type != C_NOP)
3846 {// invalid argument
3847 ShowError("script:op_2: invalid data for operator %s\n", script_op2name(op));
3848 script_reportdata(left);
3849 script_reportdata(right);
3850 script_reportsrc(st);
3851 script_removetop(st, -2, 0);
3861 void op_1(struct script_state* st, int op)
3863 struct script_data* data;
3866 data = script_getdatatop(st, -1);
3869 if( !data_isint(data) )
3871 ShowError("script:op_1: argument is not a number (op=%s)\n", script_op2name(op));
3872 script_reportdata(data);
3873 script_reportsrc(st);
3879 i1 = (int)data->u.num;
3880 script_removetop(st, -1, 0);
3883 case C_NEG: i1 = -i1; break;
3884 case C_NOT: i1 = ~i1; break;
3885 case C_LNOT: i1 = !i1; break;
3887 ShowError("script:op_1: unexpected operator %s i1=%d\n", script_op2name(op), i1);
3888 script_reportsrc(st);
3893 script_pushint(st, i1);
3897 /// Checks the type of all arguments passed to a built-in function.
3899 /// @param st Script state whose stack arguments should be inspected.
3900 /// @param func Built-in function for which the arguments are intended.
3901 static void script_check_buildin_argtype(struct script_state* st, int func)
3903 int idx, invalid = 0;
3905 for( idx = 2; script_hasdata(st, idx); idx++ )
3907 struct script_data* data = script_getdata(st, idx);
3908 script_function* sf = &buildin_func[str_data[func].val];
3909 char type = sf->arg[idx-2];
3911 if( type == '?' || type == '*' )
3912 {// optional argument or unknown number of optional parameters ( no types are after this )
3915 else if( type == 0 )
3916 {// more arguments than necessary ( should not happen, as it is checked before )
3917 ShowWarning("Found more arguments than necessary. unexpected arg type %s\n",script_op2name(data->type));
3923 const char* name = NULL;
3925 if( data_isreference(data) )
3926 {// get name for variables to determine the type they refer to
3927 name = reference_getname(data);
3933 if( !data_isstring(data) && !data_isint(data) && !data_isreference(data) )
3935 ShowWarning("Unexpected type for argument %d. Expected string, number or variable.\n", idx-1);
3936 script_reportdata(data);
3941 if( !data_isstring(data) && !( data_isreference(data) && is_string_variable(name) ) )
3943 ShowWarning("Unexpected type for argument %d. Expected string.\n", idx-1);
3944 script_reportdata(data);
3949 if( !data_isint(data) && !( data_isreference(data) && ( reference_toparam(data) || reference_toconstant(data) || !is_string_variable(name) ) ) )
3950 {// int ( params and constants are always int )
3951 ShowWarning("Unexpected type for argument %d. Expected number.\n", idx-1);
3952 script_reportdata(data);
3957 if( !data_isreference(data) )
3959 ShowWarning("Unexpected type for argument %d. Expected variable, got %s.\n", idx-1,script_op2name(data->type));
3960 script_reportdata(data);
3965 if( !data_islabel(data) && !data_isfunclabel(data) )
3967 ShowWarning("Unexpected type for argument %d. Expected label, got %s\n", idx-1,script_op2name(data->type));
3968 script_reportdata(data);
3978 ShowDebug("Function: %s\n", get_str(func));
3979 script_reportsrc(st);
3984 /// Executes a buildin command.
3985 /// Stack: C_NAME(<command>) C_ARG <arg0> <arg1> ... <argN>
3986 int run_func(struct script_state *st)
3988 struct script_data* data;
3989 int i,start_sp,end_sp,func;
3991 end_sp = st->stack->sp;// position after the last argument
3992 for( i = end_sp-1; i > 0 ; --i )
3993 if( st->stack->stack_data[i].type == C_ARG )
3996 ShowError("script:run_func: C_ARG not found. please report this!!!\n");
3998 script_reportsrc(st);
4001 start_sp = i-1;// C_NAME of the command
4002 st->start = start_sp;
4005 data = &st->stack->stack_data[st->start];
4006 if( data->type == C_NAME && str_data[data->u.num].type == C_FUNC ) {
4007 func = (int)data->u.num;
4008 st->funcname = reference_getname(data);
4010 ShowError("script:run_func: not a buildin command.\n");
4011 script_reportdata(data);
4012 script_reportsrc(st);
4017 if( script_config.warn_func_mismatch_argtypes ) {
4018 script_check_buildin_argtype(st, func);
4021 if(str_data[func].func) {
4022 #if defined(SCRIPT_COMMAND_DEPRECATION)
4023 if( buildin_func[str_data[func].val].deprecated ){
4024 ShowWarning( "Usage of deprecated script function '%s'.\n", get_str(func) );
4025 ShowWarning( "This function was deprecated on '%s' and could become unavailable anytime soon.\n", buildin_func[str_data[func].val].deprecated );
4026 script_reportsrc(st);
4030 if (str_data[func].func(st) == SCRIPT_CMD_FAILURE) //Report error
4031 script_reportsrc(st);
4033 ShowError("script:run_func: '%s' (id=%d type=%s) has no C function. please report this!!!\n", get_str(func), func, script_op2name(str_data[func].type));
4034 script_reportsrc(st);
4038 // Stack's datum are used when re-running functions [Eoe]
4039 if( st->state == RERUNLINE )
4042 pop_stack(st, st->start, st->end);
4043 if( st->state == RETFUNC ) {// return from a user-defined function
4044 struct script_retinfo* ri;
4045 int olddefsp = st->stack->defsp;
4048 pop_stack(st, st->stack->defsp, st->start);// pop distractions from the stack
4049 if( st->stack->defsp < 1 || st->stack->stack_data[st->stack->defsp-1].type != C_RETINFO )
4051 ShowWarning("script:run_func: return without callfunc or callsub!\n");
4052 script_reportsrc(st);
4056 script_free_vars(st->stack->scope.vars);
4057 st->stack->scope.arrays->destroy(st->stack->scope.arrays, script_free_array_db);
4059 ri = st->stack->stack_data[st->stack->defsp-1].u.ri;
4062 st->script = ri->script;
4063 st->stack->scope.vars = ri->scope.vars;
4064 st->stack->scope.arrays = ri->scope.arrays;
4065 st->stack->defsp = ri->defsp;
4066 memset(ri, 0, sizeof(struct script_retinfo));
4068 pop_stack(st, olddefsp-nargs-1, olddefsp);// pop arguments and retinfo
4076 /*==========================================
4078 *------------------------------------------*/
4079 void run_script(struct script_code *rootscript, int pos, int rid, int oid)
4081 struct script_state *st;
4083 if( rootscript == NULL || pos < 0 )
4086 // TODO In jAthena, this function can take over the pending script in the player. [FlavioJS]
4087 // It is unclear how that can be triggered, so it needs the be traced/checked in more detail.
4088 // NOTE At the time of this change, this function wasn't capable of taking over the script state because st->scriptroot was never set.
4089 st = script_alloc_state(rootscript, pos, rid, oid);
4090 run_script_main(st);
4094 * Free all related script code
4095 * @param code: Script code to free
4097 void script_stop_scriptinstances(struct script_code *code) {
4099 struct script_state* st;
4101 if( !active_scripts )
4102 return; // Don't even bother.
4104 iter = db_iterator(st_db);
4106 for( st = static_cast<script_state *>(dbi_first(iter)); dbi_exists(iter); st = static_cast<script_state *>(dbi_next(iter)) ) {
4107 if( st->script == code )
4108 script_free_state(st);
4114 /*==========================================
4115 * Timer function for sleep
4116 *------------------------------------------*/
4117 int run_script_timer(int tid, unsigned int tick, int id, intptr_t data)
4119 struct script_state *st = (struct script_state *)data;
4120 struct linkdb_node *node = (struct linkdb_node *)sleep_db;
4122 // If it was a player before going to sleep and there is still a unit attached to the script
4123 if( id != 0 && st->rid ){
4124 struct map_session_data *sd = map_id2sd(st->rid);
4126 // Attached player is offline(logout) or another unit type(should not happen)
4130 // Character mismatch. Cancel execution.
4131 }else if( sd->status.char_id != id ){
4132 ShowWarning( "Script sleep timer detected a character mismatch CID %d != %d\n", sd->status.char_id, id );
4133 script_reportsrc(st);
4139 while (node && st->sleep.timer != INVALID_TIMER) {
4140 if ((int)__64BPRTSIZE(node->key) == st->oid && ((struct script_state *)node->data)->sleep.timer == st->sleep.timer) {
4141 script_erase_sleepdb(node);
4142 st->sleep.timer = INVALID_TIMER;
4147 if(st->state != RERUNLINE)
4149 run_script_main(st);
4154 * Remove sleep timers from the NPC
4157 void script_stop_sleeptimers(int id) {
4159 struct script_state *st = (struct script_state *)linkdb_erase(&sleep_db, (void *)__64BPRTSIZE(id));
4162 break; // No more sleep timers
4165 script_free_state(st);
4170 * Delete the specified node from sleep_db
4171 * @param n: Linked list of sleep timers
4173 struct linkdb_node *script_erase_sleepdb(struct linkdb_node *n) {
4174 struct linkdb_node *retnode;
4182 n->prev->next = n->next;
4185 n->next->prev = n->prev;
4193 /// Detaches script state from possibly attached character and restores it's previous script if any.
4195 /// @param st Script state to detach.
4196 /// @param dequeue_event Whether to schedule any queued events, when there was no previous script.
4197 static void script_detach_state(struct script_state* st, bool dequeue_event)
4199 struct map_session_data* sd;
4201 if(st->rid && (sd = map_id2sd(st->rid))!=NULL) {
4203 sd->npc_id = st->bk_npcid;
4204 sd->state.disable_atcommand_on_npc = 0;
4206 //Remove tag for removal.
4209 } else if(dequeue_event) {
4211 #ifdef SECURE_NPCTIMEOUT
4213 * We're done with this NPC session, so we cancel the timer (if existent) and move on
4215 if( sd->npc_idle_timer != INVALID_TIMER ) {
4216 delete_timer(sd->npc_idle_timer,npc_rr_secure_timeout_timer);
4217 sd->npc_idle_timer = INVALID_TIMER;
4220 npc_event_dequeue(sd);
4224 {// rid was set to 0, before detaching the script state
4225 ShowError("script_detach_state: Found previous script state without attached player (rid=%d, oid=%d, state=%d, bk_npcid=%d)\n", st->bk_st->rid, st->bk_st->oid, st->bk_st->state, st->bk_npcid);
4226 script_reportsrc(st->bk_st);
4228 script_free_state(st->bk_st);
4233 /// Attaches script state to possibly attached character and backups it's previous script, if any.
4235 /// @param st Script state to attach.
4236 static void script_attach_state(struct script_state* st)
4238 struct map_session_data* sd;
4240 if(st->rid && (sd = map_id2sd(st->rid))!=NULL)
4245 {// there is already a backup
4246 ShowDebug("script_attach_state: Previous script state lost (rid=%d, oid=%d, state=%d, bk_npcid=%d).\n", st->bk_st->rid, st->bk_st->oid, st->bk_st->state, st->bk_npcid);
4249 st->bk_npcid = sd->npc_id;
4252 sd->npc_id = st->oid;
4253 sd->npc_item_flag = st->npc_item_flag; // load default.
4254 sd->state.disable_atcommand_on_npc = (!pc_has_permission(sd, PC_PERM_ENABLE_COMMAND));
4255 #ifdef SECURE_NPCTIMEOUT
4256 if( sd->npc_idle_timer == INVALID_TIMER )
4257 sd->npc_idle_timer = add_timer(gettick() + (SECURE_NPCTIMEOUT_INTERVAL*1000),npc_rr_secure_timeout_timer,sd->bl.id,0);
4258 sd->npc_idle_tick = gettick();
4263 /*==========================================
4264 * The main part of the script execution
4265 *------------------------------------------*/
4266 void run_script_main(struct script_state *st)
4268 int cmdcount = script_config.check_cmdcount;
4269 int gotocount = script_config.check_gotocount;
4271 struct script_stack *stack = st->stack;
4273 script_attach_state(st);
4275 if(st->state == RERUNLINE) {
4277 if(st->state == GOTO)
4279 } else if(st->state != END)
4282 while(st->state == RUN) {
4283 enum c_op c = get_com(st->script->script_buf,&st->pos);
4286 if( stack->defsp > stack->sp )
4287 ShowError("script:run_script_main: unexpected stack position (defsp=%d sp=%d). please report this!!!\n", stack->defsp, stack->sp);
4289 pop_stack(st, stack->defsp, stack->sp);// pop unused stack data. (unused return value)
4292 push_val(stack,C_INT,get_num(st->script->script_buf,&st->pos));
4296 push_val(stack,c,GETVALUE(st->script->script_buf,st->pos));
4300 push_val(stack,c,0);
4303 push_str(stack,C_CONSTSTR,(char*)(st->script->script_buf+st->pos));
4304 while(st->script->script_buf[st->pos++]);
4308 if(st->state==GOTO){
4310 if( !st->freeloop && gotocount>0 && (--gotocount)<=0 ){
4311 ShowError("script:run_script_main: infinity loop !\n");
4312 script_reportsrc(st);
4358 ShowError("script:run_script_main:unknown command : %d @ %d\n",c,st->pos);
4362 if( !st->freeloop && cmdcount>0 && (--cmdcount)<=0 ){
4363 ShowError("script:run_script_main: infinity loop !\n");
4364 script_reportsrc(st);
4369 if(st->sleep.tick > 0) {
4370 //Restore previous script
4371 script_detach_state(st, false);
4373 sd = map_id2sd(st->rid); // Get sd since script might have attached someone while running. [Inkfish]
4374 st->sleep.charid = sd?sd->status.char_id:0;
4375 st->sleep.timer = add_timer(gettick() + st->sleep.tick, run_script_timer, st->sleep.charid, (intptr_t)st);
4376 linkdb_insert(&sleep_db, (void *)__64BPRTSIZE(st->oid), st);
4377 } else if(st->state != END && st->rid) {
4378 //Resume later (st is already attached to player).
4380 ShowWarning("Unable to restore stack! Double continuation!\n");
4381 //Report BOTH scripts to see if that can help somehow.
4382 ShowDebug("Previous script (lost):\n");
4383 script_reportsrc(st->bk_st);
4384 ShowDebug("Current script:\n");
4385 script_reportsrc(st);
4387 script_free_state(st->bk_st);
4391 //Dispose of script.
4392 if ((sd = map_id2sd(st->rid))!=NULL)
4393 { //Restore previous stack and save char.
4394 if(sd->state.using_fake_npc){
4395 clif_clearunit_single(sd->npc_id, CLR_OUTSIGHT, sd->fd);
4396 sd->state.using_fake_npc = 0;
4398 //Restore previous script if any.
4399 script_detach_state(st, true);
4401 intif_saveregistry(sd);
4403 script_free_state(st);
4407 int script_config_read(const char *cfgName)
4410 char line[1024],w1[1024],w2[1024];
4414 fp=fopen(cfgName,"r");
4416 ShowError("File not found: %s\n", cfgName);
4419 while(fgets(line, sizeof(line), fp))
4421 if(line[0] == '/' && line[1] == '/')
4423 i=sscanf(line,"%1023[^:]: %1023[^\r\n]",w1,w2);
4427 if(strcmpi(w1,"warn_func_mismatch_paramnum")==0) {
4428 script_config.warn_func_mismatch_paramnum = config_switch(w2);
4430 else if(strcmpi(w1,"check_cmdcount")==0) {
4431 script_config.check_cmdcount = config_switch(w2);
4433 else if(strcmpi(w1,"check_gotocount")==0) {
4434 script_config.check_gotocount = config_switch(w2);
4436 else if(strcmpi(w1,"input_min_value")==0) {
4437 script_config.input_min_value = config_switch(w2);
4439 else if(strcmpi(w1,"input_max_value")==0) {
4440 script_config.input_max_value = config_switch(w2);
4442 else if(strcmpi(w1,"warn_func_mismatch_argtypes")==0) {
4443 script_config.warn_func_mismatch_argtypes = config_switch(w2);
4445 else if(strcmpi(w1,"import")==0){
4446 script_config_read(w2);
4449 ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName);
4460 static int db_script_free_code_sub(DBKey key, DBData *data, va_list ap)
4462 struct script_code *code = static_cast<script_code *>(db_data2ptr(data));
4464 script_free_code(code);
4468 void script_run_autobonus(const char *autobonus, struct map_session_data *sd, unsigned int pos)
4470 struct script_code *script = (struct script_code *)strdb_get(autobonus_db, autobonus);
4475 ARR_FIND( 0, EQI_MAX, j, sd->equip_index[j] >= 0 && sd->inventory.u.items_inventory[sd->equip_index[j]].equip == pos );
4477 //Single item autobonus
4478 current_equip_item_index = sd->equip_index[j];
4479 current_equip_combo_pos = 0;
4482 current_equip_item_index = -1;
4483 current_equip_combo_pos = pos;
4485 run_script(script,0,sd->bl.id,0);
4489 void script_add_autobonus(const char *autobonus)
4491 if( strdb_get(autobonus_db, autobonus) == NULL )
4493 struct script_code *script = parse_script(autobonus, "autobonus", 0, 0);
4496 strdb_put(autobonus_db, autobonus, script);
4501 /// resets a temporary character array variable to given value
4502 void script_cleararray_pc(struct map_session_data* sd, const char* varname, void* value)
4504 struct script_array *sa = NULL;
4505 struct reg_db *src = NULL;
4506 unsigned int i, *list = NULL, size = 0;
4509 key = add_str(varname);
4511 if( !(src = script_array_src(NULL,sd,varname,NULL) ) )
4515 script_array_ensure_zero(NULL,sd,reference_uid(key,0), NULL);
4517 if( !(sa = static_cast<script_array *>(idb_get(src->arrays, key))) ) /* non-existent array, nothing to empty */
4521 list = script_array_cpy_list(sa);
4523 for(i = 0; i < size; i++) {
4524 set_reg(NULL,sd,reference_uid(key, list[i]),varname,value,NULL);
4529 /// sets a temporary character array variable element idx to given value
4530 /// @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.
4531 void script_setarray_pc(struct map_session_data* sd, const char* varname, uint32 idx, void* value, int* refcache)
4535 if( idx >= SCRIPT_MAX_ARRAYSIZE ) {
4536 ShowError("script_setarray_pc: Variable '%s' has invalid index '%u' (char_id=%d).\n", varname, idx, sd->status.char_id);
4540 key = ( refcache && refcache[0] ) ? refcache[0] : add_str(varname);
4542 set_reg(NULL,sd,reference_uid(key, idx),varname,value,NULL);
4545 // save to avoid repeated script->add_str calls
4551 * Clears persistent variables from memory
4553 int script_reg_destroy(DBKey key, DBData *data, va_list ap)
4555 struct script_reg_state *src;
4557 if( data->type != DB_DATA_PTR ) // got no need for those!
4560 src = static_cast<script_reg_state *>(db_data2ptr(data));
4563 struct script_reg_str *p = (struct script_reg_str *)src;
4568 ers_free(str_reg_ers,p);
4570 ers_free(num_reg_ers,(struct script_reg_num*)src);
4577 * Clears a single persistent variable
4579 void script_reg_destroy_single(struct map_session_data *sd, int64 reg, struct script_reg_state *data)
4581 i64db_remove(sd->regs.vars, reg);
4584 struct script_reg_str *p = (struct script_reg_str*)data;
4589 ers_free(str_reg_ers,p);
4591 ers_free(num_reg_ers,(struct script_reg_num*)data);
4595 unsigned int *script_array_cpy_list(struct script_array *sa)
4597 if( sa->size > generic_ui_array_size )
4598 script_generic_ui_array_expand(sa->size);
4599 memcpy(generic_ui_array, sa->members, sizeof(unsigned int)*sa->size);
4600 return generic_ui_array;
4603 void script_generic_ui_array_expand (unsigned int plus)
4605 generic_ui_array_size += plus + 100;
4606 RECREATE(generic_ui_array, unsigned int, generic_ui_array_size);
4609 int buildin_query_sql_sub(struct script_state *st, Sql *handle);
4611 #ifdef BETA_THREAD_TEST
4612 /* used to receive items the queryThread has already processed */
4613 int queryThread_timer(int tid, unsigned int tick, int id, intptr_t data) {
4617 EnterSpinLock(&queryThreadLock);
4619 for( i = 0; i < queryThreadData.count; i++ ) {
4620 struct queryThreadEntry *entry = queryThreadData.entry[i];
4627 run_script_main(entry->st);
4629 entry->st = NULL;/* empty entries */
4631 queryThreadData.entry[i] = NULL;
4636 /* cancel the repeating timer -- it'll re-create itself when necessary, dont need to remain looping */
4637 delete_timer(queryThreadData.timer, queryThread_timer);
4638 queryThreadData.timer = INVALID_TIMER;
4641 /* now lets clear the mess. */
4642 for( i = 0; i < queryThreadData.count; i++ ) {
4643 struct queryThreadEntry *entry = queryThreadData.entry[i];
4645 continue;/* entry on hold */
4648 memmove(&queryThreadData.entry[cursor], &queryThreadData.entry[i], sizeof(struct queryThreadEntry*));
4653 queryThreadData.count = cursor;
4655 LeaveSpinLock(&queryThreadLock);
4660 void queryThread_add(struct script_state *st, bool type) {
4662 struct queryThreadEntry* entry = NULL;
4664 EnterSpinLock(&queryThreadLock);
4666 if( queryThreadData.count++ != 0 )
4667 RECREATE(queryThreadData.entry, struct queryThreadEntry* , queryThreadData.count);
4669 idx = queryThreadData.count-1;
4671 CREATE(queryThreadData.entry[idx],struct queryThreadEntry,1);
4673 entry = queryThreadData.entry[idx];
4678 if( queryThreadData.timer == INVALID_TIMER ) { /* start the receiver timer */
4679 queryThreadData.timer = add_timer_interval(gettick() + 100, queryThread_timer, 0, 0, 100);
4682 LeaveSpinLock(&queryThreadLock);
4684 /* unlock the queryThread */
4685 racond_signal(queryThreadCond);
4687 /* adds a new log to the queue */
4688 void queryThread_log(char * entry, int length) {
4689 int idx = logThreadData.count;
4691 EnterSpinLock(&queryThreadLock);
4693 if( logThreadData.count++ != 0 )
4694 RECREATE(logThreadData.entry, char* , logThreadData.count);
4696 CREATE(logThreadData.entry[idx], char, length + 1 );
4697 safestrncpy(logThreadData.entry[idx], entry, length + 1 );
4699 LeaveSpinLock(&queryThreadLock);
4701 /* unlock the queryThread */
4702 racond_signal(queryThreadCond);
4705 /* queryThread_main */
4706 static void *queryThread_main(void *x) {
4707 Sql *queryThread_handle = Sql_Malloc();
4710 if ( SQL_ERROR == Sql_Connect(queryThread_handle, map_server_id, map_server_pw, map_server_ip, map_server_port, map_server_db) ){
4711 ShowError("Couldn't connect with uname='%s',passwd='%s',host='%s',port='%d',database='%s'\n",
4712 map_server_id, map_server_pw, map_server_ip, map_server_port, map_server_db);
4713 Sql_ShowDebug(queryThread_handle);
4714 Sql_Free(queryThread_handle);
4718 if( strlen(default_codepage) > 0 )
4719 if ( SQL_ERROR == Sql_SetEncoding(queryThread_handle, default_codepage) )
4720 Sql_ShowDebug(queryThread_handle);
4722 if( log_config.sql_logs ) {
4723 logmysql_handle = Sql_Malloc();
4725 if ( SQL_ERROR == Sql_Connect(logmysql_handle, log_db_id, log_db_pw, log_db_ip, log_db_port, log_db_db) ){
4726 ShowError("Couldn't connect with uname='%s',passwd='%s',host='%s',port='%d',database='%s'\n",
4727 log_db_id, log_db_pw, log_db_ip, log_db_port, log_db_db);
4728 Sql_ShowDebug(logmysql_handle);
4729 Sql_Free(logmysql_handle);
4733 if( strlen(default_codepage) > 0 )
4734 if ( SQL_ERROR == Sql_SetEncoding(logmysql_handle, default_codepage) )
4735 Sql_ShowDebug(logmysql_handle);
4740 if(queryThreadTerminate > 0)
4743 EnterSpinLock(&queryThreadLock);
4745 /* mess with queryThreadData within the lock */
4746 for( i = 0; i < queryThreadData.count; i++ ) {
4747 struct queryThreadEntry *entry = queryThreadData.entry[i];
4751 else if ( !entry->st || !entry->st->stack ) {
4752 entry->ok = true;/* dispose */
4756 buildin_query_sql_sub(entry->st, entry->type ? logmysql_handle : queryThread_handle);
4758 entry->ok = true;/* we're done with this */
4761 /* also check for any logs in need to be sent */
4762 if( log_config.sql_logs ) {
4763 for( i = 0; i < logThreadData.count; i++ ) {
4764 if( SQL_ERROR == Sql_Query(logmysql_handle, logThreadData.entry[i]) )
4765 Sql_ShowDebug(logmysql_handle);
4766 aFree(logThreadData.entry[i]);
4768 logThreadData.count = 0;
4771 LeaveSpinLock(&queryThreadLock);
4773 ramutex_lock( queryThreadMutex );
4774 racond_wait( queryThreadCond, queryThreadMutex, -1 );
4775 ramutex_unlock( queryThreadMutex );
4779 Sql_Free(queryThread_handle);
4781 if( log_config.sql_logs ) {
4782 Sql_Free(logmysql_handle);
4788 /*==========================================
4790 *------------------------------------------*/
4791 void do_final_script() {
4794 struct script_state *st;
4797 if (battle_config.etc_log)
4799 FILE *fp = fopen("hash_dump.txt","wt");
4801 int count[SCRIPT_HASH_SIZE];
4802 int count2[SCRIPT_HASH_SIZE]; // number of buckets with a certain number of items
4804 int min=INT_MAX,max=0,zero=0;
4808 ShowNotice("Dumping script str hash information to hash_dump.txt\n");
4809 memset(count, 0, sizeof(count));
4810 fprintf(fp,"num : hash : data_name\n");
4811 fprintf(fp,"---------------------------------------------------------------\n");
4812 for(i=LABEL_START; i<str_num; i++) {
4813 unsigned int h = calc_hash(get_str(i));
4814 fprintf(fp,"%04d : %4u : %s\n",i,h, get_str(i));
4817 fprintf(fp,"--------------------\n\n");
4818 memset(count2, 0, sizeof(count2));
4819 for(i=0; i<SCRIPT_HASH_SIZE; i++) {
4820 fprintf(fp," hash %3d = %d\n",i,count[i]);
4822 min = count[i]; // minimun count of collision
4824 max = count[i]; // maximun count of collision
4829 fprintf(fp,"\n--------------------\n items : buckets\n--------------------\n");
4830 for( i=min; i <= max; ++i ){
4831 fprintf(fp," %5d : %7d\n",i,count2[i]);
4832 mean += 1.0f*i*count2[i]/SCRIPT_HASH_SIZE; // Note: this will always result in <nr labels>/<nr buckets>
4834 for( i=min; i <= max; ++i ){
4836 if( n*2 >= SCRIPT_HASH_SIZE )
4838 if( SCRIPT_HASH_SIZE%2 == 0 && SCRIPT_HASH_SIZE/2 == n )
4839 median = (i+i+1)/2.0f;
4845 fprintf(fp,"--------------------\n min = %d, max = %d, zero = %d\n mean = %lf, median = %lf\n",min,max,zero,mean,median);
4853 db_destroy(scriptlabel_db);
4854 userfunc_db->destroy(userfunc_db, db_script_free_code_sub);
4855 autobonus_db->destroy(autobonus_db, db_script_free_code_sub);
4857 ers_destroy(array_ers);
4858 if (generic_ui_array)
4859 aFree(generic_ui_array);
4861 iter = db_iterator(st_db);
4862 for( st = static_cast<script_state *>(dbi_first(iter)); dbi_exists(iter); st = static_cast<script_state *>(dbi_next(iter)) )
4863 script_free_state(st);
4871 for( i = 0; i < atcmd_binding_count; i++ ) {
4872 aFree(atcmd_binding[i]);
4875 if( atcmd_binding_count != 0 )
4876 aFree(atcmd_binding);
4878 ers_destroy(st_ers);
4879 ers_destroy(stack_ers);
4882 #ifdef BETA_THREAD_TEST
4884 InterlockedIncrement(&queryThreadTerminate);
4885 racond_signal(queryThreadCond);
4886 rathread_wait(queryThread, NULL);
4888 // Destroy cond var and mutex.
4889 racond_destroy( queryThreadCond );
4890 ramutex_destroy( queryThreadMutex );
4892 /* Clear missing vars */
4893 for( i = 0; i < queryThreadData.count; i++ ) {
4894 aFree(queryThreadData.entry[i]);
4897 aFree(queryThreadData.entry);
4899 for( i = 0; i < logThreadData.count; i++ ) {
4900 aFree(logThreadData.entry[i]);
4903 aFree(logThreadData.entry);
4906 /*==========================================
4908 *------------------------------------------*/
4909 void do_init_script(void) {
4910 st_db = idb_alloc(DB_OPT_BASE);
4911 userfunc_db = strdb_alloc(DB_OPT_DUP_KEY,0);
4912 scriptlabel_db = strdb_alloc(DB_OPT_DUP_KEY,50);
4913 autobonus_db = strdb_alloc(DB_OPT_DUP_KEY,0);
4915 st_ers = ers_new(sizeof(struct script_state), "script.cpp::st_ers", ERS_CACHE_OPTIONS);
4916 stack_ers = ers_new(sizeof(struct script_stack), "script.cpp::script_stack", ERS_OPT_FLEX_CHUNK);
4917 array_ers = ers_new(sizeof(struct script_array), "script.cpp:array_ers", ERS_CLEAN_OPTIONS);
4919 ers_chunk_size(st_ers, 10);
4920 ers_chunk_size(stack_ers, 10);
4926 #ifdef BETA_THREAD_TEST
4927 CREATE(queryThreadData.entry, struct queryThreadEntry*, 1);
4928 queryThreadData.count = 0;
4929 CREATE(logThreadData.entry, char *, 1);
4930 logThreadData.count = 0;
4931 /* QueryThread Start */
4933 InitializeSpinLock(&queryThreadLock);
4935 queryThreadData.timer = INVALID_TIMER;
4936 queryThreadTerminate = 0;
4937 queryThreadMutex = ramutex_create();
4938 queryThreadCond = racond_create();
4940 queryThread = rathread_create(queryThread_main, NULL);
4942 if(queryThread == NULL){
4943 ShowFatalError("do_init_script: cannot spawn Query Thread.\n");
4947 add_timer_func_list(queryThread_timer, "queryThread_timer");
4951 void script_reload(void) {
4954 struct script_state *st;
4956 #ifdef BETA_THREAD_TEST
4957 /* we're reloading so any queries undergoing should be...exterminated. */
4958 EnterSpinLock(&queryThreadLock);
4960 for( i = 0; i < queryThreadData.count; i++ ) {
4961 aFree(queryThreadData.entry[i]);
4963 queryThreadData.count = 0;
4965 if( queryThreadData.timer != INVALID_TIMER ) {
4966 delete_timer(queryThreadData.timer, queryThread_timer);
4967 queryThreadData.timer = INVALID_TIMER;
4970 LeaveSpinLock(&queryThreadLock);
4973 userfunc_db->clear(userfunc_db, db_script_free_code_sub);
4974 db_clear(scriptlabel_db);
4976 // @commands (script based)
4978 for( i = 0; i < atcmd_binding_count; i++ ) {
4979 aFree(atcmd_binding[i]);
4982 if( atcmd_binding_count != 0 )
4983 aFree(atcmd_binding);
4985 atcmd_binding_count = 0;
4987 iter = db_iterator(st_db);
4988 for( st = static_cast<script_state *>(dbi_first(iter)); dbi_exists(iter); st = static_cast<script_state *>(dbi_next(iter)) )
4989 script_free_state(st);
4996 //-----------------------------------------------------------------------------
4997 // buildin functions
5000 #define BUILDIN_DEF(x,args) { buildin_ ## x , #x , args, NULL }
5001 #define BUILDIN_DEF2(x,x2,args) { buildin_ ## x , x2 , args, NULL }
5002 #define BUILDIN_DEF_DEPRECATED(x,args,deprecationdate) { buildin_ ## x , #x , args, deprecationdate }
5003 #define BUILDIN_DEF2_DEPRECATED(x,x2,args,deprecationdate) { buildin_ ## x , x2 , args, deprecationdate }
5004 #define BUILDIN_FUNC(x) int buildin_ ## x (struct script_state* st)
5006 /////////////////////////////////////////////////////////////////////
5010 /// Appends a message to the npc dialog.
5011 /// If a dialog doesn't exist yet, one is created.
5013 /// mes "<message>";
5017 if( !script_rid2sd(sd) )
5018 return SCRIPT_CMD_SUCCESS;
5020 if( !script_hasdata(st, 3) )
5021 {// only a single line detected in the script
5022 clif_scriptmes(sd, st->oid, script_getstr(st, 2));
5025 {// parse multiple lines as they exist
5028 for( i = 2; script_hasdata(st, i); i++ )
5030 // send the message to the client
5031 clif_scriptmes(sd, st->oid, script_getstr(st, i));
5035 st->mes_active = 1; // Invoking character has a NPC dialog box open.
5036 return SCRIPT_CMD_SUCCESS;
5039 /// Displays the button 'next' in the npc dialog.
5040 /// The dialog text is cleared and the script continues when the button is pressed.
5047 if( !script_rid2sd(sd) )
5048 return SCRIPT_CMD_SUCCESS;
5049 #ifdef SECURE_NPCTIMEOUT
5050 sd->npc_idle_type = NPCT_WAIT;
5053 clif_scriptnext(sd, st->oid);
5054 return SCRIPT_CMD_SUCCESS;
5057 /// Ends the script and displays the button 'close' on the npc dialog.
5058 /// The dialog is closed when the button is pressed.
5065 if( !script_rid2sd(sd) )
5066 return SCRIPT_CMD_SUCCESS;
5068 if( !st->mes_active ) {
5069 TBL_NPC* nd = map_id2nd(st->oid);
5070 st->state = END; // Keep backwards compatibility.
5071 ShowWarning("Incorrect use of 'close' command! (source:%s / path:%s)\n",nd?nd->name:"Unknown",nd?nd->path:"Unknown");
5077 clif_scriptclose(sd, st->oid);
5078 return SCRIPT_CMD_SUCCESS;
5081 /// Displays the button 'close' on the npc dialog.
5082 /// The dialog is closed and the script continues when the button is pressed.
5085 BUILDIN_FUNC(close2)
5089 if( !script_rid2sd(sd) )
5090 return SCRIPT_CMD_SUCCESS;
5094 if( st->mes_active )
5097 clif_scriptclose(sd, st->oid);
5098 return SCRIPT_CMD_SUCCESS;
5101 /// Counts the number of valid and total number of options in 'str'
5102 /// If max_count > 0 the counting stops when that valid option is reached
5103 /// total is incremented for each option (NULL is supported)
5104 static int menu_countoptions(const char* str, int max_count, int* total)
5110 total = &bogus_total;
5113 // initial empty options
5114 while( *str == ':' )
5119 // count menu options
5120 while( *str != '\0' )
5124 if( max_count == 0 )
5126 while( *str != ':' && *str != '\0' )
5128 while( *str == ':' )
5137 /// Displays a menu with options and goes to the target label.
5138 /// The script is stopped if cancel is pressed.
5139 /// Options with no text are not displayed in the client.
5141 /// Options can be grouped together, separated by the character ':' in the text:
5142 /// ex: menu "A:B:C",L_target;
5143 /// All these options go to the specified target label.
5145 /// The index of the selected option is put in the variable @menu.
5146 /// Indexes start with 1 and are consistent with grouped and empty options.
5147 /// ex: menu "A::B",-,"",L_Impossible,"C",-;
5148 /// // displays "A", "B" and "C", corresponding to indexes 1, 3 and 5
5150 /// NOTE: the client closes the npc dialog when cancel is pressed
5152 /// menu "<option_text>",<target_label>{,"<option_text>",<target_label>,...};
5159 if( !script_rid2sd(sd) )
5160 return SCRIPT_CMD_SUCCESS;
5162 #ifdef SECURE_NPCTIMEOUT
5163 sd->npc_idle_type = NPCT_MENU;
5166 // TODO detect multiple scripts waiting for input at the same time, and what to do when that happens
5167 if( sd->state.menu_or_input == 0 )
5169 struct StringBuf buf;
5171 if( script_lastdata(st) % 2 == 0 )
5172 {// argument count is not even (1st argument is at index 2)
5173 ShowError("buildin_menu: Illegal number of arguments (%d).\n", (script_lastdata(st) - 1));
5175 return SCRIPT_CMD_FAILURE;
5178 StringBuf_Init(&buf);
5180 for( i = 2; i < script_lastdata(st); i += 2 )
5182 struct script_data* data;
5184 text = script_getstr(st, i);
5187 data = script_getdata(st, i+1);
5188 if( !data_islabel(data) )
5190 StringBuf_Destroy(&buf);
5191 ShowError("buildin_menu: Argument #%d (from 1) is not a label or label not found.\n", i);
5192 script_reportdata(data);
5194 return SCRIPT_CMD_FAILURE;
5198 if( text[0] == '\0' )
5199 continue;// empty string, ignore
5200 if( sd->npc_menu > 0 )
5201 StringBuf_AppendStr(&buf, ":");
5202 StringBuf_AppendStr(&buf, text);
5203 sd->npc_menu += menu_countoptions(text, 0, NULL);
5205 st->state = RERUNLINE;
5206 sd->state.menu_or_input = 1;
5209 * menus beyond this length crash the client (see bugreport:6402)
5211 if( StringBuf_Length(&buf) >= 2047 ) {
5212 struct npc_data * nd = map_id2nd(st->oid);
5214 CREATE(menu, char, 2048);
5215 safestrncpy(menu, StringBuf_Value(&buf), 2047);
5216 ShowWarning("buildin_menu: NPC Menu too long! (source:%s / length:%d)\n",nd?nd->name:"Unknown",StringBuf_Length(&buf));
5217 clif_scriptmenu(sd, st->oid, menu);
5220 clif_scriptmenu(sd, st->oid, StringBuf_Value(&buf));
5222 StringBuf_Destroy(&buf);
5224 if( sd->npc_menu >= 0xff )
5225 {// 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
5226 ShowWarning("buildin_menu: Too many options specified (current=%d, max=254).\n", sd->npc_menu);
5227 script_reportsrc(st);
5230 else if( sd->npc_menu == 0xff )
5231 {// Cancel was pressed
5232 sd->state.menu_or_input = 0;
5236 {// goto target label
5239 sd->state.menu_or_input = 0;
5240 if( sd->npc_menu <= 0 )
5242 ShowDebug("buildin_menu: Unexpected selection (%d)\n", sd->npc_menu);
5244 return SCRIPT_CMD_FAILURE;
5248 for( i = 2; i < script_lastdata(st); i += 2 )
5250 text = script_getstr(st, i);
5251 sd->npc_menu -= menu_countoptions(text, sd->npc_menu, &menu);
5252 if( sd->npc_menu <= 0 )
5253 break;// entry found
5255 if( sd->npc_menu > 0 )
5256 {// Invalid selection
5257 ShowDebug("buildin_menu: Selection is out of range (%d pairs are missing?) - please report this\n", sd->npc_menu);
5259 return SCRIPT_CMD_FAILURE;
5261 if( !data_islabel(script_getdata(st, i + 1)) )
5262 {// TODO remove this temporary crash-prevention code (fallback for multiple scripts requesting user input)
5263 ShowError("buildin_menu: Unexpected data in label argument\n");
5264 script_reportdata(script_getdata(st, i + 1));
5266 return SCRIPT_CMD_FAILURE;
5268 pc_setreg(sd, add_str("@menu"), menu);
5269 st->pos = script_getnum(st, i + 1);
5272 return SCRIPT_CMD_SUCCESS;
5275 /// Displays a menu with options and returns the selected option.
5276 /// Behaves like 'menu' without the target labels.
5278 /// select(<option_text>{,<option_text>,...}) -> <selected_option>
5281 BUILDIN_FUNC(select)
5287 if( !script_rid2sd(sd) )
5288 return SCRIPT_CMD_SUCCESS;
5290 #ifdef SECURE_NPCTIMEOUT
5291 sd->npc_idle_type = NPCT_MENU;
5294 if( sd->state.menu_or_input == 0 ) {
5295 struct StringBuf buf;
5297 StringBuf_Init(&buf);
5299 for( i = 2; i <= script_lastdata(st); ++i ) {
5300 text = script_getstr(st, i);
5302 if( sd->npc_menu > 0 )
5303 StringBuf_AppendStr(&buf, ":");
5305 StringBuf_AppendStr(&buf, text);
5306 sd->npc_menu += menu_countoptions(text, 0, NULL);
5309 st->state = RERUNLINE;
5310 sd->state.menu_or_input = 1;
5313 * menus beyond this length crash the client (see bugreport:6402)
5315 if( StringBuf_Length(&buf) >= 2047 ) {
5316 struct npc_data * nd = map_id2nd(st->oid);
5318 CREATE(menu, char, 2048);
5319 safestrncpy(menu, StringBuf_Value(&buf), 2047);
5320 ShowWarning("buildin_select: NPC Menu too long! (source:%s / length:%d)\n",nd?nd->name:"Unknown",StringBuf_Length(&buf));
5321 clif_scriptmenu(sd, st->oid, menu);
5324 clif_scriptmenu(sd, st->oid, StringBuf_Value(&buf));
5325 StringBuf_Destroy(&buf);
5327 if( sd->npc_menu >= 0xff ) {
5328 ShowWarning("buildin_select: Too many options specified (current=%d, max=254).\n", sd->npc_menu);
5329 script_reportsrc(st);
5331 } else if( sd->npc_menu == 0xff ) {// Cancel was pressed
5332 sd->state.menu_or_input = 0;
5334 } else {// return selected option
5337 sd->state.menu_or_input = 0;
5338 for( i = 2; i <= script_lastdata(st); ++i ) {
5339 text = script_getstr(st, i);
5340 sd->npc_menu -= menu_countoptions(text, sd->npc_menu, &menu);
5341 if( sd->npc_menu <= 0 )
5342 break;// entry found
5344 pc_setreg(sd, add_str("@menu"), menu);
5345 script_pushint(st, menu);
5348 return SCRIPT_CMD_SUCCESS;
5351 /// Displays a menu with options and returns the selected option.
5352 /// Behaves like 'menu' without the target labels, except when cancel is
5354 /// When cancel is pressed, the script continues and 255 is returned.
5356 /// prompt(<option_text>{,<option_text>,...}) -> <selected_option>
5359 BUILDIN_FUNC(prompt)
5365 if( !script_rid2sd(sd) )
5366 return SCRIPT_CMD_SUCCESS;
5368 #ifdef SECURE_NPCTIMEOUT
5369 sd->npc_idle_type = NPCT_MENU;
5372 if( sd->state.menu_or_input == 0 )
5374 struct StringBuf buf;
5376 StringBuf_Init(&buf);
5378 for( i = 2; i <= script_lastdata(st); ++i )
5380 text = script_getstr(st, i);
5381 if( sd->npc_menu > 0 )
5382 StringBuf_AppendStr(&buf, ":");
5383 StringBuf_AppendStr(&buf, text);
5384 sd->npc_menu += menu_countoptions(text, 0, NULL);
5387 st->state = RERUNLINE;
5388 sd->state.menu_or_input = 1;
5391 * menus beyond this length crash the client (see bugreport:6402)
5393 if( StringBuf_Length(&buf) >= 2047 ) {
5394 struct npc_data * nd = map_id2nd(st->oid);
5396 CREATE(menu, char, 2048);
5397 safestrncpy(menu, StringBuf_Value(&buf), 2047);
5398 ShowWarning("buildin_prompt: NPC Menu too long! (source:%s / length:%d)\n",nd?nd->name:"Unknown",StringBuf_Length(&buf));
5399 clif_scriptmenu(sd, st->oid, menu);
5402 clif_scriptmenu(sd, st->oid, StringBuf_Value(&buf));
5403 StringBuf_Destroy(&buf);
5405 if( sd->npc_menu >= 0xff )
5407 ShowWarning("buildin_prompt: Too many options specified (current=%d, max=254).\n", sd->npc_menu);
5408 script_reportsrc(st);
5411 else if( sd->npc_menu == 0xff )
5412 {// Cancel was pressed
5413 sd->state.menu_or_input = 0;
5414 pc_setreg(sd, add_str("@menu"), 0xff);
5415 script_pushint(st, 0xff);
5419 {// return selected option
5422 sd->state.menu_or_input = 0;
5423 for( i = 2; i <= script_lastdata(st); ++i )
5425 text = script_getstr(st, i);
5426 sd->npc_menu -= menu_countoptions(text, sd->npc_menu, &menu);
5427 if( sd->npc_menu <= 0 )
5428 break;// entry found
5430 pc_setreg(sd, add_str("@menu"), menu);
5431 script_pushint(st, menu);
5434 return SCRIPT_CMD_SUCCESS;
5437 /////////////////////////////////////////////////////////////////////
5441 /// Jumps to the target script label.
5446 if( !data_islabel(script_getdata(st,2)) )
5448 ShowError("buildin_goto: Not a label\n");
5449 script_reportdata(script_getdata(st,2));
5451 return SCRIPT_CMD_FAILURE;
5454 st->pos = script_getnum(st,2);
5456 return SCRIPT_CMD_SUCCESS;
5459 /*==========================================
5460 * user-defined function call
5461 *------------------------------------------*/
5462 BUILDIN_FUNC(callfunc)
5465 struct script_retinfo* ri;
5466 struct script_code* scr;
5467 const char* str = script_getstr(st,2);
5468 struct reg_db *ref = NULL;
5470 scr = (struct script_code*)strdb_get(userfunc_db, str);
5472 ShowError("buildin_callfunc: Function not found! [%s]\n", str);
5474 return SCRIPT_CMD_FAILURE;
5477 ref = (struct reg_db *)aCalloc(sizeof(struct reg_db), 2);
5478 ref[0].vars = st->stack->scope.vars;
5479 if (!st->stack->scope.arrays)
5480 st->stack->scope.arrays = idb_alloc(DB_OPT_BASE); // TODO: Can this happen? when?
5481 ref[0].arrays = st->stack->scope.arrays;
5482 ref[1].vars = st->script->local.vars;
5483 if (!st->script->local.arrays)
5484 st->script->local.arrays = idb_alloc(DB_OPT_BASE); // TODO: Can this happen? when?
5485 ref[1].arrays = st->script->local.arrays;
5487 for(i = st->start+3, j = 0; i < st->end; i++, j++) {
5488 struct script_data* data = push_copy(st->stack,i);
5490 if (data_isreference(data) && !data->ref) {
5491 const char* name = reference_getname(data);
5494 data->ref = (name[1] == '@' ? &ref[0] : &ref[1]);
5498 CREATE(ri, struct script_retinfo, 1);
5499 ri->script = st->script; // script code
5500 ri->scope.vars = st->stack->scope.vars; // scope variables
5501 ri->scope.arrays = st->stack->scope.arrays; // scope arrays
5502 ri->pos = st->pos; // script location
5503 ri->nargs = j; // argument count
5504 ri->defsp = st->stack->defsp; // default stack pointer
5505 push_retinfo(st->stack, ri, ref);
5509 st->stack->defsp = st->stack->sp;
5511 st->stack->scope.vars = i64db_alloc(DB_OPT_RELEASE_DATA);
5512 st->stack->scope.arrays = idb_alloc(DB_OPT_BASE);
5514 if (!st->script->local.vars)
5515 st->script->local.vars = i64db_alloc(DB_OPT_RELEASE_DATA);
5517 return SCRIPT_CMD_SUCCESS;
5520 /*==========================================
5522 *------------------------------------------*/
5523 BUILDIN_FUNC(callsub)
5526 struct script_retinfo* ri;
5527 int pos = script_getnum(st,2);
5528 struct reg_db *ref = NULL;
5530 if( !data_islabel(script_getdata(st,2)) && !data_isfunclabel(script_getdata(st,2)) ) {
5531 ShowError("buildin_callsub: Argument is not a label\n");
5532 script_reportdata(script_getdata(st,2));
5534 return SCRIPT_CMD_FAILURE;
5537 ref = (struct reg_db *)aCalloc(sizeof(struct reg_db), 1);
5538 ref[0].vars = st->stack->scope.vars;
5539 if (!st->stack->scope.arrays)
5540 st->stack->scope.arrays = idb_alloc(DB_OPT_BASE); // TODO: Can this happen? when?
5541 ref[0].arrays = st->stack->scope.arrays;
5543 for(i = st->start+3, j = 0; i < st->end; i++, j++) {
5544 struct script_data* data = push_copy(st->stack,i);
5546 if (data_isreference(data) && !data->ref) {
5547 const char* name = reference_getname(data);
5549 if (name[0] == '.' && name[1] == '@')
5550 data->ref = &ref[0];
5554 CREATE(ri, struct script_retinfo, 1);
5555 ri->script = st->script; // script code
5556 ri->scope.vars = st->stack->scope.vars; // scope variables
5557 ri->scope.arrays = st->stack->scope.arrays; // scope arrays
5558 ri->pos = st->pos; // script location
5559 ri->nargs = j; // argument count
5560 ri->defsp = st->stack->defsp; // default stack pointer
5561 push_retinfo(st->stack, ri, ref);
5564 st->stack->defsp = st->stack->sp;
5566 st->stack->scope.vars = i64db_alloc(DB_OPT_RELEASE_DATA);
5567 st->stack->scope.arrays = idb_alloc(DB_OPT_BASE);
5569 return SCRIPT_CMD_SUCCESS;
5572 /// Retrieves an argument provided to callfunc/callsub.
5573 /// If the argument doesn't exist
5575 /// getarg(<index>{,<default_value>}) -> <value>
5576 BUILDIN_FUNC(getarg)
5578 struct script_retinfo* ri;
5581 if( st->stack->defsp < 1 || st->stack->stack_data[st->stack->defsp - 1].type != C_RETINFO )
5583 ShowError("buildin_getarg: No callfunc or callsub!\n");
5585 return SCRIPT_CMD_FAILURE;
5587 ri = st->stack->stack_data[st->stack->defsp - 1].u.ri;
5589 idx = script_getnum(st,2);
5591 if( idx >= 0 && idx < ri->nargs )
5592 push_copy(st->stack, st->stack->defsp - 1 - ri->nargs + idx);
5593 else if( script_hasdata(st,3) )
5594 script_pushcopy(st, 3);
5597 ShowError("buildin_getarg: Index (idx=%d) out of range (nargs=%d) and no default value found\n", idx, ri->nargs);
5599 return SCRIPT_CMD_FAILURE;
5601 return SCRIPT_CMD_SUCCESS;
5604 /// Returns from the current function, optionaly returning a value from the functions.
5605 /// Don't use outside script functions.
5609 BUILDIN_FUNC(return)
5611 if( script_hasdata(st,2) )
5613 struct script_data* data;
5614 script_pushcopy(st, 2);
5615 data = script_getdatatop(st, -1);
5616 if( data_isreference(data) ) {
5617 const char* name = reference_getname(data);
5618 if( name[0] == '.' && name[1] == '@' ) { // scope variable
5619 if( !data->ref || data->ref->vars == st->stack->scope.vars )
5620 get_val(st, data); // current scope, convert to value
5621 if( data->ref && data->ref->vars == st->stack->stack_data[st->stack->defsp-1].u.ri->scope.vars )
5622 data->ref = NULL; // Reference to the parent scope, remove reference pointer
5630 st->state = RETFUNC;
5631 return SCRIPT_CMD_SUCCESS;
5634 /// Returns a random number from 0 to <range>-1.
5635 /// Or returns a random number from <min> to <max>.
5636 /// If <min> is greater than <max>, their numbers are switched.
5637 /// rand(<range>) -> <int>
5638 /// rand(<min>,<max>) -> <int>
5644 if( script_hasdata(st,3) )
5646 int max = script_getnum(st,3);
5647 min = script_getnum(st,2);
5650 range = max - min + 1;
5655 range = script_getnum(st,2);
5658 script_pushint(st, min);
5660 script_pushint(st, rnd()%range + min);
5662 return SCRIPT_CMD_SUCCESS;
5665 /*==========================================
5666 * Warp sd to str,x,y or Random or SavePoint/Save
5667 *------------------------------------------*/
5673 struct map_session_data* sd;
5675 if(!script_charid2sd(5, sd))
5676 return SCRIPT_CMD_SUCCESS;
5678 str = script_getstr(st,2);
5679 x = script_getnum(st,3);
5680 y = script_getnum(st,4);
5682 if(strcmp(str,"Random")==0)
5683 ret = pc_randomwarp(sd,CLR_TELEPORT);
5684 else if(strcmp(str,"SavePoint")==0 || strcmp(str,"Save")==0)
5685 ret = pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
5687 ret = pc_setpos(sd,mapindex_name2id(str),x,y,CLR_OUTSIGHT);
5690 ShowError("buildin_warp: moving player '%s' to \"%s\",%d,%d failed.\n", sd->status.name, str, x, y);
5691 return SCRIPT_CMD_FAILURE;
5694 return SCRIPT_CMD_SUCCESS;
5696 /*==========================================
5697 * Warp a specified area
5698 *------------------------------------------*/
5699 static int buildin_areawarp_sub(struct block_list *bl,va_list ap)
5704 index = va_arg(ap,unsigned int);
5705 x2 = va_arg(ap,int);
5706 y2 = va_arg(ap,int);
5707 x3 = va_arg(ap,int);
5708 y3 = va_arg(ap,int);
5711 pc_randomwarp((TBL_PC *)bl,CLR_TELEPORT);
5713 int max, tx, ty, j = 0;
5716 m = map_mapindex2mapid(index);
5718 // choose a suitable max number of attempts
5719 if( (max = (y3-y2+1)*(x3-x2+1)*3) > 1000 )
5722 // find a suitable map cell
5724 tx = rnd()%(x3-x2+1)+x2;
5725 ty = rnd()%(y3-y2+1)+y2;
5727 } while( map_getcell(m,tx,ty,CELL_CHKNOPASS) && j < max );
5729 pc_setpos((TBL_PC *)bl,index,tx,ty,CLR_OUTSIGHT);
5732 pc_setpos((TBL_PC *)bl,index,x2,y2,CLR_OUTSIGHT);
5736 BUILDIN_FUNC(areawarp)
5738 int16 m, x0,y0,x1,y1, x2,y2,x3=0,y3=0;
5741 const char *mapname;
5743 mapname = script_getstr(st,2);
5744 x0 = script_getnum(st,3);
5745 y0 = script_getnum(st,4);
5746 x1 = script_getnum(st,5);
5747 y1 = script_getnum(st,6);
5748 str = script_getstr(st,7);
5749 x2 = script_getnum(st,8);
5750 y2 = script_getnum(st,9);
5752 if( script_hasdata(st,10) && script_hasdata(st,11) ) { // Warp area to area
5753 if( (x3 = script_getnum(st,10)) < 0 || (y3 = script_getnum(st,11)) < 0 ){
5756 } else if( x3 && y3 ) {
5757 // normalize x3/y3 coordinates
5758 if( x3 < x2 ) SWAP(x3,x2);
5759 if( y3 < y2 ) SWAP(y3,y2);
5763 if( (m = map_mapname2mapid(mapname)) < 0 )
5764 return SCRIPT_CMD_FAILURE;
5766 if( strcmp(str,"Random") == 0 )
5768 else if( !(index=mapindex_name2id(str)) )
5769 return SCRIPT_CMD_FAILURE;
5771 map_foreachinallarea(buildin_areawarp_sub, m,x0,y0,x1,y1, BL_PC, index,x2,y2,x3,y3);
5772 return SCRIPT_CMD_SUCCESS;
5775 /*==========================================
5776 * areapercentheal <map>,<x1>,<y1>,<x2>,<y2>,<hp>,<sp>
5777 *------------------------------------------*/
5778 static int buildin_areapercentheal_sub(struct block_list *bl,va_list ap)
5781 hp = va_arg(ap, int);
5782 sp = va_arg(ap, int);
5783 pc_percentheal((TBL_PC *)bl,hp,sp);
5787 BUILDIN_FUNC(areapercentheal)
5790 const char *mapname;
5793 mapname=script_getstr(st,2);
5794 x0=script_getnum(st,3);
5795 y0=script_getnum(st,4);
5796 x1=script_getnum(st,5);
5797 y1=script_getnum(st,6);
5798 hp=script_getnum(st,7);
5799 sp=script_getnum(st,8);
5801 if( (m=map_mapname2mapid(mapname))< 0)
5802 return SCRIPT_CMD_FAILURE;
5804 map_foreachinallarea(buildin_areapercentheal_sub,m,x0,y0,x1,y1,BL_PC,hp,sp);
5805 return SCRIPT_CMD_SUCCESS;
5808 /*==========================================
5809 * Warpparty - [Fredzilla] [Paradox924X]
5810 * Syntax: warpparty "to_mapname",x,y,Party_ID,{<"from_mapname">,<range x>,<range y>};
5811 * If 'from_mapname' is specified, only the party members on that map will be warped
5812 *------------------------------------------*/
5813 BUILDIN_FUNC(warpparty)
5817 struct party_data* p;
5818 int type, mapindex = 0, m = -1, i, rx = 0, ry = 0;
5820 const char* str = script_getstr(st,2);
5821 int x = script_getnum(st,3);
5822 int y = script_getnum(st,4);
5823 int p_id = script_getnum(st,5);
5824 const char* str2 = NULL;
5825 if ( script_hasdata(st,6) )
5826 str2 = script_getstr(st,6);
5827 if (script_hasdata(st, 7))
5828 rx = script_getnum(st, 7);
5829 if (script_hasdata(st, 8))
5830 ry = script_getnum(st, 8);
5832 p = party_search(p_id);
5834 return SCRIPT_CMD_SUCCESS;
5836 type = ( strcmp(str,"Random")==0 ) ? 0
5837 : ( strcmp(str,"SavePointAll")==0 ) ? 1
5838 : ( strcmp(str,"SavePoint")==0 ) ? 2
5839 : ( strcmp(str,"Leader")==0 ) ? 3
5845 for(i = 0; i < MAX_PARTY && !p->party.member[i].leader; i++);
5846 if (i == MAX_PARTY || !p->data[i].sd) //Leader not found / not online
5847 return SCRIPT_CMD_FAILURE;
5848 pl_sd = p->data[i].sd;
5849 mapindex = pl_sd->mapindex;
5850 m = map_mapindex2mapid(mapindex);
5855 mapindex = mapindex_name2id(str);
5856 if (!mapindex) {// Invalid map
5857 return SCRIPT_CMD_FAILURE;
5859 m = map_mapindex2mapid(mapindex);
5862 //"SavePoint" uses save point of the currently attached player
5863 if ( !script_rid2sd(sd) )
5864 return SCRIPT_CMD_SUCCESS;
5868 for (i = 0; i < MAX_PARTY; i++)
5870 if( !(pl_sd = p->data[i].sd) || pl_sd->status.party_id != p_id )
5873 if( str2 && strcmp(str2, map[pl_sd->bl.m].name) != 0 )
5876 if( pc_isdead(pl_sd) )
5882 if(!map[pl_sd->bl.m].flag.nowarp)
5883 pc_randomwarp(pl_sd,CLR_TELEPORT);
5885 case 1: // SavePointAll
5886 if(!map[pl_sd->bl.m].flag.noreturn)
5887 pc_setpos(pl_sd,pl_sd->status.save_point.map,pl_sd->status.save_point.x,pl_sd->status.save_point.y,CLR_TELEPORT);
5889 case 2: // SavePoint
5890 if(!map[pl_sd->bl.m].flag.noreturn)
5891 pc_setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
5894 if (p->party.member[i].leader)
5898 int x1 = x + rx, y1 = y + ry,
5899 x0 = x - rx, y0 = y - ry;
5900 uint8 attempts = 10;
5903 x = x0 + rnd()%(x1 - x0 + 1);
5904 y = y0 + rnd()%(y1 - y0 + 1);
5905 } while ((--attempts) > 0 && !map_getcell(m, x, y, CELL_CHKPASS));
5908 if(!map[pl_sd->bl.m].flag.noreturn && !map[pl_sd->bl.m].flag.nowarp && pc_job_can_entermap((enum e_job)pl_sd->status.class_, m, pl_sd->group_level))
5909 pc_setpos(pl_sd,mapindex,x,y,CLR_TELEPORT);
5914 return SCRIPT_CMD_SUCCESS;
5917 /*==========================================
5918 * Warpguild - [Fredzilla]
5919 * Syntax: warpguild "mapname",x,y,Guild_ID;
5920 *------------------------------------------*/
5921 BUILDIN_FUNC(warpguild)
5926 struct s_mapiterator* iter;
5927 int type, mapindex = 0, m = -1;
5929 const char* str = script_getstr(st,2);
5930 int x = script_getnum(st,3);
5931 int y = script_getnum(st,4);
5932 int gid = script_getnum(st,5);
5934 g = guild_search(gid);
5936 return SCRIPT_CMD_SUCCESS;
5938 type = ( strcmp(str,"Random")==0 ) ? 0
5939 : ( strcmp(str,"SavePointAll")==0 ) ? 1
5940 : ( strcmp(str,"SavePoint")==0 ) ? 2
5943 if( type == 2 && !script_rid2sd(sd) )
5944 {// "SavePoint" uses save point of the currently attached player
5945 return SCRIPT_CMD_SUCCESS;
5950 mapindex = mapindex_name2id(str);
5952 return SCRIPT_CMD_FAILURE;
5953 m = map_mapindex2mapid(mapindex);
5957 iter = mapit_getallusers();
5958 for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
5960 if( pl_sd->status.guild_id != gid )
5966 if(!map[pl_sd->bl.m].flag.nowarp)
5967 pc_randomwarp(pl_sd,CLR_TELEPORT);
5969 case 1: // SavePointAll
5970 if(!map[pl_sd->bl.m].flag.noreturn)
5971 pc_setpos(pl_sd,pl_sd->status.save_point.map,pl_sd->status.save_point.x,pl_sd->status.save_point.y,CLR_TELEPORT);
5973 case 2: // SavePoint
5974 if(!map[pl_sd->bl.m].flag.noreturn)
5975 pc_setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
5978 if(!map[pl_sd->bl.m].flag.noreturn && !map[pl_sd->bl.m].flag.nowarp && pc_job_can_entermap((enum e_job)pl_sd->status.class_, m, pl_sd->group_level))
5979 pc_setpos(pl_sd,mapindex,x,y,CLR_TELEPORT);
5985 return SCRIPT_CMD_SUCCESS;
5988 /*==========================================
5989 * Force Heal a player (hp and sp)
5990 *------------------------------------------*/
5996 if (!script_charid2sd(4,sd))
5997 return SCRIPT_CMD_SUCCESS;
5999 hp=script_getnum(st,2);
6000 sp=script_getnum(st,3);
6001 status_heal(&sd->bl, hp, sp, 1);
6002 return SCRIPT_CMD_SUCCESS;
6005 /*==========================================
6006 * Heal a player by item (get vit bonus etc)
6007 *------------------------------------------*/
6008 BUILDIN_FUNC(itemheal)
6013 hp=script_getnum(st,2);
6014 sp=script_getnum(st,3);
6016 if(potion_flag==1) {
6019 return SCRIPT_CMD_SUCCESS;
6022 if (!script_charid2sd(4,sd))
6023 return SCRIPT_CMD_SUCCESS;
6025 pc_itemheal(sd,sd->itemid,hp,sp);
6026 return SCRIPT_CMD_SUCCESS;
6029 /*==========================================
6031 *------------------------------------------*/
6032 BUILDIN_FUNC(percentheal)
6037 hp=script_getnum(st,2);
6038 sp=script_getnum(st,3);
6040 if(potion_flag==1) {
6043 return SCRIPT_CMD_SUCCESS;
6046 if (!script_charid2sd(4,sd))
6047 return SCRIPT_CMD_SUCCESS;
6050 if( sd->sc.data[SC_EXTREMITYFIST2] )
6054 if (sd->sc.data[SC_NORECOVER_STATE]) {
6059 if (sd->sc.data[SC_BITESCAR])
6062 pc_percentheal(sd,hp,sp);
6063 return SCRIPT_CMD_SUCCESS;
6066 /*==========================================
6068 *------------------------------------------*/
6069 BUILDIN_FUNC(jobchange)
6073 job=script_getnum(st,2);
6074 if( script_hasdata(st,3) )
6075 upper=script_getnum(st,3);
6077 if (pcdb_checkid(job))
6081 if (!script_charid2sd(4,sd))
6082 return SCRIPT_CMD_SUCCESS;
6084 pc_jobchange(sd, job, upper);
6087 return SCRIPT_CMD_SUCCESS;
6090 /*==========================================
6092 *------------------------------------------*/
6093 BUILDIN_FUNC(jobname)
6095 int class_=script_getnum(st,2);
6096 script_pushconststr(st, (char*)job_name(class_));
6097 return SCRIPT_CMD_SUCCESS;
6100 /// Get input from the player.
6101 /// For numeric inputs the value is capped to the range [min,max]. Returns 1 if
6102 /// the value was higher than 'max', -1 if lower than 'min' and 0 otherwise.
6103 /// For string inputs it returns 1 if the string was longer than 'max', -1 is
6104 /// shorter than 'min' and 0 otherwise.
6106 /// input(<var>{,<min>{,<max>}}) -> <int>
6110 struct script_data* data;
6116 if( !script_rid2sd(sd) )
6117 return SCRIPT_CMD_SUCCESS;
6119 data = script_getdata(st,2);
6120 if( !data_isreference(data) ){
6121 ShowError("script:input: not a variable\n");
6122 script_reportdata(data);
6124 return SCRIPT_CMD_FAILURE;
6126 uid = reference_getuid(data);
6127 name = reference_getname(data);
6128 min = (script_hasdata(st,3) ? script_getnum(st,3) : script_config.input_min_value);
6129 max = (script_hasdata(st,4) ? script_getnum(st,4) : script_config.input_max_value);
6131 #ifdef SECURE_NPCTIMEOUT
6132 sd->npc_idle_type = NPCT_WAIT;
6135 if( !sd->state.menu_or_input )
6136 { // first invocation, display npc input box
6137 sd->state.menu_or_input = 1;
6138 st->state = RERUNLINE;
6139 if( is_string_variable(name) )
6140 clif_scriptinputstr(sd,st->oid);
6142 clif_scriptinput(sd,st->oid);
6145 { // take received text/value and store it in the designated variable
6146 sd->state.menu_or_input = 0;
6147 if( is_string_variable(name) )
6149 int len = (int)strlen(sd->npc_str);
6150 set_reg(st, sd, uid, name, (void*)sd->npc_str, script_getref(st,2));
6151 script_pushint(st, (len > max ? 1 : len < min ? -1 : 0));
6155 int amount = sd->npc_amount;
6156 set_reg(st, sd, uid, name, (void*)__64BPRTSIZE(cap_value(amount,min,max)), script_getref(st,2));
6157 script_pushint(st, (amount > max ? 1 : amount < min ? -1 : 0));
6161 return SCRIPT_CMD_SUCCESS;
6164 // declare the copyarray method here for future reference
6165 BUILDIN_FUNC(copyarray);
6167 /// Sets the value of a variable.
6168 /// The value is converted to the type of the variable.
6170 /// set(<variable>,<value>{,<charid>})
6174 struct script_data* data;
6175 //struct script_data* datavalue;
6178 const char* name, *command = script_getfuncname(st);
6181 data = script_getdata(st,2);
6182 //datavalue = script_getdata(st,3);
6183 if( !data_isreference(data) )
6185 ShowError("script:set: not a variable\n");
6186 script_reportdata(script_getdata(st,2));
6188 return SCRIPT_CMD_FAILURE;
6191 num = reference_getuid(data);
6192 name = reference_getname(data);
6195 if (!strcmp(command, "setr"))
6198 if (not_server_variable(prefix) && !script_charid2sd(pos,sd)) {
6199 ShowError("buildin_set: No player attached for player variable '%s'\n", name);
6200 return SCRIPT_CMD_FAILURE;
6204 if( data_isreference(datavalue) )
6205 {// the value being referenced is a variable
6206 const char* namevalue = reference_getname(datavalue);
6208 if( !not_array_variable(*namevalue) )
6209 {// array variable being copied into another array variable
6210 if( sd == NULL && not_server_variable(*namevalue) && !(sd = script_rid2sd(st)) )
6211 {// player must be attached in order to copy a player variable
6212 ShowError("script:set: no player attached for player variable '%s'\n", namevalue);
6213 return SCRIPT_CMD_SUCCESS;
6216 if( is_string_variable(namevalue) != is_string_variable(name) )
6217 {// non-matching array value types
6218 ShowWarning("script:set: two array variables do not match in type.\n");
6219 return SCRIPT_CMD_SUCCESS;
6222 // push the maximum number of array values to the stack
6223 push_val(st->stack, C_INT, SCRIPT_MAX_ARRAYSIZE);
6225 // call the copy array method directly
6226 return buildin_copyarray(st);
6231 if( !strcmp(command, "setr") && script_hasdata(st, 4) ) { // Optional argument used by post-increment/post-decrement constructs to return the previous value
6232 if( is_string_variable(name) )
6233 script_pushstrcopy(st,script_getstr(st, 4));
6235 script_pushint(st,script_getnum(st, 4));
6236 } else // Return a copy of the variable reference
6237 script_pushcopy(st, 2);
6239 if( is_string_variable(name) )
6240 set_reg(st,sd,num,name,(void*)script_getstr(st,3),script_getref(st,2));
6242 set_reg(st,sd,num,name,(void*)__64BPRTSIZE(script_getnum(st,3)),script_getref(st,2));
6244 return SCRIPT_CMD_SUCCESS;
6247 /////////////////////////////////////////////////////////////////////
6251 /// Sets values of an array, from the starting index.
6252 /// ex: setarray arr[1],1,2,3;
6254 /// setarray <array variable>,<value1>{,<value2>...};
6255 BUILDIN_FUNC(setarray)
6257 struct script_data* data;
6265 data = script_getdata(st, 2);
6266 if( !data_isreference(data) )
6268 ShowError("script:setarray: not a variable\n");
6269 script_reportdata(data);
6271 return SCRIPT_CMD_FAILURE;// not a variable
6274 id = reference_getid(data);
6275 start = reference_getindex(data);
6276 name = reference_getname(data);
6278 if( not_server_variable(*name) )
6280 if( !script_rid2sd(sd) )
6281 return SCRIPT_CMD_SUCCESS;// no player attached
6284 end = start + script_lastdata(st) - 2;
6285 if( end > SCRIPT_MAX_ARRAYSIZE )
6286 end = SCRIPT_MAX_ARRAYSIZE;
6288 if( is_string_variable(name) )
6290 for( i = 3; start < end; ++start, ++i )
6291 set_reg(st, sd, reference_uid(id, start), name, (void*)script_getstr(st,i), reference_getref(data));
6295 for( i = 3; start < end; ++start, ++i )
6296 set_reg(st, sd, reference_uid(id, start), name, (void*)__64BPRTSIZE(script_getnum(st,i)), reference_getref(data));
6298 return SCRIPT_CMD_SUCCESS;
6301 /// Sets count values of an array, from the starting index.
6302 /// ex: cleararray arr[0],0,1;
6304 /// cleararray <array variable>,<value>,<count>;
6305 BUILDIN_FUNC(cleararray)
6307 struct script_data* data;
6315 data = script_getdata(st, 2);
6316 if( !data_isreference(data) )
6318 ShowError("script:cleararray: not a variable\n");
6319 script_reportdata(data);
6321 return SCRIPT_CMD_FAILURE;// not a variable
6324 id = reference_getid(data);
6325 start = reference_getindex(data);
6326 name = reference_getname(data);
6328 if( not_server_variable(*name) )
6330 if( !script_rid2sd(sd) )
6331 return SCRIPT_CMD_SUCCESS;// no player attached
6334 if( is_string_variable(name) )
6335 v = (void*)script_getstr(st, 3);
6337 v = (void*)__64BPRTSIZE(script_getnum(st, 3));
6339 end = start + script_getnum(st, 4);
6340 if( end > SCRIPT_MAX_ARRAYSIZE )
6341 end = SCRIPT_MAX_ARRAYSIZE;
6343 for( ; start < end; ++start )
6344 set_reg(st, sd, reference_uid(id, start), name, v, script_getref(st,2));
6345 return SCRIPT_CMD_SUCCESS;
6348 /// Copies data from one array to another.
6349 /// ex: copyarray arr[0],arr[2],2;
6351 /// copyarray <destination array variable>,<source array variable>,<count>;
6352 BUILDIN_FUNC(copyarray)
6354 struct script_data* data1;
6355 struct script_data* data2;
6367 data1 = script_getdata(st, 2);
6368 data2 = script_getdata(st, 3);
6369 if( !data_isreference(data1) || !data_isreference(data2) )
6371 ShowError("script:copyarray: not a variable\n");
6372 script_reportdata(data1);
6373 script_reportdata(data2);
6375 return SCRIPT_CMD_FAILURE;// not a variable
6378 id1 = reference_getid(data1);
6379 id2 = reference_getid(data2);
6380 idx1 = reference_getindex(data1);
6381 idx2 = reference_getindex(data2);
6382 name1 = reference_getname(data1);
6383 name2 = reference_getname(data2);
6385 if( is_string_variable(name1) != is_string_variable(name2) )
6387 ShowError("script:copyarray: type mismatch\n");
6388 script_reportdata(data1);
6389 script_reportdata(data2);
6391 return SCRIPT_CMD_FAILURE;// data type mismatch
6394 if( not_server_variable(*name1) || not_server_variable(*name2) )
6396 if( !script_rid2sd(sd) )
6397 return SCRIPT_CMD_SUCCESS;// no player attached
6400 count = script_getnum(st, 4);
6401 if( count > SCRIPT_MAX_ARRAYSIZE - idx1 )
6402 count = SCRIPT_MAX_ARRAYSIZE - idx1;
6403 if( count <= 0 || (id1 == id2 && idx1 == idx2) )
6404 return SCRIPT_CMD_SUCCESS;// nothing to copy
6406 if( id1 == id2 && idx1 > idx2 )
6407 {// destination might be overlapping the source - copy in reverse order
6408 for( i = count - 1; i >= 0; --i )
6410 v = get_val2(st, reference_uid(id2, idx2 + i), reference_getref(data2));
6411 set_reg(st, sd, reference_uid(id1, idx1 + i), name1, v, reference_getref(data1));
6412 script_removetop(st, -1, 0);
6417 for( i = 0; i < count; ++i )
6419 if( idx2 + i < SCRIPT_MAX_ARRAYSIZE )
6421 v = get_val2(st, reference_uid(id2, idx2 + i), reference_getref(data2));
6422 set_reg(st, sd, reference_uid(id1, idx1 + i), name1, v, reference_getref(data1));
6423 script_removetop(st, -1, 0);
6425 else// out of range - assume ""/0
6426 set_reg(st, sd, reference_uid(id1, idx1 + i), name1, (is_string_variable(name1)?(void*)"":(void*)0), reference_getref(data1));
6429 return SCRIPT_CMD_SUCCESS;
6432 /// Returns the size of the array.
6433 /// Assumes that everything before the starting index exists.
6434 /// ex: getarraysize(arr[3])
6436 /// getarraysize(<array variable>) -> <int>
6437 BUILDIN_FUNC(getarraysize)
6439 struct script_data* data;
6441 struct map_session_data* sd = NULL;
6443 data = script_getdata(st, 2);
6444 if( !data_isreference(data) )
6446 ShowError("script:getarraysize: not a variable\n");
6447 script_reportdata(data);
6450 return SCRIPT_CMD_FAILURE;// not a variable
6453 name = reference_getname(data);
6455 if( not_server_variable(*name) ){
6456 if (!script_rid2sd(sd))
6457 return SCRIPT_CMD_SUCCESS;// no player attached
6460 script_pushint(st, script_array_highest_key(st, sd, reference_getname(data), reference_getref(data)));
6461 return SCRIPT_CMD_SUCCESS;
6464 int script_array_index_cmp(const void *a, const void *b) {
6465 return ( *(unsigned int*)a - *(unsigned int*)b );
6468 /// Deletes count or all the elements in an array, from the starting index.
6469 /// ex: deletearray arr[4],2;
6471 /// deletearray <array variable>;
6472 /// deletearray <array variable>,<count>;
6473 BUILDIN_FUNC(deletearray)
6475 struct script_data* data;
6477 unsigned int start, end, i;
6480 struct script_array *sa = NULL;
6481 struct reg_db *src = NULL;
6484 data = script_getdata(st, 2);
6485 if( !data_isreference(data) ) {
6486 ShowError("script:deletearray: not a variable\n");
6487 script_reportdata(data);
6489 return SCRIPT_CMD_FAILURE;// not a variable
6492 id = reference_getid(data);
6493 start = reference_getindex(data);
6494 name = reference_getname(data);
6496 if( not_server_variable(*name) ) {
6497 if( !script_rid2sd(sd) )
6498 return SCRIPT_CMD_SUCCESS;// no player attached
6501 if (!(src = script_array_src(st, sd, name, reference_getref(data)))) {
6502 ShowError("script:deletearray: not a array\n");
6503 script_reportdata(data);
6505 return SCRIPT_CMD_FAILURE;// not a variable
6508 script_array_ensure_zero(st, NULL, data->u.num, reference_getref(data));
6510 if ( !(sa = static_cast<script_array *>(idb_get(src->arrays, id))) ) { // non-existent array, nothing to empty
6511 return SCRIPT_CMD_SUCCESS;// not a variable
6514 end = script_array_highest_key(st, sd, name, reference_getref(data));
6517 return SCRIPT_CMD_SUCCESS;// nothing to free
6519 if( is_string_variable(name) )
6524 if( script_hasdata(st,3) ) {
6525 unsigned int count = script_getnum(st, 3);
6526 if( count > end - start )
6527 count = end - start;
6529 return SCRIPT_CMD_SUCCESS;// nothing to free
6531 if( end - start < sa->size ) {
6532 // Better to iterate directly on the array, no speed-up from using sa
6533 for( ; start + count < end; ++start ) {
6534 // Compact and overwrite
6535 void* v = get_val2(st, reference_uid(id, start + count), reference_getref(data));
6536 set_reg(st, sd, reference_uid(id, start), name, v, reference_getref(data));
6537 script_removetop(st, -1, 0);
6539 for( ; start < end; start++ ) {
6540 // Clean up any leftovers that weren't overwritten
6541 set_reg(st, sd, reference_uid(id, start), name, value, reference_getref(data));
6544 // using sa to speed up
6545 unsigned int *list = NULL, size = 0;
6546 list = script_array_cpy_list(sa);
6548 qsort(list, size, sizeof(unsigned int), script_array_index_cmp);
6550 ARR_FIND(0, size, i, list[i] >= start);
6552 for( ; i < size && list[i] < start + count; i++ ) {
6553 // Clear any entries between start and start+count, if they exist
6554 set_reg(st, sd, reference_uid(id, list[i]), name, value, reference_getref(data));
6557 for( ; i < size && list[i] < end; i++ ) {
6558 // Move back count positions any entries between start+count to fill the gaps
6559 void* v = get_val2(st, reference_uid(id, list[i]), reference_getref(data));
6560 set_reg(st, sd, reference_uid(id, list[i]-count), name, v, reference_getref(data));
6561 script_removetop(st, -1, 0);
6562 // Clear their originals
6563 set_reg(st, sd, reference_uid(id, list[i]), name, value, reference_getref(data));
6567 unsigned int *list = NULL, size = 0;
6568 list = script_array_cpy_list(sa);
6571 for(i = 0; i < size; i++) {
6572 if( list[i] >= start ) // Less expensive than sorting it, most likely
6573 set_reg(st, sd, reference_uid(id, list[i]), name, value, reference_getref(data));
6577 return SCRIPT_CMD_SUCCESS;
6580 /// Returns a reference to the target index of the array variable.
6581 /// Equivalent to var[index].
6583 /// getelementofarray(<array variable>,<index>) -> <variable reference>
6584 BUILDIN_FUNC(getelementofarray)
6586 struct script_data* data;
6590 data = script_getdata(st, 2);
6591 if( !data_isreference(data) )
6593 ShowError("script:getelementofarray: not a variable\n");
6594 script_reportdata(data);
6597 return SCRIPT_CMD_SUCCESS;// not a variable
6600 id = reference_getid(data);
6602 i = script_getnum(st, 3);
6603 if (i < 0 || i >= SCRIPT_MAX_ARRAYSIZE) {
6604 ShowWarning("script:getelementofarray: index out of range (%" PRId64 ")\n", i);
6605 script_reportdata(data);
6608 return SCRIPT_CMD_FAILURE;// out of range
6611 push_val2(st->stack, C_NAME, reference_uid(id, i), reference_getref(data));
6612 return SCRIPT_CMD_SUCCESS;
6615 /////////////////////////////////////////////////////////////////////
6619 /*==========================================
6621 *------------------------------------------*/
6622 BUILDIN_FUNC(setlook)
6627 type = script_getnum(st,2);
6628 val = script_getnum(st,3);
6630 if (!script_charid2sd(4,sd))
6631 return SCRIPT_CMD_SUCCESS;
6633 pc_changelook(sd,type,val);
6635 return SCRIPT_CMD_SUCCESS;
6638 BUILDIN_FUNC(changelook)
6639 { // As setlook but only client side
6643 type = script_getnum(st,2);
6644 val = script_getnum(st,3);
6646 if (!script_charid2sd(4,sd))
6647 return SCRIPT_CMD_SUCCESS;
6649 clif_changelook(&sd->bl,type,val);
6651 return SCRIPT_CMD_SUCCESS;
6654 /*==========================================
6656 *------------------------------------------*/
6661 if( !script_rid2sd(sd) )
6662 return SCRIPT_CMD_SUCCESS;
6664 clif_cutin(sd,script_getstr(st,2),script_getnum(st,3));
6665 return SCRIPT_CMD_SUCCESS;
6668 /*==========================================
6670 *------------------------------------------*/
6671 BUILDIN_FUNC(viewpoint)
6673 int type,x,y,id,color;
6676 type=script_getnum(st,2);
6677 x=script_getnum(st,3);
6678 y=script_getnum(st,4);
6679 id=script_getnum(st,5);
6680 color=script_getnum(st,6);
6682 if( !script_rid2sd(sd) )
6683 return SCRIPT_CMD_SUCCESS;
6685 clif_viewpoint(sd,st->oid,type,x,y,id,color);
6687 return SCRIPT_CMD_SUCCESS;
6691 * Set random options for new item
6692 * @param st Script state
6693 * @param it Temporary item data
6694 * @param funcname Function name
6695 * @param x First position of random option id array from the script
6697 static int script_getitem_randomoption(struct script_state *st, struct item *it, const char *funcname, int x) {
6698 int i, opt_id_n, opt_val_n, opt_param_n;
6699 struct script_data *opt_id = script_getdata(st,x);
6700 struct script_data *opt_val = script_getdata(st,x+1);
6701 struct script_data *opt_param = script_getdata(st,x+2);
6702 const char *opt_id_var = reference_getname(opt_id);
6703 const char *opt_val_var = reference_getname(opt_val);
6704 const char *opt_param_var = reference_getname(opt_param);
6705 int32 opt_id_id, opt_id_idx;
6706 int32 opt_val_id, opt_val_idx;
6707 int32 opt_param_id, opt_param_idx;
6708 struct reg_db *opt_id_ref = NULL, *opt_val_ref = NULL, *opt_param_ref = NULL;
6710 if (opt_id_var[strlen(opt_id_var)-1] == '$') {
6711 ShowError("buildin_%s: The array %s is not numeric type.\n", funcname, opt_id_var);
6712 return SCRIPT_CMD_FAILURE;
6715 if (opt_val_var[strlen(opt_val_var)-1] == '$') {
6716 ShowError("buildin_%s: The array %s is not numeric type.\n", funcname, opt_val_var);
6717 return SCRIPT_CMD_FAILURE;
6720 if (opt_param_var[strlen(opt_param_var)-1] == '$') {
6721 ShowError("buildin_%s: The array %s is not numeric type.\n", funcname, opt_param_var);
6722 return SCRIPT_CMD_FAILURE;
6725 opt_id_ref = reference_getref(opt_id);
6726 opt_id_n = script_array_highest_key(st, NULL, opt_id_var, opt_id_ref);
6729 ShowError("buildin_%s: No option id listed.\n", funcname);
6730 return SCRIPT_CMD_FAILURE;
6733 opt_val_ref = reference_getref(opt_val);
6734 opt_param_ref = reference_getref(opt_param);
6736 opt_val_n = script_array_highest_key(st, NULL, opt_val_var, opt_val_ref);
6737 opt_param_n = script_array_highest_key(st, NULL, opt_param_var, opt_param_ref);
6739 if (opt_val_n < 1) {
6740 ShowError("buildin_%s: No option value listed.\n", funcname);
6741 return SCRIPT_CMD_FAILURE;
6743 if (opt_param_n < 1) {
6744 ShowError("buildin_%s: No option parameter listed.\n", funcname);
6745 return SCRIPT_CMD_FAILURE;
6748 opt_id_id = reference_getid(opt_id);
6749 opt_val_id = reference_getid(opt_val);
6750 opt_param_id = reference_getid(opt_param);
6752 opt_id_idx = reference_getindex(opt_id);
6753 opt_val_idx = reference_getindex(opt_val);
6754 opt_param_idx = reference_getindex(opt_param);
6756 for (i = 0; i < opt_id_n && i < MAX_ITEM_RDM_OPT; i++) {
6757 it->option[i].id = static_cast<short>((int32)__64BPRTSIZE(get_val2(st,reference_uid(opt_id_id,opt_id_idx+i),opt_id_ref)));
6758 script_removetop(st, -1, 0);
6759 it->option[i].value = static_cast<short>((int32)__64BPRTSIZE(get_val2(st,reference_uid(opt_val_id,opt_val_idx+i),opt_val_ref)));
6760 script_removetop(st, -1, 0);
6761 it->option[i].param = static_cast<char>((int32)__64BPRTSIZE(get_val2(st,reference_uid(opt_param_id,opt_param_idx+i),opt_param_ref)));
6762 script_removetop(st, -1, 0);
6764 return SCRIPT_CMD_SUCCESS;
6767 /// Returns number of items in inventory/cart/storage
6768 /// countitem <nameID>{,<accountID>});
6769 /// countitem2 <nameID>,<Identified>,<Refine>,<Attribute>,<Card0>,<Card1>,<Card2>,<Card3>{,<accountID>}) [Lupus]
6770 /// cartcountitem <nameID>{,<accountID>});
6771 /// cartcountitem2 <nameID>,<Identified>,<Refine>,<Attribute>,<Card0>,<Card1>,<Card2>,<Card3>{,<accountID>})
6772 /// storagecountitem <nameID>{,<accountID>});
6773 /// storagecountitem2 <nameID>,<Identified>,<Refine>,<Attribute>,<Card0>,<Card1>,<Card2>,<Card3>{,<accountID>})
6774 /// guildstoragecountitem <nameID>{,<accountID>});
6775 /// guildstoragecountitem2 <nameID>,<Identified>,<Refine>,<Attribute>,<Card0>,<Card1>,<Card2>,<Card3>{,<accountID>})
6776 /// countitem3(<item id>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>)
6777 /// countitem3("<item name>",<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>)
6778 BUILDIN_FUNC(countitem)
6781 struct item_data* id = NULL;
6782 struct script_data* data;
6783 char *command = (char *)script_getfuncname(st);
6785 uint16 size, count = 0;
6788 struct s_storage *gstor = NULL;
6790 if( command[strlen(command)-1] == '2' ) {
6794 else if (command[strlen(command)-1] == '3') {
6799 if( script_hasdata(st,aid) ) {
6800 if( !(sd = map_id2sd( (aid = script_getnum(st, aid)) )) ) {
6801 ShowError("buildin_%s: player not found (AID=%d).\n", command, aid);
6803 return SCRIPT_CMD_FAILURE;
6807 if( !script_rid2sd(sd) )
6808 return SCRIPT_CMD_SUCCESS;
6811 if( !strncmp(command, "cart", 4) ) {
6814 items = sd->cart.u.items_cart;
6816 else if( !strncmp(command, "storage", 7) ) {
6817 loc = TABLE_STORAGE;
6819 items = sd->storage.u.items_storage;
6821 else if( !strncmp(command, "guildstorage", 12) ) {
6822 gstor = guild2storage2(sd->status.guild_id);
6824 if (gstor && !sd->state.storage_flag) {
6825 loc = TABLE_GUILD_STORAGE;
6826 size = MAX_GUILD_STORAGE;
6827 items = gstor->u.items_guild;
6829 script_pushint(st, -1);
6830 return SCRIPT_CMD_SUCCESS;
6834 size = MAX_INVENTORY;
6835 items = sd->inventory.u.items_inventory;
6838 if( loc == TABLE_CART && !pc_iscarton(sd) ) {
6839 ShowError("buildin_%s: Player doesn't have cart (CID:%d).\n", command, sd->status.char_id);
6840 script_pushint(st,-1);
6841 return SCRIPT_CMD_SUCCESS;
6844 data = script_getdata(st, 2);
6845 get_val(st, data); // Convert into value in case of a variable
6847 if( data_isstring(data) ) // item name
6848 id = itemdb_searchname(conv_str(st, data));
6850 id = itemdb_exists(conv_num(st, data));
6853 ShowError("buildin_%s: Invalid item '%s'.\n", command, script_getstr(st,2)); // returns string, regardless of what it was
6854 script_pushint(st,0);
6855 return SCRIPT_CMD_FAILURE;
6858 if (loc == TABLE_GUILD_STORAGE)
6861 if( !i ) { // For count/cart/storagecountitem function
6862 unsigned short nameid = id->nameid;
6863 for( i = 0; i < size; i++ )
6864 if( &items[i] && items[i].nameid == nameid )
6865 count += items[i].amount;
6867 else { // For count/cart/storagecountitem2 function
6869 bool check_randomopt = false;
6870 memset(&it, 0, sizeof(it));
6872 it.nameid = id->nameid;
6873 it.identify = script_getnum(st,3);
6874 it.refine = script_getnum(st,4);
6875 it.attribute = script_getnum(st,5);
6876 it.card[0] = script_getnum(st,6);
6877 it.card[1] = script_getnum(st,7);
6878 it.card[2] = script_getnum(st,8);
6879 it.card[3] = script_getnum(st,9);
6881 if (command[strlen(command)-1] == '3') {
6882 int res = script_getitem_randomoption(st, &it, command, 10);
6883 if (res != SCRIPT_CMD_SUCCESS)
6884 return SCRIPT_CMD_FAILURE;
6885 check_randomopt = true;
6888 for( i = 0; i < size; i++ ) {
6889 struct item *itm = &items[i];
6890 if (!itm || !itm->nameid || itm->amount < 1)
6892 if (itm->nameid != it.nameid || itm->identify != it.identify || itm->refine != it.refine || itm->attribute != it.attribute)
6894 if (memcmp(it.card, itm->card, sizeof(it.card)))
6896 if (check_randomopt) {
6898 for (j = 0; j < MAX_ITEM_RDM_OPT; j++) {
6899 if (itm->option[j].id != it.option[j].id || itm->option[j].value != it.option[j].value || itm->option[j].param != it.option[j].param)
6902 if (j != MAX_ITEM_RDM_OPT)
6905 count += items[i].amount;
6909 if (loc == TABLE_GUILD_STORAGE) {
6910 storage_guild_storageclose(sd);
6911 gstor->lock = false;
6914 script_pushint(st, count);
6915 return SCRIPT_CMD_SUCCESS;
6918 /*==========================================
6919 * Check if item with this amount can fit in inventory
6920 * Checking : weight, stack amount >(MAX_AMOUNT), slots amount >(MAX_INVENTORY)
6923 * 1 : success (npc side only)
6924 *------------------------------------------*/
6925 BUILDIN_FUNC(checkweight)
6928 unsigned short amount2 = 0;
6929 unsigned int weight = 0, i, nbargs;
6930 struct item_data* id = NULL;
6931 struct map_session_data* sd;
6933 if( !script_rid2sd(sd) )
6934 return SCRIPT_CMD_SUCCESS;
6936 nbargs = script_lastdata(st)+1;
6938 ShowError("buildin_checkweight: Invalid nb of args should be a multiple of 2.\n");
6939 script_pushint(st,0);
6940 return SCRIPT_CMD_FAILURE;
6942 slots = pc_inventoryblank(sd); //nb of empty slot
6944 for (i = 2; i < nbargs; i += 2) {
6945 unsigned short nameid, amount;
6946 struct script_data* data = script_getdata(st,i);
6947 get_val(st, data); // Convert into value in case of a variable
6948 if( data_isstring(data) ) // item name
6949 id = itemdb_searchname(conv_str(st, data));
6951 id = itemdb_exists(conv_num(st, data));
6953 ShowError("buildin_checkweight: Invalid item '%s'.\n", script_getstr(st,i)); // returns string, regardless of what it was
6954 script_pushint(st,0);
6955 return SCRIPT_CMD_FAILURE;
6957 nameid = id->nameid;
6959 amount = script_getnum(st,i+1);
6961 ShowError("buildin_checkweight: Invalid amount '%d'.\n", amount);
6962 script_pushint(st,0);
6963 return SCRIPT_CMD_FAILURE;
6966 weight += itemdb_weight(nameid)*amount; //total weight for all chk
6967 if( weight + sd->weight > sd->max_weight )
6969 script_pushint(st,0);
6970 return SCRIPT_CMD_SUCCESS;
6973 switch( pc_checkadditem(sd, nameid, amount) ) {
6974 case CHKADDITEM_EXIST:
6975 // item is already in inventory, but there is still space for the requested amount
6977 case CHKADDITEM_NEW:
6978 if( itemdb_isstackable(nameid) ) {
6981 if( slots < amount2 ) {
6982 script_pushint(st,0);
6983 return SCRIPT_CMD_SUCCESS;
6988 if( slots < amount2) {
6989 script_pushint(st,0);
6990 return SCRIPT_CMD_SUCCESS;
6994 case CHKADDITEM_OVERAMOUNT:
6995 script_pushint(st,0);
6996 return SCRIPT_CMD_SUCCESS;
7000 script_pushint(st,1);
7001 return SCRIPT_CMD_SUCCESS;
7004 BUILDIN_FUNC(checkweight2)
7006 //variable sub checkweight
7007 int i = 0, slots = 0, weight = 0;
7009 unsigned short amount2 = 0;
7011 //variable for array parsing
7012 struct script_data* data_it;
7013 struct script_data* data_nb;
7014 const char* name_it;
7015 const char* name_nb;
7017 int32 idx_it, idx_nb;
7018 int nb_it, nb_nb; //array size
7022 if( !script_rid2sd(sd) )
7023 return SCRIPT_CMD_SUCCESS;
7025 data_it = script_getdata(st, 2);
7026 data_nb = script_getdata(st, 3);
7028 if( !data_isreference(data_it) || !data_isreference(data_nb)) {
7029 ShowError("buildin_checkweight2: parameter not a variable\n");
7030 script_pushint(st,0);
7031 return SCRIPT_CMD_FAILURE;// not a variable
7034 id_it = reference_getid(data_it);
7035 id_nb = reference_getid(data_nb);
7036 idx_it = reference_getindex(data_it);
7037 idx_nb = reference_getindex(data_nb);
7038 name_it = reference_getname(data_it);
7039 name_nb = reference_getname(data_nb);
7041 if(is_string_variable(name_it) || is_string_variable(name_nb)) {
7042 ShowError("buildin_checkweight2: illegal type, need int\n");
7043 script_pushint(st,0);
7044 return SCRIPT_CMD_FAILURE;// not supported
7046 nb_it = script_array_highest_key(st, sd, reference_getname(data_it), reference_getref(data_it));
7047 nb_nb = script_array_highest_key(st, sd, reference_getname(data_nb), reference_getref(data_nb));
7048 if(nb_it != nb_nb) {
7049 ShowError("buildin_checkweight2: Size mistmatch: nb_it=%d, nb_nb=%d\n",nb_it,nb_nb);
7053 slots = pc_inventoryblank(sd);
7054 for(i=0; i<nb_it; i++) {
7055 unsigned short amount, nameid = (int32)__64BPRTSIZE(get_val2(st,reference_uid(id_it,idx_it+i),reference_getref(data_it)));
7056 script_removetop(st, -1, 0);
7057 amount = (int32)__64BPRTSIZE(get_val2(st,reference_uid(id_nb,idx_nb+i),reference_getref(data_nb)));
7058 script_removetop(st, -1, 0);
7061 continue; //cpntonie to depop rest
7063 if(itemdb_exists(nameid) == NULL ) {
7064 ShowError("buildin_checkweight2: Invalid item '%d'.\n", nameid);
7069 ShowError("buildin_checkweight2: Invalid amount '%d'.\n", amount);
7074 weight += itemdb_weight(nameid)*amount;
7075 if( weight + sd->weight > sd->max_weight ) {
7079 switch( pc_checkadditem(sd, nameid, amount) ) {
7080 case CHKADDITEM_EXIST:
7081 // item is already in inventory, but there is still space for the requested amount
7083 case CHKADDITEM_NEW:
7084 if( itemdb_isstackable(nameid) ) {// stackable
7086 if( slots < amount2 )
7088 } else {// non-stackable
7090 if( slots < amount2 ) {
7095 case CHKADDITEM_OVERAMOUNT:
7098 } //end loop DO NOT break it prematurly we need to depop all stack
7100 fail ? script_pushint(st,0) : script_pushint(st,1);
7101 return SCRIPT_CMD_SUCCESS;
7104 /*==========================================
7105 * getitem <item id>,<amount>{,<account ID>};
7106 * getitem "<item name>",<amount>{,<account ID>};
7108 * getitembound <item id>,<amount>,<type>{,<account ID>};
7109 * getitembound "<item id>",<amount>,<type>{,<account ID>};
7115 * 4 - Character Bound
7116 *------------------------------------------*/
7117 BUILDIN_FUNC(getitem)
7120 unsigned short nameid, amount;
7123 struct script_data *data;
7124 unsigned char flag = 0;
7125 const char* command = script_getfuncname(st);
7126 struct item_data *id = NULL;
7128 data = script_getdata(st,2);
7130 if( data_isstring(data) ) {// "<item name>"
7131 const char *name = conv_str(st,data);
7132 id = itemdb_searchname(name);
7134 ShowError("buildin_getitem: Nonexistant item %s requested.\n", name);
7135 return SCRIPT_CMD_FAILURE; //No item created.
7137 nameid = id->nameid;
7138 } else if( data_isint(data) ) {// <item id>
7139 nameid = conv_num(st,data);
7140 if( !(id = itemdb_exists(nameid)) ){
7141 ShowError("buildin_getitem: Nonexistant item %d requested.\n", nameid);
7142 return SCRIPT_CMD_FAILURE; //No item created.
7145 ShowError("buildin_getitem: invalid data type for argument #1 (%d).", data->type);
7146 return SCRIPT_CMD_FAILURE;
7150 if( (amount = script_getnum(st,3)) <= 0)
7151 return SCRIPT_CMD_SUCCESS; //return if amount <=0, skip the useles iteration
7153 memset(&it,0,sizeof(it));
7156 it.bound = BOUND_NONE;
7158 if( !strcmp(command,"getitembound") ) {
7159 char bound = script_getnum(st,4);
7160 if( bound < BOUND_NONE || bound >= BOUND_MAX ) {
7161 ShowError("script_getitembound: Not a correct bound type! Type=%d\n",bound);
7162 return SCRIPT_CMD_FAILURE;
7164 script_mapid2sd(5,sd);
7167 script_mapid2sd(4,sd);
7170 if( sd == NULL ) // no target
7171 return SCRIPT_CMD_SUCCESS;
7173 //Check if it's stackable.
7174 if (!itemdb_isstackable2(id))
7179 for (i = 0; i < amount; i += get_count)
7182 if (!pet_create_egg(sd, nameid))
7184 if ((flag = pc_additem(sd, &it, get_count, LOG_TYPE_SCRIPT)))
7186 clif_additem(sd, 0, 0, flag);
7187 if( pc_candrop(sd,&it) )
7188 map_addflooritem(&it,get_count,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0);
7192 return SCRIPT_CMD_SUCCESS;
7195 /*==========================================
7196 * getitem2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>};
7197 * getitem2 "<item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>};
7199 * getitembound2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<bound type>{,<account ID>};
7200 * getitembound2 "<item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<bound type>{,<account ID>};
7202 * getitem3 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<account ID>};
7203 * getitem3 "<item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<account ID>};
7205 * getitembound3 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<bound type>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<account ID>};
7206 * getitembound3 "<item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<bound type>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<account ID>};
7212 * 4 - Character Bound
7213 *------------------------------------------*/
7214 BUILDIN_FUNC(getitem2)
7216 unsigned short nameid, amount;
7217 int iden, ref, attr;
7218 unsigned short c1, c2, c3, c4;
7219 char bound = BOUND_NONE;
7220 struct item_data *item_data = NULL;
7221 struct item item_tmp;
7223 struct script_data *data;
7224 const char* command = script_getfuncname(st);
7227 if( !strncmp(command,"getitembound",12) ) {
7229 bound = script_getnum(st,11);
7230 if( bound < BOUND_NONE || bound >= BOUND_MAX ) {
7231 ShowError("script_getitembound2: Not a correct bound type! Type=%d\n",bound);
7232 return SCRIPT_CMD_FAILURE;
7234 if (command[strlen(command)-1] == '3') {
7238 script_mapid2sd(aid_pos,sd);
7241 if (strcmpi(command,"getitem3") == 0) {
7245 script_mapid2sd(aid_pos,sd);
7248 if( sd == NULL ) // no target
7249 return SCRIPT_CMD_SUCCESS;
7251 data = script_getdata(st,2);
7253 if( data_isstring(data) ) {
7254 const char *name = conv_str(st,data);
7255 if( (item_data = itemdb_searchname(name)) == NULL ){
7256 ShowError("buildin_getitem2: Nonexistant item %s requested (by conv_str).\n", name);
7257 return SCRIPT_CMD_FAILURE; //No item created.
7259 nameid = item_data->nameid;
7261 nameid = conv_num(st,data);
7262 if( (item_data = itemdb_exists(nameid)) == NULL ){
7263 ShowError("buildin_getitem2: Nonexistant item %d requested (by conv_num).\n", nameid);
7264 return SCRIPT_CMD_FAILURE; //No item created.
7268 amount = script_getnum(st,3);
7269 iden = script_getnum(st,4);
7270 ref = script_getnum(st,5);
7271 attr = script_getnum(st,6);
7272 c1 = (unsigned short)script_getnum(st,7);
7273 c2 = (unsigned short)script_getnum(st,8);
7274 c3 = (unsigned short)script_getnum(st,9);
7275 c4 = (unsigned short)script_getnum(st,10);
7278 int get_count = 0, i;
7279 memset(&item_tmp,0,sizeof(item_tmp));
7280 if( item_data->type == IT_WEAPON || item_data->type == IT_ARMOR || item_data->type == IT_SHADOWGEAR ) {
7281 if(ref > MAX_REFINE)
7284 else if( item_data->type == IT_PETEGG ) {
7293 item_tmp.nameid = nameid;
7294 item_tmp.identify = iden;
7295 item_tmp.refine = ref;
7296 item_tmp.attribute = attr;
7297 item_tmp.card[0] = c1;
7298 item_tmp.card[1] = c2;
7299 item_tmp.card[2] = c3;
7300 item_tmp.card[3] = c4;
7301 item_tmp.bound = bound;
7304 int res = script_getitem_randomoption(st, &item_tmp, command, offset);
7305 if (res == SCRIPT_CMD_FAILURE)
7306 return SCRIPT_CMD_FAILURE;
7309 //Check if it's stackable.
7310 if (!itemdb_isstackable2(item_data))
7315 for (i = 0; i < amount; i += get_count)
7318 if (!pet_create_egg(sd, nameid))
7320 unsigned char flag = 0;
7321 if ((flag = pc_additem(sd, &item_tmp, get_count, LOG_TYPE_SCRIPT)))
7323 clif_additem(sd, 0, 0, flag);
7324 if( pc_candrop(sd,&item_tmp) )
7325 map_addflooritem(&item_tmp,get_count,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0);
7330 return SCRIPT_CMD_SUCCESS;
7333 /** Gives rental item to player
7334 * rentitem <item id>,<seconds>{,<account_id>}
7335 * rentitem "<item name>",<seconds>{,<account_id>}
7337 BUILDIN_FUNC(rentitem) {
7338 struct map_session_data *sd;
7339 struct script_data *data;
7342 unsigned short nameid = 0;
7343 unsigned char flag = 0;
7345 data = script_getdata(st,2);
7348 if (!script_accid2sd(4,sd))
7349 return SCRIPT_CMD_FAILURE;
7351 if( data_isstring(data) )
7353 const char *name = conv_str(st,data);
7354 struct item_data *itd = itemdb_searchname(name);
7357 ShowError("buildin_rentitem: Nonexistant item %s requested.\n", name);
7358 return SCRIPT_CMD_FAILURE;
7360 nameid = itd->nameid;
7362 else if( data_isint(data) )
7364 nameid = conv_num(st,data);
7365 if( nameid == 0 || !itemdb_exists(nameid) )
7367 ShowError("buildin_rentitem: Nonexistant item %hu requested.\n", nameid);
7368 return SCRIPT_CMD_FAILURE;
7373 ShowError("buildin_rentitem: invalid data type for argument #1 (%d).\n", data->type);
7374 return SCRIPT_CMD_FAILURE;
7377 seconds = script_getnum(st,3);
7378 memset(&it, 0, sizeof(it));
7381 it.expire_time = (unsigned int)(time(NULL) + seconds);
7382 it.bound = BOUND_NONE;
7384 if( (flag = pc_additem(sd, &it, 1, LOG_TYPE_SCRIPT)) )
7386 clif_additem(sd, 0, 0, flag);
7387 return SCRIPT_CMD_FAILURE;
7389 return SCRIPT_CMD_SUCCESS;
7393 * Gives rental item to player with advanced option
7394 * rentitem2 <item id>,<time>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account_id>};
7395 * rentitem2 "<item name>",<time>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account_id>};
7397 * rentitem3 <item id>,<time>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<account_id>};
7398 * rentitem3 "<item name>",<time>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<account_id>};
7400 BUILDIN_FUNC(rentitem2) {
7401 struct map_session_data *sd;
7402 struct script_data *data;
7404 struct item_data *id;
7406 unsigned short nameid = 0;
7407 unsigned char flag = 0;
7408 int iden,ref,attr,c1,c2,c3,c4;
7409 const char *funcname = script_getfuncname(st);
7411 data = script_getdata(st,2);
7414 if (funcname[strlen(funcname)-1] == '3') {
7415 if (!script_accid2sd(14,sd))
7416 return SCRIPT_CMD_FAILURE;
7417 } else if (!script_accid2sd(11,sd))
7418 return SCRIPT_CMD_FAILURE;
7420 if( data_isstring(data) ) {
7421 const char *name = conv_str(st,data);
7422 id = itemdb_searchname(name);
7424 ShowError("buildin_rentitem2: Nonexistant item %s requested.\n", name);
7425 return SCRIPT_CMD_FAILURE;
7427 nameid = id->nameid;
7429 else if( data_isint(data) ) {
7430 nameid = conv_num(st,data);
7431 if( !(id = itemdb_search(nameid))) {
7432 ShowError("buildin_rentitem2: Nonexistant item %hu requested.\n", nameid);
7433 return SCRIPT_CMD_FAILURE;
7437 ShowError("buildin_rentitem2: invalid data type for argument #1 (%d).\n", data->type);
7438 return SCRIPT_CMD_FAILURE;
7441 seconds = script_getnum(st,3);
7442 iden = script_getnum(st,4);
7443 ref = script_getnum(st,5);
7444 attr = script_getnum(st,6);
7446 if (id->type==IT_WEAPON || id->type==IT_ARMOR || id->type==IT_SHADOWGEAR) {
7447 if(ref > MAX_REFINE) ref = MAX_REFINE;
7449 else if (id->type==IT_PETEGG) {
7458 c1 = (short)script_getnum(st,7);
7459 c2 = (short)script_getnum(st,8);
7460 c3 = (short)script_getnum(st,9);
7461 c4 = (short)script_getnum(st,10);
7463 memset(&it, 0, sizeof(it));
7467 it.attribute = attr;
7468 it.card[0] = (short)c1;
7469 it.card[1] = (short)c2;
7470 it.card[2] = (short)c3;
7471 it.card[3] = (short)c4;
7472 it.expire_time = (unsigned int)(time(NULL) + seconds);
7474 if (funcname[strlen(funcname)-1] == '3') {
7475 int res = script_getitem_randomoption(st, &it, funcname, 11);
7476 if (res != SCRIPT_CMD_SUCCESS)
7480 if( (flag = pc_additem(sd, &it, 1, LOG_TYPE_SCRIPT)) ) {
7481 clif_additem(sd, 0, 0, flag);
7482 return SCRIPT_CMD_FAILURE;
7485 return SCRIPT_CMD_SUCCESS;
7488 /*==========================================
7489 * gets an item with someone's name inscribed [Skotlex]
7490 * getinscribeditem item_num, character_name
7491 * Returned Qty is always 1, only works on equip-able
7493 *------------------------------------------*/
7494 BUILDIN_FUNC(getnameditem)
7496 unsigned short nameid;
7497 struct item item_tmp;
7499 struct script_data *data;
7501 if (!script_rid2sd(sd))
7502 { //Player not attached!
7503 script_pushint(st,0);
7504 return SCRIPT_CMD_SUCCESS;
7507 data=script_getdata(st,2);
7509 if( data_isstring(data) ){
7510 const char *name=conv_str(st,data);
7511 struct item_data *item_data = itemdb_searchname(name);
7512 if( item_data == NULL)
7514 script_pushint(st,0);
7515 return SCRIPT_CMD_SUCCESS;
7517 nameid = item_data->nameid;
7519 nameid = conv_num(st,data);
7521 if(!itemdb_exists(nameid)/* || itemdb_isstackable(nameid)*/)
7522 { //Even though named stackable items "could" be risky, they are required for certain quests.
7523 script_pushint(st,0);
7524 return SCRIPT_CMD_SUCCESS;
7527 data=script_getdata(st,3);
7529 if( data_isstring(data) ) //Char Name
7530 tsd=map_nick2sd(conv_str(st,data),false);
7531 else //Char Id was given
7532 tsd=map_charid2sd(conv_num(st,data));
7536 script_pushint(st,0);
7537 return SCRIPT_CMD_SUCCESS;
7540 memset(&item_tmp,0,sizeof(item_tmp));
7541 item_tmp.nameid=nameid;
7543 item_tmp.identify=1;
7544 item_tmp.card[0]=CARD0_CREATE; //we don't use 255! because for example SIGNED WEAPON shouldn't get TOP10 BS Fame bonus [Lupus]
7545 item_tmp.card[2]=tsd->status.char_id;
7546 item_tmp.card[3]=tsd->status.char_id >> 16;
7547 if(pc_additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT)) {
7548 script_pushint(st,0);
7549 return SCRIPT_CMD_SUCCESS; //Failed to add item, we will not drop if they don't fit
7552 script_pushint(st,1);
7553 return SCRIPT_CMD_SUCCESS;
7556 /*==========================================
7557 * gets a random item ID from an item group [Skotlex]
7558 * groupranditem <group_num>{,<sub_group>};
7559 *------------------------------------------*/
7560 BUILDIN_FUNC(grouprandomitem) {
7561 struct s_item_group_entry *entry = NULL;
7564 FETCH(3, sub_group);
7565 entry = itemdb_get_randgroupitem(script_getnum(st,2),sub_group);
7567 ShowError("buildin_grouprandomitem: Invalid item group with group_id '%d', sub_group '%d'.\n", script_getnum(st,2), sub_group);
7568 script_pushint(st,UNKNOWN_ITEM_ID);
7569 return SCRIPT_CMD_FAILURE;
7571 script_pushint(st,entry->nameid);
7572 return SCRIPT_CMD_SUCCESS;
7576 * makeitem <item id>,<amount>,"<map name>",<X>,<Y>;
7577 * makeitem "<item name>",<amount>,"<map name>",<X>,<Y>;
7579 BUILDIN_FUNC(makeitem) {
7580 uint16 nameid, amount, flag = 0, x, y;
7581 const char *mapname;
7583 struct item item_tmp;
7584 struct script_data *data;
7586 data = script_getdata(st,2);
7588 if( data_isstring(data) ){
7589 const char *name = conv_str(st,data);
7590 struct item_data *item_data = itemdb_searchname(name);
7592 nameid = item_data->nameid;
7594 nameid = UNKNOWN_ITEM_ID;
7597 nameid = conv_num(st,data);
7599 amount = script_getnum(st,3);
7600 mapname = script_getstr(st,4);
7601 x = script_getnum(st,5);
7602 y = script_getnum(st,6);
7604 if(strcmp(mapname,"this")==0) {
7606 if (!script_rid2sd(sd))
7607 return SCRIPT_CMD_SUCCESS; //Failed...
7610 m = map_mapname2mapid(mapname);
7618 memset(&item_tmp,0,sizeof(item_tmp));
7619 item_tmp.nameid = nameid;
7621 item_tmp.identify = 1;
7623 item_tmp.identify = itemdb_isidentified(nameid);
7625 map_addflooritem(&item_tmp,amount,m,x,y,0,0,0,4,0);
7627 return SCRIPT_CMD_SUCCESS;
7631 * makeitem2 <item id>,<amount>,"<map name>",<X>,<Y>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>;
7632 * makeitem2 "<item name>",<amount>,"<map name>",<X>,<Y>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>;
7634 * makeitem3 <item id>,<amount>,"<map name>",<X>,<Y>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>;
7635 * makeitem3 "<item name>",<amount>,"<map name>",<X>,<Y>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>;
7637 BUILDIN_FUNC(makeitem2) {
7638 uint16 nameid, amount, x, y;
7639 const char *mapname;
7641 struct item item_tmp;
7642 struct script_data *data;
7643 struct item_data *id;
7644 const char *funcname = script_getfuncname(st);
7646 data = script_getdata(st,2);
7648 if( data_isstring(data) ){
7649 const char *name = conv_str(st,data);
7650 struct item_data *item_data = itemdb_searchname(name);
7652 nameid = item_data->nameid;
7654 nameid = UNKNOWN_ITEM_ID;
7657 nameid = conv_num(st,data);
7659 amount = script_getnum(st,3);
7660 mapname = script_getstr(st,4);
7661 x = script_getnum(st,5);
7662 y = script_getnum(st,6);
7664 if (strcmp(mapname,"this")==0) {
7666 if (!script_rid2sd(sd))
7667 return SCRIPT_CMD_SUCCESS; //Failed...
7671 m = map_mapname2mapid(mapname);
7673 if ((id = itemdb_search(nameid))) {
7674 char iden, ref, attr;
7675 memset(&item_tmp,0,sizeof(item_tmp));
7676 item_tmp.nameid = nameid;
7678 iden = (char)script_getnum(st,7);
7679 ref = (char)script_getnum(st,8);
7680 attr = (char)script_getnum(st,9);
7682 if (id->type==IT_WEAPON || id->type==IT_ARMOR || id->type==IT_SHADOWGEAR) {
7683 if(ref > MAX_REFINE) ref = MAX_REFINE;
7685 else if (id->type==IT_PETEGG) {
7694 item_tmp.identify = iden;
7695 item_tmp.refine = ref;
7696 item_tmp.attribute = attr;
7697 item_tmp.card[0] = script_getnum(st,10);
7698 item_tmp.card[1] = script_getnum(st,11);
7699 item_tmp.card[2] = script_getnum(st,12);
7700 item_tmp.card[3] = script_getnum(st,13);
7702 if (funcname[strlen(funcname)-1] == '3') {
7703 int res = script_getitem_randomoption(st, &item_tmp, funcname, 14);
7704 if (res != SCRIPT_CMD_SUCCESS)
7708 map_addflooritem(&item_tmp,amount,m,x,y,0,0,0,4,0);
7711 return SCRIPT_CMD_FAILURE;
7712 return SCRIPT_CMD_SUCCESS;
7715 /// Counts / deletes the current item given by idx.
7716 /// Used by buildin_delitem_search
7717 /// Relies on all input data being already fully valid.
7718 static void buildin_delitem_delete(struct map_session_data* sd, int idx, int* amount, uint8 loc, bool delete_items)
7721 struct item *itm = NULL;
7722 struct s_storage *gstor = NULL;
7726 itm = &sd->cart.u.items_cart[idx];
7729 itm = &sd->storage.u.items_storage[idx];
7731 case TABLE_GUILD_STORAGE:
7733 gstor = guild2storage2(sd->status.guild_id);
7735 itm = &gstor->u.items_guild[idx];
7738 default: // TABLE_INVENTORY
7739 itm = &sd->inventory.u.items_inventory[idx];
7743 delamount = ( amount[0] < itm->amount ) ? amount[0] : itm->amount;
7747 if( itemdb_type(itm->nameid) == IT_PETEGG && itm->card[0] == CARD0_PET )
7748 {// delete associated pet
7749 intif_delete_petdata(MakeDWord(itm->card[1], itm->card[2]));
7753 pc_cart_delitem(sd,idx,delamount,0,LOG_TYPE_SCRIPT);
7756 storage_delitem(sd,&sd->storage,idx,delamount);
7757 log_pick_pc(sd,LOG_TYPE_SCRIPT,-delamount,itm);
7759 case TABLE_GUILD_STORAGE:
7761 storage_guild_delitem(sd, gstor, idx, delamount);
7762 log_pick_pc(sd, LOG_TYPE_SCRIPT, -delamount, itm);
7763 storage_guild_storageclose(sd);
7764 gstor->lock = false;
7766 default: // TABLE_INVENTORY
7767 pc_delitem(sd, idx, delamount, 0, 0, LOG_TYPE_SCRIPT);
7772 amount[0]-= delamount;
7776 /// Searches for item(s) and checks, if there is enough of them.
7777 /// Used by delitem and delitem2
7778 /// Relies on all input data being already fully valid.
7779 /// @param exact_match will also match item by specified attributes
7780 /// 0x0: Only item id
7781 /// 0x1: identify, attributes, cards
7782 /// 0x2: random option
7783 /// @return true when all items could be deleted, false when there were not enough items to delete
7784 static bool buildin_delitem_search(struct map_session_data* sd, struct item* it, uint8 exact_match, uint8 loc)
7786 bool delete_items = false;
7787 int i, amount, size;
7790 // prefer always non-equipped items
7793 // when searching for nameid only, prefer additionally
7796 // non-refined items
7799 memset(it->card, 0, sizeof(it->card));
7805 items = sd->cart.u.items_cart;
7809 items = sd->storage.u.items_storage;
7811 case TABLE_GUILD_STORAGE:
7813 struct s_storage *gstor = guild2storage2(sd->status.guild_id);
7815 size = MAX_GUILD_STORAGE;
7816 items = gstor->u.items_guild;
7819 default: // TABLE_INVENTORY
7820 size = MAX_INVENTORY;
7821 items = sd->inventory.u.items_inventory;
7827 unsigned short important = 0;
7828 amount = it->amount;
7830 // 1st pass -- less important items / exact match
7831 for( i = 0; amount && i < size; i++ )
7833 struct item *itm = NULL;
7835 if( !&items[i] || !(itm = &items[i])->nameid || itm->nameid != it->nameid )
7836 {// wrong/invalid item
7840 if( itm->equip != it->equip || itm->refine != it->refine )
7841 {// not matching attributes
7848 if( (exact_match&0x1) && ( itm->identify != it->identify || itm->attribute != it->attribute || memcmp(itm->card, it->card, sizeof(itm->card)) ) )
7849 {// not matching exact attributes
7852 if (exact_match&0x2) {
7854 for (j = 0; j < MAX_ITEM_RDM_OPT; j++) {
7855 if (itm->option[j].id != it->option[j].id || itm->option[j].value != it->option[j].value || itm->option[j].param != it->option[j].param)
7858 if (j != MAX_ITEM_RDM_OPT)
7864 if( itemdb_type(itm->nameid) == IT_PETEGG )
7866 if( itm->card[0] == CARD0_PET && CheckForCharServer() )
7867 {// pet which cannot be deleted
7871 else if( memcmp(itm->card, it->card, sizeof(itm->card)) )
7872 {// named/carded item
7878 // count / delete item
7879 buildin_delitem_delete(sd, i, &amount, loc, delete_items);
7882 // 2nd pass -- any matching item
7883 if( amount == 0 || important == 0 )
7884 {// either everything was already consumed or no items were skipped
7887 else for( i = 0; amount && i < size; i++ )
7889 struct item *itm = NULL;
7891 if( !&items[i] || !(itm = &items[i])->nameid || itm->nameid != it->nameid )
7892 {// wrong/invalid item
7896 if( itemdb_type(itm->nameid) == IT_PETEGG && itm->card[0] == CARD0_PET && CheckForCharServer() )
7897 {// pet which cannot be deleted
7903 if( (exact_match&0x1) && ( itm->refine != it->refine || itm->identify != it->identify || itm->attribute != it->attribute || memcmp(itm->card, it->card, sizeof(itm->card)) ) )
7904 {// not matching attributes
7907 if (exact_match&0x2) {
7909 for (j = 0; j < MAX_ITEM_RDM_OPT; j++) {
7910 if (itm->option[j].id != it->option[j].id || itm->option[j].value != it->option[j].value || itm->option[j].param != it->option[j].param)
7913 if (j != MAX_ITEM_RDM_OPT)
7918 // count / delete item
7919 buildin_delitem_delete(sd, i, &amount, loc, delete_items);
7923 {// not enough items
7926 else if( delete_items )
7927 {// we are done with the work
7931 {// get rid of the items now
7932 delete_items = true;
7938 /// Deletes items from the target/attached player.
7939 /// Prioritizes ordinary items.
7941 /// delitem <item id>,<amount>{,<account id>}
7942 /// delitem "<item name>",<amount>{,<account id>}
7943 /// cartdelitem <item id>,<amount>{,<account id>}
7944 /// cartdelitem "<item name>",<amount>{,<account id>}
7945 /// storagedelitem <item id>,<amount>{,<account id>}
7946 /// storagedelitem "<item name>",<amount>{,<account id>}
7947 /// guildstoragedelitem <item id>,<amount>{,<account id>}
7948 /// guildstoragedelitem "<item name>",<amount>{,<account id>}
7949 BUILDIN_FUNC(delitem)
7953 struct script_data *data;
7955 char* command = (char*)script_getfuncname(st);
7957 if(!strncmp(command, "cart", 4))
7959 else if(!strncmp(command, "storage", 7))
7960 loc = TABLE_STORAGE;
7961 else if(!strncmp(command, "guildstorage", 12))
7962 loc = TABLE_GUILD_STORAGE;
7964 if( !script_accid2sd(4,sd) ){
7965 // In any case cancel script execution
7967 return SCRIPT_CMD_SUCCESS;
7970 if (loc == TABLE_CART && !pc_iscarton(sd)) {
7971 ShowError("buildin_cartdelitem: player doesn't have cart (CID=%d).\n", sd->status.char_id);
7972 script_pushint(st, -1);
7973 return SCRIPT_CMD_FAILURE;
7975 if (loc == TABLE_GUILD_STORAGE) {
7976 struct s_storage *gstor = guild2storage2(sd->status.guild_id);
7978 if (gstor == NULL || sd->state.storage_flag) {
7979 script_pushint(st, -1);
7980 return SCRIPT_CMD_FAILURE;
7984 data = script_getdata(st,2);
7986 if( data_isstring(data) )
7988 const char* item_name = conv_str(st,data);
7989 struct item_data* id = itemdb_searchname(item_name);
7992 ShowError("buildin_%s: unknown item \"%s\".\n", command, item_name);
7994 return SCRIPT_CMD_FAILURE;
7996 it.nameid = id->nameid;// "<item name>"
8000 it.nameid = conv_num(st,data);// <item id>
8001 if( !itemdb_exists( it.nameid ) )
8003 ShowError("buildin_%s: unknown item \"%hu\".\n", command, it.nameid);
8005 return SCRIPT_CMD_FAILURE;
8009 it.amount=script_getnum(st,3);
8011 if( it.amount <= 0 )
8012 return SCRIPT_CMD_SUCCESS;// nothing to do
8014 if( buildin_delitem_search(sd, &it, 0, loc) )
8016 return SCRIPT_CMD_SUCCESS;
8019 ShowError("buildin_%s: failed to delete %d items (AID=%d item_id=%hu).\n", command, it.amount, sd->status.account_id, it.nameid);
8022 clif_scriptclose(sd, st->oid);
8023 return SCRIPT_CMD_FAILURE;
8026 /// Deletes items from the target/attached player.
8028 /// delitem2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
8029 /// delitem2 "<Item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
8030 /// cartdelitem2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
8031 /// cartdelitem2 "<Item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
8032 /// storagedelitem2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
8033 /// storagedelitem2 "<Item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
8034 /// guildstoragedelitem2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
8035 /// guildstoragedelitem2 "<Item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
8036 /// delitem3 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<account ID>};
8037 /// delitem3 "<item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>{,<account ID>};
8038 BUILDIN_FUNC(delitem2)
8042 struct script_data *data;
8044 char* command = (char*)script_getfuncname(st);
8048 if(!strncmp(command, "cart", 4))
8050 else if(!strncmp(command, "storage", 7))
8051 loc = TABLE_STORAGE;
8052 else if(!strncmp(command, "guildstorage", 12))
8053 loc = TABLE_GUILD_STORAGE;
8055 if (command[strlen(command)-1] == '3')
8058 if( !script_accid2sd(aid_pos,sd) ){
8059 // In any case cancel script execution
8061 return SCRIPT_CMD_SUCCESS;
8064 if (loc == TABLE_CART && !pc_iscarton(sd)) {
8065 ShowError("buildin_cartdelitem: player doesn't have cart (CID=%d).\n", sd->status.char_id);
8066 script_pushint(st,-1);
8067 return SCRIPT_CMD_FAILURE;
8069 if (loc == TABLE_GUILD_STORAGE) {
8070 struct s_storage *gstor = guild2storage2(sd->status.guild_id);
8072 if (gstor == NULL || sd->state.storage_flag) {
8073 script_pushint(st, -1);
8074 return SCRIPT_CMD_FAILURE;
8078 memset(&it, 0, sizeof(it));
8080 data = script_getdata(st,2);
8082 if( data_isstring(data) )
8084 const char* item_name = conv_str(st,data);
8085 struct item_data* id = itemdb_searchname(item_name);
8088 ShowError("buildin_%s: unknown item \"%s\".\n", command, item_name);
8090 return SCRIPT_CMD_FAILURE;
8092 it.nameid = id->nameid;// "<item name>"
8096 it.nameid = conv_num(st,data);// <item id>
8097 if( !itemdb_exists( it.nameid ) )
8099 ShowError("buildin_%s: unknown item \"%hu\".\n", command, it.nameid);
8101 return SCRIPT_CMD_FAILURE;
8105 it.amount=script_getnum(st,3);
8106 it.identify=script_getnum(st,4);
8107 it.refine=script_getnum(st,5);
8108 it.attribute=script_getnum(st,6);
8109 it.card[0]=(short)script_getnum(st,7);
8110 it.card[1]=(short)script_getnum(st,8);
8111 it.card[2]=(short)script_getnum(st,9);
8112 it.card[3]=(short)script_getnum(st,10);
8114 if (command[strlen(command)-1] == '3') {
8115 int res = script_getitem_randomoption(st, &it, command, 11);
8116 if (res != SCRIPT_CMD_SUCCESS)
8117 return SCRIPT_CMD_FAILURE;
8121 if( it.amount <= 0 )
8122 return SCRIPT_CMD_SUCCESS;// nothing to do
8124 if( buildin_delitem_search(sd, &it, flag, loc) )
8126 return SCRIPT_CMD_SUCCESS;
8129 ShowError("buildin_%s: failed to delete %d items (AID=%d item_id=%hu).\n", command, it.amount, sd->status.account_id, it.nameid);
8132 clif_scriptclose(sd, st->oid);
8133 return SCRIPT_CMD_FAILURE;
8136 /*==========================================
8137 * Enables/Disables use of items while in an NPC [Skotlex]
8138 *------------------------------------------*/
8139 BUILDIN_FUNC(enableitemuse)
8142 if (script_rid2sd(sd))
8143 st->npc_item_flag = sd->npc_item_flag = 1;
8144 return SCRIPT_CMD_SUCCESS;
8147 BUILDIN_FUNC(disableitemuse)
8150 if (script_rid2sd(sd))
8151 st->npc_item_flag = sd->npc_item_flag = 0;
8152 return SCRIPT_CMD_SUCCESS;
8155 /*==========================================
8156 * Returns a character's specified stat.
8157 * Check pc_readparam for available options.
8158 * readparam <param>{,"<nick>"}
8159 * readparam <param>{,<char_id>}
8160 *------------------------------------------*/
8161 BUILDIN_FUNC(readparam)
8164 struct script_data *data = script_getdata(st, 2);
8167 if( script_hasdata(st, 3) ){
8168 struct script_data *data2 = script_getdata(st, 3);
8171 if (data_isint(data2) || script_getnum(st, 3)) {
8172 script_charid2sd(3, sd);
8173 } else if (data_isstring(data2)) {
8174 script_nick2sd(3, sd);
8181 script_pushint(st, -1);
8182 return SCRIPT_CMD_FAILURE;
8185 // If you use a parameter, return the value behind it
8186 if( reference_toparam(data) ){
8187 get_val_(st, data, sd);
8188 value = (int)data->u.num;
8190 value = pc_readparam(sd,script_getnum(st, 2));
8193 script_pushint(st,value);
8194 return SCRIPT_CMD_SUCCESS;
8197 /*==========================================
8198 * Return charid identification
8206 *------------------------------------------*/
8207 BUILDIN_FUNC(getcharid)
8212 num = script_getnum(st,2);
8214 if( !script_nick2sd(3,sd) ){
8215 script_pushint(st,0); //return 0, according docs
8216 return SCRIPT_CMD_SUCCESS;
8220 case 0: script_pushint(st,sd->status.char_id); break;
8221 case 1: script_pushint(st,sd->status.party_id); break;
8222 case 2: script_pushint(st,sd->status.guild_id); break;
8223 case 3: script_pushint(st,sd->status.account_id); break;
8224 case 4: script_pushint(st,sd->bg_id); break;
8225 case 5: script_pushint(st,sd->status.clan_id); break;
8227 ShowError("buildin_getcharid: invalid parameter (%d).\n", num);
8228 script_pushint(st,0);
8231 return SCRIPT_CMD_SUCCESS;
8234 /*==========================================
8235 * returns the GID of an NPC
8236 *------------------------------------------*/
8237 BUILDIN_FUNC(getnpcid)
8239 int num = script_getnum(st,2);
8240 struct npc_data* nd = NULL;
8242 if( script_hasdata(st,3) )
8244 if( ( nd = npc_name2id(script_getstr(st,3)) ) == NULL )
8246 ShowError("buildin_getnpcid: No such NPC '%s'.\n", script_getstr(st,3));
8247 script_pushint(st,0);
8248 return SCRIPT_CMD_FAILURE;
8254 script_pushint(st,nd ? nd->bl.id : st->oid);
8257 ShowError("buildin_getnpcid: invalid parameter (%d).\n", num);
8258 script_pushint(st,0);
8259 return SCRIPT_CMD_FAILURE;
8261 return SCRIPT_CMD_SUCCESS;
8264 /*==========================================
8265 * Return the name of the party_id
8267 *------------------------------------------*/
8268 BUILDIN_FUNC(getpartyname)
8271 struct party_data* p;
8273 party_id = script_getnum(st,2);
8275 if( ( p = party_search(party_id) ) != NULL )
8277 script_pushstrcopy(st,p->party.name);
8281 script_pushconststr(st,"null");
8283 return SCRIPT_CMD_SUCCESS;
8286 /*==========================================
8287 * Get the information of the members of a party by type
8290 * - : nom des membres
8291 * 1 : char_id des membres
8292 * 2 : account_id des membres
8293 *------------------------------------------*/
8294 BUILDIN_FUNC(getpartymember)
8296 struct party_data *p;
8299 p = party_search(script_getnum(st,2));
8303 struct script_data *data = NULL;
8304 char *varname = NULL;
8306 if (script_hasdata(st,3))
8307 type = script_getnum(st,3);
8309 if (script_hasdata(st,4)) {
8310 data = script_getdata(st, 4);
8311 if (!data_isreference(data)) {
8312 ShowError("buildin_getpartymember: Error in argument! Please give a variable to store values in.\n");
8313 return SCRIPT_CMD_FAILURE;
8315 varname = reference_getname(data);
8316 if (type <= 0 && varname[strlen(varname)-1] != '$') {
8317 ShowError("buildin_getpartymember: The array %s is not string type.\n", varname);
8318 return SCRIPT_CMD_FAILURE;
8322 for (i = 0; i < MAX_PARTY; i++) {
8323 if (p->party.member[i].account_id) {
8327 setd_sub(st, NULL, varname, j, (void *)__64BPRTSIZE(p->party.member[i].account_id), data->ref);
8329 mapreg_setreg(reference_uid(add_str("$@partymemberaid"), j),p->party.member[i].account_id);
8333 setd_sub(st, NULL, varname, j, (void *)__64BPRTSIZE(p->party.member[i].char_id), data->ref);
8335 mapreg_setreg(reference_uid(add_str("$@partymembercid"), j),p->party.member[i].char_id);
8339 setd_sub(st, NULL, varname, j, (void *)__64BPRTSIZE(p->party.member[i].name), data->ref);
8341 mapreg_setregstr(reference_uid(add_str("$@partymembername$"), j),p->party.member[i].name);
8350 mapreg_setreg(add_str("$@partymembercount"),j);
8351 script_pushint(st, j);
8352 return SCRIPT_CMD_SUCCESS;
8355 /*==========================================
8356 * Retrieves party leader. if flag is specified,
8357 * return some of the leader data. Otherwise, return name.
8358 *------------------------------------------*/
8359 BUILDIN_FUNC(getpartyleader)
8361 int party_id, type = 0, i=0;
8362 struct party_data *p;
8364 party_id=script_getnum(st,2);
8365 if( script_hasdata(st,3) )
8366 type=script_getnum(st,3);
8368 p=party_search(party_id);
8370 if (p) //Search leader
8371 for(i = 0; i < MAX_PARTY && !p->party.member[i].leader; i++);
8373 if (!p || i == MAX_PARTY) { //leader not found
8375 script_pushint(st,-1);
8377 script_pushconststr(st,"null");
8378 return SCRIPT_CMD_SUCCESS;
8382 case 1: script_pushint(st,p->party.member[i].account_id); break;
8383 case 2: script_pushint(st,p->party.member[i].char_id); break;
8384 case 3: script_pushint(st,p->party.member[i].class_); break;
8385 case 4: script_pushstrcopy(st,mapindex_id2name(p->party.member[i].map)); break;
8386 case 5: script_pushint(st,p->party.member[i].lv); break;
8387 default: script_pushstrcopy(st,p->party.member[i].name); break;
8389 return SCRIPT_CMD_SUCCESS;
8392 /*==========================================
8393 * Return the name of the @guild_id
8395 *------------------------------------------*/
8396 BUILDIN_FUNC(getguildname)
8401 guild_id = script_getnum(st,2);
8402 if( ( g = guild_search(guild_id) ) != NULL )
8403 script_pushstrcopy(st,g->name);
8405 script_pushconststr(st,"null");
8406 return SCRIPT_CMD_SUCCESS;
8409 /*==========================================
8410 * Return the name of the guild master of @guild_id
8412 *------------------------------------------*/
8413 BUILDIN_FUNC(getguildmaster)
8418 guild_id = script_getnum(st,2);
8419 if( ( g = guild_search(guild_id) ) != NULL )
8420 script_pushstrcopy(st,g->member[0].name);
8422 script_pushconststr(st,"null");
8423 return SCRIPT_CMD_SUCCESS;
8426 BUILDIN_FUNC(getguildmasterid)
8431 guild_id = script_getnum(st,2);
8432 if( ( g = guild_search(guild_id) ) != NULL )
8433 script_pushint(st,g->member[0].char_id);
8435 script_pushint(st,0);
8436 return SCRIPT_CMD_SUCCESS;
8439 /*==========================================
8440 * Get char string information by type :
8443 * 1 : party_name or ""
8444 * 2 : guild_name or ""
8447 * strcharinfo(<type>{,<char_id>})
8448 *------------------------------------------*/
8449 BUILDIN_FUNC(strcharinfo)
8454 struct party_data* p;
8456 if (!script_charid2sd(3,sd)) {
8457 script_pushconststr(st,"");
8458 return SCRIPT_CMD_FAILURE;
8461 num=script_getnum(st,2);
8464 script_pushstrcopy(st,sd->status.name);
8467 if( ( p = party_search(sd->status.party_id) ) != NULL ) {
8468 script_pushstrcopy(st,p->party.name);
8470 script_pushconststr(st,"");
8474 if( ( g = sd->guild ) != NULL ) {
8475 script_pushstrcopy(st,g->name);
8477 script_pushconststr(st,"");
8481 script_pushconststr(st,map[sd->bl.m].name);
8484 ShowWarning("buildin_strcharinfo: unknown parameter.\n");
8485 script_pushconststr(st,"");
8489 return SCRIPT_CMD_SUCCESS;
8492 /*==========================================
8493 * Get npc string information by type
8500 *------------------------------------------*/
8501 BUILDIN_FUNC(strnpcinfo)
8505 char *buf,*name=NULL;
8507 nd = map_id2nd(st->oid);
8509 script_pushconststr(st, "");
8510 return SCRIPT_CMD_SUCCESS;
8513 num = script_getnum(st,2);
8515 case 0: // display name
8516 name = aStrdup(nd->name);
8518 case 1: // visible part of display name
8519 if((buf = strchr(nd->name,'#')) != NULL)
8521 name = aStrdup(nd->name);
8522 name[buf - nd->name] = 0;
8523 } else // Return the name, there is no '#' present
8524 name = aStrdup(nd->name);
8526 case 2: // # fragment
8527 if((buf = strchr(nd->name,'#')) != NULL)
8528 name = aStrdup(buf+1);
8530 case 3: // unique name
8531 name = aStrdup(nd->exname);
8535 name = aStrdup(map[nd->bl.m].name);
8540 script_pushstr(st, name);
8542 script_pushconststr(st, "");
8544 return SCRIPT_CMD_SUCCESS;
8548 * getequipid({<equipment slot>,<char_id>})
8550 BUILDIN_FUNC(getequipid)
8555 if (!script_charid2sd(3, sd)) {
8556 script_pushint(st,-1);
8557 return SCRIPT_CMD_FAILURE;
8560 if (script_hasdata(st, 2))
8561 num = script_getnum(st, 2);
8563 num = EQI_COMPOUND_ON;
8565 if (num == EQI_COMPOUND_ON)
8566 i = current_equip_item_index;
8567 else if (equip_index_check(num)) // get inventory position of item
8568 i = pc_checkequip(sd, equip_bitmask[num]);
8570 ShowError( "buildin_getequipid: Unknown equip index '%d'\n", num );
8571 script_pushint(st,-1);
8572 return SCRIPT_CMD_FAILURE;
8575 if (i >= 0 && i < MAX_INVENTORY && sd->inventory_data[i])
8576 script_pushint(st, sd->inventory_data[i]->nameid);
8578 script_pushint(st, -1);
8580 return SCRIPT_CMD_SUCCESS;
8583 /*==========================================
8584 * getequipuniqueid(<equipment slot>{,<char_id>})
8585 *------------------------------------------*/
8586 BUILDIN_FUNC(getequipuniqueid)
8592 if (!script_charid2sd(3, sd)) {
8593 script_pushconststr(st, "");
8594 return SCRIPT_CMD_FAILURE;
8597 num = script_getnum(st,2);
8598 if ( !equip_index_check(num) ) {
8599 script_pushconststr(st, "");
8600 return SCRIPT_CMD_FAILURE;
8603 // get inventory position of item
8604 i = pc_checkequip(sd,equip_bitmask[num]);
8606 script_pushconststr(st, "");
8607 return SCRIPT_CMD_FAILURE;
8610 item = &sd->inventory.u.items_inventory[i];
8613 char *buf = (char *)aMalloc(maxlen*sizeof(char));
8615 memset(buf, 0, maxlen);
8616 snprintf(buf, maxlen-1, "%llu", (unsigned long long)item->unique_id);
8618 script_pushstr(st, buf);
8620 script_pushconststr(st, "");
8622 return SCRIPT_CMD_SUCCESS;
8625 /*==========================================
8626 * Get the equipement name at pos
8627 * return item jname or ""
8628 * getequipname(<equipment slot>{,<char_id>})
8629 *------------------------------------------*/
8630 BUILDIN_FUNC(getequipname)
8634 struct item_data* item;
8636 if (!script_charid2sd(3, sd)) {
8637 script_pushconststr(st, "");
8638 return SCRIPT_CMD_FAILURE;
8641 num = script_getnum(st,2);
8642 if( !equip_index_check(num) )
8644 script_pushconststr(st,"");
8645 return SCRIPT_CMD_SUCCESS;
8648 // get inventory position of item
8649 i = pc_checkequip(sd,equip_bitmask[num]);
8652 script_pushconststr(st,"");
8653 return SCRIPT_CMD_SUCCESS;
8656 item = sd->inventory_data[i];
8658 script_pushstrcopy(st,item->jname);
8660 script_pushconststr(st,"");
8662 return SCRIPT_CMD_SUCCESS;
8665 /*==========================================
8666 * getbrokenid [Valaris]
8667 * getbrokenid(<number>{,<char_id>})
8668 *------------------------------------------*/
8669 BUILDIN_FUNC(getbrokenid)
8671 int i,num,id = 0,brokencounter = 0;
8674 if (!script_charid2sd(3, sd)) {
8675 script_pushint(st,0);
8676 return SCRIPT_CMD_FAILURE;
8679 num = script_getnum(st,2);
8680 for(i = 0; i < MAX_INVENTORY; i++) {
8681 if(sd->inventory.u.items_inventory[i].attribute) {
8683 if(num == brokencounter){
8684 id = sd->inventory.u.items_inventory[i].nameid;
8690 script_pushint(st,id);
8692 return SCRIPT_CMD_SUCCESS;
8695 /*==========================================
8697 * repair <num>{,<char_id>};
8698 *------------------------------------------*/
8699 BUILDIN_FUNC(repair)
8702 int repaircounter = 0;
8705 if (!script_charid2sd(3,sd))
8706 return SCRIPT_CMD_FAILURE;
8708 num = script_getnum(st,2);
8709 for(i = 0; i < MAX_INVENTORY; i++) {
8710 if(sd->inventory.u.items_inventory[i].attribute) {
8712 if(num == repaircounter) {
8713 sd->inventory.u.items_inventory[i].attribute = 0;
8715 clif_produceeffect(sd, 0, sd->inventory.u.items_inventory[i].nameid);
8716 clif_misceffect(&sd->bl, 3);
8722 return SCRIPT_CMD_SUCCESS;
8725 /*==========================================
8726 * repairall {<char_id>}
8727 *------------------------------------------*/
8728 BUILDIN_FUNC(repairall)
8730 int i, repaircounter = 0;
8733 if (!script_charid2sd(2,sd))
8734 return SCRIPT_CMD_FAILURE;
8736 for(i = 0; i < MAX_INVENTORY; i++)
8738 if(sd->inventory.u.items_inventory[i].nameid && sd->inventory.u.items_inventory[i].attribute)
8740 sd->inventory.u.items_inventory[i].attribute = 0;
8741 clif_produceeffect(sd,0,sd->inventory.u.items_inventory[i].nameid);
8748 clif_misceffect(&sd->bl, 3);
8752 return SCRIPT_CMD_SUCCESS;
8755 /*==========================================
8756 * Chk if player have something equiped at pos
8757 * getequipisequiped <pos>{,<char_id>}
8758 *------------------------------------------*/
8759 BUILDIN_FUNC(getequipisequiped)
8764 num = script_getnum(st,2);
8766 if (!script_charid2sd(3,sd))
8767 return SCRIPT_CMD_FAILURE;
8769 if ( equip_index_check(num) )
8770 i=pc_checkequip(sd,equip_bitmask[num]);
8773 script_pushint(st,1);
8775 script_pushint(st,0);
8776 return SCRIPT_CMD_SUCCESS;
8779 /*==========================================
8780 * Chk if the player have something equiped at pos
8781 * if so chk if this item ain't marked not refinable or rental
8785 * getequipisenableref(<equipment slot>{,<char_id>})
8786 *------------------------------------------*/
8787 BUILDIN_FUNC(getequipisenableref)
8792 num = script_getnum(st,2);
8794 if (!script_charid2sd(3, sd)) {
8795 script_pushint(st,0);
8796 return SCRIPT_CMD_FAILURE;
8799 if( equip_index_check(num) )
8800 i = pc_checkequip(sd,equip_bitmask[num]);
8801 if( i >= 0 && sd->inventory_data[i] && !sd->inventory_data[i]->flag.no_refine && !sd->inventory.u.items_inventory[i].expire_time )
8802 script_pushint(st,1);
8804 script_pushint(st,0);
8806 return SCRIPT_CMD_SUCCESS;
8809 /*==========================================
8810 * Get the item refined value at pos
8813 * 0 : false (not refined)
8814 * getequiprefinerycnt(<equipment slot>{,<char_id>})
8815 *------------------------------------------*/
8816 BUILDIN_FUNC(getequiprefinerycnt)
8821 num = script_getnum(st,2);
8823 if (!script_charid2sd(3, sd)) {
8824 script_pushint(st,0);
8825 return SCRIPT_CMD_FAILURE;
8828 if (equip_index_check(num))
8829 i=pc_checkequip(sd,equip_bitmask[num]);
8831 script_pushint(st,sd->inventory.u.items_inventory[i].refine);
8833 script_pushint(st,0);
8835 return SCRIPT_CMD_SUCCESS;
8838 /*==========================================
8839 * Get the weapon level value at pos
8840 * (pos should normally only be EQI_HAND_L or EQI_HAND_R)
8844 * getequipweaponlv(<equipment slot>{,<char_id>})
8845 *------------------------------------------*/
8846 BUILDIN_FUNC(getequipweaponlv)
8851 num = script_getnum(st, 2);
8853 if (!script_charid2sd(3, sd)) {
8854 script_pushint(st, 0);
8855 return SCRIPT_CMD_FAILURE;
8859 if( current_equip_item_index == -1 ){
8860 script_pushint(st, 0);
8861 return SCRIPT_CMD_FAILURE;
8864 i = current_equip_item_index;
8865 }else if (equip_index_check(num))
8866 i = pc_checkequip(sd, equip_bitmask[num]);
8867 if (i >= 0 && sd->inventory_data[i])
8868 script_pushint(st, sd->inventory_data[i]->wlv);
8870 script_pushint(st, 0);
8872 return SCRIPT_CMD_SUCCESS;
8875 /*==========================================
8876 * Get the item refine chance (from refine.txt) for item at pos
8879 * 0 : false (max refine level or unequip..)
8880 * getequippercentrefinery(<equipment slot>{,<enriched>,<char_id>})
8881 *------------------------------------------*/
8882 BUILDIN_FUNC(getequippercentrefinery)
8885 bool enriched = false;
8888 num = script_getnum(st,2);
8889 if (script_hasdata(st, 3))
8890 enriched = script_getnum(st, 3) != 0;
8892 if (!script_charid2sd(4, sd)) {
8893 script_pushint(st,0);
8894 return SCRIPT_CMD_FAILURE;
8897 if (equip_index_check(num))
8898 i = pc_checkequip(sd,equip_bitmask[num]);
8899 if (i >= 0 && sd->inventory.u.items_inventory[i].nameid && sd->inventory.u.items_inventory[i].refine < MAX_REFINE) {
8900 enum refine_type type = REFINE_TYPE_SHADOW;
8901 if (sd->inventory_data[i]->type != IT_SHADOWGEAR)
8902 type = (enum refine_type)sd->inventory_data[i]->wlv;
8903 script_pushint(st, status_get_refine_chance(type, (int)sd->inventory.u.items_inventory[i].refine, enriched));
8906 script_pushint(st,0);
8908 return SCRIPT_CMD_SUCCESS;
8911 /*==========================================
8912 * Refine +1 item at pos and log and display refine
8913 * successrefitem <equipment slot>{,<count>{,<char_id>}}
8914 *------------------------------------------*/
8915 BUILDIN_FUNC(successrefitem) {
8916 short i = -1, up = 1;
8920 pos = script_getnum(st,2);
8922 if (!script_charid2sd(4, sd)) {
8923 script_pushint(st, -1);
8924 return SCRIPT_CMD_FAILURE;
8927 if (script_hasdata(st, 3))
8928 up = script_getnum(st, 3);
8930 if (equip_index_check(pos))
8931 i = pc_checkequip(sd,equip_bitmask[pos]);
8933 unsigned int ep = sd->inventory.u.items_inventory[i].equip;
8935 //Logs items, got from (N)PC scripts [Lupus]
8936 log_pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->inventory.u.items_inventory[i]);
8938 if (sd->inventory.u.items_inventory[i].refine >= MAX_REFINE) {
8939 script_pushint(st, MAX_REFINE);
8940 return SCRIPT_CMD_SUCCESS;
8943 sd->inventory.u.items_inventory[i].refine += up;
8944 sd->inventory.u.items_inventory[i].refine = cap_value( sd->inventory.u.items_inventory[i].refine, 0, MAX_REFINE);
8945 pc_unequipitem(sd,i,2); // status calc will happen in pc_equipitem() below
8947 clif_refine(sd->fd,0,i,sd->inventory.u.items_inventory[i].refine);
8948 clif_delitem(sd,i,1,3);
8950 //Logs items, got from (N)PC scripts [Lupus]
8951 log_pick_pc(sd, LOG_TYPE_SCRIPT, 1, &sd->inventory.u.items_inventory[i]);
8953 clif_additem(sd,i,1,0);
8954 pc_equipitem(sd,i,ep);
8955 clif_misceffect(&sd->bl,3);
8956 achievement_update_objective(sd, AG_REFINE_SUCCESS, 2, sd->inventory_data[i]->wlv, sd->inventory.u.items_inventory[i].refine);
8957 if (sd->inventory.u.items_inventory[i].refine == MAX_REFINE &&
8958 sd->inventory.u.items_inventory[i].card[0] == CARD0_FORGE &&
8959 sd->status.char_id == (int)MakeDWord(sd->inventory.u.items_inventory[i].card[2],sd->inventory.u.items_inventory[i].card[3]))
8960 { // Fame point system [DracoRPG]
8961 switch (sd->inventory_data[i]->wlv){
8963 pc_addfame(sd, battle_config.fame_refine_lv1); // Success to refine to +10 a lv1 weapon you forged = +1 fame point
8966 pc_addfame(sd, battle_config.fame_refine_lv2); // Success to refine to +10 a lv2 weapon you forged = +25 fame point
8969 pc_addfame(sd, battle_config.fame_refine_lv3); // Success to refine to +10 a lv3 weapon you forged = +1000 fame point
8973 script_pushint(st, sd->inventory.u.items_inventory[i].refine);
8974 return SCRIPT_CMD_SUCCESS;
8977 ShowError("buildin_successrefitem: No item equipped at pos %d (CID=%d/AID=%d).\n", pos, sd->status.char_id, sd->status.account_id);
8978 script_pushint(st, -1);
8979 return SCRIPT_CMD_FAILURE;
8982 /*==========================================
8983 * Show a failed Refine +1 attempt
8984 * failedrefitem <equipment slot>{,<char_id>}
8985 *------------------------------------------*/
8986 BUILDIN_FUNC(failedrefitem) {
8991 pos = script_getnum(st,2);
8993 if (!script_charid2sd(3, sd)) {
8994 script_pushint(st, 0);
8995 return SCRIPT_CMD_FAILURE;
8998 if (equip_index_check(pos))
8999 i = pc_checkequip(sd,equip_bitmask[pos]);
9001 sd->inventory.u.items_inventory[i].refine = 0;
9002 pc_unequipitem(sd,i,3); //recalculate bonus
9003 clif_refine(sd->fd,1,i,sd->inventory.u.items_inventory[i].refine); //notify client of failure
9004 pc_delitem(sd,i,1,0,2,LOG_TYPE_SCRIPT);
9005 clif_misceffect(&sd->bl,2); // display failure effect
9006 achievement_update_objective(sd, AG_REFINE_FAIL, 1, 1);
9007 script_pushint(st, 1);
9008 return SCRIPT_CMD_SUCCESS;
9011 ShowError("buildin_failedrefitem: No item equipped at pos %d (CID=%d/AID=%d).\n", pos, sd->status.char_id, sd->status.account_id);
9012 script_pushint(st, 0);
9013 return SCRIPT_CMD_FAILURE;
9016 /*==========================================
9017 * Downgrades an Equipment Part by -1 . [Masao]
9018 * downrefitem <equipment slot>{,<count>{,<char_id>}}
9019 *------------------------------------------*/
9020 BUILDIN_FUNC(downrefitem) {
9021 short i = -1, down = 1;
9025 if (!script_charid2sd(4, sd)) {
9026 script_pushint(st, -1);
9027 return SCRIPT_CMD_FAILURE;
9030 pos = script_getnum(st,2);
9031 if (script_hasdata(st, 3))
9032 down = script_getnum(st, 3);
9034 if (equip_index_check(pos))
9035 i = pc_checkequip(sd,equip_bitmask[pos]);
9037 unsigned int ep = sd->inventory.u.items_inventory[i].equip;
9039 //Logs items, got from (N)PC scripts [Lupus]
9040 log_pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->inventory.u.items_inventory[i]);
9042 pc_unequipitem(sd,i,2); // status calc will happen in pc_equipitem() below
9043 sd->inventory.u.items_inventory[i].refine -= down;
9044 sd->inventory.u.items_inventory[i].refine = cap_value( sd->inventory.u.items_inventory[i].refine, 0, MAX_REFINE);
9046 clif_refine(sd->fd,2,i,sd->inventory.u.items_inventory[i].refine);
9047 clif_delitem(sd,i,1,3);
9049 //Logs items, got from (N)PC scripts [Lupus]
9050 log_pick_pc(sd, LOG_TYPE_SCRIPT, 1, &sd->inventory.u.items_inventory[i]);
9052 clif_additem(sd,i,1,0);
9053 pc_equipitem(sd,i,ep);
9054 clif_misceffect(&sd->bl,2);
9055 achievement_update_objective(sd, AG_REFINE_FAIL, 1, sd->inventory.u.items_inventory[i].refine);
9056 script_pushint(st, sd->inventory.u.items_inventory[i].refine);
9057 return SCRIPT_CMD_SUCCESS;
9060 ShowError("buildin_downrefitem: No item equipped at pos %d (CID=%d/AID=%d).\n", pos, sd->status.char_id, sd->status.account_id);
9061 script_pushint(st, -1);
9062 return SCRIPT_CMD_FAILURE;
9066 * Delete the item equipped at pos.
9067 * delequip <equipment slot>{,<char_id>};
9069 BUILDIN_FUNC(delequip) {
9075 pos = script_getnum(st,2);
9076 if (!script_charid2sd(3,sd)) {
9078 return SCRIPT_CMD_FAILURE;
9081 if (equip_index_check(pos))
9082 i = pc_checkequip(sd,equip_bitmask[pos]);
9084 pc_unequipitem(sd,i,3); //recalculate bonus
9085 ret = !(pc_delitem(sd,i,1,0,2,LOG_TYPE_SCRIPT));
9088 ShowError("buildin_delequip: No item equipped at pos %d (CID=%d/AID=%d).\n", pos, sd->status.char_id, sd->status.account_id);
9090 return SCRIPT_CMD_FAILURE;
9093 script_pushint(st,ret);
9094 return SCRIPT_CMD_SUCCESS;
9098 * Break the item equipped at pos.
9099 * breakequip <equipment slot>{,<char_id>};
9101 BUILDIN_FUNC(breakequip) {
9106 pos = script_getnum(st,2);
9107 if (!script_charid2sd(3,sd))
9108 return SCRIPT_CMD_FAILURE;
9110 if (equip_index_check(pos))
9111 i = pc_checkequip(sd,equip_bitmask[pos]);
9113 sd->inventory.u.items_inventory[i].attribute = 1;
9114 pc_unequipitem(sd,i,3);
9116 script_pushint(st,1);
9117 return SCRIPT_CMD_SUCCESS;
9120 ShowError("buildin_breakequip: No item equipped at pos %d (CID=%d/AID=%d).\n", pos, sd->status.char_id, sd->status.account_id);
9121 script_pushint(st,0);
9122 return SCRIPT_CMD_FAILURE;
9126 * statusup <stat>{,<char_id>};
9128 BUILDIN_FUNC(statusup)
9133 type = script_getnum(st,2);
9135 if (!script_charid2sd(3, sd))
9136 return SCRIPT_CMD_FAILURE;
9138 pc_statusup(sd, type, 1);
9140 return SCRIPT_CMD_SUCCESS;
9144 * statusup2 <stat>,<amount>{,<char_id>};
9146 BUILDIN_FUNC(statusup2)
9151 type=script_getnum(st,2);
9152 val=script_getnum(st,3);
9154 if (!script_charid2sd(4, sd))
9155 return SCRIPT_CMD_FAILURE;
9157 pc_statusup2(sd,type,val);
9159 return SCRIPT_CMD_SUCCESS;
9162 /// See 'doc/item_bonus.txt'
9164 /// bonus <bonus type>,<val1>;
9165 /// bonus2 <bonus type>,<val1>,<val2>;
9166 /// bonus3 <bonus type>,<val1>,<val2>,<val3>;
9167 /// bonus4 <bonus type>,<val1>,<val2>,<val3>,<val4>;
9168 /// bonus5 <bonus type>,<val1>,<val2>,<val3>,<val4>,<val5>;
9178 struct script_data *data;
9180 if( !script_rid2sd(sd) )
9181 return SCRIPT_CMD_SUCCESS; // no player attached
9183 type = script_getnum(st,2);
9186 case SP_AUTOSPELL_WHENHIT:
9187 case SP_AUTOSPELL_ONSKILL:
9190 case SP_SKILL_HEAL2:
9191 case SP_ADD_SKILL_BLOW:
9193 case SP_ADDEFF_ONSKILL:
9194 case SP_SKILL_USE_SP_RATE:
9195 case SP_SKILL_COOLDOWN:
9196 case SP_SKILL_FIXEDCAST:
9197 case SP_SKILL_VARIABLECAST:
9198 case SP_VARCASTRATE:
9199 case SP_FIXCASTRATE:
9200 case SP_SKILL_USE_SP:
9202 // these bonuses support skill names
9203 data = script_getdata(st, 3);
9204 get_val(st, data); // Convert into value in case of a variable
9205 val1 = ( data_isstring(data) ? skill_name2id(script_getstr(st,3)) : script_getnum(st,3) );
9208 val1 = script_getnum(st,3);
9212 switch( script_lastdata(st)-2 ) {
9214 pc_bonus(sd, type, val1);
9217 val2 = script_getnum(st,4);
9218 pc_bonus2(sd, type, val1, val2);
9221 val2 = script_getnum(st,4);
9222 val3 = script_getnum(st,5);
9223 pc_bonus3(sd, type, val1, val2, val3);
9226 data = script_getdata(st, 4);
9227 get_val(st, data); // Convert into value in case of a variable
9228 if( type == SP_AUTOSPELL_ONSKILL && data_isstring(data) )
9229 val2 = skill_name2id(script_getstr(st,4)); // 2nd value can be skill name
9231 val2 = script_getnum(st,4);
9233 val3 = script_getnum(st,5);
9234 val4 = script_getnum(st,6);
9235 pc_bonus4(sd, type, val1, val2, val3, val4);
9238 data = script_getdata(st, 4);
9239 get_val(st, data); // Convert into value in case of a variable
9240 if( type == SP_AUTOSPELL_ONSKILL && data_isstring(data) )
9241 val2 = skill_name2id(script_getstr(st,4)); // 2nd value can be skill name
9243 val2 = script_getnum(st,4);
9245 val3 = script_getnum(st,5);
9246 val4 = script_getnum(st,6);
9247 val5 = script_getnum(st,7);
9248 pc_bonus5(sd, type, val1, val2, val3, val4, val5);
9251 ShowDebug("buildin_bonus: unexpected number of arguments (%d)\n", (script_lastdata(st) - 1));
9255 return SCRIPT_CMD_SUCCESS;
9258 BUILDIN_FUNC(autobonus)
9260 unsigned int dur, pos;
9264 const char *bonus_script, *other_script = NULL;
9266 if( !script_rid2sd(sd) )
9267 return SCRIPT_CMD_SUCCESS; // no player attached
9269 if (current_equip_combo_pos)
9270 pos = current_equip_combo_pos;
9272 pos = sd->inventory.u.items_inventory[current_equip_item_index].equip;
9274 if((sd->state.autobonus&pos) == pos)
9275 return SCRIPT_CMD_SUCCESS;
9277 rate = script_getnum(st,3);
9278 dur = script_getnum(st,4);
9279 bonus_script = script_getstr(st,2);
9280 if( !rate || !dur || !pos || !bonus_script )
9281 return SCRIPT_CMD_SUCCESS;
9283 if( script_hasdata(st,5) )
9284 atk_type = script_getnum(st,5);
9285 if( script_hasdata(st,6) )
9286 other_script = script_getstr(st,6);
9288 if( pc_addautobonus(sd->autobonus,ARRAYLENGTH(sd->autobonus),
9289 bonus_script,rate,dur,atk_type,other_script,pos,false) )
9291 script_add_autobonus(bonus_script);
9293 script_add_autobonus(other_script);
9296 return SCRIPT_CMD_SUCCESS;
9299 BUILDIN_FUNC(autobonus2)
9301 unsigned int dur, pos;
9305 const char *bonus_script, *other_script = NULL;
9307 if( !script_rid2sd(sd) )
9308 return SCRIPT_CMD_SUCCESS; // no player attached
9310 if (current_equip_combo_pos)
9311 pos = current_equip_combo_pos;
9313 pos = sd->inventory.u.items_inventory[current_equip_item_index].equip;
9315 if((sd->state.autobonus&pos) == pos)
9316 return SCRIPT_CMD_SUCCESS;
9318 rate = script_getnum(st,3);
9319 dur = script_getnum(st,4);
9320 bonus_script = script_getstr(st,2);
9321 if( !rate || !dur || !pos || !bonus_script )
9322 return SCRIPT_CMD_SUCCESS;
9324 if( script_hasdata(st,5) )
9325 atk_type = script_getnum(st,5);
9326 if( script_hasdata(st,6) )
9327 other_script = script_getstr(st,6);
9329 if( pc_addautobonus(sd->autobonus2,ARRAYLENGTH(sd->autobonus2),
9330 bonus_script,rate,dur,atk_type,other_script,pos,false) )
9332 script_add_autobonus(bonus_script);
9334 script_add_autobonus(other_script);
9337 return SCRIPT_CMD_SUCCESS;
9340 BUILDIN_FUNC(autobonus3)
9342 unsigned int dur, pos;
9343 short rate,atk_type;
9345 const char *bonus_script, *other_script = NULL;
9346 struct script_data *data;
9348 if( !script_rid2sd(sd) )
9349 return SCRIPT_CMD_SUCCESS; // no player attached
9351 if (current_equip_combo_pos)
9352 pos = current_equip_combo_pos;
9354 pos = sd->inventory.u.items_inventory[current_equip_item_index].equip;
9356 if((sd->state.autobonus&pos) == pos)
9357 return SCRIPT_CMD_SUCCESS;
9359 rate = script_getnum(st,3);
9360 dur = script_getnum(st,4);
9361 data = script_getdata(st, 5);
9362 get_val(st, data); // Convert into value in case of a variable
9363 atk_type = ( data_isstring(data) ? skill_name2id(script_getstr(st,5)) : script_getnum(st,5) );
9364 bonus_script = script_getstr(st,2);
9365 if( !rate || !dur || !pos || !atk_type || !bonus_script )
9366 return SCRIPT_CMD_SUCCESS;
9368 if( script_hasdata(st,6) )
9369 other_script = script_getstr(st,6);
9371 if( pc_addautobonus(sd->autobonus3,ARRAYLENGTH(sd->autobonus3),
9372 bonus_script,rate,dur,atk_type,other_script,pos,true) )
9374 script_add_autobonus(bonus_script);
9376 script_add_autobonus(other_script);
9379 return SCRIPT_CMD_SUCCESS;
9382 /// Changes the level of a player skill.
9383 /// <flag> defaults to 1
9384 /// <flag>=0 : set the level of the skill
9385 /// <flag>=1 : set the temporary level of the skill
9386 /// <flag>=2 : add to the level of the skill
9388 /// skill <skill id>,<level>,<flag>
9389 /// skill <skill id>,<level>
9390 /// skill "<skill name>",<level>,<flag>
9391 /// skill "<skill name>",<level>
9396 int flag = ADDSKILL_TEMP;
9398 struct script_data *data;
9399 const char* command = script_getfuncname(st);
9401 if( !script_rid2sd(sd) )
9402 return SCRIPT_CMD_SUCCESS;// no player attached, report source
9404 if (strcmpi(command, "addtoskill") == 0)
9405 flag = ADDSKILL_TEMP_ADDLEVEL;
9407 data = script_getdata(st, 2);
9408 get_val(st, data); // Convert into value in case of a variable
9409 id = ( data_isstring(data) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
9410 level = script_getnum(st,3);
9411 if( script_hasdata(st,4) )
9412 flag = script_getnum(st,4);
9413 pc_skill(sd, id, level, (enum e_addskill_type)flag);
9415 return SCRIPT_CMD_SUCCESS;
9418 /// Increases the level of a guild skill.
9420 /// guildskill <skill id>,<amount>;
9421 /// guildskill "<skill name>",<amount>;
9422 BUILDIN_FUNC(guildskill)
9428 struct script_data *data;
9430 if( !script_rid2sd(sd) )
9431 return SCRIPT_CMD_SUCCESS;// no player attached, report source
9433 data = script_getdata(st, 2);
9434 get_val(st, data); // Convert into value in case of a variable
9435 id = ( data_isstring(data) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
9436 level = script_getnum(st,3);
9437 for( i=0; i < level; i++ )
9438 guild_skillup(sd, id);
9440 return SCRIPT_CMD_SUCCESS;
9443 /// Returns the level of the player skill.
9445 /// getskilllv(<skill id>) -> <level>
9446 /// getskilllv("<skill name>") -> <level>
9447 BUILDIN_FUNC(getskilllv)
9451 struct script_data *data;
9453 if( !script_rid2sd(sd) )
9454 return SCRIPT_CMD_SUCCESS;// no player attached, report source
9456 data = script_getdata(st, 2);
9457 get_val(st, data); // Convert into value in case of a variable
9458 id = ( data_isstring(data) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
9459 script_pushint(st, pc_checkskill(sd,id));
9461 return SCRIPT_CMD_SUCCESS;
9464 /// Returns the level of the guild skill.
9466 /// getgdskilllv(<guild id>,<skill id>) -> <level>
9467 /// getgdskilllv(<guild id>,"<skill name>") -> <level>
9468 BUILDIN_FUNC(getgdskilllv)
9473 struct script_data *data;
9475 guild_id = script_getnum(st,2);
9476 data = script_getdata(st, 3);
9477 get_val(st, data); // Convert into value in case of a variable
9478 skill_id = ( data_isstring(data) ? skill_name2id(script_getstr(st,3)) : script_getnum(st,3) );
9479 g = guild_search(guild_id);
9481 script_pushint(st, -1);
9483 script_pushint(st, guild_checkskill(g,skill_id));
9485 return SCRIPT_CMD_SUCCESS;
9488 /// Returns the 'basic_skill_check' setting.
9489 /// This config determines if the server checks the skill level of NV_BASIC
9490 /// before allowing the basic actions.
9492 /// basicskillcheck() -> <bool>
9493 BUILDIN_FUNC(basicskillcheck)
9495 script_pushint(st, battle_config.basic_skill_check);
9496 return SCRIPT_CMD_SUCCESS;
9499 /// Returns the GM level of the player.
9501 /// getgmlevel({<char_id>}) -> <level>
9502 BUILDIN_FUNC(getgmlevel)
9506 if (!script_charid2sd(2,sd))
9507 return SCRIPT_CMD_FAILURE;
9508 script_pushint(st, pc_get_group_level(sd));
9509 return SCRIPT_CMD_SUCCESS;
9512 /// Returns the group ID of the player.
9514 /// getgroupid({<char_id>}) -> <int>
9515 BUILDIN_FUNC(getgroupid)
9519 if (!script_charid2sd(2,sd))
9520 return SCRIPT_CMD_FAILURE;
9521 script_pushint(st, pc_get_group_id(sd));
9522 return SCRIPT_CMD_SUCCESS;
9525 /// Terminates the execution of this script instance.
9532 sd = map_id2sd(st->rid);
9536 if (st->stack->defsp >= 1 && st->stack->stack_data[st->stack->defsp-1].type == C_RETINFO) {
9539 for(i = 0; i < st->stack->sp; i++) {
9540 if (st->stack->stack_data[i].type == C_RETINFO) { // Grab the first, aka the original
9541 struct script_retinfo *ri = st->stack->stack_data[i].u.ri;
9542 st->script = ri->script;
9548 if( st->mes_active )
9552 if (sd->state.callshop == 0)
9553 clif_scriptclose(sd, st->oid); // If a menu/select/prompt is active, close it.
9555 sd->state.callshop = 0;
9558 return SCRIPT_CMD_SUCCESS;
9561 /// Checks if the player has that effect state (option).
9563 /// checkoption(<option>{,<char_id>}) -> <bool>
9564 BUILDIN_FUNC(checkoption)
9569 if (!script_charid2sd(3,sd))
9570 return SCRIPT_CMD_FAILURE;
9572 option = script_getnum(st,2);
9573 if( sd->sc.option&option )
9574 script_pushint(st, 1);
9576 script_pushint(st, 0);
9578 return SCRIPT_CMD_SUCCESS;
9581 /// Checks if the player is in that body state (opt1).
9583 /// checkoption1(<opt1>{,<char_id>}) -> <bool>
9584 BUILDIN_FUNC(checkoption1)
9589 if (!script_charid2sd(3,sd))
9590 return SCRIPT_CMD_FAILURE;
9592 opt1 = script_getnum(st,2);
9593 if( sd->sc.opt1 == opt1 )
9594 script_pushint(st, 1);
9596 script_pushint(st, 0);
9598 return SCRIPT_CMD_SUCCESS;
9601 /// Checks if the player has that health state (opt2).
9603 /// checkoption2(<opt2>{,<char_id>}) -> <bool>
9604 BUILDIN_FUNC(checkoption2)
9609 if (!script_charid2sd(3,sd))
9610 return SCRIPT_CMD_FAILURE;
9612 opt2 = script_getnum(st,2);
9613 if( sd->sc.opt2&opt2 )
9614 script_pushint(st, 1);
9616 script_pushint(st, 0);
9618 return SCRIPT_CMD_SUCCESS;
9621 /// Changes the effect state (option) of the player.
9622 /// <flag> defaults to 1
9623 /// <flag>=0 : removes the option
9624 /// <flag>=other : adds the option
9626 /// setoption <option>{,<flag>{,<char_id>}};
9627 BUILDIN_FUNC(setoption)
9633 if (!script_charid2sd(4,sd))
9634 return SCRIPT_CMD_FAILURE;
9636 option = script_getnum(st,2);
9637 if( script_hasdata(st,3) )
9638 flag = script_getnum(st,3);
9639 else if( !option ){// Request to remove everything.
9641 option = OPTION_FALCON|OPTION_RIDING;
9643 option |= OPTION_CART;
9646 if( flag ){// Add option
9647 if( option&OPTION_WEDDING && !battle_config.wedding_modifydisplay )
9648 option &= ~OPTION_WEDDING;// Do not show the wedding sprites
9649 pc_setoption(sd, sd->sc.option|option);
9650 } else// Remove option
9651 pc_setoption(sd, sd->sc.option&~option);
9653 return SCRIPT_CMD_SUCCESS;
9656 /// Returns if the player has a cart.
9658 /// checkcart({char_id}) -> <bool>
9661 BUILDIN_FUNC(checkcart)
9665 if (!script_charid2sd(2,sd))
9666 return SCRIPT_CMD_FAILURE;
9668 if( pc_iscarton(sd) )
9669 script_pushint(st, 1);
9671 script_pushint(st, 0);
9673 return SCRIPT_CMD_SUCCESS;
9676 /// Sets the cart of the player.
9677 /// <type> defaults to 1
9678 /// <type>=0 : removes the cart
9679 /// <type>=1 : Normal cart
9680 /// <type>=2 : Wooden cart
9681 /// <type>=3 : Covered cart with flowers and ferns
9682 /// <type>=4 : Wooden cart with a Panda doll on the back
9683 /// <type>=5 : Normal cart with bigger wheels, a roof and a banner on the back
9685 /// setcart {<type>{,<char_id>}};
9686 BUILDIN_FUNC(setcart)
9691 if (!script_charid2sd(3,sd))
9692 return SCRIPT_CMD_FAILURE;
9694 if( script_hasdata(st,2) )
9695 type = script_getnum(st,2);
9696 pc_setcart(sd, type);
9698 return SCRIPT_CMD_SUCCESS;
9701 /// Returns if the player has a falcon.
9703 /// checkfalcon({char_id}) -> <bool>
9706 BUILDIN_FUNC(checkfalcon)
9710 if (!script_charid2sd(2,sd))
9711 return SCRIPT_CMD_FAILURE;
9713 if( pc_isfalcon(sd) )
9714 script_pushint(st, 1);
9716 script_pushint(st, 0);
9718 return SCRIPT_CMD_SUCCESS;
9721 /// Sets if the player has a falcon or not.
9722 /// <flag> defaults to 1
9724 /// setfalcon {<flag>{,<char_id>}};
9725 BUILDIN_FUNC(setfalcon)
9730 if (!script_charid2sd(3,sd))
9731 return SCRIPT_CMD_FAILURE;
9733 if( script_hasdata(st,2) )
9734 flag = script_getnum(st,2);
9736 pc_setfalcon(sd, flag);
9738 return SCRIPT_CMD_SUCCESS;
9741 /// Returns if the player is riding.
9743 /// checkriding({char_id}) -> <bool>
9746 BUILDIN_FUNC(checkriding)
9750 if (!script_charid2sd(2,sd))
9751 return SCRIPT_CMD_FAILURE;
9753 if( pc_isriding(sd) )
9754 script_pushint(st, 1);
9756 script_pushint(st, 0);
9758 return SCRIPT_CMD_SUCCESS;
9761 /// Sets if the player is riding.
9762 /// <flag> defaults to 1
9764 /// setriding {<flag>{,<char_id>}};
9765 BUILDIN_FUNC(setriding)
9770 if (!script_charid2sd(3,sd))
9771 return SCRIPT_CMD_FAILURE;
9773 if( script_hasdata(st,2) )
9774 flag = script_getnum(st,2);
9775 pc_setriding(sd, flag);
9777 return SCRIPT_CMD_SUCCESS;
9780 /// Returns if the player has a warg.
9782 /// checkwug({char_id}) -> <bool>
9784 BUILDIN_FUNC(checkwug)
9788 if (!script_charid2sd(2,sd))
9789 return SCRIPT_CMD_FAILURE;
9791 if( pc_iswug(sd) || pc_isridingwug(sd) )
9792 script_pushint(st, 1);
9794 script_pushint(st, 0);
9796 return SCRIPT_CMD_SUCCESS;
9799 /// Returns if the player is wearing MADO Gear.
9801 /// checkmadogear({<char_id>}) -> <bool>
9803 BUILDIN_FUNC(checkmadogear)
9807 if (!script_charid2sd(2,sd))
9808 return SCRIPT_CMD_FAILURE;
9810 if( pc_ismadogear(sd) )
9811 script_pushint(st, 1);
9813 script_pushint(st, 0);
9815 return SCRIPT_CMD_SUCCESS;
9818 /// Sets if the player is riding MADO Gear.
9819 /// <flag> defaults to 1
9821 /// setmadogear {<flag>{,<char_id>}};
9822 BUILDIN_FUNC(setmadogear)
9827 if (!script_charid2sd(3,sd))
9828 return SCRIPT_CMD_FAILURE;
9830 if( script_hasdata(st,2) )
9831 flag = script_getnum(st,2);
9832 pc_setmadogear(sd, flag);
9834 return SCRIPT_CMD_SUCCESS;
9837 /// Sets the save point of the player.
9839 /// save "<map name>",<x>,<y>{,{<range x>,<range y>,}<char_id>}
9840 /// savepoint "<map name>",<x>,<y>{,{<range x>,<range y>,}<char_id>}
9841 BUILDIN_FUNC(savepoint)
9843 int x, y, m, cid_pos = 5;
9844 unsigned short map_idx;
9848 if (script_lastdata(st) > 5)
9851 if (!script_charid2sd(cid_pos,sd))
9852 return SCRIPT_CMD_FAILURE;// no player attached, report source
9854 str = script_getstr(st, 2);
9856 map_idx = mapindex_name2id(str);
9858 return SCRIPT_CMD_FAILURE;
9860 x = script_getnum(st,3);
9861 y = script_getnum(st,4);
9862 m = map_mapindex2mapid(map_idx);
9865 int dx = script_getnum(st,5), dy = script_getnum(st,6),
9866 x1 = x + dx, y1 = y + dy,
9867 x0 = x - dx, y0 = y - dy;
9870 x = x0 + rnd()%(x1-x0+1);
9871 y = y0 + rnd()%(y1-y0+1);
9872 } while (m != -1 && (--n) > 0 && !map_getcell(m, x, y, CELL_CHKPASS));
9875 // Check for valid coordinates if map in local map-server
9876 if (m != -1 && !map_getcell(m, x, y, CELL_CHKPASS)) {
9877 ShowError("buildin_savepoint: Invalid coordinates %d,%d at map %s.\n", x, y, str);
9878 return SCRIPT_CMD_FAILURE;
9881 pc_setsavepoint(sd, map_idx, x, y);
9883 return SCRIPT_CMD_SUCCESS;
9886 /*==========================================
9887 * GetTimeTick(0: System Tick, 1: Time Second Tick, 2: Unix epoch)
9888 *------------------------------------------*/
9889 BUILDIN_FUNC(gettimetick) /* Asgard Version */
9895 type=script_getnum(st,2);
9899 //type 2:(Get the number of seconds elapsed since 00:00 hours, Jan 1, 1970 UTC
9900 // from the system clock.)
9901 script_pushint(st,(int)time(NULL));
9904 //type 1:(Second Ticks: 0-86399, 00:00:00-23:59:59)
9906 t=localtime(&timer);
9907 script_pushint(st,((t->tm_hour)*3600+(t->tm_min)*60+t->tm_sec));
9911 //type 0:(System Ticks)
9912 script_pushint(st,gettick());
9915 return SCRIPT_CMD_SUCCESS;
9918 /*==========================================
9921 * Returns the current value of a certain date type.
9922 * Possible types are:
9923 * - DT_SECOND Current seconds
9924 * - DT_MINUTE Current minute
9925 * - DT_HOUR Current hour
9926 * - DT_DAYOFWEEK Day of current week
9927 * - DT_DAYOFMONTH Day of current month
9928 * - DT_MONTH Current month
9929 * - DT_YEAR Current year
9930 * - DT_DAYOFYEAR Day of current year
9932 * If none of the above types is supplied -1 will be returned to the script
9933 * and the script source will be reported into the mapserver console.
9934 *------------------------------------------*/
9935 BUILDIN_FUNC(gettime)
9939 type = script_getnum(st,2);
9941 if( type <= DT_MIN || type >= DT_MAX ){
9942 ShowError( "buildin_gettime: Invalid date type %d\n", type );
9943 script_reportsrc(st);
9944 script_pushint(st,-1);
9946 script_pushint(st,date_get((enum e_date_type)type));
9949 return SCRIPT_CMD_SUCCESS;
9953 * Returns the current server time or the provided time in a readable format.
9954 * gettimestr(<"time_format">,<max_length>{,<time_tick>});
9956 BUILDIN_FUNC(gettimestr)
9963 fmtstr = script_getstr(st,2);
9964 maxlen = script_getnum(st,3);
9966 if (script_hasdata(st, 4)) {
9967 if (script_getnum(st, 4) < 0) {
9968 ShowWarning("buildin_gettimestr: a positive value must be supplied to be valid.\n");
9969 return SCRIPT_CMD_FAILURE;
9971 now = (time_t)script_getnum(st, 4);
9975 tmpstr = (char *)aMalloc((maxlen+1)*sizeof(char));
9976 strftime(tmpstr,maxlen,fmtstr,localtime(&now));
9977 tmpstr[maxlen] = '\0';
9979 script_pushstr(st,tmpstr);
9980 return SCRIPT_CMD_SUCCESS;
9983 /*==========================================
9984 * Open player storage
9985 *------------------------------------------*/
9986 BUILDIN_FUNC(openstorage)
9990 if( !script_rid2sd(sd) )
9991 return SCRIPT_CMD_SUCCESS;
9993 storage_storageopen(sd);
9994 return SCRIPT_CMD_SUCCESS;
9997 BUILDIN_FUNC(guildopenstorage)
10002 if( !script_rid2sd(sd) )
10003 return SCRIPT_CMD_SUCCESS;
10005 ret = storage_guild_storageopen(sd);
10006 script_pushint(st,ret);
10007 return SCRIPT_CMD_SUCCESS;
10010 /*==========================================
10011 * Make player use a skill trought item usage
10012 *------------------------------------------*/
10013 /// itemskill <skill id>,<level>
10014 /// itemskill "<skill name>",<level>
10015 BUILDIN_FUNC(itemskill)
10019 bool keep_requirement;
10021 struct script_data *data;
10023 if( !script_rid2sd(sd) || sd->ud.skilltimer != INVALID_TIMER )
10024 return SCRIPT_CMD_SUCCESS;
10026 data = script_getdata(st, 2);
10027 get_val(st, data); // Convert into value in case of a variable
10028 id = ( data_isstring(data) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
10029 lv = script_getnum(st,3);
10030 if (script_hasdata(st, 4)) {
10031 keep_requirement = (script_getnum(st, 4) != 0);
10033 keep_requirement = false;
10037 sd->skillitemlv=lv;
10038 sd->skillitem_keep_requirement = keep_requirement;
10039 clif_item_skill(sd,id,lv);
10040 return SCRIPT_CMD_SUCCESS;
10042 /*==========================================
10043 * Attempt to create an item
10044 *------------------------------------------*/
10045 BUILDIN_FUNC(produce)
10050 if( !script_rid2sd(sd) )
10051 return SCRIPT_CMD_SUCCESS;
10053 trigger=script_getnum(st,2);
10054 clif_skill_produce_mix_list(sd, -1, trigger);
10055 return SCRIPT_CMD_SUCCESS;
10057 /*==========================================
10059 *------------------------------------------*/
10060 BUILDIN_FUNC(cooking)
10065 if( !script_rid2sd(sd) )
10066 return SCRIPT_CMD_SUCCESS;
10068 trigger=script_getnum(st,2);
10069 clif_cooking_list(sd, trigger, AM_PHARMACY, 1, 1);
10070 return SCRIPT_CMD_SUCCESS;
10073 /*==========================================
10075 *------------------------------------------*/
10076 BUILDIN_FUNC(makepet)
10081 if( !script_rid2sd(sd) )
10082 return SCRIPT_CMD_SUCCESS;
10084 id=script_getnum(st,2);
10086 pet_id = search_petDB_index(id, PET_CLASS);
10089 pet_id = search_petDB_index(id, PET_EGG);
10090 if (pet_id >= 0 && sd) {
10091 sd->catch_target_class = pet_db[pet_id].class_;
10092 intif_create_pet(sd->status.account_id, sd->status.char_id, pet_db[pet_id].class_, mob_db(pet_db[pet_id].class_)->lv, pet_db[pet_id].EggID, 0, pet_db[pet_id].intimate, 100, 0, 1, pet_db[pet_id].jname);
10095 return SCRIPT_CMD_SUCCESS;
10099 * Give player exp base,job * quest_exp_rate/100
10100 * getexp <base xp>,<job xp>{,<char_id>};
10102 BUILDIN_FUNC(getexp)
10108 if (!script_charid2sd(4,sd))
10109 return SCRIPT_CMD_FAILURE;
10111 base=script_getnum(st,2);
10112 job =script_getnum(st,3);
10113 if(base<0 || job<0)
10114 return SCRIPT_CMD_SUCCESS;
10116 // bonus for npc-given exp
10117 bonus = battle_config.quest_exp_rate / 100.;
10119 base = (int) cap_value(base * bonus, 0, INT_MAX);
10121 job = (int) cap_value(job * bonus, 0, INT_MAX);
10123 pc_gainexp(sd, NULL, base, job, 1);
10125 return SCRIPT_CMD_SUCCESS;
10128 /*==========================================
10129 * Gain guild exp [Celest]
10130 *------------------------------------------*/
10131 BUILDIN_FUNC(guildgetexp)
10136 if( !script_rid2sd(sd) )
10137 return SCRIPT_CMD_SUCCESS;
10139 exp = script_getnum(st,2);
10141 return SCRIPT_CMD_SUCCESS;
10142 if(sd && sd->status.guild_id > 0)
10143 guild_getexp (sd, exp);
10145 return SCRIPT_CMD_SUCCESS;
10148 /*==========================================
10149 * Changes the guild master of a guild [Skotlex]
10150 *------------------------------------------*/
10151 BUILDIN_FUNC(guildchangegm)
10157 guild_id = script_getnum(st,2);
10158 name = script_getstr(st,3);
10159 sd=map_nick2sd(name,false);
10162 script_pushint(st,0);
10164 script_pushint(st,guild_gm_change(guild_id, sd->status.char_id));
10166 return SCRIPT_CMD_SUCCESS;
10169 /*==========================================
10171 * *monster "<map name>",<x>,<y>,"<name to show>",<mob id>,<amount>{,"<event label>",<size>,<ai>};
10172 *------------------------------------------*/
10173 BUILDIN_FUNC(monster)
10175 const char* mapn = script_getstr(st,2);
10176 int x = script_getnum(st,3);
10177 int y = script_getnum(st,4);
10178 const char* str = script_getstr(st,5);
10179 int class_ = script_getnum(st,6);
10180 int amount = script_getnum(st,7);
10181 const char* event = "";
10182 unsigned int size = SZ_SMALL;
10183 enum mob_ai ai = AI_NONE;
10185 struct map_session_data* sd;
10189 if (script_hasdata(st, 8)) {
10190 event = script_getstr(st, 8);
10191 check_event(st, event);
10194 if (script_hasdata(st, 9)) {
10195 size = script_getnum(st, 9);
10196 if (size > SZ_BIG) {
10197 ShowWarning("buildin_monster: Attempted to spawn non-existing size %d for monster class %d\n", size, class_);
10198 return SCRIPT_CMD_FAILURE;
10202 if (script_hasdata(st, 10)) {
10203 ai = static_cast<enum mob_ai>(script_getnum(st, 10));
10204 if (ai >= AI_MAX) {
10205 ShowWarning("buildin_monster: Attempted to spawn non-existing ai %d for monster class %d\n", ai, class_);
10206 return SCRIPT_CMD_FAILURE;
10210 if (class_ >= 0 && !mobdb_checkid(class_)) {
10211 ShowWarning("buildin_monster: Attempted to spawn non-existing monster class %d\n", class_);
10212 return SCRIPT_CMD_FAILURE;
10215 sd = map_id2sd(st->rid);
10217 if (sd && strcmp(mapn, "this") == 0)
10220 m = map_mapname2mapid(mapn);
10222 for(i = 0; i < amount; i++) { //not optimised
10223 int mobid = mob_once_spawn(sd, m, x, y, str, class_, 1, event, size, ai);
10226 mapreg_setreg(reference_uid(add_str("$@mobid"), i), mobid);
10229 return SCRIPT_CMD_SUCCESS;
10232 /*==========================================
10233 * Request List of Monster Drops
10234 *------------------------------------------*/
10235 BUILDIN_FUNC(getmobdrops)
10237 int class_ = script_getnum(st,2);
10239 struct mob_db *mob;
10241 if( !mobdb_checkid(class_) )
10243 script_pushint(st, 0);
10244 return SCRIPT_CMD_SUCCESS;
10247 mob = mob_db(class_);
10249 for( i = 0; i < MAX_MOB_DROP_TOTAL; i++ )
10251 if( mob->dropitem[i].nameid < 1 )
10253 if( itemdb_exists(mob->dropitem[i].nameid) == NULL )
10256 mapreg_setreg(reference_uid(add_str("$@MobDrop_item"), j), mob->dropitem[i].nameid);
10257 mapreg_setreg(reference_uid(add_str("$@MobDrop_rate"), j), mob->dropitem[i].p);
10262 mapreg_setreg(add_str("$@MobDrop_count"), j);
10263 script_pushint(st, 1);
10265 return SCRIPT_CMD_SUCCESS;
10268 /*==========================================
10269 * Spawn a monster in a random location
10270 * in x0,x1,y0,y1 area.
10271 *------------------------------------------*/
10272 BUILDIN_FUNC(areamonster)
10274 const char* mapn = script_getstr(st,2);
10275 int x0 = script_getnum(st,3);
10276 int y0 = script_getnum(st,4);
10277 int x1 = script_getnum(st,5);
10278 int y1 = script_getnum(st,6);
10279 const char* str = script_getstr(st,7);
10280 int class_ = script_getnum(st,8);
10281 int amount = script_getnum(st,9);
10282 const char* event = "";
10283 unsigned int size = SZ_SMALL;
10284 enum mob_ai ai = AI_NONE;
10286 struct map_session_data* sd;
10290 if (script_hasdata(st,10)) {
10291 event = script_getstr(st, 10);
10292 check_event(st, event);
10295 if (script_hasdata(st, 11)) {
10296 size = script_getnum(st, 11);
10298 ShowWarning("buildin_monster: Attempted to spawn non-existing size %d for monster class %d\n", size, class_);
10299 return SCRIPT_CMD_FAILURE;
10303 if (script_hasdata(st, 12)) {
10304 ai = static_cast<enum mob_ai>(script_getnum(st, 12));
10305 if (ai >= AI_MAX) {
10306 ShowWarning("buildin_monster: Attempted to spawn non-existing ai %d for monster class %d\n", ai, class_);
10307 return SCRIPT_CMD_FAILURE;
10311 sd = map_id2sd(st->rid);
10313 if (sd && strcmp(mapn, "this") == 0)
10316 m = map_mapname2mapid(mapn);
10318 for(i = 0; i < amount; i++) { //not optimised
10319 int mobid = mob_once_spawn_area(sd, m, x0, y0, x1, y1, str, class_, 1, event, size, ai);
10322 mapreg_setreg(reference_uid(add_str("$@mobid"), i), mobid);
10325 return SCRIPT_CMD_SUCCESS;
10328 /*==========================================
10329 * KillMonster subcheck, verify if mob to kill ain't got an even to handle, could be force kill by allflag
10330 *------------------------------------------*/
10331 static int buildin_killmonster_sub_strip(struct block_list *bl,va_list ap)
10332 { //same fix but with killmonster instead - stripping events from mobs.
10333 TBL_MOB* md = (TBL_MOB*)bl;
10334 char *event=va_arg(ap,char *);
10335 int allflag=va_arg(ap,int);
10337 md->state.npc_killmonster = 1;
10340 if(strcmp(event,md->npc_event)==0)
10346 md->state.npc_killmonster = 0;
10347 return SCRIPT_CMD_SUCCESS;
10350 static int buildin_killmonster_sub(struct block_list *bl,va_list ap)
10352 TBL_MOB* md = (TBL_MOB*)bl;
10353 char *event=va_arg(ap,char *);
10354 int allflag=va_arg(ap,int);
10357 if(strcmp(event,md->npc_event)==0)
10363 return SCRIPT_CMD_SUCCESS;
10366 BUILDIN_FUNC(killmonster)
10368 const char *mapname,*event;
10370 mapname=script_getstr(st,2);
10371 event=script_getstr(st,3);
10372 if(strcmp(event,"All")==0)
10375 check_event(st, event);
10377 if( (m=map_mapname2mapid(mapname))<0 )
10378 return SCRIPT_CMD_SUCCESS;
10380 if( script_hasdata(st,4) ) {
10381 if ( script_getnum(st,4) == 1 ) {
10382 map_foreachinmap(buildin_killmonster_sub, m, BL_MOB, event ,allflag);
10383 return SCRIPT_CMD_SUCCESS;
10387 map_freeblock_lock();
10388 map_foreachinmap(buildin_killmonster_sub_strip, m, BL_MOB, event ,allflag);
10389 map_freeblock_unlock();
10390 return SCRIPT_CMD_SUCCESS;
10393 static int buildin_killmonsterall_sub_strip(struct block_list *bl,va_list ap)
10394 { //Strips the event from the mob if it's killed the old method.
10395 struct mob_data *md;
10397 md = BL_CAST(BL_MOB, bl);
10398 if (md->npc_event[0])
10399 md->npc_event[0] = 0;
10404 static int buildin_killmonsterall_sub(struct block_list *bl,va_list ap)
10409 BUILDIN_FUNC(killmonsterall)
10411 const char *mapname;
10413 mapname=script_getstr(st,2);
10415 if( (m = map_mapname2mapid(mapname))<0 )
10416 return SCRIPT_CMD_SUCCESS;
10418 if( script_hasdata(st,3) ) {
10419 if ( script_getnum(st,3) == 1 ) {
10420 map_foreachinmap(buildin_killmonsterall_sub,m,BL_MOB);
10421 return SCRIPT_CMD_SUCCESS;
10425 map_foreachinmap(buildin_killmonsterall_sub_strip,m,BL_MOB);
10426 return SCRIPT_CMD_SUCCESS;
10429 /*==========================================
10430 * Creates a clone of a player.
10431 * clone map, x, y, event, char_id, master_id, mode, flag, duration
10432 *------------------------------------------*/
10433 BUILDIN_FUNC(clone)
10435 TBL_PC *sd, *msd=NULL;
10436 uint32 char_id, master_id = 0, x, y, flag = 0;
10438 enum e_mode mode = MD_NONE;
10440 unsigned int duration = 0;
10441 const char *mapname,*event;
10443 mapname=script_getstr(st,2);
10444 x=script_getnum(st,3);
10445 y=script_getnum(st,4);
10446 event=script_getstr(st,5);
10447 char_id=script_getnum(st,6);
10449 if( script_hasdata(st,7) )
10450 master_id=script_getnum(st,7);
10452 if( script_hasdata(st,8) )
10453 mode=static_cast<e_mode>(script_getnum(st,8));
10455 if( script_hasdata(st,9) )
10456 flag=script_getnum(st,9);
10458 if( script_hasdata(st,10) )
10459 duration=script_getnum(st,10);
10461 check_event(st, event);
10463 m = map_mapname2mapid(mapname);
10465 return SCRIPT_CMD_SUCCESS;
10467 sd = map_charid2sd(char_id);
10470 msd = map_charid2sd(master_id);
10472 master_id = msd->bl.id;
10476 if (sd) //Return ID of newly crafted clone.
10477 script_pushint(st,mob_clone_spawn(sd, m, x, y, event, master_id, mode, flag, 1000*duration));
10478 else //Failed to create clone.
10479 script_pushint(st,0);
10481 return SCRIPT_CMD_SUCCESS;
10484 /*==========================================
10485 *------------------------------------------*/
10486 BUILDIN_FUNC(doevent)
10489 struct map_session_data* sd;
10491 if( !script_rid2sd(sd) )
10492 return SCRIPT_CMD_SUCCESS;
10494 event = script_getstr(st,2);
10496 check_event(st, event);
10497 npc_event(sd, event, 0);
10498 return SCRIPT_CMD_SUCCESS;
10501 /*==========================================
10502 *------------------------------------------*/
10503 BUILDIN_FUNC(donpcevent)
10505 const char* event = script_getstr(st,2);
10506 check_event(st, event);
10507 if( !npc_event_do(event) ) {
10508 struct npc_data * nd = map_id2nd(st->oid);
10509 ShowDebug("NPCEvent '%s' not found! (source: %s)\n",event,nd?nd->name:"Unknown");
10510 script_pushint(st, 0);
10512 script_pushint(st, 1);
10513 return SCRIPT_CMD_SUCCESS;
10516 /// for Aegis compatibility
10517 /// basically a specialized 'donpcevent', with the event specified as two arguments instead of one
10518 BUILDIN_FUNC(cmdothernpc) // Added by RoVeRT
10520 const char* npc = script_getstr(st,2);
10521 const char* command = script_getstr(st,3);
10522 char event[EVENT_NAME_LENGTH];
10524 safesnprintf(event,EVENT_NAME_LENGTH, "%s::%s%s",npc,script_config.oncommand_event_name,command);
10525 check_event(st, event);
10527 if( npc_event_do(event) ){
10528 script_pushint(st, true);
10530 struct npc_data * nd = map_id2nd(st->oid);
10531 ShowDebug("NPCEvent '%s' not found! (source: %s)\n", event, nd ? nd->name : "Unknown");
10532 script_pushint(st, false);
10535 return SCRIPT_CMD_SUCCESS;
10538 /*==========================================
10539 *------------------------------------------*/
10540 BUILDIN_FUNC(addtimer)
10546 if( !script_rid2sd(sd) )
10547 return SCRIPT_CMD_SUCCESS;
10549 tick = script_getnum(st,2);
10550 event = script_getstr(st, 3);
10552 check_event(st, event);
10554 if (!pc_addeventtimer(sd,tick,event)) {
10555 ShowWarning("buildin_addtimer: Event timer is full, can't add new event timer. (cid:%d timer:%s)\n",sd->status.char_id,event);
10556 return SCRIPT_CMD_FAILURE;
10558 return SCRIPT_CMD_SUCCESS;
10561 /*==========================================
10562 *------------------------------------------*/
10563 BUILDIN_FUNC(deltimer)
10568 if( !script_rid2sd(sd) )
10569 return SCRIPT_CMD_SUCCESS;
10571 event=script_getstr(st, 2);
10573 check_event(st, event);
10574 pc_deleventtimer(sd,event);
10575 return SCRIPT_CMD_SUCCESS;
10577 /*==========================================
10578 *------------------------------------------*/
10579 BUILDIN_FUNC(addtimercount)
10585 if( !script_rid2sd(sd) )
10586 return SCRIPT_CMD_SUCCESS;
10588 tick=script_getnum(st,2);
10589 event=script_getstr(st,3);
10591 check_event(st, event);
10592 pc_addeventtimercount(sd,event,tick);
10593 return SCRIPT_CMD_SUCCESS;
10596 /*==========================================
10597 *------------------------------------------*/
10598 BUILDIN_FUNC(initnpctimer)
10600 struct npc_data *nd;
10603 if( script_hasdata(st,3) )
10604 { //Two arguments: NPC name and attach flag.
10605 nd = npc_name2id(script_getstr(st, 2));
10606 flag = script_getnum(st,3);
10608 else if( script_hasdata(st,2) )
10609 { //Check if argument is numeric (flag) or string (npc name)
10610 struct script_data *data;
10611 data = script_getdata(st,2);
10613 if( data_isstring(data) ) //NPC name
10614 nd = npc_name2id(conv_str(st, data));
10615 else if( data_isint(data) ) //Flag
10617 nd = (struct npc_data *)map_id2bl(st->oid);
10618 flag = conv_num(st,data);
10622 ShowError("initnpctimer: invalid argument type #1 (needs be int or string)).\n");
10623 return SCRIPT_CMD_FAILURE;
10627 nd = (struct npc_data *)map_id2bl(st->oid);
10630 return SCRIPT_CMD_SUCCESS;
10631 if( flag ) //Attach
10634 if( !script_rid2sd(sd) )
10635 return SCRIPT_CMD_SUCCESS;
10636 nd->u.scr.rid = sd->bl.id;
10639 nd->u.scr.timertick = 0;
10640 npc_settimerevent_tick(nd,0);
10641 npc_timerevent_start(nd, st->rid);
10642 return SCRIPT_CMD_SUCCESS;
10645 /*==========================================
10646 *------------------------------------------*/
10647 BUILDIN_FUNC(startnpctimer)
10649 struct npc_data *nd;
10652 if( script_hasdata(st,3) )
10653 { //Two arguments: NPC name and attach flag.
10654 nd = npc_name2id(script_getstr(st, 2));
10655 flag = script_getnum(st,3);
10657 else if( script_hasdata(st,2) )
10658 { //Check if argument is numeric (flag) or string (npc name)
10659 struct script_data *data;
10660 data = script_getdata(st,2);
10662 if( data_isstring(data) ) //NPC name
10663 nd = npc_name2id(conv_str(st, data));
10664 else if( data_isint(data) ) //Flag
10666 nd = (struct npc_data *)map_id2bl(st->oid);
10667 flag = conv_num(st,data);
10671 ShowError("initnpctimer: invalid argument type #1 (needs be int or string)).\n");
10672 return SCRIPT_CMD_FAILURE;
10676 nd=(struct npc_data *)map_id2bl(st->oid);
10679 return SCRIPT_CMD_SUCCESS;
10680 if( flag ) //Attach
10683 if( !script_rid2sd(sd) )
10684 return SCRIPT_CMD_SUCCESS;
10685 nd->u.scr.rid = sd->bl.id;
10688 npc_timerevent_start(nd, st->rid);
10689 return SCRIPT_CMD_SUCCESS;
10691 /*==========================================
10692 *------------------------------------------*/
10693 BUILDIN_FUNC(stopnpctimer)
10695 struct npc_data *nd;
10698 if( script_hasdata(st,3) )
10699 { //Two arguments: NPC name and attach flag.
10700 nd = npc_name2id(script_getstr(st, 2));
10701 flag = script_getnum(st,3);
10703 else if( script_hasdata(st,2) )
10704 { //Check if argument is numeric (flag) or string (npc name)
10705 struct script_data *data;
10706 data = script_getdata(st,2);
10708 if( data_isstring(data) ) //NPC name
10709 nd = npc_name2id(conv_str(st, data));
10710 else if( data_isint(data) ) //Flag
10712 nd = (struct npc_data *)map_id2bl(st->oid);
10713 flag = conv_num(st,data);
10717 ShowError("initnpctimer: invalid argument type #1 (needs be int or string)).\n");
10718 return SCRIPT_CMD_FAILURE;
10722 nd=(struct npc_data *)map_id2bl(st->oid);
10725 return SCRIPT_CMD_SUCCESS;
10726 if( flag ) //Detach
10729 npc_timerevent_stop(nd);
10730 return SCRIPT_CMD_SUCCESS;
10733 /*==========================================
10734 *------------------------------------------*/
10735 BUILDIN_FUNC(getnpctimer)
10737 struct npc_data *nd;
10739 int type = script_getnum(st,2);
10742 if( script_hasdata(st,3) )
10743 nd = npc_name2id(script_getstr(st,3));
10745 nd = (struct npc_data *)map_id2bl(st->oid);
10747 if( !nd || nd->bl.type != BL_NPC )
10749 script_pushint(st,0);
10750 ShowError("getnpctimer: Invalid NPC.\n");
10751 return SCRIPT_CMD_FAILURE;
10756 case 0: val = npc_gettimerevent_tick(nd); break;
10758 if( nd->u.scr.rid )
10760 sd = map_id2sd(nd->u.scr.rid);
10763 ShowError("buildin_getnpctimer: Attached player not found!\n");
10766 val = (sd->npc_timer_id != INVALID_TIMER);
10769 val = (nd->u.scr.timerid != INVALID_TIMER);
10771 case 2: val = nd->u.scr.timeramount; break;
10774 script_pushint(st,val);
10775 return SCRIPT_CMD_SUCCESS;
10778 /*==========================================
10779 *------------------------------------------*/
10780 BUILDIN_FUNC(setnpctimer)
10783 struct npc_data *nd;
10785 tick = script_getnum(st,2);
10786 if( script_hasdata(st,3) )
10787 nd = npc_name2id(script_getstr(st,3));
10789 nd = (struct npc_data *)map_id2bl(st->oid);
10791 if( !nd || nd->bl.type != BL_NPC )
10793 script_pushint(st,1);
10794 ShowError("setnpctimer: Invalid NPC.\n");
10795 return SCRIPT_CMD_FAILURE;
10798 npc_settimerevent_tick(nd,tick);
10799 script_pushint(st,0);
10800 return SCRIPT_CMD_SUCCESS;
10803 /*==========================================
10804 * attaches the player rid to the timer [Celest]
10805 *------------------------------------------*/
10806 BUILDIN_FUNC(attachnpctimer)
10809 struct npc_data *nd = (struct npc_data *)map_id2bl(st->oid);
10811 if( !nd || nd->bl.type != BL_NPC )
10813 script_pushint(st,1);
10814 ShowError("setnpctimer: Invalid NPC.\n");
10815 return SCRIPT_CMD_FAILURE;
10818 if( !script_nick2sd(2,sd) ){
10819 script_pushint(st,1);
10820 ShowWarning("attachnpctimer: Invalid player.\n");
10821 return SCRIPT_CMD_FAILURE;
10824 nd->u.scr.rid = sd->bl.id;
10825 script_pushint(st,0);
10826 return SCRIPT_CMD_SUCCESS;
10829 /*==========================================
10830 * detaches a player rid from the timer [Celest]
10831 *------------------------------------------*/
10832 BUILDIN_FUNC(detachnpctimer)
10834 struct npc_data *nd;
10836 if( script_hasdata(st,2) )
10837 nd = npc_name2id(script_getstr(st,2));
10839 nd = (struct npc_data *)map_id2bl(st->oid);
10841 if( !nd || nd->bl.type != BL_NPC )
10843 script_pushint(st,1);
10844 ShowError("detachnpctimer: Invalid NPC.\n");
10845 return SCRIPT_CMD_FAILURE;
10849 script_pushint(st,0);
10850 return SCRIPT_CMD_SUCCESS;
10853 /*==========================================
10854 * To avoid "player not attached" script errors, this function is provided,
10855 * it checks if there is a player attached to the current script. [Skotlex]
10856 * If no, returns 0, if yes, returns the account_id of the attached player.
10857 *------------------------------------------*/
10858 BUILDIN_FUNC(playerattached)
10860 if(st->rid == 0 || map_id2sd(st->rid) == NULL)
10861 script_pushint(st,0);
10863 script_pushint(st,st->rid);
10864 return SCRIPT_CMD_SUCCESS;
10867 /*==========================================
10868 *------------------------------------------*/
10869 BUILDIN_FUNC(announce)
10871 const char *mes = script_getstr(st,2);
10872 int flag = script_getnum(st,3);
10873 const char *fontColor = script_hasdata(st,4) ? script_getstr(st,4) : NULL;
10874 int fontType = script_hasdata(st,5) ? script_getnum(st,5) : FW_NORMAL; // default fontType
10875 int fontSize = script_hasdata(st,6) ? script_getnum(st,6) : 12; // default fontSize
10876 int fontAlign = script_hasdata(st,7) ? script_getnum(st,7) : 0; // default fontAlign
10877 int fontY = script_hasdata(st,8) ? script_getnum(st,8) : 0; // default fontY
10879 if (flag&(BC_TARGET_MASK|BC_SOURCE_MASK)) // Broadcast source or broadcast region defined
10881 send_target target;
10882 struct block_list *bl;
10884 // If bc_npc flag is set, use NPC as broadcast source
10886 bl = map_id2bl(st->oid);
10888 struct map_session_data* sd;
10890 if( script_rid2sd(sd) )
10897 return SCRIPT_CMD_SUCCESS;
10899 switch (flag&BC_TARGET_MASK) {
10900 case BC_MAP: target = ALL_SAMEMAP; break;
10901 case BC_AREA: target = AREA; break;
10902 case BC_SELF: target = SELF; break;
10903 default: target = ALL_CLIENT; break; // BC_ALL
10907 clif_broadcast2(bl, mes, (int)strlen(mes)+1, strtol(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY, target);
10909 clif_broadcast(bl, mes, (int)strlen(mes)+1, flag&BC_COLOR_MASK, target);
10914 intif_broadcast2(mes, (int)strlen(mes)+1, strtol(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY);
10916 intif_broadcast(mes, (int)strlen(mes)+1, flag&BC_COLOR_MASK);
10918 return SCRIPT_CMD_SUCCESS;
10921 /*==========================================
10922 *------------------------------------------*/
10923 static int buildin_announce_sub(struct block_list *bl, va_list ap)
10925 char *mes = va_arg(ap, char *);
10926 int len = va_arg(ap, int);
10927 int type = va_arg(ap, int);
10928 char *fontColor = va_arg(ap, char *);
10929 short fontType = (short)va_arg(ap, int);
10930 short fontSize = (short)va_arg(ap, int);
10931 short fontAlign = (short)va_arg(ap, int);
10932 short fontY = (short)va_arg(ap, int);
10934 clif_broadcast2(bl, mes, len, strtol(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY, SELF);
10936 clif_broadcast(bl, mes, len, type, SELF);
10937 return SCRIPT_CMD_SUCCESS;
10940 BUILDIN_FUNC(mapannounce)
10942 const char *mapname = script_getstr(st,2);
10943 const char *mes = script_getstr(st,3);
10944 int flag = script_getnum(st,4);
10945 const char *fontColor = script_hasdata(st,5) ? script_getstr(st,5) : NULL;
10946 int fontType = script_hasdata(st,6) ? script_getnum(st,6) : FW_NORMAL; // default fontType
10947 int fontSize = script_hasdata(st,7) ? script_getnum(st,7) : 12; // default fontSize
10948 int fontAlign = script_hasdata(st,8) ? script_getnum(st,8) : 0; // default fontAlign
10949 int fontY = script_hasdata(st,9) ? script_getnum(st,9) : 0; // default fontY
10952 if ((m = map_mapname2mapid(mapname)) < 0)
10953 return SCRIPT_CMD_SUCCESS;
10955 map_foreachinmap(buildin_announce_sub, m, BL_PC,
10956 mes, strlen(mes)+1, flag&BC_COLOR_MASK, fontColor, fontType, fontSize, fontAlign, fontY);
10957 return SCRIPT_CMD_SUCCESS;
10960 /*==========================================
10961 *------------------------------------------*/
10962 BUILDIN_FUNC(areaannounce)
10964 const char *mapname = script_getstr(st,2);
10965 int x0 = script_getnum(st,3);
10966 int y0 = script_getnum(st,4);
10967 int x1 = script_getnum(st,5);
10968 int y1 = script_getnum(st,6);
10969 const char *mes = script_getstr(st,7);
10970 int flag = script_getnum(st,8);
10971 const char *fontColor = script_hasdata(st,9) ? script_getstr(st,9) : NULL;
10972 int fontType = script_hasdata(st,10) ? script_getnum(st,10) : FW_NORMAL; // default fontType
10973 int fontSize = script_hasdata(st,11) ? script_getnum(st,11) : 12; // default fontSize
10974 int fontAlign = script_hasdata(st,12) ? script_getnum(st,12) : 0; // default fontAlign
10975 int fontY = script_hasdata(st,13) ? script_getnum(st,13) : 0; // default fontY
10978 if ((m = map_mapname2mapid(mapname)) < 0)
10979 return SCRIPT_CMD_SUCCESS;
10981 map_foreachinallarea(buildin_announce_sub, m, x0, y0, x1, y1, BL_PC,
10982 mes, strlen(mes)+1, flag&BC_COLOR_MASK, fontColor, fontType, fontSize, fontAlign, fontY);
10983 return SCRIPT_CMD_SUCCESS;
10986 /*==========================================
10987 *------------------------------------------*/
10988 BUILDIN_FUNC(getusers)
10991 struct map_session_data* sd;
10992 struct block_list* bl = NULL;
10994 flag = script_getnum(st,2);
11001 bl = map_id2bl(st->oid);
11003 else if(script_rid2sd(sd))
11010 val = map[bl->m].users;
11014 val = map_getusers();
11017 ShowWarning("buildin_getusers: Unknown type %d.\n", flag);
11018 script_pushint(st,0);
11019 return SCRIPT_CMD_FAILURE;
11022 script_pushint(st,val);
11023 return SCRIPT_CMD_SUCCESS;
11026 /*==========================================
11027 * getmapguildusers("mapname",guild ID) Returns the number guild members present on a map [Reddozen]
11028 *------------------------------------------*/
11029 BUILDIN_FUNC(getmapguildusers)
11035 struct guild *g = NULL;
11036 str=script_getstr(st,2);
11037 gid=script_getnum(st,3);
11038 if ((m = map_mapname2mapid(str)) < 0) { // map id on this server (m == -1 if not in actual map-server)
11039 script_pushint(st,-1);
11040 return SCRIPT_CMD_SUCCESS;
11042 g = guild_search(gid);
11046 for(i = 0; i < g->max_member; i++)
11048 if (g->member[i].sd && g->member[i].sd->bl.m == m)
11053 script_pushint(st,c);
11054 return SCRIPT_CMD_SUCCESS;
11057 /*==========================================
11058 *------------------------------------------*/
11059 BUILDIN_FUNC(getmapusers)
11063 str=script_getstr(st,2);
11064 if( (m=map_mapname2mapid(str))< 0){
11065 script_pushint(st,-1);
11066 return SCRIPT_CMD_SUCCESS;
11068 script_pushint(st,map[m].users);
11069 return SCRIPT_CMD_SUCCESS;
11071 /*==========================================
11072 *------------------------------------------*/
11073 static int buildin_getareausers_sub(struct block_list *bl,va_list ap)
11075 int *users=va_arg(ap,int *);
11077 return SCRIPT_CMD_SUCCESS;
11080 BUILDIN_FUNC(getareausers)
11083 int16 m,x0,y0,x1,y1,users=0; //doubt we can have more then 32k users on
11084 str=script_getstr(st,2);
11085 x0=script_getnum(st,3);
11086 y0=script_getnum(st,4);
11087 x1=script_getnum(st,5);
11088 y1=script_getnum(st,6);
11089 if( (m=map_mapname2mapid(str))< 0){
11090 script_pushint(st,-1);
11091 return SCRIPT_CMD_SUCCESS;
11093 map_foreachinallarea(buildin_getareausers_sub,
11094 m,x0,y0,x1,y1,BL_PC,&users);
11095 script_pushint(st,users);
11096 return SCRIPT_CMD_SUCCESS;
11099 /*==========================================
11100 *------------------------------------------*/
11101 static int buildin_getareadropitem_sub(struct block_list *bl,va_list ap)
11103 unsigned short nameid = (unsigned short)va_arg(ap, int);
11104 unsigned short *amount = (unsigned short *)va_arg(ap, int *);
11105 struct flooritem_data *drop=(struct flooritem_data *)bl;
11107 if(drop->item.nameid==nameid)
11108 (*amount)+=drop->item.amount;
11110 return SCRIPT_CMD_SUCCESS;
11112 BUILDIN_FUNC(getareadropitem)
11115 int16 m,x0,y0,x1,y1;
11116 unsigned short nameid, amount = 0;
11117 struct script_data *data;
11119 str=script_getstr(st,2);
11120 x0=script_getnum(st,3);
11121 y0=script_getnum(st,4);
11122 x1=script_getnum(st,5);
11123 y1=script_getnum(st,6);
11125 data=script_getdata(st,7);
11127 if( data_isstring(data) ){
11128 const char *name=conv_str(st,data);
11129 struct item_data *item_data = itemdb_searchname(name);
11130 nameid=UNKNOWN_ITEM_ID;
11132 nameid=item_data->nameid;
11134 nameid=conv_num(st,data);
11136 if( (m=map_mapname2mapid(str))< 0){
11137 script_pushint(st,-1);
11138 return SCRIPT_CMD_SUCCESS;
11140 map_foreachinallarea(buildin_getareadropitem_sub,
11141 m,x0,y0,x1,y1,BL_ITEM,nameid,&amount);
11142 script_pushint(st,amount);
11143 return SCRIPT_CMD_SUCCESS;
11146 /*==========================================
11147 *------------------------------------------*/
11148 BUILDIN_FUNC(enablenpc)
11151 str=script_getstr(st,2);
11153 return SCRIPT_CMD_SUCCESS;
11156 /*==========================================
11157 *------------------------------------------*/
11158 BUILDIN_FUNC(disablenpc)
11161 str=script_getstr(st,2);
11163 return SCRIPT_CMD_SUCCESS;
11166 /*==========================================
11167 *------------------------------------------*/
11168 BUILDIN_FUNC(hideoffnpc)
11171 str=script_getstr(st,2);
11173 return SCRIPT_CMD_SUCCESS;
11175 /*==========================================
11176 *------------------------------------------*/
11177 BUILDIN_FUNC(hideonnpc)
11180 str=script_getstr(st,2);
11182 return SCRIPT_CMD_SUCCESS;
11185 /* Starts a status effect on the target unit or on the attached player.
11187 * sc_start <effect_id>,<duration>,<val1>{,<rate>,<flag>,{<unit_id>}};
11188 * sc_start2 <effect_id>,<duration>,<val1>,<val2>{,<rate,<flag>,{<unit_id>}};
11189 * sc_start4 <effect_id>,<duration>,<val1>,<val2>,<val3>,<val4>{,<rate,<flag>,{<unit_id>}};
11190 * <flag>: enum e_status_change_start_flags
11192 BUILDIN_FUNC(sc_start)
11194 TBL_NPC * nd = map_id2nd(st->oid);
11195 struct block_list* bl;
11197 int tick, val1, val2, val3, val4=0, rate, flag;
11199 const char* command = script_getfuncname(st);
11201 if(strstr(command, "4"))
11203 else if(strstr(command, "2"))
11208 type = (sc_type)script_getnum(st,2);
11209 tick = script_getnum(st,3);
11210 val1 = script_getnum(st,4);
11212 //If from NPC we make default flag 1 to be unavoidable
11213 if(nd && nd->bl.id == fake_nd->bl.id)
11214 flag = script_hasdata(st,5+start_type)?script_getnum(st,5+start_type):SCSTART_NOTICKDEF;
11216 flag = script_hasdata(st,5+start_type)?script_getnum(st,5+start_type):SCSTART_NOAVOID;
11218 rate = script_hasdata(st,4+start_type)?min(script_getnum(st,4+start_type),10000):10000;
11220 if(script_hasdata(st,(6+start_type)))
11221 bl = map_id2bl(script_getnum(st,(6+start_type)));
11223 bl = map_id2bl(st->rid);
11225 if(tick == 0 && val1 > 0 && type > SC_NONE && type < SC_MAX && status_sc2skill(type) != 0)
11226 {// When there isn't a duration specified, try to get it from the skill_db
11227 tick = skill_get_time(status_sc2skill(type), val1);
11230 if(potion_flag == 1 && potion_target) { //skill.c set the flags before running the script, this is a potion-pitched effect.
11231 bl = map_id2bl(potion_target);
11232 tick /= 2;// Thrown potions only last half.
11233 val4 = 1;// Mark that this was a thrown sc_effect
11237 return SCRIPT_CMD_SUCCESS;
11239 switch(start_type) {
11241 status_change_start(bl, bl, type, rate, val1, 0, 0, val4, tick, flag);
11244 val2 = script_getnum(st,5);
11245 status_change_start(bl, bl, type, rate, val1, val2, 0, val4, tick, flag);
11248 val2 = script_getnum(st,5);
11249 val3 = script_getnum(st,6);
11250 val4 = script_getnum(st,7);
11251 status_change_start(bl, bl, type, rate, val1, val2, val3, val4, tick, flag);
11254 return SCRIPT_CMD_SUCCESS;
11257 /// Ends one or all status effects on the target unit or on the attached player.
11259 /// sc_end <effect_id>{,<unit_id>};
11260 BUILDIN_FUNC(sc_end)
11262 struct block_list* bl;
11265 type = script_getnum(st, 2);
11266 if (script_hasdata(st, 3))
11267 bl = map_id2bl(script_getnum(st, 3));
11269 bl = map_id2bl(st->rid);
11271 if (potion_flag == 1 && potion_target) //##TODO how does this work [FlavioJS]
11272 bl = map_id2bl(potion_target);
11275 return SCRIPT_CMD_SUCCESS;
11277 if (type >= 0 && type < SC_MAX) {
11278 struct status_change *sc = status_get_sc(bl);
11279 struct status_change_entry *sce = sc ? sc->data[type] : NULL;
11282 return SCRIPT_CMD_SUCCESS;
11289 case SC_ALL_RIDING:
11290 case SC_STYLE_CHANGE:
11291 case SC_MONSTER_TRANSFORM:
11292 case SC_ACTIVE_MONSTER_TRANSFORM:
11294 case SC_MTF_RANGEATK:
11296 case SC_MTF_MLEATKED:
11297 case SC_MTF_CRIDAMAGE:
11299 case SC_MTF_RANGEATK2:
11303 case SC_MTF_PUMPKIN:
11304 case SC_MTF_HITFLEE:
11305 case SC_ATTHASTE_CASH:
11306 case SC_REUSE_LIMIT_A: case SC_REUSE_LIMIT_B: case SC_REUSE_LIMIT_C:
11307 case SC_REUSE_LIMIT_D: case SC_REUSE_LIMIT_E: case SC_REUSE_LIMIT_F:
11308 case SC_REUSE_LIMIT_G: case SC_REUSE_LIMIT_H: case SC_REUSE_LIMIT_MTF:
11309 case SC_REUSE_LIMIT_ASPD_POTION: case SC_REUSE_MILLENNIUMSHIELD: case SC_REUSE_CRUSHSTRIKE:
11310 case SC_REUSE_STORMBLAST: case SC_ALL_RIDING_REUSE_LIMIT: case SC_REUSE_REFRESH:
11311 case SC_REUSE_LIMIT_ECL: case SC_REUSE_LIMIT_RECALL:
11312 return SCRIPT_CMD_SUCCESS;
11317 //This should help status_change_end force disabling the SC in case it has no limit.
11318 sce->val1 = sce->val2 = sce->val3 = sce->val4 = 0;
11319 status_change_end(bl, (sc_type)type, INVALID_TIMER);
11321 status_change_clear(bl, 3); // remove all effects
11323 return SCRIPT_CMD_SUCCESS;
11327 * Ends all status effects from any learned skill on the attached player.
11328 * sc_end_class {<char_id>};
11330 BUILDIN_FUNC(sc_end_class)
11332 struct map_session_data *sd;
11336 if (!script_charid2sd(2, sd))
11337 return SCRIPT_CMD_FAILURE;
11339 for (i = 0; i < MAX_SKILL_TREE && (skill_id = skill_tree[pc_class2idx(sd->status.class_)][i].skill_id) > 0; i++) { // Remove status specific to your current tree skills.
11340 enum sc_type sc = status_skill2sc(skill_id);
11342 if (sc > SC_COMMON_MAX && sd->sc.data[sc])
11343 status_change_end(&sd->bl, sc, INVALID_TIMER);
11346 return SCRIPT_CMD_SUCCESS;
11349 /*==========================================
11350 * @FIXME atm will return reduced tick, 0 immune, 1 no tick
11351 *------------------------------------------*/
11352 BUILDIN_FUNC(getscrate)
11354 struct block_list *bl;
11357 type=script_getnum(st,2);
11358 rate=script_getnum(st,3);
11359 if( script_hasdata(st,4) ) //get for the bl assigned
11360 bl = map_id2bl(script_getnum(st,4));
11362 bl = map_id2bl(st->rid);
11365 rate = status_get_sc_def(NULL,bl, (sc_type)type, 10000, 10000, SCSTART_NONE);
11367 script_pushint(st,rate);
11368 return SCRIPT_CMD_SUCCESS;
11372 * getstatus(<effect type>{,<type>{,<char_id>}});
11374 BUILDIN_FUNC(getstatus)
11377 struct map_session_data* sd;
11379 if (!script_charid2sd(4,sd))
11380 return SCRIPT_CMD_FAILURE;
11382 id = script_getnum(st, 2);
11383 type = script_hasdata(st, 3) ? script_getnum(st, 3) : 0;
11385 if( id <= SC_NONE || id >= SC_MAX )
11386 {// invalid status type given
11387 ShowWarning("script.cpp:getstatus: Invalid status type given (%d).\n", id);
11388 return SCRIPT_CMD_SUCCESS;
11391 if( sd->sc.count == 0 || !sd->sc.data[id] )
11392 {// no status is active
11393 script_pushint(st, 0);
11394 return SCRIPT_CMD_SUCCESS;
11399 case 1: script_pushint(st, sd->sc.data[id]->val1); break;
11400 case 2: script_pushint(st, sd->sc.data[id]->val2); break;
11401 case 3: script_pushint(st, sd->sc.data[id]->val3); break;
11402 case 4: script_pushint(st, sd->sc.data[id]->val4); break;
11405 struct TimerData* timer = (struct TimerData*)get_timer(sd->sc.data[id]->timer);
11408 {// return the amount of time remaining
11409 script_pushint(st, timer->tick - gettick());
11411 script_pushint(st, -1);
11415 default: script_pushint(st, 1); break;
11418 return SCRIPT_CMD_SUCCESS;
11421 /*==========================================
11423 *------------------------------------------*/
11424 BUILDIN_FUNC(debugmes)
11427 str=script_getstr(st,2);
11428 ShowDebug("script debug : %d %d : %s\n",st->rid,st->oid,str);
11429 return SCRIPT_CMD_SUCCESS;
11432 /*==========================================
11433 *------------------------------------------*/
11434 BUILDIN_FUNC(catchpet)
11439 if( !script_rid2sd(sd) )
11440 return SCRIPT_CMD_SUCCESS;
11442 pet_id= script_getnum(st,2);
11444 pet_catch_process1(sd,pet_id);
11445 return SCRIPT_CMD_SUCCESS;
11448 /*==========================================
11450 *------------------------------------------*/
11451 BUILDIN_FUNC(homunculus_evolution)
11455 if( !script_rid2sd(sd) )
11456 return SCRIPT_CMD_SUCCESS;
11458 if(hom_is_active(sd->hd))
11460 if (sd->hd->homunculus.intimacy >= battle_config.homunculus_evo_intimacy_need)
11461 hom_evolution(sd->hd);
11463 clif_emotion(&sd->hd->bl, E_SWT);
11465 return SCRIPT_CMD_SUCCESS;
11468 /*==========================================
11469 * Checks for vaporized morph state
11470 * and deletes ITEMID_STRANGE_EMBRYO.
11471 *------------------------------------------*/
11472 BUILDIN_FUNC(homunculus_mutate)
11477 if( !script_rid2sd(sd) || sd->hd == NULL )
11478 return SCRIPT_CMD_SUCCESS;
11480 if(script_hasdata(st,2))
11481 homun_id = script_getnum(st,2);
11483 homun_id = 6048 + (rnd() % 4);
11485 if( sd->hd->homunculus.vaporize == HOM_ST_MORPH ) {
11486 int m_class = hom_class2mapid(sd->hd->homunculus.class_);
11487 int m_id = hom_class2mapid(homun_id);
11488 short i = pc_search_inventory(sd, ITEMID_STRANGE_EMBRYO);
11490 if ( m_class != -1 && m_id != -1 && m_class&HOM_EVO && m_id&HOM_S && sd->hd->homunculus.level >= 99 && i >= 0 ) {
11491 sd->hd->homunculus.vaporize = HOM_ST_REST; // Remove morph state.
11492 hom_call(sd); // Respawn homunculus.
11493 hom_mutate(sd->hd, homun_id);
11494 pc_delitem(sd, i, 1, 0, 0, LOG_TYPE_SCRIPT);
11495 script_pushint(st, 1);
11496 return SCRIPT_CMD_SUCCESS;
11498 clif_emotion(&sd->bl, E_SWT);
11500 clif_emotion(&sd->bl, E_SWT);
11502 script_pushint(st, 0);
11504 return SCRIPT_CMD_SUCCESS;
11507 /*==========================================
11508 * Puts homunculus into morph state
11509 * and gives ITEMID_STRANGE_EMBRYO.
11510 *------------------------------------------*/
11511 BUILDIN_FUNC(morphembryo)
11513 struct item item_tmp;
11516 if( !script_rid2sd(sd) || sd->hd == NULL )
11517 return SCRIPT_CMD_SUCCESS;
11519 if( hom_is_active(sd->hd) ) {
11520 int m_class = hom_class2mapid(sd->hd->homunculus.class_);
11522 if ( m_class != -1 && m_class&HOM_EVO && sd->hd->homunculus.level >= 99 ) {
11524 memset(&item_tmp, 0, sizeof(item_tmp));
11525 item_tmp.nameid = ITEMID_STRANGE_EMBRYO;
11526 item_tmp.identify = 1;
11528 if( (i = pc_additem(sd, &item_tmp, 1, LOG_TYPE_SCRIPT)) ) {
11529 clif_additem(sd, 0, 0, i);
11530 clif_emotion(&sd->bl, E_SWT); // Fail to avoid item drop exploit.
11532 hom_vaporize(sd, HOM_ST_MORPH);
11533 script_pushint(st, 1);
11534 return SCRIPT_CMD_SUCCESS;
11537 clif_emotion(&sd->hd->bl, E_SWT);
11539 clif_emotion(&sd->bl, E_SWT);
11541 script_pushint(st, 0);
11543 return SCRIPT_CMD_SUCCESS;
11547 BUILDIN_FUNC(homunculus_shuffle)
11551 if( !script_rid2sd(sd) )
11552 return SCRIPT_CMD_SUCCESS;
11554 if(hom_is_active(sd->hd))
11555 hom_shuffle(sd->hd);
11557 return SCRIPT_CMD_SUCCESS;
11560 /*==========================================
11561 * Check for homunculus state.
11562 * Return: -1 = No homunculus
11563 * 0 = Homunculus is active
11564 * 1 = Homunculus is vaporized (rest)
11565 * 2 = Homunculus is in morph state
11566 *------------------------------------------*/
11567 BUILDIN_FUNC(checkhomcall)
11572 if( !script_rid2sd(sd) )
11573 return SCRIPT_CMD_SUCCESS;
11578 script_pushint(st, -1);
11580 script_pushint(st, hd->homunculus.vaporize);
11582 return SCRIPT_CMD_SUCCESS;
11585 //These two functions bring the eA MAPID_* class functionality to scripts.
11586 BUILDIN_FUNC(eaclass)
11589 if( script_hasdata(st,2) )
11590 class_ = script_getnum(st,2);
11594 if (!script_charid2sd(3,sd)) {
11595 script_pushint(st,-1);
11596 return SCRIPT_CMD_SUCCESS;
11598 class_ = sd->status.class_;
11600 script_pushint(st,pc_jobid2mapid(class_));
11601 return SCRIPT_CMD_SUCCESS;
11604 BUILDIN_FUNC(roclass)
11606 int class_ =script_getnum(st,2);
11608 if( script_hasdata(st,3) )
11609 sex = script_getnum(st,3);
11612 if (st->rid && script_rid2sd(sd))
11613 sex = sd->status.sex;
11615 sex = SEX_MALE; //Just use male when not found.
11617 script_pushint(st,pc_mapid2jobid(class_, sex));
11618 return SCRIPT_CMD_SUCCESS;
11621 /*==========================================
11622 * Tells client to open a hatching window, used for pet incubator
11623 *------------------------------------------*/
11624 BUILDIN_FUNC(birthpet)
11627 if( !script_rid2sd(sd) )
11628 return SCRIPT_CMD_SUCCESS;
11630 if( sd->status.pet_id )
11631 {// do not send egg list, when you already have a pet
11632 return SCRIPT_CMD_SUCCESS;
11636 return SCRIPT_CMD_SUCCESS;
11640 * resetlvl <action type>{,<char_id>};
11641 * @param action_type:
11642 * 1 : make like after rebirth
11643 * 2 : blvl,jlvl=1, skillpoint=0
11644 * 3 : don't reset skill, blvl=1
11646 * @author AppleGirl
11648 BUILDIN_FUNC(resetlvl)
11652 int type=script_getnum(st,2);
11654 if (!script_charid2sd(3,sd))
11655 return SCRIPT_CMD_FAILURE;
11657 pc_resetlvl(sd,type);
11658 return SCRIPT_CMD_SUCCESS;
11662 * Reset a player status point
11663 * resetstatus({<char_id>});
11665 BUILDIN_FUNC(resetstatus)
11668 if (!script_charid2sd(2,sd))
11669 return SCRIPT_CMD_FAILURE;
11671 return SCRIPT_CMD_SUCCESS;
11675 * Reset player's skill
11676 * resetskill({<char_id>});
11678 BUILDIN_FUNC(resetskill)
11681 if (!script_charid2sd(2,sd))
11682 return SCRIPT_CMD_FAILURE;
11683 pc_resetskill(sd,1);
11684 return SCRIPT_CMD_SUCCESS;
11688 * Counts total amount of skill points.
11689 * skillpointcount({<char_id>})
11691 BUILDIN_FUNC(skillpointcount)
11694 if (!script_charid2sd(2,sd))
11695 return SCRIPT_CMD_FAILURE;
11696 script_pushint(st,sd->status.skill_point + pc_resetskill(sd,2));
11697 return SCRIPT_CMD_SUCCESS;
11700 /*==========================================
11702 *------------------------------------------*/
11703 BUILDIN_FUNC(changebase)
11708 if( !script_mapid2sd(3,sd) )
11709 return SCRIPT_CMD_SUCCESS;
11711 vclass = script_getnum(st,2);
11712 if(vclass == JOB_WEDDING)
11714 if (!battle_config.wedding_modifydisplay || //Do not show the wedding sprites
11715 sd->class_&JOBL_BABY //Baby classes screw up when showing wedding sprites. [Skotlex] They don't seem to anymore.
11717 return SCRIPT_CMD_SUCCESS;
11720 if(!sd->disguise && vclass != sd->vd.class_) {
11721 status_set_viewdata(&sd->bl, vclass);
11722 //Updated client view. Base, Weapon and Cloth Colors.
11723 clif_changelook(&sd->bl,LOOK_BASE,sd->vd.class_);
11724 clif_changelook(&sd->bl,LOOK_WEAPON,sd->status.weapon);
11725 if (sd->vd.cloth_color)
11726 clif_changelook(&sd->bl,LOOK_CLOTHES_COLOR,sd->vd.cloth_color);
11727 if (sd->vd.body_style)
11728 clif_changelook(&sd->bl,LOOK_BODY2,sd->vd.body_style);
11729 clif_skillinfoblock(sd);
11731 return SCRIPT_CMD_SUCCESS;
11735 * Change account sex and unequip all item and request for a changesex to char-serv
11736 * changesex({<char_id>});
11738 BUILDIN_FUNC(changesex)
11743 if (!script_charid2sd(2,sd))
11744 return SCRIPT_CMD_FAILURE;
11746 pc_resetskill(sd,4);
11747 // to avoid any problem with equipment and invalid sex, equipment is unequiped.
11748 for(i = 0; i < EQI_MAX; i++) {
11749 if (sd->equip_index[i] >= 0)
11750 pc_unequipitem(sd, sd->equip_index[i], 3);
11753 chrif_changesex(sd, true);
11754 return SCRIPT_CMD_SUCCESS;
11758 * Change character's sex and unequip all item and request for a changesex to char-serv
11759 * changecharsex({<char_id>});
11761 BUILDIN_FUNC(changecharsex)
11763 #if PACKETVER >= 20141016
11767 if (!script_charid2sd(2,sd))
11768 return SCRIPT_CMD_FAILURE;
11770 pc_resetskill(sd,4);
11771 // to avoid any problem with equipment and invalid sex, equipment is unequiped.
11772 for (i = 0; i < EQI_MAX; i++) {
11773 if (sd->equip_index[i] >= 0)
11774 pc_unequipitem(sd, sd->equip_index[i], 3);
11777 chrif_changesex(sd, false);
11778 return SCRIPT_CMD_SUCCESS;
11780 return SCRIPT_CMD_FAILURE;
11784 /*==========================================
11785 * Works like 'announce' but outputs in the common chat window
11786 *------------------------------------------*/
11787 BUILDIN_FUNC(globalmes)
11789 struct block_list *bl = map_id2bl(st->oid);
11790 struct npc_data *nd = (struct npc_data *)bl;
11791 const char *name=NULL,*mes;
11793 mes=script_getstr(st,2);
11795 return SCRIPT_CMD_SUCCESS;
11797 if(script_hasdata(st,3)){ // npc name to display
11798 name=script_getstr(st,3);
11800 name=nd->name; //use current npc name
11803 npc_globalmessage(name,mes); // broadcast to all players connected
11804 return SCRIPT_CMD_SUCCESS;
11807 /////////////////////////////////////////////////////////////////////
11808 // NPC waiting room (chat room)
11811 /// Creates a waiting room (chat room) for this npc.
11813 /// waitingroom "<title>",<limit>{,"<event>"{,<trigger>{,<zeny>{,<minlvl>{,<maxlvl>}}}}};
11814 BUILDIN_FUNC(waitingroom)
11816 struct npc_data* nd;
11817 const char* title = script_getstr(st, 2);
11818 int limit = script_getnum(st, 3);
11819 const char* ev = script_hasdata(st,4) ? script_getstr(st,4) : "";
11820 int trigger = script_hasdata(st,5) ? script_getnum(st,5) : limit;
11821 int zeny = script_hasdata(st,6) ? script_getnum(st,6) : 0;
11822 int minLvl = script_hasdata(st,7) ? script_getnum(st,7) : 1;
11823 int maxLvl = script_hasdata(st,8) ? script_getnum(st,8) : MAX_LEVEL;
11825 nd = (struct npc_data *)map_id2bl(st->oid);
11827 chat_createnpcchat(nd, title, limit, 1, trigger, ev, zeny, minLvl, maxLvl);
11829 return SCRIPT_CMD_SUCCESS;
11832 /// Removes the waiting room of the current or target npc.
11834 /// delwaitingroom "<npc_name>";
11835 /// delwaitingroom;
11836 BUILDIN_FUNC(delwaitingroom)
11838 struct npc_data* nd;
11839 if( script_hasdata(st,2) )
11840 nd = npc_name2id(script_getstr(st, 2));
11842 nd = (struct npc_data *)map_id2bl(st->oid);
11844 chat_deletenpcchat(nd);
11845 return SCRIPT_CMD_SUCCESS;
11848 /// Kick the specified player from the waiting room of the target npc.
11850 /// waitingroomkick "<npc_name>", <kickusername>;
11851 BUILDIN_FUNC(waitingroomkick)
11853 struct npc_data* nd;
11854 struct chat_data* cd;
11855 const char* kickusername;
11857 nd = npc_name2id(script_getstr(st,2));
11858 kickusername = script_getstr(st,3);
11860 if( nd != NULL && (cd=(struct chat_data *)map_id2bl(nd->chat_id)) != NULL )
11861 chat_npckickchat(cd, kickusername);
11862 return SCRIPT_CMD_SUCCESS;
11865 /// Get Users in waiting room and stores gids in .@waitingroom_users[]
11866 /// Num users stored in .@waitingroom_usercount
11868 /// getwaitingroomusers "<npc_name>";
11869 BUILDIN_FUNC(getwaitingroomusers)
11871 struct npc_data* nd;
11872 struct chat_data* cd;
11876 if( script_hasdata(st,2) )
11877 nd = npc_name2id(script_getstr(st, 2));
11879 nd = (struct npc_data *)map_id2bl(st->oid);
11881 if( nd != NULL && (cd=(struct chat_data *)map_id2bl(nd->chat_id)) != NULL ) {
11882 for(i = 0; i < cd->users; ++i) {
11883 setd_sub(st, NULL, ".@waitingroom_users", j, (void *)__64BPRTSIZE(cd->usersd[i]->status.account_id), NULL);
11886 setd_sub(st, NULL, ".@waitingroom_usercount", 0, (void *)__64BPRTSIZE(j), NULL);
11888 return SCRIPT_CMD_SUCCESS;
11891 /// Kicks all the players from the waiting room of the current or target npc.
11893 /// kickwaitingroomall "<npc_name>";
11894 /// kickwaitingroomall;
11895 BUILDIN_FUNC(waitingroomkickall)
11897 struct npc_data* nd;
11898 struct chat_data* cd;
11900 if( script_hasdata(st,2) )
11901 nd = npc_name2id(script_getstr(st,2));
11903 nd = (struct npc_data *)map_id2bl(st->oid);
11905 if( nd != NULL && (cd=(struct chat_data *)map_id2bl(nd->chat_id)) != NULL )
11906 chat_npckickall(cd);
11907 return SCRIPT_CMD_SUCCESS;
11910 /// Enables the waiting room event of the current or target npc.
11912 /// enablewaitingroomevent "<npc_name>";
11913 /// enablewaitingroomevent;
11914 BUILDIN_FUNC(enablewaitingroomevent)
11916 struct npc_data* nd;
11917 struct chat_data* cd;
11919 if( script_hasdata(st,2) )
11920 nd = npc_name2id(script_getstr(st, 2));
11922 nd = (struct npc_data *)map_id2bl(st->oid);
11924 if( nd != NULL && (cd=(struct chat_data *)map_id2bl(nd->chat_id)) != NULL )
11925 chat_enableevent(cd);
11926 return SCRIPT_CMD_SUCCESS;
11929 /// Disables the waiting room event of the current or target npc.
11931 /// disablewaitingroomevent "<npc_name>";
11932 /// disablewaitingroomevent;
11933 BUILDIN_FUNC(disablewaitingroomevent)
11935 struct npc_data *nd;
11936 struct chat_data *cd;
11938 if( script_hasdata(st,2) )
11939 nd = npc_name2id(script_getstr(st, 2));
11941 nd = (struct npc_data *)map_id2bl(st->oid);
11943 if( nd != NULL && (cd=(struct chat_data *)map_id2bl(nd->chat_id)) != NULL )
11944 chat_disableevent(cd);
11945 return SCRIPT_CMD_SUCCESS;
11948 /// Returns info on the waiting room of the current or target npc.
11949 /// Returns -1 if the type unknown
11950 /// <type>=0 : current number of users
11951 /// <type>=1 : maximum number of users allowed
11952 /// <type>=2 : the number of users that trigger the event
11953 /// <type>=3 : if the trigger is disabled
11954 /// <type>=4 : the title of the waiting room
11955 /// <type>=5 : the password of the waiting room
11956 /// <type>=16 : the name of the waiting room event
11957 /// <type>=32 : if the waiting room is full
11958 /// <type>=33 : if there are enough users to trigger the event
11960 /// getwaitingroomstate(<type>,"<npc_name>") -> <info>
11961 /// getwaitingroomstate(<type>) -> <info>
11962 BUILDIN_FUNC(getwaitingroomstate)
11964 struct npc_data *nd;
11965 struct chat_data *cd;
11968 type = script_getnum(st,2);
11969 if( script_hasdata(st,3) )
11970 nd = npc_name2id(script_getstr(st, 3));
11972 nd = (struct npc_data *)map_id2bl(st->oid);
11974 if( nd == NULL || (cd=(struct chat_data *)map_id2bl(nd->chat_id)) == NULL )
11976 script_pushint(st, -1);
11977 return SCRIPT_CMD_SUCCESS;
11982 case 0: script_pushint(st, cd->users); break;
11983 case 1: script_pushint(st, cd->limit); break;
11984 case 2: script_pushint(st, cd->trigger&0x7f); break;
11985 case 3: script_pushint(st, ((cd->trigger&0x80)!=0)); break;
11986 case 4: script_pushstrcopy(st, cd->title); break;
11987 case 5: script_pushstrcopy(st, cd->pass); break;
11988 case 16: script_pushstrcopy(st, cd->npc_event);break;
11989 case 32: script_pushint(st, (cd->users >= cd->limit)); break;
11990 case 33: script_pushint(st, (cd->users >= cd->trigger)); break;
11991 default: script_pushint(st, -1); break;
11993 return SCRIPT_CMD_SUCCESS;
11996 /// Warps the trigger or target amount of players to the target map and position.
11997 /// Players are automatically removed from the waiting room.
11998 /// Those waiting the longest will get warped first.
11999 /// The target map can be "Random" for a random position in the current map,
12000 /// and "SavePoint" for the savepoint map+position.
12001 /// The map flag noteleport of the current map is only considered when teleporting to the savepoint.
12003 /// The id's of the teleported players are put into the array $@warpwaitingpc[]
12004 /// The total number of teleported players is put into $@warpwaitingpcnum
12006 /// warpwaitingpc "<map name>",<x>,<y>,<number of players>;
12007 /// warpwaitingpc "<map name>",<x>,<y>;
12008 BUILDIN_FUNC(warpwaitingpc)
12014 const char* map_name;
12015 struct npc_data* nd;
12016 struct chat_data* cd;
12018 nd = (struct npc_data *)map_id2bl(st->oid);
12019 if( nd == NULL || (cd=(struct chat_data *)map_id2bl(nd->chat_id)) == NULL )
12020 return SCRIPT_CMD_SUCCESS;
12022 map_name = script_getstr(st,2);
12023 x = script_getnum(st,3);
12024 y = script_getnum(st,4);
12025 n = cd->trigger&0x7f;
12027 if( script_hasdata(st,5) )
12028 n = script_getnum(st,5);
12030 for( i = 0; i < n && cd->users > 0; i++ )
12032 TBL_PC* sd = cd->usersd[0];
12034 if( strcmp(map_name,"SavePoint") == 0 && map[sd->bl.m].flag.noteleport )
12035 {// can't teleport on this map
12041 if( (uint32)sd->status.zeny < cd->zeny )
12042 {// no zeny to cover set fee
12045 pc_payzeny(sd, cd->zeny, LOG_TYPE_NPC, NULL);
12048 mapreg_setreg(reference_uid(add_str("$@warpwaitingpc"), i), sd->bl.id);
12050 if( strcmp(map_name,"Random") == 0 )
12051 pc_randomwarp(sd,CLR_TELEPORT);
12052 else if( strcmp(map_name,"SavePoint") == 0 )
12053 pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT);
12055 pc_setpos(sd, mapindex_name2id(map_name), x, y, CLR_OUTSIGHT);
12057 mapreg_setreg(add_str("$@warpwaitingpcnum"), i);
12058 return SCRIPT_CMD_SUCCESS;
12061 /////////////////////////////////////////////////////////////////////
12065 /// Detaches a character from a script.
12067 /// @param st Script state to detach the character from.
12068 static void script_detach_rid(struct script_state* st)
12072 script_detach_state(st, false);
12077 /*=========================================================================
12078 * Attaches a set of RIDs to the current script. [digitalhamster]
12079 * addrid(<type>{,<flag>{,<parameters>}});
12081 * 0 : All players in the server.
12082 * 1 : All players in the map of the invoking player, or the invoking NPC if no player is attached.
12083 * 2 : Party members of a specified party ID.
12084 * [ Parameters: <party id> ]
12085 * 3 : Guild members of a specified guild ID.
12086 * [ Parameters: <guild id> ]
12087 * 4 : All players in a specified area of the map of the invoking player (or NPC).
12088 * [ Parameters: <x0>,<y0>,<x1>,<y1> ]
12089 * 5 : All players in the map.
12090 * [ Parameters: "<map name>" ]
12091 * Account ID: The specified account ID.
12093 * 0 : Players are always attached. (default)
12094 * 1 : Players currently running another script will not be attached.
12095 *-------------------------------------------------------------------------*/
12096 static int buildin_addrid_sub(struct block_list *bl,va_list ap)
12099 struct map_session_data *sd = (TBL_PC *)bl;
12100 struct script_state* st;
12102 st = va_arg(ap,struct script_state*);
12103 forceflag = va_arg(ap,int);
12105 if(!forceflag || !sd->st)
12106 if(sd->status.account_id != st->rid)
12107 run_script(st->script,st->pos,sd->status.account_id,st->oid);
12111 BUILDIN_FUNC(addrid)
12113 struct s_mapiterator* iter;
12114 struct block_list *bl;
12119 bl = map_id2bl(st->oid);
12121 bl = map_id2bl(st->rid); //if run without rid it'd error,also oid if npc, else rid for map
12122 iter = mapit_getallusers();
12124 switch(script_getnum(st,2)) {
12126 for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter)) {
12127 if(!script_getnum(st,3) || !sd->st)
12128 if(sd->status.account_id != st->rid) //attached player already runs.
12129 run_script(st->script,st->pos,sd->status.account_id,st->oid);
12133 for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter)) {
12134 if(!script_getnum(st,3) || !sd->st)
12135 if((sd->bl.m == bl->m) && (sd->status.account_id != st->rid))
12136 run_script(st->script,st->pos,sd->status.account_id,st->oid);
12140 if(script_getnum(st,4) == 0) {
12141 script_pushint(st,0);
12142 return SCRIPT_CMD_SUCCESS;
12144 for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter)) {
12145 if(!script_getnum(st,3) || !sd->st)
12146 if((sd->status.account_id != st->rid) && (sd->status.party_id == script_getnum(st,4))) //attached player already runs.
12147 run_script(st->script,st->pos,sd->status.account_id,st->oid);
12151 if(script_getnum(st,4) == 0) {
12152 script_pushint(st,0);
12153 return SCRIPT_CMD_SUCCESS;
12155 for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter)) {
12156 if(!script_getnum(st,3) || !sd->st)
12157 if((sd->status.account_id != st->rid) && (sd->status.guild_id == script_getnum(st,4))) //attached player already runs.
12158 run_script(st->script,st->pos,sd->status.account_id,st->oid);
12162 map_foreachinallarea(buildin_addrid_sub,
12163 bl->m,script_getnum(st,4),script_getnum(st,5),script_getnum(st,6),script_getnum(st,7),BL_PC,
12164 st,script_getnum(st,3));//4-x0 , 5-y0 , 6-x1, 7-y1
12167 if (script_getstr(st, 4) == NULL) {
12168 script_pushint(st, 0);
12169 return SCRIPT_CMD_FAILURE;
12171 if (map_mapname2mapid(script_getstr(st, 4)) < 0) {
12172 script_pushint(st, 0);
12173 return SCRIPT_CMD_FAILURE;
12175 map_foreachinmap(buildin_addrid_sub, map_mapname2mapid(script_getstr(st, 4)), BL_PC, st, script_getnum(st, 3));
12178 if((map_id2sd(script_getnum(st,2))) == NULL) { // Player not found.
12179 script_pushint(st,0);
12180 return SCRIPT_CMD_SUCCESS;
12182 if(!script_getnum(st,3) || !map_id2sd(script_getnum(st,2))->st) {
12183 run_script(st->script,st->pos,script_getnum(st,2),st->oid);
12184 script_pushint(st,1);
12186 return SCRIPT_CMD_SUCCESS;
12189 script_pushint(st,1);
12190 return SCRIPT_CMD_SUCCESS;
12193 /*==========================================
12194 * Attach sd char id to script and detach current one if any
12195 *------------------------------------------*/
12196 BUILDIN_FUNC(attachrid)
12198 int rid = script_getnum(st,2);
12200 if (map_id2sd(rid) != NULL) {
12201 script_detach_rid(st);
12204 script_attach_state(st);
12205 script_pushint(st,1);
12207 script_pushint(st,0);
12208 return SCRIPT_CMD_SUCCESS;
12210 /*==========================================
12211 * Detach script to rid
12212 *------------------------------------------*/
12213 BUILDIN_FUNC(detachrid)
12215 script_detach_rid(st);
12216 return SCRIPT_CMD_SUCCESS;
12218 /*==========================================
12219 * Chk if account connected, (and charid from account if specified)
12220 *------------------------------------------*/
12221 BUILDIN_FUNC(isloggedin)
12223 TBL_PC* sd = map_id2sd(script_getnum(st,2));
12224 if (script_hasdata(st,3) && sd &&
12225 sd->status.char_id != script_getnum(st,3))
12227 push_val(st->stack,C_INT,sd!=NULL);
12228 return SCRIPT_CMD_SUCCESS;
12232 /*==========================================
12234 *------------------------------------------*/
12235 BUILDIN_FUNC(setmapflagnosave)
12238 unsigned short mapindex;
12239 const char *str,*str2;
12241 str=script_getstr(st,2);
12242 str2=script_getstr(st,3);
12243 x=script_getnum(st,4);
12244 y=script_getnum(st,5);
12245 m = map_mapname2mapid(str);
12246 mapindex = mapindex_name2id(str2);
12248 if(m >= 0 && mapindex) {
12249 map[m].flag.nosave=1;
12250 map[m].save.map=mapindex;
12254 return SCRIPT_CMD_SUCCESS;
12257 BUILDIN_FUNC(getmapflag)
12262 str=script_getstr(st,2);
12263 i=script_getnum(st,3);
12265 m = map_mapname2mapid(str);
12268 case MF_NOMEMO: script_pushint(st,map[m].flag.nomemo); break;
12269 case MF_NOTELEPORT: script_pushint(st,map[m].flag.noteleport); break;
12270 case MF_NOSAVE: script_pushint(st,map[m].flag.nosave); break;
12271 case MF_NOBRANCH: script_pushint(st,map[m].flag.nobranch); break;
12272 case MF_NOPENALTY: script_pushint(st,map[m].flag.noexppenalty); break;
12273 case MF_NOZENYPENALTY: script_pushint(st,map[m].flag.nozenypenalty); break;
12274 case MF_PVP: script_pushint(st,map[m].flag.pvp); break;
12275 case MF_PVP_NOPARTY: script_pushint(st,map[m].flag.pvp_noparty); break;
12276 case MF_PVP_NOGUILD: script_pushint(st,map[m].flag.pvp_noguild); break;
12277 case MF_GVG: script_pushint(st,map[m].flag.gvg); break;
12278 case MF_GVG_NOPARTY: script_pushint(st,map[m].flag.gvg_noparty); break;
12279 case MF_NOTRADE: script_pushint(st,map[m].flag.notrade); break;
12280 case MF_NOSKILL: script_pushint(st,map[m].flag.noskill); break;
12281 case MF_NOWARP: script_pushint(st,map[m].flag.nowarp); break;
12282 case MF_PARTYLOCK: script_pushint(st,map[m].flag.partylock); break;
12283 case MF_NOICEWALL: script_pushint(st,map[m].flag.noicewall); break;
12284 case MF_SNOW: script_pushint(st,map[m].flag.snow); break;
12285 case MF_FOG: script_pushint(st,map[m].flag.fog); break;
12286 case MF_SAKURA: script_pushint(st,map[m].flag.sakura); break;
12287 case MF_LEAVES: script_pushint(st,map[m].flag.leaves); break;
12288 case MF_NOGO: script_pushint(st,map[m].flag.nogo); break;
12289 case MF_CLOUDS: script_pushint(st,map[m].flag.clouds); break;
12290 case MF_CLOUDS2: script_pushint(st,map[m].flag.clouds2); break;
12291 case MF_FIREWORKS: script_pushint(st,map[m].flag.fireworks); break;
12292 case MF_GVG_CASTLE: script_pushint(st,map[m].flag.gvg_castle); break;
12293 case MF_GVG_DUNGEON: script_pushint(st,map[m].flag.gvg_dungeon); break;
12294 case MF_NIGHTENABLED: script_pushint(st,map[m].flag.nightenabled); break;
12295 case MF_NOBASEEXP: script_pushint(st,map[m].flag.nobaseexp); break;
12296 case MF_NOJOBEXP: script_pushint(st,map[m].flag.nojobexp); break;
12297 case MF_NOMOBLOOT: script_pushint(st,map[m].flag.nomobloot); break;
12298 case MF_NOMVPLOOT: script_pushint(st,map[m].flag.nomvploot); break;
12299 case MF_NORETURN: script_pushint(st,map[m].flag.noreturn); break;
12300 case MF_NOWARPTO: script_pushint(st,map[m].flag.nowarpto); break;
12301 case MF_NIGHTMAREDROP: script_pushint(st,map[m].flag.pvp_nightmaredrop); break;
12302 case MF_RESTRICTED: script_pushint(st,map[m].flag.restricted); break;
12303 case MF_NOCOMMAND: script_pushint(st,map[m].nocommand); break;
12304 case MF_NODROP: script_pushint(st,map[m].flag.nodrop); break;
12305 case MF_JEXP: script_pushint(st,map[m].adjust.jexp); break;
12306 case MF_BEXP: script_pushint(st,map[m].adjust.bexp); break;
12307 case MF_NOVENDING: script_pushint(st,map[m].flag.novending); break;
12308 case MF_LOADEVENT: script_pushint(st,map[m].flag.loadevent); break;
12309 case MF_NOCHAT: script_pushint(st,map[m].flag.nochat); break;
12310 case MF_NOEXPPENALTY: script_pushint(st,map[m].flag.noexppenalty ); break;
12311 case MF_GUILDLOCK: script_pushint(st,map[m].flag.guildlock); break;
12312 case MF_TOWN: script_pushint(st,map[m].flag.town); break;
12313 case MF_AUTOTRADE: script_pushint(st,map[m].flag.autotrade); break;
12314 case MF_ALLOWKS: script_pushint(st,map[m].flag.allowks); break;
12315 case MF_MONSTER_NOTELEPORT: script_pushint(st,map[m].flag.monster_noteleport); break;
12316 case MF_PVP_NOCALCRANK: script_pushint(st,map[m].flag.pvp_nocalcrank); break;
12317 case MF_BATTLEGROUND: script_pushint(st,map[m].flag.battleground); break;
12318 case MF_RESET: script_pushint(st,map[m].flag.reset); break;
12319 case MF_CHANNELAUTOJOIN: script_pushint(st,map[m].flag.chmautojoin); break;
12320 case MF_NOUSECART: script_pushint(st,map[m].flag.nousecart); break;
12321 case MF_NOITEMCONSUMPTION: script_pushint(st,map[m].flag.noitemconsumption); break;
12322 case MF_SUMSTARTMIRACLE: script_pushint(st,map[m].flag.nosumstarmiracle); break;
12323 case MF_NOMINEEFFECT: script_pushint(st,map[m].flag.nomineeffect); break;
12324 case MF_NOLOCKON: script_pushint(st,map[m].flag.nolockon); break;
12325 case MF_NOTOMB: script_pushint(st,map[m].flag.notomb); break;
12326 case MF_NOCOSTUME: script_pushint(st,map[m].flag.nocostume); break;
12327 case MF_GVG_TE_CASTLE: script_pushint(st,map[m].flag.gvg_te_castle); break;
12328 case MF_GVG_TE: script_pushint(st,map[m].flag.gvg_te); break;
12329 case MF_HIDEMOBHPBAR: script_pushint(st,map[m].flag.hidemobhpbar); break;
12330 #ifdef ADJUST_SKILL_DAMAGE
12331 case MF_SKILL_DAMAGE:
12333 int ret_val=0, type=0;
12336 case 1: ret_val = map[m].adjust.damage.pc; break;
12337 case 2: ret_val = map[m].adjust.damage.mob; break;
12338 case 3: ret_val = map[m].adjust.damage.boss; break;
12339 case 4: ret_val = map[m].adjust.damage.other; break;
12340 case 5: ret_val = map[m].adjust.damage.caster; break;
12341 default: ret_val = map[m].flag.skill_damage; break;
12343 script_pushint(st,ret_val); break;
12348 return SCRIPT_CMD_SUCCESS;
12351 /* pvp timer handling */
12352 static int script_mapflag_pvp_sub(struct block_list *bl,va_list ap) {
12353 TBL_PC* sd = (TBL_PC*)bl;
12354 if (sd->pvp_timer == INVALID_TIMER) {
12355 sd->pvp_timer = add_timer(gettick() + 200, pc_calc_pvprank_timer, sd->bl.id, 0);
12357 sd->pvp_lastusers = 0;
12362 clif_map_property(&sd->bl, MAPPROPERTY_FREEPVPZONE,SELF);
12366 BUILDIN_FUNC(setmapflag)
12372 str=script_getstr(st,2);
12373 i=script_getnum(st,3);
12375 m = map_mapname2mapid(str);
12378 case MF_NOMEMO: map[m].flag.nomemo = 1; break;
12379 case MF_NOTELEPORT: map[m].flag.noteleport = 1; break;
12380 case MF_NOSAVE: map[m].flag.nosave = 1; break;
12381 case MF_NOBRANCH: map[m].flag.nobranch = 1; break;
12382 case MF_NOPENALTY: map[m].flag.noexppenalty = 1; map[m].flag.nozenypenalty = 1; break;
12383 case MF_NOZENYPENALTY: map[m].flag.nozenypenalty = 1; break;
12385 map[m].flag.pvp = 1;
12386 if( !battle_config.pk_mode ) {
12387 map_foreachinmap(script_mapflag_pvp_sub,m,BL_PC);
12390 case MF_PVP_NOPARTY: map[m].flag.pvp_noparty = 1; break;
12391 case MF_PVP_NOGUILD: map[m].flag.pvp_noguild = 1; break;
12393 map[m].flag.gvg = 1;
12394 clif_map_property_mapall(m, MAPPROPERTY_AGITZONE);
12396 case MF_GVG_NOPARTY: map[m].flag.gvg_noparty = 1; break;
12397 case MF_NOTRADE: map[m].flag.notrade = 1; break;
12398 case MF_NOSKILL: map[m].flag.noskill = 1; break;
12399 case MF_NOWARP: map[m].flag.nowarp = 1; break;
12400 case MF_PARTYLOCK: map[m].flag.partylock = 1; break;
12401 case MF_NOICEWALL: map[m].flag.noicewall = 1; break;
12402 case MF_SNOW: map[m].flag.snow = 1; break;
12403 case MF_FOG: map[m].flag.fog = 1; break;
12404 case MF_SAKURA: map[m].flag.sakura = 1; break;
12405 case MF_LEAVES: map[m].flag.leaves = 1; break;
12406 case MF_NOGO: map[m].flag.nogo = 1; break;
12407 case MF_CLOUDS: map[m].flag.clouds = 1; break;
12408 case MF_CLOUDS2: map[m].flag.clouds2 = 1; break;
12409 case MF_FIREWORKS: map[m].flag.fireworks = 1; break;
12410 case MF_GVG_CASTLE: map[m].flag.gvg_castle = 1; break;
12411 case MF_GVG_DUNGEON: map[m].flag.gvg_dungeon = 1; break;
12412 case MF_NIGHTENABLED: map[m].flag.nightenabled = 1; break;
12413 case MF_NOBASEEXP: map[m].flag.nobaseexp = 1; break;
12414 case MF_NOJOBEXP: map[m].flag.nojobexp = 1; break;
12415 case MF_NOMOBLOOT: map[m].flag.nomobloot = 1; break;
12416 case MF_NOMVPLOOT: map[m].flag.nomvploot = 1; break;
12417 case MF_NORETURN: map[m].flag.noreturn = 1; break;
12418 case MF_NOWARPTO: map[m].flag.nowarpto = 1; break;
12419 case MF_NIGHTMAREDROP: map[m].flag.pvp_nightmaredrop = 1; break;
12420 case MF_RESTRICTED:
12421 map[m].zone |= 1<<(val+1);
12422 map[m].flag.restricted=1;
12424 case MF_NOCOMMAND: map[m].nocommand = (val <= 0) ? 100 : val; break;
12425 case MF_NODROP: map[m].flag.nodrop = 1; break;
12426 case MF_JEXP: map[m].adjust.jexp = (val <= 0) ? 100 : val; break;
12427 case MF_BEXP: map[m].adjust.bexp = (val <= 0) ? 100 : val; break;
12428 case MF_NOVENDING: map[m].flag.novending = 1; break;
12429 case MF_LOADEVENT: map[m].flag.loadevent = 1; break;
12430 case MF_NOCHAT: map[m].flag.nochat = 1; break;
12431 case MF_NOEXPPENALTY: map[m].flag.noexppenalty = 1; break;
12432 case MF_GUILDLOCK: map[m].flag.guildlock = 1; break;
12433 case MF_TOWN: map[m].flag.town = 1; break;
12434 case MF_AUTOTRADE: map[m].flag.autotrade = 1; break;
12435 case MF_ALLOWKS: map[m].flag.allowks = 1; break;
12436 case MF_MONSTER_NOTELEPORT: map[m].flag.monster_noteleport = 1; break;
12437 case MF_PVP_NOCALCRANK: map[m].flag.pvp_nocalcrank = 1; break;
12438 case MF_BATTLEGROUND: map[m].flag.battleground = (val <= 0 || val > 2) ? 1 : val; break;
12439 case MF_RESET: map[m].flag.reset = 1; break;
12440 case MF_CHANNELAUTOJOIN: map[m].flag.chmautojoin = 1 ; break;
12441 case MF_NOUSECART: map[m].flag.nousecart = 1 ; break;
12442 case MF_NOITEMCONSUMPTION: map[m].flag.noitemconsumption = 1 ; break;
12443 case MF_SUMSTARTMIRACLE: map[m].flag.nosumstarmiracle = 1 ; break;
12444 case MF_NOMINEEFFECT: map[m].flag.nomineeffect = 1 ; break;
12445 case MF_NOLOCKON: map[m].flag.nolockon = 1 ; break;
12446 case MF_NOTOMB: map[m].flag.notomb = 1; break;
12447 case MF_NOCOSTUME: map[m].flag.nocostume = 1; break;
12448 case MF_GVG_TE_CASTLE: map[m].flag.gvg_te_castle = 1; break;
12450 map[m].flag.gvg_te = 1;
12451 clif_map_property_mapall(m, MAPPROPERTY_AGITZONE);
12453 case MF_HIDEMOBHPBAR: map[m].flag.hidemobhpbar = 1; break;
12454 #ifdef ADJUST_SKILL_DAMAGE
12455 case MF_SKILL_DAMAGE:
12460 case 1: map[m].adjust.damage.pc = val; break;
12461 case 2: map[m].adjust.damage.mob = val; break;
12462 case 3: map[m].adjust.damage.boss = val; break;
12463 case 4: map[m].adjust.damage.other = val; break;
12464 case 5: map[m].adjust.damage.caster = val; break;
12466 map[m].flag.skill_damage = 1;
12471 return SCRIPT_CMD_SUCCESS;
12474 BUILDIN_FUNC(removemapflag)
12480 str=script_getstr(st,2);
12481 i=script_getnum(st,3);
12483 m = map_mapname2mapid(str);
12486 case MF_NOMEMO: map[m].flag.nomemo = 0; break;
12487 case MF_NOTELEPORT: map[m].flag.noteleport = 0; break;
12488 case MF_NOSAVE: map[m].flag.nosave = 0; break;
12489 case MF_NOBRANCH: map[m].flag.nobranch = 0; break;
12490 case MF_NOPENALTY: map[m].flag.noexppenalty = 0; map[m].flag.nozenypenalty = 0; break;
12491 case MF_NOZENYPENALTY: map[m].flag.nozenypenalty = 0; break;
12493 map[m].flag.pvp = 0;
12494 clif_map_property_mapall(m, MAPPROPERTY_NOTHING);
12496 case MF_PVP_NOPARTY: map[m].flag.pvp_noparty = 0; break;
12497 case MF_PVP_NOGUILD: map[m].flag.pvp_noguild = 0; break;
12499 map[m].flag.gvg = 0;
12500 clif_map_property_mapall(m, MAPPROPERTY_NOTHING);
12502 case MF_GVG_NOPARTY: map[m].flag.gvg_noparty = 0; break;
12503 case MF_NOTRADE: map[m].flag.notrade = 0; break;
12504 case MF_NOSKILL: map[m].flag.noskill = 0; break;
12505 case MF_NOWARP: map[m].flag.nowarp = 0; break;
12506 case MF_PARTYLOCK: map[m].flag.partylock = 0; break;
12507 case MF_NOICEWALL: map[m].flag.noicewall = 0; break;
12508 case MF_SNOW: map[m].flag.snow = 0; break;
12509 case MF_FOG: map[m].flag.fog = 0; break;
12510 case MF_SAKURA: map[m].flag.sakura = 0; break;
12511 case MF_LEAVES: map[m].flag.leaves = 0; break;
12512 case MF_NOGO: map[m].flag.nogo = 0; break;
12513 case MF_CLOUDS: map[m].flag.clouds = 0; break;
12514 case MF_CLOUDS2: map[m].flag.clouds2 = 0; break;
12515 case MF_FIREWORKS: map[m].flag.fireworks = 0; break;
12516 case MF_GVG_CASTLE: map[m].flag.gvg_castle = 0; break;
12517 case MF_GVG_DUNGEON: map[m].flag.gvg_dungeon = 0; break;
12518 case MF_NIGHTENABLED: map[m].flag.nightenabled = 0; break;
12519 case MF_NOBASEEXP: map[m].flag.nobaseexp = 0; break;
12520 case MF_NOJOBEXP: map[m].flag.nojobexp = 0; break;
12521 case MF_NOMOBLOOT: map[m].flag.nomobloot = 0; break;
12522 case MF_NOMVPLOOT: map[m].flag.nomvploot = 0; break;
12523 case MF_NORETURN: map[m].flag.noreturn = 0; break;
12524 case MF_NOWARPTO: map[m].flag.nowarpto = 0; break;
12525 case MF_NIGHTMAREDROP: map[m].flag.pvp_nightmaredrop = 0; break;
12526 case MF_RESTRICTED:
12527 map[m].zone ^= 1<<(val+1);
12528 if (map[m].zone == 0){
12529 map[m].flag.restricted=0;
12532 case MF_NOCOMMAND: map[m].nocommand = 0; break;
12533 case MF_NODROP: map[m].flag.nodrop = 0; break;
12534 case MF_JEXP: map[m].adjust.jexp = 0; break;
12535 case MF_BEXP: map[m].adjust.bexp = 0; break;
12536 case MF_NOVENDING: map[m].flag.novending = 0; break;
12537 case MF_LOADEVENT: map[m].flag.loadevent = 0; break;
12538 case MF_NOCHAT: map[m].flag.nochat = 0; break;
12539 case MF_NOEXPPENALTY: map[m].flag.noexppenalty = 0; break;
12540 case MF_GUILDLOCK: map[m].flag.guildlock = 0; break;
12541 case MF_TOWN: map[m].flag.town = 0; break;
12542 case MF_AUTOTRADE: map[m].flag.autotrade = 0; break;
12543 case MF_ALLOWKS: map[m].flag.allowks = 0; break;
12544 case MF_MONSTER_NOTELEPORT: map[m].flag.monster_noteleport = 0; break;
12545 case MF_PVP_NOCALCRANK: map[m].flag.pvp_nocalcrank = 0; break;
12546 case MF_BATTLEGROUND: map[m].flag.battleground = 0; break;
12547 case MF_RESET: map[m].flag.reset = 0; break;
12548 case MF_CHANNELAUTOJOIN: map[m].flag.chmautojoin = 0 ; break;
12549 case MF_NOUSECART: map[m].flag.nousecart = 0 ; break;
12550 case MF_NOITEMCONSUMPTION: map[m].flag.noitemconsumption = 0 ; break;
12551 case MF_SUMSTARTMIRACLE: map[m].flag.nosumstarmiracle = 0 ; break;
12552 case MF_NOMINEEFFECT: map[m].flag.nomineeffect = 0 ; break;
12553 case MF_NOLOCKON: map[m].flag.nolockon = 0 ; break;
12554 case MF_NOTOMB: map[m].flag.notomb = 0; break;
12555 case MF_NOCOSTUME: map[m].flag.nocostume = 0; break;
12556 case MF_GVG_TE_CASTLE: map[m].flag.gvg_te_castle = 0; break;
12558 map[m].flag.gvg_te = 0;
12559 clif_map_property_mapall(m, MAPPROPERTY_NOTHING);
12561 case MF_HIDEMOBHPBAR: map[m].flag.hidemobhpbar = 0; break;
12562 #ifdef ADJUST_SKILL_DAMAGE
12563 case MF_SKILL_DAMAGE:
12565 map[m].flag.skill_damage = 0;
12566 memset(&map[m].adjust.damage, 0, sizeof(map[m].adjust.damage));
12567 if (map[m].skill_damage.count)
12568 map_skill_damage_free(&map[m]);
12573 return SCRIPT_CMD_SUCCESS;
12576 BUILDIN_FUNC(pvpon)
12581 struct s_mapiterator* iter;
12583 str = script_getstr(st,2);
12584 m = map_mapname2mapid(str);
12585 if( m < 0 || map[m].flag.pvp )
12586 return SCRIPT_CMD_SUCCESS; // nothing to do
12588 map[m].flag.pvp = 1;
12589 clif_map_property_mapall(m, MAPPROPERTY_FREEPVPZONE);
12591 if(battle_config.pk_mode) // disable ranking functions if pk_mode is on [Valaris]
12592 return SCRIPT_CMD_SUCCESS;
12594 iter = mapit_getallusers();
12595 for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter) )
12597 if( sd->bl.m != m || sd->pvp_timer != INVALID_TIMER )
12598 continue; // not applicable
12600 sd->pvp_timer = add_timer(gettick()+200,pc_calc_pvprank_timer,sd->bl.id,0);
12602 sd->pvp_lastusers = 0;
12608 return SCRIPT_CMD_SUCCESS;
12611 static int buildin_pvpoff_sub(struct block_list *bl,va_list ap)
12613 TBL_PC* sd = (TBL_PC*)bl;
12614 clif_pvpset(sd, 0, 0, 2);
12615 if (sd->pvp_timer != INVALID_TIMER) {
12616 delete_timer(sd->pvp_timer, pc_calc_pvprank_timer);
12617 sd->pvp_timer = INVALID_TIMER;
12622 BUILDIN_FUNC(pvpoff)
12627 str=script_getstr(st,2);
12628 m = map_mapname2mapid(str);
12629 if(m < 0 || !map[m].flag.pvp)
12630 return SCRIPT_CMD_SUCCESS; //fixed Lupus
12632 map[m].flag.pvp = 0;
12633 clif_map_property_mapall(m, MAPPROPERTY_NOTHING);
12635 if(battle_config.pk_mode) // disable ranking options if pk_mode is on [Valaris]
12636 return SCRIPT_CMD_SUCCESS;
12638 map_foreachinmap(buildin_pvpoff_sub, m, BL_PC);
12639 return SCRIPT_CMD_SUCCESS;
12642 BUILDIN_FUNC(gvgon)
12647 str=script_getstr(st,2);
12648 m = map_mapname2mapid(str);
12649 if(m >= 0 && !map[m].flag.gvg) {
12650 map[m].flag.gvg = 1;
12651 clif_map_property_mapall(m, MAPPROPERTY_AGITZONE);
12653 return SCRIPT_CMD_SUCCESS;
12656 BUILDIN_FUNC(gvgoff)
12661 str=script_getstr(st,2);
12662 m = map_mapname2mapid(str);
12663 if(m >= 0 && map[m].flag.gvg) {
12664 map[m].flag.gvg = 0;
12665 clif_map_property_mapall(m, MAPPROPERTY_NOTHING);
12667 return SCRIPT_CMD_SUCCESS;
12670 BUILDIN_FUNC(gvgon3)
12675 str = script_getstr(st,2);
12676 m = map_mapname2mapid(str);
12677 if (m >= 0 && !map[m].flag.gvg_te) {
12678 map[m].flag.gvg_te = 1;
12679 clif_map_property_mapall(m, MAPPROPERTY_AGITZONE);
12681 return SCRIPT_CMD_SUCCESS;
12684 BUILDIN_FUNC(gvgoff3)
12689 str = script_getstr(st,2);
12690 m = map_mapname2mapid(str);
12691 if (m >= 0 && map[m].flag.gvg_te) {
12692 map[m].flag.gvg_te = 0;
12693 clif_map_property_mapall(m, MAPPROPERTY_NOTHING);
12695 return SCRIPT_CMD_SUCCESS;
12698 /*==========================================
12699 * Shows an emoticon on top of the player/npc
12700 * emotion emotion#, <target: 0 - NPC, 1 - PC>, <NPC/PC name>
12701 *------------------------------------------*/
12702 //Optional second parameter added by [Skotlex]
12703 BUILDIN_FUNC(emotion)
12708 type=script_getnum(st,2);
12709 if(type < 0 || type > 100)
12710 return SCRIPT_CMD_SUCCESS;
12712 if( script_hasdata(st,3) )
12713 player=script_getnum(st,3);
12718 if( script_nick2sd(4,sd) ){
12719 clif_emotion(&sd->bl, type);
12722 if( script_hasdata(st,4) )
12724 TBL_NPC *nd = npc_name2id(script_getstr(st,4));
12726 clif_emotion(&nd->bl,type);
12729 clif_emotion(map_id2bl(st->oid),type);
12730 return SCRIPT_CMD_SUCCESS;
12734 static int buildin_maprespawnguildid_sub_pc(struct map_session_data* sd, va_list ap)
12736 int16 m=va_arg(ap,int);
12737 int g_id=va_arg(ap,int);
12738 int flag=va_arg(ap,int);
12740 if(!sd || sd->bl.m != m)
12743 (sd->status.guild_id == g_id && flag&1) || //Warp out owners
12744 (sd->status.guild_id != g_id && flag&2) || //Warp out outsiders
12745 (sd->status.guild_id == 0 && flag&2) // Warp out players not in guild
12747 pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
12751 static int buildin_maprespawnguildid_sub_mob(struct block_list *bl,va_list ap)
12753 struct mob_data *md=(struct mob_data *)bl;
12755 if(!md->guardian_data && md->mob_id != MOBID_EMPERIUM && ( !mob_is_clone(md->mob_id) || battle_config.guild_maprespawn_clones ))
12762 * Function to kick guild members out of a map and to their save points.
12764 * g_id : owner guild id
12765 * flag & 1 : Warp out owners
12766 * flag & 2 : Warp out outsiders
12767 * flag & 4 : reserved for mobs
12769 BUILDIN_FUNC(maprespawnguildid)
12771 const char *mapname=script_getstr(st,2);
12772 int g_id=script_getnum(st,3);
12773 int flag=script_getnum(st,4);
12775 int16 m=map_mapname2mapid(mapname);
12778 return SCRIPT_CMD_SUCCESS;
12780 //Catch ALL players (in case some are 'between maps' on execution time)
12781 map_foreachpc(buildin_maprespawnguildid_sub_pc,m,g_id,flag);
12782 if (flag&4) //Remove script mobs.
12783 map_foreachinmap(buildin_maprespawnguildid_sub_mob,m,BL_MOB);
12784 return SCRIPT_CMD_SUCCESS;
12793 BUILDIN_FUNC(agitstart)
12795 guild_agit_start();
12797 return SCRIPT_CMD_SUCCESS;
12804 BUILDIN_FUNC(agitend)
12808 return SCRIPT_CMD_SUCCESS;
12815 BUILDIN_FUNC(agitstart2)
12817 guild_agit2_start();
12819 return SCRIPT_CMD_SUCCESS;
12826 BUILDIN_FUNC(agitend2)
12830 return SCRIPT_CMD_SUCCESS;
12837 BUILDIN_FUNC(agitstart3)
12839 guild_agit3_start();
12841 return SCRIPT_CMD_SUCCESS;
12848 BUILDIN_FUNC(agitend3)
12852 return SCRIPT_CMD_SUCCESS;
12856 * Returns whether WoE:FE is on or off.
12859 BUILDIN_FUNC(agitcheck)
12861 script_pushint(st, agit_flag);
12862 return SCRIPT_CMD_SUCCESS;
12866 * Returns whether WoE:SE is on or off.
12869 BUILDIN_FUNC(agitcheck2)
12871 script_pushint(st, agit2_flag);
12872 return SCRIPT_CMD_SUCCESS;
12876 * Returns whether WoE:TE is on or off.
12879 BUILDIN_FUNC(agitcheck3)
12881 script_pushint(st, agit3_flag);
12882 return SCRIPT_CMD_SUCCESS;
12885 /// Sets the guild_id of this npc.
12887 /// flagemblem <guild_id>;
12888 BUILDIN_FUNC(flagemblem)
12891 int g_id = script_getnum(st,2);
12894 return SCRIPT_CMD_SUCCESS;
12896 nd = (TBL_NPC*)map_id2nd(st->oid);
12898 ShowError("script:flagemblem: npc %d not found\n", st->oid);
12899 } else if( nd->subtype != NPCTYPE_SCRIPT ) {
12900 ShowError("script:flagemblem: unexpected subtype %d for npc %d '%s'\n", nd->subtype, st->oid, nd->exname);
12902 bool changed = ( nd->u.scr.guild_id != g_id )?true:false;
12903 nd->u.scr.guild_id = g_id;
12904 clif_guild_emblem_area(&nd->bl);
12905 /* guild flag caching */
12906 if( g_id ) /* adding a id */
12907 guild_flag_add(nd);
12908 else if( changed ) /* removing a flag */
12909 guild_flag_remove(nd);
12911 return SCRIPT_CMD_SUCCESS;
12914 BUILDIN_FUNC(getcastlename)
12916 const char* mapname = mapindex_getmapname(script_getstr(st,2),NULL);
12917 struct guild_castle* gc = guild_mapname2gc(mapname);
12918 const char* name = (gc) ? gc->castle_name : "";
12919 script_pushstrcopy(st,name);
12920 return SCRIPT_CMD_SUCCESS;
12923 BUILDIN_FUNC(getcastledata)
12925 const char *mapname = mapindex_getmapname(script_getstr(st,2),NULL);
12926 int index = script_getnum(st,3);
12927 struct guild_castle *gc = guild_mapname2gc(mapname);
12930 script_pushint(st,0);
12931 ShowWarning("buildin_getcastledata: guild castle for map '%s' not found\n", mapname);
12932 return SCRIPT_CMD_FAILURE;
12937 script_pushint(st,gc->guild_id); break;
12939 script_pushint(st,gc->economy); break;
12941 script_pushint(st,gc->defense); break;
12943 script_pushint(st,gc->triggerE); break;
12945 script_pushint(st,gc->triggerD); break;
12947 script_pushint(st,gc->nextTime); break;
12949 script_pushint(st,gc->payTime); break;
12951 script_pushint(st,gc->createTime); break;
12953 script_pushint(st,gc->visibleC); break;
12955 if (index > 9 && index <= 9+MAX_GUARDIANS) {
12956 script_pushint(st,gc->guardian[index-10].visible);
12959 script_pushint(st,0);
12960 ShowWarning("buildin_getcastledata: index = '%d' is out of allowed range\n", index);
12961 return SCRIPT_CMD_FAILURE;
12963 return SCRIPT_CMD_SUCCESS;
12966 BUILDIN_FUNC(setcastledata)
12968 const char *mapname = mapindex_getmapname(script_getstr(st,2),NULL);
12969 int index = script_getnum(st,3);
12970 int value = script_getnum(st,4);
12971 struct guild_castle *gc = guild_mapname2gc(mapname);
12974 ShowWarning("buildin_setcastledata: guild castle for map '%s' not found\n", mapname);
12975 return SCRIPT_CMD_FAILURE;
12978 if (index <= 0 || index > 9+MAX_GUARDIANS) {
12979 ShowWarning("buildin_setcastledata: index = '%d' is out of allowed range\n", index);
12980 return SCRIPT_CMD_FAILURE;
12983 guild_castledatasave(gc->castle_id, index, value);
12984 return SCRIPT_CMD_SUCCESS;
12987 /* =====================================================================
12988 * ---------------------------------------------------------------------*/
12989 BUILDIN_FUNC(requestguildinfo)
12991 int guild_id=script_getnum(st,2);
12992 const char *event=NULL;
12994 if( script_hasdata(st,3) ){
12995 event=script_getstr(st,3);
12996 check_event(st, event);
13000 guild_npc_request_info(guild_id,event);
13001 return SCRIPT_CMD_SUCCESS;
13004 /// Returns the number of cards that have been compounded onto the specified equipped item.
13005 /// getequipcardcnt(<equipment slot>);
13006 BUILDIN_FUNC(getequipcardcnt)
13012 if( !script_rid2sd(sd) )
13013 return SCRIPT_CMD_SUCCESS;
13015 num=script_getnum(st,2);
13016 if (equip_index_check(num))
13017 i=pc_checkequip(sd,equip_bitmask[num]);
13019 if (i < 0 || !sd->inventory_data[i]) {
13020 script_pushint(st,0);
13021 return SCRIPT_CMD_SUCCESS;
13024 if(itemdb_isspecial(sd->inventory.u.items_inventory[i].card[0]))
13026 script_pushint(st,0);
13027 return SCRIPT_CMD_SUCCESS;
13031 for( j = 0; j < sd->inventory_data[i]->slot; j++ )
13032 if( sd->inventory.u.items_inventory[i].card[j] && itemdb_type(sd->inventory.u.items_inventory[i].card[j]) == IT_CARD )
13035 script_pushint(st,count);
13036 return SCRIPT_CMD_SUCCESS;
13039 /// Removes all cards from the item found in the specified equipment slot of the invoking character,
13040 /// and give them to the character. If any cards were removed in this manner, it will also show a success effect.
13041 /// successremovecards <slot>;
13042 BUILDIN_FUNC(successremovecards) {
13043 int i=-1,c,cardflag=0;
13048 if( !script_rid2sd(sd) )
13049 return SCRIPT_CMD_SUCCESS;
13051 num = script_getnum(st,2);
13053 if (equip_index_check(num))
13054 i=pc_checkequip(sd,equip_bitmask[num]);
13056 if (i < 0 || !sd->inventory_data[i]) {
13057 return SCRIPT_CMD_SUCCESS;
13060 if(itemdb_isspecial(sd->inventory.u.items_inventory[i].card[0]))
13061 return SCRIPT_CMD_SUCCESS;
13063 for( c = sd->inventory_data[i]->slot - 1; c >= 0; --c ) {
13064 if( sd->inventory.u.items_inventory[i].card[c] && itemdb_type(sd->inventory.u.items_inventory[i].card[c]) == IT_CARD ) {// extract this card from the item
13065 unsigned char flag = 0;
13066 struct item item_tmp;
13067 memset(&item_tmp,0,sizeof(item_tmp));
13069 item_tmp.nameid = sd->inventory.u.items_inventory[i].card[c];
13070 item_tmp.identify = 1;
13072 if((flag=pc_additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))){ // get back the cart in inventory
13073 clif_additem(sd,0,0,flag);
13074 map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0);
13079 if(cardflag == 1) {//if card was remove remplace item with no card
13080 unsigned char flag = 0, j;
13081 struct item item_tmp;
13082 memset(&item_tmp,0,sizeof(item_tmp));
13084 item_tmp.nameid = sd->inventory.u.items_inventory[i].nameid;
13085 item_tmp.identify = 1;
13086 item_tmp.refine = sd->inventory.u.items_inventory[i].refine;
13087 item_tmp.attribute = sd->inventory.u.items_inventory[i].attribute;
13088 item_tmp.expire_time = sd->inventory.u.items_inventory[i].expire_time;
13089 item_tmp.bound = sd->inventory.u.items_inventory[i].bound;
13091 for (j = sd->inventory_data[i]->slot; j < MAX_SLOTS; j++)
13092 item_tmp.card[j]=sd->inventory.u.items_inventory[i].card[j];
13094 for (j = 0; j < MAX_ITEM_RDM_OPT; j++){
13095 item_tmp.option[j].id=sd->inventory.u.items_inventory[i].option[j].id;
13096 item_tmp.option[j].value=sd->inventory.u.items_inventory[i].option[j].value;
13097 item_tmp.option[j].param=sd->inventory.u.items_inventory[i].option[j].param;
13100 pc_delitem(sd,i,1,0,3,LOG_TYPE_SCRIPT);
13101 if((flag=pc_additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))){ //chk if can be spawn in inventory otherwise put on floor
13102 clif_additem(sd,0,0,flag);
13103 map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0);
13106 clif_misceffect(&sd->bl,3);
13108 return SCRIPT_CMD_SUCCESS;
13111 /// Removes all cards from the item found in the specified equipment slot of the invoking character.
13112 /// failedremovecards <slot>, <type>;
13113 /// <type>=0 : will destroy both the item and the cards.
13114 /// <type>=1 : will keep the item, but destroy the cards.
13115 /// <type>=2 : will keep the cards, but destroy the item.
13116 /// <type>=? : will just display the failure effect.
13117 BUILDIN_FUNC(failedremovecards) {
13118 int i=-1,c,cardflag=0;
13124 if( !script_rid2sd(sd) )
13125 return SCRIPT_CMD_SUCCESS;
13127 num = script_getnum(st,2);
13128 typefail = script_getnum(st,3);
13130 if (equip_index_check(num))
13131 i=pc_checkequip(sd,equip_bitmask[num]);
13133 if (i < 0 || !sd->inventory_data[i])
13134 return SCRIPT_CMD_SUCCESS;
13136 if(itemdb_isspecial(sd->inventory.u.items_inventory[i].card[0]))
13137 return SCRIPT_CMD_SUCCESS;
13139 for( c = sd->inventory_data[i]->slot - 1; c >= 0; --c ) {
13140 if( sd->inventory.u.items_inventory[i].card[c] && itemdb_type(sd->inventory.u.items_inventory[i].card[c]) == IT_CARD ) {
13143 if(typefail == 2) {// add cards to inventory, clear
13144 unsigned char flag = 0;
13145 struct item item_tmp;
13147 memset(&item_tmp,0,sizeof(item_tmp));
13149 item_tmp.nameid = sd->inventory.u.items_inventory[i].card[c];
13150 item_tmp.identify = 1;
13152 if((flag=pc_additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))){
13153 clif_additem(sd,0,0,flag);
13154 map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0);
13160 if(cardflag == 1) {
13161 if(typefail == 0 || typefail == 2){ // destroy the item
13162 pc_delitem(sd,i,1,0,2,LOG_TYPE_SCRIPT);
13163 }else if(typefail == 1){ // destroy the card
13164 unsigned char flag = 0, j;
13165 struct item item_tmp;
13167 memset(&item_tmp,0,sizeof(item_tmp));
13169 item_tmp.nameid = sd->inventory.u.items_inventory[i].nameid;
13170 item_tmp.identify = 1;
13171 item_tmp.refine = sd->inventory.u.items_inventory[i].refine;
13172 item_tmp.attribute = sd->inventory.u.items_inventory[i].attribute;
13173 item_tmp.expire_time = sd->inventory.u.items_inventory[i].expire_time;
13174 item_tmp.bound = sd->inventory.u.items_inventory[i].bound;
13176 for (j = sd->inventory_data[i]->slot; j < MAX_SLOTS; j++)
13177 item_tmp.card[j]=sd->inventory.u.items_inventory[i].card[j];
13179 for (j = 0; j < MAX_ITEM_RDM_OPT; j++){
13180 item_tmp.option[j].id=sd->inventory.u.items_inventory[i].option[j].id;
13181 item_tmp.option[j].value=sd->inventory.u.items_inventory[i].option[j].value;
13182 item_tmp.option[j].param=sd->inventory.u.items_inventory[i].option[j].param;
13185 pc_delitem(sd,i,1,0,2,LOG_TYPE_SCRIPT);
13187 if((flag=pc_additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))){
13188 clif_additem(sd,0,0,flag);
13189 map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0);
13192 clif_misceffect(&sd->bl,2);
13194 return SCRIPT_CMD_SUCCESS;
13197 /* ================================================================
13198 * mapwarp "<from map>","<to map>",<x>,<y>,<type>,<ID for Type>;
13199 * type: 0=everyone, 1=guild, 2=party; [Reddozen]
13200 * improved by [Lance]
13201 * ================================================================*/
13202 BUILDIN_FUNC(mapwarp) // Added by RoVeRT
13204 int x,y,m,check_val=0,check_ID=0,i=0;
13205 struct guild *g = NULL;
13206 struct party_data *p = NULL;
13208 const char *mapname;
13209 unsigned int index;
13210 mapname=script_getstr(st,2);
13211 str=script_getstr(st,3);
13212 x=script_getnum(st,4);
13213 y=script_getnum(st,5);
13214 if(script_hasdata(st,7)){
13215 check_val=script_getnum(st,6);
13216 check_ID=script_getnum(st,7);
13219 if((m=map_mapname2mapid(mapname))< 0)
13220 return SCRIPT_CMD_SUCCESS;
13222 if(!(index=mapindex_name2id(str)))
13223 return SCRIPT_CMD_SUCCESS;
13227 g = guild_search(check_ID);
13229 for( i=0; i < g->max_member; i++)
13231 if(g->member[i].sd && g->member[i].sd->bl.m==m){
13232 pc_setpos(g->member[i].sd,index,x,y,CLR_TELEPORT);
13238 p = party_search(check_ID);
13240 for(i=0;i<MAX_PARTY; i++){
13241 if(p->data[i].sd && p->data[i].sd->bl.m == m){
13242 pc_setpos(p->data[i].sd,index,x,y,CLR_TELEPORT);
13248 map_foreachinmap(buildin_areawarp_sub,m,BL_PC,index,x,y,0,0);
13251 return SCRIPT_CMD_SUCCESS;
13254 static int buildin_mobcount_sub(struct block_list *bl,va_list ap) // Added by RoVeRT
13256 char *event=va_arg(ap,char *);
13257 struct mob_data *md = ((struct mob_data *)bl);
13258 if( md->status.hp > 0 && (!event || strcmp(event,md->npc_event) == 0) )
13260 return SCRIPT_CMD_SUCCESS;
13263 BUILDIN_FUNC(mobcount) // Added by RoVeRT
13265 const char *mapname,*event;
13267 mapname=script_getstr(st,2);
13268 event=script_getstr(st,3);
13270 if( strcmp(event, "all") == 0 )
13273 check_event(st, event);
13275 if( strcmp(mapname, "this") == 0 ) {
13276 struct map_session_data *sd;
13277 if( script_rid2sd(sd) )
13280 script_pushint(st,-1);
13281 return SCRIPT_CMD_SUCCESS;
13284 else if( (m = map_mapname2mapid(mapname)) < 0 ) {
13285 script_pushint(st,-1);
13286 return SCRIPT_CMD_SUCCESS;
13289 script_pushint(st,map_foreachinmap(buildin_mobcount_sub, m, BL_MOB, event));
13290 return SCRIPT_CMD_SUCCESS;
13293 BUILDIN_FUNC(marriage)
13298 if(!script_rid2sd(sd) || !(p_sd=map_nick2sd(script_getstr(st,2),false)) || !pc_marriage(sd,p_sd)){
13299 script_pushint(st,0);
13300 return SCRIPT_CMD_SUCCESS;
13302 script_pushint(st,1);
13303 return SCRIPT_CMD_SUCCESS;
13306 BUILDIN_FUNC(wedding_effect)
13309 struct block_list *bl;
13311 if(!script_rid2sd(sd)) {
13312 bl=map_id2bl(st->oid);
13315 clif_wedding_effect(bl);
13316 return SCRIPT_CMD_SUCCESS;
13320 * divorce({<char_id>})
13322 BUILDIN_FUNC(divorce)
13326 if (!script_charid2sd(2,sd) || !pc_divorce(sd)) {
13327 script_pushint(st,0);
13328 return SCRIPT_CMD_FAILURE;
13330 script_pushint(st,1);
13331 return SCRIPT_CMD_SUCCESS;
13335 * ispartneron({<char_id>})
13337 BUILDIN_FUNC(ispartneron)
13341 if (!script_charid2sd(2,sd) || !pc_ismarried(sd) ||
13342 map_charid2sd(sd->status.partner_id) == NULL)
13344 script_pushint(st,0);
13345 return SCRIPT_CMD_FAILURE;
13348 script_pushint(st,1);
13349 return SCRIPT_CMD_SUCCESS;
13353 * getpartnerid({<char_id>})
13355 BUILDIN_FUNC(getpartnerid)
13359 if (!script_charid2sd(2,sd)) {
13360 script_pushint(st,0);
13361 return SCRIPT_CMD_FAILURE;
13364 script_pushint(st,sd->status.partner_id);
13365 return SCRIPT_CMD_SUCCESS;
13369 * getchildid({<char_id>})
13371 BUILDIN_FUNC(getchildid)
13375 if (!script_charid2sd(2,sd)) {
13376 script_pushint(st,0);
13377 return SCRIPT_CMD_FAILURE;
13380 script_pushint(st,sd->status.child);
13381 return SCRIPT_CMD_SUCCESS;
13385 * getmotherid({<char_id>})
13387 BUILDIN_FUNC(getmotherid)
13391 if (!script_charid2sd(2,sd)) {
13392 script_pushint(st,0);
13393 return SCRIPT_CMD_FAILURE;
13396 script_pushint(st,sd->status.mother);
13397 return SCRIPT_CMD_SUCCESS;
13401 * getfatherid({<char_id>})
13403 BUILDIN_FUNC(getfatherid)
13407 if (!script_charid2sd(2,sd)) {
13408 script_pushint(st,0);
13409 return SCRIPT_CMD_FAILURE;
13412 script_pushint(st,sd->status.father);
13413 return SCRIPT_CMD_SUCCESS;
13416 BUILDIN_FUNC(warppartner)
13419 unsigned short mapindex;
13424 if(!script_rid2sd(sd) || !pc_ismarried(sd) ||
13425 (p_sd=map_charid2sd(sd->status.partner_id)) == NULL) {
13426 script_pushint(st,0);
13427 return SCRIPT_CMD_SUCCESS;
13430 str=script_getstr(st,2);
13431 x=script_getnum(st,3);
13432 y=script_getnum(st,4);
13434 mapindex = mapindex_name2id(str);
13436 pc_setpos(p_sd,mapindex,x,y,CLR_OUTSIGHT);
13437 script_pushint(st,1);
13439 script_pushint(st,0);
13440 return SCRIPT_CMD_SUCCESS;
13443 /*================================================
13444 * Script for Displaying MOB Information [Valaris]
13445 *------------------------------------------------*/
13446 BUILDIN_FUNC(strmobinfo)
13449 int num=script_getnum(st,2);
13450 int class_=script_getnum(st,3);
13452 if(!mobdb_checkid(class_))
13454 if (num < 3) //requested a string
13455 script_pushconststr(st,"");
13457 script_pushint(st,0);
13458 return SCRIPT_CMD_SUCCESS;
13462 case 1: script_pushstrcopy(st,mob_db(class_)->name); break;
13463 case 2: script_pushstrcopy(st,mob_db(class_)->jname); break;
13464 case 3: script_pushint(st,mob_db(class_)->lv); break;
13465 case 4: script_pushint(st,mob_db(class_)->status.max_hp); break;
13466 case 5: script_pushint(st,mob_db(class_)->status.max_sp); break;
13467 case 6: script_pushint(st,mob_db(class_)->base_exp); break;
13468 case 7: script_pushint(st,mob_db(class_)->job_exp); break;
13470 script_pushint(st,0);
13473 return SCRIPT_CMD_SUCCESS;
13476 /*==========================================
13477 * Summon guardians [Valaris]
13478 * guardian("<map name>",<x>,<y>,"<name to show>",<mob id>{,"<event label>"}{,<guardian index>}) -> <id>
13479 *------------------------------------------*/
13480 BUILDIN_FUNC(guardian)
13482 int class_=0,x=0,y=0,guardian=0;
13483 const char *str,*mapname,*evt="";
13484 bool has_index = false;
13486 mapname =script_getstr(st,2);
13487 x =script_getnum(st,3);
13488 y =script_getnum(st,4);
13489 str =script_getstr(st,5);
13490 class_=script_getnum(st,6);
13492 if( script_hasdata(st,8) )
13493 {// "<event label>",<guardian index>
13494 evt=script_getstr(st,7);
13495 guardian=script_getnum(st,8);
13497 } else if( script_hasdata(st,7) ){
13498 struct script_data *data = script_getdata(st,7);
13500 if( data_isstring(data) )
13501 {// "<event label>"
13502 evt=script_getstr(st,7);
13503 } else if( data_isint(data) )
13504 {// <guardian index>
13505 guardian=script_getnum(st,7);
13508 ShowError("script:guardian: invalid data type for argument #6 (from 1)\n");
13509 script_reportdata(data);
13510 return SCRIPT_CMD_FAILURE;
13514 check_event(st, evt);
13515 script_pushint(st, mob_spawn_guardian(mapname,x,y,str,class_,evt,guardian,has_index));
13516 return SCRIPT_CMD_SUCCESS;
13519 /*==========================================
13520 * Invisible Walls [Zephyrus]
13521 *------------------------------------------*/
13522 BUILDIN_FUNC(setwall)
13524 const char *mapname, *name;
13525 int x, y, m, size, dir;
13528 mapname = script_getstr(st,2);
13529 x = script_getnum(st,3);
13530 y = script_getnum(st,4);
13531 size = script_getnum(st,5);
13532 dir = script_getnum(st,6);
13533 shootable = script_getnum(st,7) != 0;
13534 name = script_getstr(st,8);
13536 if( (m = map_mapname2mapid(mapname)) < 0 )
13537 return SCRIPT_CMD_SUCCESS; // Invalid Map
13539 map_iwall_set(m, x, y, size, dir, shootable, name);
13540 return SCRIPT_CMD_SUCCESS;
13543 BUILDIN_FUNC(delwall)
13545 const char *name = script_getstr(st,2);
13546 map_iwall_remove(name);
13547 return SCRIPT_CMD_SUCCESS;
13550 /// Retrieves various information about the specified guardian.
13552 /// guardianinfo("<map_name>", <index>, <type>) -> <value>
13553 /// type: 0 - whether it is deployed or not
13557 BUILDIN_FUNC(guardianinfo)
13559 const char* mapname = mapindex_getmapname(script_getstr(st,2),NULL);
13560 int id = script_getnum(st,3);
13561 int type = script_getnum(st,4);
13563 struct guild_castle* gc = guild_mapname2gc(mapname);
13564 struct mob_data* gd;
13566 if( gc == NULL || id < 0 || id >= MAX_GUARDIANS )
13568 script_pushint(st,-1);
13569 return SCRIPT_CMD_SUCCESS;
13573 script_pushint(st, gc->guardian[id].visible);
13575 if( !gc->guardian[id].visible )
13576 script_pushint(st,-1);
13578 if( (gd = map_id2md(gc->guardian[id].id)) == NULL )
13579 script_pushint(st,-1);
13582 if ( type == 1 ) script_pushint(st,gd->status.max_hp);
13583 else if( type == 2 ) script_pushint(st,gd->status.hp);
13585 script_pushint(st,-1);
13587 return SCRIPT_CMD_SUCCESS;
13590 /*==========================================
13591 * Get the item name by item_id or null
13592 *------------------------------------------*/
13593 BUILDIN_FUNC(getitemname)
13595 unsigned short item_id = 0;
13596 struct item_data *i_data;
13598 struct script_data *data;
13600 data=script_getdata(st,2);
13603 if( data_isstring(data) ){
13604 const char *name=conv_str(st,data);
13605 struct item_data *item_data = itemdb_searchname(name);
13607 item_id=item_data->nameid;
13609 item_id=conv_num(st,data);
13611 i_data = itemdb_exists(item_id);
13612 if (i_data == NULL)
13614 script_pushconststr(st,"null");
13615 return SCRIPT_CMD_SUCCESS;
13617 item_name=(char *)aMalloc(ITEM_NAME_LENGTH*sizeof(char));
13619 memcpy(item_name, i_data->jname, ITEM_NAME_LENGTH);
13620 script_pushstr(st,item_name);
13621 return SCRIPT_CMD_SUCCESS;
13624 /*==========================================
13625 * Returns number of slots an item has. [Skotlex]
13626 *------------------------------------------*/
13627 BUILDIN_FUNC(getitemslots)
13629 unsigned short item_id;
13630 struct item_data *i_data;
13632 item_id=script_getnum(st,2);
13634 i_data = itemdb_exists(item_id);
13637 script_pushint(st,i_data->slot);
13639 script_pushint(st,-1);
13640 return SCRIPT_CMD_SUCCESS;
13643 // TODO: add matk here if needed/once we get rid of RENEWAL
13645 /*==========================================
13646 * Returns some values of an item [Lupus]
13647 * Price, Weight, etc...
13648 getiteminfo(itemID,n), where n
13652 3 maxchance = Max drop chance of this item e.g. 1 = 0.01% , etc..
13653 if = 0, then monsters don't drop it at all (rare or a quest item)
13654 if = -1, then this item is sold in NPC shops only
13668 *------------------------------------------*/
13669 BUILDIN_FUNC(getiteminfo)
13671 unsigned short item_id,n;
13672 struct item_data *i_data;
13674 item_id = script_getnum(st,2);
13675 n = script_getnum(st,3);
13676 i_data = itemdb_exists(item_id);
13678 if (i_data && n <= 16) {
13679 int *item_arr = (int*)&i_data->value_buy;
13682 script_pushint(st,0);
13685 script_pushint(st,item_arr[n]);
13687 script_pushint(st,-1);
13688 return SCRIPT_CMD_SUCCESS;
13691 /*==========================================
13692 * Set some values of an item [Lupus]
13693 * Price, Weight, etc...
13694 setiteminfo(itemID,n,Value), where n
13698 3 maxchance = Max drop chance of this item e.g. 1 = 0.01% , etc..
13699 if = 0, then monsters don't drop it at all (rare or a quest item)
13700 if = -1, then this item is sold in NPC shops only
13712 * Returns Value or -1 if the wrong field's been set
13713 *------------------------------------------*/
13714 BUILDIN_FUNC(setiteminfo)
13716 unsigned short item_id;
13718 struct item_data *i_data;
13720 item_id = script_getnum(st,2);
13721 n = script_getnum(st,3);
13722 value = script_getnum(st,4);
13723 i_data = itemdb_exists(item_id);
13725 if (i_data && n>=0 && n<=14) {
13726 int *item_arr = (int*)&i_data->value_buy;
13727 item_arr[n] = value;
13728 script_pushint(st,value);
13730 script_pushint(st,-1);
13731 return SCRIPT_CMD_SUCCESS;
13734 /*==========================================
13735 * Returns value from equipped item slot n [Lupus]
13736 getequipcardid(num,slot)
13738 num = eqip position slot
13739 slot = 0,1,2,3 (Card Slot N)
13741 This func returns CARD ID, 255,254,-255 (for card 0, if the item is produced)
13742 it's useful when you want to check item cards or if it's signed
13743 Useful for such quests as "Sign this refined item with players name" etc
13744 Hat[0] +4 -> Player's Hat[0] +4
13745 *------------------------------------------*/
13746 BUILDIN_FUNC(getequipcardid)
13751 if( !script_rid2sd(sd) )
13752 return SCRIPT_CMD_SUCCESS;
13754 num=script_getnum(st,2);
13755 slot=script_getnum(st,3);
13757 if (equip_index_check(num))
13758 i=pc_checkequip(sd,equip_bitmask[num]);
13759 if(i >= 0 && slot>=0 && slot<4)
13760 script_pushint(st,sd->inventory.u.items_inventory[i].card[slot]);
13762 script_pushint(st,0);
13763 return SCRIPT_CMD_SUCCESS;
13766 /*==========================================
13767 * petskillbonus [Valaris] //Rewritten by [Skotlex]
13768 *------------------------------------------*/
13769 BUILDIN_FUNC(petskillbonus)
13771 struct pet_data *pd;
13774 if(!script_rid2sd(sd) || sd->pd == NULL)
13775 return SCRIPT_CMD_FAILURE;
13779 { //Clear previous bonus
13780 if (pd->bonus->timer != INVALID_TIMER)
13781 delete_timer(pd->bonus->timer, pet_skill_bonus_timer);
13783 pd->bonus = (struct pet_bonus *) aMalloc(sizeof(struct pet_bonus));
13785 pd->bonus->type = script_getnum(st,2);
13786 pd->bonus->val = script_getnum(st,3);
13787 pd->bonus->duration = script_getnum(st,4);
13788 pd->bonus->delay = script_getnum(st,5);
13790 if (pd->state.skillbonus == 1)
13791 pd->state.skillbonus = 0; // waiting state
13793 // wait for timer to start
13794 if (battle_config.pet_equip_required && pd->pet.equip == 0)
13795 pd->bonus->timer = INVALID_TIMER;
13797 pd->bonus->timer = add_timer(gettick()+pd->bonus->delay*1000, pet_skill_bonus_timer, sd->bl.id, 0);
13798 return SCRIPT_CMD_SUCCESS;
13801 /*==========================================
13802 * pet looting [Valaris] //Rewritten by [Skotlex]
13803 *------------------------------------------*/
13804 BUILDIN_FUNC(petloot)
13807 struct pet_data *pd;
13810 if(!script_rid2sd(sd) || sd->pd==NULL)
13811 return SCRIPT_CMD_SUCCESS;
13813 max=script_getnum(st,2);
13816 max = 1; //Let'em loot at least 1 item.
13817 else if (max > MAX_PETLOOT_SIZE)
13818 max = MAX_PETLOOT_SIZE;
13821 if (pd->loot != NULL)
13822 { //Release whatever was there already and reallocate memory
13823 pet_lootitem_drop(pd, pd->master);
13824 aFree(pd->loot->item);
13827 pd->loot = (struct pet_loot *)aMalloc(sizeof(struct pet_loot));
13829 pd->loot->item = (struct item *)aCalloc(max,sizeof(struct item));
13832 pd->loot->count = 0;
13833 pd->loot->weight = 0;
13834 return SCRIPT_CMD_SUCCESS;
13836 /*==========================================
13837 * Set arrays with info of all sd inventory :
13838 * @inventorylist_id, @inventorylist_amount, @inventorylist_equip,
13839 * @inventorylist_refine, @inventorylist_identify, @inventorylist_attribute,
13840 * @inventorylist_card(0..3), @inventorylist_expire
13841 * @inventorylist_count = scalar
13842 *------------------------------------------*/
13843 BUILDIN_FUNC(getinventorylist)
13846 char card_var[NAME_LENGTH];
13849 if (!script_charid2sd(2,sd))
13850 return SCRIPT_CMD_FAILURE;
13851 for(i=0;i<MAX_INVENTORY;i++){
13852 if(sd->inventory.u.items_inventory[i].nameid > 0 && sd->inventory.u.items_inventory[i].amount > 0){
13853 pc_setreg(sd,reference_uid(add_str("@inventorylist_id"), j),sd->inventory.u.items_inventory[i].nameid);
13854 pc_setreg(sd,reference_uid(add_str("@inventorylist_amount"), j),sd->inventory.u.items_inventory[i].amount);
13855 pc_setreg(sd,reference_uid(add_str("@inventorylist_equip"), j),sd->inventory.u.items_inventory[i].equip);
13856 pc_setreg(sd,reference_uid(add_str("@inventorylist_refine"), j),sd->inventory.u.items_inventory[i].refine);
13857 pc_setreg(sd,reference_uid(add_str("@inventorylist_identify"), j),sd->inventory.u.items_inventory[i].identify);
13858 pc_setreg(sd,reference_uid(add_str("@inventorylist_attribute"), j),sd->inventory.u.items_inventory[i].attribute);
13859 for (k = 0; k < MAX_SLOTS; k++)
13861 sprintf(card_var, "@inventorylist_card%d",k+1);
13862 pc_setreg(sd,reference_uid(add_str(card_var), j),sd->inventory.u.items_inventory[i].card[k]);
13864 pc_setreg(sd,reference_uid(add_str("@inventorylist_expire"), j),sd->inventory.u.items_inventory[i].expire_time);
13865 pc_setreg(sd,reference_uid(add_str("@inventorylist_bound"), j),sd->inventory.u.items_inventory[i].bound);
13869 pc_setreg(sd,add_str("@inventorylist_count"),j);
13870 return SCRIPT_CMD_SUCCESS;
13874 * getskilllist ({<char_id>});
13876 BUILDIN_FUNC(getskilllist)
13881 if (!script_charid2sd(2,sd))
13882 return SCRIPT_CMD_FAILURE;
13883 for(i=0;i<MAX_SKILL;i++){
13884 if(sd->status.skill[i].id > 0 && sd->status.skill[i].lv > 0){
13885 pc_setreg(sd,reference_uid(add_str("@skilllist_id"), j),sd->status.skill[i].id);
13886 pc_setreg(sd,reference_uid(add_str("@skilllist_lv"), j),sd->status.skill[i].lv);
13887 pc_setreg(sd,reference_uid(add_str("@skilllist_flag"), j),sd->status.skill[i].flag);
13891 pc_setreg(sd,add_str("@skilllist_count"),j);
13892 return SCRIPT_CMD_SUCCESS;
13896 * clearitem ({<char_id>});
13898 BUILDIN_FUNC(clearitem)
13903 if (!script_charid2sd(2,sd))
13904 return SCRIPT_CMD_FAILURE;
13906 for (i=0; i<MAX_INVENTORY; i++) {
13907 if (sd->inventory.u.items_inventory[i].amount) {
13908 pc_delitem(sd, i, sd->inventory.u.items_inventory[i].amount, 0, 0, LOG_TYPE_SCRIPT);
13911 return SCRIPT_CMD_SUCCESS;
13915 * Disguise Player (returns Mob/NPC ID if success, 0 on fail)
13916 * disguise <Monster ID>{,<char_id>};
13918 BUILDIN_FUNC(disguise)
13923 if (!script_charid2sd(3,sd))
13924 return SCRIPT_CMD_FAILURE;
13926 id = script_getnum(st,2);
13928 if (mobdb_checkid(id) || npcdb_checkid(id)) {
13929 pc_disguise(sd, id);
13930 script_pushint(st,id);
13932 script_pushint(st,0);
13933 return SCRIPT_CMD_SUCCESS;
13937 * Undisguise Player (returns 1 if success, 0 on fail)
13938 * undisguise {<char_id>};
13940 BUILDIN_FUNC(undisguise)
13944 if (!script_charid2sd(2,sd))
13945 return SCRIPT_CMD_FAILURE;
13947 if (sd->disguise) {
13948 pc_disguise(sd, 0);
13949 script_pushint(st,0);
13951 script_pushint(st,1);
13953 return SCRIPT_CMD_SUCCESS;
13957 * Transform an NPC to another _class
13959 * classchange(<view id>{,"<NPC name>","<flag>"});
13960 * @param flag: Specify target
13961 * BC_AREA - Sprite is sent to players in the vicinity of the source (default).
13962 * BC_SELF - Sprite is sent only to player attached.
13964 BUILDIN_FUNC(classchange)
13966 int _class, type = 1;
13967 struct npc_data* nd = NULL;
13968 TBL_PC *sd = map_id2sd(st->rid);
13969 send_target target = AREA;
13971 _class = script_getnum(st,2);
13973 if (script_hasdata(st, 3) && strlen(script_getstr(st,3)) > 0)
13974 nd = npc_name2id(script_getstr(st, 3));
13976 nd = (struct npc_data *)map_id2bl(st->oid);
13979 return SCRIPT_CMD_FAILURE;
13981 if (script_hasdata(st, 4)) {
13982 switch(script_getnum(st, 4)) {
13983 case BC_SELF: target = SELF; break;
13985 default: target = AREA; break;
13988 if (target != SELF)
13989 clif_class_change(&nd->bl,_class,type);
13990 else if (sd == NULL)
13991 return SCRIPT_CMD_FAILURE;
13993 clif_class_change_target(&nd->bl,_class,type,target,sd);
13995 return SCRIPT_CMD_SUCCESS;
13998 /*==========================================
13999 * Display an effect
14000 *------------------------------------------*/
14001 BUILDIN_FUNC(misceffect)
14005 type=script_getnum(st,2);
14006 if(st->oid && st->oid != fake_nd->bl.id) {
14007 struct block_list *bl = map_id2bl(st->oid);
14009 clif_specialeffect(bl,type,AREA);
14012 if(script_rid2sd(sd))
14013 clif_specialeffect(&sd->bl,type,AREA);
14015 return SCRIPT_CMD_SUCCESS;
14017 /*==========================================
14018 * Play a BGM on a single client [Rikter/Yommy]
14019 *------------------------------------------*/
14020 BUILDIN_FUNC(playBGM)
14022 struct map_session_data* sd;
14024 if( script_rid2sd(sd) ) {
14025 clif_playBGM(sd, script_getstr(st,2));
14027 return SCRIPT_CMD_SUCCESS;
14030 static int playBGM_sub(struct block_list* bl,va_list ap)
14032 const char* name = va_arg(ap,const char*);
14033 clif_playBGM(BL_CAST(BL_PC, bl), name);
14037 static int playBGM_foreachpc_sub(struct map_session_data* sd, va_list args)
14039 const char* name = va_arg(args, const char*);
14040 clif_playBGM(sd, name);
14044 /*==========================================
14045 * Play a BGM on multiple client [Rikter/Yommy]
14046 *------------------------------------------*/
14047 BUILDIN_FUNC(playBGMall)
14050 name = script_getstr(st,2);
14052 if( script_hasdata(st,7) ) {// specified part of map
14053 const char* mapname = script_getstr(st,3);
14054 int x0 = script_getnum(st,4);
14055 int y0 = script_getnum(st,5);
14056 int x1 = script_getnum(st,6);
14057 int y1 = script_getnum(st,7);
14059 map_foreachinallarea(playBGM_sub, map_mapname2mapid(mapname), x0, y0, x1, y1, BL_PC, name);
14061 else if( script_hasdata(st,3) ) {// entire map
14062 const char* mapname = script_getstr(st,3);
14064 map_foreachinmap(playBGM_sub, map_mapname2mapid(mapname), BL_PC, name);
14066 else {// entire server
14067 map_foreachpc(&playBGM_foreachpc_sub, name);
14069 return SCRIPT_CMD_SUCCESS;
14072 /*==========================================
14073 * Play a .wav sound for sd
14074 *------------------------------------------*/
14075 BUILDIN_FUNC(soundeffect)
14079 if(script_rid2sd(sd)){
14080 const char* name = script_getstr(st,2);
14081 int type = script_getnum(st,3);
14083 clif_soundeffect(sd,&sd->bl,name,type);
14085 return SCRIPT_CMD_SUCCESS;
14088 int soundeffect_sub(struct block_list* bl,va_list ap)
14090 char* name = va_arg(ap,char*);
14091 int type = va_arg(ap,int);
14093 clif_soundeffect((TBL_PC *)bl, bl, name, type);
14098 /*==========================================
14099 * Play a sound effect (.wav) on multiple clients
14100 * soundeffectall "<filepath>",<type>{,"<map name>"}{,<x0>,<y0>,<x1>,<y1>};
14101 *------------------------------------------*/
14102 BUILDIN_FUNC(soundeffectall)
14104 struct block_list* bl;
14105 struct map_session_data* sd;
14109 if( st->rid && script_rid2sd(sd) )
14112 bl = map_id2bl(st->oid);
14115 return SCRIPT_CMD_SUCCESS;
14117 name = script_getstr(st,2);
14118 type = script_getnum(st,3);
14120 //FIXME: enumerating map squares (map_foreach) is slower than enumerating the list of online players (map_foreachpc?) [ultramage]
14122 if(!script_hasdata(st,4))
14124 clif_soundeffectall(bl, name, type, AREA);
14127 if(!script_hasdata(st,5))
14129 const char* mapname = script_getstr(st,4);
14130 map_foreachinmap(soundeffect_sub, map_mapname2mapid(mapname), BL_PC, name, type);
14133 if(script_hasdata(st,8))
14134 { // specified part of map
14135 const char* mapname = script_getstr(st,4);
14136 int x0 = script_getnum(st,5);
14137 int y0 = script_getnum(st,6);
14138 int x1 = script_getnum(st,7);
14139 int y1 = script_getnum(st,8);
14140 map_foreachinallarea(soundeffect_sub, map_mapname2mapid(mapname), x0, y0, x1, y1, BL_PC, name, type);
14144 ShowError("buildin_soundeffectall: insufficient arguments for specific area broadcast.\n");
14146 return SCRIPT_CMD_SUCCESS;
14148 /*==========================================
14149 * pet status recovery [Valaris] / Rewritten by [Skotlex]
14150 *------------------------------------------*/
14151 BUILDIN_FUNC(petrecovery)
14153 struct pet_data *pd;
14157 if(!script_rid2sd(sd) || sd->pd == NULL)
14158 return SCRIPT_CMD_FAILURE;
14160 sc = script_getnum(st,2);
14161 if (sc <= SC_NONE || sc >= SC_MAX) {
14162 ShowError("buildin_petrecovery: Invalid SC type: %d\n", sc);
14163 return SCRIPT_CMD_FAILURE;
14169 { //Halt previous bonus
14170 if (pd->recovery->timer != INVALID_TIMER)
14171 delete_timer(pd->recovery->timer, pet_recovery_timer);
14173 pd->recovery = (struct pet_recovery *)aMalloc(sizeof(struct pet_recovery));
14175 pd->recovery->type = (sc_type)sc;
14176 pd->recovery->delay = script_getnum(st,3);
14177 pd->recovery->timer = INVALID_TIMER;
14178 return SCRIPT_CMD_SUCCESS;
14181 /*==========================================
14182 * pet attack skills [Valaris] //Rewritten by [Skotlex]
14183 *------------------------------------------*/
14184 /// petskillattack <skill id>,<level>,<rate>,<bonusrate>
14185 /// petskillattack "<skill name>",<level>,<rate>,<bonusrate>
14186 BUILDIN_FUNC(petskillattack)
14188 struct pet_data *pd;
14189 struct script_data *data;
14193 if(!script_rid2sd(sd) || sd->pd == NULL)
14194 return SCRIPT_CMD_FAILURE;
14196 data = script_getdata(st, 2);
14198 id = (data_isstring(data) ? skill_name2id(script_getstr(st,2)) : skill_get_index(script_getnum(st,2)));
14200 ShowError("buildin_petskillattack: Invalid skill defined!\n");
14201 return SCRIPT_CMD_FAILURE;
14205 if (pd->a_skill == NULL)
14206 pd->a_skill = (struct pet_skill_attack *)aMalloc(sizeof(struct pet_skill_attack));
14208 pd->a_skill->id = id;
14209 pd->a_skill->damage = 0;
14210 pd->a_skill->lv = (unsigned short)min(script_getnum(st,3), skill_get_max(pd->a_skill->id));
14211 pd->a_skill->div_ = 0;
14212 pd->a_skill->rate = script_getnum(st,4);
14213 pd->a_skill->bonusrate = script_getnum(st,5);
14214 return SCRIPT_CMD_SUCCESS;
14217 /*==========================================
14218 * pet attack skills [Valaris]
14219 *------------------------------------------*/
14220 /// petskillattack2 <skill id>,<damage>,<div>,<rate>,<bonusrate>
14221 /// petskillattack2 "<skill name>",<damage>,<div>,<rate>,<bonusrate>
14222 BUILDIN_FUNC(petskillattack2)
14224 struct pet_data *pd;
14225 struct script_data *data;
14229 if(!script_rid2sd(sd) || sd->pd == NULL)
14230 return SCRIPT_CMD_FAILURE;
14232 data = script_getdata(st, 2);
14234 id = (data_isstring(data) ? skill_name2id(script_getstr(st,2)) : skill_get_index(script_getnum(st,2)));
14236 ShowError("buildin_petskillattack2: Invalid skill defined!\n");
14237 return SCRIPT_CMD_FAILURE;
14241 if (pd->a_skill == NULL)
14242 pd->a_skill = (struct pet_skill_attack *)aMalloc(sizeof(struct pet_skill_attack));
14244 pd->a_skill->id = id;
14245 pd->a_skill->damage = script_getnum(st,3); // Fixed damage
14246 pd->a_skill->lv = (unsigned short)skill_get_max(pd->a_skill->id); // Adjust to max skill level
14247 pd->a_skill->div_ = script_getnum(st,4);
14248 pd->a_skill->rate = script_getnum(st,5);
14249 pd->a_skill->bonusrate = script_getnum(st,6);
14250 return SCRIPT_CMD_SUCCESS;
14253 /*==========================================
14254 * pet support skills [Skotlex]
14255 *------------------------------------------*/
14256 /// petskillsupport <skill id>,<level>,<delay>,<hp>,<sp>
14257 /// petskillsupport "<skill name>",<level>,<delay>,<hp>,<sp>
14258 BUILDIN_FUNC(petskillsupport)
14260 struct pet_data *pd;
14261 struct script_data *data;
14265 if(!script_rid2sd(sd) || sd->pd == NULL)
14266 return SCRIPT_CMD_FAILURE;
14268 data = script_getdata(st, 2);
14270 id = (data_isstring(data) ? skill_name2id(script_getstr(st,2)) : skill_get_index(script_getnum(st,2)));
14272 ShowError("buildin_petskillsupport: Invalid skill defined!\n");
14273 return SCRIPT_CMD_FAILURE;
14278 { //Clear previous skill
14279 if (pd->s_skill->timer != INVALID_TIMER)
14281 if (pd->s_skill->id)
14282 delete_timer(pd->s_skill->timer, pet_skill_support_timer);
14284 delete_timer(pd->s_skill->timer, pet_heal_timer);
14286 } else //init memory
14287 pd->s_skill = (struct pet_skill_support *) aMalloc(sizeof(struct pet_skill_support));
14289 pd->s_skill->id = id;
14290 pd->s_skill->lv = script_getnum(st,3);
14291 pd->s_skill->delay = script_getnum(st,4);
14292 pd->s_skill->hp = script_getnum(st,5);
14293 pd->s_skill->sp = script_getnum(st,6);
14295 //Use delay as initial offset to avoid skill/heal exploits
14296 if (battle_config.pet_equip_required && pd->pet.equip == 0)
14297 pd->s_skill->timer = INVALID_TIMER;
14299 pd->s_skill->timer = add_timer(gettick()+pd->s_skill->delay*1000,pet_skill_support_timer,sd->bl.id,0);
14300 return SCRIPT_CMD_SUCCESS;
14303 /*==========================================
14304 * Scripted skill effects [Celest]
14305 *------------------------------------------*/
14306 /// skilleffect <skill id>,<level>
14307 /// skilleffect "<skill name>",<level>
14308 BUILDIN_FUNC(skilleffect)
14311 uint16 skill_id, skill_lv;
14312 struct script_data *data;
14314 if( !script_rid2sd(sd) )
14315 return SCRIPT_CMD_SUCCESS;
14317 data = script_getdata(st, 2);
14319 get_val(st, data); // Convert into value in case of a variable
14320 skill_id = ( data_isstring(data) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
14321 skill_lv = script_getnum(st,3);
14323 /* Ensure we're standing because the following packet causes the client to virtually set the char to stand,
14324 * which leaves the server thinking it still is sitting. */
14325 if( pc_issit(sd) && pc_setstand(sd, false) ) {
14327 clif_standing(&sd->bl);
14330 clif_skill_nodamage(&sd->bl,&sd->bl,skill_id,skill_lv,1);
14331 return SCRIPT_CMD_SUCCESS;
14334 /*==========================================
14335 * NPC skill effects [Valaris]
14336 *------------------------------------------*/
14337 /// npcskilleffect <skill id>,<level>,<x>,<y>
14338 /// npcskilleffect "<skill name>",<level>,<x>,<y>
14339 BUILDIN_FUNC(npcskilleffect)
14341 struct block_list *bl= map_id2bl(st->oid);
14342 uint16 skill_id, skill_lv;
14344 struct script_data *data = script_getdata(st, 2);
14346 get_val(st, data); // Convert into value in case of a variable
14347 skill_id=( data_isstring(data) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
14348 skill_lv=script_getnum(st,3);
14349 x=script_getnum(st,4);
14350 y=script_getnum(st,5);
14353 clif_skill_poseffect(bl,skill_id,skill_lv,x,y,gettick());
14354 return SCRIPT_CMD_SUCCESS;
14357 /*==========================================
14358 * Special effects [Valaris]
14359 *------------------------------------------*/
14360 BUILDIN_FUNC(specialeffect)
14362 struct block_list *bl=map_id2bl(st->oid);
14363 int type = script_getnum(st,2);
14364 enum send_target target = script_hasdata(st,3) ? (send_target)script_getnum(st,3) : AREA;
14367 return SCRIPT_CMD_SUCCESS;
14369 if( script_hasdata(st,4) )
14371 TBL_NPC *nd = npc_name2id(script_getstr(st,4));
14373 clif_specialeffect(&nd->bl, type, target);
14377 if (target == SELF) {
14379 if (script_rid2sd(sd))
14380 clif_specialeffect_single(bl,type,sd->fd);
14382 clif_specialeffect(bl, type, target);
14385 return SCRIPT_CMD_SUCCESS;
14388 BUILDIN_FUNC(specialeffect2)
14392 if( script_nick2sd(4,sd) ){
14393 int type = script_getnum(st,2);
14394 enum send_target target = script_hasdata(st,3) ? (send_target)script_getnum(st,3) : AREA;
14396 clif_specialeffect(&sd->bl, type, target);
14398 return SCRIPT_CMD_SUCCESS;
14402 * nude({<char_id>});
14403 * @author [Valaris]
14408 int i, calcflag = 0;
14410 if (!script_charid2sd(2,sd))
14411 return SCRIPT_CMD_FAILURE;
14413 for( i = 0 ; i < EQI_MAX; i++ ) {
14414 if( sd->equip_index[ i ] >= 0 ) {
14417 pc_unequipitem( sd , sd->equip_index[ i ] , 2);
14422 status_calc_pc(sd,SCO_NONE);
14423 return SCRIPT_CMD_SUCCESS;
14426 int atcommand_sub(struct script_state* st,int type) {
14427 TBL_PC *sd, dummy_sd;
14431 cmd = script_getstr(st,2);
14434 if( !script_rid2sd(sd) )
14435 return SCRIPT_CMD_SUCCESS;
14438 } else { //Use a dummy character.
14442 memset(&dummy_sd, 0, sizeof(TBL_PC));
14444 struct block_list* bl = map_id2bl(st->oid);
14445 memcpy(&dummy_sd.bl, bl, sizeof(struct block_list));
14446 if (bl->type == BL_NPC)
14447 safestrncpy(dummy_sd.status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH);
14448 sd->mapindex = (bl->m > 0) ? map_id2index(bl->m) : mapindex_name2id(map_default.mapname);
14451 // Init Group ID, Level, & permissions
14452 sd->group_id = sd->group_level = 99;
14453 sd->permissions |= PC_PERM_ALLPERMISSION;
14456 if (!is_atcommand(fd, sd, cmd, type)) {
14457 ShowWarning("buildin_atcommand: failed to execute command '%s'\n", cmd);
14458 script_reportsrc(st);
14459 return SCRIPT_CMD_FAILURE;
14461 return SCRIPT_CMD_SUCCESS;
14464 /*==========================================
14465 * gmcommand [MouseJstr]
14466 *------------------------------------------*/
14467 BUILDIN_FUNC(atcommand) {
14468 return atcommand_sub(st,0);
14471 /** Displays a message for the player only (like system messages like "you got an apple" )
14472 * dispbottom("<message>"{,<color>{,<char_id>}})
14474 * @param color Hex color default (Green)
14476 BUILDIN_FUNC(dispbottom)
14480 const char *message;
14482 if (!script_charid2sd(4,sd))
14483 return SCRIPT_CMD_FAILURE;
14485 message = script_getstr(st,2);
14487 if (script_hasdata(st,3))
14488 color = script_getnum(st,3); // <color>
14491 if (script_hasdata(st,3))
14492 clif_messagecolor(&sd->bl, color, message, true, SELF); // [Napster]
14494 clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], message, false, SELF);
14496 return SCRIPT_CMD_SUCCESS;
14499 /*===================================
14500 * Heal portion of recovery command
14501 *-----------------------------------*/
14502 int recovery_sub(struct map_session_data* sd, int revive)
14504 if(revive&(1|4) && pc_isdead(sd)) {
14505 status_revive(&sd->bl, 100, 100);
14506 clif_displaymessage(sd->fd,msg_txt(sd,16)); // You've been revived!
14507 clif_specialeffect(&sd->bl, 77, AREA);
14508 } else if(revive&(1|2) && !pc_isdead(sd)) {
14509 status_percent_heal(&sd->bl, 100, 100);
14510 clif_displaymessage(sd->fd,msg_txt(sd,680)); // You have been recovered!
14512 return SCRIPT_CMD_SUCCESS;
14515 /*=========================================================================
14516 * Fully Recover a Character's HP/SP - [Capuche] & [Akinari]
14517 * recovery <type>{,<option>,<revive_flag>{,<map name>}};
14518 * <type> determines <option>:
14523 * 4 : all characters
14525 * 1 : Revive and heal all players (default)
14526 * 2 : Heal living players only
14527 * 4 : Revive dead players only
14529 * for types 1-2 : map_name (null = all maps)
14530 *-------------------------------------------------------------------------*/
14531 BUILDIN_FUNC(recovery)
14534 int map_idx = 0, type = 0, revive = 1;
14536 type = script_getnum(st,2);
14538 if(script_hasdata(st,4))
14539 revive = script_getnum(st,4);
14543 if(!script_charid2sd(3,sd))
14544 return SCRIPT_CMD_SUCCESS; //If we don't have sd by now, bail out
14545 recovery_sub(sd, revive);
14549 struct party_data* p;
14550 //When no party given, we use invoker party
14552 if(script_hasdata(st,5)) {//Bad maps shouldn't cause issues
14553 map_idx = map_mapname2mapid(script_getstr(st,5));
14554 if(map_idx < 1) { //But we'll check anyways
14555 ShowDebug("recovery: bad map name given (%s)\n", script_getstr(st,5));
14556 return SCRIPT_CMD_FAILURE;
14559 if(script_hasdata(st,3))
14560 p_id = script_getnum(st,3);
14561 else if(script_rid2sd(sd))
14562 p_id = sd->status.party_id;
14563 p = party_search(p_id);
14565 return SCRIPT_CMD_SUCCESS;
14566 for (i = 0; i < MAX_PARTY; i++) {
14567 struct map_session_data* pl_sd;
14568 if((!(pl_sd = p->data[i].sd) || pl_sd->status.party_id != p_id)
14569 || (map_idx && pl_sd->bl.m != map_idx))
14571 recovery_sub(pl_sd, revive);
14578 //When no guild given, we use invoker guild
14580 if(script_hasdata(st,5)) {//Bad maps shouldn't cause issues
14581 map_idx = map_mapname2mapid(script_getstr(st,5));
14582 if(map_idx < 1) { //But we'll check anyways
14583 ShowDebug("recovery: bad map name given (%s)\n", script_getstr(st,5));
14584 return SCRIPT_CMD_FAILURE;
14587 if(script_hasdata(st,3))
14588 g_id = script_getnum(st,3);
14589 else if(script_rid2sd(sd))
14590 g_id = sd->status.guild_id;
14591 g = guild_search(g_id);
14593 return SCRIPT_CMD_SUCCESS;
14594 for (i = 0; i < MAX_GUILD; i++) {
14595 struct map_session_data* pl_sd;
14596 if((!(pl_sd = g->member[i].sd) || pl_sd->status.guild_id != g_id)
14597 || (map_idx && pl_sd->bl.m != map_idx))
14599 recovery_sub(pl_sd, revive);
14604 if(script_hasdata(st,3))
14605 map_idx = map_mapname2mapid(script_getstr(st,3));
14606 else if(script_rid2sd(sd))
14607 map_idx = sd->bl.m;
14609 return SCRIPT_CMD_FAILURE; //No sd and no map given - return
14612 struct s_mapiterator *iter;
14613 struct script_data *data = script_getdata(st, 3);
14615 get_val(st, data); // Convert into value in case of a variable
14616 if(script_hasdata(st,3) && !data_isstring(data))
14617 revive = script_getnum(st,3); // recovery 4,<revive_flag>;
14618 iter = mapit_getallusers();
14619 for (sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter)) {
14620 if(type == 3 && sd->bl.m != map_idx)
14622 recovery_sub(sd, revive);
14628 ShowWarning("script: buildin_recovery: Invalid type %d\n", type);
14629 script_pushint(st,-1);
14630 return SCRIPT_CMD_FAILURE;
14632 script_pushint(st,1); //Successfully executed without errors
14633 return SCRIPT_CMD_SUCCESS;
14636 /*==========================================
14637 * Get your pet info: getpetinfo <type>{,<char_id>}
14638 * n -> 0:pet_id 1:pet_class 2:pet_name
14639 * 3:friendly 4:hungry, 5: rename flag.6:level,
14641 *------------------------------------------*/
14642 BUILDIN_FUNC(getpetinfo)
14646 int type = script_getnum(st,2);
14648 if (!script_charid2sd(3, sd) || !(pd = sd->pd)) {
14650 script_pushconststr(st,"null");
14652 script_pushint(st,0);
14653 return SCRIPT_CMD_SUCCESS;
14657 case PETINFO_ID: script_pushint(st,pd->pet.pet_id); break;
14658 case PETINFO_CLASS: script_pushint(st,pd->pet.class_); break;
14659 case PETINFO_NAME: script_pushstrcopy(st,pd->pet.name); break;
14660 case PETINFO_INTIMATE: script_pushint(st,pd->pet.intimate); break;
14661 case PETINFO_HUNGRY: script_pushint(st,pd->pet.hungry); break;
14662 case PETINFO_RENAMED: script_pushint(st,pd->pet.rename_flag); break;
14663 case PETINFO_LEVEL: script_pushint(st,(int)pd->pet.level); break;
14664 case PETINFO_BLOCKID: script_pushint(st,pd->bl.id); break;
14666 script_pushint(st,0);
14669 return SCRIPT_CMD_SUCCESS;
14672 /*==========================================
14673 * Get your homunculus info: gethominfo <type>{,<char_id>};
14674 * type -> 0:hom_id 1:class 2:name
14675 * 3:friendly 4:hungry, 5: rename flag.
14676 * 6: level, 7: game id
14677 *------------------------------------------*/
14678 BUILDIN_FUNC(gethominfo)
14682 int type=script_getnum(st,2);
14684 if (!script_charid2sd(3, sd) || !(hd = sd->hd)) {
14686 script_pushconststr(st,"null");
14688 script_pushint(st,0);
14689 return SCRIPT_CMD_SUCCESS;
14693 case 0: script_pushint(st,hd->homunculus.hom_id); break;
14694 case 1: script_pushint(st,hd->homunculus.class_); break;
14695 case 2: script_pushstrcopy(st,hd->homunculus.name); break;
14696 case 3: script_pushint(st,hd->homunculus.intimacy); break;
14697 case 4: script_pushint(st,hd->homunculus.hunger); break;
14698 case 5: script_pushint(st,hd->homunculus.rename_flag); break;
14699 case 6: script_pushint(st,hd->homunculus.level); break;
14700 case 7: script_pushint(st,hd->bl.id); break;
14702 script_pushint(st,0);
14705 return SCRIPT_CMD_SUCCESS;
14708 /// Retrieves information about character's mercenary
14709 /// getmercinfo <type>[,<char id>];
14710 BUILDIN_FUNC(getmercinfo)
14713 struct map_session_data* sd;
14714 struct mercenary_data* md;
14716 if( !script_charid2sd(3,sd) ){
14717 script_pushnil(st);
14718 return SCRIPT_CMD_FAILURE;
14721 type = script_getnum(st,2);
14726 script_pushconststr(st,"");
14728 script_pushint(st,0);
14729 return SCRIPT_CMD_SUCCESS;
14734 case 0: script_pushint(st,md->mercenary.mercenary_id); break;
14735 case 1: script_pushint(st,md->mercenary.class_); break;
14736 case 2: script_pushstrcopy(st,md->db->name); break;
14737 case 3: script_pushint(st,mercenary_get_faith(md)); break;
14738 case 4: script_pushint(st,mercenary_get_calls(md)); break;
14739 case 5: script_pushint(st,md->mercenary.kill_count); break;
14740 case 6: script_pushint(st,mercenary_get_lifetime(md)); break;
14741 case 7: script_pushint(st,md->db->lv); break;
14742 case 8: script_pushint(st,md->bl.id); break;
14744 ShowError("buildin_getmercinfo: Invalid type %d (char_id=%d).\n", type, sd->status.char_id);
14745 script_pushnil(st);
14746 return SCRIPT_CMD_FAILURE;
14749 return SCRIPT_CMD_SUCCESS;
14752 /*==========================================
14753 * Shows wether your inventory(and equips) contain
14754 selected card or not.
14755 checkequipedcard(4001);
14756 *------------------------------------------*/
14757 BUILDIN_FUNC(checkequipedcard)
14761 if(script_rid2sd(sd)){
14763 c=script_getnum(st,2);
14765 for(i=0;i<MAX_INVENTORY;i++){
14766 if(sd->inventory.u.items_inventory[i].nameid > 0 && sd->inventory.u.items_inventory[i].amount && sd->inventory_data[i]){
14767 if (itemdb_isspecial(sd->inventory.u.items_inventory[i].card[0]))
14769 for(n=0;n<sd->inventory_data[i]->slot;n++){
14770 if(sd->inventory.u.items_inventory[i].card[n] == c) {
14771 script_pushint(st,1);
14772 return SCRIPT_CMD_SUCCESS;
14778 script_pushint(st,0);
14779 return SCRIPT_CMD_SUCCESS;
14782 BUILDIN_FUNC(jump_zero)
14785 sel=script_getnum(st,2);
14788 if( !data_islabel(script_getdata(st,3)) ){
14789 ShowError("script: jump_zero: not label !\n");
14791 return SCRIPT_CMD_FAILURE;
14794 pos=script_getnum(st,3);
14798 return SCRIPT_CMD_SUCCESS;
14801 /*==========================================
14802 * movenpc [MouseJstr]
14803 *------------------------------------------*/
14804 BUILDIN_FUNC(movenpc)
14806 TBL_NPC *nd = NULL;
14810 npc = script_getstr(st,2);
14811 x = script_getnum(st,3);
14812 y = script_getnum(st,4);
14814 if ((nd = npc_name2id(npc)) == NULL){
14815 ShowError("script: movenpc: NPC with ID '%s' was not found!\n", npc );
14819 if (script_hasdata(st,5))
14820 nd->ud.dir = script_getnum(st,5) % 8;
14821 npc_movenpc(nd, x, y);
14822 return SCRIPT_CMD_SUCCESS;
14825 /*==========================================
14826 * message [MouseJstr]
14827 *------------------------------------------*/
14828 BUILDIN_FUNC(message)
14830 const char *msg,*player;
14831 TBL_PC *pl_sd = NULL;
14833 player = script_getstr(st,2);
14834 msg = script_getstr(st,3);
14836 if((pl_sd=map_nick2sd((char *) player,false)) == NULL)
14837 return SCRIPT_CMD_SUCCESS;
14838 clif_displaymessage(pl_sd->fd, msg);
14840 return SCRIPT_CMD_SUCCESS;
14844 * npctalk("<message>"{,"<NPC name>","<flag>"});
14845 * @param flag: Specify target
14846 * BC_ALL - Broadcast message is sent server-wide.
14847 * BC_MAP - Message is sent to everyone in the same map as the source of the npc.
14848 * BC_AREA - Message is sent to players in the vicinity of the source (default).
14849 * BC_SELF - Message is sent only to player attached.
14851 BUILDIN_FUNC(npctalk)
14853 struct npc_data* nd = NULL;
14854 const char* str = script_getstr(st,2);
14856 if (script_hasdata(st, 3) && strlen(script_getstr(st,3)) > 0)
14857 nd = npc_name2id(script_getstr(st, 3));
14859 nd = (struct npc_data *)map_id2bl(st->oid);
14862 send_target target = AREA;
14863 char message[CHAT_SIZE_MAX];
14865 if (script_hasdata(st, 4)) {
14866 switch(script_getnum(st, 4)) {
14867 case BC_ALL: target = ALL_CLIENT; break;
14868 case BC_MAP: target = ALL_SAMEMAP; break;
14869 case BC_SELF: target = SELF; break;
14871 default: target = AREA; break;
14874 safesnprintf(message, sizeof(message), "%s", str);
14875 if (target != SELF)
14876 clif_messagecolor(&nd->bl, color_table[COLOR_WHITE], message, false, target);
14878 TBL_PC *sd = map_id2sd(st->rid);
14880 return SCRIPT_CMD_FAILURE;
14881 clif_messagecolor_target(&nd->bl, color_table[COLOR_WHITE], message, false, target, sd);
14884 return SCRIPT_CMD_SUCCESS;
14888 * Sends a message to the waitingroom of the invoking NPC.
14889 * chatmes "<message>"{,"<NPC name>"};
14892 BUILDIN_FUNC(chatmes)
14894 struct npc_data* nd = NULL;
14895 const char* str = script_getstr(st,2);
14897 if (script_hasdata(st, 3))
14898 nd = npc_name2id(script_getstr(st, 3));
14900 nd = (struct npc_data *)map_id2bl(st->oid);
14902 if (nd != NULL && nd->chat_id) {
14904 safesnprintf(message, sizeof(message), "%s", str);
14905 clif_GlobalMessage(map_id2bl(nd->chat_id), message, CHAT_WOS);
14907 return SCRIPT_CMD_SUCCESS;
14910 // change npc walkspeed [Valaris]
14911 BUILDIN_FUNC(npcspeed)
14913 struct npc_data* nd;
14916 speed = script_getnum(st,2);
14917 nd =(struct npc_data *)map_id2bl(st->oid);
14921 nd->ud.state.speed_changed = 1;
14924 return SCRIPT_CMD_SUCCESS;
14926 // make an npc walk to a position [Valaris]
14927 BUILDIN_FUNC(npcwalkto)
14929 struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid);
14932 x=script_getnum(st,2);
14933 y=script_getnum(st,3);
14936 if (!nd->status.hp)
14937 status_calc_npc(nd, SCO_FIRST);
14939 status_calc_npc(nd, SCO_NONE);
14940 unit_walktoxy(&nd->bl,x,y,0);
14942 return SCRIPT_CMD_SUCCESS;
14945 // stop an npc's movement [Valaris]
14946 BUILDIN_FUNC(npcstop)
14948 struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid);
14951 unit_stop_walking(&nd->bl,1|4);
14953 return SCRIPT_CMD_SUCCESS;
14958 * getlook(<type>{,<char_id>})
14960 BUILDIN_FUNC(getlook)
14965 if (!script_charid2sd(3,sd)) {
14966 script_pushint(st,-1);
14967 return SCRIPT_CMD_FAILURE;
14970 type=script_getnum(st,2);
14973 // TODO: implement LOOK_BASE as stated in script doc
14974 case LOOK_HAIR: val=sd->status.hair; break; //1
14975 case LOOK_WEAPON: val=sd->status.weapon; break; //2
14976 case LOOK_HEAD_BOTTOM: val=sd->status.head_bottom; break; //3
14977 case LOOK_HEAD_TOP: val=sd->status.head_top; break; //4
14978 case LOOK_HEAD_MID: val=sd->status.head_mid; break; //5
14979 case LOOK_HAIR_COLOR: val=sd->status.hair_color; break; //6
14980 case LOOK_CLOTHES_COLOR: val=sd->status.clothes_color; break; //7
14981 case LOOK_SHIELD: val=sd->status.shield; break; //8
14982 case LOOK_SHOES: break; //9
14983 case LOOK_ROBE: val=sd->status.robe; break; //12
14984 case LOOK_BODY2: val=sd->status.body; break; //13
14987 script_pushint(st,val);
14988 return SCRIPT_CMD_SUCCESS;
14992 * getsavepoint(<information type>{,<char_id>})
14993 * @param type 0- map name, 1- x, 2- y
14995 BUILDIN_FUNC(getsavepoint)
15000 if (!script_charid2sd(3,sd)) {
15001 script_pushint(st,0);
15002 return SCRIPT_CMD_SUCCESS;
15005 type = script_getnum(st,2);
15008 case 0: script_pushstrcopy(st,mapindex_id2name(sd->status.save_point.map)); break;
15009 case 1: script_pushint(st,sd->status.save_point.x); break;
15010 case 2: script_pushint(st,sd->status.save_point.y); break;
15012 script_pushint(st,0);
15015 return SCRIPT_CMD_SUCCESS;
15019 * Get position for BL objects.
15020 * getmapxy(<map name>,<x>,<y>,<type>{,<char name>});
15021 * @param mapname: String variable for output map name
15022 * @param x: Integer variable for output coord X
15023 * @param y: Integer variable for output coord Y
15024 * @param type: Type of object
15025 * UNITTYPE_PC - Character coord
15026 * UNITTYPE_NPC - NPC coord
15027 * UNITTYPE_PET - Pet coord
15028 * UNITTYPE_HOM - Homun coord
15029 * UNITTYPE_MER - Mercenary coord
15030 * UNITTYPE_ELEM - Elemental coord
15031 * @param charname: Name object. If empty or "this" use the current object
15032 * @return 0 - success; -1 - some error, MapName$,MapX,MapY contains unknown value.
15034 BUILDIN_FUNC(getmapxy)
15036 struct block_list *bl = NULL;
15044 char mapname[MAP_NAME_LENGTH];
15046 if( !data_isreference(script_getdata(st,2)) ) {
15047 ShowWarning("script: buildin_getmapxy: mapname value is not a variable.\n");
15048 script_pushint(st,-1);
15049 return SCRIPT_CMD_FAILURE;
15051 if( !data_isreference(script_getdata(st,3)) ) {
15052 ShowWarning("script: buildin_getmapxy: mapx value is not a variable.\n");
15053 script_pushint(st,-1);
15054 return SCRIPT_CMD_FAILURE;
15056 if( !data_isreference(script_getdata(st,4)) ) {
15057 ShowWarning("script: buildin_getmapxy: mapy value is not a variable.\n");
15058 script_pushint(st,-1);
15059 return SCRIPT_CMD_FAILURE;
15062 if( !is_string_variable(reference_getname(script_getdata(st, 2))) ) {
15063 ShowWarning("script: buildin_getmapxy: %s is not a string variable.\n",reference_getname(script_getdata(st, 2)));
15064 script_pushint(st,-1);
15065 return SCRIPT_CMD_FAILURE;
15068 if( is_string_variable(reference_getname(script_getdata(st, 3))) ) {
15069 ShowWarning("script: buildin_getmapxy: %s is a string variable, should be an INT.\n",reference_getname(script_getdata(st, 3)));
15070 script_pushint(st,-1);
15071 return SCRIPT_CMD_FAILURE;
15074 if( is_string_variable(reference_getname(script_getdata(st, 4))) ) {
15075 ShowWarning("script: buildin_getmapxy: %s is a string variable, should be an INT.\n",reference_getname(script_getdata(st, 4)));
15076 script_pushint(st,-1);
15077 return SCRIPT_CMD_FAILURE;
15080 // Possible needly check function parameters on C_STR,C_INT,C_INT
15081 type=script_getnum(st,5);
15084 case UNITTYPE_PC: //Get Character Position
15085 if( script_nick2sd(6,sd) )
15088 case UNITTYPE_NPC: //Get NPC Position
15089 if( script_hasdata(st,6) )
15091 struct npc_data *nd;
15092 nd=npc_name2id(script_getstr(st,6));
15095 } else //In case the origin is not an npc?
15096 bl=map_id2bl(st->oid);
15098 case UNITTYPE_PET: //Get Pet Position
15099 if( script_nick2sd(6, sd) && sd->pd )
15102 case UNITTYPE_HOM: //Get Homun Position
15103 if( script_nick2sd(6, sd) && sd->hd )
15106 case UNITTYPE_MER: //Get Mercenary Position
15107 if( script_nick2sd(6, sd) && sd->md )
15110 case UNITTYPE_ELEM: //Get Elemental Position
15111 if( script_nick2sd(6, sd) && sd->ed )
15115 ShowWarning("script: buildin_getmapxy: Invalid type %d.\n", type);
15116 script_pushint(st,-1);
15117 return SCRIPT_CMD_FAILURE;
15119 if (!bl) { //No object found.
15120 script_pushint(st,-1);
15121 return SCRIPT_CMD_SUCCESS;
15126 safestrncpy(mapname, map[bl->m].name, MAP_NAME_LENGTH);
15129 num=st->stack->stack_data[st->start+2].u.num;
15130 name=get_str(script_getvarid(num));
15133 if(not_server_variable(prefix)){
15134 if( !script_rid2sd(sd) ){
15135 ShowError( "buildin_getmapxy: variable '%s' for mapname is not a server variable, but no player is attached!", name );
15136 return SCRIPT_CMD_FAILURE;
15140 set_reg(st,sd,num,name,(void*)mapname,script_getref(st,2));
15143 num=st->stack->stack_data[st->start+3].u.num;
15144 name=get_str(script_getvarid(num));
15147 if(not_server_variable(prefix)){
15148 if( !script_rid2sd(sd) ){
15149 ShowError( "buildin_getmapxy: variable '%s' for mapX is not a server variable, but no player is attached!", name );
15150 return SCRIPT_CMD_FAILURE;
15154 set_reg(st,sd,num,name,(void*)__64BPRTSIZE(x),script_getref(st,3));
15157 num=st->stack->stack_data[st->start+4].u.num;
15158 name=get_str(script_getvarid(num));
15161 if(not_server_variable(prefix)){
15162 if( !script_rid2sd(sd) ){
15163 ShowError( "buildin_getmapxy: variable '%s' for mapY is not a server variable, but no player is attached!", name );
15164 return SCRIPT_CMD_FAILURE;
15168 set_reg(st,sd,num,name,(void*)__64BPRTSIZE(y),script_getref(st,4));
15170 //Return Success value
15171 script_pushint(st,0);
15172 return SCRIPT_CMD_SUCCESS;
15175 /// Returns the map name of given map ID.
15177 /// mapid2name <map ID>;
15178 BUILDIN_FUNC(mapid2name)
15180 uint16 m = script_getnum(st, 2);
15182 if (m < 0 || m >= MAX_MAP_PER_SERVER) {
15183 script_pushconststr(st, "");
15184 return SCRIPT_CMD_FAILURE;
15187 script_pushstrcopy(st, map_mapid2mapname(m));
15189 return SCRIPT_CMD_SUCCESS;
15192 /*==========================================
15193 * Allows player to write NPC logs (i.e. Bank NPC, etc) [Lupus]
15194 *------------------------------------------*/
15195 BUILDIN_FUNC(logmes)
15200 if( !script_rid2sd(sd) )
15201 return SCRIPT_CMD_FAILURE;
15203 str = script_getstr(st,2);
15205 return SCRIPT_CMD_SUCCESS;
15208 BUILDIN_FUNC(summon)
15210 int _class, timeout=0;
15211 const char *str,*event="";
15213 struct mob_data *md;
15214 int tick = gettick();
15216 if (!script_rid2sd(sd))
15217 return SCRIPT_CMD_SUCCESS;
15219 str =script_getstr(st,2);
15220 _class=script_getnum(st,3);
15221 if( script_hasdata(st,4) )
15222 timeout=script_getnum(st,4);
15223 if( script_hasdata(st,5) ){
15224 event=script_getstr(st,5);
15225 check_event(st, event);
15228 clif_skill_poseffect(&sd->bl,AM_CALLHOMUN,1,sd->bl.x,sd->bl.y,tick);
15230 md = mob_once_spawn_sub(&sd->bl, sd->bl.m, sd->bl.x, sd->bl.y, str, _class, event, SZ_SMALL, AI_NONE);
15232 md->master_id=sd->bl.id;
15233 md->special_state.ai = AI_ATTACK;
15234 if( md->deletetimer != INVALID_TIMER )
15235 delete_timer(md->deletetimer, mob_timer_delete);
15236 md->deletetimer = add_timer(tick+(timeout>0?timeout:60000),mob_timer_delete,md->bl.id,0);
15237 mob_spawn (md); //Now it is ready for spawning.
15238 clif_specialeffect(&md->bl,344,AREA);
15239 sc_start4(NULL,&md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, 60000);
15241 script_pushint(st, md->bl.id);
15243 return SCRIPT_CMD_SUCCESS;
15246 /*==========================================
15247 * Checks whether it is daytime/nighttime
15248 *------------------------------------------*/
15249 BUILDIN_FUNC(isnight)
15251 script_pushint(st,(night_flag == 1));
15252 return SCRIPT_CMD_SUCCESS;
15255 BUILDIN_FUNC(isday)
15257 script_pushint(st,(night_flag == 0));
15258 return SCRIPT_CMD_SUCCESS;
15261 /*================================================
15262 * Check how many items/cards in the list are
15263 * equipped - used for 2/15's cards patch [celest]
15264 *------------------------------------------------*/
15265 BUILDIN_FUNC(isequippedcnt)
15271 if (!script_rid2sd(sd)) { //If the player is not attached it is a script error anyway... but better prevent the map server from crashing...
15272 script_pushint(st,0);
15273 return SCRIPT_CMD_SUCCESS;
15276 for (i=0; id!=0; i++) {
15278 FETCH (i+2, id) else id = 0;
15282 for (j=0; j<EQI_MAX; j++) {
15283 short index = sd->equip_index[j];
15286 if (pc_is_same_equip_index((enum equip_index)j, sd->equip_index, index))
15289 if(!sd->inventory_data[index])
15292 if (itemdb_type(id) != IT_CARD) { //No card. Count amount in inventory.
15293 if (sd->inventory_data[index]->nameid == id)
15294 ret+= sd->inventory.u.items_inventory[index].amount;
15295 } else { //Count cards.
15297 if (itemdb_isspecial(sd->inventory.u.items_inventory[index].card[0]))
15298 continue; //No cards
15299 for(k=0; k<sd->inventory_data[index]->slot; k++) {
15300 if (sd->inventory.u.items_inventory[index].card[k] == id)
15307 script_pushint(st,ret);
15308 return SCRIPT_CMD_SUCCESS;
15311 /*================================================
15312 * Check whether another card has been
15313 * equipped - used for 2/15's cards patch [celest]
15314 * -- Items checked cannot be reused in another
15315 * card set to prevent exploits
15316 *------------------------------------------------*/
15317 BUILDIN_FUNC(isequipped)
15322 //Original hash to reverse it when full check fails.
15323 unsigned int setitem_hash = 0, setitem_hash2 = 0;
15325 if (!script_rid2sd(sd)) { //If the player is not attached it is a script error anyway... but better prevent the map server from crashing...
15326 script_pushint(st,0);
15327 return SCRIPT_CMD_SUCCESS;
15330 setitem_hash = sd->bonus.setitem_hash;
15331 setitem_hash2 = sd->bonus.setitem_hash2;
15332 for (i=0; id!=0; i++) {
15335 FETCH (i+2, id) else id = 0;
15338 for (j=0; j<EQI_MAX; j++) {
15339 short index = sd->equip_index[j];
15342 if (pc_is_same_equip_index((enum equip_index)i, sd->equip_index, index))
15345 if(!sd->inventory_data[index])
15348 if (itemdb_type(id) != IT_CARD) {
15349 if (sd->inventory_data[index]->nameid != id)
15355 if (sd->inventory_data[index]->slot == 0 ||
15356 itemdb_isspecial(sd->inventory.u.items_inventory[index].card[0]))
15359 for (k = 0; k < sd->inventory_data[index]->slot; k++)
15360 { //New hash system which should support up to 4 slots on any equipment. [Skotlex]
15361 unsigned int hash = 0;
15362 if (sd->inventory.u.items_inventory[index].card[k] != id)
15365 hash = 1<<((j<5?j:j-5)*4 + k);
15366 // check if card is already used by another set
15367 if ( ( j < 5 ? sd->bonus.setitem_hash : sd->bonus.setitem_hash2 ) & hash)
15370 // We have found a match
15372 // Set hash so this card cannot be used by another
15374 sd->bonus.setitem_hash |= hash;
15376 sd->bonus.setitem_hash2 |= hash;
15380 if (flag) break; //Card found
15388 if (!ret) {//When check fails, restore original hash values. [Skotlex]
15389 sd->bonus.setitem_hash = setitem_hash;
15390 sd->bonus.setitem_hash2 = setitem_hash2;
15392 script_pushint(st,ret);
15393 return SCRIPT_CMD_SUCCESS;
15396 /*================================================
15397 * Check how many given inserted cards in the CURRENT
15398 * weapon - used for 2/15's cards patch [Lupus]
15399 *------------------------------------------------*/
15400 BUILDIN_FUNC(cardscnt)
15407 if( !script_rid2sd(sd) ){
15408 script_pushint(st,0);
15409 return SCRIPT_CMD_SUCCESS;
15412 for (i=0; id!=0; i++) {
15413 FETCH (i+2, id) else id = 0;
15417 index = current_equip_item_index; //we get CURRENT WEAPON inventory index from status.c [Lupus]
15418 if(index < 0) continue;
15420 if(!sd->inventory_data[index])
15423 if(itemdb_type(id) != IT_CARD) {
15424 if (sd->inventory_data[index]->nameid == id)
15425 ret+= sd->inventory.u.items_inventory[index].amount;
15427 if (itemdb_isspecial(sd->inventory.u.items_inventory[index].card[0]))
15429 for(k=0; k<sd->inventory_data[index]->slot; k++) {
15430 if (sd->inventory.u.items_inventory[index].card[k] == id)
15435 script_pushint(st,ret);
15436 // script_pushint(st,current_equip_item_index);
15437 return SCRIPT_CMD_SUCCESS;
15440 /*=======================================================
15441 * Returns the refined number of the current item, or an
15442 * item with inventory index specified
15443 *-------------------------------------------------------*/
15444 BUILDIN_FUNC(getrefine)
15447 if (script_rid2sd(sd)){
15448 if( current_equip_item_index == -1 ){
15449 script_pushint(st, 0);
15450 return SCRIPT_CMD_FAILURE;
15453 script_pushint(st,sd->inventory.u.items_inventory[current_equip_item_index].refine);
15455 script_pushint(st,0);
15456 return SCRIPT_CMD_SUCCESS;
15459 /*=======================================================
15460 * Day/Night controls
15461 *-------------------------------------------------------*/
15462 BUILDIN_FUNC(night)
15464 if (night_flag != 1) map_night_timer(night_timer_tid, 0, 0, 1);
15465 return SCRIPT_CMD_SUCCESS;
15469 if (night_flag != 0) map_day_timer(day_timer_tid, 0, 0, 1);
15470 return SCRIPT_CMD_SUCCESS;
15474 * unequip <equipment slot>{,<char_id>};
15475 * @author [Spectre]
15477 BUILDIN_FUNC(unequip) {
15481 if (!script_charid2sd(3,sd))
15482 return SCRIPT_CMD_FAILURE;
15484 pos = script_getnum(st,2);
15485 if (equip_index_check(pos)) {
15486 short i = pc_checkequip(sd,equip_bitmask[pos]);
15488 pc_unequipitem(sd,i,1|2);
15489 script_pushint(st, 1);
15490 return SCRIPT_CMD_SUCCESS;
15493 ShowError("buildin_unequip: No item equipped at pos %d (CID=%d/AID=%d).\n", pos, sd->status.char_id, sd->status.account_id);
15494 script_pushint(st, 0);
15495 return SCRIPT_CMD_FAILURE;
15499 * equip <item id>{,<char_id>};
15501 BUILDIN_FUNC(equip) {
15502 unsigned short nameid = 0;
15504 struct item_data *item_data;
15506 if (!script_charid2sd(3,sd))
15507 return SCRIPT_CMD_FAILURE;
15509 nameid = script_getnum(st,2);
15510 if ((item_data = itemdb_exists(nameid))) {
15513 ARR_FIND( 0, MAX_INVENTORY, i, sd->inventory.u.items_inventory[i].nameid == nameid );
15514 if (i < MAX_INVENTORY) {
15515 pc_equipitem(sd,i,item_data->equip);
15516 script_pushint(st,1);
15517 return SCRIPT_CMD_SUCCESS;
15521 ShowError("buildin_equip: Item %hu cannot be equipped\n",nameid);
15522 script_pushint(st,0);
15523 return SCRIPT_CMD_FAILURE;
15526 BUILDIN_FUNC(autoequip)
15528 unsigned short nameid;
15530 struct item_data *item_data;
15531 nameid=script_getnum(st,2);
15532 flag=script_getnum(st,3);
15534 if( ( item_data = itemdb_exists(nameid) ) == NULL )
15536 ShowError("buildin_autoequip: Invalid item '%hu'.\n", nameid);
15537 return SCRIPT_CMD_FAILURE;
15540 if( !itemdb_isequip2(item_data) )
15542 ShowError("buildin_autoequip: Item '%hu' cannot be equipped.\n", nameid);
15543 return SCRIPT_CMD_FAILURE;
15546 item_data->flag.autoequip = flag>0?1:0;
15547 return SCRIPT_CMD_SUCCESS;
15551 * Set the value of a given battle config
15552 * setbattleflag "<battle flag>",<value>{,<reload>};
15554 BUILDIN_FUNC(setbattleflag)
15556 const char *flag, *value;
15558 flag = script_getstr(st,2);
15559 value = script_getstr(st,3); // HACK: Retrieve number as string (auto-converted) for battle_set_value
15561 if (battle_set_value(flag, value) == 0)
15562 ShowWarning("buildin_setbattleflag: unknown battle_config flag '%s'\n",flag);
15564 ShowInfo("buildin_setbattleflag: battle_config flag '%s' is now set to '%s'.\n",flag,value);
15566 if (script_hasdata(st, 4) && script_getnum(st, 4)) { // Only attempt to reload monster data if told to
15567 const char *expdrop_flags[] = { // Only certain flags require a reload, check for those types
15568 "base_exp_rate", "job_exp_rate", "mvp_exp_rate", "quest_exp_rate", "heal_exp", "resurrection_exp",
15569 "item_rate_common", "item_rate_common_boss", "item_rate_common_mvp", "item_drop_common_min", "item_drop_common_max",
15570 "item_rate_heal", "item_rate_heal_boss", "item_rate_heal_mvp", "item_rate_heal_min", "item_rate_heal_max",
15571 "item_rate_use", "item_rate_use_boss", "item_rate_use_mvp", "item_rate_use_min", "item_rate_use_max",
15572 "item_rate_equip", "item_rate_equip_boss", "item_rate_equip_mvp", "item_rate_equip_min", "item_rate_equip_max",
15573 "item_rate_card", "item_rate_card_boss", "item_rate_card_mvp", "item_rate_card_min", "item_rate_card_max",
15574 "item_rate_mvp", "item_rate_mvp_min", "item_rate_mvp_max", "item_rate_mvp_mode",
15575 "item_rate_treasure", "item_rate_treasure_min", "item_rate_treasure_max",
15576 "item_logarithmic_drops", "drop_rate0item", "drop_rateincrease",
15580 for (i = 0; i < ARRAYLENGTH(expdrop_flags); i++) {
15581 if (!strcmpi(flag, expdrop_flags[i])) {
15589 return SCRIPT_CMD_SUCCESS;
15593 * Get the value of a given battle config
15594 * getbattleflag("<battle flag>")
15596 BUILDIN_FUNC(getbattleflag)
15598 const char *flag = script_getstr(st,2);
15600 script_pushint(st,battle_get_value(flag));
15601 return SCRIPT_CMD_SUCCESS;
15604 //=======================================================
15605 // strlen [Valaris]
15606 //-------------------------------------------------------
15607 BUILDIN_FUNC(getstrlen)
15610 const char *str = script_getstr(st,2);
15611 int len = (str) ? (int)strlen(str) : 0;
15613 script_pushint(st,len);
15614 return SCRIPT_CMD_SUCCESS;
15617 //=======================================================
15618 // isalpha [Valaris]
15619 //-------------------------------------------------------
15620 BUILDIN_FUNC(charisalpha)
15622 const char *str=script_getstr(st,2);
15623 int pos=script_getnum(st,3);
15625 int val = ( str && pos >= 0 && (unsigned int)pos < strlen(str) ) ? ISALPHA( str[pos] ) != 0 : 0;
15627 script_pushint(st,val);
15628 return SCRIPT_CMD_SUCCESS;
15631 //=======================================================
15632 // charisupper <str>, <index>
15633 //-------------------------------------------------------
15634 BUILDIN_FUNC(charisupper)
15636 const char *str = script_getstr(st,2);
15637 int pos = script_getnum(st,3);
15639 int val = ( str && pos >= 0 && (unsigned int)pos < strlen(str) ) ? ISUPPER( str[pos] ) : 0;
15641 script_pushint(st,val);
15642 return SCRIPT_CMD_SUCCESS;
15645 //=======================================================
15646 // charislower <str>, <index>
15647 //-------------------------------------------------------
15648 BUILDIN_FUNC(charislower)
15650 const char *str = script_getstr(st,2);
15651 int pos = script_getnum(st,3);
15653 int val = ( str && pos >= 0 && (unsigned int)pos < strlen(str) ) ? ISLOWER( str[pos] ) : 0;
15655 script_pushint(st,val);
15656 return SCRIPT_CMD_SUCCESS;
15659 //=======================================================
15660 // charat <str>, <index>
15661 //-------------------------------------------------------
15662 BUILDIN_FUNC(charat) {
15663 const char *str = script_getstr(st,2);
15664 int pos = script_getnum(st,3);
15666 if( pos >= 0 && (unsigned int)pos < strlen(str) ) {
15668 output[0] = str[pos];
15670 script_pushstrcopy(st, output);
15672 script_pushconststr(st, "");
15673 return SCRIPT_CMD_SUCCESS;
15676 //=======================================================
15677 // setchar <string>, <char>, <index>
15678 //-------------------------------------------------------
15679 BUILDIN_FUNC(setchar)
15681 const char *str = script_getstr(st,2);
15682 const char *c = script_getstr(st,3);
15683 int index = script_getnum(st,4);
15684 char *output = aStrdup(str);
15686 if(index >= 0 && index < strlen(output))
15687 output[index] = *c;
15689 script_pushstr(st, output);
15690 return SCRIPT_CMD_SUCCESS;
15693 //=======================================================
15694 // insertchar <string>, <char>, <index>
15695 //-------------------------------------------------------
15696 BUILDIN_FUNC(insertchar)
15698 const char *str = script_getstr(st,2);
15699 const char *c = script_getstr(st,3);
15700 int index = script_getnum(st,4);
15702 size_t len = strlen(str);
15706 else if(index > len)
15709 output = (char*)aMalloc(len + 2);
15711 memcpy(output, str, index);
15712 output[index] = c[0];
15713 memcpy(&output[index+1], &str[index], len - index);
15714 output[len+1] = '\0';
15716 script_pushstr(st, output);
15717 return SCRIPT_CMD_SUCCESS;
15720 //=======================================================
15721 // delchar <string>, <index>
15722 //-------------------------------------------------------
15723 BUILDIN_FUNC(delchar)
15725 const char *str = script_getstr(st,2);
15726 int index = script_getnum(st,3);
15728 size_t len = strlen(str);
15730 if(index < 0 || index > len) {
15732 output = aStrdup(str);
15733 script_pushstr(st, output);
15734 return SCRIPT_CMD_SUCCESS;
15737 output = (char*)aMalloc(len);
15739 memcpy(output, str, index);
15740 memcpy(&output[index], &str[index+1], len - index);
15742 script_pushstr(st, output);
15743 return SCRIPT_CMD_SUCCESS;
15746 //=======================================================
15747 // strtoupper <str>
15748 //-------------------------------------------------------
15749 BUILDIN_FUNC(strtoupper)
15751 const char *str = script_getstr(st,2);
15752 char *output = aStrdup(str);
15753 char *cursor = output;
15755 while (*cursor != '\0') {
15756 *cursor = TOUPPER(*cursor);
15760 script_pushstr(st, output);
15761 return SCRIPT_CMD_SUCCESS;
15764 //=======================================================
15765 // strtolower <str>
15766 //-------------------------------------------------------
15767 BUILDIN_FUNC(strtolower)
15769 const char *str = script_getstr(st,2);
15770 char *output = aStrdup(str);
15771 char *cursor = output;
15773 while (*cursor != '\0') {
15774 *cursor = TOLOWER(*cursor);
15778 script_pushstr(st, output);
15779 return SCRIPT_CMD_SUCCESS;
15782 //=======================================================
15783 // substr <str>, <start>, <end>
15784 //-------------------------------------------------------
15785 BUILDIN_FUNC(substr)
15787 const char *str = script_getstr(st,2);
15789 int start = script_getnum(st,3);
15790 int end = script_getnum(st,4);
15793 if(start >= 0 && end < strlen(str) && start <= end) {
15794 len = end - start + 1;
15795 output = (char*)aMalloc(len + 1);
15796 memcpy(output, &str[start], len);
15798 output = (char*)aMalloc(1);
15800 output[len] = '\0';
15802 script_pushstr(st, output);
15803 return SCRIPT_CMD_SUCCESS;
15806 //=======================================================
15807 // explode <dest_string_array>, <str>, <delimiter>
15808 // Note: delimiter is limited to 1 char
15809 //-------------------------------------------------------
15810 BUILDIN_FUNC(explode)
15812 struct script_data* data = script_getdata(st, 2);
15813 const char *str = script_getstr(st,3);
15814 const char delimiter = script_getstr(st, 4)[0];
15816 size_t len = strlen(str);
15823 temp = (char*)aMalloc(len + 1);
15825 if( !data_isreference(data) ) {
15826 ShowError("script:explode: not a variable\n");
15827 script_reportdata(data);
15829 return SCRIPT_CMD_FAILURE;// not a variable
15832 id = reference_getid(data);
15833 start = reference_getindex(data);
15834 name = reference_getname(data);
15836 if( !is_string_variable(name) ) {
15837 ShowError("script:explode: not string array\n");
15838 script_reportdata(data);
15840 return SCRIPT_CMD_FAILURE;// data type mismatch
15843 if( not_server_variable(*name) ) {
15844 if( !script_rid2sd(sd) )
15845 return SCRIPT_CMD_SUCCESS;// no player attached
15848 while(str[i] != '\0') {
15849 if(str[i] == delimiter && start < SCRIPT_MAX_ARRAYSIZE-1) { //break at delimiter but ignore after reaching last array index
15851 set_reg(st, sd, reference_uid(id, start++), name, (void*)temp, reference_getref(data));
15855 temp[j++] = str[i++];
15861 set_reg(st, sd, reference_uid(id, start), name, (void*)temp, reference_getref(data));
15864 return SCRIPT_CMD_SUCCESS;
15867 //=======================================================
15868 // implode <string_array>
15869 // implode <string_array>, <glue>
15870 //-------------------------------------------------------
15871 BUILDIN_FUNC(implode)
15873 struct script_data* data = script_getdata(st, 2);
15875 uint32 glue_len = 0, array_size, id;
15879 if( !data_isreference(data) ) {
15880 ShowError("script:implode: not a variable\n");
15881 script_reportdata(data);
15883 return SCRIPT_CMD_FAILURE;// not a variable
15886 id = reference_getid(data);
15887 name = reference_getname(data);
15889 if( !is_string_variable(name) ) {
15890 ShowError("script:implode: not string array\n");
15891 script_reportdata(data);
15893 return SCRIPT_CMD_FAILURE;// data type mismatch
15896 if( not_server_variable(*name) && !script_rid2sd(sd) ) {
15897 return SCRIPT_CMD_SUCCESS;// no player attached
15901 array_size = script_array_highest_key(st, sd, name, reference_getref(data)) - 1;
15903 if(array_size == -1) { //empty array check (AmsTaff)
15904 ShowWarning("script:implode: array length = 0\n");
15905 output = (char*)aMalloc(sizeof(char)*5);
15906 sprintf(output,"%s","NULL");
15908 const char *glue = NULL, *temp;
15912 for(i = 0; i <= array_size; ++i) {
15913 temp = (char*) get_val2(st, reference_uid(id, i), reference_getref(data));
15914 len += strlen(temp);
15915 script_removetop(st, -1, 0);
15919 if( script_hasdata(st,3) ) {
15920 glue = script_getstr(st,3);
15921 glue_len = strlen(glue);
15922 len += glue_len * (array_size);
15924 output = (char*)aMalloc(len + 1);
15927 for(i = 0; i < array_size; ++i) {
15928 temp = (char*) get_val2(st, reference_uid(id, i), reference_getref(data));
15929 len = strlen(temp);
15930 memcpy(&output[k], temp, len);
15933 if(glue_len != 0) {
15934 memcpy(&output[k], glue, glue_len);
15938 script_removetop(st, -1, 0);
15941 temp = (char*) get_val2(st, reference_uid(id, array_size), reference_getref(data));
15942 len = strlen(temp);
15943 memcpy(&output[k], temp, len);
15945 script_removetop(st, -1, 0);
15949 script_pushstr(st, output);
15950 return SCRIPT_CMD_SUCCESS;
15953 //=======================================================
15954 // sprintf(<format>, ...);
15955 // Implements C sprintf, except format %n. The resulting string is
15956 // returned, instead of being saved in variable by reference.
15957 //-------------------------------------------------------
15958 BUILDIN_FUNC(sprintf)
15960 unsigned int len, argc = 0, arg = 0, buf2_len = 0;
15961 const char* format;
15966 struct script_data* data;
15967 StringBuf final_buf;
15970 format = script_getstr(st, 2);
15971 argc = script_lastdata(st)-2;
15972 len = strlen(format);
15974 // Skip parsing, where no parsing is required.
15976 script_pushconststr(st,"");
15977 return SCRIPT_CMD_SUCCESS;
15980 // Pessimistic alloc
15981 CREATE(buf, char, len+1);
15983 // Need not be parsed, just solve stuff like %%.
15985 memcpy(buf,format,len+1);
15986 script_pushstrcopy(st, buf);
15988 return SCRIPT_CMD_SUCCESS;
15991 safestrncpy(buf, format, len+1);
15993 // Issue sprintf for each parameter
15994 StringBuf_Init(&final_buf);
15996 while((p = strchr(q, '%')) != NULL) {
16000 if(buf2_len < len) {
16001 RECREATE(buf2, char, len);
16005 safestrncpy(buf2, q, len);
16006 StringBuf_AppendStr(&final_buf, buf2);
16012 if(*p == '%') { // %%
16013 StringBuf_AppendStr(&final_buf, "%");
16018 if(*p == 'n') { // %n
16019 ShowWarning("buildin_sprintf: Format %%n not supported! Skipping...\n");
16020 script_reportsrc(st);
16026 ShowError("buildin_sprintf: Not enough arguments passed!\n");
16027 if(buf) aFree(buf);
16028 if(buf2) aFree(buf2);
16029 StringBuf_Destroy(&final_buf);
16030 script_pushconststr(st,"");
16031 return SCRIPT_CMD_FAILURE;
16034 if((p = strchr(q+1, '%')) == NULL)
16035 p = strchr(q, 0); // EOS
16039 if(buf2_len < len) {
16040 RECREATE(buf2, char, len);
16044 safestrncpy(buf2, q, len);
16047 // Note: This assumes the passed value being the correct
16048 // type to the current format specifier. If not, the server
16049 // probably crashes or returns anything else, than expected,
16050 // but it would behave in normal code the same way so it's
16051 // the scripter's responsibility.
16052 data = script_getdata(st, arg+3);
16054 if(data_isstring(data)) // String
16055 StringBuf_Printf(&final_buf, buf2, script_getstr(st, arg+3));
16056 else if(data_isint(data)) // Number
16057 StringBuf_Printf(&final_buf, buf2, script_getnum(st, arg+3));
16058 else if(data_isreference(data)) { // Variable
16059 char* name = reference_getname(data);
16061 if(name[strlen(name)-1]=='$') // var Str
16062 StringBuf_Printf(&final_buf, buf2, script_getstr(st, arg+3));
16064 StringBuf_Printf(&final_buf, buf2, script_getnum(st, arg+3));
16065 } else { // Unsupported type
16066 ShowError("buildin_sprintf: Unknown argument type!\n");
16067 if(buf) aFree(buf);
16068 if(buf2) aFree(buf2);
16069 StringBuf_Destroy(&final_buf);
16070 script_pushconststr(st,"");
16071 return SCRIPT_CMD_FAILURE;
16077 // Append anything left
16079 StringBuf_AppendStr(&final_buf, q);
16081 // Passed more, than needed
16083 ShowWarning("buildin_sprintf: Unused arguments passed.\n");
16084 script_reportsrc(st);
16087 script_pushstrcopy(st, StringBuf_Value(&final_buf));
16089 if(buf) aFree(buf);
16090 if(buf2) aFree(buf2);
16091 StringBuf_Destroy(&final_buf);
16093 return SCRIPT_CMD_SUCCESS;
16096 //=======================================================
16097 // sscanf(<str>, <format>, ...);
16098 // Implements C sscanf.
16099 //-------------------------------------------------------
16100 BUILDIN_FUNC(sscanf){
16101 unsigned int argc, arg = 0, len;
16102 struct script_data* data;
16103 struct map_session_data* sd = NULL;
16105 const char* format;
16110 char* ref_str = NULL;
16114 str = script_getstr(st, 2);
16115 format = script_getstr(st, 3);
16116 argc = script_lastdata(st)-3;
16118 len = strlen(format);
16121 if (len != 0 && strlen(str) == 0) {
16122 // If the source string is empty but the format string is not, we return -1
16123 // according to the C specs. (if the format string is also empty, we shall
16124 // continue and return 0: 0 conversions took place out of the 0 attempted.)
16125 script_pushint(st, -1);
16126 return SCRIPT_CMD_SUCCESS;
16129 CREATE(buf, char, len*2+1);
16131 // Issue sscanf for each parameter
16134 while((p = strchr(q, '%'))){
16136 strncat(buf, q, (size_t)(p-q));
16140 if(*p=='*' || *p=='%'){ // Skip
16141 strncat(buf, q, 2);
16146 ShowError("buildin_sscanf: Not enough arguments passed!\n");
16147 script_pushint(st, -1);
16148 if(buf) aFree(buf);
16149 if(ref_str) aFree(ref_str);
16150 return SCRIPT_CMD_FAILURE;
16152 if((p = strchr(q+1, '%'))==NULL){
16153 p = strchr(q, 0); // EOS
16156 strncat(buf, q, len);
16160 data = script_getdata(st, arg+4);
16161 if(!data_isreference(data) || !reference_tovariable(data)){
16162 ShowError("buildin_sscanf: Target argument is not a variable!\n");
16163 script_pushint(st, -1);
16164 if(buf) aFree(buf);
16165 if(ref_str) aFree(ref_str);
16166 return SCRIPT_CMD_FAILURE;
16168 buf_p = reference_getname(data);
16169 if(not_server_variable(*buf_p) && !script_rid2sd(sd)){
16170 script_pushint(st, -1);
16171 if(buf) aFree(buf);
16172 if(ref_str) aFree(ref_str);
16173 return SCRIPT_CMD_SUCCESS;
16176 // Save value if any
16177 if(buf_p[strlen(buf_p)-1]=='$'){ // String
16179 CREATE(ref_str, char, strlen(str)+1);
16181 if(sscanf(str, buf, ref_str)==0){
16184 set_reg(st, sd, reference_uid( reference_getid(data), reference_getindex(data) ), buf_p, (void *)(ref_str), reference_getref(data));
16186 if(sscanf(str, buf, &ref_int)==0){
16189 set_reg(st, sd, reference_uid( reference_getid(data), reference_getindex(data) ), buf_p, (void *)__64BPRTSIZE(ref_int), reference_getref(data));
16193 // Disable used format (%... -> %*...)
16194 buf_p = strchr(buf, 0);
16195 memmove(buf_p-len+2, buf_p-len+1, len);
16196 *(buf_p-len+1) = '*';
16199 script_pushint(st, arg);
16200 if(buf) aFree(buf);
16201 if(ref_str) aFree(ref_str);
16203 return SCRIPT_CMD_SUCCESS;
16206 //=======================================================
16207 // strpos(<haystack>, <needle>)
16208 // strpos(<haystack>, <needle>, <offset>)
16210 // Implements PHP style strpos. Adapted from code from
16211 // http://www.daniweb.com/code/snippet313.html, Dave Sinkula
16212 //-------------------------------------------------------
16213 BUILDIN_FUNC(strpos) {
16214 const char *haystack = script_getstr(st,2);
16215 const char *needle = script_getstr(st,3);
16219 if( script_hasdata(st,4) )
16220 i = script_getnum(st,4);
16224 if (needle[0] == '\0') {
16225 script_pushint(st, -1);
16226 return SCRIPT_CMD_SUCCESS;
16229 len = strlen(haystack);
16230 for ( ; i < len; ++i ) {
16231 if ( haystack[i] == *needle ) {
16232 // matched starting char -- loop through remaining chars
16234 for ( h = &haystack[i], n = needle; *h && *n; ++h, ++n ) {
16239 if ( !*n ) { // matched all of 'needle' to null termination
16240 script_pushint(st, i);
16241 return SCRIPT_CMD_SUCCESS;
16245 script_pushint(st, -1);
16246 return SCRIPT_CMD_SUCCESS;
16249 //===============================================================
16250 // replacestr <input>, <search>, <replace>{, <usecase>{, <count>}}
16252 // Note: Finds all instances of <search> in <input> and replaces
16253 // with <replace>. If specified will only replace as many
16254 // instances as specified in <count>. By default will be case
16256 //---------------------------------------------------------------
16257 BUILDIN_FUNC(replacestr)
16259 const char *input = script_getstr(st, 2);
16260 const char *find = script_getstr(st, 3);
16261 const char *replace = script_getstr(st, 4);
16262 size_t inputlen = strlen(input);
16263 size_t findlen = strlen(find);
16264 struct StringBuf output;
16265 bool usecase = true;
16272 ShowError("script:replacestr: Invalid search length.\n");
16274 return SCRIPT_CMD_FAILURE;
16277 if(script_hasdata(st, 5)) {
16278 struct script_data *data = script_getdata(st, 5);
16280 get_val(st, data); // Convert into value in case of a variable
16281 if( !data_isstring(data) )
16282 usecase = script_getnum(st, 5) != 0;
16284 ShowError("script:replacestr: Invalid usecase value. Expected int got string\n");
16286 return SCRIPT_CMD_FAILURE;
16290 if(script_hasdata(st, 6)) {
16291 count = script_getnum(st, 6);
16293 ShowError("script:replacestr: Invalid count value. Expected int got string\n");
16295 return SCRIPT_CMD_FAILURE;
16299 StringBuf_Init(&output);
16301 for(; i < inputlen; i++) {
16302 if(count && count == numFinds) { //found enough, stop looking
16306 for(f = 0; f <= findlen; f++) {
16307 if(f == findlen) { //complete match
16309 StringBuf_AppendStr(&output, replace);
16315 if((i + f) > inputlen || input[i + f] != find[f]) {
16316 StringBuf_Printf(&output, "%c", input[i]);
16320 if(((i + f) > inputlen || input[i + f] != find[f]) && TOUPPER(input[i+f]) != TOUPPER(find[f])) {
16321 StringBuf_Printf(&output, "%c", input[i]);
16329 //append excess after enough found
16331 StringBuf_AppendStr(&output, &(input[i]));
16333 script_pushstrcopy(st, StringBuf_Value(&output));
16334 StringBuf_Destroy(&output);
16335 return SCRIPT_CMD_SUCCESS;
16338 //========================================================
16339 // countstr <input>, <search>{, <usecase>}
16341 // Note: Counts the number of times <search> occurs in
16342 // <input>. By default will be case sensitive.
16343 //--------------------------------------------------------
16344 BUILDIN_FUNC(countstr)
16346 const char *input = script_getstr(st, 2);
16347 const char *find = script_getstr(st, 3);
16348 size_t inputlen = strlen(input);
16349 size_t findlen = strlen(find);
16350 bool usecase = true;
16356 ShowError("script:countstr: Invalid search length.\n");
16358 return SCRIPT_CMD_FAILURE;
16361 if(script_hasdata(st, 4)) {
16362 struct script_data *data;
16364 data = script_getdata(st, 4);
16365 get_val(st, data); // Convert into value in case of a variable
16366 if( !data_isstring(data) )
16367 usecase = script_getnum(st, 4) != 0;
16369 ShowError("script:countstr: Invalid usecase value. Expected int got string\n");
16371 return SCRIPT_CMD_FAILURE;
16375 for(; i < inputlen; i++) {
16376 for(f = 0; f <= findlen; f++) {
16377 if(f == findlen) { //complete match
16383 if((i + f) > inputlen || input[i + f] != find[f]) {
16387 if(((i + f) > inputlen || input[i + f] != find[f]) && TOUPPER(input[i+f]) != TOUPPER(find[f])) {
16394 script_pushint(st, numFinds);
16395 return SCRIPT_CMD_SUCCESS;
16399 /// Changes the display name and/or display class of the npc.
16400 /// Returns 0 is successful, 1 if the npc does not exist.
16402 /// setnpcdisplay("<npc name>", "<new display name>", <new class id>, <new size>) -> <int>
16403 /// setnpcdisplay("<npc name>", "<new display name>", <new class id>) -> <int>
16404 /// setnpcdisplay("<npc name>", "<new display name>") -> <int>
16405 /// setnpcdisplay("<npc name>", <new class id>) -> <int>
16406 BUILDIN_FUNC(setnpcdisplay)
16409 const char* newname = NULL;
16410 int class_ = -1, size = -1;
16411 struct script_data* data;
16412 struct npc_data* nd;
16414 name = script_getstr(st,2);
16415 data = script_getdata(st,3);
16417 if( script_hasdata(st,4) )
16418 class_ = script_getnum(st,4);
16419 if( script_hasdata(st,5) )
16420 size = script_getnum(st,5);
16423 if( data_isstring(data) )
16424 newname = conv_str(st,data);
16425 else if( data_isint(data) )
16426 class_ = conv_num(st,data);
16429 ShowError("script:setnpcdisplay: expected string or number\n");
16430 script_reportdata(data);
16431 return SCRIPT_CMD_FAILURE;
16434 nd = npc_name2id(name);
16437 script_pushint(st,1);
16438 return SCRIPT_CMD_SUCCESS;
16443 npc_setdisplayname(nd, newname);
16445 if( size != -1 && size != (int)nd->size )
16450 if( class_ != -1 && nd->class_ != class_ )
16451 npc_setclass(nd, class_);
16452 else if( size != -1 )
16453 { // Required to update the visual size
16454 clif_clearunit_area(&nd->bl, CLR_OUTSIGHT);
16455 clif_spawn(&nd->bl);
16458 script_pushint(st,0);
16459 return SCRIPT_CMD_SUCCESS;
16465 value = script_getstr(st,2);
16466 script_pushint(st,atoi(value));
16467 return SCRIPT_CMD_SUCCESS;
16470 BUILDIN_FUNC(axtoi)
16472 const char *hex = script_getstr(st,2);
16473 long value = strtol(hex, NULL, 16);
16474 #if LONG_MAX > INT_MAX || LONG_MIN < INT_MIN
16475 value = cap_value(value, INT_MIN, INT_MAX);
16477 script_pushint(st, (int)value);
16478 return SCRIPT_CMD_SUCCESS;
16481 BUILDIN_FUNC(strtol)
16483 const char *string = script_getstr(st, 2);
16484 int base = script_getnum(st, 3);
16485 long value = strtol(string, NULL, base);
16486 #if LONG_MAX > INT_MAX || LONG_MIN < INT_MIN
16487 value = cap_value(value, INT_MIN, INT_MAX);
16489 script_pushint(st, (int)value);
16490 return SCRIPT_CMD_SUCCESS;
16493 // case-insensitive substring search [lordalfa]
16494 BUILDIN_FUNC(compare)
16496 const char *message;
16497 const char *cmpstring;
16498 message = script_getstr(st,2);
16499 cmpstring = script_getstr(st,3);
16500 script_pushint(st,(stristr(message,cmpstring) != NULL));
16501 return SCRIPT_CMD_SUCCESS;
16504 BUILDIN_FUNC(strcmp)
16508 str1 = script_getstr(st,2);
16509 str2 = script_getstr(st,3);
16510 script_pushint(st,strcmp(str1, str2));
16511 return SCRIPT_CMD_SUCCESS;
16514 // [zBuffer] List of mathematics commands --->
16518 i = script_getnum(st,2);
16520 script_pushint(st,(int)a);
16521 return SCRIPT_CMD_SUCCESS;
16527 a = script_getnum(st,2);
16528 b = script_getnum(st,3);
16530 script_pushint(st,(int)i);
16531 return SCRIPT_CMD_SUCCESS;
16534 BUILDIN_FUNC(distance)
16536 int x0, y0, x1, y1;
16538 x0 = script_getnum(st,2);
16539 y0 = script_getnum(st,3);
16540 x1 = script_getnum(st,4);
16541 y1 = script_getnum(st,5);
16543 script_pushint(st,distance_xy(x0,y0,x1,y1));
16544 return SCRIPT_CMD_SUCCESS;
16547 // <--- [zBuffer] List of mathematics commands
16551 const char *tmpstr;
16554 tmpstr = script_getstr(st,2);
16555 md5str = (char *)aMalloc((32+1)*sizeof(char));
16556 MD5_String(tmpstr, md5str);
16557 script_pushstr(st, md5str);
16558 return SCRIPT_CMD_SUCCESS;
16561 // [zBuffer] List of dynamic var commands --->
16563 * setd "<variable name>",<value>{,<char_id>};
16569 const char *buffer;
16571 buffer = script_getstr(st, 2);
16573 if(sscanf(buffer, "%99[^[][%11d]", varname, &elem) < 2)
16576 if( not_server_variable(*varname) ) {
16577 if (!script_charid2sd(4,sd))
16578 return SCRIPT_CMD_FAILURE;
16581 if( is_string_variable(varname) ) {
16582 setd_sub(st, sd, varname, elem, (void *)script_getstr(st, 3), NULL);
16584 setd_sub(st, sd, varname, elem, (void *)__64BPRTSIZE(script_getnum(st, 3)), NULL);
16587 return SCRIPT_CMD_SUCCESS;
16590 int buildin_query_sql_sub(struct script_state* st, Sql* handle)
16595 struct script_data* data;
16597 unsigned int max_rows = SCRIPT_MAX_ARRAYSIZE; // maximum number of rows
16601 // check target variables
16602 for( i = 3; script_hasdata(st,i); ++i ) {
16603 data = script_getdata(st, i);
16604 if( data_isreference(data) ) { // it's a variable
16605 name = reference_getname(data);
16606 if( not_server_variable(*name) && sd == NULL ) { // requires a player
16607 if( !script_rid2sd(sd) ) { // no player attached
16608 script_reportdata(data);
16610 return SCRIPT_CMD_FAILURE;
16614 ShowError("script:query_sql: not a variable\n");
16615 script_reportdata(data);
16617 return SCRIPT_CMD_FAILURE;
16622 // Execute the query
16623 query = script_getstr(st,2);
16625 if( SQL_ERROR == Sql_QueryStr(handle, query) ) {
16626 Sql_ShowDebug(handle);
16627 script_pushint(st, -1);
16628 return SCRIPT_CMD_FAILURE;
16631 if( Sql_NumRows(handle) == 0 ) { // No data received
16632 Sql_FreeResult(handle);
16633 script_pushint(st, 0);
16634 return SCRIPT_CMD_SUCCESS;
16637 // Count the number of columns to store
16638 num_cols = Sql_NumColumns(handle);
16639 if( num_vars < num_cols ) {
16640 ShowWarning("script:query_sql: Too many columns, discarding last %u columns.\n", (unsigned int)(num_cols-num_vars));
16641 script_reportsrc(st);
16642 } else if( num_vars > num_cols ) {
16643 ShowWarning("script:query_sql: Too many variables (%u extra).\n", (unsigned int)(num_vars-num_cols));
16644 script_reportsrc(st);
16648 for( i = 0; i < max_rows && SQL_SUCCESS == Sql_NextRow(handle); ++i ) {
16649 for( j = 0; j < num_vars; ++j ) {
16653 Sql_GetData(handle, j, &str, NULL);
16655 data = script_getdata(st, j+3);
16656 name = reference_getname(data);
16657 if( is_string_variable(name) )
16658 setd_sub(st, sd, name, i, (void *)(str?str:""), reference_getref(data));
16660 setd_sub(st, sd, name, i, (void *)__64BPRTSIZE((str?atoi(str):0)), reference_getref(data));
16663 if( i == max_rows && max_rows < Sql_NumRows(handle) ) {
16664 ShowWarning("script:query_sql: Only %d/%u rows have been stored.\n", max_rows, (unsigned int)Sql_NumRows(handle));
16665 script_reportsrc(st);
16669 Sql_FreeResult(handle);
16670 script_pushint(st, i);
16671 return SCRIPT_CMD_SUCCESS;
16674 BUILDIN_FUNC(query_sql) {
16675 #ifdef BETA_THREAD_TEST
16676 if( st->state != RERUNLINE ) {
16677 queryThread_add(st,false);
16679 st->state = RERUNLINE;/* will continue when the query is finished running. */
16683 return SCRIPT_CMD_SUCCESS;
16685 return buildin_query_sql_sub(st, qsmysql_handle);
16689 BUILDIN_FUNC(query_logsql) {
16690 if( !log_config.sql_logs ) {// logmysql_handle == NULL
16691 ShowWarning("buildin_query_logsql: SQL logs are disabled, query '%s' will not be executed.\n", script_getstr(st,2));
16692 script_pushint(st,-1);
16693 return SCRIPT_CMD_FAILURE;
16695 #ifdef BETA_THREAD_TEST
16696 if( st->state != RERUNLINE ) {
16697 queryThread_add(st,true);
16699 st->state = RERUNLINE;/* will continue when the query is finished running. */
16703 return SCRIPT_CMD_SUCCESS;
16705 return buildin_query_sql_sub(st, logmysql_handle);
16709 //Allows escaping of a given string.
16710 BUILDIN_FUNC(escape_sql)
16716 str = script_getstr(st,2);
16718 esc_str = (char*)aMalloc(len*2+1);
16719 Sql_EscapeStringLen(mmysql_handle, esc_str, str, len);
16720 script_pushstr(st, esc_str);
16721 return SCRIPT_CMD_SUCCESS;
16727 const char *buffer;
16730 buffer = script_getstr(st, 2);
16732 if(sscanf(buffer, "%99[^[][%11d]", varname, &elem) < 2)
16735 // Push the 'pointer' so it's more flexible [Lance]
16736 push_val(st->stack, C_NAME, reference_uid(add_str(varname), elem));
16738 return SCRIPT_CMD_SUCCESS;
16741 BUILDIN_FUNC(callshop)
16744 struct npc_data *nd;
16745 const char *shopname;
16747 if (!script_rid2sd(sd)) {
16748 script_pushint(st,0);
16749 return SCRIPT_CMD_SUCCESS;
16751 shopname = script_getstr(st, 2);
16752 if (script_hasdata(st,3))
16753 flag = script_getnum(st,3);
16754 nd = npc_name2id(shopname);
16755 if( !nd || nd->bl.type != BL_NPC || (nd->subtype != NPCTYPE_SHOP && nd->subtype != NPCTYPE_CASHSHOP && nd->subtype != NPCTYPE_ITEMSHOP && nd->subtype != NPCTYPE_POINTSHOP && nd->subtype != NPCTYPE_MARKETSHOP) ) {
16756 ShowError("buildin_callshop: Shop [%s] not found (or NPC is not shop type)\n", shopname);
16757 script_pushint(st,0);
16758 return SCRIPT_CMD_FAILURE;
16761 if (nd->subtype == NPCTYPE_SHOP) {
16762 // flag the user as using a valid script call for opening the shop (for floating NPCs)
16763 sd->state.callshop = 1;
16766 case 1: npc_buysellsel(sd,nd->bl.id,0); break; //Buy window
16767 case 2: npc_buysellsel(sd,nd->bl.id,1); break; //Sell window
16768 default: clif_npcbuysell(sd,nd->bl.id); break; //Show menu
16771 #if PACKETVER >= 20131223
16772 else if (nd->subtype == NPCTYPE_MARKETSHOP) {
16775 for (i = 0; i < nd->u.shop.count; i++) {
16776 if (nd->u.shop.shop_item[i].qty)
16780 if (i == nd->u.shop.count) {
16781 clif_messagecolor(&sd->bl, color_table[COLOR_RED], msg_txt(sd, 534), false, SELF);
16782 return SCRIPT_CMD_FAILURE;
16785 sd->npc_shopid = nd->bl.id;
16786 clif_npc_market_open(sd, nd);
16787 script_pushint(st,1);
16788 return SCRIPT_CMD_SUCCESS;
16792 clif_cashshop_show(sd, nd);
16794 sd->npc_shopid = nd->bl.id;
16795 script_pushint(st,1);
16796 return SCRIPT_CMD_SUCCESS;
16799 BUILDIN_FUNC(npcshopitem)
16801 const char* npcname = script_getstr(st, 2);
16802 struct npc_data* nd = npc_name2id(npcname);
16807 if( !nd || ( nd->subtype != NPCTYPE_SHOP && nd->subtype != NPCTYPE_CASHSHOP && nd->subtype != NPCTYPE_ITEMSHOP && nd->subtype != NPCTYPE_POINTSHOP && nd->subtype != NPCTYPE_MARKETSHOP ) ) { // Not found.
16808 script_pushint(st,0);
16809 return SCRIPT_CMD_SUCCESS;
16812 #if PACKETVER >= 20131223
16813 if (nd->subtype == NPCTYPE_MARKETSHOP) {
16815 npc_market_delfromsql_(nd->exname, 0, true);
16819 // get the count of new entries
16820 amount = (script_lastdata(st)-2)/offs;
16822 // generate new shop item list
16823 RECREATE(nd->u.shop.shop_item, struct npc_item_list, amount);
16824 for (n = 0, i = 3; n < amount; n++, i+=offs) {
16825 nd->u.shop.shop_item[n].nameid = script_getnum(st,i);
16826 nd->u.shop.shop_item[n].value = script_getnum(st,i+1);
16827 #if PACKETVER >= 20131223
16828 if (nd->subtype == NPCTYPE_MARKETSHOP) {
16829 nd->u.shop.shop_item[n].qty = script_getnum(st,i+2);
16830 nd->u.shop.shop_item[n].flag = 1;
16831 npc_market_tosql(nd->exname, &nd->u.shop.shop_item[n]);
16835 nd->u.shop.count = n;
16837 script_pushint(st,1);
16838 return SCRIPT_CMD_SUCCESS;
16841 BUILDIN_FUNC(npcshopadditem)
16843 const char* npcname = script_getstr(st,2);
16844 struct npc_data* nd = npc_name2id(npcname);
16846 uint16 offs = 2, amount;
16848 if (!nd || ( nd->subtype != NPCTYPE_SHOP && nd->subtype != NPCTYPE_CASHSHOP && nd->subtype != NPCTYPE_ITEMSHOP && nd->subtype != NPCTYPE_POINTSHOP && nd->subtype != NPCTYPE_MARKETSHOP)) { // Not found.
16849 script_pushint(st,0);
16850 return SCRIPT_CMD_SUCCESS;
16853 if (nd->subtype == NPCTYPE_MARKETSHOP)
16856 // get the count of new entries
16857 amount = (script_lastdata(st)-2)/offs;
16859 #if PACKETVER >= 20131223
16860 if (nd->subtype == NPCTYPE_MARKETSHOP) {
16861 for (n = 0, i = 3; n < amount; n++, i += offs) {
16862 uint16 nameid = script_getnum(st,i), j;
16864 // Check existing entries
16865 ARR_FIND(0, nd->u.shop.count, j, nd->u.shop.shop_item[j].nameid == nameid);
16866 if (j == nd->u.shop.count) {
16867 RECREATE(nd->u.shop.shop_item, struct npc_item_list, nd->u.shop.count+1);
16868 j = nd->u.shop.count;
16869 nd->u.shop.shop_item[j].flag = 1;
16870 nd->u.shop.count++;
16873 nd->u.shop.shop_item[j].nameid = nameid;
16874 nd->u.shop.shop_item[j].value = script_getnum(st,i+1);
16875 nd->u.shop.shop_item[j].qty = script_getnum(st,i+2);
16877 npc_market_tosql(nd->exname, &nd->u.shop.shop_item[j]);
16879 script_pushint(st,1);
16880 return SCRIPT_CMD_SUCCESS;
16884 // append new items to existing shop item list
16885 RECREATE(nd->u.shop.shop_item, struct npc_item_list, nd->u.shop.count+amount);
16886 for (n = nd->u.shop.count, i = 3; n < nd->u.shop.count+amount; n++, i+=offs)
16888 nd->u.shop.shop_item[n].nameid = script_getnum(st,i);
16889 nd->u.shop.shop_item[n].value = script_getnum(st,i+1);
16891 nd->u.shop.count = n;
16893 script_pushint(st,1);
16894 return SCRIPT_CMD_SUCCESS;
16897 BUILDIN_FUNC(npcshopdelitem)
16899 const char* npcname = script_getstr(st,2);
16900 struct npc_data* nd = npc_name2id(npcname);
16902 unsigned short amount;
16904 if (!nd || ( nd->subtype != NPCTYPE_SHOP && nd->subtype != NPCTYPE_CASHSHOP && nd->subtype != NPCTYPE_ITEMSHOP && nd->subtype != NPCTYPE_POINTSHOP && nd->subtype != NPCTYPE_MARKETSHOP)) { // Not found.
16905 script_pushint(st,0);
16906 return SCRIPT_CMD_SUCCESS;
16909 amount = script_lastdata(st)-2;
16910 size = nd->u.shop.count;
16912 // remove specified items from the shop item list
16913 for( i = 3; i < 3 + amount; i++ ) {
16914 unsigned short nameid = script_getnum(st,i);
16916 ARR_FIND( 0, size, n, nd->u.shop.shop_item[n].nameid == nameid );
16919 memmove(&nd->u.shop.shop_item[n], &nd->u.shop.shop_item[n+1], sizeof(nd->u.shop.shop_item[0])*(size-n));
16920 #if PACKETVER >= 20131223
16921 if (nd->subtype == NPCTYPE_MARKETSHOP)
16922 npc_market_delfromsql_(nd->exname, nameid, false);
16928 RECREATE(nd->u.shop.shop_item, struct npc_item_list, size);
16929 nd->u.shop.count = size;
16931 script_pushint(st,1);
16932 return SCRIPT_CMD_SUCCESS;
16936 * Sets a script to attach to a shop npc.
16937 * npcshopattach "<npc_name>";
16939 BUILDIN_FUNC(npcshopattach)
16941 const char* npcname = script_getstr(st,2);
16942 struct npc_data* nd = npc_name2id(npcname);
16945 if( script_hasdata(st,3) )
16946 flag = script_getnum(st,3);
16948 if (!nd || ( nd->subtype != NPCTYPE_SHOP && nd->subtype != NPCTYPE_CASHSHOP && nd->subtype != NPCTYPE_ITEMSHOP && nd->subtype != NPCTYPE_POINTSHOP && nd->subtype != NPCTYPE_MARKETSHOP)) { // Not found.
16949 script_pushint(st,0);
16950 return SCRIPT_CMD_SUCCESS;
16954 nd->master_nd = ((struct npc_data *)map_id2bl(st->oid));
16956 nd->master_nd = NULL;
16958 script_pushint(st,1);
16959 return SCRIPT_CMD_SUCCESS;
16962 /*==========================================
16963 * Returns some values of an item [Lupus]
16964 * Price, Weight, etc...
16965 setitemscript(itemID,"{new item bonus script}",[n]);
16970 *------------------------------------------*/
16971 BUILDIN_FUNC(setitemscript)
16973 unsigned short item_id;
16975 const char *script;
16976 struct item_data *i_data;
16977 struct script_code **dstscript;
16979 item_id = script_getnum(st,2);
16980 script = script_getstr(st,3);
16981 if( script_hasdata(st,4) )
16982 n=script_getnum(st,4);
16983 i_data = itemdb_exists(item_id);
16985 if (!i_data || script==NULL || ( script[0] && script[0]!='{' )) {
16986 script_pushint(st,0);
16987 return SCRIPT_CMD_SUCCESS;
16991 dstscript = &i_data->unequip_script;
16994 dstscript = &i_data->equip_script;
16997 dstscript = &i_data->script;
17001 script_free_code(*dstscript);
17003 *dstscript = script[0] ? parse_script(script, "script_setitemscript", 0, 0) : NULL;
17004 script_pushint(st,1);
17005 return SCRIPT_CMD_SUCCESS;
17008 /*=======================================================
17009 * Add or Update a mob drop temporarily [Akinari]
17010 * Original Idea By: [Lupus]
17012 * addmonsterdrop <mob_id or name>,<item_id>,<rate>;
17014 * If given an item the mob already drops, the rate
17015 * is updated to the new rate. Rate cannot exceed 10000
17016 * Returns 1 if succeeded (added/updated a mob drop)
17017 *-------------------------------------------------------*/
17018 BUILDIN_FUNC(addmonsterdrop)
17020 struct mob_db *mob;
17021 struct script_data *data;
17022 unsigned short item_id;
17025 data = script_getdata(st, 2);
17026 get_val(st, data); // Convert into value in case of a variable
17027 if(data_isstring(data))
17028 mob = mob_db(mobdb_searchname(script_getstr(st,2)));
17030 mob = mob_db(script_getnum(st,2));
17032 item_id=script_getnum(st,3);
17033 rate=script_getnum(st,4);
17035 if(!itemdb_exists(item_id)){
17036 ShowError("addmonsterdrop: Nonexistant item %hu requested.\n", item_id );
17037 return SCRIPT_CMD_FAILURE;
17040 if(mob) { //We got a valid monster, check for available drop slot
17041 unsigned char i, c = 0;
17042 for(i = 0; i < MAX_MOB_DROP_TOTAL; i++) {
17043 if(mob->dropitem[i].nameid) {
17044 if(mob->dropitem[i].nameid == item_id) { //If it equals item_id we update that drop
17050 if(!c) //Accept first available slot only
17053 if(c) { //Fill in the slot with the item and rate
17054 mob->dropitem[c].nameid = item_id;
17055 mob->dropitem[c].p = (rate > 10000)?10000:rate;
17056 itemdb_reload_itemmob_data(); // Reload the mob search data stored in the item_data
17057 script_pushint(st,1);
17058 } else //No place to put the new drop
17059 script_pushint(st,0);
17061 ShowWarning("addmonsterdrop: bad mob id given %d\n",script_getnum(st,2));
17062 return SCRIPT_CMD_FAILURE;
17064 return SCRIPT_CMD_SUCCESS;
17068 /*=======================================================
17069 * Delete a mob drop temporarily [Akinari]
17070 * Original Idea By: [Lupus]
17072 * delmonsterdrop <mob_id or name>,<item_id>;
17074 * Returns 1 if succeeded (deleted a mob drop)
17075 *-------------------------------------------------------*/
17076 BUILDIN_FUNC(delmonsterdrop)
17078 struct mob_db *mob;
17079 struct script_data *data;
17080 unsigned short item_id;
17082 data = script_getdata(st, 2);
17083 get_val(st, data); // Convert into value in case of a variable
17084 if(data_isstring(data))
17085 mob = mob_db(mobdb_searchname(script_getstr(st,2)));
17087 mob = mob_db(script_getnum(st,2));
17089 item_id=script_getnum(st,3);
17091 if(!itemdb_exists(item_id)){
17092 ShowError("delmonsterdrop: Nonexistant item %hu requested.\n", item_id );
17093 return SCRIPT_CMD_FAILURE;
17096 if(mob) { //We got a valid monster, check for item drop on monster
17098 for(i = 0; i < MAX_MOB_DROP_TOTAL; i++) {
17099 if(mob->dropitem[i].nameid == item_id) {
17100 mob->dropitem[i].nameid = 0;
17101 mob->dropitem[i].p = 0;
17102 itemdb_reload_itemmob_data(); // Reload the mob search data stored in the item_data
17103 script_pushint(st,1);
17104 return SCRIPT_CMD_SUCCESS;
17107 //No drop on that monster
17108 script_pushint(st,0);
17110 ShowWarning("delmonsterdrop: bad mob id given %d\n",script_getnum(st,2));
17111 return SCRIPT_CMD_FAILURE;
17113 return SCRIPT_CMD_SUCCESS;
17117 /*==========================================
17118 * Returns some values of a monster [Lupus]
17119 * Name, Level, race, size, etc...
17120 getmonsterinfo(monsterID,queryIndex);
17121 *------------------------------------------*/
17122 BUILDIN_FUNC(getmonsterinfo)
17124 struct mob_db *mob;
17127 mob_id = script_getnum(st,2);
17128 if (!mobdb_checkid(mob_id)) {
17129 //ShowError("buildin_getmonsterinfo: Wrong Monster ID: %i\n", mob_id);
17130 if ( script_getnum(st,3) == MOB_NAME ) // requested the name
17131 script_pushconststr(st,"null");
17133 script_pushint(st,-1);
17134 return SCRIPT_CMD_SUCCESS;
17136 mob = mob_db(mob_id);
17137 switch ( script_getnum(st,3) ) {
17138 case MOB_NAME: script_pushstrcopy(st,mob->jname); break;
17139 case MOB_LV: script_pushint(st,mob->lv); break;
17140 case MOB_MAXHP: script_pushint(st,mob->status.max_hp); break;
17141 case MOB_BASEEXP: script_pushint(st,mob->base_exp); break;
17142 case MOB_JOBEXP: script_pushint(st,mob->job_exp); break;
17143 case MOB_ATK1: script_pushint(st,mob->status.rhw.atk); break;
17144 case MOB_ATK2: script_pushint(st,mob->status.rhw.atk2); break;
17145 case MOB_DEF: script_pushint(st,mob->status.def); break;
17146 case MOB_MDEF: script_pushint(st,mob->status.mdef); break;
17147 case MOB_STR: script_pushint(st,mob->status.str); break;
17148 case MOB_AGI: script_pushint(st,mob->status.agi); break;
17149 case MOB_VIT: script_pushint(st,mob->status.vit); break;
17150 case MOB_INT: script_pushint(st,mob->status.int_); break;
17151 case MOB_DEX: script_pushint(st,mob->status.dex); break;
17152 case MOB_LUK: script_pushint(st,mob->status.luk); break;
17153 case MOB_RANGE: script_pushint(st,mob->status.rhw.range); break;
17154 case MOB_RANGE2: script_pushint(st,mob->range2); break;
17155 case MOB_RANGE3: script_pushint(st,mob->range3); break;
17156 case MOB_SIZE: script_pushint(st,mob->status.size); break;
17157 case MOB_RACE: script_pushint(st,mob->status.race); break;
17158 case MOB_ELEMENT: script_pushint(st,mob->status.def_ele); break;
17159 case MOB_MODE: script_pushint(st,mob->status.mode); break;
17160 case MOB_MVPEXP: script_pushint(st,mob->mexp); break;
17161 default: script_pushint(st,-1); //wrong Index
17163 return SCRIPT_CMD_SUCCESS;
17167 * Check player's vending/buyingstore/autotrade state
17168 * checkvending({"<Player Name>"})
17171 BUILDIN_FUNC(checkvending) {
17174 if (!script_nick2sd(2,sd) ) {
17175 script_pushint(st,0);
17176 return SCRIPT_CMD_SUCCESS;
17180 if (sd->state.vending)
17182 else if (sd->state.buyingstore)
17185 if (sd->state.autotrade)
17187 script_pushint(st, ret);
17189 return SCRIPT_CMD_SUCCESS;
17193 BUILDIN_FUNC(checkchatting) // check chatting [Marka]
17197 if( script_nick2sd(2,sd) )
17198 script_pushint(st,(sd->chatID != 0));
17200 script_pushint(st,0);
17201 return SCRIPT_CMD_SUCCESS;
17204 BUILDIN_FUNC(checkidle)
17208 if( script_nick2sd(2,sd) )
17209 script_pushint(st, DIFF_TICK(last_tick, sd->idletime));
17211 script_pushint(st, 0);
17212 return SCRIPT_CMD_SUCCESS;
17215 BUILDIN_FUNC(searchitem)
17217 struct script_data* data = script_getdata(st, 2);
17218 const char *itemname = script_getstr(st,3);
17219 struct item_data *items[MAX_SEARCH];
17228 if ((items[0] = itemdb_exists(atoi(itemname))))
17231 count = itemdb_searchname_array(items, ARRAYLENGTH(items), itemname);
17234 script_pushint(st, 0);
17235 return SCRIPT_CMD_SUCCESS;
17238 if( !data_isreference(data) )
17240 ShowError("script:searchitem: not a variable\n");
17241 script_reportdata(data);
17243 return SCRIPT_CMD_FAILURE;// not a variable
17246 id = reference_getid(data);
17247 start = reference_getindex(data);
17248 name = reference_getname(data);
17250 if( not_server_variable(*name) && !script_rid2sd(sd) )
17252 return SCRIPT_CMD_SUCCESS;// no player attached
17255 if( is_string_variable(name) )
17257 ShowError("script:searchitem: not an integer array reference\n");
17258 script_reportdata(data);
17260 return SCRIPT_CMD_FAILURE;// not supported
17263 for( i = 0; i < count; ++start, ++i )
17265 void* v = (void*)__64BPRTSIZE((int)items[i]->nameid);
17266 set_reg(st, sd, reference_uid(id, start), name, v, reference_getref(data));
17269 script_pushint(st, count);
17270 return SCRIPT_CMD_SUCCESS;
17273 // [zBuffer] List of player cont commands --->
17274 BUILDIN_FUNC(rid2name)
17276 struct block_list *bl = NULL;
17277 int rid = script_getnum(st,2);
17278 if((bl = map_id2bl(rid)))
17281 case BL_MOB: script_pushstrcopy(st,((TBL_MOB*)bl)->name); break;
17282 case BL_PC: script_pushstrcopy(st,((TBL_PC*)bl)->status.name); break;
17283 case BL_NPC: script_pushstrcopy(st,((TBL_NPC*)bl)->exname); break;
17284 case BL_PET: script_pushstrcopy(st,((TBL_PET*)bl)->pet.name); break;
17285 case BL_HOM: script_pushstrcopy(st,((TBL_HOM*)bl)->homunculus.name); break;
17286 case BL_MER: script_pushstrcopy(st,((TBL_MER*)bl)->db->name); break;
17288 ShowError("buildin_rid2name: BL type unknown.\n");
17289 script_pushconststr(st,"");
17293 ShowError("buildin_rid2name: invalid RID\n");
17294 script_pushconststr(st,"(null)");
17296 return SCRIPT_CMD_SUCCESS;
17300 * Toggle a unit from moving.
17301 * pcblockmove(<unit_id>,<option>);
17303 BUILDIN_FUNC(pcblockmove)
17305 struct block_list *bl = NULL;
17307 if (script_getnum(st, 2))
17308 bl = map_id2bl(script_getnum(st,2));
17310 bl = map_id2bl(st->rid);
17313 struct unit_data *ud = unit_bl2ud(bl);
17316 ud->state.blockedmove = script_getnum(st,3) > 0;
17319 return SCRIPT_CMD_SUCCESS;
17323 * Toggle a unit from casting skills.
17324 * pcblockskill(<unit_id>,<option>);
17326 BUILDIN_FUNC(pcblockskill)
17328 struct block_list *bl = NULL;
17330 if (script_getnum(st, 2))
17331 bl = map_id2bl(script_getnum(st,2));
17333 bl = map_id2bl(st->rid);
17336 struct unit_data *ud = unit_bl2ud(bl);
17339 ud->state.blockedskill = script_getnum(st, 3) > 0;
17342 return SCRIPT_CMD_SUCCESS;
17345 BUILDIN_FUNC(pcfollow)
17349 if( script_mapid2sd(2,sd) )
17350 pc_follow(sd, script_getnum(st,3));
17352 return SCRIPT_CMD_SUCCESS;
17355 BUILDIN_FUNC(pcstopfollow)
17359 if(script_mapid2sd(2,sd))
17360 pc_stop_following(sd);
17362 return SCRIPT_CMD_SUCCESS;
17364 // <--- [zBuffer] List of player cont commands
17365 // [zBuffer] List of unit control commands --->
17367 /// Checks to see if the unit exists.
17369 /// unitexists <unit id>;
17370 BUILDIN_FUNC(unitexists)
17372 struct block_list* bl;
17374 bl = map_id2bl(script_getnum(st, 2));
17377 script_pushint(st, false);
17379 script_pushint(st, true);
17381 return SCRIPT_CMD_SUCCESS;
17384 /// Gets the type of the given Game ID.
17386 /// getunittype <unit id>;
17387 BUILDIN_FUNC(getunittype)
17389 struct block_list* bl;
17392 if(!script_rid2bl(2,bl))
17394 script_pushint(st, -1);
17395 return SCRIPT_CMD_FAILURE;
17398 switch (bl->type) {
17399 case BL_PC: value = UNITTYPE_PC; break;
17400 case BL_NPC: value = UNITTYPE_NPC; break;
17401 case BL_PET: value = UNITTYPE_PET; break;
17402 case BL_MOB: value = UNITTYPE_MOB; break;
17403 case BL_HOM: value = UNITTYPE_HOM; break;
17404 case BL_MER: value = UNITTYPE_MER; break;
17405 case BL_ELEM: value = UNITTYPE_ELEM; break;
17406 default: value = -1; break;
17409 script_pushint(st, value);
17410 return SCRIPT_CMD_SUCCESS;
17413 /// Gets specific live information of a bl.
17415 /// getunitdata <unit id>,<arrayname>;
17416 BUILDIN_FUNC(getunitdata)
17418 TBL_PC *sd = st->rid ? map_id2sd(st->rid) : NULL;
17419 struct block_list* bl;
17420 TBL_MOB* md = NULL;
17421 TBL_HOM* hd = NULL;
17422 TBL_MER* mc = NULL;
17423 TBL_PET* pd = NULL;
17424 TBL_ELEM* ed = NULL;
17425 TBL_NPC* nd = NULL;
17427 struct script_data *data = script_getdata(st, 3);
17429 if (!data_isreference(data)) {
17430 ShowWarning("buildin_getunitdata: Error in argument! Please give a variable to store values in.\n");
17431 return SCRIPT_CMD_FAILURE;
17434 if(!script_rid2bl(2,bl))
17436 script_pushint(st, -1);
17437 return SCRIPT_CMD_FAILURE;
17440 switch (bl->type) {
17441 case BL_MOB: md = map_id2md(bl->id); break;
17442 case BL_HOM: hd = map_id2hd(bl->id); break;
17443 case BL_PET: pd = map_id2pd(bl->id); break;
17444 case BL_MER: mc = map_id2mc(bl->id); break;
17445 case BL_ELEM: ed = map_id2ed(bl->id); break;
17446 case BL_NPC: nd = map_id2nd(bl->id); break;
17448 ShowWarning("buildin_getunitdata: Invalid object type!\n");
17449 return SCRIPT_CMD_FAILURE;
17452 name = reference_getname(data);
17454 #define getunitdata_sub(idx__,var__) setd_sub(st,sd,name,(idx__),(void *)__64BPRTSIZE((int)(var__)),data->ref)
17459 ShowWarning("buildin_getunitdata: Error in finding object BL_MOB!\n");
17460 return SCRIPT_CMD_FAILURE;
17462 getunitdata_sub(UMOB_SIZE, md->status.size);
17463 getunitdata_sub(UMOB_LEVEL, md->level);
17464 getunitdata_sub(UMOB_HP, md->status.hp);
17465 getunitdata_sub(UMOB_MAXHP, md->status.max_hp);
17466 getunitdata_sub(UMOB_MASTERAID, md->master_id);
17467 getunitdata_sub(UMOB_MAPID, md->bl.m);
17468 getunitdata_sub(UMOB_X, md->bl.x);
17469 getunitdata_sub(UMOB_Y, md->bl.y);
17470 getunitdata_sub(UMOB_SPEED, md->status.speed);
17471 getunitdata_sub(UMOB_MODE, md->status.mode);
17472 getunitdata_sub(UMOB_AI, md->special_state.ai);
17473 getunitdata_sub(UMOB_SCOPTION, md->sc.option);
17474 getunitdata_sub(UMOB_SEX, md->vd->sex);
17475 getunitdata_sub(UMOB_CLASS, md->vd->class_);
17476 getunitdata_sub(UMOB_HAIRSTYLE, md->vd->hair_style);
17477 getunitdata_sub(UMOB_HAIRCOLOR, md->vd->hair_color);
17478 getunitdata_sub(UMOB_HEADBOTTOM, md->vd->head_bottom);
17479 getunitdata_sub(UMOB_HEADMIDDLE, md->vd->head_mid);
17480 getunitdata_sub(UMOB_HEADTOP, md->vd->head_top);
17481 getunitdata_sub(UMOB_CLOTHCOLOR, md->vd->cloth_color);
17482 getunitdata_sub(UMOB_SHIELD, md->vd->shield);
17483 getunitdata_sub(UMOB_WEAPON, md->vd->weapon);
17484 getunitdata_sub(UMOB_LOOKDIR, md->ud.dir);
17485 getunitdata_sub(UMOB_CANMOVETICK, md->ud.canmove_tick);
17486 getunitdata_sub(UMOB_STR, md->status.str);
17487 getunitdata_sub(UMOB_AGI, md->status.agi);
17488 getunitdata_sub(UMOB_VIT, md->status.vit);
17489 getunitdata_sub(UMOB_INT, md->status.int_);
17490 getunitdata_sub(UMOB_DEX, md->status.dex);
17491 getunitdata_sub(UMOB_LUK, md->status.luk);
17492 getunitdata_sub(UMOB_SLAVECPYMSTRMD, md->state.copy_master_mode);
17493 getunitdata_sub(UMOB_DMGIMMUNE, md->ud.immune_attack);
17494 getunitdata_sub(UMOB_ATKRANGE, md->status.rhw.range);
17495 getunitdata_sub(UMOB_ATKMIN, md->status.rhw.atk);
17496 getunitdata_sub(UMOB_ATKMAX, md->status.rhw.atk2);
17497 getunitdata_sub(UMOB_MATKMIN, md->status.matk_min);
17498 getunitdata_sub(UMOB_MATKMAX, md->status.matk_max);
17499 getunitdata_sub(UMOB_DEF, md->status.def);
17500 getunitdata_sub(UMOB_MDEF, md->status.mdef);
17501 getunitdata_sub(UMOB_HIT, md->status.hit);
17502 getunitdata_sub(UMOB_FLEE, md->status.flee);
17503 getunitdata_sub(UMOB_PDODGE, md->status.flee2);
17504 getunitdata_sub(UMOB_CRIT, md->status.cri);
17505 getunitdata_sub(UMOB_RACE, md->status.race);
17506 getunitdata_sub(UMOB_ELETYPE, md->status.def_ele);
17507 getunitdata_sub(UMOB_ELELEVEL, md->status.ele_lv);
17508 getunitdata_sub(UMOB_AMOTION, md->status.amotion);
17509 getunitdata_sub(UMOB_ADELAY, md->status.adelay);
17510 getunitdata_sub(UMOB_DMOTION, md->status.dmotion);
17515 ShowWarning("buildin_getunitdata: Error in finding object BL_HOM!\n");
17516 return SCRIPT_CMD_FAILURE;
17518 getunitdata_sub(UHOM_SIZE, hd->base_status.size);
17519 getunitdata_sub(UHOM_LEVEL, hd->homunculus.level);
17520 getunitdata_sub(UHOM_HP, hd->homunculus.hp);
17521 getunitdata_sub(UHOM_MAXHP, hd->homunculus.max_hp);
17522 getunitdata_sub(UHOM_SP, hd->homunculus.sp);
17523 getunitdata_sub(UHOM_MAXSP, hd->homunculus.max_sp);
17524 getunitdata_sub(UHOM_MASTERCID, hd->homunculus.char_id);
17525 getunitdata_sub(UHOM_MAPID, hd->bl.m);
17526 getunitdata_sub(UHOM_X, hd->bl.x);
17527 getunitdata_sub(UHOM_Y, hd->bl.y);
17528 getunitdata_sub(UHOM_HUNGER, hd->homunculus.hunger);
17529 getunitdata_sub(UHOM_INTIMACY, hd->homunculus.intimacy);
17530 getunitdata_sub(UHOM_SPEED, hd->base_status.speed);
17531 getunitdata_sub(UHOM_LOOKDIR, hd->ud.dir);
17532 getunitdata_sub(UHOM_CANMOVETICK, hd->ud.canmove_tick);
17533 getunitdata_sub(UHOM_STR, hd->base_status.str);
17534 getunitdata_sub(UHOM_AGI, hd->base_status.agi);
17535 getunitdata_sub(UHOM_VIT, hd->base_status.vit);
17536 getunitdata_sub(UHOM_INT, hd->base_status.int_);
17537 getunitdata_sub(UHOM_DEX, hd->base_status.dex);
17538 getunitdata_sub(UHOM_LUK, hd->base_status.luk);
17539 getunitdata_sub(UHOM_DMGIMMUNE, hd->ud.immune_attack);
17540 getunitdata_sub(UHOM_ATKRANGE, hd->battle_status.rhw.range);
17541 getunitdata_sub(UHOM_ATKMIN, hd->base_status.rhw.atk);
17542 getunitdata_sub(UHOM_ATKMAX, hd->base_status.rhw.atk2);
17543 getunitdata_sub(UHOM_MATKMIN, hd->base_status.matk_min);
17544 getunitdata_sub(UHOM_MATKMAX, hd->base_status.matk_max);
17545 getunitdata_sub(UHOM_DEF, hd->battle_status.def);
17546 getunitdata_sub(UHOM_MDEF, hd->battle_status.mdef);
17547 getunitdata_sub(UHOM_HIT, hd->battle_status.hit);
17548 getunitdata_sub(UHOM_FLEE, hd->battle_status.flee);
17549 getunitdata_sub(UHOM_PDODGE, hd->battle_status.flee2);
17550 getunitdata_sub(UHOM_CRIT, hd->battle_status.cri);
17551 getunitdata_sub(UHOM_RACE, hd->battle_status.race);
17552 getunitdata_sub(UHOM_ELETYPE, hd->battle_status.def_ele);
17553 getunitdata_sub(UHOM_ELELEVEL, hd->battle_status.ele_lv);
17554 getunitdata_sub(UHOM_AMOTION, hd->battle_status.amotion);
17555 getunitdata_sub(UHOM_ADELAY, hd->battle_status.adelay);
17556 getunitdata_sub(UHOM_DMOTION, hd->battle_status.dmotion);
17561 ShowWarning("buildin_getunitdata: Error in finding object BL_PET!\n");
17562 return SCRIPT_CMD_FAILURE;
17564 getunitdata_sub(UPET_SIZE, pd->status.size);
17565 getunitdata_sub(UPET_LEVEL, pd->pet.level);
17566 getunitdata_sub(UPET_HP, pd->status.hp);
17567 getunitdata_sub(UPET_MAXHP, pd->status.max_hp);
17568 getunitdata_sub(UPET_MASTERAID, pd->pet.account_id);
17569 getunitdata_sub(UPET_MAPID, pd->bl.m);
17570 getunitdata_sub(UPET_X, pd->bl.x);
17571 getunitdata_sub(UPET_Y, pd->bl.y);
17572 getunitdata_sub(UPET_HUNGER, pd->pet.hungry);
17573 getunitdata_sub(UPET_INTIMACY, pd->pet.intimate);
17574 getunitdata_sub(UPET_SPEED, pd->status.speed);
17575 getunitdata_sub(UPET_LOOKDIR, pd->ud.dir);
17576 getunitdata_sub(UPET_CANMOVETICK, pd->ud.canmove_tick);
17577 getunitdata_sub(UPET_STR, pd->status.str);
17578 getunitdata_sub(UPET_AGI, pd->status.agi);
17579 getunitdata_sub(UPET_VIT, pd->status.vit);
17580 getunitdata_sub(UPET_INT, pd->status.int_);
17581 getunitdata_sub(UPET_DEX, pd->status.dex);
17582 getunitdata_sub(UPET_LUK, pd->status.luk);
17583 getunitdata_sub(UPET_DMGIMMUNE, pd->ud.immune_attack);
17584 getunitdata_sub(UPET_ATKRANGE, pd->status.rhw.range);
17585 getunitdata_sub(UPET_ATKMIN, pd->status.rhw.atk);
17586 getunitdata_sub(UPET_ATKMAX, pd->status.rhw.atk2);
17587 getunitdata_sub(UPET_MATKMIN, pd->status.matk_min);
17588 getunitdata_sub(UPET_MATKMAX, pd->status.matk_max);
17589 getunitdata_sub(UPET_DEF, pd->status.def);
17590 getunitdata_sub(UPET_MDEF, pd->status.mdef);
17591 getunitdata_sub(UPET_HIT, pd->status.hit);
17592 getunitdata_sub(UPET_FLEE, pd->status.flee);
17593 getunitdata_sub(UPET_PDODGE, pd->status.flee2);
17594 getunitdata_sub(UPET_CRIT, pd->status.cri);
17595 getunitdata_sub(UPET_RACE, pd->status.race);
17596 getunitdata_sub(UPET_ELETYPE, pd->status.def_ele);
17597 getunitdata_sub(UPET_ELELEVEL, pd->status.ele_lv);
17598 getunitdata_sub(UPET_AMOTION, pd->status.amotion);
17599 getunitdata_sub(UPET_ADELAY, pd->status.adelay);
17600 getunitdata_sub(UPET_DMOTION, pd->status.dmotion);
17605 ShowWarning("buildin_getunitdata: Error in finding object BL_MER!\n");
17606 return SCRIPT_CMD_FAILURE;
17608 getunitdata_sub(UMER_SIZE, mc->base_status.size);
17609 getunitdata_sub(UMER_HP, mc->base_status.hp);
17610 getunitdata_sub(UMER_MAXHP, mc->base_status.max_hp);
17611 getunitdata_sub(UMER_MASTERCID, mc->mercenary.char_id);
17612 getunitdata_sub(UMER_MAPID, mc->bl.m);
17613 getunitdata_sub(UMER_X, mc->bl.x);
17614 getunitdata_sub(UMER_Y, mc->bl.y);
17615 getunitdata_sub(UMER_KILLCOUNT, mc->mercenary.kill_count);
17616 getunitdata_sub(UMER_LIFETIME, mc->mercenary.life_time);
17617 getunitdata_sub(UMER_SPEED, mc->base_status.speed);
17618 getunitdata_sub(UMER_LOOKDIR, mc->ud.dir);
17619 getunitdata_sub(UMER_CANMOVETICK, mc->ud.canmove_tick);
17620 getunitdata_sub(UMER_STR, mc->base_status.str);
17621 getunitdata_sub(UMER_AGI, mc->base_status.agi);
17622 getunitdata_sub(UMER_VIT, mc->base_status.vit);
17623 getunitdata_sub(UMER_INT, mc->base_status.int_);
17624 getunitdata_sub(UMER_DEX, mc->base_status.dex);
17625 getunitdata_sub(UMER_LUK, mc->base_status.luk);
17626 getunitdata_sub(UMER_DMGIMMUNE, mc->ud.immune_attack);
17627 getunitdata_sub(UMER_ATKRANGE, mc->base_status.rhw.range);
17628 getunitdata_sub(UMER_ATKMIN, mc->base_status.rhw.atk);
17629 getunitdata_sub(UMER_ATKMAX, mc->base_status.rhw.atk2);
17630 getunitdata_sub(UMER_MATKMIN, mc->base_status.matk_min);
17631 getunitdata_sub(UMER_MATKMAX, mc->base_status.matk_max);
17632 getunitdata_sub(UMER_DEF, mc->base_status.def);
17633 getunitdata_sub(UMER_MDEF, mc->base_status.mdef);
17634 getunitdata_sub(UMER_HIT, mc->base_status.hit);
17635 getunitdata_sub(UMER_FLEE, mc->base_status.flee);
17636 getunitdata_sub(UMER_PDODGE, mc->base_status.flee2);
17637 getunitdata_sub(UMER_CRIT, mc->base_status.cri);
17638 getunitdata_sub(UMER_RACE, mc->base_status.race);
17639 getunitdata_sub(UMER_ELETYPE, mc->base_status.def_ele);
17640 getunitdata_sub(UMER_ELELEVEL, mc->base_status.ele_lv);
17641 getunitdata_sub(UMER_AMOTION, mc->base_status.amotion);
17642 getunitdata_sub(UMER_ADELAY, mc->base_status.adelay);
17643 getunitdata_sub(UMER_DMOTION, mc->base_status.dmotion);
17648 ShowWarning("buildin_getunitdata: Error in finding object BL_ELEM!\n");
17649 return SCRIPT_CMD_FAILURE;
17651 getunitdata_sub(UELE_SIZE, ed->base_status.size);
17652 getunitdata_sub(UELE_HP, ed->elemental.hp);
17653 getunitdata_sub(UELE_MAXHP, ed->elemental.max_hp);
17654 getunitdata_sub(UELE_SP, ed->elemental.sp);
17655 getunitdata_sub(UELE_MAXSP, ed->elemental.max_sp);
17656 getunitdata_sub(UELE_MASTERCID, ed->elemental.char_id);
17657 getunitdata_sub(UELE_MAPID, ed->bl.m);
17658 getunitdata_sub(UELE_X, ed->bl.x);
17659 getunitdata_sub(UELE_Y, ed->bl.y);
17660 getunitdata_sub(UELE_LIFETIME, ed->elemental.life_time);
17661 getunitdata_sub(UELE_MODE, ed->elemental.mode);
17662 getunitdata_sub(UELE_SP, ed->base_status.speed);
17663 getunitdata_sub(UELE_LOOKDIR, ed->ud.dir);
17664 getunitdata_sub(UELE_CANMOVETICK, ed->ud.canmove_tick);
17665 getunitdata_sub(UELE_STR, ed->base_status.str);
17666 getunitdata_sub(UELE_AGI, ed->base_status.agi);
17667 getunitdata_sub(UELE_VIT, ed->base_status.vit);
17668 getunitdata_sub(UELE_INT, ed->base_status.int_);
17669 getunitdata_sub(UELE_DEX, ed->base_status.dex);
17670 getunitdata_sub(UELE_LUK, ed->base_status.luk);
17671 getunitdata_sub(UELE_DMGIMMUNE, ed->ud.immune_attack);
17672 getunitdata_sub(UELE_ATKRANGE, ed->base_status.rhw.range);
17673 getunitdata_sub(UELE_ATKMIN, ed->base_status.rhw.atk);
17674 getunitdata_sub(UELE_ATKMAX, ed->base_status.rhw.atk2);
17675 getunitdata_sub(UELE_MATKMIN, ed->base_status.matk_min);
17676 getunitdata_sub(UELE_MATKMAX, ed->base_status.matk_max);
17677 getunitdata_sub(UELE_DEF, ed->base_status.def);
17678 getunitdata_sub(UELE_MDEF, ed->base_status.mdef);
17679 getunitdata_sub(UELE_HIT, ed->base_status.hit);
17680 getunitdata_sub(UELE_FLEE, ed->base_status.flee);
17681 getunitdata_sub(UELE_PDODGE, ed->base_status.flee2);
17682 getunitdata_sub(UELE_CRIT, ed->base_status.cri);
17683 getunitdata_sub(UELE_RACE, ed->base_status.race);
17684 getunitdata_sub(UELE_ELETYPE, ed->base_status.def_ele);
17685 getunitdata_sub(UELE_ELELEVEL, ed->base_status.ele_lv);
17686 getunitdata_sub(UELE_AMOTION, ed->base_status.amotion);
17687 getunitdata_sub(UELE_ADELAY, ed->base_status.adelay);
17688 getunitdata_sub(UELE_DMOTION, ed->base_status.dmotion);
17693 ShowWarning("buildin_getunitdata: Error in finding object BL_NPC!\n");
17694 return SCRIPT_CMD_FAILURE;
17696 getunitdata_sub(UNPC_DISPLAY, nd->class_);
17697 getunitdata_sub(UNPC_LEVEL, nd->level);
17698 getunitdata_sub(UNPC_HP, nd->status.hp);
17699 getunitdata_sub(UNPC_MAXHP, nd->status.max_hp);
17700 getunitdata_sub(UNPC_MAPID, nd->bl.m);
17701 getunitdata_sub(UNPC_X, nd->bl.x);
17702 getunitdata_sub(UNPC_Y, nd->bl.y);
17703 getunitdata_sub(UNPC_LOOKDIR, nd->ud.dir);
17704 getunitdata_sub(UNPC_STR, nd->status.str);
17705 getunitdata_sub(UNPC_AGI, nd->status.agi);
17706 getunitdata_sub(UNPC_VIT, nd->status.vit);
17707 getunitdata_sub(UNPC_INT, nd->status.int_);
17708 getunitdata_sub(UNPC_DEX, nd->status.dex);
17709 getunitdata_sub(UNPC_LUK, nd->status.luk);
17710 getunitdata_sub(UNPC_PLUSALLSTAT, nd->stat_point);
17711 getunitdata_sub(UNPC_DMGIMMUNE, nd->ud.immune_attack);
17712 getunitdata_sub(UNPC_ATKRANGE, nd->status.rhw.range);
17713 getunitdata_sub(UNPC_ATKMIN, nd->status.rhw.atk);
17714 getunitdata_sub(UNPC_ATKMAX, nd->status.rhw.atk2);
17715 getunitdata_sub(UNPC_MATKMIN, nd->status.matk_min);
17716 getunitdata_sub(UNPC_MATKMAX, nd->status.matk_max);
17717 getunitdata_sub(UNPC_DEF, nd->status.def);
17718 getunitdata_sub(UNPC_MDEF, nd->status.mdef);
17719 getunitdata_sub(UNPC_HIT, nd->status.hit);
17720 getunitdata_sub(UNPC_FLEE, nd->status.flee);
17721 getunitdata_sub(UNPC_PDODGE, nd->status.flee2);
17722 getunitdata_sub(UNPC_CRIT, nd->status.cri);
17723 getunitdata_sub(UNPC_RACE, nd->status.race);
17724 getunitdata_sub(UNPC_ELETYPE, nd->status.def_ele);
17725 getunitdata_sub(UNPC_ELELEVEL, nd->status.ele_lv);
17726 getunitdata_sub(UNPC_AMOTION, nd->status.amotion);
17727 getunitdata_sub(UNPC_ADELAY, nd->status.adelay);
17728 getunitdata_sub(UNPC_DMOTION, nd->status.dmotion);
17732 ShowWarning("buildin_getunitdata: Unknown object type!\n");
17733 return SCRIPT_CMD_FAILURE;
17736 #undef getunitdata_sub
17738 return SCRIPT_CMD_SUCCESS;
17741 /// Changes the live data of a bl.
17743 /// setunitdata <unit id>,<type>,<value>;
17744 BUILDIN_FUNC(setunitdata)
17746 struct block_list* bl = NULL;
17747 struct script_data* data;
17748 const char *mapname = NULL;
17749 TBL_MOB* md = NULL;
17750 TBL_HOM* hd = NULL;
17751 TBL_MER* mc = NULL;
17752 TBL_PET* pd = NULL;
17753 TBL_ELEM* ed = NULL;
17754 TBL_NPC* nd = NULL;
17755 int type, value = 0;
17756 bool calc_status = false;
17758 if(!script_rid2bl(2,bl))
17760 script_pushint(st, -1);
17761 return SCRIPT_CMD_FAILURE;
17764 switch (bl->type) {
17765 case BL_MOB: md = map_id2md(bl->id); break;
17766 case BL_HOM: hd = map_id2hd(bl->id); break;
17767 case BL_PET: pd = map_id2pd(bl->id); break;
17768 case BL_MER: mc = map_id2mc(bl->id); break;
17769 case BL_ELEM: ed = map_id2ed(bl->id); break;
17771 nd = map_id2nd(bl->id);
17772 if (!nd->status.hp)
17773 status_calc_npc(nd, SCO_FIRST);
17775 status_calc_npc(nd, SCO_NONE);
17778 ShowError("buildin_setunitdata: Invalid object!\n");
17779 return SCRIPT_CMD_FAILURE;
17782 type = script_getnum(st, 3);
17783 data = script_getdata(st, 4);
17786 if (type == 5 && data_isstring(data))
17787 mapname = conv_str(st, data);
17788 else if (data_isint(data))
17789 value = conv_num(st, data);
17791 ShowError("buildin_setunitdata: Invalid data type for argument #3 (%d).\n", data->type);
17792 return SCRIPT_CMD_FAILURE;
17795 switch (bl->type) {
17798 ShowWarning("buildin_setunitdata: Error in finding object BL_MOB!\n");
17799 return SCRIPT_CMD_FAILURE;
17801 if (!md->base_status) {
17802 md->base_status = (struct status_data*)aCalloc(1, sizeof(struct status_data));
17803 memcpy(md->base_status, &md->db->status, sizeof(struct status_data));
17806 // Check if the view data will be modified
17809 //case UMOB_CLASS: // Called by status_set_viewdata
17810 case UMOB_HAIRSTYLE:
17811 case UMOB_HAIRCOLOR:
17812 case UMOB_HEADBOTTOM:
17813 case UMOB_HEADMIDDLE:
17815 case UMOB_CLOTHCOLOR:
17818 mob_set_dynamic_viewdata( md );
17823 case UMOB_SIZE: md->base_status->size = (unsigned char)value; calc_status = true; break;
17824 case UMOB_LEVEL: md->level = (unsigned short)value; break;
17825 case UMOB_HP: md->base_status->hp = (unsigned int)value; status_set_hp(bl, (unsigned int)value, 0); clif_name_area(&md->bl); break;
17826 case UMOB_MAXHP: md->base_status->max_hp = (unsigned int)value; status_set_maxhp(bl, (unsigned int)value, 0); clif_name_area(&md->bl); break;
17827 case UMOB_MASTERAID: md->master_id = value; break;
17828 case UMOB_MAPID: if (mapname) value = map_mapname2mapid(mapname); unit_warp(bl, (short)value, 0, 0, CLR_TELEPORT); break;
17829 case UMOB_X: if (!unit_walktoxy(bl, (short)value, md->bl.y, 2)) unit_movepos(bl, (short)value, md->bl.y, 0, 0); break;
17830 case UMOB_Y: if (!unit_walktoxy(bl, md->bl.x, (short)value, 2)) unit_movepos(bl, md->bl.x, (short)value, 0, 0); break;
17831 case UMOB_SPEED: md->base_status->speed = (unsigned short)value; status_calc_misc(bl, &md->status, md->level); calc_status = true; break;
17832 case UMOB_MODE: md->base_status->mode = (enum e_mode)value; calc_status = true; break;
17833 case UMOB_AI: md->special_state.ai = (enum mob_ai)value; break;
17834 case UMOB_SCOPTION: md->sc.option = (unsigned short)value; break;
17835 case UMOB_SEX: md->vd->sex = (char)value; clif_clearunit_area(bl, CLR_OUTSIGHT); clif_spawn(bl); break;
17836 case UMOB_CLASS: status_set_viewdata(bl, (unsigned short)value); clif_clearunit_area(bl, CLR_OUTSIGHT); clif_spawn(bl); break;
17837 case UMOB_HAIRSTYLE: clif_changelook(bl, LOOK_HAIR, (unsigned short)value); break;
17838 case UMOB_HAIRCOLOR: clif_changelook(bl, LOOK_HAIR_COLOR, (unsigned short)value); break;
17839 case UMOB_HEADBOTTOM: clif_changelook(bl, LOOK_HEAD_BOTTOM, (unsigned short)value); break;
17840 case UMOB_HEADMIDDLE: clif_changelook(bl, LOOK_HEAD_MID, (unsigned short)value); break;
17841 case UMOB_HEADTOP: clif_changelook(bl, LOOK_HEAD_TOP, (unsigned short)value); break;
17842 case UMOB_CLOTHCOLOR: clif_changelook(bl, LOOK_CLOTHES_COLOR, (unsigned short)value); break;
17843 case UMOB_SHIELD: clif_changelook(bl, LOOK_SHIELD, (unsigned short)value); break;
17844 case UMOB_WEAPON: clif_changelook(bl, LOOK_WEAPON, (unsigned short)value); break;
17845 case UMOB_LOOKDIR: unit_setdir(bl, (uint8)value); break;
17846 case UMOB_CANMOVETICK: md->ud.canmove_tick = value > 0 ? (unsigned int)value : 0; break;
17847 case UMOB_STR: md->base_status->str = (unsigned short)value; status_calc_misc(bl, &md->status, md->level); calc_status = true; break;
17848 case UMOB_AGI: md->base_status->agi = (unsigned short)value; status_calc_misc(bl, &md->status, md->level); calc_status = true; break;
17849 case UMOB_VIT: md->base_status->vit = (unsigned short)value; status_calc_misc(bl, &md->status, md->level); calc_status = true; break;
17850 case UMOB_INT: md->base_status->int_ = (unsigned short)value; status_calc_misc(bl, &md->status, md->level); calc_status = true; break;
17851 case UMOB_DEX: md->base_status->dex = (unsigned short)value; status_calc_misc(bl, &md->status, md->level); calc_status = true; break;
17852 case UMOB_LUK: md->base_status->luk = (unsigned short)value; status_calc_misc(bl, &md->status, md->level); calc_status = true; break;
17853 case UMOB_SLAVECPYMSTRMD:
17855 TBL_MOB *md2 = NULL;
17856 if (!md->master_id || !(md2 = map_id2md(md->master_id))) {
17857 ShowWarning("buildin_setunitdata: Trying to set UMOB_SLAVECPYMSTRMD on mob without master!\n");
17860 md->base_status->mode = md2->status.mode;
17861 md->state.copy_master_mode = 1;
17863 md->state.copy_master_mode = 0;
17864 calc_status = true;
17866 case UMOB_DMGIMMUNE: md->ud.immune_attack = value > 0; break;
17867 case UMOB_ATKRANGE: md->base_status->rhw.range = (unsigned short)value; calc_status = true; break;
17868 case UMOB_ATKMIN: md->base_status->rhw.atk = (unsigned short)value; calc_status = true; break;
17869 case UMOB_ATKMAX: md->base_status->rhw.atk2 = (unsigned short)value; calc_status = true; break;
17870 case UMOB_MATKMIN: md->base_status->matk_min = (unsigned short)value; calc_status = true; break;
17871 case UMOB_MATKMAX: md->base_status->matk_max = (unsigned short)value; calc_status = true; break;
17872 case UMOB_DEF: md->base_status->def = (defType)value; calc_status = true; break;
17873 case UMOB_MDEF: md->base_status->mdef = (defType)value; calc_status = true; break;
17874 case UMOB_HIT: md->base_status->hit = (short)value; calc_status = true; break;
17875 case UMOB_FLEE: md->base_status->flee = (short)value; calc_status = true; break;
17876 case UMOB_PDODGE: md->base_status->flee2 = (short)value; calc_status = true; break;
17877 case UMOB_CRIT: md->base_status->cri = (short)value; calc_status = true; break;
17878 case UMOB_RACE: md->base_status->race = (unsigned char)value; calc_status = true; break;
17879 case UMOB_ELETYPE: md->base_status->def_ele = (unsigned char)value; calc_status = true; break;
17880 case UMOB_ELELEVEL: md->base_status->ele_lv = (unsigned char)value; calc_status = true; break;
17881 case UMOB_AMOTION: md->base_status->amotion = (short)value; calc_status = true; break;
17882 case UMOB_ADELAY: md->base_status->adelay = (short)value; calc_status = true; break;
17883 case UMOB_DMOTION: md->base_status->dmotion = (short)value; calc_status = true; break;
17885 ShowError("buildin_setunitdata: Unknown data identifier %d for BL_MOB.\n", type);
17886 return SCRIPT_CMD_FAILURE;
17889 status_calc_bl(&md->bl, SCB_BATTLE);
17894 ShowWarning("buildin_setunitdata: Error in finding object BL_HOM!\n");
17895 return SCRIPT_CMD_FAILURE;
17898 case UHOM_SIZE: hd->base_status.size = (unsigned char)value; calc_status = true; break;
17899 case UHOM_LEVEL: hd->homunculus.level = (unsigned short)value; break;
17900 case UHOM_HP: hd->base_status.hp = (unsigned int)value; status_set_hp(bl, (unsigned int)value, 0); break;
17901 case UHOM_MAXHP: hd->base_status.max_hp = (unsigned int)value; status_set_maxhp(bl, (unsigned int)value, 0); break;
17902 case UHOM_SP: hd->base_status.sp = (unsigned int)value; status_set_sp(bl, (unsigned int)value, 0); break;
17903 case UHOM_MAXSP: hd->base_status.max_sp = (unsigned int)value; status_set_maxsp(bl, (unsigned int)value, 0); break;
17904 case UHOM_MASTERCID: hd->homunculus.char_id = (uint32)value; break;
17905 case UHOM_MAPID: if (mapname) value = map_mapname2mapid(mapname); unit_warp(bl, (short)value, 0, 0, CLR_TELEPORT); break;
17906 case UHOM_X: if (!unit_walktoxy(bl, (short)value, hd->bl.y, 2)) unit_movepos(bl, (short)value, hd->bl.y, 0, 0); break;
17907 case UHOM_Y: if (!unit_walktoxy(bl, hd->bl.x, (short)value, 2)) unit_movepos(bl, hd->bl.x, (short)value, 0, 0); break;
17908 case UHOM_HUNGER: hd->homunculus.hunger = (short)value; clif_send_homdata(map_charid2sd(hd->homunculus.char_id), SP_HUNGRY, hd->homunculus.hunger); break;
17909 case UHOM_INTIMACY: hom_increase_intimacy(hd, (unsigned int)value); clif_send_homdata(map_charid2sd(hd->homunculus.char_id), SP_INTIMATE, hd->homunculus.intimacy / 100); break;
17910 case UHOM_SPEED: hd->base_status.speed = (unsigned short)value; status_calc_misc(bl, &hd->base_status, hd->homunculus.level); calc_status = true; break;
17911 case UHOM_LOOKDIR: unit_setdir(bl, (uint8)value); break;
17912 case UHOM_CANMOVETICK: hd->ud.canmove_tick = value > 0 ? (unsigned int)value : 0; break;
17913 case UHOM_STR: hd->base_status.str = (unsigned short)value; status_calc_misc(bl, &hd->base_status, hd->homunculus.level); calc_status = true; break;
17914 case UHOM_AGI: hd->base_status.agi = (unsigned short)value; status_calc_misc(bl, &hd->base_status, hd->homunculus.level); calc_status = true; break;
17915 case UHOM_VIT: hd->base_status.vit = (unsigned short)value; status_calc_misc(bl, &hd->base_status, hd->homunculus.level); calc_status = true; break;
17916 case UHOM_INT: hd->base_status.int_ = (unsigned short)value; status_calc_misc(bl, &hd->base_status, hd->homunculus.level); calc_status = true; break;
17917 case UHOM_DEX: hd->base_status.dex = (unsigned short)value; status_calc_misc(bl, &hd->base_status, hd->homunculus.level); calc_status = true; break;
17918 case UHOM_LUK: hd->base_status.luk = (unsigned short)value; status_calc_misc(bl, &hd->base_status, hd->homunculus.level); calc_status = true; break;
17919 case UHOM_DMGIMMUNE: hd->ud.immune_attack = value > 0; break;
17920 case UHOM_ATKRANGE: hd->base_status.rhw.range = (unsigned short)value; calc_status = true; break;
17921 case UHOM_ATKMIN: hd->base_status.rhw.atk = (unsigned short)value; calc_status = true; break;
17922 case UHOM_ATKMAX: hd->base_status.rhw.atk2 = (unsigned short)value; calc_status = true; break;
17923 case UHOM_MATKMIN: hd->base_status.matk_min = (unsigned short)value; calc_status = true; break;
17924 case UHOM_MATKMAX: hd->base_status.matk_max = (unsigned short)value; calc_status = true; break;
17925 case UHOM_DEF: hd->base_status.def = (defType)value; calc_status = true; break;
17926 case UHOM_MDEF: hd->base_status.mdef = (defType)value; calc_status = true; break;
17927 case UHOM_HIT: hd->base_status.hit = (short)value; calc_status = true; break;
17928 case UHOM_FLEE: hd->base_status.flee = (short)value; calc_status = true; break;
17929 case UHOM_PDODGE: hd->base_status.flee2 = (short)value; calc_status = true; break;
17930 case UHOM_CRIT: hd->base_status.cri = (short)value; calc_status = true; break;
17931 case UHOM_RACE: hd->base_status.race = (unsigned char)value; calc_status = true; break;
17932 case UHOM_ELETYPE: hd->base_status.def_ele = (unsigned char)value; calc_status = true; break;
17933 case UHOM_ELELEVEL: hd->base_status.ele_lv = (unsigned char)value; calc_status = true; break;
17934 case UHOM_AMOTION: hd->base_status.amotion = (short)value; calc_status = true; break;
17935 case UHOM_ADELAY: hd->base_status.adelay = (short)value; calc_status = true; break;
17936 case UHOM_DMOTION: hd->base_status.dmotion = (short)value; calc_status = true; break;
17938 ShowError("buildin_setunitdata: Unknown data identifier %d for BL_HOM.\n", type);
17939 return SCRIPT_CMD_FAILURE;
17942 status_calc_bl(&hd->bl, SCB_BATTLE);
17947 ShowWarning("buildin_setunitdata: Error in finding object BL_PET!\n");
17948 return SCRIPT_CMD_FAILURE;
17951 case UPET_SIZE: pd->status.size = (unsigned char)value; break;
17952 case UPET_LEVEL: pd->pet.level = (unsigned short)value; break;
17953 case UPET_HP: status_set_hp(bl, (unsigned int)value, 0); break;
17954 case UPET_MAXHP: status_set_maxhp(bl, (unsigned int)value, 0); break;
17955 case UPET_MASTERAID: pd->pet.account_id = (unsigned int)value; break;
17956 case UPET_MAPID: if (mapname) value = map_mapname2mapid(mapname); unit_warp(bl, (short)value, 0, 0, CLR_TELEPORT); break;
17957 case UPET_X: if (!unit_walktoxy(bl, (short)value, pd->bl.y, 2)) unit_movepos(bl, (short)value, md->bl.y, 0, 0); break;
17958 case UPET_Y: if (!unit_walktoxy(bl, pd->bl.x, (short)value, 2)) unit_movepos(bl, pd->bl.x, (short)value, 0, 0); break;
17959 case UPET_HUNGER: pd->pet.hungry = (short)value; clif_send_petdata(map_id2sd(pd->pet.account_id), pd, 2, pd->pet.hungry); break;
17960 case UPET_INTIMACY: pet_set_intimate(pd, (unsigned int)value); clif_send_petdata(map_id2sd(pd->pet.account_id), pd, 1, pd->pet.intimate); break;
17961 case UPET_SPEED: pd->status.speed = (unsigned short)value; status_calc_misc(bl, &pd->status, pd->pet.level); break;
17962 case UPET_LOOKDIR: unit_setdir(bl, (uint8)value); break;
17963 case UPET_CANMOVETICK: pd->ud.canmove_tick = value > 0 ? (unsigned int)value : 0; break;
17964 case UPET_STR: pd->status.str = (unsigned short)value; status_calc_misc(bl, &pd->status, pd->pet.level); break;
17965 case UPET_AGI: pd->status.agi = (unsigned short)value; status_calc_misc(bl, &pd->status, pd->pet.level); break;
17966 case UPET_VIT: pd->status.vit = (unsigned short)value; status_calc_misc(bl, &pd->status, pd->pet.level); break;
17967 case UPET_INT: pd->status.int_ = (unsigned short)value; status_calc_misc(bl, &pd->status, pd->pet.level); break;
17968 case UPET_DEX: pd->status.dex = (unsigned short)value; status_calc_misc(bl, &pd->status, pd->pet.level); break;
17969 case UPET_LUK: pd->status.luk = (unsigned short)value; status_calc_misc(bl, &pd->status, pd->pet.level); break;
17970 case UPET_DMGIMMUNE: pd->ud.immune_attack = value > 0; break;
17971 case UPET_ATKRANGE: pd->status.rhw.range = (unsigned short)value; break;
17972 case UPET_ATKMIN: pd->status.rhw.atk = (unsigned short)value; break;
17973 case UPET_ATKMAX: pd->status.rhw.atk2 = (unsigned short)value; break;
17974 case UPET_MATKMIN: pd->status.matk_min = (unsigned short)value; break;
17975 case UPET_MATKMAX: pd->status.matk_max = (unsigned short)value; break;
17976 case UPET_DEF: pd->status.def = (defType)value; break;
17977 case UPET_MDEF: pd->status.mdef = (defType)value; break;
17978 case UPET_HIT: pd->status.hit = (short)value; break;
17979 case UPET_FLEE: pd->status.flee = (short)value; break;
17980 case UPET_PDODGE: pd->status.flee2 = (short)value; break;
17981 case UPET_CRIT: pd->status.cri = (short)value; break;
17982 case UPET_RACE: pd->status.race = (unsigned char)value; break;
17983 case UPET_ELETYPE: pd->status.def_ele = (unsigned char)value; break;
17984 case UPET_ELELEVEL: pd->status.ele_lv = (unsigned char)value; break;
17985 case UPET_AMOTION: pd->status.amotion = (short)value; break;
17986 case UPET_ADELAY: pd->status.adelay = (short)value; break;
17987 case UPET_DMOTION: pd->status.dmotion = (short)value; break;
17989 ShowError("buildin_setunitdata: Unknown data identifier %d for BL_PET.\n", type);
17990 return SCRIPT_CMD_FAILURE;
17996 ShowWarning("buildin_setunitdata: Error in finding object BL_MER!\n");
17997 return SCRIPT_CMD_FAILURE;
18000 case UMER_SIZE: mc->base_status.size = (unsigned char)value; calc_status = true; break;
18001 case UMER_HP: mc->base_status.hp = (unsigned int)value; status_set_hp(bl, (unsigned int)value, 0); break;
18002 case UMER_MAXHP: mc->base_status.max_hp = (unsigned int)value; status_set_maxhp(bl, (unsigned int)value, 0); break;
18003 case UMER_MASTERCID: mc->mercenary.char_id = (uint32)value; break;
18004 case UMER_MAPID: if (mapname) value = map_mapname2mapid(mapname); unit_warp(bl, (short)value, 0, 0, CLR_TELEPORT); break;
18005 case UMER_X: if (!unit_walktoxy(bl, (short)value, mc->bl.y, 2)) unit_movepos(bl, (short)value, mc->bl.y, 0, 0); break;
18006 case UMER_Y: if (!unit_walktoxy(bl, mc->bl.x, (short)value, 2)) unit_movepos(bl, mc->bl.x, (short)value, 0, 0); break;
18007 case UMER_KILLCOUNT: mc->mercenary.kill_count = (unsigned int)value; break;
18008 case UMER_LIFETIME: mc->mercenary.life_time = (unsigned int)value; break;
18009 case UMER_SPEED: mc->base_status.speed = (unsigned short)value; status_calc_misc(bl, &mc->base_status, mc->db->lv); calc_status = true; break;
18010 case UMER_LOOKDIR: unit_setdir(bl, (uint8)value); break;
18011 case UMER_CANMOVETICK: mc->ud.canmove_tick = value > 0 ? (unsigned int)value : 0; break;
18012 case UMER_STR: mc->base_status.str = (unsigned short)value; status_calc_misc(bl, &mc->base_status, mc->db->lv); calc_status = true; break;
18013 case UMER_AGI: mc->base_status.agi = (unsigned short)value; status_calc_misc(bl, &mc->base_status, mc->db->lv); calc_status = true; break;
18014 case UMER_VIT: mc->base_status.vit = (unsigned short)value; status_calc_misc(bl, &mc->base_status, mc->db->lv); calc_status = true; break;
18015 case UMER_INT: mc->base_status.int_ = (unsigned short)value; status_calc_misc(bl, &mc->base_status, mc->db->lv); calc_status = true; break;
18016 case UMER_DEX: mc->base_status.dex = (unsigned short)value; status_calc_misc(bl, &mc->base_status, mc->db->lv); calc_status = true; break;
18017 case UMER_LUK: mc->base_status.luk = (unsigned short)value; status_calc_misc(bl, &mc->base_status, mc->db->lv); calc_status = true; break;
18018 case UMER_DMGIMMUNE: mc->ud.immune_attack = value > 0; break;
18019 case UMER_ATKRANGE: mc->base_status.rhw.range = (unsigned short)value; calc_status = true; break;
18020 case UMER_ATKMIN: mc->base_status.rhw.atk = (unsigned short)value; calc_status = true; break;
18021 case UMER_ATKMAX: mc->base_status.rhw.atk2 = (unsigned short)value; calc_status = true; break;
18022 case UMER_MATKMIN: mc->base_status.matk_min = (unsigned short)value; calc_status = true; break;
18023 case UMER_MATKMAX: mc->base_status.matk_max = (unsigned short)value; calc_status = true; break;
18024 case UMER_DEF: mc->base_status.def = (defType)value; calc_status = true; break;
18025 case UMER_MDEF: mc->base_status.mdef = (defType)value; calc_status = true; break;
18026 case UMER_HIT: mc->base_status.hit = (short)value; calc_status = true; break;
18027 case UMER_FLEE: mc->base_status.flee = (short)value; calc_status = true; break;
18028 case UMER_PDODGE: mc->base_status.flee2 = (short)value; calc_status = true; break;
18029 case UMER_CRIT: mc->base_status.cri = (short)value; calc_status = true; break;
18030 case UMER_RACE: mc->base_status.race = (unsigned char)value; calc_status = true; break;
18031 case UMER_ELETYPE: mc->base_status.def_ele = (unsigned char)value; calc_status = true; break;
18032 case UMER_ELELEVEL: mc->base_status.ele_lv = (unsigned char)value; calc_status = true; break;
18033 case UMER_AMOTION: mc->base_status.amotion = (short)value; calc_status = true; break;
18034 case UMER_ADELAY: mc->base_status.adelay = (short)value; calc_status = true; break;
18035 case UMER_DMOTION: mc->base_status.dmotion = (short)value; calc_status = true; break;
18037 ShowError("buildin_setunitdata: Unknown data identifier %d for BL_MER.\n", type);
18038 return SCRIPT_CMD_FAILURE;
18041 status_calc_bl(&mc->bl, SCB_BATTLE);
18046 ShowWarning("buildin_setunitdata: Error in finding object BL_ELEM!\n");
18047 return SCRIPT_CMD_FAILURE;
18050 case UELE_SIZE: ed->base_status.size = (unsigned char)value; calc_status = true; break;
18051 case UELE_HP: ed->base_status.hp = (unsigned int)value; status_set_hp(bl, (unsigned int)value, 0); break;
18052 case UELE_MAXHP: ed->base_status.max_hp = (unsigned int)value; status_set_maxhp(bl, (unsigned int)value, 0); break;
18053 case UELE_SP: ed->base_status.sp = (unsigned int)value; status_set_sp(bl, (unsigned int)value, 0); break;
18054 case UELE_MAXSP: ed->base_status.max_sp = (unsigned int)value; status_set_maxsp(bl, (unsigned int)value, 0); break;
18055 case UELE_MASTERCID: ed->elemental.char_id = (uint32)value; break;
18056 case UELE_MAPID: if (mapname) value = map_mapname2mapid(mapname); unit_warp(bl, (short)value, 0, 0, CLR_TELEPORT); break;
18057 case UELE_X: if (!unit_walktoxy(bl, (short)value, ed->bl.y, 2)) unit_movepos(bl, (short)value, ed->bl.y, 0, 0); break;
18058 case UELE_Y: if (!unit_walktoxy(bl, ed->bl.x, (short)value, 2)) unit_movepos(bl, ed->bl.x, (short)value, 0, 0); break;
18059 case UELE_LIFETIME: ed->elemental.life_time = (unsigned int)value; break;
18060 case UELE_MODE: ed->elemental.mode = (enum e_mode)value; calc_status = true; break;
18061 case UELE_SPEED: ed->base_status.speed = (unsigned short)value; status_calc_misc(bl, &ed->base_status, ed->db->lv); calc_status = true; break;
18062 case UELE_LOOKDIR: unit_setdir(bl, (uint8)value); break;
18063 case UELE_CANMOVETICK: ed->ud.canmove_tick = value > 0 ? (unsigned int)value : 0; break;
18064 case UELE_STR: ed->base_status.str = (unsigned short)value; status_calc_misc(bl, &ed->base_status, ed->db->lv); calc_status = true; break;
18065 case UELE_AGI: ed->base_status.agi = (unsigned short)value; status_calc_misc(bl, &ed->base_status, ed->db->lv); calc_status = true; break;
18066 case UELE_VIT: ed->base_status.vit = (unsigned short)value; status_calc_misc(bl, &ed->base_status, ed->db->lv); calc_status = true; break;
18067 case UELE_INT: ed->base_status.int_ = (unsigned short)value; status_calc_misc(bl, &ed->base_status, ed->db->lv); calc_status = true; break;
18068 case UELE_DEX: ed->base_status.dex = (unsigned short)value; status_calc_misc(bl, &ed->base_status, ed->db->lv); calc_status = true; break;
18069 case UELE_LUK: ed->base_status.luk = (unsigned short)value; status_calc_misc(bl, &ed->base_status, ed->db->lv); calc_status = true; break;
18070 case UELE_DMGIMMUNE: ed->ud.immune_attack = value > 0; break;
18071 case UELE_ATKRANGE: ed->base_status.rhw.range = (unsigned short)value; calc_status = true; break;
18072 case UELE_ATKMIN: ed->base_status.rhw.atk = (unsigned short)value; calc_status = true; break;
18073 case UELE_ATKMAX: ed->base_status.rhw.atk2 = (unsigned short)value; calc_status = true; break;
18074 case UELE_MATKMIN: ed->base_status.matk_min = (unsigned short)value; calc_status = true; break;
18075 case UELE_MATKMAX: ed->base_status.matk_max = (unsigned short)value; calc_status = true; break;
18076 case UELE_DEF: ed->base_status.def = (defType)value; calc_status = true; break;
18077 case UELE_MDEF: ed->base_status.mdef = (defType)value; calc_status = true; break;
18078 case UELE_HIT: ed->base_status.hit = (short)value; calc_status = true; break;
18079 case UELE_FLEE: ed->base_status.flee = (short)value; calc_status = true; break;
18080 case UELE_PDODGE: ed->base_status.flee2 = (short)value; calc_status = true; break;
18081 case UELE_CRIT: ed->base_status.cri = (short)value; calc_status = true; break;
18082 case UELE_RACE: ed->base_status.race = (unsigned char)value; calc_status = true; break;
18083 case UELE_ELETYPE: ed->base_status.def_ele = (unsigned char)value; calc_status = true; break;
18084 case UELE_ELELEVEL: ed->base_status.ele_lv = (unsigned char)value; calc_status = true; break;
18085 case UELE_AMOTION: ed->base_status.amotion = (short)value; calc_status = true; break;
18086 case UELE_ADELAY: ed->base_status.adelay = (short)value; calc_status = true; break;
18087 case UELE_DMOTION: ed->base_status.dmotion = (short)value; calc_status = true; break;
18089 ShowError("buildin_setunitdata: Unknown data identifier %d for BL_ELEM.\n", type);
18090 return SCRIPT_CMD_FAILURE;
18093 status_calc_bl(&ed->bl, SCB_BATTLE);
18098 ShowWarning("buildin_setunitdata: Error in finding object BL_NPC!\n");
18099 return SCRIPT_CMD_FAILURE;
18102 case UNPC_DISPLAY: status_set_viewdata(bl, (unsigned short)value); break;
18103 case UNPC_LEVEL: nd->level = (unsigned int)value; break;
18104 case UNPC_HP: status_set_hp(bl, (unsigned int)value, 0); break;
18105 case UNPC_MAXHP: status_set_maxhp(bl, (unsigned int)value, 0); break;
18106 case UNPC_MAPID: if (mapname) value = map_mapname2mapid(mapname); unit_warp(bl, (short)value, 0, 0, CLR_TELEPORT); break;
18107 case UNPC_X: if (!unit_walktoxy(bl, (short)value, nd->bl.y, 2)) unit_movepos(bl, (short)value, nd->bl.x, 0, 0); break;
18108 case UNPC_Y: if (!unit_walktoxy(bl, nd->bl.x, (short)value, 2)) unit_movepos(bl, nd->bl.x, (short)value, 0, 0); break;
18109 case UNPC_LOOKDIR: unit_setdir(bl, (uint8)value); break;
18110 case UNPC_STR: nd->params.str = (unsigned short)value; status_calc_misc(bl, &nd->status, nd->level); break;
18111 case UNPC_AGI: nd->params.agi = (unsigned short)value; status_calc_misc(bl, &nd->status, nd->level); break;
18112 case UNPC_VIT: nd->params.vit = (unsigned short)value; status_calc_misc(bl, &nd->status, nd->level); break;
18113 case UNPC_INT: nd->params.int_ = (unsigned short)value; status_calc_misc(bl, &nd->status, nd->level); break;
18114 case UNPC_DEX: nd->params.dex = (unsigned short)value; status_calc_misc(bl, &nd->status, nd->level); break;
18115 case UNPC_LUK: nd->params.luk = (unsigned short)value; status_calc_misc(bl, &nd->status, nd->level); break;
18116 case UNPC_PLUSALLSTAT: nd->stat_point = (unsigned int)value; break;
18117 case UNPC_ATKRANGE: nd->status.rhw.range = (unsigned short)value; break;
18118 case UNPC_ATKMIN: nd->status.rhw.atk = (unsigned short)value; break;
18119 case UNPC_ATKMAX: nd->status.rhw.atk2 = (unsigned short)value; break;
18120 case UNPC_MATKMIN: nd->status.matk_min = (unsigned short)value; break;
18121 case UNPC_MATKMAX: nd->status.matk_max = (unsigned short)value; break;
18122 case UNPC_DEF: nd->status.def = (defType)value; break;
18123 case UNPC_MDEF: nd->status.mdef = (defType)value; break;
18124 case UNPC_HIT: nd->status.hit = (short)value; break;
18125 case UNPC_FLEE: nd->status.flee = (short)value; break;
18126 case UNPC_PDODGE: nd->status.flee2 = (short)value; break;
18127 case UNPC_CRIT: nd->status.cri = (short)value; break;
18128 case UNPC_RACE: nd->status.race = (unsigned char)value; break;
18129 case UNPC_ELETYPE: nd->status.def_ele = (unsigned char)value; break;
18130 case UNPC_ELELEVEL: nd->status.ele_lv = (unsigned char)value; break;
18131 case UNPC_AMOTION: nd->status.amotion = (short)value; break;
18132 case UNPC_ADELAY: nd->status.adelay = (short)value; break;
18133 case UNPC_DMOTION: nd->status.dmotion = (short)value; break;
18135 ShowError("buildin_setunitdata: Unknown data identifier %d for BL_NPC.\n", type);
18136 return SCRIPT_CMD_FAILURE;
18141 ShowWarning("buildin_setunitdata: Unknown object type!\n");
18142 return SCRIPT_CMD_FAILURE;
18145 // Client information updates
18146 switch (bl->type) {
18148 clif_send_homdata(hd->master, SP_ACK, 0);
18151 clif_send_petstatus(pd->master);
18154 clif_mercenary_info(map_charid2sd(mc->mercenary.char_id));
18155 clif_mercenary_skillblock(map_charid2sd(mc->mercenary.char_id));
18158 clif_elemental_info(ed->master);
18161 ShowWarning("buildin_setunitdata: Invalid object type!\n");
18162 return SCRIPT_CMD_FAILURE;
18165 return SCRIPT_CMD_SUCCESS;
18168 /// Gets the name of a bl.
18169 /// Supported types are [MOB|HOM|PET|NPC].
18170 /// MER and ELEM don't support custom names.
18172 /// getunitname <unit id>;
18173 BUILDIN_FUNC(getunitname)
18175 struct block_list* bl = NULL;
18177 if(!script_rid2bl(2,bl)){
18178 script_pushconststr(st, "Unknown");
18179 return SCRIPT_CMD_FAILURE;
18182 script_pushstrcopy(st, status_get_name(bl));
18184 return SCRIPT_CMD_SUCCESS;
18187 /// Changes the name of a bl.
18188 /// Supported types are [MOB|HOM|PET].
18189 /// For NPC see 'setnpcdisplay', MER and ELEM don't support custom names.
18191 /// setunitname <unit id>,<name>;
18192 BUILDIN_FUNC(setunitname)
18194 struct block_list* bl = NULL;
18195 TBL_MOB* md = NULL;
18196 TBL_HOM* hd = NULL;
18197 TBL_PET* pd = NULL;
18199 if(!script_rid2bl(2,bl))
18201 script_pushconststr(st, "Unknown");
18202 return SCRIPT_CMD_FAILURE;
18205 switch (bl->type) {
18206 case BL_MOB: md = map_id2md(bl->id); break;
18207 case BL_HOM: hd = map_id2hd(bl->id); break;
18208 case BL_PET: pd = map_id2pd(bl->id); break;
18210 ShowWarning("buildin_setunitname: Invalid object type!\n");
18211 return SCRIPT_CMD_FAILURE;
18214 switch (bl->type) {
18217 ShowWarning("buildin_setunitname: Error in finding object BL_MOB!\n");
18218 return SCRIPT_CMD_FAILURE;
18220 safestrncpy(md->name, script_getstr(st, 3), NAME_LENGTH);
18224 ShowWarning("buildin_setunitname: Error in finding object BL_HOM!\n");
18225 return SCRIPT_CMD_FAILURE;
18227 safestrncpy(hd->homunculus.name, script_getstr(st, 3), NAME_LENGTH);
18231 ShowWarning("buildin_setunitname: Error in finding object BL_PET!\n");
18232 return SCRIPT_CMD_FAILURE;
18234 safestrncpy(pd->pet.name, script_getstr(st, 3), NAME_LENGTH);
18237 ShowWarning("buildin_setunitname: Unknown object type!\n");
18238 return SCRIPT_CMD_FAILURE;
18240 clif_name_area(bl); // Send update to client.
18242 return SCRIPT_CMD_SUCCESS;
18245 /// Makes the unit walk to target position or map.
18246 /// Returns if it was successful.
18248 /// unitwalk(<unit_id>,<x>,<y>{,<event_label>}) -> <bool>
18249 /// unitwalkto(<unit_id>,<target_id>{,<event_label>}) -> <bool>
18250 BUILDIN_FUNC(unitwalk)
18252 struct block_list* bl;
18253 struct unit_data *ud = NULL;
18254 const char *cmd = script_getfuncname(st), *done_label = "";
18257 if(!script_rid2bl(2,bl))
18259 script_pushint(st, 0);
18260 return SCRIPT_CMD_FAILURE;
18263 ud = unit_bl2ud(bl);
18265 if (!strcmp(cmd,"unitwalk")) {
18266 int x = script_getnum(st,3);
18267 int y = script_getnum(st,4);
18269 if (script_pushint(st, unit_can_reach_pos(bl,x,y,0)))
18270 add_timer(gettick()+50, unit_delay_walktoxy_timer, bl->id, (x<<16)|(y&0xFFFF)); // Need timer to avoid mismatches
18272 struct block_list* tbl = map_id2bl(script_getnum(st,3));
18275 ShowError("buildin_unitwalk: Bad target destination.\n");
18276 script_pushint(st, 0);
18277 return SCRIPT_CMD_FAILURE;
18278 } else if (script_pushint(st, unit_can_reach_bl(bl, tbl, distance_bl(bl, tbl)+1, 0, NULL, NULL)))
18279 add_timer(gettick()+50, unit_delay_walktobl_timer, bl->id, tbl->id); // Need timer to avoid mismatches
18283 if (ud && script_hasdata(st, off)) {
18284 done_label = script_getstr(st, off);
18285 check_event(st, done_label);
18286 safestrncpy(ud->walk_done_event, done_label, sizeof(ud->walk_done_event));
18289 return SCRIPT_CMD_SUCCESS;
18292 /// Kills the unit.
18294 /// unitkill <unit_id>;
18295 BUILDIN_FUNC(unitkill)
18297 struct block_list* bl;
18299 if(script_rid2bl(2,bl))
18302 return SCRIPT_CMD_SUCCESS;
18305 /// Warps the unit to the target position in the target map.
18306 /// Returns if it was successful.
18308 /// unitwarp(<unit_id>,"<map name>",<x>,<y>) -> <bool>
18309 BUILDIN_FUNC(unitwarp)
18314 struct block_list* bl;
18315 const char *mapname;
18317 mapname = script_getstr(st, 3);
18318 x = (short)script_getnum(st,4);
18319 y = (short)script_getnum(st,5);
18321 if(!script_rid2bl(2,bl))
18323 script_pushint(st, 0);
18324 return SCRIPT_CMD_SUCCESS;
18327 if (!strcmp(mapname,"this"))
18328 map_idx = bl?bl->m:-1;
18330 map_idx = map_mapname2mapid(mapname);
18332 if (map_idx >= 0 && bl != NULL)
18333 script_pushint(st, unit_warp(bl,map_idx,x,y,CLR_OUTSIGHT));
18335 script_pushint(st, 0);
18337 return SCRIPT_CMD_SUCCESS;
18340 /// Makes the unit attack the target.
18341 /// If the unit is a player and <action type> is not 0, it does a continuous
18342 /// attack instead of a single attack.
18343 /// Returns if the request was successful.
18345 /// unitattack(<unit_id>,"<target name>"{,<action type>}) -> <bool>
18346 /// unitattack(<unit_id>,<target_id>{,<action type>}) -> <bool>
18347 BUILDIN_FUNC(unitattack)
18349 struct block_list* unit_bl;
18350 struct block_list* target_bl = NULL;
18351 struct script_data* data;
18352 int actiontype = 0;
18354 if (!script_rid2bl(2,unit_bl)) {
18355 script_pushint(st, false);
18356 return SCRIPT_CMD_FAILURE;
18359 data = script_getdata(st, 3);
18362 if (data_isstring(data)) {
18363 TBL_PC* sd = map_nick2sd(conv_str(st, data),false);
18365 target_bl = &sd->bl;
18367 target_bl = map_id2bl(conv_num(st, data));
18370 script_pushint(st, false);
18371 return SCRIPT_CMD_FAILURE;
18374 if (script_hasdata(st,4))
18375 actiontype = script_getnum(st,4);
18377 switch(unit_bl->type) {
18379 struct map_session_data* sd = (struct map_session_data*)unit_bl;
18381 clif_parse_ActionRequest_sub(sd, actiontype > 0 ? 0x07 : 0x00, target_bl->id, gettick());
18382 script_pushint(st, sd->ud.target == target_bl->id);
18383 return SCRIPT_CMD_SUCCESS;
18386 ((TBL_MOB *)unit_bl)->target_id = target_bl->id;
18389 ((TBL_PET *)unit_bl)->target_id = target_bl->id;
18392 ShowError("buildin_unitattack: Unsupported source unit type %d.\n", unit_bl->type);
18393 script_pushint(st, false);
18394 return SCRIPT_CMD_FAILURE;
18397 script_pushint(st, unit_walktobl(unit_bl, target_bl, 65025, 2));
18398 return SCRIPT_CMD_SUCCESS;
18401 /// Makes the unit stop attacking.
18403 /// unitstopattack <unit_id>;
18404 BUILDIN_FUNC(unitstopattack)
18406 struct block_list* bl;
18408 if(script_rid2bl(2,bl))
18410 unit_stop_attack(bl);
18411 if (bl->type == BL_MOB)
18412 ((TBL_MOB*)bl)->target_id = 0;
18415 return SCRIPT_CMD_SUCCESS;
18418 /// Makes the unit stop walking.
18420 /// unitstopwalk <unit_id>{,<flag>};
18421 BUILDIN_FUNC(unitstopwalk)
18423 struct block_list* bl;
18424 int flag = USW_NONE;
18426 if (script_hasdata(st, 3))
18427 flag = script_getnum(st, 3);
18429 if(script_rid2bl(2,bl))
18430 unit_stop_walking(bl, flag);
18432 return SCRIPT_CMD_SUCCESS;
18436 * Makes the unit say the given message.
18438 * unittalk <unit_id>,"<message>"{,"<flag>"};
18439 * @param flag: Specify target
18440 * bc_area - Message is sent to players in the vicinity of the source (default).
18441 * bc_self - Message is sent only to player attached.
18443 BUILDIN_FUNC(unittalk)
18445 const char* message;
18446 struct block_list* bl;
18448 message = script_getstr(st, 3);
18450 if(script_rid2bl(2,bl))
18452 send_target target = AREA;
18453 struct StringBuf sbuf;
18455 if (script_hasdata(st, 4)) {
18456 if (script_getnum(st, 4) == BC_SELF) {
18457 if (map_id2sd(bl->id) == NULL) {
18458 ShowWarning("script: unittalk: bc_self can't be used for non-players objects.\n");
18459 return SCRIPT_CMD_FAILURE;
18465 StringBuf_Init(&sbuf);
18466 StringBuf_Printf(&sbuf, "%s", message);
18467 clif_disp_overhead_(bl, StringBuf_Value(&sbuf), target);
18468 StringBuf_Destroy(&sbuf);
18471 return SCRIPT_CMD_SUCCESS;
18474 /// Makes the unit do an emotion.
18476 /// unitemote <unit_id>,<emotion>;
18478 /// @see e_* in db/const.txt
18479 BUILDIN_FUNC(unitemote)
18482 struct block_list* bl;
18484 emotion = script_getnum(st,3);
18486 if(script_rid2bl(2,bl))
18487 clif_emotion(bl, emotion);
18489 return SCRIPT_CMD_SUCCESS;
18492 /// Makes the unit cast the skill on the target or self if no target is specified.
18494 /// unitskilluseid <unit_id>,<skill_id>,<skill_lv>{,<target_id>,<casttime>};
18495 /// unitskilluseid <unit_id>,"<skill name>",<skill_lv>{,<target_id>,<casttime>};
18496 BUILDIN_FUNC(unitskilluseid)
18498 int unit_id, target_id, casttime;
18499 uint16 skill_id, skill_lv;
18500 struct block_list* bl;
18501 struct script_data *data;
18503 unit_id = script_getnum(st,2);
18504 data = script_getdata(st, 3);
18505 get_val(st, data); // Convert into value in case of a variable
18506 skill_id = ( data_isstring(data) ? skill_name2id(script_getstr(st,3)) : script_getnum(st,3) );
18507 skill_lv = script_getnum(st,4);
18508 target_id = ( script_hasdata(st,5) ? script_getnum(st,5) : unit_id );
18509 casttime = ( script_hasdata(st,6) ? script_getnum(st,6) : 0 );
18511 if(script_rid2bl(2,bl)){
18512 if (bl->type == BL_NPC) {
18513 if (!((TBL_NPC*)bl)->status.hp)
18514 status_calc_npc(((TBL_NPC*)bl), SCO_FIRST);
18516 status_calc_npc(((TBL_NPC*)bl), SCO_NONE);
18518 unit_skilluse_id2(bl, target_id, skill_id, skill_lv, (casttime * 1000) + skill_castfix(bl, skill_id, skill_lv), skill_get_castcancel(skill_id));
18521 return SCRIPT_CMD_SUCCESS;
18524 /// Makes the unit cast the skill on the target position.
18526 /// unitskillusepos <unit_id>,<skill_id>,<skill_lv>,<target_x>,<target_y>{,<casttime>};
18527 /// unitskillusepos <unit_id>,"<skill name>",<skill_lv>,<target_x>,<target_y>{,<casttime>};
18528 BUILDIN_FUNC(unitskillusepos)
18530 int skill_x, skill_y, casttime;
18531 uint16 skill_id, skill_lv;
18532 struct block_list* bl;
18533 struct script_data *data;
18535 data = script_getdata(st, 3);
18536 get_val(st, data); // Convert into value in case of a variable
18537 skill_id = ( data_isstring(data) ? skill_name2id(script_getstr(st,3)) : script_getnum(st,3) );
18538 skill_lv = script_getnum(st,4);
18539 skill_x = script_getnum(st,5);
18540 skill_y = script_getnum(st,6);
18541 casttime = ( script_hasdata(st,7) ? script_getnum(st,7) : 0 );
18543 if(script_rid2bl(2,bl)){
18544 if (bl->type == BL_NPC) {
18545 if (!((TBL_NPC*)bl)->status.hp)
18546 status_calc_npc(((TBL_NPC*)bl), SCO_FIRST);
18548 status_calc_npc(((TBL_NPC*)bl), SCO_NONE);
18550 unit_skilluse_pos2(bl, skill_x, skill_y, skill_id, skill_lv, (casttime * 1000) + skill_castfix(bl, skill_id, skill_lv), skill_get_castcancel(skill_id));
18553 return SCRIPT_CMD_SUCCESS;
18556 // <--- [zBuffer] List of unit control commands
18558 /// Pauses the execution of the script, detaching the player
18560 /// sleep <mili seconds>;
18561 BUILDIN_FUNC(sleep)
18563 // First call(by function call)
18564 if (st->sleep.tick == 0) {
18567 ticks = script_getnum(st, 2);
18570 ShowError("buildin_sleep2: negative amount('%d') of milli seconds is not supported\n", ticks);
18571 return SCRIPT_CMD_FAILURE;
18574 // detach the player
18575 script_detach_rid(st);
18577 // sleep for the target amount of time
18578 st->state = RERUNLINE;
18579 st->sleep.tick = ticks;
18580 // Second call(by timer after sleeping time is over)
18582 // Continue the script
18584 st->sleep.tick = 0;
18587 return SCRIPT_CMD_SUCCESS;
18590 /// Pauses the execution of the script, keeping the unit attached
18591 /// Stops the script if no unit is attached
18593 /// sleep2(<milli seconds>)
18594 BUILDIN_FUNC(sleep2)
18596 // First call(by function call)
18597 if (st->sleep.tick == 0) {
18600 ticks = script_getnum(st, 2);
18603 ShowError( "buildin_sleep2: negative amount('%d') of milli seconds is not supported\n", ticks );
18604 return SCRIPT_CMD_FAILURE;
18607 if (map_id2bl(st->rid) == NULL) {
18608 ShowError( "buildin_sleep2: no unit is attached\n" );
18609 return SCRIPT_CMD_FAILURE;
18612 // sleep for the target amount of time
18613 st->state = RERUNLINE;
18614 st->sleep.tick = ticks;
18615 // Second call(by timer after sleeping time is over)
18617 // Check if the unit is still attached
18618 // NOTE: This should never happen, since run_script_timer already checks this
18619 if (map_id2bl(st->rid) == NULL) {
18620 // The unit is not attached anymore - terminate the script
18624 // The unit is still attached - continue the script
18626 st->sleep.tick = 0;
18630 return SCRIPT_CMD_SUCCESS;
18633 /// Awakes all the sleep timers of the target npc
18635 /// awake "<npc name>";
18636 BUILDIN_FUNC(awake)
18639 struct script_state *tst;
18640 struct npc_data* nd;
18642 if ((nd = npc_name2id(script_getstr(st, 2))) == NULL) {
18643 ShowError("buildin_awake: NPC \"%s\" not found\n", script_getstr(st, 2));
18644 return SCRIPT_CMD_FAILURE;
18647 iter = db_iterator(st_db);
18649 for (tst = static_cast<script_state *>(dbi_first(iter)); dbi_exists(iter); tst = static_cast<script_state *>(dbi_next(iter))) {
18650 if (tst->oid == nd->bl.id) {
18651 if (tst->sleep.timer == INVALID_TIMER) { // already awake ???
18655 delete_timer(tst->sleep.timer, run_script_timer);
18657 // Trigger the timer function
18658 run_script_timer(INVALID_TIMER, gettick(), tst->sleep.charid, (intptr_t)tst);
18663 return SCRIPT_CMD_SUCCESS;
18666 /// Returns a reference to a variable of the target NPC.
18667 /// Returns 0 if an error occurs.
18669 /// getvariableofnpc(<variable>, "<npc name>") -> <reference>
18670 BUILDIN_FUNC(getvariableofnpc)
18672 struct script_data* data;
18674 struct npc_data* nd;
18676 data = script_getdata(st,2);
18677 if( !data_isreference(data) )
18678 {// Not a reference (aka varaible name)
18679 ShowError("buildin_getvariableofnpc: not a variable\n");
18680 script_reportdata(data);
18681 script_pushnil(st);
18683 return SCRIPT_CMD_FAILURE;
18686 name = reference_getname(data);
18687 if( *name != '.' || name[1] == '@' )
18688 {// not a npc variable
18689 ShowError("buildin_getvariableofnpc: invalid scope (not npc variable)\n");
18690 script_reportdata(data);
18691 script_pushnil(st);
18693 return SCRIPT_CMD_FAILURE;
18696 nd = npc_name2id(script_getstr(st,3));
18697 if( nd == NULL || nd->subtype != NPCTYPE_SCRIPT || nd->u.scr.script == NULL )
18698 {// NPC not found or has no script
18699 ShowError("buildin_getvariableofnpc: can't find npc %s\n", script_getstr(st,3));
18700 script_pushnil(st);
18702 return SCRIPT_CMD_FAILURE;
18705 if (!nd->u.scr.script->local.vars)
18706 nd->u.scr.script->local.vars = i64db_alloc(DB_OPT_RELEASE_DATA);
18708 push_val2(st->stack, C_NAME, reference_getuid(data), &nd->u.scr.script->local);
18709 return SCRIPT_CMD_SUCCESS;
18712 /// Opens a warp portal.
18713 /// Has no "portal opening" effect/sound, it opens the portal immediately.
18715 /// warpportal <source x>,<source y>,"<target map>",<target x>,<target y>;
18717 /// @author blackhole89
18718 BUILDIN_FUNC(warpportal)
18722 unsigned short mapindex;
18725 struct skill_unit_group* group;
18726 struct block_list* bl;
18728 bl = map_id2bl(st->oid);
18730 ShowError("buildin_warpportal: NPC is needed\n");
18731 return SCRIPT_CMD_FAILURE;
18734 spx = script_getnum(st,2);
18735 spy = script_getnum(st,3);
18736 mapindex = mapindex_name2id(script_getstr(st, 4));
18737 tpx = script_getnum(st,5);
18738 tpy = script_getnum(st,6);
18740 if( mapindex == 0 ) {
18741 ShowError("buildin_warpportal: Target map not found %s.\n", script_getstr(st, 4));
18742 return SCRIPT_CMD_FAILURE;
18745 group = skill_unitsetting(bl, AL_WARP, 4, spx, spy, 0);
18746 if( group == NULL )
18747 return SCRIPT_CMD_FAILURE;// failed
18748 group->val1 = (group->val1<<16)|(short)0;
18749 group->val2 = (tpx<<16) | tpy;
18750 group->val3 = mapindex;
18752 return SCRIPT_CMD_SUCCESS;
18756 * openmail({<char_id>});
18758 BUILDIN_FUNC(openmail)
18762 if (!script_charid2sd(2,sd))
18763 return SCRIPT_CMD_FAILURE;
18767 return SCRIPT_CMD_SUCCESS;
18771 * openauction({<char_id>});
18773 BUILDIN_FUNC(openauction)
18777 if (!script_charid2sd(2,sd))
18778 return SCRIPT_CMD_FAILURE;
18780 if( !battle_config.feature_auction ) {
18781 clif_messagecolor(&sd->bl, color_table[COLOR_RED], msg_txt(sd, 517), false, SELF);
18782 return SCRIPT_CMD_SUCCESS;
18785 clif_Auction_openwindow(sd);
18787 return SCRIPT_CMD_SUCCESS;
18790 /// Retrieves the value of the specified flag of the specified cell.
18792 /// checkcell("<map name>",<x>,<y>,<type>) -> <bool>
18794 /// @see cell_chk* constants in const.txt for the types
18795 BUILDIN_FUNC(checkcell)
18797 int16 m = map_mapname2mapid(script_getstr(st,2));
18798 int16 x = script_getnum(st,3);
18799 int16 y = script_getnum(st,4);
18800 cell_chk type = (cell_chk)script_getnum(st,5);
18802 script_pushint(st, map_getcell(m, x, y, type));
18804 return SCRIPT_CMD_SUCCESS;
18807 /// Modifies flags of cells in the specified area.
18809 /// setcell "<map name>",<x1>,<y1>,<x2>,<y2>,<type>,<flag>;
18811 /// @see cell_* constants in const.txt for the types
18812 BUILDIN_FUNC(setcell)
18814 int16 m = map_mapname2mapid(script_getstr(st,2));
18815 int16 x1 = script_getnum(st,3);
18816 int16 y1 = script_getnum(st,4);
18817 int16 x2 = script_getnum(st,5);
18818 int16 y2 = script_getnum(st,6);
18819 cell_t type = (cell_t)script_getnum(st,7);
18820 bool flag = script_getnum(st,8) != 0;
18824 if( x1 > x2 ) SWAP(x1,x2);
18825 if( y1 > y2 ) SWAP(y1,y2);
18827 for( y = y1; y <= y2; ++y )
18828 for( x = x1; x <= x2; ++x )
18829 map_setcell(m, x, y, type, flag);
18831 return SCRIPT_CMD_SUCCESS;
18835 * Gets a free cell in the specified area.
18836 * getfreecell "<map name>",<rX>,<rY>{,<x>,<y>,<rangeX>,<rangeY>,<flag>};
18838 BUILDIN_FUNC(getfreecell)
18840 const char *mapn = script_getstr(st, 2), *name;
18842 struct map_session_data *sd;
18844 int16 m, x = 0, y = 0;
18845 int rx = -1, ry = -1, flag = 1;
18847 sd = map_id2sd(st->rid);
18849 if (!data_isreference(script_getdata(st, 3))) {
18850 ShowWarning("script: buildin_getfreecell: rX is not a variable.\n");
18851 script_pushint(st, -1);
18852 return SCRIPT_CMD_FAILURE;
18855 if (!data_isreference(script_getdata(st, 4))) {
18856 ShowWarning("script: buildin_getfreecell: rY is not a variable.\n");
18857 script_pushint(st, -1);
18858 return SCRIPT_CMD_FAILURE;
18861 if (is_string_variable(reference_getname(script_getdata(st, 3)))) {
18862 ShowWarning("script: buildin_getfreecell: rX is a string, must be an INT.\n");
18863 script_pushint(st, -1);
18864 return SCRIPT_CMD_FAILURE;
18867 if (is_string_variable(reference_getname(script_getdata(st, 4)))) {
18868 ShowWarning("script: buildin_getfreecell: rY is a string, must be an INT.\n");
18869 script_pushint(st, -1);
18870 return SCRIPT_CMD_FAILURE;
18873 if (script_hasdata(st, 5))
18874 x = script_getnum(st, 5);
18876 if (script_hasdata(st, 6))
18877 y = script_getnum(st, 6);
18879 if (script_hasdata(st, 7))
18880 rx = script_getnum(st, 7);
18882 if (script_hasdata(st, 8))
18883 ry = script_getnum(st, 8);
18885 if (script_hasdata(st, 9))
18886 flag = script_getnum(st, 9);
18888 if (sd && strcmp(mapn, "this") == 0)
18891 m = map_mapname2mapid(mapn);
18893 map_search_freecell(NULL, m, &x, &y, rx, ry, flag);
18896 num = st->stack->stack_data[st->start + 3].u.num;
18897 name = get_str(num&0x00ffffff);
18900 if (not_server_variable(prefix)){
18901 if( !script_rid2sd(sd) ){
18902 ShowError( "buildin_getfreecell: variable '%s' for mapX is not a server variable, but no player is attached!", name );
18903 return SCRIPT_CMD_FAILURE;
18908 set_reg(st, sd, num, name, (void*)__64BPRTSIZE((int)x), script_getref(st, 3));
18911 num = st->stack->stack_data[st->start + 4].u.num;
18912 name = get_str(num&0x00ffffff);
18915 if (not_server_variable(prefix)){
18916 if( !script_rid2sd(sd) ){
18917 ShowError( "buildin_getfreecell: variable '%s' for mapY is not a server variable, but no player is attached!", name );
18918 return SCRIPT_CMD_FAILURE;
18923 set_reg(st, sd, num, name, (void*)__64BPRTSIZE((int)y), script_getref(st, 4));
18925 return SCRIPT_CMD_SUCCESS;
18928 /*==========================================
18929 * Mercenary Commands
18930 *------------------------------------------*/
18931 BUILDIN_FUNC(mercenary_create)
18933 struct map_session_data *sd;
18934 int class_, contract_time;
18936 if( !script_rid2sd(sd) || sd->md || sd->status.mer_id != 0 )
18937 return SCRIPT_CMD_SUCCESS;
18939 class_ = script_getnum(st,2);
18941 if( !mercenary_class(class_) )
18942 return SCRIPT_CMD_SUCCESS;
18944 contract_time = script_getnum(st,3);
18945 mercenary_create(sd, class_, contract_time);
18947 return SCRIPT_CMD_SUCCESS;
18950 BUILDIN_FUNC(mercenary_heal)
18952 struct map_session_data *sd;
18955 if( !script_rid2sd(sd) || sd->md == NULL )
18956 return SCRIPT_CMD_SUCCESS;
18957 hp = script_getnum(st,2);
18958 sp = script_getnum(st,3);
18960 status_heal(&sd->md->bl, hp, sp, 0);
18961 return SCRIPT_CMD_SUCCESS;
18964 BUILDIN_FUNC(mercenary_sc_start)
18966 struct map_session_data *sd;
18970 if( !script_rid2sd(sd) || sd->md == NULL )
18971 return SCRIPT_CMD_SUCCESS;
18973 type = (sc_type)script_getnum(st,2);
18974 tick = script_getnum(st,3);
18975 val1 = script_getnum(st,4);
18977 status_change_start(NULL, &sd->md->bl, type, 10000, val1, 0, 0, 0, tick, SCSTART_NOTICKDEF);
18978 return SCRIPT_CMD_SUCCESS;
18981 BUILDIN_FUNC(mercenary_get_calls)
18983 struct map_session_data *sd;
18986 if( !script_rid2sd(sd) )
18987 return SCRIPT_CMD_SUCCESS;
18989 guild = script_getnum(st,2);
18992 case ARCH_MERC_GUILD:
18993 script_pushint(st,sd->status.arch_calls);
18995 case SPEAR_MERC_GUILD:
18996 script_pushint(st,sd->status.spear_calls);
18998 case SWORD_MERC_GUILD:
18999 script_pushint(st,sd->status.sword_calls);
19002 script_pushint(st,0);
19005 return SCRIPT_CMD_SUCCESS;
19008 BUILDIN_FUNC(mercenary_set_calls)
19010 struct map_session_data *sd;
19011 int guild, value, *calls;
19013 if( !script_rid2sd(sd) )
19014 return SCRIPT_CMD_SUCCESS;
19016 guild = script_getnum(st,2);
19017 value = script_getnum(st,3);
19021 case ARCH_MERC_GUILD:
19022 calls = &sd->status.arch_calls;
19024 case SPEAR_MERC_GUILD:
19025 calls = &sd->status.spear_calls;
19027 case SWORD_MERC_GUILD:
19028 calls = &sd->status.sword_calls;
19031 ShowError("buildin_mercenary_set_calls: Invalid guild '%d'.\n", guild);
19032 return SCRIPT_CMD_SUCCESS; // Invalid Guild
19036 *calls = cap_value(*calls, 0, INT_MAX);
19037 return SCRIPT_CMD_SUCCESS;
19040 BUILDIN_FUNC(mercenary_get_faith)
19042 struct map_session_data *sd;
19045 if( !script_rid2sd(sd) )
19046 return SCRIPT_CMD_SUCCESS;
19048 guild = script_getnum(st,2);
19051 case ARCH_MERC_GUILD:
19052 script_pushint(st,sd->status.arch_faith);
19054 case SPEAR_MERC_GUILD:
19055 script_pushint(st,sd->status.spear_faith);
19057 case SWORD_MERC_GUILD:
19058 script_pushint(st,sd->status.sword_faith);
19061 script_pushint(st,0);
19064 return SCRIPT_CMD_SUCCESS;
19067 BUILDIN_FUNC(mercenary_set_faith)
19069 struct map_session_data *sd;
19070 int guild, value, *calls;
19072 if( !script_rid2sd(sd) )
19073 return SCRIPT_CMD_SUCCESS;
19075 guild = script_getnum(st,2);
19076 value = script_getnum(st,3);
19080 case ARCH_MERC_GUILD:
19081 calls = &sd->status.arch_faith;
19083 case SPEAR_MERC_GUILD:
19084 calls = &sd->status.spear_faith;
19086 case SWORD_MERC_GUILD:
19087 calls = &sd->status.sword_faith;
19090 ShowError("buildin_mercenary_set_faith: Invalid guild '%d'.\n", guild);
19091 return SCRIPT_CMD_SUCCESS; // Invalid Guild
19095 *calls = cap_value(*calls, 0, INT_MAX);
19096 if( mercenary_get_guild(sd->md) == guild )
19097 clif_mercenary_updatestatus(sd,SP_MERCFAITH);
19099 return SCRIPT_CMD_SUCCESS;
19102 /*------------------------------------------
19104 *------------------------------------------*/
19105 BUILDIN_FUNC(readbook)
19107 struct map_session_data *sd;
19110 if( !script_rid2sd(sd) )
19111 return SCRIPT_CMD_SUCCESS;
19113 book_id = script_getnum(st,2);
19114 page = script_getnum(st,3);
19116 clif_readbook(sd->fd, book_id, page);
19117 return SCRIPT_CMD_SUCCESS;
19120 /******************
19121 Questlog script commands
19122 *******************/
19124 * Add job criteria to questinfo
19125 * @param qi Quest Info
19129 static void buildin_questinfo_setjob(struct questinfo *qi, int job) {
19130 RECREATE(qi->jobid, unsigned short, qi->jobid_count+1);
19131 qi->jobid[qi->jobid_count++] = job;
19134 * questinfo <Quest ID>,<Icon>{,<Map Mark Color>{,<Job Class>}};
19136 BUILDIN_FUNC(questinfo)
19138 TBL_NPC* nd = map_id2nd(st->oid);
19139 int quest_id, icon, color = 0;
19140 struct questinfo qi, *q2;
19142 if( nd == NULL || nd->bl.m == -1 ) {
19143 ShowError("buildin_questinfo: No NPC attached.\n");
19144 return SCRIPT_CMD_FAILURE;
19147 quest_id = script_getnum(st, 2);
19148 icon = script_getnum(st, 3);
19150 #if PACKETVER >= 20120410
19160 // Leave everything as it is
19164 // Default to nothing if icon id is invalid.
19169 if(icon < QTYPE_QUEST || icon > 7) // TODO: check why 7 and not QTYPE_WARG, might be related to icon + 1 below
19170 icon = QTYPE_QUEST;
19175 qi.quest_id = quest_id;
19176 qi.icon = (unsigned char)icon;
19179 if( script_hasdata(st, 4) ) {
19180 color = script_getnum(st, 4);
19181 if( color < 0 || color > 3 ) {
19182 ShowWarning("buildin_questinfo: invalid color '%d', changing to 0\n",color);
19183 script_reportfunc(st);
19187 qi.color = (unsigned char)color;
19190 qi.max_level = MAX_LEVEL;
19192 q2 = map_add_questinfo(nd->bl.m, &qi);
19196 q2->jobid_count = 0;
19198 if(script_hasdata(st, 5)) {
19199 int job = script_getnum(st, 5);
19201 if (!pcdb_checkid(job))
19202 ShowError("buildin_questinfo: Nonexistant Job Class.\n");
19204 buildin_questinfo_setjob(q2, job);
19208 return SCRIPT_CMD_SUCCESS;
19212 * setquest <ID>{,<char_id>};
19214 BUILDIN_FUNC(setquest)
19216 struct map_session_data *sd;
19219 quest_id = script_getnum(st, 2);
19221 if (!script_charid2sd(3,sd))
19222 return SCRIPT_CMD_FAILURE;
19224 if( quest_add(sd, quest_id) == -1 ){
19225 script_reportsrc(st);
19226 script_reportfunc(st);
19229 //20120410 or 20090218 ? no reason that shouldn't work for 2009
19230 pc_show_questinfo(sd);
19231 return SCRIPT_CMD_SUCCESS;
19235 * erasequest <ID>{,<char_id>};
19237 BUILDIN_FUNC(erasequest)
19239 struct map_session_data *sd;
19241 if (!script_charid2sd(3,sd))
19242 return SCRIPT_CMD_FAILURE;
19244 if( quest_delete(sd, script_getnum(st, 2)) == -1 ){
19245 script_reportsrc(st);
19246 script_reportfunc(st);
19249 return SCRIPT_CMD_SUCCESS;
19253 * completequest <ID>{,<char_id>};
19255 BUILDIN_FUNC(completequest)
19257 struct map_session_data *sd;
19259 if (!script_charid2sd(3,sd))
19260 return SCRIPT_CMD_FAILURE;
19262 quest_update_status(sd, script_getnum(st, 2), Q_COMPLETE);
19263 //20120410 or 20090218
19264 pc_show_questinfo(sd);
19265 return SCRIPT_CMD_SUCCESS;
19269 * changequest <ID>,<ID2>{,<char_id>};
19271 BUILDIN_FUNC(changequest)
19273 struct map_session_data *sd;
19275 if (!script_charid2sd(4,sd))
19276 return SCRIPT_CMD_FAILURE;
19278 if( quest_change(sd, script_getnum(st, 2),script_getnum(st, 3)) == -1 ){
19279 script_reportsrc(st);
19280 script_reportfunc(st);
19283 //20120410 or 20090218
19284 pc_show_questinfo(sd);
19285 return SCRIPT_CMD_SUCCESS;
19289 * checkquest(<ID>{,PLAYTIME|HUNTING{,<char_id>}})
19291 BUILDIN_FUNC(checkquest)
19293 struct map_session_data *sd;
19294 enum quest_check_type type = HAVEQUEST;
19296 if( script_hasdata(st, 3) )
19297 type = (enum quest_check_type)script_getnum(st, 3);
19299 if (!script_charid2sd(4,sd))
19300 return SCRIPT_CMD_FAILURE;
19302 script_pushint(st, quest_check(sd, script_getnum(st, 2), type));
19304 return SCRIPT_CMD_SUCCESS;
19308 * isbegin_quest(<ID>{,<char_id>})
19310 BUILDIN_FUNC(isbegin_quest)
19312 struct map_session_data *sd;
19315 if (!script_charid2sd(3,sd))
19316 return SCRIPT_CMD_FAILURE;
19318 i = quest_check(sd, script_getnum(st, 2), (enum quest_check_type) HAVEQUEST);
19319 script_pushint(st, i + (i < 1));
19321 return SCRIPT_CMD_SUCCESS;
19325 * showevent <icon>{,<mark color>{,<char_id>}}
19327 BUILDIN_FUNC(showevent)
19330 struct npc_data *nd = map_id2nd(st->oid);
19331 int icon, color = 0;
19333 if (!script_charid2sd(4,sd))
19334 return SCRIPT_CMD_FAILURE;
19336 if( sd == NULL || nd == NULL )
19337 return SCRIPT_CMD_SUCCESS;
19339 icon = script_getnum(st, 2);
19340 if( script_hasdata(st, 3) ) {
19341 color = script_getnum(st, 3);
19342 if( color < 0 || color > 3 ) {
19343 ShowWarning("buildin_showevent: invalid color '%d', changing to 0\n",color);
19344 script_reportfunc(st);
19349 #if PACKETVER >= 20120410
19350 if(icon < 0 || (icon > 8 && icon != 9999) || icon == 7)
19351 icon = 9999; // Default to nothing if icon id is invalid.
19353 if(icon < 0 || icon > 7)
19359 clif_quest_show_event(sd, &nd->bl, icon, color);
19360 return SCRIPT_CMD_SUCCESS;
19363 /*==========================================
19364 * BattleGround System
19365 *------------------------------------------*/
19366 BUILDIN_FUNC(waitingroom2bg)
19368 struct npc_data *nd;
19369 struct chat_data *cd;
19370 const char *map_name, *ev = "", *dev = "";
19371 int x, y, mapindex = 0, bg_id;
19372 unsigned char i,c=0;
19374 if( script_hasdata(st,7) )
19375 nd = npc_name2id(script_getstr(st,7));
19377 nd = (struct npc_data *)map_id2bl(st->oid);
19379 if( nd == NULL || (cd = (struct chat_data *)map_id2bl(nd->chat_id)) == NULL )
19381 script_pushint(st,0);
19382 return SCRIPT_CMD_SUCCESS;
19385 map_name = script_getstr(st,2);
19386 if (strcmp(map_name, "-") != 0 && (mapindex = mapindex_name2id(map_name)) == 0)
19388 script_pushint(st, 0);
19389 return SCRIPT_CMD_SUCCESS;
19392 x = script_getnum(st,3);
19393 y = script_getnum(st,4);
19394 if(script_hasdata(st,5))
19395 ev = script_getstr(st,5); // Logout Event
19396 if(script_hasdata(st,6))
19397 dev = script_getstr(st,6); // Die Event
19399 check_event(st, ev);
19400 check_event(st, dev);
19402 if( (bg_id = bg_create(mapindex, x, y, ev, dev)) == 0 )
19403 { // Creation failed
19404 script_pushint(st,0);
19405 return SCRIPT_CMD_SUCCESS;
19408 for (i = 0; i < cd->users; i++) { // Only add those who are in the chat room
19409 struct map_session_data *sd;
19410 if( (sd = cd->usersd[i]) != NULL && bg_team_join(bg_id, sd) ){
19411 mapreg_setreg(reference_uid(add_str("$@arenamembers"), c), sd->bl.id);
19416 mapreg_setreg(add_str("$@arenamembersnum"), c);
19417 script_pushint(st,bg_id);
19418 return SCRIPT_CMD_SUCCESS;
19421 BUILDIN_FUNC(waitingroom2bg_single)
19423 const char* map_name;
19424 struct npc_data *nd;
19425 struct chat_data *cd;
19426 struct map_session_data *sd;
19427 struct battleground_data *bg;
19428 int x, y, mapindex, bg_id;
19430 bg_id = script_getnum(st,2);
19431 if ((bg = bg_team_search(bg_id)) == NULL) {
19432 script_pushint(st, false);
19433 return SCRIPT_CMD_SUCCESS;
19435 if (script_hasdata(st, 3)) {
19436 map_name = script_getstr(st, 3);
19437 if ((mapindex = mapindex_name2id(map_name)) == 0) {
19438 script_pushint(st, false);
19439 return SCRIPT_CMD_SUCCESS; // Invalid Map
19441 x = script_getnum(st, 4);
19442 y = script_getnum(st, 5);
19445 mapindex = bg->mapindex;
19450 nd = npc_name2id(script_getstr(st,6));
19452 if( nd == NULL || (cd = (struct chat_data *)map_id2bl(nd->chat_id)) == NULL || cd->users <= 0 )
19453 return SCRIPT_CMD_SUCCESS;
19455 if( (sd = cd->usersd[0]) == NULL )
19456 return SCRIPT_CMD_SUCCESS;
19458 if( bg_team_join(bg_id, sd) && pc_setpos(sd, mapindex, x, y, CLR_TELEPORT) == SETPOS_OK)
19460 script_pushint(st, true);
19463 script_pushint(st, false);
19465 return SCRIPT_CMD_SUCCESS;
19469 /// Creates an instance of battleground battle group.
19470 /// *bg_create("<map name>",<x>,<y>{,"<On Quit Event>","<On Death Event>"});
19471 /// @author [secretdataz]
19472 BUILDIN_FUNC(bg_create) {
19473 const char *map_name, *ev = "", *dev = "";
19474 int x, y, mapindex = 0;
19476 map_name = script_getstr(st, 2);
19477 if (strcmp(map_name, "-") != 0 && (mapindex = mapindex_name2id(map_name)) == 0)
19479 script_pushint(st, 0);
19480 return SCRIPT_CMD_SUCCESS;
19483 x = script_getnum(st, 3);
19484 y = script_getnum(st, 4);
19485 if(script_hasdata(st, 5))
19486 ev = script_getstr(st, 5); // Logout Event
19487 if(script_hasdata(st, 6))
19488 dev = script_getstr(st, 6); // Die Event
19490 check_event(st, ev);
19491 check_event(st, dev);
19493 script_pushint(st, bg_create(mapindex, x, y, ev, dev));
19494 return SCRIPT_CMD_SUCCESS;
19497 /// Adds attached player or <char id> (if specified) to an existing
19498 /// battleground group and warps it to the specified coordinates on
19500 /// bg_join(<battle group>,{"<map name>",<x>,<y>{,<char id>}});
19501 /// @author [secretdataz]
19502 BUILDIN_FUNC(bg_join) {
19503 const char* map_name;
19504 struct map_session_data *sd;
19505 struct battleground_data *bg;
19506 int x, y, bg_id, mapindex;
19508 bg_id = script_getnum(st, 2);
19509 if ((bg = bg_team_search(bg_id)) == NULL) {
19510 script_pushint(st, false);
19511 return SCRIPT_CMD_SUCCESS;
19513 if (script_hasdata(st, 3)) {
19514 map_name = script_getstr(st, 3);
19515 if ((mapindex = mapindex_name2id(map_name)) == 0) {
19516 script_pushint(st, false);
19517 return SCRIPT_CMD_SUCCESS; // Invalid Map
19519 x = script_getnum(st, 4);
19520 y = script_getnum(st, 5);
19522 mapindex = bg->mapindex;
19527 if (!script_charid2sd(6, sd)) {
19528 script_pushint(st, false);
19529 return SCRIPT_CMD_FAILURE;
19532 if (bg_team_join(bg_id, sd) && pc_setpos(sd, mapindex, x, y, CLR_TELEPORT) == SETPOS_OK)
19534 script_pushint(st, true);
19537 script_pushint(st, false);
19539 return SCRIPT_CMD_SUCCESS;
19542 BUILDIN_FUNC(bg_team_setxy)
19544 struct battleground_data *bg;
19547 bg_id = script_getnum(st,2);
19548 if( (bg = bg_team_search(bg_id)) == NULL )
19549 return SCRIPT_CMD_SUCCESS;
19551 bg->x = script_getnum(st,3);
19552 bg->y = script_getnum(st,4);
19553 return SCRIPT_CMD_SUCCESS;
19556 BUILDIN_FUNC(bg_warp)
19558 int x, y, mapindex, bg_id;
19559 const char* map_name;
19561 bg_id = script_getnum(st,2);
19562 map_name = script_getstr(st,3);
19563 if( (mapindex = mapindex_name2id(map_name)) == 0 )
19564 return SCRIPT_CMD_SUCCESS; // Invalid Map
19565 x = script_getnum(st,4);
19566 y = script_getnum(st,5);
19567 bg_team_warp(bg_id, mapindex, x, y);
19568 return SCRIPT_CMD_SUCCESS;
19571 BUILDIN_FUNC(bg_monster)
19573 int class_ = 0, x = 0, y = 0, bg_id = 0;
19574 const char *str,*mapname, *evt="";
19576 bg_id = script_getnum(st,2);
19577 mapname = script_getstr(st,3);
19578 x = script_getnum(st,4);
19579 y = script_getnum(st,5);
19580 str = script_getstr(st,6);
19581 class_ = script_getnum(st,7);
19582 if( script_hasdata(st,8) ) evt = script_getstr(st,8);
19583 check_event(st, evt);
19584 script_pushint(st, mob_spawn_bg(mapname,x,y,str,class_,evt,bg_id));
19585 return SCRIPT_CMD_SUCCESS;
19588 BUILDIN_FUNC(bg_monster_set_team)
19590 struct mob_data *md;
19591 struct block_list *mbl;
19592 int id = script_getnum(st,2),
19593 bg_id = script_getnum(st,3);
19595 if( id == 0 || (mbl = map_id2bl(id)) == NULL || mbl->type != BL_MOB )
19596 return SCRIPT_CMD_SUCCESS;
19597 md = (TBL_MOB *)mbl;
19600 mob_stop_attack(md);
19601 mob_stop_walking(md, 0);
19602 md->target_id = md->attacked_id = 0;
19603 clif_name_area(&md->bl);
19605 return SCRIPT_CMD_SUCCESS;
19608 BUILDIN_FUNC(bg_leave)
19610 struct map_session_data *sd = NULL;
19611 if( !script_charid2sd(2,sd) || !sd->bg_id )
19612 return SCRIPT_CMD_SUCCESS;
19614 bg_team_leave(sd,0);
19615 return SCRIPT_CMD_SUCCESS;
19618 BUILDIN_FUNC(bg_destroy)
19620 int bg_id = script_getnum(st,2);
19621 bg_team_delete(bg_id);
19622 return SCRIPT_CMD_SUCCESS;
19625 BUILDIN_FUNC(bg_getareausers)
19628 int16 m, x0, y0, x1, y1;
19631 struct battleground_data *bg = NULL;
19633 bg_id = script_getnum(st,2);
19634 str = script_getstr(st,3);
19636 if( (bg = bg_team_search(bg_id)) == NULL || (m = map_mapname2mapid(str)) < 0 )
19638 script_pushint(st,0);
19639 return SCRIPT_CMD_SUCCESS;
19642 x0 = script_getnum(st,4);
19643 y0 = script_getnum(st,5);
19644 x1 = script_getnum(st,6);
19645 y1 = script_getnum(st,7);
19647 for( i = 0; i < MAX_BG_MEMBERS; i++ )
19649 struct map_session_data *sd;
19650 if( (sd = bg->members[i].sd) == NULL )
19652 if( sd->bl.m != m || sd->bl.x < x0 || sd->bl.y < y0 || sd->bl.x > x1 || sd->bl.y > y1 )
19657 script_pushint(st,c);
19658 return SCRIPT_CMD_SUCCESS;
19661 BUILDIN_FUNC(bg_updatescore)
19666 str = script_getstr(st,2);
19667 if( (m = map_mapname2mapid(str)) < 0 )
19668 return SCRIPT_CMD_SUCCESS;
19670 map[m].bgscore_lion = script_getnum(st,3);
19671 map[m].bgscore_eagle = script_getnum(st,4);
19673 clif_bg_updatescore(m);
19674 return SCRIPT_CMD_SUCCESS;
19677 BUILDIN_FUNC(bg_get_data)
19679 struct battleground_data *bg;
19680 int bg_id = script_getnum(st,2),
19681 type = script_getnum(st,3), i;
19683 if( (bg = bg_team_search(bg_id)) == NULL )
19685 script_pushint(st,0);
19686 return SCRIPT_CMD_SUCCESS;
19691 case 0: script_pushint(st, bg->count); break;
19693 for (i = 0; bg->members[i].sd != NULL; i++)
19694 mapreg_setreg(reference_uid(add_str("$@arenamembers"), i), bg->members[i].sd->bl.id);
19695 mapreg_setreg(add_str("$@arenamemberscount"), i);
19696 script_pushint(st, i);
19699 ShowError("script:bg_get_data: unknown data identifier %d\n", type);
19703 return SCRIPT_CMD_SUCCESS;
19706 /*==========================================
19707 * Instancing System
19708 *------------------------------------------*/
19709 //Returns an Instance ID
19710 //Checks NPC first, then if player is attached we check
19711 unsigned short script_instancegetid(struct script_state* st)
19713 unsigned short instance_id = 0;
19714 struct npc_data *nd;
19716 if( (nd = map_id2nd(st->oid)) && nd->instance_id > 0 )
19717 instance_id = nd->instance_id;
19719 struct map_session_data *sd = NULL;
19720 struct party_data *pd = NULL;
19721 struct guild *gd = NULL;
19722 struct clan *cd = NULL;
19724 if ((sd = map_id2sd(st->rid))) {
19725 if (sd->instance_id)
19726 instance_id = sd->instance_id;
19727 if (instance_id == 0 && sd->status.party_id && (pd = party_search(sd->status.party_id)) != NULL && pd->instance_id)
19728 instance_id = pd->instance_id;
19729 if (instance_id == 0 && sd->status.guild_id && (gd = guild_search(sd->status.guild_id)) != NULL && gd->instance_id)
19730 instance_id = gd->instance_id;
19731 if (instance_id == 0 && sd->status.clan_id && (cd = clan_search(sd->status.clan_id)) != NULL && cd->instance_id)
19732 instance_id = cd->instance_id;
19736 return instance_id;
19739 /*==========================================
19740 * Creates the instance
19741 * Returns Instance ID if created successfully
19742 *------------------------------------------*/
19743 BUILDIN_FUNC(instance_create)
19745 enum instance_mode mode = IM_PARTY;
19748 if (script_hasdata(st, 3)) {
19749 mode = static_cast<instance_mode>(script_getnum(st, 3));
19751 if (mode < IM_NONE || mode >= IM_MAX) {
19752 ShowError("buildin_instance_create: Unknown instance mode %d for '%s'\n", mode, script_getstr(st, 2));
19753 return SCRIPT_CMD_FAILURE;
19756 if (script_hasdata(st, 4))
19757 owner_id = script_getnum(st, 4);
19759 // If sd is NULL, instance_create will return -2.
19760 struct map_session_data *sd = NULL;
19764 owner_id = st->oid;
19767 if (script_rid2sd(sd))
19768 owner_id = sd->status.char_id;
19771 if (script_rid2sd(sd))
19772 owner_id = sd->status.party_id;
19775 if (script_rid2sd(sd))
19776 owner_id = sd->status.guild_id;
19779 if (script_rid2sd(sd))
19780 owner_id = sd->status.clan_id;
19783 ShowError("buildin_instance_create: Invalid instance mode (instance name: %s)\n", script_getstr(st, 2));
19784 return SCRIPT_CMD_FAILURE;
19788 script_pushint(st, instance_create(owner_id, script_getstr(st, 2), mode));
19789 return SCRIPT_CMD_SUCCESS;
19792 /*==========================================
19793 * Destroys an instance (unofficial)
19794 * Officially instances are only destroyed by timeout
19796 * instance_destroy {<instance_id>};
19797 *------------------------------------------*/
19798 BUILDIN_FUNC(instance_destroy)
19800 unsigned short instance_id;
19802 if( script_hasdata(st,2) )
19803 instance_id = script_getnum(st,2);
19805 instance_id = script_instancegetid(st);
19807 if( instance_id == 0 || instance_id >= MAX_MAP_PER_SERVER ) {
19808 ShowError("buildin_instance_destroy: Trying to destroy invalid instance %hu.\n", instance_id);
19809 return SCRIPT_CMD_FAILURE;
19812 instance_destroy(instance_id);
19813 return SCRIPT_CMD_SUCCESS;
19816 /*==========================================
19817 * Warps player to instance
19820 * IE_NOMEMBER: Character not in party/guild (for party/guild type instances)
19821 * IE_NOINSTANCE: Character/Party/Guild doesn't have instance
19822 * IE_OTHER: Other errors (instance not in DB, instance doesn't match with character/party/guild, etc.)
19823 *------------------------------------------*/
19824 BUILDIN_FUNC(instance_enter)
19826 struct map_session_data *sd = NULL;
19827 int x = script_hasdata(st,3) ? script_getnum(st, 3) : -1;
19828 int y = script_hasdata(st,4) ? script_getnum(st, 4) : -1;
19829 unsigned short instance_id;
19831 if (script_hasdata(st, 6))
19832 instance_id = script_getnum(st, 6);
19834 instance_id = script_instancegetid(st);
19836 if (!script_charid2sd(5,sd))
19837 return SCRIPT_CMD_FAILURE;
19839 script_pushint(st, instance_enter(sd, instance_id, script_getstr(st, 2), x, y));
19841 return SCRIPT_CMD_SUCCESS;
19844 /*==========================================
19845 * Returns the name of a duplicated NPC
19847 * instance_npcname <npc_name>{,<instance_id>};
19848 * <npc_name> is the full name of an NPC.
19849 *------------------------------------------*/
19850 BUILDIN_FUNC(instance_npcname)
19853 unsigned short instance_id = 0;
19854 struct npc_data *nd;
19856 str = script_getstr(st,2);
19857 if( script_hasdata(st,3) )
19858 instance_id = script_getnum(st,3);
19860 instance_id = script_instancegetid(st);
19862 if( instance_id && (nd = npc_name2id(str)) != NULL ) {
19863 static char npcname[NAME_LENGTH];
19864 snprintf(npcname, sizeof(npcname), "dup_%hu_%d", instance_id, nd->bl.id);
19865 script_pushconststr(st,npcname);
19867 ShowError("buildin_instance_npcname: Invalid instance NPC (instance_id: %hu, NPC name: \"%s\".)\n", instance_id, str);
19869 return SCRIPT_CMD_FAILURE;
19872 return SCRIPT_CMD_SUCCESS;
19875 /*==========================================
19876 * Returns the name of a duplicated map
19878 * instance_mapname <map_name>{,<instance_id>};
19879 *------------------------------------------*/
19880 BUILDIN_FUNC(instance_mapname)
19884 unsigned short instance_id = 0;
19886 str = script_getstr(st,2);
19888 if( script_hasdata(st,3) )
19889 instance_id = script_getnum(st,3);
19891 instance_id = script_instancegetid(st);
19893 // Check that instance mapname is a valid map
19894 if(!instance_id || (m = instance_mapname2mapid(str,instance_id)) < 0)
19895 script_pushconststr(st, "");
19897 script_pushconststr(st, map[m].name);
19899 return SCRIPT_CMD_SUCCESS;
19902 /*==========================================
19903 * Returns an Instance ID
19904 *------------------------------------------*/
19905 BUILDIN_FUNC(instance_id)
19907 script_pushint(st, script_instancegetid(st));
19908 return SCRIPT_CMD_SUCCESS;
19911 /*==========================================
19912 * Warps all players inside an instance
19914 * instance_warpall <map_name>,<x>,<y>{,<instance_id>};
19915 *------------------------------------------*/
19916 static int buildin_instance_warpall_sub(struct block_list *bl, va_list ap)
19918 unsigned int m = va_arg(ap,unsigned int);
19919 int x = va_arg(ap,int);
19920 int y = va_arg(ap,int);
19921 unsigned short instance_id = va_arg(ap,unsigned int);
19922 struct map_session_data *sd = NULL;
19925 nullpo_retr(0, bl);
19927 if (bl->type != BL_PC)
19931 owner_id = instance_data[instance_id].owner_id;
19932 switch(instance_data[instance_id].mode) {
19936 if (sd->status.char_id != owner_id)
19940 if (sd->status.party_id != owner_id)
19944 if (sd->status.guild_id != owner_id)
19947 if (sd->status.clan_id != owner_id)
19951 pc_setpos(sd, m, x, y, CLR_TELEPORT);
19956 BUILDIN_FUNC(instance_warpall)
19959 unsigned short instance_id;
19963 mapn = script_getstr(st,2);
19964 x = script_getnum(st,3);
19965 y = script_getnum(st,4);
19966 if( script_hasdata(st,5) )
19967 instance_id = script_getnum(st,5);
19969 instance_id = script_instancegetid(st);
19971 if( !instance_id || (m = map_mapname2mapid(mapn)) < 0 || (m = instance_mapname2mapid(map[m].name,instance_id)) < 0)
19972 return SCRIPT_CMD_FAILURE;
19974 for(i = 0; i < instance_data[instance_id].cnt_map; i++)
19975 map_foreachinmap(buildin_instance_warpall_sub, instance_data[instance_id].map[i]->m, BL_PC, map_id2index(m), x, y, instance_id);
19977 return SCRIPT_CMD_SUCCESS;
19980 /*==========================================
19981 * Broadcasts to all maps inside an instance
19983 * instance_announce <instance id>,"<text>",<flag>{,<fontColor>{,<fontType>{,<fontSize>{,<fontAlign>{,<fontY>}}}}};
19984 * Using 0 for <instance id> will auto-detect the id.
19985 *------------------------------------------*/
19986 BUILDIN_FUNC(instance_announce) {
19987 unsigned short instance_id = script_getnum(st,2);
19988 const char *mes = script_getstr(st,3);
19989 int flag = script_getnum(st,4);
19990 const char *fontColor = script_hasdata(st,5) ? script_getstr(st,5) : NULL;
19991 int fontType = script_hasdata(st,6) ? script_getnum(st,6) : FW_NORMAL; // default fontType
19992 int fontSize = script_hasdata(st,7) ? script_getnum(st,7) : 12; // default fontSize
19993 int fontAlign = script_hasdata(st,8) ? script_getnum(st,8) : 0; // default fontAlign
19994 int fontY = script_hasdata(st,9) ? script_getnum(st,9) : 0; // default fontY
19997 if( instance_id == 0 ) {
19998 instance_id = script_instancegetid(st);
20001 if( !instance_id && &instance_data[instance_id] != NULL) {
20002 ShowError("buildin_instance_announce: Intance is not found.\n");
20003 return SCRIPT_CMD_FAILURE;
20006 for( i = 0; i < instance_data[instance_id].cnt_map; i++ )
20007 map_foreachinmap(buildin_announce_sub, instance_data[instance_id].map[i]->m, BL_PC,
20008 mes, strlen(mes)+1, flag&BC_COLOR_MASK, fontColor, fontType, fontSize, fontAlign, fontY);
20010 return SCRIPT_CMD_SUCCESS;
20013 /*==========================================
20014 * instance_check_party [malufett]
20016 * party_id : Party ID of the invoking character. [Required Parameter]
20017 * amount : Amount of needed Partymembers for the Instance. [Optional Parameter]
20018 * min : Minimum Level needed to join the Instance. [Optional Parameter]
20019 * max : Maxium Level allowed to join the Instance. [Optional Parameter]
20020 * Example: instance_check_party (getcharid(1){,amount}{,min}{,max});
20021 * Example 2: instance_check_party (getcharid(1),1,1,99);
20022 *------------------------------------------*/
20023 BUILDIN_FUNC(instance_check_party)
20025 int amount, min, max, i, party_id, c = 0;
20026 struct party_data *p = NULL;
20028 amount = script_hasdata(st,3) ? script_getnum(st,3) : 1; // Amount of needed Partymembers for the Instance.
20029 min = script_hasdata(st,4) ? script_getnum(st,4) : 1; // Minimum Level needed to join the Instance.
20030 max = script_hasdata(st,5) ? script_getnum(st,5) : MAX_LEVEL; // Maxium Level allowed to join the Instance.
20032 if( min < 1 || min > MAX_LEVEL) {
20033 ShowError("buildin_instance_check_party: Invalid min level, %d\n", min);
20034 return SCRIPT_CMD_FAILURE;
20035 } else if( max < 1 || max > MAX_LEVEL) {
20036 ShowError("buildin_instance_check_party: Invalid max level, %d\n", max);
20037 return SCRIPT_CMD_FAILURE;
20040 if( script_hasdata(st,2) )
20041 party_id = script_getnum(st,2);
20042 else return SCRIPT_CMD_FAILURE;
20044 if( !(p = party_search(party_id)) ) {
20045 script_pushint(st, 0); // Returns false if party does not exist.
20046 return SCRIPT_CMD_FAILURE;
20049 for( i = 0; i < MAX_PARTY; i++ ) {
20050 struct map_session_data *pl_sd;
20051 if( (pl_sd = p->data[i].sd) )
20052 if(map_id2bl(pl_sd->bl.id)) {
20053 if(pl_sd->status.base_level < min) {
20054 script_pushint(st, 0);
20055 return SCRIPT_CMD_SUCCESS;
20056 } else if(pl_sd->status.base_level > max) {
20057 script_pushint(st, 0);
20058 return SCRIPT_CMD_SUCCESS;
20065 script_pushint(st, 0); // Not enough Members in the Party to join Instance.
20067 script_pushint(st, 1);
20069 return SCRIPT_CMD_SUCCESS;
20072 /*==========================================
20073 * instance_check_guild
20075 * guild_id : Guild ID of the invoking character. [Required Parameter]
20076 * amount : Amount of needed Guild members for the Instance. [Optional Parameter]
20077 * min : Minimum Level needed to join the Instance. [Optional Parameter]
20078 * max : Maxium Level allowed to join the Instance. [Optional Parameter]
20079 * Example: instance_check_guild (getcharid(2){,amount}{,min}{,max});
20080 * Example 2: instance_check_guild (getcharid(2),1,1,99);
20081 *------------------------------------------*/
20082 BUILDIN_FUNC(instance_check_guild)
20084 int amount, min, max, i, guild_id = 0, c = 0;
20085 struct guild *g = NULL;
20087 amount = script_hasdata(st,3) ? script_getnum(st,3) : 1; // Amount of needed Guild members for the Instance.
20088 min = script_hasdata(st,4) ? script_getnum(st,4) : 1; // Minimum Level needed to join the Instance.
20089 max = script_hasdata(st,5) ? script_getnum(st,5) : MAX_LEVEL; // Maxium Level allowed to join the Instance.
20091 if (min < 1 || min > MAX_LEVEL) {
20092 ShowError("buildin_instance_check_guild: Invalid min level, %d\n", min);
20093 return SCRIPT_CMD_FAILURE;
20094 } else if (max < 1 || max > MAX_LEVEL) {
20095 ShowError("buildin_instance_check_guild: Invalid max level, %d\n", max);
20096 return SCRIPT_CMD_FAILURE;
20099 if (script_hasdata(st,2))
20100 guild_id = script_getnum(st,2);
20102 return SCRIPT_CMD_FAILURE;
20104 if (!(g = guild_search(guild_id))) {
20105 script_pushint(st, 0); // Returns false if guild does not exist.
20106 return SCRIPT_CMD_FAILURE;
20109 for(i = 0; i < MAX_GUILD; i++) {
20110 struct map_session_data *pl_sd;
20112 if ((pl_sd = g->member[i].sd)) {
20113 if (map_id2bl(pl_sd->bl.id)) {
20114 if (pl_sd->status.base_level < min) {
20115 script_pushint(st, 0);
20116 return SCRIPT_CMD_SUCCESS;
20117 } else if (pl_sd->status.base_level > max) {
20118 script_pushint(st, 0);
20119 return SCRIPT_CMD_SUCCESS;
20127 script_pushint(st, 0); // Not enough Members in the Guild to join Instance.
20129 script_pushint(st, 1);
20131 return SCRIPT_CMD_SUCCESS;
20134 /*==========================================
20135 * instance_check_clan
20137 * clan_id : Clan ID of the invoking character. [Required Parameter]
20138 * amount : Amount of needed Clan members for the Instance. [Optional Parameter]
20139 * min : Minimum Level needed to join the Instance. [Optional Parameter]
20140 * max : Maxium Level allowed to join the Instance. [Optional Parameter]
20141 * Example: instance_check_clan (getcharid(5){,amount}{,min}{,max});
20142 * Example 2: instance_check_clan (getcharid(5),1,1,99);
20143 *------------------------------------------*/
20144 BUILDIN_FUNC(instance_check_clan)
20146 int amount, min, max, i, clan_id = 0, c = 0;
20147 struct clan *cd = NULL;
20149 amount = script_hasdata(st,3) ? script_getnum(st,3) : 1; // Amount of needed Clan members for the Instance.
20150 min = script_hasdata(st,4) ? script_getnum(st,4) : 1; // Minimum Level needed to join the Instance.
20151 max = script_hasdata(st,5) ? script_getnum(st,5) : MAX_LEVEL; // Maxium Level allowed to join the Instance.
20153 if (min < 1 || min > MAX_LEVEL) {
20154 ShowError("buildin_instance_check_clan: Invalid min level, %d\n", min);
20155 return SCRIPT_CMD_FAILURE;
20156 } else if (max < 1 || max > MAX_LEVEL) {
20157 ShowError("buildin_instance_check_clan: Invalid max level, %d\n", max);
20158 return SCRIPT_CMD_FAILURE;
20161 if (script_hasdata(st,2))
20162 clan_id = script_getnum(st,2);
20164 return SCRIPT_CMD_FAILURE;
20166 if (!(cd = clan_search(clan_id))) {
20167 script_pushint(st, 0); // Returns false if clan does not exist.
20168 return SCRIPT_CMD_FAILURE;
20171 for(i = 0; i < MAX_CLAN; i++) {
20172 struct map_session_data *pl_sd;
20174 if ((pl_sd = cd->members[i])) {
20175 if (map_id2bl(pl_sd->bl.id)) {
20176 if (pl_sd->status.base_level < min) {
20177 script_pushint(st, 0);
20178 return SCRIPT_CMD_SUCCESS;
20179 } else if (pl_sd->status.base_level > max) {
20180 script_pushint(st, 0);
20181 return SCRIPT_CMD_SUCCESS;
20189 script_pushint(st, 0); // Not enough Members in the Clan to join Instance.
20191 script_pushint(st, 1);
20193 return SCRIPT_CMD_SUCCESS;
20196 /*==========================================
20199 * name : name of the instance you want to look up. [Required Parameter]
20200 * type : type of information you want to look up for the specified instance. [Required Parameter]
20201 * index : index of the map in the instance. [Optional Parameter]
20202 *------------------------------------------*/
20203 BUILDIN_FUNC(instance_info)
20205 const char* name = script_getstr(st, 2);
20206 int type = script_getnum(st, 3);
20208 struct instance_db *db = instance_searchname_db(name);
20211 ShowError( "buildin_instance_info: Unknown instance name \"%s\".\n", name );
20212 script_pushint(st, -1);
20213 return SCRIPT_CMD_FAILURE;
20218 script_pushint(st, db->id);
20220 case IIT_TIME_LIMIT:
20221 script_pushint(st, db->limit);
20223 case IIT_IDLE_TIMEOUT:
20224 script_pushint(st, db->timeout);
20226 case IIT_ENTER_MAP:
20227 script_pushstrcopy(st, StringBuf_Value(db->enter.mapname));
20230 script_pushint(st, db->enter.x);
20233 script_pushint(st, db->enter.y);
20236 script_pushint(st, db->maplist_count);
20239 if( !script_hasdata(st, 4) || script_isstring(st, 4) ){
20240 ShowError( "buildin_instance_info: Type IIT_MAP requires a numeric index argument.\n" );
20241 script_pushconststr(st, "");
20242 return SCRIPT_CMD_FAILURE;
20245 index = script_getnum(st, 4);
20248 ShowError( "buildin_instance_info: Type IIT_MAP does not support a negative index argument.\n" );
20249 script_pushconststr(st, "");
20250 return SCRIPT_CMD_FAILURE;
20253 if( index > UINT8_MAX ){
20254 ShowError( "buildin_instance_info: Type IIT_MAP does only support up to index %hu.\n", UINT8_MAX );
20255 script_pushconststr(st, "");
20256 return SCRIPT_CMD_FAILURE;
20259 script_pushstrcopy(st, StringBuf_Value(db->maplist[index]));
20263 ShowError("buildin_instance_info: Unknown instance information type \"%d\".\n", type );
20264 script_pushint(st, -1);
20265 return SCRIPT_CMD_FAILURE;
20268 return SCRIPT_CMD_SUCCESS;
20271 /*==========================================
20273 *------------------------------------------*/
20274 BUILDIN_FUNC(setfont)
20276 struct map_session_data *sd;
20279 if( !script_rid2sd(sd) )
20280 return SCRIPT_CMD_SUCCESS;
20282 font = script_getnum(st,2);
20284 if( sd->status.font != font )
20285 sd->status.font = font;
20287 sd->status.font = 0;
20290 return SCRIPT_CMD_SUCCESS;
20293 static int buildin_mobuseskill_sub(struct block_list *bl,va_list ap)
20295 TBL_MOB* md = (TBL_MOB*)bl;
20296 struct block_list *tbl;
20297 int mobid = va_arg(ap,int);
20298 uint16 skill_id = va_arg(ap,int);
20299 uint16 skill_lv = va_arg(ap,int);
20300 int casttime = va_arg(ap,int);
20301 int cancel = va_arg(ap,int);
20302 int emotion = va_arg(ap,int);
20303 int target = va_arg(ap,int);
20305 if( md->mob_id != mobid )
20308 // 0:self, 1:target, 2:master, default:random
20310 case 0: tbl = map_id2bl(md->bl.id); break;
20311 case 1: tbl = map_id2bl(md->target_id); break;
20312 case 2: tbl = map_id2bl(md->master_id); break;
20313 default:tbl = battle_getenemy(&md->bl, DEFAULT_ENEMY_TYPE(md), skill_get_range2(&md->bl, skill_id, skill_lv, true)); break;
20319 if( md->ud.skilltimer != INVALID_TIMER ) // Cancel the casting skill.
20320 unit_skillcastcancel(bl,0);
20322 if( skill_get_casttype(skill_id) == CAST_GROUND )
20323 unit_skilluse_pos2(&md->bl, tbl->x, tbl->y, skill_id, skill_lv, casttime, cancel);
20325 unit_skilluse_id2(&md->bl, tbl->id, skill_id, skill_lv, casttime, cancel);
20327 clif_emotion(&md->bl, emotion);
20332 /*==========================================
20333 * areamobuseskill "Map Name",<x>,<y>,<range>,<Mob ID>,"Skill Name"/<Skill ID>,<Skill Lv>,<Cast Time>,<Cancelable>,<Emotion>,<Target Type>;
20334 *------------------------------------------*/
20335 BUILDIN_FUNC(areamobuseskill)
20337 struct block_list center;
20338 struct script_data *data;
20340 int range,mobid,skill_id,skill_lv,casttime,emotion,target,cancel;
20342 if( (m = map_mapname2mapid(script_getstr(st,2))) < 0 ) {
20343 ShowError("areamobuseskill: invalid map name.\n");
20344 return SCRIPT_CMD_SUCCESS;
20348 center.x = script_getnum(st,3);
20349 center.y = script_getnum(st,4);
20350 range = script_getnum(st,5);
20351 mobid = script_getnum(st,6);
20352 data = script_getdata(st, 7);
20353 get_val(st, data); // Convert into value in case of a variable
20354 skill_id = ( data_isstring(data) ? skill_name2id(script_getstr(st,7)) : script_getnum(st,7) );
20355 if( (skill_lv = script_getnum(st,8)) > battle_config.mob_max_skilllvl )
20356 skill_lv = battle_config.mob_max_skilllvl;
20358 casttime = script_getnum(st,9);
20359 cancel = script_getnum(st,10);
20360 emotion = script_getnum(st,11);
20361 target = script_getnum(st,12);
20363 map_foreachinallrange(buildin_mobuseskill_sub, ¢er, range, BL_MOB, mobid, skill_id, skill_lv, casttime, cancel, emotion, target);
20364 return SCRIPT_CMD_SUCCESS;
20368 * Display a progress bar above a character
20369 * progressbar "<color>",<seconds>;
20371 BUILDIN_FUNC(progressbar)
20373 struct map_session_data * sd;
20374 const char * color;
20375 unsigned int second;
20377 if( !script_rid2sd(sd) )
20378 return SCRIPT_CMD_SUCCESS;
20382 color = script_getstr(st,2);
20383 second = script_getnum(st,3);
20385 sd->progressbar.npc_id = st->oid;
20386 sd->progressbar.timeout = gettick() + second*1000;
20387 sd->state.workinprogress = WIP_DISABLE_ALL;
20389 clif_progressbar(sd, strtol(color, (char **)NULL, 0), second);
20390 return SCRIPT_CMD_SUCCESS;
20394 * Display a progress bar above an NPC
20395 * progressbar_npc "<color>",<seconds>{,<"NPC Name">};
20397 BUILDIN_FUNC(progressbar_npc){
20398 struct npc_data* nd = NULL;
20400 if( script_hasdata(st, 4) ){
20401 const char* name = script_getstr(st, 4);
20403 nd = npc_name2id(name);
20406 ShowError( "buildin_progressbar_npc: NPC \"%s\" was not found.\n", name );
20407 return SCRIPT_CMD_FAILURE;
20410 nd = map_id2nd(st->oid);
20413 // First call(by function call)
20414 if( !nd->progressbar.timeout ){
20418 color = script_getstr(st, 2);
20419 second = script_getnum(st, 3);
20422 ShowError( "buildin_progressbar_npc: negative amount('%d') of seconds is not supported\n", second );
20423 return SCRIPT_CMD_FAILURE;
20426 // detach the player
20427 script_detach_rid(st);
20429 // sleep for the target amount of time
20430 st->state = RERUNLINE;
20431 st->sleep.tick = second * 1000;
20432 nd->progressbar.timeout = gettick() + second * 1000;
20433 nd->progressbar.color = strtol(color, (char **)NULL, 0);
20435 clif_progressbar_npc_area(nd);
20436 // Second call(by timer after sleeping time is over)
20438 // Continue the script
20440 st->sleep.tick = 0;
20441 nd->progressbar.timeout = nd->progressbar.color = 0;
20444 return SCRIPT_CMD_SUCCESS;
20447 BUILDIN_FUNC(pushpc)
20451 struct map_session_data* sd;
20453 if(!script_rid2sd(sd))
20455 return SCRIPT_CMD_SUCCESS;
20458 dir = script_getnum(st,2);
20459 cells = script_getnum(st,3);
20463 ShowWarning("buildin_pushpc: Invalid direction %d specified.\n", dir);
20464 script_reportsrc(st);
20466 dir%= DIR_MAX; // trim spin-over
20471 return SCRIPT_CMD_SUCCESS;
20474 {// pushing backwards
20475 dir = (dir+DIR_MAX/2)%DIR_MAX; // turn around
20482 unit_blown(&sd->bl, dx, dy, cells, BLOWN_NONE);
20483 return SCRIPT_CMD_SUCCESS;
20487 /// Invokes buying store preparation window
20488 /// buyingstore <slots>;
20489 BUILDIN_FUNC(buyingstore)
20491 struct map_session_data* sd;
20493 if( !script_rid2sd(sd) )
20495 return SCRIPT_CMD_SUCCESS;
20498 if( npc_isnear(&sd->bl) ) {
20500 sprintf(output, msg_txt(sd,662), battle_config.min_npc_vendchat_distance);
20501 clif_displaymessage(sd->fd, output);
20502 return SCRIPT_CMD_SUCCESS;
20505 buyingstore_setup(sd, script_getnum(st,2));
20506 return SCRIPT_CMD_SUCCESS;
20510 /// Invokes search store info window
20511 /// searchstores <uses>,<effect>;
20512 BUILDIN_FUNC(searchstores)
20514 unsigned short effect;
20516 struct map_session_data* sd;
20518 if( !script_rid2sd(sd) )
20520 return SCRIPT_CMD_SUCCESS;
20523 uses = script_getnum(st,2);
20524 effect = script_getnum(st,3);
20528 ShowError("buildin_searchstores: Amount of uses cannot be zero.\n");
20529 return SCRIPT_CMD_FAILURE;
20534 ShowError("buildin_searchstores: Invalid effect id %hu, specified.\n", effect);
20535 return SCRIPT_CMD_FAILURE;
20538 searchstore_open(sd, uses, effect);
20539 return SCRIPT_CMD_SUCCESS;
20541 /// Displays a number as large digital clock.
20542 /// showdigit <value>[,<type>];
20543 BUILDIN_FUNC(showdigit)
20545 unsigned int type = 0;
20547 struct map_session_data* sd;
20549 if( !script_rid2sd(sd) )
20551 return SCRIPT_CMD_SUCCESS;
20554 value = script_getnum(st,2);
20556 if( script_hasdata(st,3) ){
20557 type = script_getnum(st,3);
20565 // Use absolute value and then the negative value of it as starting value
20566 // This is what gravity's client does for these counters
20567 value = -abs(value);
20570 value = abs(value);
20572 ShowWarning("buildin_showdigit: type 3 can display 2 digits at max. Capping value %d to 99...\n", value);
20573 script_reportsrc(st);
20578 ShowError("buildin_showdigit: Invalid type %u.\n", type);
20579 return SCRIPT_CMD_FAILURE;
20582 clif_showdigit(sd, (unsigned char)type, value);
20583 return SCRIPT_CMD_SUCCESS;
20587 * makerune <% success bonus>{,<char_id>};
20589 BUILDIN_FUNC(makerune) {
20592 if (!script_charid2sd(3,sd))
20593 return SCRIPT_CMD_FAILURE;
20594 clif_skill_produce_mix_list(sd,RK_RUNEMASTERY,24);
20595 sd->itemid = script_getnum(st,2);
20596 return SCRIPT_CMD_SUCCESS;
20599 * checkdragon({<char_id>}) returns 1 if mounting a dragon or 0 otherwise.
20601 BUILDIN_FUNC(checkdragon) {
20604 if (!script_charid2sd(2,sd))
20605 return SCRIPT_CMD_FAILURE;
20606 if( pc_isridingdragon(sd) )
20607 script_pushint(st,1);
20609 script_pushint(st,0);
20610 return SCRIPT_CMD_SUCCESS;
20613 * setdragon({optional Color{,<char_id>}}) returns 1 on success or 0 otherwise
20614 * - Toggles the dragon on a RK if he can mount;
20615 * @param Color - when not provided uses the green dragon;
20616 * - 1 : Green Dragon
20617 * - 2 : Brown Dragon
20618 * - 3 : Gray Dragon
20619 * - 4 : Blue Dragon
20622 BUILDIN_FUNC(setdragon) {
20624 int color = script_hasdata(st,2) ? script_getnum(st,2) : 0;
20626 if (!script_charid2sd(3,sd))
20627 return SCRIPT_CMD_FAILURE;
20628 if( !pc_checkskill(sd,RK_DRAGONTRAINING) || (sd->class_&MAPID_THIRDMASK) != MAPID_RUNE_KNIGHT )
20629 script_pushint(st,0);//Doesn't have the skill or it's not a Rune Knight
20630 else if ( pc_isridingdragon(sd) ) {//Is mounted; release
20631 pc_setoption(sd, sd->sc.option&~OPTION_DRAGON);
20632 script_pushint(st,1);
20633 } else {//Not mounted; Mount now.
20634 unsigned int option = OPTION_DRAGON1;
20636 option = ( color == 1 ? OPTION_DRAGON1 :
20637 color == 2 ? OPTION_DRAGON2 :
20638 color == 3 ? OPTION_DRAGON3 :
20639 color == 4 ? OPTION_DRAGON4 :
20640 color == 5 ? OPTION_DRAGON5 : 0);
20642 ShowWarning("script_setdragon: Unknown Color %d used; changing to green (1)\n",color);
20643 option = OPTION_DRAGON1;
20646 pc_setoption(sd, sd->sc.option|option);
20647 script_pushint(st,1);
20649 return SCRIPT_CMD_SUCCESS;
20653 * ismounting({<char_id>}) returns 1 if mounting a new mount or 0 otherwise
20655 BUILDIN_FUNC(ismounting) {
20658 if (!script_charid2sd(2,sd))
20659 return SCRIPT_CMD_FAILURE;
20660 if( sd->sc.data[SC_ALL_RIDING] )
20661 script_pushint(st,1);
20663 script_pushint(st,0);
20664 return SCRIPT_CMD_SUCCESS;
20668 * setmounting({<char_id>}) returns 1 on success or 0 otherwise
20669 * - Toggles new mounts on a player when he can mount
20670 * - Will fail if the player is mounting a non-new mount, e.g. dragon, peco, wug, etc.
20671 * - Will unmount the player is he is already mounting
20673 BUILDIN_FUNC(setmounting) {
20676 if (!script_charid2sd(2,sd))
20677 return SCRIPT_CMD_FAILURE;
20678 if( sd->sc.option&(OPTION_WUGRIDER|OPTION_RIDING|OPTION_DRAGON|OPTION_MADOGEAR) ) {
20679 clif_msg(sd, NEED_REINS_OF_MOUNT);
20680 script_pushint(st,0); //can't mount with one of these
20682 if( sd->sc.data[SC_ALL_RIDING] )
20683 status_change_end(&sd->bl, SC_ALL_RIDING, INVALID_TIMER); //release mount
20685 sc_start(NULL, &sd->bl, SC_ALL_RIDING, 10000, 1, INVALID_TIMER); //mount
20686 script_pushint(st,1);//in both cases, return 1.
20688 return SCRIPT_CMD_SUCCESS;
20691 * Retrieves quantity of arguments provided to callfunc/callsub.
20692 * getargcount() -> amount of arguments received in a function
20694 BUILDIN_FUNC(getargcount) {
20695 struct script_retinfo* ri;
20697 if( st->stack->defsp < 1 || st->stack->stack_data[st->stack->defsp - 1].type != C_RETINFO ) {
20698 ShowError("script:getargcount: used out of function or callsub label!\n");
20700 return SCRIPT_CMD_FAILURE;
20702 ri = st->stack->stack_data[st->stack->defsp - 1].u.ri;
20704 script_pushint(st, ri->nargs);
20705 return SCRIPT_CMD_SUCCESS;
20708 * getcharip(<account ID>/<character ID>/<character name>)
20710 BUILDIN_FUNC(getcharip)
20712 struct map_session_data* sd = NULL;
20714 /* check if a character name is specified */
20715 if( script_hasdata(st, 2) )
20717 struct script_data *data;
20719 data = script_getdata(st, 2);
20720 get_val(st, data); // Convert into value in case of a variable
20721 if (data_isstring(data))
20722 sd = map_nick2sd(script_getstr(st, 2),false);
20723 else if (data_isint(data) || script_getnum(st, 2))
20726 id = script_getnum(st, 2);
20727 sd = (map_id2sd(id) ? map_id2sd(id) : map_charid2sd(id));
20733 /* check for sd and IP */
20734 if (!sd || !session[sd->fd]->client_addr)
20736 script_pushconststr(st, "");
20737 return SCRIPT_CMD_SUCCESS;
20740 /* return the client ip_addr converted for output */
20741 if (sd && sd->fd && session[sd->fd])
20744 const char *ip_addr = NULL;
20747 /* set ip, ip_addr and convert to ip and push str */
20748 ip = session[sd->fd]->client_addr;
20749 ip_addr = ip2str(ip, NULL);
20750 script_pushstrcopy(st, ip_addr);
20752 return SCRIPT_CMD_SUCCESS;
20755 * is_function(<function name>) -> 1 if function exists, 0 otherwise
20757 BUILDIN_FUNC(is_function) {
20758 const char* str = script_getstr(st,2);
20760 if( strdb_exists(userfunc_db, str) )
20761 script_pushint(st,1);
20763 script_pushint(st,0);
20764 return SCRIPT_CMD_SUCCESS;
20767 * get_revision() -> retrieves the current svn revision (if available)
20769 BUILDIN_FUNC(get_revision) {
20770 const char *svn = get_svn_revision();
20772 if ( svn[0] != UNKNOWN_VERSION )
20773 script_pushint(st,atoi(svn));
20775 script_pushint(st,-1); //unknown
20776 return SCRIPT_CMD_SUCCESS;
20778 /* get_hash() -> retrieves the current git hash (if available)*/
20779 BUILDIN_FUNC(get_githash) {
20780 const char* git = get_git_hash();
20781 char buf[CHAT_SIZE_MAX];
20782 safestrncpy(buf,git,strlen(git)+1);
20784 if ( git[0] != UNKNOWN_VERSION )
20785 script_pushstr(st,buf);
20787 script_pushconststr(st,"Unknown"); //unknown
20788 return SCRIPT_CMD_SUCCESS;
20791 * freeloop(<toggle>) -> toggles this script instance's looping-check ability
20793 BUILDIN_FUNC(freeloop) {
20795 if( script_hasdata(st,2) ) {
20796 if( script_getnum(st,2) )
20802 script_pushint(st, st->freeloop);
20803 return SCRIPT_CMD_SUCCESS;
20807 * @commands (script based)
20809 BUILDIN_FUNC(bindatcmd) {
20811 const char* eventName;
20812 int i, level = 0, level2 = 0;
20813 bool create = false;
20815 atcmd = script_getstr(st,2);
20816 eventName = script_getstr(st,3);
20818 if( *atcmd == atcommand_symbol || *atcmd == charcommand_symbol )
20821 if( script_hasdata(st,4) ) level = script_getnum(st,4);
20822 if( script_hasdata(st,5) ) level2 = script_getnum(st,5);
20824 if( atcmd_binding_count == 0 ) {
20825 CREATE(atcmd_binding,struct atcmd_binding_data*,1);
20829 ARR_FIND(0, atcmd_binding_count, i, strcmp(atcmd_binding[i]->command,atcmd) == 0);
20830 if( i < atcmd_binding_count ) {/* update existent entry */
20831 safestrncpy(atcmd_binding[i]->npc_event, eventName, EVENT_NAME_LENGTH);
20832 atcmd_binding[i]->level = level;
20833 atcmd_binding[i]->level2 = level2;
20839 i = atcmd_binding_count;
20841 if( atcmd_binding_count++ != 0 )
20842 RECREATE(atcmd_binding,struct atcmd_binding_data*,atcmd_binding_count);
20844 CREATE(atcmd_binding[i],struct atcmd_binding_data,1);
20846 safestrncpy(atcmd_binding[i]->command, atcmd, 50);
20847 safestrncpy(atcmd_binding[i]->npc_event, eventName, EVENT_NAME_LENGTH);
20848 atcmd_binding[i]->level = level;
20849 atcmd_binding[i]->level2 = level2;
20851 return SCRIPT_CMD_SUCCESS;
20854 BUILDIN_FUNC(unbindatcmd) {
20858 atcmd = script_getstr(st, 2);
20860 if( *atcmd == atcommand_symbol || *atcmd == charcommand_symbol )
20863 if( atcmd_binding_count == 0 ) {
20864 script_pushint(st, 0);
20865 return SCRIPT_CMD_SUCCESS;
20868 ARR_FIND(0, atcmd_binding_count, i, strcmp(atcmd_binding[i]->command, atcmd) == 0);
20869 if( i < atcmd_binding_count ) {
20871 aFree(atcmd_binding[i]);
20872 atcmd_binding[i] = NULL;
20873 /* compact the list now that we freed a slot somewhere */
20874 for( i = 0, cursor = 0; i < atcmd_binding_count; i++ ) {
20875 if( atcmd_binding[i] == NULL )
20878 if( cursor != i ) {
20879 memmove(&atcmd_binding[cursor], &atcmd_binding[i], sizeof(struct atcmd_binding_data*));
20885 if( (atcmd_binding_count = cursor) == 0 )
20886 aFree(atcmd_binding);
20888 script_pushint(st, 1);
20890 script_pushint(st, 0);/* not found */
20892 return SCRIPT_CMD_SUCCESS;
20895 BUILDIN_FUNC(useatcmd) {
20896 return atcommand_sub(st,3);
20899 BUILDIN_FUNC(checkre)
20903 num=script_getnum(st,2);
20907 script_pushint(st, 1);
20909 script_pushint(st, 0);
20913 #ifdef RENEWAL_CAST
20914 script_pushint(st, 1);
20916 script_pushint(st, 0);
20920 #ifdef RENEWAL_DROP
20921 script_pushint(st, 1);
20923 script_pushint(st, 0);
20928 script_pushint(st, 1);
20930 script_pushint(st, 0);
20934 #ifdef RENEWAL_LVDMG
20935 script_pushint(st, 1);
20937 script_pushint(st, 0);
20941 #ifdef RENEWAL_ASPD
20942 script_pushint(st, 1);
20944 script_pushint(st, 0);
20948 ShowWarning("buildin_checkre: unknown parameter.\n");
20951 return SCRIPT_CMD_SUCCESS;
20954 /* getrandgroupitem <group_id>{,<quantity>{,<sub_group>}} */
20955 BUILDIN_FUNC(getrandgroupitem) {
20957 int i, get_count = 0;
20958 uint16 group, qty = 0;
20959 uint8 sub_group = 1;
20960 struct item item_tmp;
20961 struct s_item_group_entry *entry = NULL;
20963 if (!script_rid2sd(sd))
20964 return SCRIPT_CMD_SUCCESS;
20966 group = script_getnum(st,2);
20969 ShowError("buildin_getrandgroupitem: Invalid group id (%d)!\n",script_getnum(st,2));
20970 return SCRIPT_CMD_FAILURE;
20974 FETCH(4, sub_group);
20976 entry = itemdb_get_randgroupitem(group,sub_group);
20978 return SCRIPT_CMD_FAILURE; //ensure valid itemid
20980 memset(&item_tmp,0,sizeof(item_tmp));
20981 item_tmp.nameid = entry->nameid;
20982 item_tmp.identify = itemdb_isidentified(entry->nameid);
20985 qty = entry->amount;
20987 //Check if it's stackable.
20988 if (!itemdb_isstackable(entry->nameid)) {
20989 item_tmp.amount = 1;
20993 item_tmp.amount = qty;
20997 for (i = 0; i < get_count; i++) {
20999 if (!pet_create_egg(sd, entry->nameid)) {
21000 unsigned char flag = 0;
21001 if ((flag = pc_additem(sd,&item_tmp,item_tmp.amount,LOG_TYPE_SCRIPT))) {
21002 clif_additem(sd,0,0,flag);
21003 if (pc_candrop(sd,&item_tmp))
21004 map_addflooritem(&item_tmp,item_tmp.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0);
21009 return SCRIPT_CMD_SUCCESS;
21012 /* getgroupitem <group_id>{,<char_id>};
21013 * Gives item(s) to the attached player based on item group contents
21015 BUILDIN_FUNC(getgroupitem) {
21017 int group_id = script_getnum(st,2);
21019 if (!script_charid2sd(3,sd))
21020 return SCRIPT_CMD_SUCCESS;
21022 if (itemdb_pc_get_itemgroup(group_id,sd)) {
21023 ShowError("buildin_getgroupitem: Invalid group id '%d' specified.\n",group_id);
21024 return SCRIPT_CMD_FAILURE;
21027 return SCRIPT_CMD_SUCCESS;
21030 /* cleanmap <map_name>;
21031 * cleanarea <map_name>, <x0>, <y0>, <x1>, <y1>; */
21032 static int atcommand_cleanfloor_sub(struct block_list *bl, va_list ap)
21035 map_clearflooritem(bl);
21037 return SCRIPT_CMD_SUCCESS;
21040 BUILDIN_FUNC(cleanmap)
21042 const char *mapname;
21045 mapname = script_getstr(st, 2);
21046 m = map_mapname2mapid(mapname);
21048 return SCRIPT_CMD_FAILURE;
21050 if ((script_lastdata(st) - 2) < 4) {
21051 map_foreachinmap(atcommand_cleanfloor_sub, m, BL_ITEM);
21053 int16 x0 = script_getnum(st, 3);
21054 int16 y0 = script_getnum(st, 4);
21055 int16 x1 = script_getnum(st, 5);
21056 int16 y1 = script_getnum(st, 6);
21057 if (x0 > 0 && y0 > 0 && x1 > 0 && y1 > 0) {
21058 map_foreachinallarea(atcommand_cleanfloor_sub, m, x0, y0, x1, y1, BL_ITEM);
21060 ShowError("cleanarea: invalid coordinate defined!\n");
21061 return SCRIPT_CMD_FAILURE;
21064 return SCRIPT_CMD_SUCCESS;
21067 /* Cast a skill on the attached player.
21068 * npcskill <skill id>, <skill lvl>, <stat point>, <NPC level>;
21069 * npcskill "<skill name>", <skill lvl>, <stat point>, <NPC level>; */
21070 BUILDIN_FUNC(npcskill)
21073 unsigned short skill_level;
21074 unsigned int stat_point;
21075 unsigned int npc_level;
21076 struct npc_data *nd;
21077 struct map_session_data *sd;
21078 struct script_data *data;
21080 if( !script_rid2sd(sd) )
21081 return SCRIPT_CMD_SUCCESS;
21083 data = script_getdata(st, 2);
21084 get_val(st, data); // Convert into value in case of a variable
21085 skill_id = data_isstring(data) ? skill_name2id(script_getstr(st, 2)) : script_getnum(st, 2);
21086 skill_level = script_getnum(st, 3);
21087 stat_point = script_getnum(st, 4);
21088 npc_level = script_getnum(st, 5);
21089 nd = (struct npc_data *)map_id2bl(sd->npc_id);
21091 if (stat_point > battle_config.max_third_parameter) {
21092 ShowError("npcskill: stat point exceeded maximum of %d.\n",battle_config.max_third_parameter );
21093 return SCRIPT_CMD_FAILURE;
21095 if (npc_level > MAX_LEVEL) {
21096 ShowError("npcskill: level exceeded maximum of %d.\n", MAX_LEVEL);
21097 return SCRIPT_CMD_FAILURE;
21099 if (nd == NULL) { //ain't possible, but I don't trust people.
21100 return SCRIPT_CMD_FAILURE;
21103 nd->level = npc_level;
21104 nd->stat_point = stat_point;
21106 if (!nd->status.hp)
21107 status_calc_npc(nd, SCO_FIRST);
21109 status_calc_npc(nd, SCO_NONE);
21111 if (skill_get_inf(skill_id)&INF_GROUND_SKILL)
21112 unit_skilluse_pos2(&nd->bl, sd->bl.x, sd->bl.y, skill_id, skill_level,0,0);
21114 unit_skilluse_id2(&nd->bl, sd->bl.id, skill_id, skill_level,0,0);
21116 return SCRIPT_CMD_SUCCESS;
21119 /* Consumes an item.
21120 * consumeitem <item id>{,<char_id>};
21121 * consumeitem "<item name>"{,<char_id>};
21122 * @param item: Item ID or name
21124 BUILDIN_FUNC(consumeitem)
21127 struct script_data *data;
21128 struct item_data *item_data;
21130 if (!script_charid2sd(3, sd))
21131 return SCRIPT_CMD_FAILURE;
21133 data = script_getdata( st, 2 );
21134 get_val( st, data );
21136 if( data_isstring( data ) ){
21137 const char *name = conv_str( st, data );
21139 if( ( item_data = itemdb_searchname( name ) ) == NULL ){
21140 ShowError( "buildin_consumeitem: Nonexistant item %s requested.\n", name );
21141 return SCRIPT_CMD_FAILURE;
21143 }else if( data_isint( data ) ){
21144 unsigned short nameid = conv_num( st, data );
21146 if( ( item_data = itemdb_exists( nameid ) ) == NULL ){
21147 ShowError("buildin_consumeitem: Nonexistant item %hu requested.\n", nameid );
21148 return SCRIPT_CMD_FAILURE;
21151 ShowError("buildin_consumeitem: invalid data type for argument #1 (%d).\n", data->type );
21152 return SCRIPT_CMD_FAILURE;
21155 run_script( item_data->script, 0, sd->bl.id, 0 );
21156 return SCRIPT_CMD_SUCCESS;
21159 /** Makes a player sit/stand.
21160 * sit {"<character name>"};
21161 * stand {"<character name>"};
21162 * Note: Use readparam(Sitting) which returns 1 or 0 (sitting or standing).
21163 * @param name: Player name that will be invoked
21169 if( !script_nick2sd(2,sd) )
21170 return SCRIPT_CMD_FAILURE;
21172 if( !pc_issit(sd) ) {
21175 clif_sitting(&sd->bl);
21177 return SCRIPT_CMD_SUCCESS;
21180 /** Makes player to stand
21181 * @param name: Player name that will be set
21183 BUILDIN_FUNC(stand)
21187 if( !script_nick2sd(2,sd) )
21188 return SCRIPT_CMD_FAILURE;
21190 if( pc_issit(sd) && pc_setstand(sd, false)) {
21192 clif_standing(&sd->bl);
21195 return SCRIPT_CMD_SUCCESS;
21198 /** Creates an array of bounded item IDs
21199 * countbound {<type>{,<char_id>}};
21200 * @param type: 0 - All bound items; 1 - Account Bound; 2 - Guild Bound; 3 - Party Bound
21201 * @return amt: Amount of items found
21203 BUILDIN_FUNC(countbound)
21205 int i, type, j = 0, k = 0;
21208 if (!script_charid2sd(3,sd))
21209 return SCRIPT_CMD_FAILURE;
21211 type = script_getnum(st,2);
21213 for( i = 0; i < MAX_INVENTORY; i ++ ) {
21214 if( sd->inventory.u.items_inventory[i].nameid > 0 && (
21215 (!type && sd->inventory.u.items_inventory[i].bound) || (type && sd->inventory.u.items_inventory[i].bound == type)
21218 pc_setreg(sd,reference_uid(add_str("@bound_items"), k),sd->inventory.u.items_inventory[i].nameid);
21220 j += sd->inventory.u.items_inventory[i].amount;
21224 script_pushint(st,j);
21225 return SCRIPT_CMD_SUCCESS;
21228 /** Creates new party
21229 * party_create "<party name>"{,<char id>{,<item share>{,<item share type>}}};
21230 * @param party_name: String of party name that will be created
21231 * @param char_id: Chara that will be leader of this new party. If no char_id specified, the invoker will be party leader
21232 * @param item_share: 0-Each Take. 1-Party Share
21233 * @param item_share_type: 0-Each Take. 1-Even Share
21234 * @return val: Result value
21235 * -3 - party name is exist
21236 * -2 - player is in party already
21237 * -1 - player is not found
21238 * 0 - unknown error
21239 * 1 - success, will return party id $@party_create_id
21241 BUILDIN_FUNC(party_create)
21243 char party_name[NAME_LENGTH];
21244 int item1 = 0, item2 = 0;
21247 if (!script_charid2sd(3, sd)) {
21248 script_pushint(st,-1);
21249 return SCRIPT_CMD_FAILURE;
21252 if( sd->status.party_id ) {
21253 script_pushint(st,-2);
21254 return SCRIPT_CMD_FAILURE;
21257 safestrncpy(party_name,script_getstr(st,2),NAME_LENGTH);
21259 if( party_searchname(party_name) ) {
21260 script_pushint(st,-3);
21261 return SCRIPT_CMD_FAILURE;
21263 if( script_getnum(st,4) )
21265 if( script_getnum(st,5) )
21268 party_create_byscript = 1;
21269 script_pushint(st,party_create(sd,party_name,item1,item2));
21270 return SCRIPT_CMD_SUCCESS;
21273 /** Adds player to specified party
21274 * party_addmember <party id>,<char id>;
21275 * @param party_id: The party that will be entered by player
21276 * @param char_id: Char id of player that will be joined to the party
21277 * @return val: Result value
21278 * -5 - another character of the same account is in the party
21279 * -4 - party is full
21280 * -3 - party is not found
21281 * -2 - player is in party already
21282 * -1 - player is not found
21283 * 0 - unknown error
21286 BUILDIN_FUNC(party_addmember)
21288 int party_id = script_getnum(st,2);
21290 struct party_data *party;
21292 if( !(sd = map_charid2sd(script_getnum(st,3))) ) {
21293 script_pushint(st,-1);
21294 return SCRIPT_CMD_FAILURE;
21297 if( sd->status.party_id ) {
21298 script_pushint(st,-2);
21299 return SCRIPT_CMD_FAILURE;
21302 if( !(party = party_search(party_id)) ) {
21303 script_pushint(st,-3);
21304 return SCRIPT_CMD_FAILURE;
21307 if (battle_config.block_account_in_same_party) {
21309 ARR_FIND(0, MAX_PARTY, i, party->party.member[i].account_id == sd->status.account_id);
21310 if (i < MAX_PARTY) {
21311 script_pushint(st,-5);
21312 return SCRIPT_CMD_FAILURE;
21316 if( party->party.count >= MAX_PARTY ) {
21317 script_pushint(st,-4);
21318 return SCRIPT_CMD_FAILURE;
21320 sd->party_invite = party_id;
21321 script_pushint(st,party_add_member(party_id,sd));
21322 return SCRIPT_CMD_SUCCESS;
21325 /** Removes player from his/her party. If party_id and char_id is empty remove the invoker from his/her party
21326 * party_delmember {<char id>,<party_id>};
21329 * @return val: Result value
21330 * -3 - player is not in party
21331 * -2 - party is not found
21332 * -1 - player is not found
21333 * 0 - unknown error
21336 BUILDIN_FUNC(party_delmember)
21340 if( !script_hasdata(st,2) && !script_hasdata(st,3) && !script_rid2sd(sd) ) {
21341 script_pushint(st,-1);
21342 return SCRIPT_CMD_FAILURE;
21344 if( sd || script_charid2sd(2,sd) )
21345 script_pushint(st,party_removemember2(sd,0,0));
21347 script_pushint(st,party_removemember2(NULL,script_getnum(st,2),script_getnum(st,3)));
21348 return SCRIPT_CMD_SUCCESS;
21351 /** Changes party leader of specified party (even the leader is offline)
21352 * party_changeleader <party id>,<char id>;
21353 * @param party_id: ID of party
21354 * @param char_id: Char ID of new leader
21355 * @return val: Result value
21356 * -4 - player is party leader already
21357 * -3 - player is not in this party
21358 * -2 - player is not found
21359 * -1 - party is not found
21360 * 0 - unknown error
21362 BUILDIN_FUNC(party_changeleader)
21364 int i, party_id = script_getnum(st,2);
21366 TBL_PC *tsd = NULL;
21367 struct party_data *party = NULL;
21369 if( !(party = party_search(party_id)) ) {
21370 script_pushint(st,-1);
21371 return SCRIPT_CMD_FAILURE;
21374 if( !(tsd = map_charid2sd(script_getnum(st,3))) ) {
21375 script_pushint(st,-2);
21376 return SCRIPT_CMD_FAILURE;
21379 if( tsd->status.party_id != party_id ) {
21380 script_pushint(st,-3);
21381 return SCRIPT_CMD_FAILURE;
21384 ARR_FIND(0,MAX_PARTY,i,party->party.member[i].leader);
21385 if( i >= MAX_PARTY ) { //this is should impossible!
21386 script_pushint(st,0);
21387 return SCRIPT_CMD_FAILURE;
21389 if( party->data[i].sd == tsd ) {
21390 script_pushint(st,-4);
21391 return SCRIPT_CMD_FAILURE;
21394 script_pushint(st,party_changeleader(sd,tsd,party));
21395 return SCRIPT_CMD_SUCCESS;
21398 /** Changes party option
21399 * party_changeoption <party id>,<option>,<flag>;
21400 * @param party_id: ID of party that will be changed
21401 * @param option: Type of option
21402 * @return val: -1 - party is not found, 0 - invalid option, 1 - success
21404 BUILDIN_FUNC(party_changeoption)
21406 struct party_data *party;
21408 if( !(party = party_search(script_getnum(st,2))) ) {
21409 script_pushint(st,-1);
21410 return SCRIPT_CMD_FAILURE;
21412 script_pushint(st,party_setoption(party,script_getnum(st,3),script_getnum(st,4)));
21413 return SCRIPT_CMD_SUCCESS;
21416 /** Destroys party with party id.
21417 * party_destroy <party id>;
21418 * @param party_id: ID of party that will be destroyed
21420 BUILDIN_FUNC(party_destroy)
21423 struct party_data *party;
21425 if( !(party = party_search(script_getnum(st,2))) ) {
21426 script_pushint(st,0);
21427 return SCRIPT_CMD_FAILURE;
21430 ARR_FIND(0,MAX_PARTY,i,party->party.member[i].leader);
21431 if( i >= MAX_PARTY || !party->data[i].sd ) { //leader not online
21433 for( j = 0; j < MAX_PARTY; j++ ) {
21434 TBL_PC *sd = party->data[j].sd;
21436 party_member_withdraw(party->party.party_id,sd->status.account_id,sd->status.char_id,sd->status.name,PARTY_MEMBER_WITHDRAW_LEAVE);
21437 else if( party->party.member[j].char_id )
21438 intif_party_leave(party->party.party_id,party->party.member[j].account_id,party->party.member[j].char_id,party->party.member[j].name,PARTY_MEMBER_WITHDRAW_LEAVE);
21440 party_broken(party->party.party_id);
21441 script_pushint(st,1);
21443 else //leader leave = party broken
21444 script_pushint(st,party_leave(party->data[i].sd));
21445 return SCRIPT_CMD_SUCCESS;
21448 /** Returns various information about a player's VIP status. Need to enable VIP system
21449 * vip_status <type>,{"<character name>"};
21450 * @param type: Info type, see enum vip_status_type
21451 * @param name: Character name (Optional)
21453 BUILDIN_FUNC(vip_status) {
21458 if( !script_nick2sd(3,sd) )
21459 return SCRIPT_CMD_FAILURE;
21461 type = script_getnum(st, 2);
21464 case VIP_STATUS_ACTIVE: // Get VIP status.
21465 script_pushint(st, pc_isvip(sd));
21467 case VIP_STATUS_EXPIRE: // Get VIP expire date.
21468 if (pc_isvip(sd)) {
21469 script_pushint(st, sd->vip.time);
21471 script_pushint(st, 0);
21473 case VIP_STATUS_REMAINING: // Get remaining time.
21474 if (pc_isvip(sd)) {
21475 script_pushint(st, sd->vip.time - time(NULL));
21477 script_pushint(st, 0);
21480 ShowError( "buildin_vip_status: Unsupported type %d.\n", type );
21481 return SCRIPT_CMD_FAILURE;
21484 script_pushint(st, 0);
21486 return SCRIPT_CMD_SUCCESS;
21490 /** Adds or removes VIP time in minutes. Need to enable VIP system
21491 * vip_time <time in mn>,{"<character name>"};
21492 * @param time: VIP duration in minutes. If time < 0 remove time, else add time.
21493 * @param name: Character name (optional)
21495 BUILDIN_FUNC(vip_time) {
21496 #ifdef VIP_ENABLE //would be a pain for scripting npc otherwise
21498 int viptime = script_getnum(st, 2) * 60; // Convert since it's given in minutes.
21500 if( !script_nick2sd(3,sd) )
21501 return SCRIPT_CMD_FAILURE;
21503 chrif_req_login_operation(sd->status.account_id, sd->status.name, CHRIF_OP_LOGIN_VIP, viptime, 7, 0);
21505 return SCRIPT_CMD_SUCCESS;
21510 * Turns a player into a monster and optionally can grant a SC attribute effect.
21511 * montransform <monster name/ID>, <duration>, <sc type>, <val1>, <val2>, <val3>, <val4>;
21512 * active_transform <monster name/ID>, <duration>, <sc type>, <val1>, <val2>, <val3>, <val4>;
21513 * @param monster: Monster ID or name
21514 * @param duration: Transform duration in millisecond (ms)
21515 * @param sc_type: Type of SC that will be affected during the transformation
21516 * @param val1: Value for SC
21517 * @param val2: Value for SC
21518 * @param val3: Value for SC
21519 * @param val4: Value for SC
21520 * @author: malufett
21522 BUILDIN_FUNC(montransform) {
21525 int tick, mob_id, val1, val2, val3, val4;
21526 struct script_data *data;
21527 val1 = val2 = val3 = val4 = 0;
21529 if( !script_rid2sd(sd) )
21530 return SCRIPT_CMD_FAILURE;
21532 data = script_getdata(st, 2);
21533 get_val(st, data); // Convert into value in case of a variable
21534 if( data_isstring(data) )
21535 mob_id = mobdb_searchname(script_getstr(st, 2));
21537 mob_id = mobdb_checkid(script_getnum(st, 2));
21539 tick = script_getnum(st, 3);
21541 if (script_hasdata(st, 4))
21542 type = (sc_type)script_getnum(st, 4);
21547 if( data_isstring(data) )
21548 ShowWarning("buildin_montransform: Attempted to use non-existing monster '%s'.\n", script_getstr(st, 2));
21550 ShowWarning("buildin_montransform: Attempted to use non-existing monster of ID '%d'.\n", script_getnum(st, 2));
21551 return SCRIPT_CMD_FAILURE;
21554 if (mob_id == MOBID_EMPERIUM) {
21555 ShowWarning("buildin_montransform: Monster 'Emperium' cannot be used.\n");
21556 return SCRIPT_CMD_FAILURE;
21559 if (!(type >= SC_NONE && type < SC_MAX)) {
21560 ShowWarning("buildin_montransform: Unsupported status change id %d\n", type);
21561 return SCRIPT_CMD_FAILURE;
21564 if (script_hasdata(st, 5))
21565 val1 = script_getnum(st, 5);
21567 if (script_hasdata(st, 6))
21568 val2 = script_getnum(st, 6);
21570 if (script_hasdata(st, 7))
21571 val3 = script_getnum(st, 7);
21573 if (script_hasdata(st, 8))
21574 val4 = script_getnum(st, 8);
21577 if (battle_config.mon_trans_disable_in_gvg && map_flag_gvg2(sd->bl.m)) {
21578 clif_displaymessage(sd->fd, msg_txt(sd,731)); // Transforming into monster is not allowed in Guild Wars.
21579 return SCRIPT_CMD_FAILURE;
21583 clif_displaymessage(sd->fd, msg_txt(sd,729)); // Cannot transform into monster while in disguise.
21584 return SCRIPT_CMD_FAILURE;
21587 if (!strcmp(script_getfuncname(st), "active_transform")) {
21588 status_change_end(&sd->bl, SC_ACTIVE_MONSTER_TRANSFORM, INVALID_TIMER); // Clear previous
21589 sc_start2(NULL, &sd->bl, SC_ACTIVE_MONSTER_TRANSFORM, 100, mob_id, type, tick);
21591 status_change_end(&sd->bl, SC_MONSTER_TRANSFORM, INVALID_TIMER); // Clear previous
21592 sc_start2(NULL, &sd->bl, SC_MONSTER_TRANSFORM, 100, mob_id, type, tick);
21594 if (type != SC_NONE)
21595 sc_start4(NULL, &sd->bl, type, 100, val1, val2, val3, val4, tick);
21598 return SCRIPT_CMD_SUCCESS;
21602 * Attach script to player for certain duration
21603 * bonus_script "<script code>",<duration>{,<flag>{,<type>{,<status_icon>{,<char_id>}}}};
21604 * @param "script code"
21611 BUILDIN_FUNC(bonus_script) {
21613 int16 icon = SI_BLANK;
21617 const char *script_str = NULL;
21618 struct s_bonus_script_entry *entry = NULL;
21620 if ( !script_charid2sd(7,sd) )
21621 return SCRIPT_CMD_FAILURE;
21623 script_str = script_getstr(st,2);
21624 dur = 1000 * abs(script_getnum(st,3));
21629 // No Script string, No Duration!
21630 if (script_str[0] == '\0' || !dur) {
21631 ShowError("buildin_bonus_script: Invalid! Script: \"%s\". Duration: %d\n", script_str, dur);
21632 return SCRIPT_CMD_FAILURE;
21635 if (strlen(script_str) >= MAX_BONUS_SCRIPT_LENGTH) {
21636 ShowError("buildin_bonus_script: Script string to long: \"%s\".\n", script_str);
21637 return SCRIPT_CMD_FAILURE;
21640 if (icon <= SI_BLANK || icon >= SI_MAX)
21643 if ((entry = pc_bonus_script_add(sd, script_str, dur, (enum si_type)icon, flag, type))) {
21644 linkdb_insert(&sd->bonus_script.head, (void *)((intptr_t)entry), entry);
21645 status_calc_pc(sd,SCO_NONE);
21647 return SCRIPT_CMD_SUCCESS;
21651 * Removes all bonus script from player
21652 * bonus_script_clear {<flag>,{<char_id>}};
21653 * @param flag 0 - Except permanent bonus, 1 - With permanent bonus
21654 * @param char_id Clear script from this character
21657 BUILDIN_FUNC(bonus_script_clear) {
21661 if (!script_charid2sd(3,sd))
21662 return SCRIPT_CMD_FAILURE;
21664 if (script_hasdata(st,2))
21665 flag = script_getnum(st,2) != 0;
21667 pc_bonus_script_clear(sd,(flag ? BSF_PERMANENT : BSF_REM_ALL));
21668 return SCRIPT_CMD_SUCCESS;
21671 /** Allows player to use atcommand while talking with NPC
21673 * @author [Cydh], [Kichi]
21675 BUILDIN_FUNC(enable_command) {
21678 if (!script_rid2sd(sd))
21679 return SCRIPT_CMD_FAILURE;
21680 sd->state.disable_atcommand_on_npc = 0;
21681 return SCRIPT_CMD_SUCCESS;
21684 /** Prevents player to use atcommand while talking with NPC
21686 * @author [Cydh], [Kichi]
21688 BUILDIN_FUNC(disable_command) {
21691 if (!script_rid2sd(sd))
21692 return SCRIPT_CMD_FAILURE;
21693 sd->state.disable_atcommand_on_npc = 1;
21694 return SCRIPT_CMD_SUCCESS;
21697 /** Get the information of the members of a guild by type.
21698 * getguildmember <guild_id>{,<type>};
21699 * @param guild_id: ID of guild
21700 * @param type: Type of option (optional)
21702 BUILDIN_FUNC(getguildmember)
21704 struct guild *g = NULL;
21707 g = guild_search(script_getnum(st,2));
21711 struct script_data *data = NULL;
21712 char *varname = NULL;
21714 if (script_hasdata(st,3))
21715 type = script_getnum(st,3);
21717 if (script_hasdata(st,4)) {
21718 data = script_getdata(st, 4);
21719 if (!data_isreference(data)) {
21720 ShowError("buildin_getguildmember: Error in argument! Please give a variable to store values in.\n");
21721 return SCRIPT_CMD_FAILURE;
21723 varname = reference_getname(data);
21724 if (type <= 0 && varname[strlen(varname)-1] != '$') {
21725 ShowError("buildin_getguildmember: The array %s is not string type.\n", varname);
21726 return SCRIPT_CMD_FAILURE;
21730 for (i = 0; i < MAX_GUILD; i++) {
21731 if (g->member[i].account_id) {
21735 setd_sub(st, NULL, varname, j, (void *)__64BPRTSIZE(g->member[i].account_id), data->ref);
21737 mapreg_setreg(reference_uid(add_str("$@guildmemberaid"), j),g->member[i].account_id);
21741 setd_sub(st, NULL, varname, j, (void *)__64BPRTSIZE(g->member[i].char_id), data->ref);
21743 mapreg_setreg(reference_uid(add_str("$@guildmembercid"), j), g->member[i].char_id);
21747 setd_sub(st, NULL, varname, j, (void *)__64BPRTSIZE(g->member[i].name), data->ref);
21749 mapreg_setregstr(reference_uid(add_str("$@guildmembername$"), j), g->member[i].name);
21756 mapreg_setreg(add_str("$@guildmembercount"), j);
21757 script_pushint(st, j);
21758 return SCRIPT_CMD_SUCCESS;
21761 /** Adds spirit ball to player for 'duration' in milisecond
21762 * addspiritball <count>,<duration>{,<char_id>};
21763 * @param count How many spirit ball will be added
21764 * @param duration How long spiritball is active until it disappears
21765 * @param char_id Target player (Optional)
21768 BUILDIN_FUNC(addspiritball) {
21771 struct map_session_data *sd = NULL;
21773 if (script_hasdata(st,4)) {
21774 if (!script_isstring(st,4))
21775 sd = map_charid2sd(script_getnum(st,4));
21777 sd = map_nick2sd(script_getstr(st,4),false);
21782 return SCRIPT_CMD_FAILURE;
21784 count = script_getnum(st,2);
21787 return SCRIPT_CMD_SUCCESS;
21789 duration = script_getnum(st,3);
21791 for (i = 0; i < count; i++)
21792 pc_addspiritball(sd,duration,10);
21793 return SCRIPT_CMD_SUCCESS;
21796 /** Deletes the spirit ball(s) from player
21797 * delspiritball <count>{,<char_id>};
21798 * @param count How many spirit ball will be deleted
21799 * @param char_id Target player (Optional)
21802 BUILDIN_FUNC(delspiritball) {
21804 struct map_session_data *sd = NULL;
21806 if (script_hasdata(st,3)) {
21807 if (!script_isstring(st,3))
21808 sd = map_charid2sd(script_getnum(st,3));
21810 sd = map_nick2sd(script_getstr(st,3),false);
21815 return SCRIPT_CMD_FAILURE;
21817 count = script_getnum(st,2);
21822 pc_delspiritball(sd,count,0);
21823 return SCRIPT_CMD_SUCCESS;
21826 /** Counts the spirit ball that player has
21827 * countspiritball {<char_id>};
21828 * @param char_id Target player (Optional)
21831 BUILDIN_FUNC(countspiritball) {
21832 struct map_session_data *sd;
21834 if (script_hasdata(st,2)) {
21835 if (!script_isstring(st,2))
21836 sd = map_charid2sd(script_getnum(st,2));
21838 sd = map_nick2sd(script_getstr(st,2),false);
21843 return SCRIPT_CMD_FAILURE;
21844 script_pushint(st,sd->spiritball);
21845 return SCRIPT_CMD_SUCCESS;
21848 /** Merges separated stackable items because of guid
21849 * mergeitem {<char_id>};
21850 * @param char_id Char ID (Optional)
21853 BUILDIN_FUNC(mergeitem) {
21854 struct map_session_data *sd;
21856 if (!script_charid2sd(2, sd))
21857 return SCRIPT_CMD_FAILURE;
21859 clif_merge_item_open(sd);
21860 return SCRIPT_CMD_SUCCESS;
21863 /** Merges separated stackable items because of guid (Unofficial)
21864 * mergeitem2 {<item_id>,{<char_id>}};
21865 * mergeitem2 {"<item name>",{<char_id>}};
21866 * @param item Item ID/Name for merging specific item (Optional)
21869 BUILDIN_FUNC(mergeitem2) {
21870 struct map_session_data *sd;
21871 struct item *items = NULL;
21872 uint16 i, count = 0, nameid = 0;
21874 if (!script_charid2sd(3, sd))
21875 return SCRIPT_CMD_FAILURE;
21877 if (script_hasdata(st, 2)) {
21878 struct script_data *data = script_getdata(st, 2);
21881 if (data_isstring(data)) {// "<item name>"
21882 const char *name = conv_str(st,data);
21883 struct item_data *id;
21884 if (!(id = itemdb_searchname(name))) {
21885 ShowError("buildin_mergeitem2: Nonexistant item %s requested.\n", name);
21886 script_pushint(st, count);
21887 return SCRIPT_CMD_FAILURE;
21889 nameid = id->nameid;
21891 else if (data_isint(data)) {// <item id>
21892 nameid = conv_num(st,data);
21893 if (!itemdb_exists(nameid)) {
21894 ShowError("buildin_mergeitem: Nonexistant item %d requested.\n", nameid);
21895 script_pushint(st, count);
21896 return SCRIPT_CMD_FAILURE;
21901 for (i = 0; i < MAX_INVENTORY; i++) {
21902 struct item *it = &sd->inventory.u.items_inventory[i];
21904 if (!it || !it->unique_id || it->expire_time || !itemdb_isstackable(it->nameid))
21906 if ((!nameid || (nameid == it->nameid))) {
21909 CREATE(items, struct item, 1);
21910 memcpy(&items[count++], it, sizeof(struct item));
21911 pc_delitem(sd, i, it->amount, 0, 0, LOG_TYPE_NPC);
21914 for (k = 0; k < count; k++) {
21916 if (&items[k] && items[k].nameid == it->nameid && items[k].bound == it->bound && memcmp(items[k].card, it->card, sizeof(it->card)) == 0) {
21917 items[k].amount += it->amount;
21918 pc_delitem(sd, i, it->amount, 0, 0, LOG_TYPE_NPC);
21924 RECREATE(items, struct item, count+1);
21925 memcpy(&items[count++], it, sizeof(struct item));
21926 pc_delitem(sd, i, it->amount, 0, 0, LOG_TYPE_NPC);
21931 if (!items) // Nothing todo here
21932 return SCRIPT_CMD_SUCCESS;
21934 // Retrieve the items
21935 for (i = 0; i < count; i++) {
21940 items[i].unique_id = 0;
21941 if ((flag = pc_additem(sd, &items[i], items[i].amount, LOG_TYPE_NPC)))
21942 clif_additem(sd, i, items[i].amount, flag);
21945 script_pushint(st, count);
21946 return SCRIPT_CMD_SUCCESS;
21950 * Update an entry from NPC shop.
21951 * npcshopupdate "<name>",<item_id>,<price>{,<stock>}
21953 BUILDIN_FUNC(npcshopupdate) {
21954 const char* npcname = script_getstr(st, 2);
21955 struct npc_data* nd = npc_name2id(npcname);
21956 uint16 nameid = script_getnum(st, 3);
21957 int price = script_getnum(st, 4);
21958 #if PACKETVER >= 20131223
21959 uint16 stock = script_hasdata(st,5) ? script_getnum(st,5) : 0;
21963 if( !nd || ( nd->subtype != NPCTYPE_SHOP && nd->subtype != NPCTYPE_CASHSHOP && nd->subtype != NPCTYPE_ITEMSHOP && nd->subtype != NPCTYPE_POINTSHOP && nd->subtype != NPCTYPE_MARKETSHOP ) ) { // Not found.
21964 script_pushint(st,0);
21965 return SCRIPT_CMD_FAILURE;
21968 if (!nd->u.shop.count) {
21969 ShowError("buildin_npcshopupdate: Attempt to update empty shop from '%s'.\n", nd->exname);
21970 script_pushint(st,0);
21971 return SCRIPT_CMD_FAILURE;
21974 for (i = 0; i < nd->u.shop.count; i++) {
21975 if (nd->u.shop.shop_item[i].nameid == nameid) {
21978 nd->u.shop.shop_item[i].value = price;
21979 #if PACKETVER >= 20131223
21980 if (nd->subtype == NPCTYPE_MARKETSHOP) {
21981 nd->u.shop.shop_item[i].qty = stock;
21982 npc_market_tosql(nd->exname, &nd->u.shop.shop_item[i]);
21988 script_pushint(st,1);
21989 return SCRIPT_CMD_SUCCESS;
21993 BUILDIN_FUNC(clan_join){
21994 struct map_session_data *sd;
21995 int clan_id = script_getnum(st,2);
21997 if( !script_charid2sd( 3, sd ) ){
21998 script_pushint(st, false);
21999 return SCRIPT_CMD_FAILURE;
22002 if( clan_member_join( sd, clan_id, sd->status.account_id, sd->status.char_id ) )
22003 script_pushint(st, true);
22005 script_pushint(st, false);
22007 return SCRIPT_CMD_SUCCESS;
22010 BUILDIN_FUNC(clan_leave){
22011 struct map_session_data *sd;
22013 if( !script_charid2sd( 2, sd ) ){
22014 script_pushint(st, false);
22015 return SCRIPT_CMD_FAILURE;
22018 if( clan_member_leave( sd, sd->status.clan_id, sd->status.account_id, sd->status.char_id ) )
22019 script_pushint(st, true);
22021 script_pushint(st, false);
22023 return SCRIPT_CMD_SUCCESS;
22027 * Get rid from running script.
22028 * getattachedrid();
22030 BUILDIN_FUNC(getattachedrid) {
22031 script_pushint(st, st->rid);
22032 return SCRIPT_CMD_SUCCESS;
22036 * Get variable from a Player
22037 * getvar <variable>,<char_id>;
22039 BUILDIN_FUNC(getvar) {
22040 int char_id = script_getnum(st, 3);
22041 struct map_session_data *sd = map_charid2sd(char_id);
22042 struct script_data *data = NULL;
22043 const char *name = NULL;
22046 ShowError("buildin_getvar: No player found with char id '%d'.\n", char_id);
22047 return SCRIPT_CMD_FAILURE;
22050 data = script_getdata(st, 2);
22051 if (!data_isreference(data)) {
22052 ShowError("buildin_getvar: Not a variable\n");
22053 script_reportdata(data);
22054 script_pushnil(st);
22056 return SCRIPT_CMD_FAILURE;
22059 name = reference_getname(data);
22061 if (reference_toparam(data)) {
22062 ShowError("buildin_getvar: '%s' is a parameter - please use readparam instead\n", name);
22063 script_reportdata(data);
22064 script_pushnil(st);
22066 return SCRIPT_CMD_FAILURE;
22069 if (name[0] == '.' || name[0] == '$' || name[0] == '\'') { // Not a PC variable
22070 ShowError("buildin_getvar: Invalid scope (not PC variable)\n");
22071 script_reportdata(data);
22072 script_pushnil(st);
22074 return SCRIPT_CMD_FAILURE;
22077 get_val_(st, data, sd);
22078 if (data_isint(data))
22079 script_pushint(st, conv_num_(st, data, sd));
22081 script_pushstrcopy(st, conv_str_(st, data, sd));
22083 push_val2(st->stack, C_NAME, reference_getuid(data), reference_getref(data));
22084 return SCRIPT_CMD_SUCCESS;
22088 * Display script message
22089 * showscript "<message>"{,<GID>,<flag>};
22090 * @param flag: Specify target
22091 * AREA - Message is sent to players in the vicinity of the source (default).
22092 * SELF - Message is sent only to player attached.
22094 BUILDIN_FUNC(showscript) {
22095 struct block_list *bl = NULL;
22096 const char *msg = script_getstr(st,2);
22098 send_target target = AREA;
22100 if (script_hasdata(st,3)) {
22101 id = script_getnum(st,3);
22102 bl = map_id2bl(id);
22105 bl = st->rid ? map_id2bl(st->rid) : map_id2bl(st->oid);
22109 ShowError("buildin_showscript: Script not attached. (id=%d, rid=%d, oid=%d)\n", id, st->rid, st->oid);
22110 script_pushint(st,0);
22111 return SCRIPT_CMD_FAILURE;
22114 if (script_hasdata(st, 4)) {
22115 target = static_cast<send_target>(script_getnum(st, 4));
22116 if (target == SELF && map_id2sd(bl->id) == NULL) {
22117 ShowWarning("script: showscript: self can't be used for non-players objects.\n");
22118 return SCRIPT_CMD_FAILURE;
22122 clif_showscript(bl, msg, target);
22124 script_pushint(st,1);
22125 return SCRIPT_CMD_SUCCESS;
22129 * Ignore the SECURE_NPCTIMEOUT function.
22130 * ignoretimeout <flag>{,<char_id>};
22132 BUILDIN_FUNC(ignoretimeout)
22134 #ifdef SECURE_NPCTIMEOUT
22135 struct map_session_data *sd = NULL;
22137 if (script_hasdata(st,3)) {
22138 if (!script_isstring(st,3))
22139 sd = map_charid2sd(script_getnum(st,3));
22141 sd = map_nick2sd(script_getstr(st,3),false);
22146 return SCRIPT_CMD_FAILURE;
22148 sd->state.ignoretimeout = script_getnum(st,2) > 0;
22150 return SCRIPT_CMD_SUCCESS;
22154 * geteleminfo <type>{,<char_id>};
22156 BUILDIN_FUNC(geteleminfo) {
22157 TBL_ELEM *ed = NULL;
22159 int type = script_getnum(st,2);
22161 if (!script_charid2sd(3, sd)) {
22162 script_pushint(st, 0);
22163 return SCRIPT_CMD_SUCCESS;
22166 if (!(ed = sd->ed)) {
22167 //ShowDebug("buildin_geteleminfo: Player doesn't have Elemental.\n");
22168 script_pushint(st, 0);
22169 return SCRIPT_CMD_SUCCESS;
22173 case 0: script_pushint(st, ed->elemental.elemental_id); break;
22174 case 1: script_pushint(st, ed->bl.id); break;
22176 ShowError("buildin_geteleminfo: Invalid type '%d'.\n", type);
22177 script_pushint(st, 0);
22178 return SCRIPT_CMD_FAILURE;
22181 return SCRIPT_CMD_SUCCESS;
22186 * Set the quest info of quest_id only showed on player in level range.
22187 * setquestinfo_level <quest_id>,<min_level>,<max_level>
22190 BUILDIN_FUNC(setquestinfo_level) {
22191 TBL_NPC* nd = map_id2nd(st->oid);
22192 int quest_id = script_getnum(st, 2);
22193 struct questinfo *qi = map_has_questinfo(nd->bl.m, nd, quest_id);
22196 ShowError("buildin_setquestinfo_level: Quest with ID '%d' is not defined yet.\n", quest_id);
22197 return SCRIPT_CMD_FAILURE;
22200 qi->min_level = script_getnum(st, 3);
22201 qi->max_level = script_getnum(st, 4);
22202 if (!qi->max_level)
22203 qi->max_level = MAX_LEVEL;
22205 return SCRIPT_CMD_SUCCESS;
22209 * Set the quest info of quest_id only showed for player that has quest criteria
22210 * setquestinfo_req <quest_id>,<quest_req_id>,<state>{,<quest_req_id>,<state>,...};
22213 BUILDIN_FUNC(setquestinfo_req) {
22214 TBL_NPC* nd = map_id2nd(st->oid);
22215 int quest_id = script_getnum(st, 2);
22216 struct questinfo *qi = map_has_questinfo(nd->bl.m, nd, quest_id);
22218 uint8 num = script_lastdata(st);
22221 ShowError("buildin_setquestinfo_req: Quest with ID '%d' is not defined yet.\n", quest_id);
22222 return SCRIPT_CMD_FAILURE;
22225 if (quest_search(quest_id) == &quest_dummy) {
22226 ShowError("buildin_setquestinfo_req: Quest with ID '%d' is not found in Quest DB.\n", quest_id);
22227 return SCRIPT_CMD_FAILURE;
22231 ShowError("buildin_setquestinfo_req: Odd number of parameters(%d) - pairs of requirements are expected.\n", num-2);
22232 return SCRIPT_CMD_FAILURE;
22235 for (i = 3; i <= num; i += 2) {
22236 RECREATE(qi->req, struct questinfo_req, qi->req_count+1);
22237 qi->req[qi->req_count].quest_id = script_getnum(st, i);
22238 qi->req[qi->req_count].state = (script_getnum(st, i+1) >= 2) ? 2 : (script_getnum(st, i+1) <= 0) ? 0 : 1;
22242 return SCRIPT_CMD_SUCCESS;
22246 * Set the quest info of quest_id only showed for player that has specified Job
22247 * setquestinfo_job <quest_id>,<job>{,<job>...};
22250 BUILDIN_FUNC(setquestinfo_job) {
22251 TBL_NPC* nd = map_id2nd(st->oid);
22252 int quest_id = script_getnum(st, 2);
22253 struct questinfo *qi = map_has_questinfo(nd->bl.m, nd, quest_id);
22256 uint8 num = script_lastdata(st)+1;
22259 ShowError("buildin_setquestinfo_job: Quest with ID '%d' is not defined yet.\n", quest_id);
22260 return SCRIPT_CMD_FAILURE;
22263 for (i = 3; i < num; i++) {
22264 job_id = script_getnum(st, i);
22265 if (!pcdb_checkid(job_id)) {
22266 ShowError("buildin_setquestinfo_job: Invalid job id '%d' in Quest with ID %d.\n", job_id, quest_id);
22269 buildin_questinfo_setjob(qi, job_id);
22272 return SCRIPT_CMD_SUCCESS;
22276 * opendressroom(<flag>{,<char_id>});
22278 BUILDIN_FUNC(opendressroom)
22280 #if PACKETVER >= 20150513
22284 if( script_hasdata(st,2) )
22285 flag = script_getnum(st,2);
22287 if (!script_charid2sd(3, sd))
22288 return SCRIPT_CMD_FAILURE;
22290 clif_dressing_room(sd, flag);
22292 return SCRIPT_CMD_SUCCESS;
22294 return SCRIPT_CMD_FAILURE;
22299 * navigateto("<map>"{,<x>,<y>,<flag>,<hide_window>,<monster_id>,<char_id>});
22301 BUILDIN_FUNC(navigateto){
22302 #if PACKETVER >= 20111010
22304 const char *mapname;
22305 uint16 x = 0, y = 0, monster_id = 0;
22306 uint8 flag = NAV_KAFRA_AND_AIRSHIP;
22307 bool hideWindow = true;
22309 mapname = script_getstr(st,2);
22311 if( script_hasdata(st,3) )
22312 x = script_getnum(st,3);
22313 if( script_hasdata(st,4) )
22314 y = script_getnum(st,4);
22315 if( script_hasdata(st,5) )
22316 flag = (uint8)script_getnum(st,5);
22317 if( script_hasdata(st,6) )
22318 hideWindow = script_getnum(st,6) ? true : false;
22319 if( script_hasdata(st,7) )
22320 monster_id = script_getnum(st,7);
22322 if (!script_charid2sd(8, sd))
22323 return SCRIPT_CMD_FAILURE;
22325 clif_navigateTo(sd,mapname,x,y,flag,hideWindow,monster_id);
22327 return SCRIPT_CMD_SUCCESS;
22329 return SCRIPT_CMD_FAILURE;
22334 * adopt("<parent_name>","<baby_name>");
22335 * adopt(<parent_id>,<baby_id>);
22336 * https://rathena.org/board/topic/104014-suggestion-add-adopt-or-etc/
22338 BUILDIN_FUNC(adopt)
22341 struct script_data *data;
22342 enum adopt_responses response;
22344 data = script_getdata(st, 2);
22347 if (data_isstring(data)) {
22348 const char *name = conv_str(st, data);
22350 sd = map_nick2sd(name,false);
22352 ShowError("buildin_adopt: Non-existant parent character %s requested.\n", name);
22353 return SCRIPT_CMD_FAILURE;
22355 } else if (data_isint(data)) {
22356 uint32 char_id = conv_num(st, data);
22358 sd = map_charid2sd(char_id);
22360 ShowError("buildin_adopt: Non-existant parent character %d requested.\n", char_id);
22361 return SCRIPT_CMD_FAILURE;
22364 ShowError("buildin_adopt: Invalid data type for argument #1 (%d).", data->type);
22365 return SCRIPT_CMD_FAILURE;
22368 data = script_getdata(st, 3);
22371 if (data_isstring(data)) {
22372 const char *name = conv_str(st, data);
22374 b_sd = map_nick2sd(name,false);
22375 if (b_sd == NULL) {
22376 ShowError("buildin_adopt: Non-existant baby character %s requested.\n", name);
22377 return SCRIPT_CMD_FAILURE;
22379 } else if (data_isint(data)) {
22380 uint32 char_id = conv_num(st, data);
22382 b_sd = map_charid2sd(char_id);
22383 if (b_sd == NULL) {
22384 ShowError("buildin_adopt: Non-existant baby character %d requested.\n", char_id);
22385 return SCRIPT_CMD_FAILURE;
22388 ShowError("buildin_adopt: Invalid data type for argument #2 (%d).", data->type);
22389 return SCRIPT_CMD_FAILURE;
22392 response = pc_try_adopt(sd, map_charid2sd(sd->status.partner_id), b_sd);
22394 if (response == ADOPT_ALLOWED) {
22395 TBL_PC *p_sd = map_charid2sd(sd->status.partner_id);
22397 b_sd->adopt_invite = sd->status.account_id;
22398 clif_Adopt_request(b_sd, sd, p_sd->status.account_id);
22399 script_pushint(st, ADOPT_ALLOWED);
22400 return SCRIPT_CMD_SUCCESS;
22403 script_pushint(st, response);
22404 return SCRIPT_CMD_FAILURE;
22408 * Returns the minimum or maximum of all the given parameters for integer variables.
22410 * min( <value or array>{,value or array 2,...} );
22411 * minimum( <value or array>{,value or array 2,...} );
22412 * max( <value or array>{,value or array 2,...} );
22413 * maximum( <value or array>{,value or array 2,...} );
22415 BUILDIN_FUNC(minmax){
22416 char *functionname;
22419 // Function pointer for our comparison function (either min or max at the moment)
22420 int32 (*func)(int32, int32);
22422 // Get the real function name
22423 functionname = script_getfuncname(st);
22425 // Our data should start at offset 2
22428 if( !script_hasdata( st, i ) ){
22429 ShowError( "buildin_%s: no arguments given!\n", functionname );
22431 return SCRIPT_CMD_FAILURE;
22434 if( strnicmp( functionname, "min", strlen( "min" ) ) == 0 ){
22437 }else if( strnicmp( functionname, "max", strlen( "max" ) ) == 0 ){
22441 ShowError( "buildin_%s: Unknown call case for min/max!\n", functionname );
22443 return SCRIPT_CMD_FAILURE;
22446 // As long as we have data on our script stack
22447 while( script_hasdata(st,i) ){
22448 struct script_data *data;
22450 // Get the next piece of data from the script stack
22451 data = script_getdata( st, i );
22453 // Is the current parameter a single integer?
22454 if( data_isint( data ) ){
22455 value = func( value, script_getnum( st, i ) );
22456 // Is the current parameter an array variable?
22457 }else if( data_isreference( data ) ){
22459 struct map_session_data* sd;
22460 unsigned int start, end;
22462 // Get the name of the variable
22463 name = reference_getname(data);
22465 // Check if it's a string variable
22466 if( is_string_variable( name ) ){
22467 ShowError( "buildin_%s: illegal type, need integer!\n", functionname );
22468 script_reportdata( data );
22470 return SCRIPT_CMD_FAILURE;
22473 // Get the session data, if a player is attached
22474 sd = st->rid ? map_id2sd(st->rid) : NULL;
22476 // Try to find the array's source pointer
22477 if( !script_array_src( st, sd, name, reference_getref( data ) ) ){
22478 ShowError( "buildin_%s: not a array!\n", functionname );
22479 script_reportdata( data );
22481 return SCRIPT_CMD_FAILURE;
22484 // Get the start and end indices of the array
22485 start = reference_getindex( data );
22486 end = script_array_highest_key( st, sd, name, reference_getref( data ) );
22488 // Skip empty arrays
22492 // For getting the values we need the id of the array
22493 id = reference_getid( data );
22495 // Loop through each value stored in the array
22496 for( ; start < end; start++ ){
22497 value = func( value, (int32)__64BPRTSIZE( get_val2( st, reference_uid( id, start ), reference_getref( data ) ) ) );
22499 script_removetop( st, -1, 0 );
22503 ShowError( "buildin_%s: not a supported data type!\n", functionname );
22504 script_reportdata( data );
22506 return SCRIPT_CMD_FAILURE;
22509 // Continue with the next stack entry
22513 script_pushint( st, value );
22515 return SCRIPT_CMD_SUCCESS;
22519 * Safety Base/Job EXP addition than using `set BaseExp,n;` or `set JobExp,n;`
22520 * Unlike `getexp` that affected by some adjustments.
22521 * getexp2 <base_exp>,<job_exp>{,<char_id>};
22524 BUILDIN_FUNC(getexp2) {
22526 int base_exp = script_getnum(st, 2);
22527 int job_exp = script_getnum(st, 3);
22529 if (!script_charid2sd(4, sd))
22530 return SCRIPT_CMD_FAILURE;
22532 if (base_exp == 0 && job_exp == 0)
22533 return SCRIPT_CMD_SUCCESS;
22536 pc_gainexp(sd, NULL, base_exp, 0, 2);
22537 else if (base_exp < 0)
22538 pc_lostexp(sd, base_exp * -1, 0);
22541 pc_gainexp(sd, NULL, 0, job_exp, 2);
22542 else if (job_exp < 0)
22543 pc_lostexp(sd, 0, job_exp * -1);
22544 return SCRIPT_CMD_SUCCESS;
22548 * Force stat recalculation of sd
22550 * @author [secretdataz]
22552 BUILDIN_FUNC(recalculatestat) {
22555 if (!script_rid2sd(sd))
22556 return SCRIPT_CMD_FAILURE;
22558 status_calc_pc(sd, SCO_FORCE);
22559 return SCRIPT_CMD_SUCCESS;
22562 BUILDIN_FUNC(hateffect){
22563 #if PACKETVER >= 20150513
22564 struct map_session_data* sd;
22568 if( !script_rid2sd(sd) )
22569 return SCRIPT_CMD_FAILURE;
22571 effectID = script_getnum(st,2);
22572 enable = script_getnum(st,3) ? true : false;
22574 ARR_FIND( 0, sd->hatEffectCount, i, sd->hatEffectIDs[i] == effectID );
22577 if( i < sd->hatEffectCount ){
22578 return SCRIPT_CMD_SUCCESS;
22581 RECREATE(sd->hatEffectIDs,uint32,sd->hatEffectCount+1);
22582 sd->hatEffectIDs[sd->hatEffectCount] = effectID;
22583 sd->hatEffectCount++;
22585 if( i == sd->hatEffectCount ){
22586 return SCRIPT_CMD_SUCCESS;
22589 for( ; i < sd->hatEffectCount - 1; i++ ){
22590 sd->hatEffectIDs[i] = sd->hatEffectIDs[i+1];
22593 sd->hatEffectCount--;
22595 if( !sd->hatEffectCount ){
22596 aFree(sd->hatEffectIDs);
22597 sd->hatEffectIDs = NULL;
22601 if( !sd->state.connect_new ){
22602 clif_hat_effect_single( sd, effectID, enable );
22606 return SCRIPT_CMD_SUCCESS;
22610 * Retrieves param of current random option. Intended for random option script only.
22611 * getrandomoptinfo(<type>);
22612 * @author [secretdataz]
22614 BUILDIN_FUNC(getrandomoptinfo) {
22615 struct map_session_data *sd;
22617 if (script_rid2sd(sd) && current_equip_item_index != -1 && current_equip_opt_index != -1 && sd->inventory.u.items_inventory[current_equip_item_index].option[current_equip_opt_index].id) {
22618 int param = script_getnum(st, 2);
22622 val = sd->inventory.u.items_inventory[current_equip_item_index].option[current_equip_opt_index].id;
22625 val = sd->inventory.u.items_inventory[current_equip_item_index].option[current_equip_opt_index].value;
22628 val = sd->inventory.u.items_inventory[current_equip_item_index].option[current_equip_opt_index].param;
22631 ShowWarning("buildin_getrandomoptinfo: Invalid attribute type %d (Max %d).\n", param, MAX_ITEM_RDM_OPT);
22635 script_pushint(st, val);
22638 script_pushint(st, 0);
22640 return SCRIPT_CMD_SUCCESS;
22644 * Retrieves a random option on an equipped item.
22645 * getequiprandomoption(<equipment slot>,<index>,<type>{,<char id>});
22646 * @author [secretdataz]
22648 BUILDIN_FUNC(getequiprandomoption) {
22649 struct map_session_data *sd;
22652 int pos = script_getnum(st, 2);
22653 int index = script_getnum(st, 3);
22654 int type = script_getnum(st, 4);
22655 if (!script_charid2sd(5, sd)) {
22656 script_pushint(st, -1);
22657 return SCRIPT_CMD_FAILURE;
22659 if (index < 0 || index >= MAX_ITEM_RDM_OPT) {
22660 ShowError("buildin_getequiprandomoption: Invalid random option index %d.\n", index);
22661 script_pushint(st, -1);
22662 return SCRIPT_CMD_FAILURE;
22664 if (equip_index_check(pos))
22665 i = pc_checkequip(sd, equip_bitmask[pos]);
22667 ShowError("buildin_getequiprandomoption: No item equipped at pos %d (CID=%d/AID=%d).\n", pos, sd->status.char_id, sd->status.account_id);
22668 script_pushint(st, -1);
22669 return SCRIPT_CMD_FAILURE;
22674 val = sd->inventory.u.items_inventory[i].option[index].id;
22677 val = sd->inventory.u.items_inventory[i].option[index].value;
22680 val = sd->inventory.u.items_inventory[i].option[index].param;
22683 ShowWarning("buildin_getequiprandomoption: Invalid attribute type %d (Max %d).\n", type, MAX_ITEM_RDM_OPT);
22687 script_pushint(st, val);
22688 return SCRIPT_CMD_SUCCESS;
22692 * Adds a random option on a random option slot on an equipped item and overwrites
22693 * existing random option in the process.
22694 * setrandomoption(<equipment slot>,<index>,<id>,<value>,<param>{,<char id>});
22695 * @author [secretdataz]
22697 BUILDIN_FUNC(setrandomoption) {
22698 struct map_session_data *sd;
22699 struct s_random_opt_data *opt;
22700 int pos, index, id, value, param, ep;
22702 if (!script_charid2sd(7, sd))
22703 return SCRIPT_CMD_FAILURE;
22704 pos = script_getnum(st, 2);
22705 index = script_getnum(st, 3);
22706 id = script_getnum(st, 4);
22707 value = script_getnum(st, 5);
22708 param = script_getnum(st, 6);
22710 if ((opt = itemdb_randomopt_exists((short)id)) == NULL) {
22711 ShowError("buildin_setrandomoption: Random option ID %d does not exists.\n", id);
22712 script_pushint(st, 0);
22713 return SCRIPT_CMD_FAILURE;
22715 if (index < 0 || index >= MAX_ITEM_RDM_OPT) {
22716 ShowError("buildin_setrandomoption: Invalid random option index %d.\n", index);
22717 script_pushint(st, 0);
22718 return SCRIPT_CMD_FAILURE;
22720 if (equip_index_check(pos))
22721 i = pc_checkequip(sd, equip_bitmask[pos]);
22723 ep = sd->inventory.u.items_inventory[i].equip;
22724 log_pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->inventory.u.items_inventory[i]);
22725 pc_unequipitem(sd, i, 2);
22726 sd->inventory.u.items_inventory[i].option[index].id = id;
22727 sd->inventory.u.items_inventory[i].option[index].value = value;
22728 sd->inventory.u.items_inventory[i].option[index].param = param;
22729 clif_delitem(sd, i, 1, 3);
22730 log_pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->inventory.u.items_inventory[i]);
22731 clif_additem(sd, i, 1, 0);
22732 pc_equipitem(sd, i, ep);
22733 script_pushint(st, 1);
22734 return SCRIPT_CMD_SUCCESS;
22737 ShowError("buildin_setrandomoption: No item equipped at pos %d (CID=%d/AID=%d).\n", pos, sd->status.char_id, sd->status.account_id);
22738 script_pushint(st, 0);
22739 return SCRIPT_CMD_FAILURE;
22742 /// Returns the number of stat points needed to change the specified stat by val.
22743 /// If val is negative, returns the number of stat points that would be needed to
22744 /// raise the specified stat from (current value - val) to current value.
22745 /// *needed_status_point(<type>,<val>{,<char id>});
22746 /// @author [secretdataz]
22747 BUILDIN_FUNC(needed_status_point) {
22748 struct map_session_data *sd;
22750 if (!script_charid2sd(4, sd))
22751 return SCRIPT_CMD_FAILURE;
22752 type = script_getnum(st, 2);
22753 val = script_getnum(st, 3);
22755 script_pushint(st, pc_need_status_point(sd, type, val));
22756 return SCRIPT_CMD_SUCCESS;
22760 * jobcanentermap("<mapname>"{,<JobID>});
22761 * Check if (player with) JobID can enter the map.
22762 * @param mapname Map name
22763 * @param JobID Player's JobID (optional)
22765 BUILDIN_FUNC(jobcanentermap) {
22766 const char *mapname = script_getstr(st, 2);
22767 int mapidx = mapindex_name2id(mapname), m = -1;
22771 if (!mapidx) {// Invalid map
22772 script_pushint(st, false);
22773 return SCRIPT_CMD_FAILURE;
22775 m = map_mapindex2mapid(mapidx);
22776 if (m == -1) { // Map is on different map server
22777 ShowError("buildin_jobcanentermap: Map '%s' is not found in this server.\n", mapname);
22778 script_pushint(st, false);
22779 return SCRIPT_CMD_FAILURE;
22782 if (script_hasdata(st, 3)) {
22783 jobid = script_getnum(st, 3);
22785 if (!script_rid2sd(sd)) {
22786 script_pushint(st, false);
22787 return SCRIPT_CMD_FAILURE;
22789 jobid = sd->status.class_;
22792 script_pushint(st, pc_job_can_entermap((enum e_job)jobid, m, sd ? sd->group_level : 0));
22793 return SCRIPT_CMD_SUCCESS;
22797 * Return alliance information between the two guilds.
22798 * getguildalliance(<guild id1>,<guild id2>);
22800 * -2 - Guild ID1 does not exist
22801 * -1 - Guild ID2 does not exist
22802 * 0 - Both guilds have no relation OR guild ID aren't given
22803 * 1 - Both guilds are allies
22804 * 2 - Both guilds are antagonists
22806 BUILDIN_FUNC(getguildalliance)
22808 struct guild *guild_data1, *guild_data2;
22809 int guild_id1, guild_id2, i = 0;
22811 guild_id1 = script_getnum(st,2);
22812 guild_id2 = script_getnum(st,3);
22814 if (guild_id1 < 1 || guild_id2 < 1) {
22815 script_pushint(st, 0);
22816 return SCRIPT_CMD_SUCCESS;
22819 if (guild_id1 == guild_id2) {
22820 script_pushint(st, 1);
22821 return SCRIPT_CMD_SUCCESS;
22824 guild_data1 = guild_search(guild_id1);
22825 guild_data2 = guild_search(guild_id2);
22827 if (guild_data1 == NULL) {
22828 ShowWarning("buildin_getguildalliance: Requesting non-existent GuildID1 '%d'.\n", guild_id1);
22829 script_pushint(st, -2);
22830 return SCRIPT_CMD_FAILURE;
22832 if (guild_data2 == NULL) {
22833 ShowWarning("buildin_getguildalliance: Requesting non-existent GuildID2 '%d'.\n", guild_id2);
22834 script_pushint(st, -1);
22835 return SCRIPT_CMD_FAILURE;
22838 ARR_FIND(0, MAX_GUILDALLIANCE, i, guild_data1->alliance[i].guild_id == guild_id2);
22839 if (i == MAX_GUILDALLIANCE) {
22840 script_pushint(st, 0);
22841 return SCRIPT_CMD_SUCCESS;
22844 if (guild_data1->alliance[i].opposition)
22845 script_pushint(st, 2);
22847 script_pushint(st, 1);
22848 return SCRIPT_CMD_SUCCESS;
22852 * openstorage2 <storage_id>,<mode>{,<account_id>}
22853 * mode @see enum e_storage_mode
22855 BUILDIN_FUNC(openstorage2) {
22856 int stor_id = script_getnum(st, 2);
22859 if (!script_accid2sd(4, sd)) {
22860 script_pushint(st, 0);
22861 return SCRIPT_CMD_FAILURE;
22864 if (!storage_exists(stor_id)) {
22865 ShowError("buildin_openstorage2: Invalid storage_id '%d'!\n", stor_id);
22866 return SCRIPT_CMD_FAILURE;
22869 script_pushint(st, storage_premiumStorage_load(sd, stor_id, script_getnum(st, 3)));
22870 return SCRIPT_CMD_SUCCESS;
22874 * Create a new channel
22875 * channel_create "<chname>","<alias>"{,"<password>"{<option>{,<delay>{,<color>{,<char_id>}}}}};
22878 BUILDIN_FUNC(channel_create) {
22879 struct Channel tmp_chan, *ch = NULL;
22880 const char *chname = script_getstr(st,2), *pass = NULL;
22881 int i = channel_chk((char*)chname, NULL, 3);
22885 ShowError("buildin_channel_create: Channel name '%s' is invalid. Errno %d\n", chname, i);
22886 script_pushint(st,i);
22887 return SCRIPT_CMD_FAILURE;
22890 memset(&tmp_chan, 0, sizeof(struct Channel));
22892 if (script_hasdata(st,8)) {
22893 tmp_chan.char_id = script_getnum(st,8);
22894 if (!(sd = map_charid2sd(tmp_chan.char_id))) {
22895 ShowError("buildin_channel_create: Player with char id '%d' is not found.\n", tmp_chan.char_id);
22896 script_pushint(st,-5);
22897 return SCRIPT_CMD_FAILURE;
22899 tmp_chan.type = CHAN_TYPE_PRIVATE;
22903 tmp_chan.type = CHAN_TYPE_PUBLIC;
22907 safestrncpy(tmp_chan.name, chname+1, sizeof(tmp_chan.name));
22908 safestrncpy(tmp_chan.alias, script_getstr(st,3), sizeof(tmp_chan.alias));
22909 if (script_hasdata(st,4) && (pass = script_getstr(st,4)) && strcmpi(pass,"null") != 0)
22910 safestrncpy(tmp_chan.pass, pass, sizeof(tmp_chan.pass));
22911 if (script_hasdata(st,5))
22912 tmp_chan.opt = script_getnum(st,5);
22914 tmp_chan.opt = i ? channel_config.private_channel.opt : CHAN_OPT_BASE;
22915 if (script_hasdata(st,6))
22916 tmp_chan.msg_delay = script_getnum(st,6);
22918 tmp_chan.msg_delay = i ? channel_config.private_channel.delay : 1000;
22919 if (script_hasdata(st,7))
22920 tmp_chan.color = script_getnum(st,7);
22922 tmp_chan.color = i ? channel_config.private_channel.color : channel_getColor("Default");
22924 if (!(ch = channel_create(&tmp_chan))) {
22925 ShowError("buildin_channel_create: Cannot create channel '%s'.\n", chname);
22926 script_pushint(st,0);
22927 return SCRIPT_CMD_FAILURE;
22929 if (tmp_chan.char_id)
22930 channel_join(ch, sd);
22931 script_pushint(st,1);
22932 return SCRIPT_CMD_SUCCESS;
22936 * Set channel option
22937 * channel_setopt "<chname>",<option>,<value>;
22940 BUILDIN_FUNC(channel_setopt) {
22941 struct Channel *ch = NULL;
22942 const char *chname = script_getstr(st,2);
22943 int opt = script_getnum(st,3), value = script_getnum(st,4);
22945 if (!(ch = channel_name2channel((char *)chname, NULL, 0))) {
22946 ShowError("buildin_channel_setopt: Channel name '%s' is invalid.\n", chname);
22947 script_pushint(st,0);
22948 return SCRIPT_CMD_FAILURE;
22952 case CHAN_OPT_ANNOUNCE_SELF:
22953 case CHAN_OPT_ANNOUNCE_JOIN:
22954 case CHAN_OPT_ANNOUNCE_LEAVE:
22955 case CHAN_OPT_COLOR_OVERRIDE:
22956 case CHAN_OPT_CAN_CHAT:
22957 case CHAN_OPT_CAN_LEAVE:
22958 case CHAN_OPT_AUTOJOIN:
22964 case CHAN_OPT_MSG_DELAY:
22965 ch->msg_delay = value;
22968 ShowError("buildin_channel_setopt: Invalid option %d!\n", opt);
22969 script_pushint(st,0);
22970 return SCRIPT_CMD_FAILURE;
22973 script_pushint(st,1);
22974 return SCRIPT_CMD_SUCCESS;
22978 * Set channel color
22979 * channel_setcolor "<chname>",<color>;
22982 BUILDIN_FUNC(channel_setcolor) {
22983 struct Channel *ch = NULL;
22984 const char *chname = script_getstr(st,2);
22985 int color = script_getnum(st,3);
22987 if (!(ch = channel_name2channel((char *)chname, NULL, 0))) {
22988 ShowError("buildin_channel_setcolor: Channel name '%s' is invalid.\n", chname);
22989 script_pushint(st,0);
22990 return SCRIPT_CMD_FAILURE;
22993 ch->color = (color & 0x0000FF) << 16 | (color & 0x00FF00) | (color & 0xFF0000) >> 16;//RGB to BGR
22995 script_pushint(st,1);
22996 return SCRIPT_CMD_SUCCESS;
23000 * Set channel password
23001 * channel_setpass "<chname>","<password>";
23004 BUILDIN_FUNC(channel_setpass) {
23005 struct Channel *ch = NULL;
23006 const char *chname = script_getstr(st,2), *passwd = script_getstr(st,3);
23008 if (!(ch = channel_name2channel((char *)chname, NULL, 0))) {
23009 ShowError("buildin_channel_setpass: Channel name '%s' is invalid.\n", chname);
23010 script_pushint(st,0);
23011 return SCRIPT_CMD_FAILURE;
23014 if (!passwd || !strcmpi(passwd,"null"))
23015 memset(ch->pass, '\0', sizeof(ch->pass));
23017 safestrncpy(ch->pass, passwd, sizeof(ch->pass));
23018 script_pushint(st,1);
23019 return SCRIPT_CMD_SUCCESS;
23023 * Set authorized groups
23024 * channel_setgroup "<chname>",<group_id>{,...,<group_id>};
23027 BUILDIN_FUNC(channel_setgroup) {
23028 struct Channel *ch = NULL;
23029 const char *funcname = script_getfuncname(st), *chname = script_getstr(st,2);
23030 int i, n = 0, group = 0;
23032 if (!(ch = channel_name2channel((char *)chname, NULL, 0))) {
23033 ShowError("buildin_channel_setgroup: Channel name '%s' is invalid.\n", chname);
23034 script_pushint(st,0);
23035 return SCRIPT_CMD_FAILURE;
23038 if (funcname[strlen(funcname)-1] == '2') {
23039 struct script_data *data = script_getdata(st,3);
23040 const char *varname = reference_getname(data);
23043 if (varname[strlen(varname)-1] == '$') {
23044 ShowError("buildin_channel_setgroup: The array %s is not numeric type.\n", varname);
23045 script_pushint(st,0);
23046 return SCRIPT_CMD_FAILURE;
23049 n = script_array_highest_key(st, NULL, reference_getname(data), reference_getref(data));
23051 ShowError("buildin_channel_setgroup: No group id listed.\n");
23052 script_pushint(st,0);
23053 return SCRIPT_CMD_FAILURE;
23059 ch->group_count = 0;
23061 id = reference_getid(data);
23062 idx = reference_getindex(data);
23063 for (i = 0; i < n; i++) {
23064 group = (int32)__64BPRTSIZE(get_val2(st,reference_uid(id,idx+i),reference_getref(data)));
23066 script_pushint(st,1);
23067 return SCRIPT_CMD_SUCCESS;
23069 RECREATE(ch->groups, unsigned short, ++ch->group_count);
23070 ch->groups[ch->group_count-1] = group;
23071 ShowInfo("buildin_channel_setgroup: (2) Added group %d. Num: %d\n", ch->groups[ch->group_count-1], ch->group_count);
23075 group = script_getnum(st,3);
23076 n = script_lastdata(st)-1;
23079 ShowError("buildin_channel_setgroup: Please input at least 1 group_id.\n");
23080 script_pushint(st,0);
23081 return SCRIPT_CMD_FAILURE;
23087 ch->group_count = 0;
23089 if (group == 0) { // Removed group list
23090 script_pushint(st,1);
23091 return SCRIPT_CMD_SUCCESS;
23094 CREATE(ch->groups, unsigned short, n);
23095 for (i = 3; i < n+2; i++) {
23096 ch->groups[ch->group_count++] = script_getnum(st,i);
23097 ShowInfo("buildin_channel_setgroup: (1) Added group %d. Num: %d\n", ch->groups[ch->group_count-1], ch->group_count);
23100 script_pushint(st,n);
23101 return SCRIPT_CMD_SUCCESS;
23105 * Send message on channel
23106 * channel_chat "<chname>","<message>"{,<color>};
23109 BUILDIN_FUNC(channel_chat) {
23110 struct Channel *ch = NULL;
23111 const char *chname = script_getstr(st,2), *msg = script_getstr(st,3);
23112 char output[CHAT_SIZE_MAX+1];
23113 unsigned long color = 0;
23115 // Check also local channels
23116 if (chname[0] != '#') { // By Map
23117 int m = mapindex_name2id(chname);
23118 if (!m || (m = map_mapindex2mapid(m)) < 0) {
23119 ShowError("buildin_channel_chat: Invalid map '%s'.\n", chname);
23120 script_pushint(st,0);
23121 return SCRIPT_CMD_FAILURE;
23123 if (!(ch = map[m].channel)) {
23124 ShowDebug("buildin_channel_chat: Map '%s' doesn't have local channel yet.\n", chname);
23125 script_pushint(st,0);
23126 return SCRIPT_CMD_SUCCESS;
23129 else if (strcmpi(chname+1,channel_config.map_tmpl.name) == 0) {
23130 TBL_NPC *nd = map_id2nd(st->oid);
23131 if (!nd || nd->bl.m == -1) {
23132 ShowError("buildin_channel_chat: Floating NPC needs map name instead '%s'.\n", chname);
23133 script_pushint(st,0);
23134 return SCRIPT_CMD_FAILURE;
23136 if (!(ch = map[nd->bl.m].channel)) {
23137 ShowDebug("buildin_channel_chat: Map '%s' doesn't have local channel yet.\n", chname);
23138 script_pushint(st,0);
23139 return SCRIPT_CMD_SUCCESS;
23142 else if (!(ch = channel_name2channel((char *)chname, NULL, 0))) {
23143 ShowError("buildin_channel_chat: Channel name '%s' is invalid.\n", chname);
23144 script_pushint(st,0);
23145 return SCRIPT_CMD_FAILURE;
23149 script_pushint(st,0);
23150 return SCRIPT_CMD_FAILURE;
23156 safesnprintf(output, CHAT_SIZE_MAX, "%s %s", ch->alias, msg);
23157 clif_channel_msg(ch,output,color);
23158 script_pushint(st,1);
23159 return SCRIPT_CMD_SUCCESS;
23163 * Ban player from a channel
23164 * channel_ban "<chname>",<char_id>;
23167 BUILDIN_FUNC(channel_ban) {
23168 struct Channel *ch = NULL;
23169 const char *chname = script_getstr(st,2);
23170 unsigned int char_id = script_getnum(st,3);
23173 if (!(ch = channel_name2channel((char *)chname, NULL, 0))) {
23174 ShowError("buildin_channel_ban: Channel name '%s' is invalid.\n", chname);
23175 script_pushint(st,0);
23176 return SCRIPT_CMD_FAILURE;
23179 if (ch->char_id == char_id) {
23180 script_pushint(st,0);
23181 return SCRIPT_CMD_SUCCESS;
23184 tsd = map_charid2sd(char_id);
23185 if (tsd && pc_has_permission(tsd,PC_PERM_CHANNEL_ADMIN)) {
23186 script_pushint(st,0);
23187 return SCRIPT_CMD_SUCCESS;
23190 if (!idb_exists(ch->banned, char_id)) {
23191 struct chan_banentry *cbe;
23192 char output[CHAT_SIZE_MAX+1];
23194 CREATE(cbe, struct chan_banentry, 1);
23195 cbe->char_id = char_id;
23197 strcpy(cbe->char_name,tsd->status.name);
23198 channel_clean(ch,tsd,0);
23199 safesnprintf(output, CHAT_SIZE_MAX, msg_txt(tsd,769), ch->alias, tsd->status.name); // %s %s has been banned.
23202 safesnprintf(output, CHAT_SIZE_MAX, msg_txt(tsd,769), ch->alias, "****"); // %s %s has been banned.
23203 idb_put(ch->banned, char_id, cbe);
23204 clif_channel_msg(ch,output,ch->color);
23207 script_pushint(st,1);
23208 return SCRIPT_CMD_SUCCESS;
23212 * Ban player from a channel
23213 * channel_unban "<chname>",<char_id>;
23216 BUILDIN_FUNC(channel_unban) {
23217 struct Channel *ch = NULL;
23218 const char *chname = script_getstr(st,2);
23219 unsigned int char_id = script_getnum(st,3);
23221 if (!(ch = channel_name2channel((char *)chname, NULL, 0))) {
23222 ShowError("buildin_channel_unban: Channel name '%s' is invalid.\n", chname);
23223 script_pushint(st,0);
23224 return SCRIPT_CMD_FAILURE;
23227 if (ch->char_id == char_id) {
23228 script_pushint(st,0);
23229 return SCRIPT_CMD_SUCCESS;
23232 if (idb_exists(ch->banned, char_id)) {
23233 char output[CHAT_SIZE_MAX+1];
23234 TBL_PC *tsd = map_charid2sd(char_id);
23236 safesnprintf(output, CHAT_SIZE_MAX, msg_txt(tsd,770), ch->alias, tsd->status.name); // %s %s has been unbanned
23238 safesnprintf(output, CHAT_SIZE_MAX, msg_txt(tsd,770), ch->alias, "****"); // %s %s has been unbanned.
23239 idb_remove(ch->banned, char_id);
23240 clif_channel_msg(ch,output,ch->color);
23243 script_pushint(st,1);
23244 return SCRIPT_CMD_SUCCESS;
23248 * Kick player from a channel
23249 * channel_kick "<chname>",<char_id>;
23250 * channel_kick "<chname>","<char_name>";
23253 BUILDIN_FUNC(channel_kick) {
23254 struct Channel *ch = NULL;
23255 const char *chname = script_getstr(st,2);
23256 struct script_data *data = script_getdata(st,3);
23257 TBL_PC *tsd = NULL;
23261 if (data_isstring(data)) {
23262 if (!(tsd = map_nick2sd(conv_str(st,data),false))) {
23263 ShowError("buildin_channel_kick: Player with nick '%s' is not online\n", conv_str(st,data));
23264 script_pushint(st,0);
23265 return SCRIPT_CMD_FAILURE;
23269 if (!(tsd = map_charid2sd(conv_num(st,data)))) {
23270 ShowError("buildin_channel_kick: Player with char_id '%d' is not online\n", conv_num(st,data));
23271 script_pushint(st,0);
23272 return SCRIPT_CMD_FAILURE;
23276 if (!(ch = channel_name2channel((char *)chname, tsd, 0))) {
23277 ShowError("buildin_channel_kick: Channel name '%s' is invalid.\n", chname);
23278 script_pushint(st,0);
23279 return SCRIPT_CMD_FAILURE;
23282 if (channel_pc_haschan(tsd, ch) < 0 || ch->char_id == tsd->status.char_id || pc_has_permission(tsd,PC_PERM_CHANNEL_ADMIN)) {
23283 script_pushint(st,0);
23284 return SCRIPT_CMD_SUCCESS;
23288 case CHAN_TYPE_ALLY: res = channel_pcquit(tsd,3); break;
23289 case CHAN_TYPE_MAP: res = channel_pcquit(tsd,4); break;
23290 default: res = channel_clean(ch,tsd,0); break;
23294 char output[CHAT_SIZE_MAX+1];
23295 safesnprintf(output, CHAT_SIZE_MAX, msg_txt(tsd,889), ch->alias, tsd->status.name); // "%s %s is kicked"
23296 clif_channel_msg(ch,output,ch->color);
23299 script_pushint(st,1);
23300 return SCRIPT_CMD_SUCCESS;
23305 * channel_delete "<chname>";
23308 BUILDIN_FUNC(channel_delete) {
23309 struct Channel *ch = NULL;
23310 const char *chname = script_getstr(st,2);
23312 if (!(ch = channel_name2channel((char *)chname, NULL, 0))) {
23313 ShowError("channel_delete: Channel name '%s' is invalid.\n", chname);
23314 script_pushint(st,-1);
23315 return SCRIPT_CMD_FAILURE;
23318 script_pushint(st,channel_delete(ch,true));
23319 return SCRIPT_CMD_SUCCESS;
23322 BUILDIN_FUNC(unloadnpc) {
23324 struct npc_data* nd;
23326 name = script_getstr(st, 2);
23327 nd = npc_name2id(name);
23330 ShowError( "buildin_unloadnpc: npc '%s' was not found.\n", name );
23331 return SCRIPT_CMD_FAILURE;
23334 npc_unload_duplicates(nd);
23335 npc_unload(nd, true);
23336 npc_read_event_script();
23338 return SCRIPT_CMD_SUCCESS;
23342 * Add an achievement to the player's log
23343 * achievementadd(<achievement ID>{,<char ID>});
23345 BUILDIN_FUNC(achievementadd) {
23346 struct map_session_data *sd;
23347 int achievement_id = script_getnum(st, 2);
23349 if (!script_charid2sd(3, sd)) {
23350 script_pushint(st, false);
23351 return SCRIPT_CMD_FAILURE;
23354 if (achievement_search(achievement_id) == &achievement_dummy) {
23355 ShowWarning("buildin_achievementadd: Achievement '%d' doesn't exist.\n", achievement_id);
23356 script_pushint(st, false);
23357 return SCRIPT_CMD_FAILURE;
23360 if( !sd->state.pc_loaded ){
23361 if( !running_npc_stat_calc_event ){
23362 ShowError( "buildin_achievementadd: call was too early. Character %s(CID: '%u') was not loaded yet.\n", sd->status.name, sd->status.char_id );
23363 return SCRIPT_CMD_FAILURE;
23365 // Simply ignore it on the first call, because the status will be recalculated after loading anyway
23366 return SCRIPT_CMD_SUCCESS;
23370 if (achievement_add(sd, achievement_id))
23371 script_pushint(st, true);
23373 script_pushint(st, false);
23374 return SCRIPT_CMD_SUCCESS;
23378 * Removes an achievement on a player.
23379 * achievementremove(<achievement ID>{,<char ID>});
23380 * Just for Atemo. ;)
23382 BUILDIN_FUNC(achievementremove) {
23383 struct map_session_data *sd;
23384 int achievement_id = script_getnum(st, 2);
23386 if (!script_charid2sd(3, sd)) {
23387 script_pushint(st, false);
23388 return SCRIPT_CMD_FAILURE;
23391 if (achievement_search(achievement_id) == &achievement_dummy) {
23392 ShowWarning("buildin_achievementremove: Achievement '%d' doesn't exist.\n", achievement_id);
23393 script_pushint(st, false);
23394 return SCRIPT_CMD_SUCCESS;
23397 if( !sd->state.pc_loaded ){
23398 if( !running_npc_stat_calc_event ){
23399 ShowError( "buildin_achievementremove: call was too early. Character %s(CID: '%u') was not loaded yet.\n", sd->status.name, sd->status.char_id );
23400 return SCRIPT_CMD_FAILURE;
23402 // Simply ignore it on the first call, because the status will be recalculated after loading anyway
23403 return SCRIPT_CMD_SUCCESS;
23407 if (achievement_remove(sd, achievement_id))
23408 script_pushint(st, true);
23410 script_pushint(st, false);
23411 return SCRIPT_CMD_SUCCESS;
23415 * Returns achievement progress
23416 * achievementinfo(<achievement ID>,<type>{,<char ID>});
23418 BUILDIN_FUNC(achievementinfo) {
23419 struct map_session_data *sd;
23420 int achievement_id = script_getnum(st, 2);
23422 if (!script_charid2sd(4, sd)) {
23423 script_pushint(st, false);
23424 return SCRIPT_CMD_FAILURE;
23427 if (achievement_search(achievement_id) == &achievement_dummy) {
23428 ShowWarning("buildin_achievementinfo: Achievement '%d' doesn't exist.\n", achievement_id);
23429 script_pushint(st, false);
23430 return SCRIPT_CMD_FAILURE;
23433 if( !sd->state.pc_loaded ){
23434 script_pushint(st, false);
23435 if( !running_npc_stat_calc_event ){
23436 ShowError( "buildin_achievementinfo: call was too early. Character %s(CID: '%u') was not loaded yet.\n", sd->status.name, sd->status.char_id );
23437 return SCRIPT_CMD_FAILURE;
23439 // Simply ignore it on the first call, because the status will be recalculated after loading anyway
23440 return SCRIPT_CMD_SUCCESS;
23444 script_pushint(st, achievement_check_progress(sd, achievement_id, script_getnum(st, 3)));
23445 return SCRIPT_CMD_SUCCESS;
23449 * Award an achievement; Ignores requirements
23450 * achievementcomplete(<achievement ID>{,<char ID>});
23452 BUILDIN_FUNC(achievementcomplete) {
23453 struct map_session_data *sd;
23454 int i, achievement_id = script_getnum(st, 2);
23456 if (!script_charid2sd(3, sd)) {
23457 script_pushint(st, false);
23458 return SCRIPT_CMD_FAILURE;
23461 if (achievement_search(achievement_id) == &achievement_dummy) {
23462 ShowWarning("buildin_achievementcomplete: Achievement '%d' doesn't exist.\n", achievement_id);
23463 script_pushint(st, false);
23464 return SCRIPT_CMD_FAILURE;
23467 if( !sd->state.pc_loaded ){
23468 if( !running_npc_stat_calc_event ){
23469 ShowError( "buildin_achievementcomplete: call was too early. Character %s(CID: '%u') was not loaded yet.\n", sd->status.name, sd->status.char_id );
23470 return SCRIPT_CMD_FAILURE;
23472 // Simply ignore it on the first call, because the status will be recalculated after loading anyway
23473 return SCRIPT_CMD_SUCCESS;
23477 ARR_FIND(0, sd->achievement_data.count, i, sd->achievement_data.achievements[i].achievement_id == achievement_id);
23478 if (i == sd->achievement_data.count)
23479 achievement_add(sd, achievement_id);
23480 achievement_update_achievement(sd, achievement_id, true);
23481 script_pushint(st, true);
23482 return SCRIPT_CMD_SUCCESS;
23486 * Checks if the achievement exists on player.
23487 * achievementexists(<achievement ID>{,<char ID>});
23489 BUILDIN_FUNC(achievementexists) {
23490 struct map_session_data *sd;
23491 int i, achievement_id = script_getnum(st, 2);
23493 if (!script_charid2sd(3, sd)) {
23494 script_pushint(st, false);
23495 return SCRIPT_CMD_FAILURE;
23498 if (achievement_search(achievement_id) == &achievement_dummy) {
23499 ShowWarning("buildin_achievementexists: Achievement '%d' doesn't exist.\n", achievement_id);
23500 script_pushint(st, false);
23501 return SCRIPT_CMD_SUCCESS;
23504 if( !sd->state.pc_loaded ){
23505 script_pushint(st, false);
23506 if( !running_npc_stat_calc_event ){
23507 ShowError( "buildin_achievementexists: call was too early. Character %s(CID: '%u') was not loaded yet.\n", sd->status.name, sd->status.char_id );
23508 return SCRIPT_CMD_FAILURE;
23510 // Simply ignore it on the first call, because the status will be recalculated after loading anyway
23511 return SCRIPT_CMD_SUCCESS;
23515 ARR_FIND(0, sd->achievement_data.count, i, sd->achievement_data.achievements[i].achievement_id == achievement_id);
23516 script_pushint(st, i < sd->achievement_data.count ? true : false);
23517 return SCRIPT_CMD_SUCCESS;
23521 * Updates an achievement's value.
23522 * achievementupdate(<achievement ID>,<type>,<value>{,<char ID>});
23524 BUILDIN_FUNC(achievementupdate) {
23525 struct map_session_data *sd;
23526 int i, achievement_id, type, value;
23528 achievement_id = script_getnum(st, 2);
23529 type = script_getnum(st, 3);
23530 value = script_getnum(st, 4);
23532 if (!script_charid2sd(5, sd)) {
23533 script_pushint(st, false);
23534 return SCRIPT_CMD_FAILURE;
23537 if (achievement_search(achievement_id) == &achievement_dummy) {
23538 ShowWarning("buildin_achievementupdate: Achievement '%d' doesn't exist.\n", achievement_id);
23539 script_pushint(st, false);
23540 return SCRIPT_CMD_FAILURE;
23543 if( !sd->state.pc_loaded ){
23544 if( !running_npc_stat_calc_event ){
23545 ShowError( "buildin_achievementupdate: call was too early. Character %s(CID: '%u') was not loaded yet.\n", sd->status.name, sd->status.char_id );
23546 return SCRIPT_CMD_FAILURE;
23548 // Simply ignore it on the first call, because the status will be recalculated after loading anyway
23549 return SCRIPT_CMD_SUCCESS;
23553 ARR_FIND(0, sd->achievement_data.count, i, sd->achievement_data.achievements[i].achievement_id == achievement_id);
23554 if (i == sd->achievement_data.count)
23555 achievement_add(sd, achievement_id);
23557 ARR_FIND(0, sd->achievement_data.count, i, sd->achievement_data.achievements[i].achievement_id == achievement_id);
23558 if (i == sd->achievement_data.count) {
23559 script_pushint(st, false);
23560 return SCRIPT_CMD_SUCCESS;
23563 if (type >= ACHIEVEINFO_COUNT1 && type <= ACHIEVEINFO_COUNT10)
23564 sd->achievement_data.achievements[i].count[type - 1] = value;
23565 else if (type == ACHIEVEINFO_COMPLETE || type == ACHIEVEINFO_COMPLETEDATE)
23566 sd->achievement_data.achievements[i].completed = value;
23567 else if (type == ACHIEVEINFO_GOTREWARD)
23568 sd->achievement_data.achievements[i].rewarded = value;
23570 ShowWarning("buildin_achievementupdate: Unknown type '%d'.\n", type);
23571 script_pushint(st, false);
23572 return SCRIPT_CMD_FAILURE;
23575 achievement_update_achievement(sd, achievement_id, false);
23576 script_pushint(st, true);
23577 return SCRIPT_CMD_SUCCESS;
23581 * Get an equipment's refine cost
23582 * getequiprefinecost(<equipment slot>,<type>,<information>{,<char id>})
23583 * returns -1 on fail
23585 BUILDIN_FUNC(getequiprefinecost) {
23586 int i = -1, slot, type, info;
23587 map_session_data *sd;
23589 slot = script_getnum(st, 2);
23590 type = script_getnum(st, 3);
23591 info = script_getnum(st, 4);
23593 if (!script_charid2sd(5, sd)) {
23594 script_pushint(st, 0);
23595 return SCRIPT_CMD_FAILURE;
23598 if (type < 0 || type >= REFINE_COST_MAX) {
23599 script_pushint(st, -1);
23600 return SCRIPT_CMD_SUCCESS;
23603 if (equip_index_check(slot))
23604 i = pc_checkequip(sd, equip_bitmask[slot]);
23607 script_pushint(st, -1);
23608 return SCRIPT_CMD_SUCCESS;
23611 int weapon_lv = sd->inventory_data[i]->wlv;
23612 if (sd->inventory_data[i]->type == IT_SHADOWGEAR) {
23613 if (sd->inventory_data[i]->equip == EQP_SHADOW_WEAPON)
23614 weapon_lv = REFINE_TYPE_WEAPON4;
23616 weapon_lv = REFINE_TYPE_SHADOW;
23619 script_pushint(st, status_get_refine_cost(weapon_lv, type, info != 0));
23621 return SCRIPT_CMD_SUCCESS;
23624 #include "../custom/script.inc"
23626 // declarations that were supposed to be exported from npc_chat.c
23627 #ifdef PCRE_SUPPORT
23628 BUILDIN_FUNC(defpattern);
23629 BUILDIN_FUNC(activatepset);
23630 BUILDIN_FUNC(deactivatepset);
23631 BUILDIN_FUNC(deletepset);
23634 /** Regular expression matching
23635 * preg_match(<pattern>,<string>{,<offset>})
23637 BUILDIN_FUNC(preg_match) {
23638 #ifdef PCRE_SUPPORT
23640 pcre_extra *pcreExtra;
23642 int erroffset, r, offset = 0;
23645 const char* pattern = script_getstr(st,2);
23646 const char* subject = script_getstr(st,3);
23647 if (script_hasdata(st,4))
23648 offset = script_getnum(st,4);
23650 re = pcre_compile(pattern, 0, &error, &erroffset, NULL);
23651 pcreExtra = pcre_study(re, 0, &error);
23653 r = pcre_exec(re, pcreExtra, subject, (int)strlen(subject), offset, 0, subStrVec, 30);
23656 if (pcreExtra != NULL)
23657 pcre_free(pcreExtra);
23660 script_pushint(st,0);
23662 script_pushint(st,(r > 0) ? r : 30 / 3);
23664 return SCRIPT_CMD_SUCCESS;
23666 ShowDebug("script:preg_match: cannot run without PCRE library enabled.\n");
23667 script_pushint(st,0);
23668 return SCRIPT_CMD_SUCCESS;
23672 /// script command definitions
23673 /// for an explanation on args, see add_buildin_func
23674 struct script_function buildin_func[] = {
23676 BUILDIN_DEF(mes,"s*"),
23677 BUILDIN_DEF(next,""),
23678 BUILDIN_DEF(close,""),
23679 BUILDIN_DEF(close2,""),
23680 BUILDIN_DEF(menu,"sl*"),
23681 BUILDIN_DEF(select,"s*"), //for future jA script compatibility
23682 BUILDIN_DEF(prompt,"s*"),
23684 BUILDIN_DEF(goto,"l"),
23685 BUILDIN_DEF(callsub,"l*"),
23686 BUILDIN_DEF(callfunc,"s*"),
23687 BUILDIN_DEF(return,"?"),
23688 BUILDIN_DEF(getarg,"i?"),
23689 BUILDIN_DEF(jobchange,"i??"),
23690 BUILDIN_DEF(jobname,"i"),
23691 BUILDIN_DEF(input,"r??"),
23692 BUILDIN_DEF(warp,"sii?"),
23693 BUILDIN_DEF2(warp, "warpchar", "sii?"),
23694 BUILDIN_DEF(areawarp,"siiiisii??"),
23695 BUILDIN_DEF(warpparty,"siii???"), // [Fredzilla] [Paradox924X]
23696 BUILDIN_DEF(warpguild,"siii"), // [Fredzilla]
23697 BUILDIN_DEF(setlook,"ii?"),
23698 BUILDIN_DEF(changelook,"ii?"), // Simulates but don't Store it
23699 BUILDIN_DEF2(setr,"set","rv?"),
23700 BUILDIN_DEF(setr,"rv??"), // Not meant to be used directly, required for var++/var--
23701 BUILDIN_DEF(setarray,"rv*"),
23702 BUILDIN_DEF(cleararray,"rvi"),
23703 BUILDIN_DEF(copyarray,"rri"),
23704 BUILDIN_DEF(getarraysize,"r"),
23705 BUILDIN_DEF(deletearray,"r?"),
23706 BUILDIN_DEF(getelementofarray,"ri"),
23707 BUILDIN_DEF(getitem,"vi?"),
23708 BUILDIN_DEF(rentitem,"vi?"),
23709 BUILDIN_DEF(rentitem2,"viiiiiiii?"),
23710 BUILDIN_DEF(getitem2,"viiiiiiii?"),
23711 BUILDIN_DEF(getnameditem,"vv"),
23712 BUILDIN_DEF2(grouprandomitem,"groupranditem","i?"),
23713 BUILDIN_DEF(makeitem,"visii"),
23714 BUILDIN_DEF(makeitem2,"visiiiiiiiii"),
23715 BUILDIN_DEF(delitem,"vi?"),
23716 BUILDIN_DEF2(delitem,"storagedelitem","vi?"),
23717 BUILDIN_DEF2(delitem,"guildstoragedelitem","vi?"),
23718 BUILDIN_DEF2(delitem,"cartdelitem","vi?"),
23719 BUILDIN_DEF(delitem2,"viiiiiiii?"),
23720 BUILDIN_DEF2(delitem2,"storagedelitem2","viiiiiiii?"),
23721 BUILDIN_DEF2(delitem2,"guildstoragedelitem2","viiiiiiii?"),
23722 BUILDIN_DEF2(delitem2,"cartdelitem2","viiiiiiii?"),
23723 BUILDIN_DEF2(enableitemuse,"enable_items",""),
23724 BUILDIN_DEF2(disableitemuse,"disable_items",""),
23725 BUILDIN_DEF(cutin,"si"),
23726 BUILDIN_DEF(viewpoint,"iiiii"),
23727 BUILDIN_DEF(heal,"ii?"),
23728 BUILDIN_DEF(itemheal,"ii?"),
23729 BUILDIN_DEF(percentheal,"ii?"),
23730 BUILDIN_DEF(rand,"i?"),
23731 BUILDIN_DEF(countitem,"v?"),
23732 BUILDIN_DEF2(countitem,"storagecountitem","v?"),
23733 BUILDIN_DEF2(countitem,"guildstoragecountitem","v?"),
23734 BUILDIN_DEF2(countitem,"cartcountitem","v?"),
23735 BUILDIN_DEF2(countitem,"countitem2","viiiiiii?"),
23736 BUILDIN_DEF2(countitem,"storagecountitem2","viiiiiii?"),
23737 BUILDIN_DEF2(countitem,"guildstoragecountitem2","viiiiiii?"),
23738 BUILDIN_DEF2(countitem,"cartcountitem2","viiiiiii?"),
23739 BUILDIN_DEF(checkweight,"vi*"),
23740 BUILDIN_DEF(checkweight2,"rr"),
23741 BUILDIN_DEF(readparam,"i?"),
23742 BUILDIN_DEF(getcharid,"i?"),
23743 BUILDIN_DEF(getnpcid,"i?"),
23744 BUILDIN_DEF(getpartyname,"i"),
23745 BUILDIN_DEF(getpartymember,"i??"),
23746 BUILDIN_DEF(getpartyleader,"i?"),
23747 BUILDIN_DEF(getguildname,"i"),
23748 BUILDIN_DEF(getguildmaster,"i"),
23749 BUILDIN_DEF(getguildmasterid,"i"),
23750 BUILDIN_DEF(strcharinfo,"i?"),
23751 BUILDIN_DEF(strnpcinfo,"i"),
23752 BUILDIN_DEF(getequipid,"??"),
23753 BUILDIN_DEF(getequipuniqueid,"i?"),
23754 BUILDIN_DEF(getequipname,"i?"),
23755 BUILDIN_DEF(getbrokenid,"i?"), // [Valaris]
23756 BUILDIN_DEF(repair,"i?"), // [Valaris]
23757 BUILDIN_DEF(repairall,"?"),
23758 BUILDIN_DEF(getequipisequiped,"i?"),
23759 BUILDIN_DEF(getequipisenableref,"i?"),
23760 BUILDIN_DEF(getequiprefinerycnt,"i?"),
23761 BUILDIN_DEF(getequipweaponlv,"i?"),
23762 BUILDIN_DEF(getequippercentrefinery,"i?"),
23763 BUILDIN_DEF(successrefitem,"i??"),
23764 BUILDIN_DEF(failedrefitem,"i?"),
23765 BUILDIN_DEF(downrefitem,"i??"),
23766 BUILDIN_DEF(statusup,"i?"),
23767 BUILDIN_DEF(statusup2,"ii?"),
23768 BUILDIN_DEF(bonus,"iv"),
23769 BUILDIN_DEF2(bonus,"bonus2","ivi"),
23770 BUILDIN_DEF2(bonus,"bonus3","ivii"),
23771 BUILDIN_DEF2(bonus,"bonus4","ivvii"),
23772 BUILDIN_DEF2(bonus,"bonus5","ivviii"),
23773 BUILDIN_DEF(autobonus,"sii??"),
23774 BUILDIN_DEF(autobonus2,"sii??"),
23775 BUILDIN_DEF(autobonus3,"siiv?"),
23776 BUILDIN_DEF(skill,"vi?"),
23777 BUILDIN_DEF2(skill,"addtoskill","vi?"), // [Valaris]
23778 BUILDIN_DEF(guildskill,"vi"),
23779 BUILDIN_DEF(getskilllv,"v"),
23780 BUILDIN_DEF(getgdskilllv,"iv"),
23781 BUILDIN_DEF(basicskillcheck,""),
23782 BUILDIN_DEF(getgmlevel,"?"),
23783 BUILDIN_DEF(getgroupid,"?"),
23784 BUILDIN_DEF(end,""),
23785 BUILDIN_DEF(checkoption,"i?"),
23786 BUILDIN_DEF(setoption,"i??"),
23787 BUILDIN_DEF(setcart,"??"),
23788 BUILDIN_DEF(checkcart,"?"),
23789 BUILDIN_DEF(setfalcon,"??"),
23790 BUILDIN_DEF(checkfalcon,"?"),
23791 BUILDIN_DEF(setriding,"??"),
23792 BUILDIN_DEF(checkriding,"?"),
23793 BUILDIN_DEF(checkwug,"?"),
23794 BUILDIN_DEF(checkmadogear,"?"),
23795 BUILDIN_DEF(setmadogear,"??"),
23796 BUILDIN_DEF2(savepoint,"save","sii???"),
23797 BUILDIN_DEF(savepoint,"sii???"),
23798 BUILDIN_DEF(gettimetick,"i"),
23799 BUILDIN_DEF(gettime,"i"),
23800 BUILDIN_DEF(gettimestr,"si?"),
23801 BUILDIN_DEF(openstorage,""),
23802 BUILDIN_DEF(guildopenstorage,""),
23803 BUILDIN_DEF(itemskill,"vi?"),
23804 BUILDIN_DEF(produce,"i"),
23805 BUILDIN_DEF(cooking,"i"),
23806 BUILDIN_DEF(monster,"siisii???"),
23807 BUILDIN_DEF(getmobdrops,"i"),
23808 BUILDIN_DEF(areamonster,"siiiisii???"),
23809 BUILDIN_DEF(killmonster,"ss?"),
23810 BUILDIN_DEF(killmonsterall,"s?"),
23811 BUILDIN_DEF(clone,"siisi????"),
23812 BUILDIN_DEF(doevent,"s"),
23813 BUILDIN_DEF(donpcevent,"s"),
23814 BUILDIN_DEF(cmdothernpc,"ss"),
23815 BUILDIN_DEF(addtimer,"is"),
23816 BUILDIN_DEF(deltimer,"s"),
23817 BUILDIN_DEF(addtimercount,"is"),
23818 BUILDIN_DEF(initnpctimer,"??"),
23819 BUILDIN_DEF(stopnpctimer,"??"),
23820 BUILDIN_DEF(startnpctimer,"??"),
23821 BUILDIN_DEF(setnpctimer,"i?"),
23822 BUILDIN_DEF(getnpctimer,"i?"),
23823 BUILDIN_DEF(attachnpctimer,"?"), // attached the player id to the npc timer [Celest]
23824 BUILDIN_DEF(detachnpctimer,"?"), // detached the player id from the npc timer [Celest]
23825 BUILDIN_DEF(playerattached,""), // returns id of the current attached player. [Skotlex]
23826 BUILDIN_DEF(announce,"si?????"),
23827 BUILDIN_DEF(mapannounce,"ssi?????"),
23828 BUILDIN_DEF(areaannounce,"siiiisi?????"),
23829 BUILDIN_DEF(getusers,"i"),
23830 BUILDIN_DEF(getmapguildusers,"si"),
23831 BUILDIN_DEF(getmapusers,"s"),
23832 BUILDIN_DEF(getareausers,"siiii"),
23833 BUILDIN_DEF(getareadropitem,"siiiiv"),
23834 BUILDIN_DEF(enablenpc,"s"),
23835 BUILDIN_DEF(disablenpc,"s"),
23836 BUILDIN_DEF(hideoffnpc,"s"),
23837 BUILDIN_DEF(hideonnpc,"s"),
23838 BUILDIN_DEF(sc_start,"iii???"),
23839 BUILDIN_DEF2(sc_start,"sc_start2","iiii???"),
23840 BUILDIN_DEF2(sc_start,"sc_start4","iiiiii???"),
23841 BUILDIN_DEF(sc_end,"i?"),
23842 BUILDIN_DEF(sc_end_class,"?"),
23843 BUILDIN_DEF(getstatus, "i??"),
23844 BUILDIN_DEF(getscrate,"ii?"),
23845 BUILDIN_DEF(debugmes,"s"),
23846 BUILDIN_DEF2(catchpet,"pet","i"),
23847 BUILDIN_DEF2(birthpet,"bpet",""),
23848 BUILDIN_DEF(resetlvl,"i?"),
23849 BUILDIN_DEF(resetstatus,"?"),
23850 BUILDIN_DEF(resetskill,"?"),
23851 BUILDIN_DEF(skillpointcount,"?"),
23852 BUILDIN_DEF(changebase,"i?"),
23853 BUILDIN_DEF(changesex,"?"),
23854 BUILDIN_DEF(changecharsex,"?"),
23855 BUILDIN_DEF(waitingroom,"si?????"),
23856 BUILDIN_DEF(delwaitingroom,"?"),
23857 BUILDIN_DEF(waitingroomkick,"ss"),
23858 BUILDIN_DEF(getwaitingroomusers, "?"),
23859 BUILDIN_DEF2(waitingroomkickall,"kickwaitingroomall","?"),
23860 BUILDIN_DEF(enablewaitingroomevent,"?"),
23861 BUILDIN_DEF(disablewaitingroomevent,"?"),
23862 BUILDIN_DEF2(enablewaitingroomevent,"enablearena",""), // Added by RoVeRT
23863 BUILDIN_DEF2(disablewaitingroomevent,"disablearena",""), // Added by RoVeRT
23864 BUILDIN_DEF(getwaitingroomstate,"i?"),
23865 BUILDIN_DEF(warpwaitingpc,"sii?"),
23866 BUILDIN_DEF(attachrid,"i"),
23867 BUILDIN_DEF(addrid,"i?????"),
23868 BUILDIN_DEF(detachrid,""),
23869 BUILDIN_DEF(isloggedin,"i?"),
23870 BUILDIN_DEF(setmapflagnosave,"ssii"),
23871 BUILDIN_DEF(getmapflag,"si?"),
23872 BUILDIN_DEF(setmapflag,"si??"),
23873 BUILDIN_DEF(removemapflag,"si?"),
23874 BUILDIN_DEF(pvpon,"s"),
23875 BUILDIN_DEF(pvpoff,"s"),
23876 BUILDIN_DEF(gvgon,"s"),
23877 BUILDIN_DEF(gvgoff,"s"),
23878 BUILDIN_DEF(emotion,"i??"),
23879 BUILDIN_DEF(maprespawnguildid,"sii"),
23880 BUILDIN_DEF(agitstart,""), // <Agit>
23881 BUILDIN_DEF(agitend,""),
23882 BUILDIN_DEF(agitcheck,""), // <Agitcheck>
23883 BUILDIN_DEF(flagemblem,"i"), // Flag Emblem
23884 BUILDIN_DEF(getcastlename,"s"),
23885 BUILDIN_DEF(getcastledata,"si"),
23886 BUILDIN_DEF(setcastledata,"sii"),
23887 BUILDIN_DEF(requestguildinfo,"i?"),
23888 BUILDIN_DEF(getequipcardcnt,"i"),
23889 BUILDIN_DEF(successremovecards,"i"),
23890 BUILDIN_DEF(failedremovecards,"ii"),
23891 BUILDIN_DEF(marriage,"s"),
23892 BUILDIN_DEF2(wedding_effect,"wedding",""),
23893 BUILDIN_DEF(divorce,"?"),
23894 BUILDIN_DEF(ispartneron,"?"),
23895 BUILDIN_DEF(getpartnerid,"?"),
23896 BUILDIN_DEF(getchildid,"?"),
23897 BUILDIN_DEF(getmotherid,"?"),
23898 BUILDIN_DEF(getfatherid,"?"),
23899 BUILDIN_DEF(warppartner,"sii"),
23900 BUILDIN_DEF(getitemname,"v"),
23901 BUILDIN_DEF(getitemslots,"i"),
23902 BUILDIN_DEF(makepet,"i"),
23903 BUILDIN_DEF(getexp,"ii?"),
23904 BUILDIN_DEF(getinventorylist,"?"),
23905 BUILDIN_DEF(getskilllist,"?"),
23906 BUILDIN_DEF(clearitem,"?"),
23907 BUILDIN_DEF(classchange,"i??"),
23908 BUILDIN_DEF(misceffect,"i"),
23909 BUILDIN_DEF(playBGM,"s"),
23910 BUILDIN_DEF(playBGMall,"s?????"),
23911 BUILDIN_DEF(soundeffect,"si"),
23912 BUILDIN_DEF(soundeffectall,"si?????"), // SoundEffectAll [Codemaster]
23913 BUILDIN_DEF(strmobinfo,"ii"), // display mob data [Valaris]
23914 BUILDIN_DEF(guardian,"siisi??"), // summon guardians
23915 BUILDIN_DEF(guardianinfo,"sii"), // display guardian data [Valaris]
23916 BUILDIN_DEF(petskillbonus,"iiii"), // [Valaris]
23917 BUILDIN_DEF(petrecovery,"ii"), // [Valaris]
23918 BUILDIN_DEF(petloot,"i"), // [Valaris]
23919 BUILDIN_DEF(petskillattack,"viii"), // [Skotlex]
23920 BUILDIN_DEF(petskillattack2,"viiii"), // [Valaris]
23921 BUILDIN_DEF(petskillsupport,"viiii"), // [Skotlex]
23922 BUILDIN_DEF(skilleffect,"vi"), // skill effect [Celest]
23923 BUILDIN_DEF(npcskilleffect,"viii"), // npc skill effect [Valaris]
23924 BUILDIN_DEF(specialeffect,"i??"), // npc skill effect [Valaris]
23925 BUILDIN_DEF(specialeffect2,"i??"), // skill effect on players[Valaris]
23926 BUILDIN_DEF(nude,"?"), // nude command [Valaris]
23927 BUILDIN_DEF(mapwarp,"ssii??"), // Added by RoVeRT
23928 BUILDIN_DEF(atcommand,"s"), // [MouseJstr]
23929 BUILDIN_DEF2(atcommand,"charcommand","s"), // [MouseJstr]
23930 BUILDIN_DEF(movenpc,"sii?"), // [MouseJstr]
23931 BUILDIN_DEF(message,"ss"), // [MouseJstr]
23932 BUILDIN_DEF(npctalk,"s??"), // [Valaris]
23933 BUILDIN_DEF(chatmes,"s?"), // [Jey]
23934 BUILDIN_DEF(mobcount,"ss"),
23935 BUILDIN_DEF(getlook,"i?"),
23936 BUILDIN_DEF(getsavepoint,"i?"),
23937 BUILDIN_DEF(npcspeed,"i"), // [Valaris]
23938 BUILDIN_DEF(npcwalkto,"ii"), // [Valaris]
23939 BUILDIN_DEF(npcstop,""), // [Valaris]
23940 BUILDIN_DEF(getmapxy,"rrri?"), //by Lorky [Lupus]
23941 BUILDIN_DEF(mapid2name,"i"),
23942 BUILDIN_DEF(checkoption1,"i?"),
23943 BUILDIN_DEF(checkoption2,"i?"),
23944 BUILDIN_DEF(guildgetexp,"i"),
23945 BUILDIN_DEF(guildchangegm,"is"),
23946 BUILDIN_DEF(logmes,"s"), //this command actls as MES but rints info into LOG file either SQL/TXT [Lupus]
23947 BUILDIN_DEF(summon,"si??"), // summons a slave monster [Celest]
23948 BUILDIN_DEF(isnight,""), // check whether it is night time [Celest]
23949 BUILDIN_DEF(isday,""), // check whether it is day time [Celest]
23950 BUILDIN_DEF(isequipped,"i*"), // check whether another item/card has been equipped [Celest]
23951 BUILDIN_DEF(isequippedcnt,"i*"), // check how many items/cards are being equipped [Celest]
23952 BUILDIN_DEF(cardscnt,"i*"), // check how many items/cards are being equipped in the same arm [Lupus]
23953 BUILDIN_DEF(getrefine,""), // returns the refined number of the current item, or an item with index specified [celest]
23954 BUILDIN_DEF(night,""), // sets the server to night time
23955 BUILDIN_DEF(day,""), // sets the server to day time
23956 #ifdef PCRE_SUPPORT
23957 BUILDIN_DEF(defpattern,"iss"), // Define pattern to listen for [MouseJstr]
23958 BUILDIN_DEF(activatepset,"i"), // Activate a pattern set [MouseJstr]
23959 BUILDIN_DEF(deactivatepset,"i"), // Deactive a pattern set [MouseJstr]
23960 BUILDIN_DEF(deletepset,"i"), // Delete a pattern set [MouseJstr]
23962 BUILDIN_DEF(preg_match,"ss?"),
23963 BUILDIN_DEF(dispbottom,"s??"), //added from jA [Lupus]
23964 BUILDIN_DEF(recovery,"i???"),
23965 BUILDIN_DEF(getpetinfo,"i?"),
23966 BUILDIN_DEF(gethominfo,"i?"),
23967 BUILDIN_DEF(getmercinfo,"i?"),
23968 BUILDIN_DEF(checkequipedcard,"i"),
23969 BUILDIN_DEF(jump_zero,"il"), //for future jA script compatibility
23970 BUILDIN_DEF(globalmes,"s?"), //end jA addition
23971 BUILDIN_DEF(unequip,"i?"), // unequip command [Spectre]
23972 BUILDIN_DEF(getstrlen,"s"), //strlen [Valaris]
23973 BUILDIN_DEF(charisalpha,"si"), //isalpha [Valaris]
23974 BUILDIN_DEF(charat,"si"),
23975 BUILDIN_DEF(setchar,"ssi"),
23976 BUILDIN_DEF(insertchar,"ssi"),
23977 BUILDIN_DEF(delchar,"si"),
23978 BUILDIN_DEF(strtoupper,"s"),
23979 BUILDIN_DEF(strtolower,"s"),
23980 BUILDIN_DEF(charisupper, "si"),
23981 BUILDIN_DEF(charislower, "si"),
23982 BUILDIN_DEF(substr,"sii"),
23983 BUILDIN_DEF(explode, "rss"),
23984 BUILDIN_DEF(implode, "r?"),
23985 BUILDIN_DEF(sprintf,"s*"), // [Mirei]
23986 BUILDIN_DEF(sscanf,"ss*"), // [Mirei]
23987 BUILDIN_DEF(strpos,"ss?"),
23988 BUILDIN_DEF(replacestr,"sss??"),
23989 BUILDIN_DEF(countstr,"ss?"),
23990 BUILDIN_DEF(setnpcdisplay,"sv??"),
23991 BUILDIN_DEF(compare,"ss"), // Lordalfa - To bring strstr to scripting Engine.
23992 BUILDIN_DEF(strcmp,"ss"),
23993 BUILDIN_DEF(getiteminfo,"ii"), //[Lupus] returns Items Buy / sell Price, etc info
23994 BUILDIN_DEF(setiteminfo,"iii"), //[Lupus] set Items Buy / sell Price, etc info
23995 BUILDIN_DEF(getequipcardid,"ii"), //[Lupus] returns CARD ID or other info from CARD slot N of equipped item
23996 // [zBuffer] List of mathematics commands --->
23997 BUILDIN_DEF(sqrt,"i"),
23998 BUILDIN_DEF(pow,"ii"),
23999 BUILDIN_DEF(distance,"iiii"),
24000 BUILDIN_DEF2(minmax,"min", "*"),
24001 BUILDIN_DEF2(minmax,"minimum", "*"),
24002 BUILDIN_DEF2(minmax,"max", "*"),
24003 BUILDIN_DEF2(minmax,"maximum", "*"),
24004 // <--- [zBuffer] List of mathematics commands
24005 BUILDIN_DEF(md5,"s"),
24006 // [zBuffer] List of dynamic var commands --->
24007 BUILDIN_DEF(getd,"s"),
24008 BUILDIN_DEF(setd,"sv?"),
24009 BUILDIN_DEF(callshop,"s?"), // [Skotlex]
24010 BUILDIN_DEF(npcshopitem,"sii*"), // [Lance]
24011 BUILDIN_DEF(npcshopadditem,"sii*"),
24012 BUILDIN_DEF(npcshopdelitem,"si*"),
24013 BUILDIN_DEF(npcshopattach,"s?"),
24014 BUILDIN_DEF(equip,"i?"),
24015 BUILDIN_DEF(autoequip,"ii"),
24016 BUILDIN_DEF(setbattleflag,"si?"),
24017 BUILDIN_DEF(getbattleflag,"s"),
24018 BUILDIN_DEF(setitemscript,"is?"), //Set NEW item bonus script. Lupus
24019 BUILDIN_DEF(disguise,"i?"), //disguise player. Lupus
24020 BUILDIN_DEF(undisguise,"?"), //undisguise player. Lupus
24021 BUILDIN_DEF(getmonsterinfo,"ii"), //Lupus
24022 BUILDIN_DEF(addmonsterdrop,"vii"), //Akinari [Lupus]
24023 BUILDIN_DEF(delmonsterdrop,"vi"), //Akinari [Lupus]
24024 BUILDIN_DEF(axtoi,"s"),
24025 BUILDIN_DEF(query_sql,"s*"),
24026 BUILDIN_DEF(query_logsql,"s*"),
24027 BUILDIN_DEF(escape_sql,"v"),
24028 BUILDIN_DEF(atoi,"s"),
24029 BUILDIN_DEF(strtol,"si"),
24030 // [zBuffer] List of player cont commands --->
24031 BUILDIN_DEF(rid2name,"i"),
24032 BUILDIN_DEF(pcfollow,"ii"),
24033 BUILDIN_DEF(pcstopfollow,"i"),
24034 BUILDIN_DEF(pcblockmove,"ii"),
24035 BUILDIN_DEF2(pcblockmove,"unitblockmove","ii"),
24036 BUILDIN_DEF(pcblockskill,"ii"),
24037 BUILDIN_DEF2(pcblockskill,"unitblockskill","ii"),
24038 // <--- [zBuffer] List of player cont commands
24039 // [zBuffer] List of unit control commands --->
24040 BUILDIN_DEF(unitexists,"i"),
24041 BUILDIN_DEF(getunittype,"i"),
24042 BUILDIN_DEF(getunitname,"i"),
24043 BUILDIN_DEF(setunitname,"is"),
24044 BUILDIN_DEF(getunitdata,"i*"),
24045 BUILDIN_DEF(setunitdata,"iii"),
24046 BUILDIN_DEF(unitwalk,"iii?"),
24047 BUILDIN_DEF2(unitwalk,"unitwalkto","ii?"),
24048 BUILDIN_DEF(unitkill,"i"),
24049 BUILDIN_DEF(unitwarp,"isii"),
24050 BUILDIN_DEF(unitattack,"iv?"),
24051 BUILDIN_DEF(unitstopattack,"i"),
24052 BUILDIN_DEF(unitstopwalk,"i?"),
24053 BUILDIN_DEF(unittalk,"is?"),
24054 BUILDIN_DEF(unitemote,"ii"),
24055 BUILDIN_DEF(unitskilluseid,"ivi??"), // originally by Qamera [Celest]
24056 BUILDIN_DEF(unitskillusepos,"iviii?"), // [Celest]
24057 // <--- [zBuffer] List of unit control commands
24058 BUILDIN_DEF(sleep,"i"),
24059 BUILDIN_DEF(sleep2,"i"),
24060 BUILDIN_DEF(awake,"s"),
24061 BUILDIN_DEF(getvariableofnpc,"rs"),
24062 BUILDIN_DEF(warpportal,"iisii"),
24063 BUILDIN_DEF2(homunculus_evolution,"homevolution",""), //[orn]
24064 BUILDIN_DEF2(homunculus_mutate,"hommutate","?"),
24065 BUILDIN_DEF(morphembryo,""),
24066 BUILDIN_DEF2(homunculus_shuffle,"homshuffle",""), //[Zephyrus]
24067 BUILDIN_DEF(checkhomcall,""),
24068 BUILDIN_DEF(eaclass,"??"), //[Skotlex]
24069 BUILDIN_DEF(roclass,"i?"), //[Skotlex]
24070 BUILDIN_DEF(checkvending,"?"),
24071 BUILDIN_DEF(checkchatting,"?"),
24072 BUILDIN_DEF(checkidle,"?"),
24073 BUILDIN_DEF(openmail,"?"),
24074 BUILDIN_DEF(openauction,"?"),
24075 BUILDIN_DEF(checkcell,"siii"),
24076 BUILDIN_DEF(setcell,"siiiiii"),
24077 BUILDIN_DEF(getfreecell,"srr?????"),
24078 BUILDIN_DEF(setwall,"siiiiis"),
24079 BUILDIN_DEF(delwall,"s"),
24080 BUILDIN_DEF(searchitem,"rs"),
24081 BUILDIN_DEF(mercenary_create,"ii"),
24082 BUILDIN_DEF(mercenary_heal,"ii"),
24083 BUILDIN_DEF(mercenary_sc_start,"iii"),
24084 BUILDIN_DEF(mercenary_get_calls,"i"),
24085 BUILDIN_DEF(mercenary_get_faith,"i"),
24086 BUILDIN_DEF(mercenary_set_calls,"ii"),
24087 BUILDIN_DEF(mercenary_set_faith,"ii"),
24088 BUILDIN_DEF(readbook,"ii"),
24089 BUILDIN_DEF(setfont,"i"),
24090 BUILDIN_DEF(areamobuseskill,"siiiiviiiii"),
24091 BUILDIN_DEF(progressbar,"si"),
24092 BUILDIN_DEF(progressbar_npc, "si?"),
24093 BUILDIN_DEF(pushpc,"ii"),
24094 BUILDIN_DEF(buyingstore,"i"),
24095 BUILDIN_DEF(searchstores,"ii"),
24096 BUILDIN_DEF(showdigit,"i?"),
24098 BUILDIN_DEF(agitstart2,""),
24099 BUILDIN_DEF(agitend2,""),
24100 BUILDIN_DEF(agitcheck2,""),
24102 BUILDIN_DEF(waitingroom2bg,"sii???"),
24103 BUILDIN_DEF(waitingroom2bg_single,"i????"),
24104 BUILDIN_DEF(bg_team_setxy,"iii"),
24105 BUILDIN_DEF(bg_warp,"isii"),
24106 BUILDIN_DEF(bg_monster,"isiisi?"),
24107 BUILDIN_DEF(bg_monster_set_team,"ii"),
24108 BUILDIN_DEF(bg_leave,"?"),
24109 BUILDIN_DEF(bg_destroy,"i"),
24110 BUILDIN_DEF(areapercentheal,"siiiiii"),
24111 BUILDIN_DEF(bg_get_data,"ii"),
24112 BUILDIN_DEF(bg_getareausers,"isiiii"),
24113 BUILDIN_DEF(bg_updatescore,"sii"),
24114 BUILDIN_DEF(bg_join,"i????"),
24115 BUILDIN_DEF(bg_create,"sii??"),
24118 BUILDIN_DEF(instance_create,"s??"),
24119 BUILDIN_DEF(instance_destroy,"?"),
24120 BUILDIN_DEF(instance_id,""),
24121 BUILDIN_DEF(instance_enter,"s????"),
24122 BUILDIN_DEF(instance_npcname,"s?"),
24123 BUILDIN_DEF(instance_mapname,"s?"),
24124 BUILDIN_DEF(instance_warpall,"sii?"),
24125 BUILDIN_DEF(instance_announce,"isi?????"),
24126 BUILDIN_DEF(instance_check_party,"i???"),
24127 BUILDIN_DEF(instance_check_guild,"i???"),
24128 BUILDIN_DEF(instance_check_clan,"i???"),
24129 BUILDIN_DEF(instance_info,"si?"),
24133 BUILDIN_DEF(makerune,"i?"),
24134 BUILDIN_DEF(checkdragon,"?"),//[Ind]
24135 BUILDIN_DEF(setdragon,"??"),//[Ind]
24136 BUILDIN_DEF(ismounting,"?"),//[Ind]
24137 BUILDIN_DEF(setmounting,"?"),//[Ind]
24138 BUILDIN_DEF(checkre,"i"),
24140 * rAthena and beyond!
24142 BUILDIN_DEF(getargcount,""),
24143 BUILDIN_DEF(getcharip,"?"),
24144 BUILDIN_DEF(is_function,"s"),
24145 BUILDIN_DEF(get_revision,""),
24146 BUILDIN_DEF(get_githash,""),
24147 BUILDIN_DEF(freeloop,"?"),
24148 BUILDIN_DEF(getrandgroupitem,"i??"),
24149 BUILDIN_DEF(cleanmap,"s"),
24150 BUILDIN_DEF2(cleanmap,"cleanarea","siiii"),
24151 BUILDIN_DEF(npcskill,"viii"),
24152 BUILDIN_DEF(consumeitem,"v?"),
24153 BUILDIN_DEF(delequip,"i?"),
24154 BUILDIN_DEF(breakequip,"i?"),
24155 BUILDIN_DEF(sit,"?"),
24156 BUILDIN_DEF(stand,"?"),
24157 //@commands (script based)
24158 BUILDIN_DEF(bindatcmd, "ss??"),
24159 BUILDIN_DEF(unbindatcmd, "s"),
24160 BUILDIN_DEF(useatcmd, "s"),
24162 //Quest Log System [Inkfish]
24163 BUILDIN_DEF(questinfo, "ii??"),
24164 BUILDIN_DEF(setquest, "i?"),
24165 BUILDIN_DEF(erasequest, "i?"),
24166 BUILDIN_DEF(completequest, "i?"),
24167 BUILDIN_DEF(checkquest, "i??"),
24168 BUILDIN_DEF(isbegin_quest,"i?"),
24169 BUILDIN_DEF(changequest, "ii?"),
24170 BUILDIN_DEF(showevent, "i??"),
24172 //Bound items [Xantara] & [Akinari]
24173 BUILDIN_DEF2(getitem,"getitembound","vii?"),
24174 BUILDIN_DEF2(getitem2,"getitembound2","viiiiiiiii?"),
24175 BUILDIN_DEF(countbound, "??"),
24178 BUILDIN_DEF(party_create,"s???"),
24179 BUILDIN_DEF(party_addmember,"ii"),
24180 BUILDIN_DEF(party_delmember,"??"),
24181 BUILDIN_DEF(party_changeleader,"ii"),
24182 BUILDIN_DEF(party_changeoption,"iii"),
24183 BUILDIN_DEF(party_destroy,"i"),
24186 BUILDIN_DEF(clan_join,"i?"),
24187 BUILDIN_DEF(clan_leave,"?"),
24189 BUILDIN_DEF2(montransform, "transform", "vi?????"), // Monster Transform [malufett/Hercules]
24190 BUILDIN_DEF2(montransform, "active_transform", "vi?????"),
24191 BUILDIN_DEF(vip_status,"i?"),
24192 BUILDIN_DEF(vip_time,"i?"),
24193 BUILDIN_DEF(bonus_script,"si????"),
24194 BUILDIN_DEF(bonus_script_clear,"??"),
24195 BUILDIN_DEF(getgroupitem,"i?"),
24196 BUILDIN_DEF(enable_command,""),
24197 BUILDIN_DEF(disable_command,""),
24198 BUILDIN_DEF(getguildmember,"i??"),
24199 BUILDIN_DEF(addspiritball,"ii?"),
24200 BUILDIN_DEF(delspiritball,"i?"),
24201 BUILDIN_DEF(countspiritball,"?"),
24202 BUILDIN_DEF(mergeitem,"?"),
24203 BUILDIN_DEF(mergeitem2,"??"),
24204 BUILDIN_DEF(npcshopupdate,"sii?"),
24205 BUILDIN_DEF(getattachedrid,""),
24206 BUILDIN_DEF(getvar,"vi"),
24207 BUILDIN_DEF(showscript,"s??"),
24208 BUILDIN_DEF(ignoretimeout,"i?"),
24209 BUILDIN_DEF(geteleminfo,"i?"),
24210 BUILDIN_DEF(setquestinfo_level,"iii"),
24211 BUILDIN_DEF(setquestinfo_req,"iii*"),
24212 BUILDIN_DEF(setquestinfo_job,"ii*"),
24213 BUILDIN_DEF(opendressroom,"i?"),
24214 BUILDIN_DEF(navigateto,"s???????"),
24215 BUILDIN_DEF(getguildalliance,"ii"),
24216 BUILDIN_DEF(adopt,"vv"),
24217 BUILDIN_DEF(getexp2,"ii?"),
24218 BUILDIN_DEF(recalculatestat,""),
24219 BUILDIN_DEF(hateffect,"ii"),
24220 BUILDIN_DEF(getrandomoptinfo, "i"),
24221 BUILDIN_DEF(getequiprandomoption, "iii?"),
24222 BUILDIN_DEF(setrandomoption,"iiiii?"),
24223 BUILDIN_DEF(needed_status_point,"ii?"),
24224 BUILDIN_DEF(jobcanentermap,"s?"),
24225 BUILDIN_DEF(openstorage2,"ii?"),
24226 BUILDIN_DEF(unloadnpc, "s"),
24229 BUILDIN_DEF(agitstart3,""),
24230 BUILDIN_DEF(agitend3,""),
24231 BUILDIN_DEF(agitcheck3,""),
24232 BUILDIN_DEF(gvgon3,"s"),
24233 BUILDIN_DEF(gvgoff3,"s"),
24236 BUILDIN_DEF(channel_create,"ss?????"),
24237 BUILDIN_DEF(channel_setopt,"sii"),
24238 BUILDIN_DEF(channel_setcolor,"si"),
24239 BUILDIN_DEF(channel_setpass,"ss"),
24240 BUILDIN_DEF(channel_setgroup,"si*"),
24241 BUILDIN_DEF2(channel_setgroup,"channel_setgroup2","sr"),
24242 BUILDIN_DEF(channel_chat,"ss?"),
24243 BUILDIN_DEF(channel_ban,"si"),
24244 BUILDIN_DEF(channel_unban,"si"),
24245 BUILDIN_DEF(channel_kick,"sv"),
24246 BUILDIN_DEF(channel_delete,"s"),
24248 // Item Random Option Extension [Cydh]
24249 BUILDIN_DEF2(getitem2,"getitem3","viiiiiiiirrr?"),
24250 BUILDIN_DEF2(getitem2,"getitembound3","viiiiiiiiirrr?"),
24251 BUILDIN_DEF2(rentitem2,"rentitem3","viiiiiiiirrr?"),
24252 BUILDIN_DEF2(makeitem2,"makeitem3","visiiiiiiiiirrr"),
24253 BUILDIN_DEF2(delitem2,"delitem3","viiiiiiiirrr?"),
24254 BUILDIN_DEF2(countitem,"countitem3","viiiiiiirrr?"),
24256 // Achievement System
24257 BUILDIN_DEF(achievementinfo,"ii?"),
24258 BUILDIN_DEF(achievementadd,"i?"),
24259 BUILDIN_DEF(achievementremove,"i?"),
24260 BUILDIN_DEF(achievementcomplete,"i?"),
24261 BUILDIN_DEF(achievementexists,"i?"),
24262 BUILDIN_DEF(achievementupdate,"iii?"),
24265 BUILDIN_DEF(getequiprefinecost,"iii?"),
24266 #include "../custom/script_def.inc"