OSDN Git Service

First version
[st-ro/stro.git] / src / map / script.cpp
1 // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
2 // For more information, see LICENCE in the main folder
3
4 //#define DEBUG_DISP
5 //#define DEBUG_DISASM
6 //#define DEBUG_RUN
7 //#define DEBUG_HASH
8 //#define DEBUG_DUMP_STACK
9
10 #ifdef PCRE_SUPPORT
11 #include "../../3rdparty/pcre/include/pcre.h" // preg_match
12 #endif
13
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"
29 #endif
30
31 #include "map.h"
32 #include "path.h"
33 #include "clan.h"
34 #include "clif.h"
35 #include "chrif.h"
36 #include "date.h" // date type enum, date_get()
37 #include "itemdb.h"
38 #include "pc.h"
39 #include "storage.h"
40 #include "pet.h"
41 #include "mapreg.h"
42 #include "homunculus.h"
43 #include "instance.h"
44 #include "mercenary.h"
45 #include "intif.h"
46 #include "chat.h"
47 #include "battleground.h"
48 #include "party.h"
49 #include "mail.h"
50 #include "quest.h"
51 #include "elemental.h"
52 #include "channel.h"
53 #include "achievement.h"
54
55 #include <math.h>
56 #include <stdlib.h> // atoi, strtol, strtoll, exit
57 #include <setjmp.h>
58 #include <errno.h>
59
60 #ifdef __cplusplus
61 extern "C" {
62 #endif
63
64 struct eri *array_ers;
65 DBMap *st_db;
66 unsigned int active_scripts;
67 unsigned int next_id;
68 struct eri *st_ers;
69 struct eri *stack_ers;
70
71 static bool script_rid2sd_( struct script_state *st, struct map_session_data** sd, const char *func );
72
73 /**
74  * Get `sd` from a account id in `loc` param instead of attached rid
75  * @param st Script
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
79  **/
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_);
85                         return false;
86                 }else{
87                         return true;
88                 }
89         }
90         else
91                 return script_rid2sd_(st,sd,func);
92 }
93
94 /**
95  * Get `sd` from a char id in `loc` param instead of attached rid
96  * @param st Script
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
100  **/
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_);
106                         return false;
107                 }else{
108                         return true;
109                 }
110         }
111         else
112                 return script_rid2sd_(st,sd,func);
113 }
114
115 /**
116  * Get `sd` from a nick in `loc` param instead of attached rid
117  * @param st Script
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
121  **/
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_);
127                         return false;
128                 }else{
129                         return true;
130                 }
131         }
132         else
133                 return script_rid2sd_(st,sd,func);
134 }
135
136 /**
137  * Get `sd` from a mapid in `loc` param instead of attached rid
138  * @param st Script
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
142  **/
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_);
148                         return false;
149                 }else{
150                         return true;
151                 }
152         }
153         else
154                 return script_rid2sd_(st,sd,func);
155 }
156
157 /**
158  * Get `bl` from an ID in `loc` param, if ID is 0 will return the `bl` of the script's activator.
159  * @param st Script
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
163  **/
164 static bool script_rid2bl_(struct script_state *st, uint8 loc, struct block_list **bl, const char *func) {
165         int unit_id;
166
167         if ( !script_hasdata(st, loc) || ( unit_id = script_getnum(st, loc) ) == 0)
168                 unit_id = st->rid;
169                 
170         *bl =  map_id2bl(unit_id);
171
172         if ( *bl )
173                 return true;
174         else {
175                 ShowError("%s: Unit with ID '%d' is not found.\n", func, unit_id);
176                 return false;
177         }
178 }
179
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__)
186
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;
191
192 static inline int GETVALUE(const unsigned char* buf, int i)
193 {
194         return (int)MakeDWord(MakeWord(buf[i], buf[i+1]), MakeWord(buf[i+2], 0));
195 }
196 static inline void SETVALUE(unsigned char* buf, int i, int n)
197 {
198         buf[i]   = GetByte(n, 0);
199         buf[i+1] = GetByte(n, 1);
200         buf[i+2] = GetByte(n, 2);
201 }
202
203 // String buffer structures.
204 // str_data stores string information
205 static struct str_data_struct {
206         enum c_op type;
207         int str;
208         int backpatch;
209         int label;
210         int (*func)(struct script_state *st);
211         int val;
212         int next;
213         bool deprecated;
214 } *str_data = NULL;
215 static int str_data_size = 0; // size of the data
216 static int str_num = LABEL_START; // next id to be assigned
217
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
222
223
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
231
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; }
237
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;
243
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
247
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
253         // PC related
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
263         // NPC related
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)
269         // Init related
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)
273         // Guild related
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)
284         // Timer related
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)
297         // Instance related
298         "OnInstanceInit", //instance_init_event_name (is executed right after instance creation)
299         "OnInstanceDestroy", //instance_destroy_event_name (is executed right before instance destruction)
300 };
301
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;
310
311 // for advanced scripting support ( nested if, switch, while, for, do-while, function, etc )
312 // [Eoe / jA 1080, 1081, 1094, 1164]
313 enum curly_type {
314         TYPE_NULL = 0,
315         TYPE_IF,
316         TYPE_SWITCH,
317         TYPE_WHILE,
318         TYPE_FOR,
319         TYPE_DO,
320         TYPE_USERFUNC,
321         TYPE_ARGLIST // function argument list
322 };
323
324 enum e_arglist
325 {
326         ARGLIST_UNDEFINED = 0,
327         ARGLIST_NO_PAREN  = 1,
328         ARGLIST_PAREN     = 2,
329 };
330
331 static struct {
332         struct {
333                 enum curly_type type;
334                 int index;
335                 int count;
336                 int flag;
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
341 } syntax;
342
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;
348
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;
351
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;
357
358
359 c_op get_com(unsigned char *script,int *pos);
360 int get_num(unsigned char *script,int *pos);
361
362 typedef struct script_function {
363         int (*func)(struct script_state *st);
364         const char *name;
365         const char *arg;
366         const char *deprecated;
367 } script_function;
368
369 extern script_function buildin_func[];
370
371 static struct linkdb_node *sleep_db; // int oid -> struct script_state *
372
373 #ifdef BETA_THREAD_TEST
374 /**
375  * MySQL Query Slave
376  **/
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;
382
383 struct queryThreadEntry {
384         bool ok;
385         bool type; /* main db or log db? */
386         struct script_state *st;
387 };
388
389 /* Ladies and Gentleman the Manager! */
390 struct {
391         struct queryThreadEntry **entry;/* array of structs */
392         int count;
393         int timer;/* used to receive processed entries */
394 } queryThreadData;
395 #endif
396
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);
403
404 enum {
405         MF_NOMEMO,      //0
406         MF_NOTELEPORT,
407         MF_NOSAVE,
408         MF_NOBRANCH,
409         MF_NOPENALTY,
410         MF_NOZENYPENALTY,
411         MF_PVP,
412         MF_PVP_NOPARTY,
413         MF_PVP_NOGUILD,
414         MF_GVG,
415         MF_GVG_NOPARTY, //10
416         MF_NOTRADE,
417         MF_NOSKILL,
418         MF_NOWARP,
419         MF_PARTYLOCK,
420         MF_NOICEWALL,
421         MF_SNOW,
422         MF_FOG,
423         MF_SAKURA,
424         MF_LEAVES,
425         /**
426          * No longer available, keeping here just in case it's back someday. [Ind]
427          **/
428         //MF_RAIN,      //20
429         // 21 free
430         MF_NOGO = 22,
431         MF_CLOUDS,
432         MF_CLOUDS2,
433         MF_FIREWORKS,
434         MF_GVG_CASTLE,
435         MF_GVG_DUNGEON,
436         MF_NIGHTENABLED,
437         MF_NOBASEEXP,
438         MF_NOJOBEXP,    //30
439         MF_NOMOBLOOT,
440         MF_NOMVPLOOT,
441         MF_NORETURN,
442         MF_NOWARPTO,
443         MF_NIGHTMAREDROP,
444         MF_RESTRICTED,
445         MF_NOCOMMAND,
446         MF_NODROP,
447         MF_JEXP,
448         MF_BEXP,        //40
449         MF_NOVENDING,
450         MF_LOADEVENT,
451         MF_NOCHAT,
452         MF_NOEXPPENALTY,
453         MF_GUILDLOCK,
454         MF_TOWN,
455         MF_AUTOTRADE,
456         MF_ALLOWKS,
457         MF_MONSTER_NOTELEPORT,
458         MF_PVP_NOCALCRANK,      //50
459         MF_BATTLEGROUND,
460         MF_RESET,
461         MF_CHANNELAUTOJOIN,
462         MF_NOUSECART,
463         MF_NOITEMCONSUMPTION,
464         MF_SUMSTARTMIRACLE,
465         MF_NOMINEEFFECT,
466         MF_NOLOCKON,
467         MF_NOTOMB,
468         MF_SKILL_DAMAGE,        //60
469         MF_NOCOSTUME,
470         MF_GVG_TE_CASTLE,
471         MF_GVG_TE,
472         MF_HIDEMOBHPBAR,
473 };
474
475 const char* script_op2name(int op)
476 {
477 #define RETURN_OP_NAME(type) case type: return #type
478         switch( op )
479         {
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);
493
494         RETURN_OP_NAME(C_REF);
495
496         // operators
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);
523
524         default:
525                 ShowDebug("script_op2name: unexpected op=%d\n", op);
526                 return "???";
527         }
528 #undef RETURN_OP_NAME
529 }
530
531 #ifdef DEBUG_DUMP_STACK
532 static void script_dump_stack(struct script_state* st)
533 {
534         int i;
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 )
540         {
541                 struct script_data* data = &st->stack->stack_data[i];
542                 ShowMessage("\t[%d] %s", i, script_op2name(data->type));
543                 switch( data->type )
544                 {
545                 case C_INT:
546                 case C_POS:
547                         ShowMessage(" %d\n", data->u.num);
548                         break;
549
550                 case C_STR:
551                 case C_CONSTSTR:
552                         ShowMessage(" \"%s\"\n", data->u.str);
553                         break;
554
555                 case C_NAME:
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));
557                         break;
558
559                 case C_RETINFO:
560                         {
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);
563                         }
564                         break;
565                 default:
566                         ShowMessage("\n");
567                         break;
568                 }
569         }
570 }
571 #endif
572
573 /// Reports on the console the src of a script error.
574 static void script_reportsrc(struct script_state *st)
575 {
576         struct block_list* bl;
577
578         if( st->oid == 0 )
579                 return; //Can't report source.
580
581         bl = map_id2bl(st->oid);
582         if( bl == NULL )
583                 return;
584
585         switch( bl->type ) {
586                 case BL_NPC:
587                         if( bl->m >= 0 )
588                                 ShowDebug("Source (NPC): %s at %s (%d,%d)\n", ((struct npc_data *)bl)->name, map[bl->m].name, bl->x, bl->y);
589                         else
590                                 ShowDebug("Source (NPC): %s (invisible/not on a map)\n", ((struct npc_data *)bl)->name);
591                         break;
592                 default:
593                         if( bl->m >= 0 )
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);
595                         else
596                                 ShowDebug("Source (Non-NPC type %d): name %s (invisible/not on a map)\n", bl->type, status_get_name(bl));
597                         break;
598         }
599 }
600
601 /// Reports on the console information about the script data.
602 static void script_reportdata(struct script_data* data)
603 {
604         if( data == NULL )
605                 return;
606         switch( data->type ) {
607                 case C_NOP:// no value
608                         ShowDebug("Data: nothing (nil)\n");
609                         break;
610                 case C_INT:// number
611                         ShowDebug("Data: number value=%" PRId64 "\n", data->u.num);
612                         break;
613                 case C_STR:
614                 case C_CONSTSTR:// string
615                         if( data->u.str ) {
616                                 ShowDebug("Data: string value=\"%s\"\n", data->u.str);
617                         } else {
618                                 ShowDebug("Data: string value=NULL\n");
619                         }
620                         break;
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));
629                         } else {// ???
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));
632                         }
633                         break;
634                 case C_POS:// label
635                         ShowDebug("Data: label pos=%" PRId64 "\n", data->u.num);
636                         break;
637                 default:
638                         ShowDebug("Data: %s\n", script_op2name(data->type));
639                         break;
640         }
641 }
642
643
644 /// Reports on the console information about the current built-in function.
645 static void script_reportfunc(struct script_state* st)
646 {
647         int params, id;
648         struct script_data* data;
649
650         if( !script_hasdata(st,0) )
651         {// no stack
652                 return;
653         }
654
655         data = script_getdata(st,0);
656
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
659                 return;
660         }
661
662         id     = reference_getid(data);
663         params = script_lastdata(st)-1;
664
665         if( params > 0 )
666         {
667                 int i;
668                 ShowDebug("Function: %s (%d parameter%s):\n", get_str(id), params, ( params == 1 ) ? "" : "s");
669
670                 for( i = 2; i <= script_lastdata(st); i++ )
671                 {
672                         script_reportdata(script_getdata(st,i));
673                 }
674         }
675         else
676         {
677                 ShowDebug("Function: %s (no parameters)\n", get_str(id));
678         }
679 }
680 /*==========================================
681  * Output error message
682  *------------------------------------------*/
683 static void disp_error_message2(const char *mes,const char *pos,int report)
684 {
685         error_msg = aStrdup(mes);
686         error_pos = pos;
687         error_report = report;
688         longjmp( error_jump, 1 );
689 }
690 #define disp_error_message(mes,pos) disp_error_message2(mes,pos,1)
691
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);
694 }
695
696 /// Checks event parameter validity
697 static void check_event(struct script_state *st, const char *evt)
698 {
699         if( evt && evt[0] && !stristr(evt, "::On") )
700         {
701                 ShowWarning("NPC event parameter deprecated! Please use 'NPCNAME::OnEVENT' instead of '%s'.\n", evt);
702                 script_reportsrc(st);
703         }
704 }
705
706 /*==========================================
707  * Hashes the input string
708  *------------------------------------------*/
709 static unsigned int calc_hash(const char* p)
710 {
711         unsigned int h;
712
713 #if defined(SCRIPT_HASH_DJB2)
714         h = 5381;
715         while( *p ) // hash*33 + c
716                 h = ( h << 5 ) + h + ((unsigned char)TOLOWER(*p++));
717 #elif defined(SCRIPT_HASH_SDBM)
718         h = 0;
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
722         h = 0;
723         while( *p ){
724                 unsigned int g;
725                 h = ( h << 4 ) + ((unsigned char)TOLOWER(*p++));
726                 g = h & 0xF0000000;
727                 if( g )
728                 {
729                         h ^= g >> 24;
730                         h &= ~g;
731                 }
732         }
733 #else // athena hash
734         h = 0;
735         while( *p )
736                 h = ( h << 1 ) + ( h >> 3 ) + ( h >> 5 ) + ( h >> 8 ) + (unsigned char)TOLOWER(*p++);
737 #endif
738
739         return h % SCRIPT_HASH_SIZE;
740 }
741
742
743 /*==========================================
744  * str_data manipulation functions
745  *------------------------------------------*/
746
747 /// Looks up string using the provided id.
748 const char* get_str(int id)
749 {
750         Assert( id >= LABEL_START && id < str_size );
751         return str_buf+str_data[id].str;
752 }
753
754 /// Returns the uid of the string, or -1.
755 static int search_str(const char* p)
756 {
757         int i;
758
759         for( i = str_hash[calc_hash(p)]; i != 0; i = str_data[i].next )
760                 if( strcasecmp(get_str(i),p) == 0 )
761                         return i;
762
763         return -1;
764 }
765
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)
769 {
770         int h;
771         int len;
772
773         h = calc_hash(p);
774
775         if( str_hash[h] == 0 )
776         {// empty bucket, add new node here
777                 str_hash[h] = str_num;
778         }
779         else
780         {// scan for end of list, or occurence of identical string
781                 int i;
782                 for( i = str_hash[h]; ; i = str_data[i].next )
783                 {
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
788                 }
789
790                 // append node to end of list
791                 str_data[i].next = str_num;
792         }
793
794         // grow list if neccessary
795         if( str_num >= str_data_size )
796         {
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);
800         }
801
802         len=(int)strlen(p);
803
804         // grow string buffer if neccessary
805         while( str_pos+len+1 >= str_size )
806         {
807                 str_size += 256;
808                 RECREATE(str_buf,char,str_size);
809                 memset(str_buf + (str_size - 256), '\0', 256);
810         }
811
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;
819         str_pos += len+1;
820
821         return str_num++;
822 }
823
824
825 /// Appends 1 byte to the script buffer.
826 static void add_scriptb(int a)
827 {
828         if( script_pos+1 >= script_size )
829         {
830                 script_size += SCRIPT_BLOCK_SIZE;
831                 RECREATE(script_buf,unsigned char,script_size);
832         }
833         script_buf[script_pos++] = (uint8)(a);
834 }
835
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)
841 {
842         while( a >= 0x40 )
843         {
844                 add_scriptb((a&0x3f)|0x40);
845                 a = (a - 0x40) >> 6;
846         }
847
848         add_scriptb(a);
849 }
850
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)
856 {
857         while( a >= 0x40 )
858         {
859                 add_scriptb((a&0x3f)|0xc0);
860                 a = (a - 0x40) >> 6;
861         }
862         add_scriptb(a|0x80);
863 }
864
865 /// Appends a str_data object (label/function/variable/integer) to the script buffer.
866
867 ///
868 /// @param l The id of the str_data entry
869 // Maximum up to 16M
870 static void add_scriptl(int l)
871 {
872         int backpatch = str_data[l].backpatch;
873
874         switch(str_data[l].type){
875         case C_POS:
876         case C_USERFUNC_POS:
877                 add_scriptc(C_POS);
878                 add_scriptb(str_data[l].label);
879                 add_scriptb(str_data[l].label>>8);
880                 add_scriptb(str_data[l].label>>16);
881                 break;
882         case C_NOP:
883         case C_USERFUNC:
884                 // Embedded data backpatch there is a possibility of label
885                 add_scriptc(C_NAME);
886                 str_data[l].backpatch = script_pos;
887                 add_scriptb(backpatch);
888                 add_scriptb(backpatch>>8);
889                 add_scriptb(backpatch>>16);
890                 break;
891         case C_INT:
892                 add_scripti(abs(str_data[l].val));
893                 if( str_data[l].val < 0 ) //Notice that this is negative, from jA (Rayce)
894                         add_scriptc(C_NEG);
895                 break;
896         default: // assume C_NAME
897                 add_scriptc(C_NAME);
898                 add_scriptb(l);
899                 add_scriptb(l>>8);
900                 add_scriptb(l>>16);
901                 break;
902         }
903 }
904
905 /*==========================================
906  * Resolve the label
907  *------------------------------------------*/
908 void set_label(int l,int pos, const char* script_pos_cur)
909 {
910         int i;
911
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);
915                 return;
916         }
917         if(str_data[l].label!=-1){
918                 disp_error_message("set_label: dup label ",script_pos_cur);
919                 return;
920         }
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);
927                 i=next;
928         }
929 }
930
931 /// Skips spaces and/or comments.
932 const char* skip_space(const char* p)
933 {
934         if( p == NULL )
935                 return NULL;
936         for(;;)
937         {
938                 while( ISSPACE(*p) )
939                         ++p;
940                 if( *p == '/' && p[1] == '/' )
941                 {// line comment
942                         while(*p && *p!='\n')
943                                 ++p;
944                 }
945                 else if( *p == '/' && p[1] == '*' )
946                 {// block comment
947                         p += 2;
948                         for(;;)
949                         {
950                                 if( *p == '\0' ) {
951                                         disp_warning_message("script:script->skip_space: end of file while parsing block comment. expected " CL_BOLD "*/" CL_NORM, p);
952                                         return p;
953                                 }
954                                 if( *p == '*' && p[1] == '/' )
955                                 {// end of block comment
956                                         p += 2;
957                                         break;
958                                 }
959                                 ++p;
960                         }
961                 }
962                 else
963                         break;
964         }
965         return p;
966 }
967
968 /// Skips a word.
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)
972 {
973         // prefix
974         switch( *p ) {
975                 case '@':// temporary char variable
976                         ++p; break;
977                 case '#':// account variable
978                         p += ( p[1] == '#' ? 2 : 1 ); break;
979                 case '\'':// instance variable
980                         ++p; break;
981                 case '.':// npc variable
982                         p += ( p[1] == '@' ? 2 : 1 ); break;
983                 case '$':// global variable
984                         p += ( p[1] == '@' ? 2 : 1 ); break;
985         }
986
987         while( ISALNUM(*p) || *p == '_' )
988                 ++p;
989
990         // postfix
991         if( *p == '$' )// string
992                 p++;
993
994         return p;
995 }
996
997 /// Adds a word to str_data.
998 /// @see skip_word
999 /// @see add_str
1000 static int add_word(const char* p)
1001 {
1002         char* word;
1003         int len;
1004         int i;
1005
1006         // Check for a word
1007         len = skip_word(p) - p;
1008         if( len == 0 )
1009                 disp_error_message("script:add_word: invalid word. A word consists of undercores and/or alphanumeric characters, and valid variable prefixes/postfixes.", p);
1010
1011         // Duplicate the word
1012         word = (char*)aMalloc(len+1);
1013         memcpy(word, p, len);
1014         word[len] = 0;
1015
1016         // add the word
1017         i = add_str(word);
1018         aFree(word);
1019         return i;
1020 }
1021
1022 /// Parses a function call.
1023 /// The argument list can have parenthesis or not.
1024 /// The number of arguments is checked.
1025 static
1026 const char* parse_callfunc(const char* p, int require_paren, int is_custom)
1027 {
1028         const char* p2;
1029         const char* arg=NULL;
1030         int func;
1031
1032         func = add_word(p);
1033         if( str_data[func].type == C_FUNC ){
1034                 // buildin function
1035                 add_scriptl(func);
1036                 add_scriptc(C_ARG);
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 );
1042                 }
1043 #endif
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);
1047                 add_scriptc(C_ARG);
1048                 add_scriptl(func);
1049                 arg = buildin_func[str_data[buildin_callsub_ref].val].arg;
1050                 if( *arg == 0 )
1051                         disp_error_message("parse_callfunc: callsub has no arguments, please review its definition",p);
1052                 if( *arg != '*' )
1053                         ++arg; // count func as argument
1054         } else {
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);
1058                 } else {;
1059                         add_scriptl(buildin_callfunc_ref);
1060                         add_scriptc(C_ARG);
1061                         add_scriptc(C_STR);
1062                         while( *name ) add_scriptb(*name ++);
1063                         add_scriptb(0);
1064                         arg = buildin_func[str_data[buildin_callfunc_ref].val].arg;
1065                         if( *arg != '*' ) ++ arg;
1066                 }
1067         }
1068
1069         p = skip_word(p);
1070         p = skip_space(p);
1071         syntax.curly[syntax.curly_count].type = TYPE_ARGLIST;
1072         syntax.curly[syntax.curly_count].count = 0;
1073         if( *p == ';' )
1074         {// <func name> ';'
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;
1079                 p = p2;
1080         /*
1081         } else if( 0 && require_paren && *p != '(' )
1082         {// <func name>
1083                 syntax.curly[syntax.curly_count].flag = ARGLIST_NO_PAREN;
1084         */
1085         } else
1086         {// <func name> <arg list>
1087                 if( require_paren ){
1088                         if( *p != '(' )
1089                                 disp_error_message("need '('",p);
1090                         ++p; // skip '('
1091                         syntax.curly[syntax.curly_count].flag = ARGLIST_PAREN;
1092                 } else if( *p == '(' ){
1093                         syntax.curly[syntax.curly_count].flag = ARGLIST_UNDEFINED;
1094                 } else {
1095                         syntax.curly[syntax.curly_count].flag = ARGLIST_NO_PAREN;
1096                 }
1097                 ++syntax.curly_count;
1098                 while( *arg ) {
1099                         p2=parse_subexpr(p,-1);
1100                         if( p == p2 )
1101                                 break; // not an argument
1102                         if( *arg != '*' )
1103                                 ++arg; // next argument
1104
1105                         p=skip_space(p2);
1106                         if( *arg == 0 || *p != ',' )
1107                                 break; // no more arguments
1108                         ++p; // skip comma
1109                 }
1110                 --syntax.curly_count;
1111         }
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 ){
1117                 if( *p != ')' )
1118                         disp_error_message("parse_callfunc: expected ')' to close argument list",p);
1119                 ++p;
1120         }
1121         add_scriptc(C_FUNC);
1122         return p;
1123 }
1124
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)
1129 {
1130         if( !first )
1131         {
1132                 add_scriptc(C_EOL);  // mark end of line for stack cleanup
1133                 set_label(LABEL_NEXTLINE, script_pos, p);  // fix up '-' labels
1134         }
1135
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;
1140 }
1141
1142 /**
1143  * Pushes a variable into stack, processing its array index if needed.
1144  * @see parse_variable
1145  */
1146 void parse_variable_sub_push(int word, const char *p2)
1147 {
1148         if( p2 ) { // Process the variable index
1149                 const char *p3 = NULL;
1150
1151                 // Push the getelementofarray method into the stack
1152                 add_scriptl(buildin_getelementofarray_ref);
1153                 add_scriptc(C_ARG);
1154                 add_scriptl(word);
1155
1156                 // Process the sub-expression for this assignment
1157                 p3 = parse_subexpr(p2 + 1, 1);
1158                 p3 = skip_space(p3);
1159
1160                 if( *p3 != ']' ) // Closing parenthesis is required for this script
1161                         disp_error_message("Missing closing ']' parenthesis for the variable assignment.", p3);
1162
1163                 // Push the closing function stack operator onto the stack
1164                 add_scriptc(C_FUNC);
1165                 p3++;
1166         } else // No array index, simply push the variable or value onto the stack
1167                 add_scriptl(word);
1168 }
1169
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) {
1174         int word;
1175         c_op type = C_NOP;
1176         const char *p2 = NULL;
1177         const char *var = p;
1178
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]);
1182
1183         // skip the variable where applicable
1184         p = skip_word(p);
1185         p = skip_space(p);
1186
1187         if( p == NULL ) {// end of the line or invalid buffer
1188                 return NULL;
1189         }
1190
1191         if( *p == '[' ) {// array variable so process the array as appropriate
1192                 int i,j;
1193                 for( p2 = p, i = 0, j = 1; p; ++ i ) {
1194                         if( *p ++ == ']' && --(j) == 0 ) break;
1195                         if( *p == '[' ) ++ j;
1196                 }
1197
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);
1200                 }
1201         }
1202
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) ) // >>=
1218         ) )
1219         {// failed to find a matching operator combination so invalid
1220                 return NULL;
1221         }
1222
1223         switch( type ) {
1224                 case C_ADD_PRE: // pre ++
1225                 case C_SUB_PRE: // pre --
1226                         // Nothing more to skip
1227                 break;
1228
1229                 case C_EQ: {// incremental modifier
1230                         p = skip_space( &p[1] );
1231                 }
1232                 break;
1233
1234                 case C_L_SHIFT:
1235                 case C_R_SHIFT: {// left or right shift modifier
1236                         p = skip_space( &p[3] );
1237                 }
1238                 break;
1239
1240                 default: {// normal incremental command
1241                         p = skip_space( &p[2] );
1242                 }
1243         }
1244
1245         if( p == NULL ) {// end of line or invalid buffer
1246                 return NULL;
1247         }
1248
1249         // push the set function onto the stack
1250         add_scriptl(buildin_set_ref);
1251         add_scriptc(C_ARG);
1252
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;
1257
1258         // increment the total curly count for the position in the script
1259         ++ syntax.curly_count;
1260
1261         // parse the variable currently being modified
1262         word = add_word(var);
1263
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);
1266
1267         parse_variable_sub_push(word, p2); // Push variable onto the stack
1268
1269         if( type != C_EQ )
1270                 parse_variable_sub_push(word, p2); // Push variable onto the stack once again (first argument of setr)
1271
1272         if( type == C_ADD_POST || type == C_SUB_POST ) { // post ++ / --
1273                 add_scripti(1);
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 ++ / --
1277                 add_scripti(1);
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);
1281
1282                 if( type != C_EQ )
1283                 {// push the type of modifier onto the stack
1284                         add_scriptc(type);
1285                 }
1286         }
1287
1288         // decrement the curly count for the position within the script
1289         -- syntax.curly_count;
1290
1291         // close the script by appending the function operator
1292         add_scriptc(C_FUNC);
1293
1294         // push the buffer from the method
1295         return p;
1296 }
1297
1298 /*
1299  * Checks whether the gives string is a number literal
1300  *
1301  * Mainly necessary to differentiate between number literals and NPC name
1302  * constants, since several of those start with a digit.
1303  *
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.
1307  *
1308  * @author : Hercules.ws
1309  * @param p Pointer to the string to check
1310  * @return Whether the string is a number literal
1311  */
1312 bool is_number(const char *p) {
1313         const char *np;
1314         if (!p)
1315                 return false;
1316         if (*p == '-' || *p == '+')
1317                 p++;
1318         np = p;
1319         if (*p == '0' && p[1] == 'x') {
1320                 p+=2;
1321                 np = p;
1322                 // Hexadecimal
1323                 while (ISXDIGIT(*np))
1324                         np++;
1325         } else {
1326                 // Decimal
1327                 while (ISDIGIT(*np))
1328                         np++;
1329         }
1330         if (p != np && *np != '_' && !ISALPHA(*np)) // At least one digit, and next isn't a letter or _
1331                 return true;
1332         return false;
1333 }
1334
1335 /*==========================================
1336  * Analysis section
1337  *------------------------------------------*/
1338 const char* parse_simpleexpr(const char *p)
1339 {
1340         long long i;
1341         p=skip_space(p);
1342
1343         if(*p==';' || *p==',')
1344                 disp_error_message("parse_simpleexpr: unexpected end of expression",p);
1345         if(*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);
1349                 p=skip_space(p);
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
1352                 ){
1353                         if( *p == ',' ){
1354                                 syntax.curly[i].flag = ARGLIST_PAREN;
1355                                 return p;
1356                         } else
1357                                 syntax.curly[i].flag = ARGLIST_NO_PAREN;
1358                 }
1359                 if( *p != ')' )
1360                         disp_error_message("parse_simpleexpr: unmatched ')'",p);
1361                 ++p;
1362         } else if(is_number(p)) {
1363                 char *np;
1364                 while(*p == '0' && ISDIGIT(p[1])) p++;
1365                 i=strtoll(p,&np,0);
1366                 if( i < INT_MIN ) {
1367                         i = INT_MIN;
1368                         disp_warning_message("parse_simpleexpr: underflow detected, capping value to INT_MIN",p);
1369                 } else if( i > INT_MAX ) {
1370                         i = INT_MAX;
1371                         disp_warning_message("parse_simpleexpr: overflow detected, capping value to INT_MAX",p);
1372                 }
1373                 add_scripti((int)i);
1374                 p=np;
1375         } else if(*p=='"'){
1376                 add_scriptc(C_STR);
1377                 p++;
1378                 while( *p && *p != '"' ){
1379                         if( (unsigned char)p[-1] <= 0x7e && *p == '\\' )
1380                         {
1381                                 char buf[8];
1382                                 size_t len = skip_escaped_c(p) - p;
1383                                 size_t n = sv_unescape_c(buf, p, len);
1384                                 if( n != 1 )
1385                                         ShowDebug("parse_simpleexpr: unexpected length %d after unescape (\"%.*s\" -> %.*s)\n", (int)n, (int)len, p, (int)n, buf);
1386                                 p += len;
1387                                 add_scriptb(*buf);
1388                                 continue;
1389                         }
1390                         else if( *p == '\n' )
1391                                 disp_error_message("parse_simpleexpr: unexpected newline @ string",p);
1392                         add_scriptb(*p++);
1393                 }
1394                 if(!*p)
1395                         disp_error_message("parse_simpleexpr: unexpected eof @ string",p);
1396                 add_scriptb(0);
1397                 p++;    //'"'
1398         } else {
1399                 int l;
1400                 const char* pv;
1401
1402                 // label , register , function etc
1403                 if(skip_word(p)==p)
1404                         disp_error_message("parse_simpleexpr: unexpected character",p);
1405
1406                 l=add_word(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);
1409                 else {
1410                         const char* name = get_str(l);
1411                         if( strdb_get(userfunc_db,name) != NULL ) {
1412                                 return parse_callfunc(p,1,1);
1413                         }
1414                 }
1415
1416                 if( (pv = parse_variable(p)) )
1417                 {// successfully processed a variable assignment
1418                         return pv;
1419                 }
1420
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" );
1425                 }
1426 #endif
1427
1428                 p=skip_word(p);
1429                 if( *p == '[' ){
1430                         // array(name[i] => getelementofarray(name,i) )
1431                         add_scriptl(buildin_getelementofarray_ref);
1432                         add_scriptc(C_ARG);
1433                         add_scriptl(l);
1434
1435                         p=parse_subexpr(p+1,-1);
1436                         p=skip_space(p);
1437                         if( *p != ']' )
1438                                 disp_error_message("parse_simpleexpr: unmatched ']'",p);
1439                         ++p;
1440                         add_scriptc(C_FUNC);
1441                 }else
1442                         add_scriptl(l);
1443
1444         }
1445
1446         return p;
1447 }
1448
1449 /*==========================================
1450  * Analysis of the expression
1451  *------------------------------------------*/
1452 const char* parse_subexpr(const char* p,int limit)
1453 {
1454         int op,opl,len;
1455
1456         p=skip_space(p);
1457
1458         if( *p == '-' ){
1459                 const char* tmpp = skip_space(p+1);
1460                 if( *tmpp == ';' || *tmpp == ',' ){
1461                         add_scriptl(LABEL_NEXTLINE);
1462                         p++;
1463                         return p;
1464                 }
1465         }
1466
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);
1471                 add_scriptc(op);
1472         } else
1473                 p = parse_simpleexpr(p);
1474         p = skip_space(p);
1475         while((
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){
1495                 p+=len;
1496                 if(op == C_OP3) {
1497                         p=parse_subexpr(p,-1);
1498                         p=skip_space(p);
1499                         if( *(p++) != ':')
1500                                 disp_error_message("parse_subexpr: expected ':'", p-1);
1501                         p=parse_subexpr(p,-1);
1502                 } else {
1503                         p=parse_subexpr(p,opl);
1504                 }
1505                 add_scriptc(op);
1506                 p=skip_space(p);
1507         }
1508
1509         return p;  /* return first untreated operator */
1510 }
1511
1512 /*==========================================
1513  * Evaluation of the expression
1514  *------------------------------------------*/
1515 const char* parse_expr(const char *p)
1516 {
1517         switch(*p){
1518         case ')': case ';': case ':': case '[': case ']':
1519         case '}':
1520                 disp_error_message("parse_expr: unexpected character",p);
1521         }
1522         p=parse_subexpr(p,-1);
1523         return p;
1524 }
1525
1526 /*==========================================
1527  * Analysis of the line
1528  *------------------------------------------*/
1529 const char* parse_line(const char* p)
1530 {
1531         const char* p2;
1532
1533         p=skip_space(p);
1534         if(*p==';') {
1535                 //Close decision for if(); for(); while();
1536                 p = parse_syntax_close(p + 1);
1537                 return p;
1538         }
1539         if(*p==')' && parse_syntax_for_flag)
1540                 return p+1;
1541
1542         p = skip_space(p);
1543         if(p[0] == '{') {
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++;
1548                 return p + 1;
1549         } else if(p[0] == '}') {
1550                 return parse_curly_close(p);
1551         }
1552
1553         // Syntax-related processing
1554         p2 = parse_syntax(p);
1555         if(p2 != NULL)
1556                 return p2;
1557
1558         // attempt to process a variable assignment
1559         p2 = parse_variable(p);
1560
1561         if( p2 != NULL )
1562         {// variable assignment processed so leave the method
1563                 return parse_syntax_close(p2 + 1);
1564         }
1565
1566         p = parse_callfunc(p,0,0);
1567         p = skip_space(p);
1568
1569         if(parse_syntax_for_flag) {
1570                 if( *p != ')' )
1571                         disp_error_message("parse_line: expected ')'",p);
1572         } else {
1573                 if( *p != ';' )
1574                         disp_error_message("parse_line: expected ';'",p);
1575         }
1576
1577         //Binding decision for if(), for(), while()
1578         p = parse_syntax_close(p+1);
1579
1580         return p;
1581 }
1582
1583 // { ... } Closing process
1584 const char* parse_curly_close(const char* p)
1585 {
1586         if(syntax.curly_count <= 0) {
1587                 disp_error_message("parse_curly_close: unexpected string",p);
1588                 return p + 1;
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);
1593                 return p;
1594         } else if(syntax.curly[syntax.curly_count-1].type == TYPE_SWITCH) {
1595                 //Closing switch()
1596                 int pos = syntax.curly_count-1;
1597                 char label[256];
1598                 int l;
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;
1602                 parse_line(label);
1603                 syntax.curly_count--;
1604
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;
1608                 parse_line(label);
1609                 syntax.curly_count--;
1610
1611                 // You are here labeled
1612                 sprintf(label,"__SW%x_%x",syntax.curly[pos].index,syntax.curly[pos].count);
1613                 l=add_str(label);
1614                 set_label(l,script_pos, p);
1615
1616                 if(syntax.curly[pos].flag) {
1617                         //Exists default
1618                         sprintf(label,"goto __SW%x_DEF;",syntax.curly[pos].index);
1619                         syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1620                         parse_line(label);
1621                         syntax.curly_count--;
1622                 }
1623
1624                 // Label end
1625                 sprintf(label,"__SW%x_FIN",syntax.curly[pos].index);
1626                 l=add_str(label);
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);
1632                 return p;
1633         } else {
1634                 disp_error_message("parse_curly_close: unexpected string",p);
1635                 return p + 1;
1636         }
1637 }
1638
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)
1643 {
1644         const char *p2 = skip_word(p);
1645
1646         switch(*p) {
1647         case 'B':
1648         case 'b':
1649                 if(p2 - p == 5 && !strncasecmp(p,"break",5)) {
1650                         // break Processing
1651                         char label[256];
1652                         int pos = syntax.curly_count - 1;
1653                         while(pos >= 0) {
1654                                 if(syntax.curly[pos].type == TYPE_DO) {
1655                                         sprintf(label,"goto __DO%x_FIN;",syntax.curly[pos].index);
1656                                         break;
1657                                 } else if(syntax.curly[pos].type == TYPE_FOR) {
1658                                         sprintf(label,"goto __FR%x_FIN;",syntax.curly[pos].index);
1659                                         break;
1660                                 } else if(syntax.curly[pos].type == TYPE_WHILE) {
1661                                         sprintf(label,"goto __WL%x_FIN;",syntax.curly[pos].index);
1662                                         break;
1663                                 } else if(syntax.curly[pos].type == TYPE_SWITCH) {
1664                                         sprintf(label,"goto __SW%x_FIN;",syntax.curly[pos].index);
1665                                         break;
1666                                 }
1667                                 pos--;
1668                         }
1669                         if(pos < 0) {
1670                                 disp_error_message("parse_syntax: unexpected 'break'",p);
1671                         } else {
1672                                 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1673                                 parse_line(label);
1674                                 syntax.curly_count--;
1675                         }
1676                         p = skip_space(p2);
1677                         if(*p != ';')
1678                                 disp_error_message("parse_syntax: expected ';'",p);
1679                         // Closing decision if, for , while
1680                         p = parse_syntax_close(p + 1);
1681                         return p;
1682                 }
1683                 break;
1684         case 'c':
1685         case 'C':
1686                 if(p2 - p == 4 && !strncasecmp(p,"case",4)) {
1687                         //Processing case
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);
1691                                 return p+1;
1692                         } else {
1693                                 char label[256];
1694                                 int  l,v;
1695                                 char *np;
1696                                 if(syntax.curly[pos].count != 1) {
1697                                         //Jump for FALLTHRU
1698                                         sprintf(label,"goto __SW%x_%xJ;",syntax.curly[pos].index,syntax.curly[pos].count);
1699                                         syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1700                                         parse_line(label);
1701                                         syntax.curly_count--;
1702
1703                                         // You are here labeled
1704                                         sprintf(label,"__SW%x_%x",syntax.curly[pos].index,syntax.curly[pos].count);
1705                                         l=add_str(label);
1706                                         set_label(l,script_pos, p);
1707                                 }
1708                                 //Decision statement switch
1709                                 p = skip_space(p2);
1710                                 if(p == p2) {
1711                                         disp_error_message("parse_syntax: expected a space ' '",p);
1712                                 }
1713                                 // check whether case label is integer or not
1714                                 if(is_number(p)) {
1715                                         //Numeric value
1716                                         v = (int)strtol(p,&np,0);
1717                                         if((*p == '-' || *p == '+') && ISDIGIT(p[1])) // pre-skip because '-' can not skip_word
1718                                                 p++;
1719                                         p = skip_word(p);
1720                                         if(np != p)
1721                                                 disp_error_message("parse_syntax: 'case' label is not an integer",np);
1722                                 } else {
1723                                         //Check for constants
1724                                         p2 = skip_word(p);
1725                                         v = (int)(size_t) (p2-p); // length of word at p2
1726                                         memcpy(label,p,v);
1727                                         label[v]='\0';
1728                                         if( !script_get_constant(label, &v) )
1729                                                 disp_error_message("parse_syntax: 'case' label is not an integer",p);
1730                                         p = skip_word(p);
1731                                 }
1732                                 p = skip_space(p);
1733                                 if(*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);
1740                                 parse_line(p2);
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);
1745                                         l=add_str(label);
1746                                         set_label(l,script_pos,p);
1747                                 }
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);
1752
1753                                 sprintf(label,"set $@__SW%x_VAL,0;",syntax.curly[pos].index);
1754                                 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1755
1756                                 parse_line(label);
1757                                 syntax.curly_count--;
1758                                 syntax.curly[pos].count++;
1759                         }
1760                         return p + 1;
1761                 } else if(p2 - p == 8 && !strncasecmp(p,"continue",8)) {
1762                         // Processing continue
1763                         char label[256];
1764                         int pos = syntax.curly_count - 1;
1765                         while(pos >= 0) {
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
1769                                         break;
1770                                 } else if(syntax.curly[pos].type == TYPE_FOR) {
1771                                         sprintf(label,"goto __FR%x_NXT;",syntax.curly[pos].index);
1772                                         break;
1773                                 } else if(syntax.curly[pos].type == TYPE_WHILE) {
1774                                         sprintf(label,"goto __WL%x_NXT;",syntax.curly[pos].index);
1775                                         break;
1776                                 }
1777                                 pos--;
1778                         }
1779                         if(pos < 0) {
1780                                 disp_error_message("parse_syntax: unexpected 'continue'",p);
1781                         } else {
1782                                 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1783                                 parse_line(label);
1784                                 syntax.curly_count--;
1785                         }
1786                         p = skip_space(p2);
1787                         if(*p != ';')
1788                                 disp_error_message("parse_syntax: expected ';'",p);
1789                         //Closing decision if, for , while
1790                         p = parse_syntax_close(p + 1);
1791                         return p;
1792                 }
1793                 break;
1794         case 'd':
1795         case 'D':
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);
1803                         } else {
1804                                 char label[256];
1805                                 int l;
1806                                 // Put the label location
1807                                 p = skip_space(p2);
1808                                 if(*p != ':') {
1809                                         disp_error_message("parse_syntax: expected ':'",p);
1810                                 }
1811                                 sprintf(label,"__SW%x_%x",syntax.curly[pos].index,syntax.curly[pos].count);
1812                                 l=add_str(label);
1813                                 set_label(l,script_pos,p);
1814
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;
1818                                 parse_line(label);
1819                                 syntax.curly_count--;
1820
1821                                 // The default label
1822                                 sprintf(label,"__SW%x_DEF",syntax.curly[pos].index);
1823                                 l=add_str(label);
1824                                 set_label(l,script_pos,p);
1825
1826                                 syntax.curly[syntax.curly_count - 1].flag = 1;
1827                                 syntax.curly[pos].count++;
1828                         }
1829                         return p + 1;
1830                 } else if(p2 - p == 2 && !strncasecmp(p,"do",2)) {
1831                         int l;
1832                         char label[256];
1833                         p=skip_space(p2);
1834
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);
1841                         l=add_str(label);
1842                         set_label(l,script_pos,p);
1843                         syntax.curly_count++;
1844                         return p;
1845                 }
1846                 break;
1847         case 'f':
1848         case 'F':
1849                 if(p2 - p == 3 && !strncasecmp(p,"for",3)) {
1850                         int l;
1851                         char label[256];
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++;
1858
1859                         p=skip_space(p2);
1860
1861                         if(*p != '(')
1862                                 disp_error_message("parse_syntax: expected '('",p);
1863                         p++;
1864
1865                         // Execute the initialization statement
1866                         syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1867                         p=parse_line(p);
1868                         syntax.curly_count--;
1869
1870                         // Form the start of label decision
1871                         sprintf(label,"__FR%x_J",syntax.curly[pos].index);
1872                         l=add_str(label);
1873                         set_label(l,script_pos,p);
1874
1875                         p=skip_space(p);
1876                         if(*p == ';') {
1877                                 // For (; Because the pattern of always true ;)
1878                                 ;
1879                         } else {
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"));
1883                                 add_scriptc(C_ARG);
1884                                 p=parse_expr(p);
1885                                 p=skip_space(p);
1886                                 add_scriptl(add_str(label));
1887                                 add_scriptc(C_FUNC);
1888                         }
1889                         if(*p != ';')
1890                                 disp_error_message("parse_syntax: expected ';'",p);
1891                         p++;
1892
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;
1896                         parse_line(label);
1897                         syntax.curly_count--;
1898
1899                         // Labels to form the next loop
1900                         sprintf(label,"__FR%x_NXT",syntax.curly[pos].index);
1901                         l=add_str(label);
1902                         set_label(l,script_pos,p);
1903
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;
1908                         p=parse_line(p);
1909                         syntax.curly_count--;
1910                         parse_syntax_for_flag = 0;
1911
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;
1915                         parse_line(label);
1916                         syntax.curly_count--;
1917
1918                         // Loop start labeling
1919                         sprintf(label,"__FR%x_BGN",syntax.curly[pos].index);
1920                         l=add_str(label);
1921                         set_label(l,script_pos,p);
1922                         return p;
1923                 }
1924                 else if( p2 - p == 8 && strncasecmp(p,"function",8) == 0 )
1925                 {// internal script function
1926                         const char *func_name;
1927
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);
1932                         p2 = skip_space(p);
1933                         if( *p2 == ';' )
1934                         {// function <name> ;
1935                                 // function declaration - just register the name
1936                                 int l;
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
1942                                 else
1943                                         disp_error_message("parse_syntax:function: function name is invalid", func_name);
1944
1945                                 // Close condition of if, for, while
1946                                 p = parse_syntax_close(p2 + 1);
1947                                 return p;
1948                         }
1949                         else if(*p2 == '{')
1950                         {// function <name> <line/block of code>
1951                                 char label[256];
1952                                 int l;
1953
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;
1959
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;
1964                                 parse_line(label);
1965                                 --syntax.curly_count;
1966
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
1970                                 {
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);
1975                                 }
1976                                 else
1977                                         disp_error_message("parse_syntax:function: function name is invalid", func_name);
1978
1979                                 return skip_space(p);
1980                         }
1981                         else
1982                         {
1983                                 disp_error_message("expect ';' or '{' at function syntax",p);
1984                         }
1985                 }
1986                 break;
1987         case 'i':
1988         case 'I':
1989                 if(p2 - p == 2 && !strncasecmp(p,"if",2)) {
1990                         // If process
1991                         char label[256];
1992                         p=skip_space(p2);
1993                         if(*p != '(') { //Prevent if this {} non-c syntax. from Rayce (jA)
1994                                 disp_error_message("need '('",p);
1995                         }
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"));
2003                         add_scriptc(C_ARG);
2004                         p=parse_expr(p);
2005                         p=skip_space(p);
2006                         add_scriptl(add_str(label));
2007                         add_scriptc(C_FUNC);
2008                         return p;
2009                 }
2010                 break;
2011         case 's':
2012         case 'S':
2013                 if(p2 - p == 6 && !strncasecmp(p,"switch",6)) {
2014                         // Processing of switch ()
2015                         char label[256];
2016                         p=skip_space(p2);
2017                         if(*p != '(') {
2018                                 disp_error_message("need '('",p);
2019                         }
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"));
2027                         add_scriptc(C_ARG);
2028                         add_scriptl(add_str(label));
2029                         p=parse_expr(p);
2030                         p=skip_space(p);
2031                         if(*p != '{') {
2032                                 disp_error_message("parse_syntax: expected '{'",p);
2033                         }
2034                         add_scriptc(C_FUNC);
2035                         return p + 1;
2036                 }
2037                 break;
2038         case 'w':
2039         case 'W':
2040                 if(p2 - p == 5 && !strncasecmp(p,"while",5)) {
2041                         int l;
2042                         char label[256];
2043                         p=skip_space(p2);
2044                         if(*p != '(') {
2045                                 disp_error_message("need '('",p);
2046                         }
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);
2053                         l=add_str(label);
2054                         set_label(l,script_pos,p);
2055
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"));
2060                         add_scriptc(C_ARG);
2061                         p=parse_expr(p);
2062                         p=skip_space(p);
2063                         add_scriptl(add_str(label));
2064                         add_scriptc(C_FUNC);
2065                         return p;
2066                 }
2067                 break;
2068         }
2069         return NULL;
2070 }
2071
2072 const char* parse_syntax_close(const char *p) {
2073         // If (...) for (...) hoge (); as to make sure closed closed once again
2074         int flag;
2075
2076         do {
2077                 p = parse_syntax_close_sub(p,&flag);
2078         } while(flag);
2079         return p;
2080 }
2081
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)
2086 {
2087         char label[256];
2088         int pos = syntax.curly_count - 1;
2089         int l;
2090         *flag = 1;
2091
2092         if(syntax.curly_count <= 0) {
2093                 *flag = 0;
2094                 return p;
2095         } else if(syntax.curly[pos].type == TYPE_IF) {
2096                 const char *bp = p;
2097                 const char *p2;
2098
2099                 // if-block and else-block end is a new line
2100                 parse_nextline(false, p);
2101
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;
2105                 parse_line(label);
2106                 syntax.curly_count--;
2107
2108                 // Put the label of the location
2109                 sprintf(label,"__IF%x_%x",syntax.curly[pos].index,syntax.curly[pos].count);
2110                 l=add_str(label);
2111                 set_label(l,script_pos,p);
2112
2113                 syntax.curly[pos].count++;
2114                 p = skip_space(p);
2115                 p2 = skip_word(p);
2116                 if(!syntax.curly[pos].flag && p2 - p == 4 && !strncasecmp(p,"else",4)) {
2117                         // else  or else - if
2118                         p = skip_space(p2);
2119                         p2 = skip_word(p);
2120                         if(p2 - p == 2 && !strncasecmp(p,"if",2)) {
2121                                 // else - if
2122                                 p=skip_space(p2);
2123                                 if(*p != '(') {
2124                                         disp_error_message("need '('",p);
2125                                 }
2126                                 sprintf(label,"__IF%x_%x",syntax.curly[pos].index,syntax.curly[pos].count);
2127                                 add_scriptl(add_str("jump_zero"));
2128                                 add_scriptc(C_ARG);
2129                                 p=parse_expr(p);
2130                                 p=skip_space(p);
2131                                 add_scriptl(add_str(label));
2132                                 add_scriptc(C_FUNC);
2133                                 *flag = 0;
2134                                 return p;
2135                         } else {
2136                                 // else
2137                                 if(!syntax.curly[pos].flag) {
2138                                         syntax.curly[pos].flag = 1;
2139                                         *flag = 0;
2140                                         return p;
2141                                 }
2142                         }
2143                 }
2144                 // Close if
2145                 syntax.curly_count--;
2146                 // Put the label of the final location
2147                 sprintf(label,"__IF%x_FIN",syntax.curly[pos].index);
2148                 l=add_str(label);
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
2152                         return bp;
2153                 }
2154                 return p;
2155         } else if(syntax.curly[pos].type == TYPE_DO) {
2156                 int l2;
2157                 char label2[256];
2158                 const char *p2;
2159
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);
2163                         l2=add_str(label2);
2164                         set_label(l2,script_pos,p);
2165                 }
2166
2167                 // Skip to the end point if the condition is false
2168                 p = skip_space(p);
2169                 p2 = skip_word(p);
2170                 if(p2 - p != 5 || strncasecmp(p,"while",5))
2171                         disp_error_message("parse_syntax: expected 'while'",p);
2172
2173                 p = skip_space(p2);
2174                 if(*p != '(') {
2175                         disp_error_message("need '('",p);
2176                 }
2177
2178                 // do-block end is a new line
2179                 parse_nextline(false, p);
2180
2181                 sprintf(label2,"__DO%x_FIN",syntax.curly[pos].index);
2182                 add_scriptl(add_str("jump_zero"));
2183                 add_scriptc(C_ARG);
2184                 p=parse_expr(p);
2185                 p=skip_space(p);
2186                 add_scriptl(add_str(label2));
2187                 add_scriptc(C_FUNC);
2188
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;
2192                 parse_line(label2);
2193                 syntax.curly_count--;
2194
2195                 // Form label of the end point conditions
2196                 sprintf(label2,"__DO%x_FIN",syntax.curly[pos].index);
2197                 l2=add_str(label2);
2198                 set_label(l2,script_pos,p);
2199                 p = skip_space(p);
2200                 if(*p != ';') {
2201                         disp_error_message("parse_syntax: expected ';'",p);
2202                         return p+1;
2203                 }
2204                 p++;
2205                 syntax.curly_count--;
2206                 return p;
2207         } else if(syntax.curly[pos].type == TYPE_FOR) {
2208                 // for-block end is a new line
2209                 parse_nextline(false, p);
2210
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;
2214                 parse_line(label);
2215                 syntax.curly_count--;
2216
2217                 // End for labeling
2218                 sprintf(label,"__FR%x_FIN",syntax.curly[pos].index);
2219                 l=add_str(label);
2220                 set_label(l,script_pos,p);
2221                 syntax.curly_count--;
2222                 return p;
2223         } else if(syntax.curly[pos].type == TYPE_WHILE) {
2224                 // while-block end is a new line
2225                 parse_nextline(false, p);
2226
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;
2230                 parse_line(label);
2231                 syntax.curly_count--;
2232
2233                 // End while labeling
2234                 sprintf(label,"__WL%x_FIN",syntax.curly[pos].index);
2235                 l=add_str(label);
2236                 set_label(l,script_pos,p);
2237                 syntax.curly_count--;
2238                 return p;
2239         } else if(syntax.curly[syntax.curly_count-1].type == TYPE_USERFUNC) {
2240                 int pos2 = syntax.curly_count-1;
2241                 char label2[256];
2242                 int l2;
2243                 // Back
2244                 sprintf(label2,"return;");
2245                 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
2246                 parse_line(label2);
2247                 syntax.curly_count--;
2248
2249                 // Put the label of the location
2250                 sprintf(label2,"__FN%x_FIN",syntax.curly[pos2].index);
2251                 l2=add_str(label2);
2252                 set_label(l2,script_pos,p);
2253                 syntax.curly_count--;
2254                 return p;
2255         } else {
2256                 *flag = 0;
2257                 return p;
2258         }
2259 }
2260
2261 /*==========================================
2262  * Added built-in functions
2263  *------------------------------------------*/
2264 static void add_buildin_func(void)
2265 {
2266         int i;
2267         for( i = 0; buildin_func[i].func; i++ )
2268         {
2269                 // arg must follow the pattern: (v|s|i|r|l)*\?*\*?
2270                 // 'v' - value (either string or int or reference)
2271                 // 's' - string
2272                 // 'i' - int
2273                 // 'r' - reference (of a variable)
2274                 // 'l' - label
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;
2281                 if( *p != 0){
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);
2285                 } else {
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);
2291
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;
2296                 }
2297         }
2298 }
2299
2300 /// Retrieves the value of a constant parameter.
2301 bool script_get_parameter(const char* name, int* value)
2302 {
2303         int n = search_str(name);
2304
2305         if (n == -1 || str_data[n].type != C_PARAM)
2306         {// not found or not a parameter
2307                 return false;
2308         }
2309         value[0] = str_data[n].val;
2310
2311         return true;
2312 }
2313
2314 /// Retrieves the value of a constant.
2315 bool script_get_constant(const char* name, int* value)
2316 {
2317         int n = search_str(name);
2318
2319         if( n == -1 || str_data[n].type != C_INT )
2320         {// not found or not a constant
2321                 return false;
2322         }
2323         value[0] = str_data[n].val;
2324
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" );
2329         }
2330 #endif
2331
2332         return true;
2333 }
2334
2335 /// Creates new constant or parameter with given value.
2336 void script_set_constant(const char* name, int value, bool isparameter, bool deprecated)
2337 {
2338         int n = add_str(name);
2339
2340         if( str_data[n].type == C_NOP )
2341         {// new
2342                 str_data[n].type = isparameter ? C_PARAM : C_INT;
2343                 str_data[n].val  = value;
2344                 str_data[n].deprecated = deprecated;
2345         }
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);
2349         }
2350         else
2351         {// existing name
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));
2353         }
2354 }
2355
2356 /*==========================================
2357  * Reading constant databases
2358  * const.txt
2359  *------------------------------------------*/
2360 static void read_constdb(void)
2361 {
2362         FILE *fp;
2363         char line[1024],name[1024],val[1024];
2364         int type;
2365         int entries=0, skipped=0, linenum=0;
2366
2367         sprintf(line, "%s/const.txt", db_path);
2368         fp=fopen(line, "r");
2369         if(fp==NULL){
2370                 ShowError("can't read %s\n", line);
2371                 return ;
2372         }
2373         while(fgets(line, sizeof(line), fp))
2374         {
2375                 linenum++;
2376                 if( line[0] == '\0' || line[0] == '\n' || line[0] == '\r') //ignore empty line
2377                         continue;
2378                 if(line[0]=='/' && line[1]=='/') //ignore commented line
2379                         continue;
2380                 
2381                 type=0;
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){
2384                         entries++;
2385                         script_set_constant(name, (int)strtol(val, NULL, 0), (type != 0), false);
2386                 }
2387                 else {
2388                         skipped++;
2389                         ShowWarning("Skipping line '" CL_WHITE "%d" CL_RESET "', invalid constant definition\n",linenum);
2390                 }
2391         }
2392         fclose(fp);
2393         ShowStatus("Done reading '" CL_WHITE "%d" CL_RESET "' entries in '" CL_WHITE "%s/const.txt" CL_RESET "'.\n", entries, db_path);
2394         if(skipped){
2395                 ShowWarning("Skipped '" CL_WHITE "%d" CL_RESET "', entries\n",skipped);
2396         }
2397 }
2398
2399 /**
2400  * Sets source-end constants for NPC scripts to access.
2401  **/
2402 void script_hardcoded_constants(void) {
2403         #include "script_constants.h"
2404 }
2405
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)
2410 {
2411         int i;
2412         if( p == NULL || !p[0] ) return NULL;
2413         if( line < 0 )
2414                 StringBuf_Printf(buf, "*% 5d : ", -line);
2415         else
2416                 StringBuf_Printf(buf, " % 5d : ", line);
2417         for(i=0;p[i] && p[i] != '\n';i++){
2418                 if(p + i != mark)
2419                         StringBuf_Printf(buf, "%c", p[i]);
2420                 else
2421                         StringBuf_Printf(buf, "\'%c\'", p[i]);
2422         }
2423         StringBuf_AppendStr(buf, "\n");
2424         return p+i+(p[i] == '\n' ? 1 : 0);
2425 }
2426
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
2429         int j;
2430         int line = start_line;
2431         const char *p;
2432         const char *linestart[5] = { NULL, NULL, NULL, NULL, NULL };
2433
2434         for(p=src;p && *p;line++){
2435                 const char *lineend=strchr(p,'\n');
2436                 if(lineend==NULL || error_pos_cur<lineend){
2437                         break;
2438                 }
2439                 for( j = 0; j < 4; j++ ) {
2440                         linestart[j] = linestart[j+1];
2441                 }
2442                 linestart[4] = p;
2443                 p=lineend+1;
2444         }
2445
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);
2450         }
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 );
2454         }
2455 }
2456
2457 void script_error(const char* src, const char* file, int start_line, const char* error_msg_cur, const char* error_pos_cur) {
2458         StringBuf buf;
2459
2460         StringBuf_Init(&buf);
2461         StringBuf_AppendStr(&buf, "\a\n");
2462
2463         script_errorwarning_sub(&buf, src, file, start_line, error_msg_cur, error_pos_cur);
2464
2465         ShowError("%s", StringBuf_Value(&buf));
2466         StringBuf_Destroy(&buf);
2467 }
2468
2469 void script_warning(const char* src, const char* file, int start_line, const char* error_msg_cur, const char* error_pos_cur) {
2470         StringBuf buf;
2471
2472         StringBuf_Init(&buf);
2473
2474         script_errorwarning_sub(&buf, src, file, start_line, error_msg_cur, error_pos_cur);
2475
2476         ShowWarning("%s", StringBuf_Value(&buf));
2477         StringBuf_Destroy(&buf);
2478 }
2479
2480 /*==========================================
2481  * Analysis of the script
2482  *------------------------------------------*/
2483 struct script_code* parse_script(const char *src,const char *file,int line,int options)
2484 {
2485         const char *p,*tmpp;
2486         int i;
2487         struct script_code* code = NULL;
2488         static int first=1;
2489         char end;
2490         bool unresolved_names = false;
2491
2492         parser_current_src = src;
2493         parser_current_file = file;
2494         parser_current_line = line;
2495
2496         if( src == NULL )
2497                 return NULL;// empty script
2498
2499         memset(&syntax,0,sizeof(syntax));
2500         if(first){
2501                 add_buildin_func();
2502                 read_constdb();
2503                 script_hardcoded_constants();
2504                 first=0;
2505         }
2506
2507         script_buf=(unsigned char *)aMalloc(SCRIPT_BLOCK_SIZE*sizeof(unsigned char));
2508         script_pos=0;
2509         script_size=SCRIPT_BLOCK_SIZE;
2510         parse_nextline(true, NULL);
2511
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;
2516
2517         if( setjmp( error_jump ) != 0 ) {
2518                 //Restore program state when script has problems. [from jA]
2519                 int j;
2520                 const int size = ARRAYLENGTH(syntax.curly);
2521                 if( error_report )
2522                         script_error(src,file,line,error_msg,error_pos);
2523                 aFree( error_msg );
2524                 aFree( script_buf );
2525                 script_pos  = 0;
2526                 script_size = 0;
2527                 script_buf  = NULL;
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);
2532                 return NULL;
2533         }
2534
2535         parse_syntax_for_flag=0;
2536         p=src;
2537         p=skip_space(p);
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 );
2543                         script_pos  = 0;
2544                         script_size = 0;
2545                         script_buf  = NULL;
2546                         return NULL;
2547                 }
2548                 end = '\0';
2549         }
2550         else
2551         {// requires brackets around the script
2552                 if( *p != '{' )
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 );
2558                         script_pos  = 0;
2559                         script_size = 0;
2560                         script_buf  = NULL;
2561                         return NULL;
2562                 }
2563                 end = '}';
2564         }
2565
2566         // clear references of labels, variables and internal functions
2567         for(i=LABEL_START;i<str_num;i++){
2568                 if(
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
2571                 ){
2572                         str_data[i].type=C_NOP;
2573                         str_data[i].backpatch=-1;
2574                         str_data[i].label=-1;
2575                 }
2576         }
2577
2578         while( syntax.curly_count != 0 || *p != end )
2579         {
2580                 if( *p == '\0' )
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)){
2585                         i=add_word(p);
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);
2589                         p=tmpp+1;
2590                         p=skip_space(p);
2591                         continue;
2592                 }
2593
2594                 // All other lumped
2595                 p=parse_line(p);
2596                 p=skip_space(p);
2597
2598                 parse_nextline(false, p);
2599         }
2600
2601         add_scriptc(C_NOP);
2602
2603         // trim code to size
2604         script_size = script_pos;
2605         RECREATE(script_buf,unsigned char,script_pos);
2606
2607         // default unknown references to variables
2608         for(i=LABEL_START;i<str_num;i++){
2609                 if(str_data[i].type==C_NOP){
2610                         int j;
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);
2616                                 j=next;
2617                         }
2618                 }
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;
2623                 }
2624         }
2625
2626         if( unresolved_names )
2627         {
2628                 disp_error_message("parse_script: unresolved function references", p);
2629         }
2630
2631 #ifdef DEBUG_DISP
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");
2636         }
2637         ShowMessage("\n");
2638 #endif
2639 #ifdef DEBUG_DISASM
2640         {
2641                 int i = 0,j;
2642                 while(i < script_pos) {
2643                         c_op op = get_com(script_buf,&i);
2644
2645                         ShowMessage("%06x %s", i, script_op2name(op));
2646                         j = i;
2647                         switch(op) {
2648                         case C_INT:
2649                                 ShowMessage(" %d", get_num(script_buf,&i));
2650                                 break;
2651                         case C_POS:
2652                                 ShowMessage(" 0x%06x", *(int*)(script_buf+i)&0xffffff);
2653                                 i += 3;
2654                                 break;
2655                         case C_NAME:
2656                                 j = (*(int*)(script_buf+i)&0xffffff);
2657                                 ShowMessage(" %s", ( j == 0xffffff ) ? "?? unknown ??" : get_str(j));
2658                                 i += 3;
2659                                 break;
2660                         case C_STR:
2661                                 j = strlen(script_buf + i);
2662                                 ShowMessage(" %s", script_buf + i);
2663                                 i += j+1;
2664                                 break;
2665                         }
2666                         ShowMessage(CL_CLL"\n");
2667                 }
2668         }
2669 #endif
2670
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;
2676         return code;
2677 }
2678
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 );
2683
2684         if( *sd ){
2685                 return true;
2686         }else{
2687                 ShowError("%s: fatal error ! player not attached!\n",func);
2688                 script_reportfunc(st);
2689                 script_reportsrc(st);
2690                 st->state = END;
2691                 return false;
2692         }
2693 }
2694
2695 /**
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)
2700  */
2701 void get_val_(struct script_state* st, struct script_data* data, struct map_session_data *sd)
2702 {
2703         const char* name;
2704         char prefix;
2705         char postfix;
2706
2707         if( !data_isreference(data) )
2708                 return;// not a variable/constant
2709
2710         name = reference_getname(data);
2711         prefix = name[0];
2712         postfix = name[strlen(name) - 1];
2713
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);
2723                                 data->type = C_INT;
2724                                 data->u.num = 0;
2725                         }
2726                         return;
2727                 }
2728         }
2729
2730         if( postfix == '$' ) {// string variable
2731
2732                 switch( prefix ) {
2733                         case '@':
2734                                 data->u.str = pc_readregstr(sd, data->u.num);
2735                                 break;
2736                         case '$':
2737                                 data->u.str = mapreg_readregstr(data->u.num);
2738                                 break;
2739                         case '#':
2740                                 if( name[1] == '#' )
2741                                         data->u.str = pc_readaccountreg2str(sd, data->u.num);// global
2742                                 else
2743                                         data->u.str = pc_readaccountregstr(sd, data->u.num);// local
2744                                 break;
2745                         case '.':
2746                                 {
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
2751                                         if( n )
2752                                                 data->u.str = (char*)i64db_get(n,reference_getuid(data));
2753                                         else
2754                                                 data->u.str = NULL;
2755                                 }
2756                                 break;
2757                         case '\'':
2758                                 {
2759                                         unsigned short instance_id = script_instancegetid(st);
2760                                         if( instance_id )
2761                                                 data->u.str = (char*)i64db_get(instance_data[instance_id].regs.vars,reference_getuid(data));
2762                                         else {
2763                                                 ShowWarning("script:get_val: cannot access instance variable '%s', defaulting to \"\"\n", name);
2764                                                 data->u.str = NULL;
2765                                         }
2766                                 }
2767                                 break;
2768                         default:
2769                                 data->u.str = pc_readglobalreg_str(sd, data->u.num);
2770                                 break;
2771                 }
2772
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
2777                         data->type = C_STR;
2778                         data->u.str = aStrdup(data->u.str);
2779                 }
2780
2781         } else {// integer variable
2782
2783                 data->type = C_INT;
2784
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));
2789                 } else
2790                         switch( prefix ) {
2791                                 case '@':
2792                                         data->u.num = pc_readreg(sd, data->u.num);
2793                                         break;
2794                                 case '$':
2795                                         data->u.num = mapreg_readreg(data->u.num);
2796                                         break;
2797                                 case '#':
2798                                         if( name[1] == '#' )
2799                                                 data->u.num = pc_readaccountreg2(sd, data->u.num);// global
2800                                         else
2801                                                 data->u.num = pc_readaccountreg(sd, data->u.num);// local
2802                                         break;
2803                                 case '.':
2804                                         {
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
2809                                                 if( n )
2810                                                         data->u.num = (int)i64db_iget(n,reference_getuid(data));
2811                                                 else
2812                                                         data->u.num = 0;
2813                                         }
2814                                         break;
2815                                 case '\'':
2816                                         {
2817                                                 unsigned short instance_id = script_instancegetid(st);
2818                                                 if( instance_id )
2819                                                         data->u.num = (int)i64db_iget(instance_data[instance_id].regs.vars,reference_getuid(data));
2820                                                 else {
2821                                                         ShowWarning("script:get_val: cannot access instance variable '%s', defaulting to 0\n", name);
2822                                                         data->u.num = 0;
2823                                                 }
2824                                         }
2825                                         break;
2826                                 default:
2827                                         data->u.num = pc_readglobalreg(sd, data->u.num);
2828                                         break;
2829                         }
2830
2831         }
2832         data->ref = NULL;
2833
2834         return;
2835 }
2836
2837 void get_val(struct script_state* st, struct script_data* data)
2838 {
2839         get_val_(st,data,NULL);
2840 }
2841
2842 struct script_data* push_val2(struct script_stack* stack, enum c_op type, int64 val, struct reg_db* ref);
2843
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)
2851 {
2852         struct script_data* data;
2853         push_val2(st->stack, C_NAME, uid, ref);
2854         data = script_getdatatop(st, -1);
2855         get_val(st, data);
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));
2858 }
2859
2860 /**
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
2863  **/
2864 void script_array_ensure_zero(struct script_state *st, struct map_session_data *sd, int64 uid, struct reg_db *ref)
2865 {
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;
2870
2871         if (sd && !st) {
2872                 // when sd comes, st isn't available
2873                 insert = true;
2874         } else {
2875                 if( is_string_variable(name) ) {
2876                         char* str = (char*)get_val2(st, uid, ref);
2877                         if( str && *str )
2878                                 insert = true;
2879                         script_removetop(st, -1, 0);
2880                 } else {
2881                         int32 num = (int32)__64BPRTSIZE(get_val2(st, uid, ref));
2882                         if( num )
2883                                 insert = true;
2884                         script_removetop(st, -1, 0);
2885                 }
2886         }
2887
2888         if (src && src->arrays) {
2889                 struct script_array *sa = static_cast<script_array *>(idb_get(src->arrays, script_getvarid(uid)));
2890                 if (sa) {
2891                         unsigned int i;
2892
2893                         ARR_FIND(0, sa->size, i, sa->members[i] == 0);
2894                         if( i != sa->size ) {
2895                                 if( !insert )
2896                                         script_array_remove_member(src,sa,i);
2897                                 return;
2898                         }
2899
2900                         script_array_add_member(sa,0);
2901                 } else if (insert) {
2902                         script_array_update(src,reference_uid(script_getvarid(uid), 0),false);
2903                 }
2904         }
2905 }
2906
2907 /**
2908  * Returns array size by ID
2909  **/
2910 unsigned int script_array_size(struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref)
2911 {
2912         struct script_array *sa = NULL;
2913         struct reg_db *src = script_array_src(st, sd, name, ref);
2914
2915         if (src && src->arrays)
2916                 sa = static_cast<script_array *>(idb_get(src->arrays, search_str(name)));
2917
2918         return sa ? sa->size : 0;
2919 }
2920
2921 /**
2922  * Returns array's highest key (for that awful getarraysize implementation that doesn't really gets the array size)
2923  **/
2924 unsigned int script_array_highest_key(struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref)
2925 {
2926         struct script_array *sa = NULL;
2927         struct reg_db *src = script_array_src(st, sd, name, ref);
2928
2929         if (src && src->arrays) {
2930                 int key = add_word(name);
2931
2932                 script_array_ensure_zero(st,sd,reference_uid(key, 0), ref);
2933
2934                 if( ( sa = static_cast<script_array *>(idb_get(src->arrays, key)) ) ) {
2935                         unsigned int i, highest_key = 0;
2936
2937                         for(i = 0; i < sa->size; i++) {
2938                                 if( sa->members[i] > highest_key )
2939                                         highest_key = sa->members[i];
2940                         }
2941
2942                         return sa->size ? highest_key + 1 : 0;
2943                 }
2944         }
2945         
2946         return SCRIPT_CMD_SUCCESS;
2947 }
2948
2949 int script_free_array_db(DBKey key, DBData *data, va_list ap)
2950 {
2951         struct script_array *sa = static_cast<script_array *>(db_data2ptr(data));
2952         aFree(sa->members);
2953         ers_free(array_ers, sa);
2954         return SCRIPT_CMD_SUCCESS;
2955 }
2956
2957 /**
2958  * Clears script_array and removes it from script->array_db
2959  **/
2960 void script_array_delete(struct reg_db *src, struct script_array *sa)
2961 {
2962         aFree(sa->members);
2963         idb_remove(src->arrays, sa->id);
2964         ers_free(array_ers, sa);
2965 }
2966
2967 /**
2968  * Removes a member from a script_array list
2969  *
2970  * @param idx the index of the member in script_array struct list, not of the actual array member
2971  **/
2972 void script_array_remove_member(struct reg_db *src, struct script_array *sa, unsigned int idx)
2973 {
2974         unsigned int i, cursor;
2975
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);
2979                 return;
2980         }
2981
2982         sa->members[idx] = UINT_MAX;
2983
2984         for(i = 0, cursor = 0; i < sa->size; i++) {
2985                 if( sa->members[i] == UINT_MAX )
2986                         continue;
2987                 if( i != cursor )
2988                         sa->members[cursor] = sa->members[i];
2989                 cursor++;
2990         }
2991
2992         sa->size = cursor;
2993 }
2994
2995 /**
2996  * Appends a new array index to the list in script_array
2997  *
2998  * @param idx the index of the array member being inserted
2999  **/
3000 void script_array_add_member(struct script_array *sa, unsigned int idx)
3001 {
3002         RECREATE(sa->members, unsigned int, ++sa->size);
3003
3004         sa->members[sa->size - 1] = idx;
3005 }
3006
3007 /**
3008  * Obtains the source of the array database for this type and scenario
3009  * Initializes such database when not yet initialized.
3010  **/
3011 struct reg_db *script_array_src(struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref)
3012 {
3013         struct reg_db *src = NULL;
3014
3015         switch( name[0] ) {
3016                 // from player
3017                 default:  // char reg
3018                 case '@': // temp char reg
3019                 case '#': // account reg
3020                         src = &sd->regs;
3021                         break;
3022                 case '$': // map reg
3023                         src = &regs;
3024                         break;
3025                 case '.': // npc/script
3026                         if (ref)
3027                                 src = ref;
3028                         else
3029                                 src = (name[1] == '@') ? &st->stack->scope : &st->script->local;
3030                         break;
3031                 case '\'': // instance
3032                         {
3033                                 unsigned short instance_id = script_instancegetid(st);
3034
3035                                 if( instance_id ) {
3036                                         src = &instance_data[instance_id].regs;
3037                                 }
3038                                 break;
3039                         }
3040         }
3041
3042         if( src ) {
3043                 if( !src->arrays )
3044                         src->arrays = idb_alloc(DB_OPT_BASE);
3045                 return src;
3046         }
3047
3048         return NULL;
3049 }
3050
3051 /**
3052  * Processes a array member modification, and update data accordingly
3053  *
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)
3057  **/
3058 void script_array_update(struct reg_db *src, int64 num, bool empty)
3059 {
3060         struct script_array *sa = NULL;
3061         int id = script_getvarid(num);
3062         unsigned int index = script_getvaridx(num);
3063
3064         if (!src->arrays) {
3065                 src->arrays = idb_alloc(DB_OPT_BASE);
3066         } else {
3067                 sa = static_cast<script_array *>(idb_get(src->arrays, id));
3068         }
3069
3070         if( sa ) {
3071                 unsigned int i;
3072
3073                 // search
3074                 for(i = 0; i < sa->size; i++) {
3075                         if( sa->members[i] == index )
3076                                 break;
3077                 }
3078
3079                 // if existent
3080                 if( i != sa->size ) {
3081                         // if empty, we gotta remove it
3082                         if( empty ) {
3083                                 script_array_remove_member(src, sa, i);
3084                         }
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
3088                 }
3089         } else if ( !empty ) { // we only move to create if not empty
3090                 sa = ers_alloc(array_ers, struct script_array);
3091                 sa->id = id;
3092                 sa->members = NULL;
3093                 sa->size = 0;
3094                 script_array_add_member(sa,index);
3095                 idb_put(src->arrays, id, sa);
3096         }
3097 }
3098
3099 /**
3100  * Stores the value of a script variable
3101  *
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.
3109  *
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)
3113 {
3114         char prefix = name[0];
3115
3116         if( is_string_variable(name) ) {// string variable
3117                 const char *str = (const char*)value;
3118
3119                 switch (prefix) {
3120                         case '@':
3121                                 pc_setregstr(sd, num, str);
3122                                 return 1;
3123                         case '$':
3124                                 return mapreg_setregstr(num, str);
3125                         case '#':
3126                                 return (name[1] == '#') ?
3127                                         pc_setaccountreg2str(sd, num, str) :
3128                                         pc_setaccountregstr(sd, num, str);
3129                         case '.':
3130                                 {
3131                                         struct reg_db *n = (ref) ? ref : (name[1] == '@') ? &st->stack->scope : &st->script->local;
3132                                         if( n ) {
3133                                                 if (str[0])  {
3134                                                         i64db_put(n->vars, num, aStrdup(str));
3135                                                         if( script_getvaridx(num) )
3136                                                                 script_array_update(n, num, false);
3137                                                 } else {
3138                                                         i64db_remove(n->vars, num);
3139                                                         if( script_getvaridx(num) )
3140                                                                 script_array_update(n, num, true);
3141                                                 }
3142                                         }
3143                                 }
3144                                 return 1;
3145                         case '\'':
3146                                 {
3147                                         unsigned short instance_id = script_instancegetid(st);
3148                                         if( instance_id ) {
3149                                                 if( str[0] ) {
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);
3153                                                 } else {
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);
3157                                                 }
3158                                         } else {
3159                                                 ShowError("script_set_reg: cannot write instance variable '%s', NPC not in a instance!\n", name);
3160                                                 script_reportsrc(st);
3161                                         }
3162                                 return 1;
3163                                 }
3164                         default:
3165                                 return pc_setglobalreg_str(sd, num, str);
3166                 }
3167         } else {// integer variable
3168                 int val = (int)__64BPRTSIZE(value);
3169
3170                 if(str_data[script_getvarid(num)].type == C_PARAM) {
3171                         if( pc_setparam(sd, str_data[script_getvarid(num)].val, val) == 0 ) {
3172                                 if( st != NULL ) {
3173                                         ShowError("script_set_reg: failed to set param '%s' to %d.\n", name, val);
3174                                         script_reportsrc(st);
3175                                         st->state = END;
3176                                 }
3177                                 return 0;
3178                         }
3179                         return 1;
3180                 }
3181
3182                 switch (prefix) {
3183                         case '@':
3184                                 pc_setreg(sd, num, val);
3185                                 return 1;
3186                         case '$':
3187                                 return mapreg_setreg(num, val);
3188                         case '#':
3189                                 return (name[1] == '#') ?
3190                                         pc_setaccountreg2(sd, num, val) :
3191                                         pc_setaccountreg(sd, num, val);
3192                         case '.':
3193                                 {
3194                                         struct reg_db *n = (ref) ? ref : (name[1] == '@') ? &st->stack->scope : &st->script->local;
3195                                         if( n ) {
3196                                                 if( val != 0 ) {
3197                                                         i64db_iput(n->vars, num, val);
3198                                                         if( script_getvaridx(num) )
3199                                                                 script_array_update(n, num, false);
3200                                                 } else {
3201                                                         i64db_remove(n->vars, num);
3202                                                         if( script_getvaridx(num) )
3203                                                                 script_array_update(n, num, true);
3204                                                 }
3205                                         }
3206                                 }
3207                                 return 1;
3208                         case '\'':
3209                                 {
3210                                         unsigned short instance_id = script_instancegetid(st);
3211                                         if( instance_id ) {
3212                                                 if( val != 0 ) {
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);
3216                                                 } else {
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);
3220                                                 }
3221                                         } else {
3222                                                 ShowError("script_set_reg: cannot write instance variable '%s', NPC not in a instance!\n", name);
3223                                                 script_reportsrc(st);
3224                                         }
3225                                 return 1;
3226                                 }
3227                         default:
3228                                 return pc_setglobalreg(sd, num, val);
3229                 }
3230         }
3231 }
3232
3233 int set_var(struct map_session_data* sd, char* name, void* val)
3234 {
3235         return set_reg(NULL, sd, reference_uid(add_str(name),0), name, val, NULL);
3236 }
3237
3238 void setd_sub(struct script_state *st, TBL_PC *sd, const char *varname, int elem, void *value, struct reg_db *ref)
3239 {
3240         set_reg(st, sd, reference_uid(add_str(varname),elem), varname, value, ref);
3241 }
3242
3243 /**
3244  * Converts the data to a string
3245  * @param st
3246  * @param data
3247  * @param sd
3248  */
3249 const char* conv_str_(struct script_state* st, struct script_data* data, struct map_session_data *sd)
3250 {
3251         char* p;
3252
3253         get_val_(st, data, sd);
3254         if( data_isstring(data) )
3255         {// nothing to convert
3256         }
3257         else if( data_isint(data) )
3258         {// int -> string
3259                 CREATE(p, char, ITEM_NAME_LENGTH);
3260                 snprintf(p, ITEM_NAME_LENGTH, "%" PRId64 "", data->u.num);
3261                 p[ITEM_NAME_LENGTH-1] = '\0';
3262                 data->type = C_STR;
3263                 data->u.str = p;
3264         }
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);
3270         }
3271         else
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 *>("");
3278         }
3279         return data->u.str;
3280 }
3281
3282 const char* conv_str(struct script_state* st, struct script_data* data)
3283 {
3284         return conv_str_(st, data, NULL);
3285 }
3286
3287 /**
3288  * Converts the data to an int
3289  * @param st
3290  * @param data
3291  * @param sd
3292  */
3293 int conv_num_(struct script_state* st, struct script_data* data, struct map_session_data *sd)
3294 {
3295         get_val_(st, data, sd);
3296         if( data_isint(data) )
3297         {// nothing to convert
3298         }
3299         else if( data_isstring(data) )
3300         {// string -> int
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;
3304                 long num;
3305
3306                 errno = 0;
3307                 num = strtol(data->u.str, NULL, 10);// change radix to 0 to support octal numbers "o377" and hex numbers "0xFF"
3308                 if( errno == ERANGE
3309 #if LONG_MAX > INT_MAX
3310                         || num < INT_MIN || num > INT_MAX
3311 #endif
3312                         )
3313                 {
3314                         if( num <= INT_MIN )
3315                         {
3316                                 num = INT_MIN;
3317                                 ShowError("script:conv_num: underflow detected, capping to %ld\n", num);
3318                         }
3319                         else//if( num >= INT_MAX )
3320                         {
3321                                 num = INT_MAX;
3322                                 ShowError("script:conv_num: overflow detected, capping to %ld\n", num);
3323                         }
3324                         script_reportdata(data);
3325                         script_reportsrc(st);
3326                 }
3327                 if( data->type == C_STR )
3328                         aFree(p);
3329                 data->type = C_INT;
3330                 data->u.num = (int)num;
3331         }
3332 #if 0
3333         // FIXME this function is being used to retrieve the position of labels and
3334         // probably other stuff [FlavioJS]
3335         else
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);
3340                 data->type = C_INT;
3341                 data->u.num = 0;
3342         }
3343 #endif
3344         return (int)data->u.num;
3345 }
3346
3347 int conv_num(struct script_state* st, struct script_data* data)
3348 {
3349         return conv_num_(st, data, NULL);
3350 }
3351
3352 //
3353 // Stack operations
3354 //
3355
3356 /// Increases the size of the stack
3357 void stack_expand(struct script_stack* stack)
3358 {
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]) );
3364 }
3365
3366 /// Pushes a value into the stack
3367 #define push_val(stack,type,val) push_val2(stack, type, val, NULL)
3368
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)
3371 {
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;
3377         stack->sp++;
3378         return &stack->stack_data[stack->sp-1];
3379 }
3380
3381 /// Pushes a string into the stack
3382 struct script_data* push_str(struct script_stack* stack, enum c_op type, char* str)
3383 {
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;
3389         stack->sp++;
3390         return &stack->stack_data[stack->sp-1];
3391 }
3392
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)
3395 {
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;
3401         stack->sp++;
3402         return &stack->stack_data[stack->sp-1];
3403 }
3404
3405 /// Pushes a copy of the target position into the stack
3406 struct script_data* push_copy(struct script_stack* stack, int pos)
3407 {
3408         switch( stack->stack_data[pos].type ) {
3409                 case C_CONSTSTR:
3410                         return push_str(stack, C_CONSTSTR, stack->stack_data[pos].u.str);
3411                         break;
3412                 case C_STR:
3413                         return push_str(stack, C_STR, aStrdup(stack->stack_data[pos].u.str));
3414                         break;
3415                 case C_RETINFO:
3416                         ShowFatalError("script:push_copy: can't create copies of C_RETINFO. Exiting...\n");
3417                         exit(1);
3418                         break;
3419                 default:
3420                         return push_val2(
3421                                 stack,stack->stack_data[pos].type,
3422                                 stack->stack_data[pos].u.num,
3423                                 stack->stack_data[pos].ref
3424                         );
3425                         break;
3426         }
3427 }
3428
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)
3432 {
3433         struct script_stack* stack = st->stack;
3434         struct script_data* data;
3435         int i;
3436
3437         if( start < 0 )
3438                 start = 0;
3439         if( end > stack->sp )
3440                 end = stack->sp;
3441         if( start >= end )
3442                 return;// nothing to pop
3443
3444         // free stack elements
3445         for( i = start; i < end; i++ )
3446         {
3447                 data = &stack->stack_data[i];
3448                 if( data->type == C_STR )
3449                         aFree(data->u.str);
3450                 if( data->type == C_RETINFO ) {
3451                         struct script_retinfo* ri = data->u.ri;
3452
3453                         if (ri->scope.vars) {
3454                                 script_free_vars(ri->scope.vars);
3455                                 ri->scope.vars = NULL;
3456                         }
3457                         if (ri->scope.arrays) {
3458                                 ri->scope.arrays->destroy(ri->scope.arrays, script_free_array_db);
3459                                 ri->scope.arrays = NULL;
3460                         }
3461                         if( data->ref )
3462                                 aFree(data->ref);
3463                         aFree(ri);
3464                 }
3465                 data->type = C_NOP;
3466         }
3467
3468         // move the rest of the elements
3469         if( stack->sp > end )
3470         {
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;
3474         }
3475
3476         // adjust stack pointers
3477         if( st->start > end ){
3478                 st->start -= end - start;
3479         }else if( st->start > start ){
3480                 st->start = start;
3481         }
3482         
3483         if( st->end > end ){
3484                 st->end -= end - start;
3485         }else if( st->end > start ){
3486                 st->end = start;
3487         }
3488         
3489         if( stack->defsp > end ){
3490                 stack->defsp -= end - start;
3491         }else if( stack->defsp > start ){
3492                 stack->defsp = start;
3493         }
3494         
3495         stack->sp -= end - start;
3496 }
3497
3498 ///
3499 ///
3500 ///
3501
3502 /*==========================================
3503  * Release script dependent variable, dependent variable of function
3504  *------------------------------------------*/
3505 void script_free_vars(struct DBMap* storage)
3506 {
3507         if( storage ) {
3508                 // destroy the storage construct containing the variables
3509                 db_destroy(storage);
3510         }
3511 }
3512
3513 void script_free_code(struct script_code* code)
3514 {
3515         nullpo_retv(code);
3516
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);
3523         aFree(code);
3524 }
3525
3526 /// Creates a new script state.
3527 ///
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)
3534 {
3535         struct script_state* st;
3536
3537         st = ers_alloc(st_ers, struct script_state);
3538         st->stack = ers_alloc(stack_ers, struct script_stack);
3539         st->stack->sp = 0;
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;
3545         st->state = RUN;
3546         st->script = rootscript;
3547         st->pos = pos;
3548         st->rid = rid;
3549         st->oid = oid;
3550         st->sleep.timer = INVALID_TIMER;
3551         st->npc_item_flag = battle_config.item_enabled_npc;
3552         
3553         if( st->script->instances != USHRT_MAX )
3554                 st->script->instances++;
3555         else {
3556                 struct npc_data *nd = map_id2nd(oid);
3557
3558                 ShowError("Over 65k instances of '%s' script are being run!\n",nd ? nd->name : "unknown");
3559         }
3560
3561         if (!st->script->local.vars)
3562                 st->script->local.vars = i64db_alloc(DB_OPT_RELEASE_DATA);
3563
3564         st->id = next_id++;
3565         active_scripts++;
3566
3567         idb_put(st_db, st->id, st);
3568
3569         return st;
3570 }
3571
3572 /// Frees a script state.
3573 ///
3574 /// @param st Script state
3575 void script_free_state(struct script_state* st)
3576 {
3577         if (idb_exists(st_db, st->id)) {
3578                 struct map_session_data *sd = st->rid ? map_id2sd(st->rid) : NULL;
3579
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);
3582
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;
3587                         }
3588                         sd->st = NULL;
3589                         sd->npc_id = 0;
3590                 }
3591
3592                 if (st->sleep.timer != INVALID_TIMER)
3593                         delete_timer(st->sleep.timer, run_script_timer);
3594                 if (st->stack) {
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);
3601                         st->stack = NULL;
3602                 }
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;
3607                         }
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;
3611                         }
3612                 }
3613                 st->pos = -1;
3614
3615                 idb_remove(st_db, st->id);
3616                 ers_free(st_ers, st);
3617                 if (--active_scripts == 0)
3618                         next_id = 0;
3619         }
3620 }
3621
3622 //
3623 // Main execution unit
3624 //
3625 /*==========================================
3626  * Read command
3627  *------------------------------------------*/
3628 c_op get_com(unsigned char *script,int *pos)
3629 {
3630         int i = 0, j = 0;
3631
3632         if(script[*pos]>=0x80){
3633                 return C_INT;
3634         }
3635         while(script[*pos]>=0x40){
3636                 i=script[(*pos)++]<<j;
3637                 j+=6;
3638         }
3639         return (c_op)(i+(script[(*pos)++]<<j));
3640 }
3641
3642 /*==========================================
3643  *  Income figures
3644  *------------------------------------------*/
3645 int get_num(unsigned char *script,int *pos)
3646 {
3647         int i,j;
3648         i=0; j=0;
3649         while(script[*pos]>=0xc0){
3650                 i+=(script[(*pos)++]&0x7f)<<j;
3651                 j+=6;
3652         }
3653         return i+((script[(*pos)++]&0x7f)<<j);
3654 }
3655
3656 /// Ternary operators
3657 /// test ? if_true : if_false
3658 void op_3(struct script_state* st, int op)
3659 {
3660         struct script_data* data;
3661         int flag = 0;
3662
3663         data = script_getdatatop(st, -3);
3664         get_val(st, data);
3665
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
3670         else
3671         {
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);
3676                 script_pushnil(st);
3677                 return;
3678         }
3679         if( flag )
3680                 script_pushcopytop(st, -2);
3681         else
3682                 script_pushcopytop(st, -1);
3683         script_removetop(st, -4, -1);
3684 }
3685
3686 /// Binary string operators
3687 /// s1 EQ s2 -> i
3688 /// s1 NE s2 -> i
3689 /// s1 GT s2 -> i
3690 /// s1 GE s2 -> i
3691 /// s1 LT s2 -> i
3692 /// s1 LE s2 -> i
3693 /// s1 ADD s2 -> s
3694 void op_2str(struct script_state* st, int op, const char* s1, const char* s2)
3695 {
3696         int a = 0;
3697
3698         switch(op){
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;
3705                 case C_ADD:
3706                         {
3707                                 char* buf = (char *)aMalloc((strlen(s1)+strlen(s2)+1)*sizeof(char));
3708                                 strcpy(buf, s1);
3709                                 strcat(buf, s2);
3710                                 script_pushstr(st, buf);
3711                                 return;
3712                         }
3713                 default:
3714                         ShowError("script:op2_str: unexpected string operator %s\n", script_op2name(op));
3715                         script_reportsrc(st);
3716                         script_pushnil(st);
3717                         st->state = END;
3718                         return;
3719         }
3720
3721         script_pushint(st,a);
3722 }
3723
3724 /// Binary number operators
3725 /// i OP i -> i
3726 void op_2num(struct script_state* st, int op, int i1, int i2)
3727 {
3728         int ret;
3729         double ret_double;
3730
3731         switch( op ) {
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;
3745                 case C_DIV:
3746                 case C_MOD:
3747                         if( i2 == 0 )
3748                         {
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);
3751                                 script_pushnil(st);
3752                                 st->state = END;
3753                                 return;
3754                         }
3755                         else if( op == C_DIV )
3756                                 ret = i1 / i2;
3757                         else//if( op == C_MOD )
3758                                 ret = i1 % i2;
3759                         break;
3760                 default:
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;
3765                                 default:
3766                                         ShowError("script:op_2num: unexpected number operator %s i1=%d i2=%d\n", script_op2name(op), i1, i2);
3767                                         script_reportsrc(st);
3768                                         script_pushnil(st);
3769                                         return;
3770                         }
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);
3774                                 ret = INT_MIN;
3775                         }
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);
3779                                 ret = INT_MAX;
3780                         }
3781         }
3782         script_pushint(st, ret);
3783 }
3784
3785 /// Binary operators
3786 void op_2(struct script_state *st, int op)
3787 {
3788         struct script_data* left, leftref;
3789         struct script_data* right;
3790
3791         leftref.type = C_NOP;
3792
3793         left = script_getdatatop(st, -2);
3794         right = script_getdatatop(st, -1);
3795
3796         if (st->op2ref) {
3797                 if (data_isreference(left)) {
3798                         leftref = *left;
3799                 }
3800
3801                 st->op2ref = 0;
3802         }
3803
3804         get_val(st, left);
3805         get_val(st, right);
3806
3807         // automatic conversions
3808         switch( op )
3809         {
3810                 case C_ADD:
3811                         if( data_isint(left) && data_isstring(right) )
3812                         {// convert int-string to string-string
3813                                 conv_str(st, left);
3814                         }
3815                         else if( data_isstring(left) && data_isint(right) )
3816                         {// convert string-int to string-string
3817                                 conv_str(st, right);
3818                         }
3819                         break;
3820         }
3821
3822         if( data_isstring(left) && data_isstring(right) )
3823         {// ss => op_2str
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
3826
3827                 if (leftref.type != C_NOP)
3828                 {
3829                         if (left->type == C_STR) // don't free C_CONSTSTR
3830                                 aFree(left->u.str);
3831                         *left = leftref;
3832                 }
3833         }
3834         else if( data_isint(left) && data_isint(right) )
3835         {// ii => op_2num
3836                 int i1 = (int)left->u.num;
3837                 int i2 = (int)right->u.num;
3838
3839                 script_removetop(st, leftref.type == C_NOP ? -2 : -1, 0);
3840                 op_2num(st, op, i1, i2);
3841
3842                 if (leftref.type != C_NOP)
3843                         *left = leftref;
3844         }
3845         else
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);
3852                 script_pushnil(st);
3853                 st->state = END;
3854         }
3855 }
3856
3857 /// Unary operators
3858 /// NEG i -> i
3859 /// NOT i -> i
3860 /// LNOT i -> i
3861 void op_1(struct script_state* st, int op)
3862 {
3863         struct script_data* data;
3864         int i1;
3865
3866         data = script_getdatatop(st, -1);
3867         get_val(st, data);
3868
3869         if( !data_isint(data) )
3870         {// not a number
3871                 ShowError("script:op_1: argument is not a number (op=%s)\n", script_op2name(op));
3872                 script_reportdata(data);
3873                 script_reportsrc(st);
3874                 script_pushnil(st);
3875                 st->state = END;
3876                 return;
3877         }
3878
3879         i1 = (int)data->u.num;
3880         script_removetop(st, -1, 0);
3881         switch( op )
3882         {
3883                 case C_NEG: i1 = -i1; break;
3884                 case C_NOT: i1 = ~i1; break;
3885                 case C_LNOT: i1 = !i1; break;
3886                 default:
3887                         ShowError("script:op_1: unexpected operator %s i1=%d\n", script_op2name(op), i1);
3888                         script_reportsrc(st);
3889                         script_pushnil(st);
3890                         st->state = END;
3891                         return;
3892         }
3893         script_pushint(st, i1);
3894 }
3895
3896
3897 /// Checks the type of all arguments passed to a built-in function.
3898 ///
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)
3902 {
3903         int idx, invalid = 0;
3904
3905         for( idx = 2; script_hasdata(st, idx); idx++ )
3906         {
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];
3910
3911                 if( type == '?' || type == '*' )
3912                 {// optional argument or unknown number of optional parameters ( no types are after this )
3913                         break;
3914                 }
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));
3918                         invalid++;
3919                         break;
3920                 }
3921                 else
3922                 {
3923                         const char* name = NULL;
3924
3925                         if( data_isreference(data) )
3926                         {// get name for variables to determine the type they refer to
3927                                 name = reference_getname(data);
3928                         }
3929
3930                         switch( type )
3931                         {
3932                                 case 'v':
3933                                         if( !data_isstring(data) && !data_isint(data) && !data_isreference(data) )
3934                                         {// variant
3935                                                 ShowWarning("Unexpected type for argument %d. Expected string, number or variable.\n", idx-1);
3936                                                 script_reportdata(data);
3937                                                 invalid++;
3938                                         }
3939                                         break;
3940                                 case 's':
3941                                         if( !data_isstring(data) && !( data_isreference(data) && is_string_variable(name) ) )
3942                                         {// string
3943                                                 ShowWarning("Unexpected type for argument %d. Expected string.\n", idx-1);
3944                                                 script_reportdata(data);
3945                                                 invalid++;
3946                                         }
3947                                         break;
3948                                 case 'i':
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);
3953                                                 invalid++;
3954                                         }
3955                                         break;
3956                                 case 'r':
3957                                         if( !data_isreference(data) )
3958                                         {// variables
3959                                                 ShowWarning("Unexpected type for argument %d. Expected variable, got %s.\n", idx-1,script_op2name(data->type));
3960                                                 script_reportdata(data);
3961                                                 invalid++;
3962                                         }
3963                                         break;
3964                                 case 'l':
3965                                         if( !data_islabel(data) && !data_isfunclabel(data) )
3966                                         {// label
3967                                                 ShowWarning("Unexpected type for argument %d. Expected label, got %s\n", idx-1,script_op2name(data->type));
3968                                                 script_reportdata(data);
3969                                                 invalid++;
3970                                         }
3971                                         break;
3972                         }
3973                 }
3974         }
3975
3976         if(invalid)
3977         {
3978                 ShowDebug("Function: %s\n", get_str(func));
3979                 script_reportsrc(st);
3980         }
3981 }
3982
3983
3984 /// Executes a buildin command.
3985 /// Stack: C_NAME(<command>) C_ARG <arg0> <arg1> ... <argN>
3986 int run_func(struct script_state *st)
3987 {
3988         struct script_data* data;
3989         int i,start_sp,end_sp,func;
3990
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 )
3994                         break;
3995         if( i == 0 ) {
3996                 ShowError("script:run_func: C_ARG not found. please report this!!!\n");
3997                 st->state = END;
3998                 script_reportsrc(st);
3999                 return 1;
4000         }
4001         start_sp = i-1;// C_NAME of the command
4002         st->start = start_sp;
4003         st->end = end_sp;
4004
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);
4009         } else {
4010                 ShowError("script:run_func: not a buildin command.\n");
4011                 script_reportdata(data);
4012                 script_reportsrc(st);
4013                 st->state = END;
4014                 return 1;
4015         }
4016
4017         if( script_config.warn_func_mismatch_argtypes ) {
4018                 script_check_buildin_argtype(st, func);
4019         }
4020
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);
4027                 }
4028 #endif
4029
4030                 if (str_data[func].func(st) == SCRIPT_CMD_FAILURE) //Report error
4031                         script_reportsrc(st);
4032         } else {
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);
4035                 st->state = END;
4036         }
4037
4038         // Stack's datum are used when re-running functions [Eoe]
4039         if( st->state == RERUNLINE )
4040                 return 0;
4041
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;
4046                 int nargs;
4047
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 )
4050                 {
4051                         ShowWarning("script:run_func: return without callfunc or callsub!\n");
4052                         script_reportsrc(st);
4053                         st->state = END;
4054                         return 1;
4055                 }
4056                 script_free_vars(st->stack->scope.vars);
4057                 st->stack->scope.arrays->destroy(st->stack->scope.arrays, script_free_array_db);
4058
4059                 ri = st->stack->stack_data[st->stack->defsp-1].u.ri;
4060                 nargs = ri->nargs;
4061                 st->pos = ri->pos;
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));
4067
4068                 pop_stack(st, olddefsp-nargs-1, olddefsp);// pop arguments and retinfo
4069
4070                 st->state = GOTO;
4071         }
4072
4073         return 0;
4074 }
4075
4076 /*==========================================
4077  * script execution
4078  *------------------------------------------*/
4079 void run_script(struct script_code *rootscript, int pos, int rid, int oid)
4080 {
4081         struct script_state *st;
4082
4083         if( rootscript == NULL || pos < 0 )
4084                 return;
4085
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);
4091 }
4092
4093 /**
4094  * Free all related script code
4095  * @param code: Script code to free
4096  */
4097 void script_stop_scriptinstances(struct script_code *code) {
4098         DBIterator *iter;
4099         struct script_state* st;
4100
4101         if( !active_scripts )
4102                 return; // Don't even bother.
4103
4104         iter = db_iterator(st_db);
4105
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);
4109         }
4110
4111         dbi_destroy(iter);
4112 }
4113
4114 /*==========================================
4115  * Timer function for sleep
4116  *------------------------------------------*/
4117 int run_script_timer(int tid, unsigned int tick, int id, intptr_t data)
4118 {
4119         struct script_state *st = (struct script_state *)data;
4120         struct linkdb_node *node = (struct linkdb_node *)sleep_db;
4121
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);
4125
4126                 // Attached player is offline(logout) or another unit type(should not happen)
4127                 if( !sd ){
4128                         st->rid = 0;
4129                         st->state = END;
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);
4134                         st->rid = 0;
4135                         st->state = END;
4136                 }
4137         }
4138
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;
4143                         break;
4144                 }
4145                 node = node->next;
4146         }
4147         if(st->state != RERUNLINE)
4148                 st->sleep.tick = 0;
4149         run_script_main(st);
4150         return 0;
4151 }
4152
4153 /**
4154  * Remove sleep timers from the NPC
4155  * @param id: NPC ID
4156  */
4157 void script_stop_sleeptimers(int id) {
4158         for (;;) {
4159                 struct script_state *st = (struct script_state *)linkdb_erase(&sleep_db, (void *)__64BPRTSIZE(id));
4160
4161                 if (!st)
4162                         break; // No more sleep timers
4163
4164                 if (st->oid == id)
4165                         script_free_state(st);
4166         }
4167 }
4168
4169 /**
4170  * Delete the specified node from sleep_db
4171  * @param n: Linked list of sleep timers
4172  */
4173 struct linkdb_node *script_erase_sleepdb(struct linkdb_node *n) {
4174         struct linkdb_node *retnode;
4175
4176         if (!n)
4177                 return NULL;
4178
4179         if (!n->prev)
4180                 sleep_db = n->next;
4181         else
4182                 n->prev->next = n->next;
4183
4184         if (n->next)
4185                 n->next->prev = n->prev;
4186
4187         retnode = n->next;
4188         aFree(n);
4189
4190         return retnode;
4191 }
4192
4193 /// Detaches script state from possibly attached character and restores it's previous script if any.
4194 ///
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)
4198 {
4199         struct map_session_data* sd;
4200
4201         if(st->rid && (sd = map_id2sd(st->rid))!=NULL) {
4202                 sd->st = st->bk_st;
4203                 sd->npc_id = st->bk_npcid;
4204                 sd->state.disable_atcommand_on_npc = 0;
4205                 if(st->bk_st) {
4206                         //Remove tag for removal.
4207                         st->bk_st = NULL;
4208                         st->bk_npcid = 0;
4209                 } else if(dequeue_event) {
4210
4211 #ifdef SECURE_NPCTIMEOUT
4212                         /**
4213                          * We're done with this NPC session, so we cancel the timer (if existent) and move on
4214                          **/
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;
4218                         }
4219 #endif
4220                         npc_event_dequeue(sd);
4221                 }
4222         }
4223         else if(st->bk_st)
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);
4227
4228                 script_free_state(st->bk_st);
4229                 st->bk_st = NULL;
4230         }
4231 }
4232
4233 /// Attaches script state to possibly attached character and backups it's previous script, if any.
4234 ///
4235 /// @param st Script state to attach.
4236 static void script_attach_state(struct script_state* st)
4237 {
4238         struct map_session_data* sd;
4239
4240         if(st->rid && (sd = map_id2sd(st->rid))!=NULL)
4241         {
4242                 if(st!=sd->st)
4243                 {
4244                         if(st->bk_st)
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);
4247                         }
4248                         st->bk_st = sd->st;
4249                         st->bk_npcid = sd->npc_id;
4250                 }
4251                 sd->st = st;
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();
4259 #endif
4260         }
4261 }
4262
4263 /*==========================================
4264  * The main part of the script execution
4265  *------------------------------------------*/
4266 void run_script_main(struct script_state *st)
4267 {
4268         int cmdcount = script_config.check_cmdcount;
4269         int gotocount = script_config.check_gotocount;
4270         TBL_PC *sd;
4271         struct script_stack *stack = st->stack;
4272
4273         script_attach_state(st);
4274
4275         if(st->state == RERUNLINE) {
4276                 run_func(st);
4277                 if(st->state == GOTO)
4278                         st->state = RUN;
4279         } else if(st->state != END)
4280                 st->state = RUN;
4281
4282         while(st->state == RUN) {
4283                 enum c_op c = get_com(st->script->script_buf,&st->pos);
4284                 switch(c){
4285                 case C_EOL:
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);
4288                         else
4289                                 pop_stack(st, stack->defsp, stack->sp);// pop unused stack data. (unused return value)
4290                         break;
4291                 case C_INT:
4292                         push_val(stack,C_INT,get_num(st->script->script_buf,&st->pos));
4293                         break;
4294                 case C_POS:
4295                 case C_NAME:
4296                         push_val(stack,c,GETVALUE(st->script->script_buf,st->pos));
4297                         st->pos+=3;
4298                         break;
4299                 case C_ARG:
4300                         push_val(stack,c,0);
4301                         break;
4302                 case C_STR:
4303                         push_str(stack,C_CONSTSTR,(char*)(st->script->script_buf+st->pos));
4304                         while(st->script->script_buf[st->pos++]);
4305                         break;
4306                 case C_FUNC:
4307                         run_func(st);
4308                         if(st->state==GOTO){
4309                                 st->state = RUN;
4310                                 if( !st->freeloop && gotocount>0 && (--gotocount)<=0 ){
4311                                         ShowError("script:run_script_main: infinity loop !\n");
4312                                         script_reportsrc(st);
4313                                         st->state=END;
4314                                 }
4315                         }
4316                         break;
4317
4318                 case C_REF:
4319                         st->op2ref = 1;
4320                         break;
4321
4322                 case C_NEG:
4323                 case C_NOT:
4324                 case C_LNOT:
4325                         op_1(st ,c);
4326                         break;
4327
4328                 case C_ADD:
4329                 case C_SUB:
4330                 case C_MUL:
4331                 case C_DIV:
4332                 case C_MOD:
4333                 case C_EQ:
4334                 case C_NE:
4335                 case C_GT:
4336                 case C_GE:
4337                 case C_LT:
4338                 case C_LE:
4339                 case C_AND:
4340                 case C_OR:
4341                 case C_XOR:
4342                 case C_LAND:
4343                 case C_LOR:
4344                 case C_R_SHIFT:
4345                 case C_L_SHIFT:
4346                         op_2(st, c);
4347                         break;
4348
4349                 case C_OP3:
4350                         op_3(st, c);
4351                         break;
4352
4353                 case C_NOP:
4354                         st->state=END;
4355                         break;
4356
4357                 default:
4358                         ShowError("script:run_script_main:unknown command : %d @ %d\n",c,st->pos);
4359                         st->state=END;
4360                         break;
4361                 }
4362                 if( !st->freeloop && cmdcount>0 && (--cmdcount)<=0 ){
4363                         ShowError("script:run_script_main: infinity loop !\n");
4364                         script_reportsrc(st);
4365                         st->state=END;
4366                 }
4367         }
4368
4369         if(st->sleep.tick > 0) {
4370                 //Restore previous script
4371                 script_detach_state(st, false);
4372                 //Delay execution
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).
4379                 if(st->bk_st) {
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);
4386
4387                         script_free_state(st->bk_st);
4388                         st->bk_st = NULL;
4389                 }
4390         } else {
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;
4397                         }
4398                         //Restore previous script if any.
4399                         script_detach_state(st, true);
4400                         if (sd->vars_dirty)
4401                                 intif_saveregistry(sd);
4402                 }
4403                 script_free_state(st);
4404         }
4405 }
4406
4407 int script_config_read(const char *cfgName)
4408 {
4409         int i;
4410         char line[1024],w1[1024],w2[1024];
4411         FILE *fp;
4412
4413
4414         fp=fopen(cfgName,"r");
4415         if(fp==NULL){
4416                 ShowError("File not found: %s\n", cfgName);
4417                 return 1;
4418         }
4419         while(fgets(line, sizeof(line), fp))
4420         {
4421                 if(line[0] == '/' && line[1] == '/')
4422                         continue;
4423                 i=sscanf(line,"%1023[^:]: %1023[^\r\n]",w1,w2);
4424                 if(i!=2)
4425                         continue;
4426
4427                 if(strcmpi(w1,"warn_func_mismatch_paramnum")==0) {
4428                         script_config.warn_func_mismatch_paramnum = config_switch(w2);
4429                 }
4430                 else if(strcmpi(w1,"check_cmdcount")==0) {
4431                         script_config.check_cmdcount = config_switch(w2);
4432                 }
4433                 else if(strcmpi(w1,"check_gotocount")==0) {
4434                         script_config.check_gotocount = config_switch(w2);
4435                 }
4436                 else if(strcmpi(w1,"input_min_value")==0) {
4437                         script_config.input_min_value = config_switch(w2);
4438                 }
4439                 else if(strcmpi(w1,"input_max_value")==0) {
4440                         script_config.input_max_value = config_switch(w2);
4441                 }
4442                 else if(strcmpi(w1,"warn_func_mismatch_argtypes")==0) {
4443                         script_config.warn_func_mismatch_argtypes = config_switch(w2);
4444                 }
4445                 else if(strcmpi(w1,"import")==0){
4446                         script_config_read(w2);
4447                 }
4448                 else {
4449                         ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName);
4450                 }
4451         }
4452         fclose(fp);
4453
4454         return 0;
4455 }
4456
4457 /**
4458  * @see DBApply
4459  */
4460 static int db_script_free_code_sub(DBKey key, DBData *data, va_list ap)
4461 {
4462         struct script_code *code = static_cast<script_code *>(db_data2ptr(data));
4463         if (code)
4464                 script_free_code(code);
4465         return 0;
4466 }
4467
4468 void script_run_autobonus(const char *autobonus, struct map_session_data *sd, unsigned int pos)
4469 {
4470         struct script_code *script = (struct script_code *)strdb_get(autobonus_db, autobonus);
4471
4472         if( script )
4473         {
4474                 int j;
4475                 ARR_FIND( 0, EQI_MAX, j, sd->equip_index[j] >= 0 && sd->inventory.u.items_inventory[sd->equip_index[j]].equip == pos );
4476                 if( j < EQI_MAX ) {
4477                         //Single item autobonus
4478                         current_equip_item_index = sd->equip_index[j];
4479                         current_equip_combo_pos = 0;
4480                 } else {
4481                         //Combo autobonus
4482                         current_equip_item_index = -1;
4483                         current_equip_combo_pos = pos;
4484                 }
4485                 run_script(script,0,sd->bl.id,0);
4486         }
4487 }
4488
4489 void script_add_autobonus(const char *autobonus)
4490 {
4491         if( strdb_get(autobonus_db, autobonus) == NULL )
4492         {
4493                 struct script_code *script = parse_script(autobonus, "autobonus", 0, 0);
4494
4495                 if( script )
4496                         strdb_put(autobonus_db, autobonus, script);
4497         }
4498 }
4499
4500
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)
4503 {
4504         struct script_array *sa = NULL;
4505         struct reg_db *src = NULL;
4506         unsigned int i, *list = NULL, size = 0;
4507         int key;
4508
4509         key = add_str(varname);
4510
4511         if( !(src = script_array_src(NULL,sd,varname,NULL) ) )
4512                 return;
4513
4514         if( value )
4515                 script_array_ensure_zero(NULL,sd,reference_uid(key,0), NULL);
4516
4517         if( !(sa = static_cast<script_array *>(idb_get(src->arrays, key))) ) /* non-existent array, nothing to empty */
4518                 return;
4519
4520         size = sa->size;
4521         list = script_array_cpy_list(sa);
4522
4523         for(i = 0; i < size; i++) {
4524                 set_reg(NULL,sd,reference_uid(key, list[i]),varname,value,NULL);
4525         }
4526 }
4527
4528
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)
4532 {
4533         int key;
4534
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);
4537                 return;
4538         }
4539
4540         key = ( refcache && refcache[0] ) ? refcache[0] : add_str(varname);
4541
4542         set_reg(NULL,sd,reference_uid(key, idx),varname,value,NULL);
4543
4544         if( refcache ) {
4545                 // save to avoid repeated script->add_str calls
4546                 refcache[0] = key;
4547         }
4548 }
4549
4550 /**
4551  * Clears persistent variables from memory
4552  **/
4553 int script_reg_destroy(DBKey key, DBData *data, va_list ap)
4554 {
4555         struct script_reg_state *src;
4556
4557         if( data->type != DB_DATA_PTR ) // got no need for those!
4558                 return 0;
4559
4560         src = static_cast<script_reg_state *>(db_data2ptr(data));
4561
4562         if( src->type ) {
4563                 struct script_reg_str *p = (struct script_reg_str *)src;
4564
4565                 if( p->value )
4566                         aFree(p->value);
4567
4568                 ers_free(str_reg_ers,p);
4569         } else {
4570                 ers_free(num_reg_ers,(struct script_reg_num*)src);
4571         }
4572
4573         return 0;
4574 }
4575
4576 /**
4577  * Clears a single persistent variable
4578  **/
4579 void script_reg_destroy_single(struct map_session_data *sd, int64 reg, struct script_reg_state *data)
4580 {
4581         i64db_remove(sd->regs.vars, reg);
4582
4583         if( data->type ) {
4584                 struct script_reg_str *p = (struct script_reg_str*)data;
4585
4586                 if( p->value )
4587                         aFree(p->value);
4588
4589                 ers_free(str_reg_ers,p);
4590         } else {
4591                 ers_free(num_reg_ers,(struct script_reg_num*)data);
4592         }
4593 }
4594
4595 unsigned int *script_array_cpy_list(struct script_array *sa)
4596 {
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;
4601 }
4602
4603 void script_generic_ui_array_expand (unsigned int plus)
4604 {
4605         generic_ui_array_size += plus + 100;
4606         RECREATE(generic_ui_array, unsigned int, generic_ui_array_size);
4607 }
4608
4609 int buildin_query_sql_sub(struct script_state *st, Sql *handle);
4610
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) {
4614         int i, cursor = 0;
4615         bool allOk = true;
4616
4617         EnterSpinLock(&queryThreadLock);
4618
4619         for( i = 0; i < queryThreadData.count; i++ ) {
4620                 struct queryThreadEntry *entry = queryThreadData.entry[i];
4621
4622                 if( !entry->ok ) {
4623                         allOk = false;
4624                         continue;
4625                 }
4626
4627                 run_script_main(entry->st);
4628
4629                 entry->st = NULL;/* empty entries */
4630                 aFree(entry);
4631                 queryThreadData.entry[i] = NULL;
4632         }
4633
4634
4635         if( allOk ) {
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;
4639         }
4640
4641         /* now lets clear the mess. */
4642         for( i = 0; i < queryThreadData.count; i++ ) {
4643                 struct queryThreadEntry *entry = queryThreadData.entry[i];
4644                 if( entry == NULL )
4645                         continue;/* entry on hold */
4646
4647                 /* move */
4648                 memmove(&queryThreadData.entry[cursor], &queryThreadData.entry[i], sizeof(struct queryThreadEntry*));
4649
4650                 cursor++;
4651         }
4652
4653         queryThreadData.count = cursor;
4654
4655         LeaveSpinLock(&queryThreadLock);
4656
4657         return 0;
4658 }
4659
4660 void queryThread_add(struct script_state *st, bool type) {
4661         int idx = 0;
4662         struct queryThreadEntry* entry = NULL;
4663
4664         EnterSpinLock(&queryThreadLock);
4665
4666         if( queryThreadData.count++ != 0 )
4667                 RECREATE(queryThreadData.entry, struct queryThreadEntry* , queryThreadData.count);
4668
4669         idx = queryThreadData.count-1;
4670
4671         CREATE(queryThreadData.entry[idx],struct queryThreadEntry,1);
4672
4673         entry = queryThreadData.entry[idx];
4674
4675         entry->st = st;
4676         entry->ok = false;
4677         entry->type = type;
4678         if( queryThreadData.timer == INVALID_TIMER ) { /* start the receiver timer */
4679                 queryThreadData.timer = add_timer_interval(gettick() + 100, queryThread_timer, 0, 0, 100);
4680         }
4681
4682         LeaveSpinLock(&queryThreadLock);
4683
4684         /* unlock the queryThread */
4685         racond_signal(queryThreadCond);
4686 }
4687 /* adds a new log to the queue */
4688 void queryThread_log(char * entry, int length) {
4689         int idx = logThreadData.count;
4690
4691         EnterSpinLock(&queryThreadLock);
4692
4693         if( logThreadData.count++ != 0 )
4694                 RECREATE(logThreadData.entry, char* , logThreadData.count);
4695
4696         CREATE(logThreadData.entry[idx], char, length + 1 );
4697         safestrncpy(logThreadData.entry[idx], entry, length + 1 );
4698
4699         LeaveSpinLock(&queryThreadLock);
4700
4701         /* unlock the queryThread */
4702         racond_signal(queryThreadCond);
4703 }
4704
4705 /* queryThread_main */
4706 static void *queryThread_main(void *x) {
4707         Sql *queryThread_handle = Sql_Malloc();
4708         int i;
4709
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);
4715                 exit(EXIT_FAILURE);
4716         }
4717
4718         if( strlen(default_codepage) > 0 )
4719                 if ( SQL_ERROR == Sql_SetEncoding(queryThread_handle, default_codepage) )
4720                         Sql_ShowDebug(queryThread_handle);
4721
4722         if( log_config.sql_logs ) {
4723                 logmysql_handle = Sql_Malloc();
4724
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);
4730                         exit(EXIT_FAILURE);
4731                 }
4732
4733                 if( strlen(default_codepage) > 0 )
4734                         if ( SQL_ERROR == Sql_SetEncoding(logmysql_handle, default_codepage) )
4735                                 Sql_ShowDebug(logmysql_handle);
4736         }
4737
4738         while( 1 ) {
4739
4740                 if(queryThreadTerminate > 0)
4741                         break;
4742
4743                 EnterSpinLock(&queryThreadLock);
4744
4745                 /* mess with queryThreadData within the lock */
4746                 for( i = 0; i < queryThreadData.count; i++ ) {
4747                         struct queryThreadEntry *entry = queryThreadData.entry[i];
4748
4749                         if( entry->ok )
4750                                 continue;
4751                         else if ( !entry->st || !entry->st->stack ) {
4752                                 entry->ok = true;/* dispose */
4753                                 continue;
4754                         }
4755
4756                         buildin_query_sql_sub(entry->st, entry->type ? logmysql_handle : queryThread_handle);
4757
4758                         entry->ok = true;/* we're done with this */
4759                 }
4760
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]);
4767                         }
4768                         logThreadData.count = 0;
4769                 }
4770
4771                 LeaveSpinLock(&queryThreadLock);
4772
4773                 ramutex_lock( queryThreadMutex );
4774                 racond_wait( queryThreadCond,   queryThreadMutex,  -1 );
4775                 ramutex_unlock( queryThreadMutex );
4776
4777         }
4778
4779         Sql_Free(queryThread_handle);
4780
4781         if( log_config.sql_logs ) {
4782                 Sql_Free(logmysql_handle);
4783         }
4784
4785         return NULL;
4786 }
4787 #endif
4788 /*==========================================
4789  * Destructor
4790  *------------------------------------------*/
4791 void do_final_script() {
4792         int i;
4793         DBIterator *iter;
4794         struct script_state *st;
4795
4796 #ifdef DEBUG_HASH
4797         if (battle_config.etc_log)
4798         {
4799                 FILE *fp = fopen("hash_dump.txt","wt");
4800                 if(fp) {
4801                         int count[SCRIPT_HASH_SIZE];
4802                         int count2[SCRIPT_HASH_SIZE]; // number of buckets with a certain number of items
4803                         int n=0;
4804                         int min=INT_MAX,max=0,zero=0;
4805                         double mean=0.0f;
4806                         double median=0.0f;
4807
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));
4815                                 ++count[h];
4816                         }
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]);
4821                                 if(min > count[i])
4822                                         min = count[i];         // minimun count of collision
4823                                 if(max < count[i])
4824                                         max = count[i];         // maximun count of collision
4825                                 if(count[i] == 0)
4826                                         zero++;
4827                                 ++count2[count[i]];
4828                         }
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>
4833                         }
4834                         for( i=min; i <= max; ++i ){
4835                                 n += count2[i];
4836                                 if( n*2 >= SCRIPT_HASH_SIZE )
4837                                 {
4838                                         if( SCRIPT_HASH_SIZE%2 == 0 && SCRIPT_HASH_SIZE/2 == n )
4839                                                 median = (i+i+1)/2.0f;
4840                                         else
4841                                                 median = i;
4842                                         break;
4843                                 }
4844                         }
4845                         fprintf(fp,"--------------------\n    min = %d, max = %d, zero = %d\n    mean = %lf, median = %lf\n",min,max,zero,mean,median);
4846                         fclose(fp);
4847                 }
4848         }
4849 #endif
4850
4851         mapreg_final();
4852
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);
4856
4857         ers_destroy(array_ers);
4858         if (generic_ui_array)
4859                 aFree(generic_ui_array);
4860
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);
4864         dbi_destroy(iter);
4865
4866         if (str_data)
4867                 aFree(str_data);
4868         if (str_buf)
4869                 aFree(str_buf);
4870
4871         for( i = 0; i < atcmd_binding_count; i++ ) {
4872                 aFree(atcmd_binding[i]);
4873         }
4874
4875         if( atcmd_binding_count != 0 )
4876                 aFree(atcmd_binding);
4877
4878         ers_destroy(st_ers);
4879         ers_destroy(stack_ers);
4880         db_destroy(st_db);
4881
4882 #ifdef BETA_THREAD_TEST
4883         /* QueryThread */
4884         InterlockedIncrement(&queryThreadTerminate);
4885         racond_signal(queryThreadCond);
4886         rathread_wait(queryThread, NULL);
4887
4888         // Destroy cond var and mutex.
4889         racond_destroy( queryThreadCond );
4890         ramutex_destroy( queryThreadMutex );
4891
4892         /* Clear missing vars */
4893         for( i = 0; i < queryThreadData.count; i++ ) {
4894                 aFree(queryThreadData.entry[i]);
4895         }
4896
4897         aFree(queryThreadData.entry);
4898
4899         for( i = 0; i < logThreadData.count; i++ ) {
4900                 aFree(logThreadData.entry[i]);
4901         }
4902
4903         aFree(logThreadData.entry);
4904 #endif
4905 }
4906 /*==========================================
4907  * Initialization
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);
4914
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);
4918
4919         ers_chunk_size(st_ers, 10);
4920         ers_chunk_size(stack_ers, 10);
4921
4922         active_scripts = 0;
4923         next_id = 0;
4924
4925         mapreg_init();
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 */
4932
4933         InitializeSpinLock(&queryThreadLock);
4934
4935         queryThreadData.timer = INVALID_TIMER;
4936         queryThreadTerminate = 0;
4937         queryThreadMutex = ramutex_create();
4938         queryThreadCond = racond_create();
4939
4940         queryThread = rathread_create(queryThread_main, NULL);
4941
4942         if(queryThread == NULL){
4943                 ShowFatalError("do_init_script: cannot spawn Query Thread.\n");
4944                 exit(EXIT_FAILURE);
4945         }
4946
4947         add_timer_func_list(queryThread_timer, "queryThread_timer");
4948 #endif
4949 }
4950
4951 void script_reload(void) {
4952         int i;
4953         DBIterator *iter;
4954         struct script_state *st;
4955
4956 #ifdef BETA_THREAD_TEST
4957         /* we're reloading so any queries undergoing should be...exterminated. */
4958         EnterSpinLock(&queryThreadLock);
4959
4960         for( i = 0; i < queryThreadData.count; i++ ) {
4961                 aFree(queryThreadData.entry[i]);
4962         }
4963         queryThreadData.count = 0;
4964
4965         if( queryThreadData.timer != INVALID_TIMER ) {
4966                 delete_timer(queryThreadData.timer, queryThread_timer);
4967                 queryThreadData.timer = INVALID_TIMER;
4968         }
4969
4970         LeaveSpinLock(&queryThreadLock);
4971 #endif
4972
4973         userfunc_db->clear(userfunc_db, db_script_free_code_sub);
4974         db_clear(scriptlabel_db);
4975
4976         // @commands (script based)
4977         // Clear bindings
4978         for( i = 0; i < atcmd_binding_count; i++ ) {
4979                 aFree(atcmd_binding[i]);
4980         }
4981
4982         if( atcmd_binding_count != 0 )
4983                 aFree(atcmd_binding);
4984
4985         atcmd_binding_count = 0;
4986
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);
4990         dbi_destroy(iter);
4991         db_clear(st_db);
4992
4993         mapreg_reload();
4994 }
4995
4996 //-----------------------------------------------------------------------------
4997 // buildin functions
4998 //
4999
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)
5005
5006 /////////////////////////////////////////////////////////////////////
5007 // NPC interaction
5008 //
5009
5010 /// Appends a message to the npc dialog.
5011 /// If a dialog doesn't exist yet, one is created.
5012 ///
5013 /// mes "<message>";
5014 BUILDIN_FUNC(mes)
5015 {
5016         TBL_PC* sd;
5017         if( !script_rid2sd(sd) )
5018                 return SCRIPT_CMD_SUCCESS;
5019
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));
5023         }
5024         else
5025         {// parse multiple lines as they exist
5026                 int i;
5027
5028                 for( i = 2; script_hasdata(st, i); i++ )
5029                 {
5030                         // send the message to the client
5031                         clif_scriptmes(sd, st->oid, script_getstr(st, i));
5032                 }
5033         }
5034
5035         st->mes_active = 1; // Invoking character has a NPC dialog box open.
5036         return SCRIPT_CMD_SUCCESS;
5037 }
5038
5039 /// Displays the button 'next' in the npc dialog.
5040 /// The dialog text is cleared and the script continues when the button is pressed.
5041 ///
5042 /// next;
5043 BUILDIN_FUNC(next)
5044 {
5045         TBL_PC* sd;
5046
5047         if( !script_rid2sd(sd) )
5048                 return SCRIPT_CMD_SUCCESS;
5049 #ifdef SECURE_NPCTIMEOUT
5050         sd->npc_idle_type = NPCT_WAIT;
5051 #endif
5052         st->state = STOP;
5053         clif_scriptnext(sd, st->oid);
5054         return SCRIPT_CMD_SUCCESS;
5055 }
5056
5057 /// Ends the script and displays the button 'close' on the npc dialog.
5058 /// The dialog is closed when the button is pressed.
5059 ///
5060 /// close;
5061 BUILDIN_FUNC(close)
5062 {
5063         TBL_PC* sd;
5064
5065         if( !script_rid2sd(sd) )
5066                 return SCRIPT_CMD_SUCCESS;
5067
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");
5072         } else {
5073                 st->state = CLOSE;
5074                 st->mes_active = 0;
5075         }
5076
5077         clif_scriptclose(sd, st->oid);
5078         return SCRIPT_CMD_SUCCESS;
5079 }
5080
5081 /// Displays the button 'close' on the npc dialog.
5082 /// The dialog is closed and the script continues when the button is pressed.
5083 ///
5084 /// close2;
5085 BUILDIN_FUNC(close2)
5086 {
5087         TBL_PC* sd;
5088
5089         if( !script_rid2sd(sd) )
5090                 return SCRIPT_CMD_SUCCESS;
5091
5092         st->state = STOP;
5093
5094         if( st->mes_active )
5095                 st->mes_active = 0;
5096
5097         clif_scriptclose(sd, st->oid);
5098         return SCRIPT_CMD_SUCCESS;
5099 }
5100
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)
5105 {
5106         int count = 0;
5107         int bogus_total;
5108
5109         if( total == NULL )
5110                 total = &bogus_total;
5111         ++(*total);
5112
5113         // initial empty options
5114         while( *str == ':' )
5115         {
5116                 ++str;
5117                 ++(*total);
5118         }
5119         // count menu options
5120         while( *str != '\0' )
5121         {
5122                 ++count;
5123                 --max_count;
5124                 if( max_count == 0 )
5125                         break;
5126                 while( *str != ':' && *str != '\0' )
5127                         ++str;
5128                 while( *str == ':' )
5129                 {
5130                         ++str;
5131                         ++(*total);
5132                 }
5133         }
5134         return count;
5135 }
5136
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.
5140 ///
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.
5144 ///
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
5149 ///
5150 /// NOTE: the client closes the npc dialog when cancel is pressed
5151 ///
5152 /// menu "<option_text>",<target_label>{,"<option_text>",<target_label>,...};
5153 BUILDIN_FUNC(menu)
5154 {
5155         int i;
5156         const char* text;
5157         TBL_PC* sd;
5158
5159         if( !script_rid2sd(sd) )
5160                 return SCRIPT_CMD_SUCCESS;
5161
5162 #ifdef SECURE_NPCTIMEOUT
5163         sd->npc_idle_type = NPCT_MENU;
5164 #endif
5165
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 )
5168         {
5169                 struct StringBuf buf;
5170
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));
5174                         st->state = END;
5175                         return SCRIPT_CMD_FAILURE;
5176                 }
5177
5178                 StringBuf_Init(&buf);
5179                 sd->npc_menu = 0;
5180                 for( i = 2; i < script_lastdata(st); i += 2 )
5181                 {
5182                         struct script_data* data;
5183                         // menu options
5184                         text = script_getstr(st, i);
5185
5186                         // target label
5187                         data = script_getdata(st, i+1);
5188                         if( !data_islabel(data) )
5189                         {// not a label
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);
5193                                 st->state = END;
5194                                 return SCRIPT_CMD_FAILURE;
5195                         }
5196
5197                         // append option(s)
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);
5204                 }
5205                 st->state = RERUNLINE;
5206                 sd->state.menu_or_input = 1;
5207
5208                 /**
5209                  * menus beyond this length crash the client (see bugreport:6402)
5210                  **/
5211                 if( StringBuf_Length(&buf) >= 2047 ) {
5212                         struct npc_data * nd = map_id2nd(st->oid);
5213                         char* menu;
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);
5218                         aFree(menu);
5219                 } else
5220                         clif_scriptmenu(sd, st->oid, StringBuf_Value(&buf));
5221
5222                 StringBuf_Destroy(&buf);
5223
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);
5228                 }
5229         }
5230         else if( sd->npc_menu == 0xff )
5231         {// Cancel was pressed
5232                 sd->state.menu_or_input = 0;
5233                 st->state = END;
5234         }
5235         else
5236         {// goto target label
5237                 int menu = 0;
5238
5239                 sd->state.menu_or_input = 0;
5240                 if( sd->npc_menu <= 0 )
5241                 {
5242                         ShowDebug("buildin_menu: Unexpected selection (%d)\n", sd->npc_menu);
5243                         st->state = END;
5244                         return SCRIPT_CMD_FAILURE;
5245                 }
5246
5247                 // get target label
5248                 for( i = 2; i < script_lastdata(st); i += 2 )
5249                 {
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
5254                 }
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);
5258                         st->state = END;
5259                         return SCRIPT_CMD_FAILURE;
5260                 }
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));
5265                         st->state = END;
5266                         return SCRIPT_CMD_FAILURE;
5267                 }
5268                 pc_setreg(sd, add_str("@menu"), menu);
5269                 st->pos = script_getnum(st, i + 1);
5270                 st->state = GOTO;
5271         }
5272         return SCRIPT_CMD_SUCCESS;
5273 }
5274
5275 /// Displays a menu with options and returns the selected option.
5276 /// Behaves like 'menu' without the target labels.
5277 ///
5278 /// select(<option_text>{,<option_text>,...}) -> <selected_option>
5279 ///
5280 /// @see menu
5281 BUILDIN_FUNC(select)
5282 {
5283         int i;
5284         const char* text;
5285         TBL_PC* sd;
5286
5287         if( !script_rid2sd(sd) )
5288                 return SCRIPT_CMD_SUCCESS;
5289
5290 #ifdef SECURE_NPCTIMEOUT
5291         sd->npc_idle_type = NPCT_MENU;
5292 #endif
5293
5294         if( sd->state.menu_or_input == 0 ) {
5295                 struct StringBuf buf;
5296
5297                 StringBuf_Init(&buf);
5298                 sd->npc_menu = 0;
5299                 for( i = 2; i <= script_lastdata(st); ++i ) {
5300                         text = script_getstr(st, i);
5301
5302                         if( sd->npc_menu > 0 )
5303                                 StringBuf_AppendStr(&buf, ":");
5304
5305                         StringBuf_AppendStr(&buf, text);
5306                         sd->npc_menu += menu_countoptions(text, 0, NULL);
5307                 }
5308
5309                 st->state = RERUNLINE;
5310                 sd->state.menu_or_input = 1;
5311
5312                 /**
5313                  * menus beyond this length crash the client (see bugreport:6402)
5314                  **/
5315                 if( StringBuf_Length(&buf) >= 2047 ) {
5316                         struct npc_data * nd = map_id2nd(st->oid);
5317                         char* menu;
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);
5322                         aFree(menu);
5323                 } else
5324                         clif_scriptmenu(sd, st->oid, StringBuf_Value(&buf));
5325                 StringBuf_Destroy(&buf);
5326
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);
5330                 }
5331         } else if( sd->npc_menu == 0xff ) {// Cancel was pressed
5332                 sd->state.menu_or_input = 0;
5333                 st->state = END;
5334         } else {// return selected option
5335                 int menu = 0;
5336
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
5343                 }
5344                 pc_setreg(sd, add_str("@menu"), menu);
5345                 script_pushint(st, menu);
5346                 st->state = RUN;
5347         }
5348         return SCRIPT_CMD_SUCCESS;
5349 }
5350
5351 /// Displays a menu with options and returns the selected option.
5352 /// Behaves like 'menu' without the target labels, except when cancel is
5353 /// pressed.
5354 /// When cancel is pressed, the script continues and 255 is returned.
5355 ///
5356 /// prompt(<option_text>{,<option_text>,...}) -> <selected_option>
5357 ///
5358 /// @see menu
5359 BUILDIN_FUNC(prompt)
5360 {
5361         int i;
5362         const char *text;
5363         TBL_PC* sd;
5364
5365         if( !script_rid2sd(sd) )
5366                 return SCRIPT_CMD_SUCCESS;
5367
5368 #ifdef SECURE_NPCTIMEOUT
5369         sd->npc_idle_type = NPCT_MENU;
5370 #endif
5371
5372         if( sd->state.menu_or_input == 0 )
5373         {
5374                 struct StringBuf buf;
5375
5376                 StringBuf_Init(&buf);
5377                 sd->npc_menu = 0;
5378                 for( i = 2; i <= script_lastdata(st); ++i )
5379                 {
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);
5385                 }
5386
5387                 st->state = RERUNLINE;
5388                 sd->state.menu_or_input = 1;
5389
5390                 /**
5391                  * menus beyond this length crash the client (see bugreport:6402)
5392                  **/
5393                 if( StringBuf_Length(&buf) >= 2047 ) {
5394                         struct npc_data * nd = map_id2nd(st->oid);
5395                         char* menu;
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);
5400                         aFree(menu);
5401                 } else
5402                         clif_scriptmenu(sd, st->oid, StringBuf_Value(&buf));
5403                 StringBuf_Destroy(&buf);
5404
5405                 if( sd->npc_menu >= 0xff )
5406                 {
5407                         ShowWarning("buildin_prompt: Too many options specified (current=%d, max=254).\n", sd->npc_menu);
5408                         script_reportsrc(st);
5409                 }
5410         }
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);
5416                 st->state = RUN;
5417         }
5418         else
5419         {// return selected option
5420                 int menu = 0;
5421
5422                 sd->state.menu_or_input = 0;
5423                 for( i = 2; i <= script_lastdata(st); ++i )
5424                 {
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
5429                 }
5430                 pc_setreg(sd, add_str("@menu"), menu);
5431                 script_pushint(st, menu);
5432                 st->state = RUN;
5433         }
5434         return SCRIPT_CMD_SUCCESS;
5435 }
5436
5437 /////////////////////////////////////////////////////////////////////
5438 // ...
5439 //
5440
5441 /// Jumps to the target script label.
5442 ///
5443 /// goto <label>;
5444 BUILDIN_FUNC(goto)
5445 {
5446         if( !data_islabel(script_getdata(st,2)) )
5447         {
5448                 ShowError("buildin_goto: Not a label\n");
5449                 script_reportdata(script_getdata(st,2));
5450                 st->state = END;
5451                 return SCRIPT_CMD_FAILURE;
5452         }
5453
5454         st->pos = script_getnum(st,2);
5455         st->state = GOTO;
5456         return SCRIPT_CMD_SUCCESS;
5457 }
5458
5459 /*==========================================
5460  * user-defined function call
5461  *------------------------------------------*/
5462 BUILDIN_FUNC(callfunc)
5463 {
5464         int i, j;
5465         struct script_retinfo* ri;
5466         struct script_code* scr;
5467         const char* str = script_getstr(st,2);
5468         struct reg_db *ref = NULL;
5469
5470         scr = (struct script_code*)strdb_get(userfunc_db, str);
5471         if(!scr) {
5472                 ShowError("buildin_callfunc: Function not found! [%s]\n", str);
5473                 st->state = END;
5474                 return SCRIPT_CMD_FAILURE;
5475         }
5476
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;
5486
5487         for(i = st->start+3, j = 0; i < st->end; i++, j++) {
5488                 struct script_data* data = push_copy(st->stack,i);
5489
5490                 if (data_isreference(data) && !data->ref) {
5491                         const char* name = reference_getname(data);
5492
5493                         if (name[0] == '.')
5494                                 data->ref = (name[1] == '@' ? &ref[0] : &ref[1]);
5495                 }
5496         }
5497
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);
5506
5507         st->pos = 0;
5508         st->script = scr;
5509         st->stack->defsp = st->stack->sp;
5510         st->state = GOTO;
5511         st->stack->scope.vars = i64db_alloc(DB_OPT_RELEASE_DATA);
5512         st->stack->scope.arrays = idb_alloc(DB_OPT_BASE);
5513
5514         if (!st->script->local.vars)
5515                 st->script->local.vars = i64db_alloc(DB_OPT_RELEASE_DATA);
5516
5517         return SCRIPT_CMD_SUCCESS;
5518 }
5519
5520 /*==========================================
5521  * subroutine call
5522  *------------------------------------------*/
5523 BUILDIN_FUNC(callsub)
5524 {
5525         int i,j;
5526         struct script_retinfo* ri;
5527         int pos = script_getnum(st,2);
5528         struct reg_db *ref = NULL;
5529
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));
5533                 st->state = END;
5534                 return SCRIPT_CMD_FAILURE;
5535         }
5536
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;
5542
5543         for(i = st->start+3, j = 0; i < st->end; i++, j++) {
5544                 struct script_data* data = push_copy(st->stack,i);
5545
5546                 if (data_isreference(data) && !data->ref) {
5547                         const char* name = reference_getname(data);
5548
5549                         if (name[0] == '.' && name[1] == '@')
5550                                 data->ref = &ref[0];
5551                 }
5552         }
5553
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);
5562
5563         st->pos = pos;
5564         st->stack->defsp = st->stack->sp;
5565         st->state = GOTO;
5566         st->stack->scope.vars = i64db_alloc(DB_OPT_RELEASE_DATA);
5567         st->stack->scope.arrays = idb_alloc(DB_OPT_BASE);
5568
5569         return SCRIPT_CMD_SUCCESS;
5570 }
5571
5572 /// Retrieves an argument provided to callfunc/callsub.
5573 /// If the argument doesn't exist
5574 ///
5575 /// getarg(<index>{,<default_value>}) -> <value>
5576 BUILDIN_FUNC(getarg)
5577 {
5578         struct script_retinfo* ri;
5579         int idx;
5580
5581         if( st->stack->defsp < 1 || st->stack->stack_data[st->stack->defsp - 1].type != C_RETINFO )
5582         {
5583                 ShowError("buildin_getarg: No callfunc or callsub!\n");
5584                 st->state = END;
5585                 return SCRIPT_CMD_FAILURE;
5586         }
5587         ri = st->stack->stack_data[st->stack->defsp - 1].u.ri;
5588
5589         idx = script_getnum(st,2);
5590
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);
5595         else
5596         {
5597                 ShowError("buildin_getarg: Index (idx=%d) out of range (nargs=%d) and no default value found\n", idx, ri->nargs);
5598                 st->state = END;
5599                 return SCRIPT_CMD_FAILURE;
5600         }
5601         return SCRIPT_CMD_SUCCESS;
5602 }
5603
5604 /// Returns from the current function, optionaly returning a value from the functions.
5605 /// Don't use outside script functions.
5606 ///
5607 /// return;
5608 /// return <value>;
5609 BUILDIN_FUNC(return)
5610 {
5611         if( script_hasdata(st,2) )
5612         {// return value
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
5623                         }
5624                 }
5625         }
5626         else
5627         {// no return value
5628                 script_pushnil(st);
5629         }
5630         st->state = RETFUNC;
5631         return SCRIPT_CMD_SUCCESS;
5632 }
5633
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>
5639 BUILDIN_FUNC(rand)
5640 {
5641         int range;
5642         int min;
5643
5644         if( script_hasdata(st,3) )
5645         {// min,max
5646                 int max = script_getnum(st,3);
5647                 min = script_getnum(st,2);
5648                 if( max < min )
5649                         SWAP(min, max);
5650                 range = max - min + 1;
5651         }
5652         else
5653         {// range
5654                 min = 0;
5655                 range = script_getnum(st,2);
5656         }
5657         if( range <= 1 )
5658                 script_pushint(st, min);
5659         else
5660                 script_pushint(st, rnd()%range + min);
5661
5662         return SCRIPT_CMD_SUCCESS;
5663 }
5664
5665 /*==========================================
5666  * Warp sd to str,x,y or Random or SavePoint/Save
5667  *------------------------------------------*/
5668 BUILDIN_FUNC(warp)
5669 {
5670         int ret;
5671         int x,y;
5672         const char* str;
5673         struct map_session_data* sd;
5674
5675         if(!script_charid2sd(5, sd))
5676                 return SCRIPT_CMD_SUCCESS;
5677
5678         str = script_getstr(st,2);
5679         x = script_getnum(st,3);
5680         y = script_getnum(st,4);
5681
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);
5686         else
5687                 ret = pc_setpos(sd,mapindex_name2id(str),x,y,CLR_OUTSIGHT);
5688
5689         if( ret ) {
5690                 ShowError("buildin_warp: moving player '%s' to \"%s\",%d,%d failed.\n", sd->status.name, str, x, y);
5691                 return SCRIPT_CMD_FAILURE;
5692         }
5693
5694         return SCRIPT_CMD_SUCCESS;
5695 }
5696 /*==========================================
5697  * Warp a specified area
5698  *------------------------------------------*/
5699 static int buildin_areawarp_sub(struct block_list *bl,va_list ap)
5700 {
5701         int x2,y2,x3,y3;
5702         unsigned int index;
5703
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);
5709
5710         if(index == 0)
5711                 pc_randomwarp((TBL_PC *)bl,CLR_TELEPORT);
5712         else if(x3 && y3) {
5713                 int max, tx, ty, j = 0;
5714                 int16 m;
5715
5716                 m = map_mapindex2mapid(index);
5717
5718                 // choose a suitable max number of attempts
5719                 if( (max = (y3-y2+1)*(x3-x2+1)*3) > 1000 )
5720                         max = 1000;
5721
5722                 // find a suitable map cell
5723                 do {
5724                         tx = rnd()%(x3-x2+1)+x2;
5725                         ty = rnd()%(y3-y2+1)+y2;
5726                         j++;
5727                 } while( map_getcell(m,tx,ty,CELL_CHKNOPASS) && j < max );
5728
5729                 pc_setpos((TBL_PC *)bl,index,tx,ty,CLR_OUTSIGHT);
5730         }
5731         else
5732                 pc_setpos((TBL_PC *)bl,index,x2,y2,CLR_OUTSIGHT);
5733         return 0;
5734 }
5735
5736 BUILDIN_FUNC(areawarp)
5737 {
5738         int16 m, x0,y0,x1,y1, x2,y2,x3=0,y3=0;
5739         unsigned int index;
5740         const char *str;
5741         const char *mapname;
5742
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);
5751
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 ){
5754                         x3 = 0;
5755                         y3 = 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);
5760                 }
5761         }
5762
5763         if( (m = map_mapname2mapid(mapname)) < 0 )
5764                 return SCRIPT_CMD_FAILURE;
5765
5766         if( strcmp(str,"Random") == 0 )
5767                 index = 0;
5768         else if( !(index=mapindex_name2id(str)) )
5769                 return SCRIPT_CMD_FAILURE;
5770
5771         map_foreachinallarea(buildin_areawarp_sub, m,x0,y0,x1,y1, BL_PC, index,x2,y2,x3,y3);
5772         return SCRIPT_CMD_SUCCESS;
5773 }
5774
5775 /*==========================================
5776  * areapercentheal <map>,<x1>,<y1>,<x2>,<y2>,<hp>,<sp>
5777  *------------------------------------------*/
5778 static int buildin_areapercentheal_sub(struct block_list *bl,va_list ap)
5779 {
5780         int hp, sp;
5781         hp = va_arg(ap, int);
5782         sp = va_arg(ap, int);
5783         pc_percentheal((TBL_PC *)bl,hp,sp);
5784         return 0;
5785 }
5786
5787 BUILDIN_FUNC(areapercentheal)
5788 {
5789         int hp,sp,m;
5790         const char *mapname;
5791         int x0,y0,x1,y1;
5792
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);
5800
5801         if( (m=map_mapname2mapid(mapname))< 0)
5802                 return SCRIPT_CMD_FAILURE;
5803
5804         map_foreachinallarea(buildin_areapercentheal_sub,m,x0,y0,x1,y1,BL_PC,hp,sp);
5805         return SCRIPT_CMD_SUCCESS;
5806 }
5807
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)
5814 {
5815         TBL_PC *sd = NULL;
5816         TBL_PC *pl_sd;
5817         struct party_data* p;
5818         int type, mapindex = 0, m = -1, i, rx = 0, ry = 0;
5819
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);
5831
5832         p = party_search(p_id);
5833         if(!p)
5834                 return SCRIPT_CMD_SUCCESS;
5835
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
5840                  : 4;
5841
5842         switch (type)
5843         {
5844                 case 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);
5851                         x = pl_sd->bl.x;
5852                         y = pl_sd->bl.y;
5853                         break;
5854                 case 4:
5855                         mapindex = mapindex_name2id(str);
5856                         if (!mapindex) {// Invalid map
5857                                 return SCRIPT_CMD_FAILURE;
5858                         }
5859                         m = map_mapindex2mapid(mapindex);
5860                         break;
5861                 case 2:
5862                         //"SavePoint" uses save point of the currently attached player
5863                         if ( !script_rid2sd(sd) )
5864                                 return SCRIPT_CMD_SUCCESS;
5865                         break;
5866         }
5867
5868         for (i = 0; i < MAX_PARTY; i++)
5869         {
5870                 if( !(pl_sd = p->data[i].sd) || pl_sd->status.party_id != p_id )
5871                         continue;
5872
5873                 if( str2 && strcmp(str2, map[pl_sd->bl.m].name) != 0 )
5874                         continue;
5875
5876                 if( pc_isdead(pl_sd) )
5877                         continue;
5878
5879                 switch( type )
5880                 {
5881                 case 0: // Random
5882                         if(!map[pl_sd->bl.m].flag.nowarp)
5883                                 pc_randomwarp(pl_sd,CLR_TELEPORT);
5884                 break;
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);
5888                 break;
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);
5892                 break;
5893                 case 3: // Leader
5894                         if (p->party.member[i].leader)
5895                                 continue;
5896                 case 4: // m,x,y
5897                         if (rx || ry) {
5898                                 int x1 = x + rx, y1 = y + ry,
5899                                         x0 = x - rx, y0 = y - ry;
5900                                 uint8 attempts = 10;
5901
5902                                 do {
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));
5906                         }
5907
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);
5910                 break;
5911                 }
5912         }
5913
5914         return SCRIPT_CMD_SUCCESS;
5915 }
5916
5917 /*==========================================
5918  * Warpguild - [Fredzilla]
5919  * Syntax: warpguild "mapname",x,y,Guild_ID;
5920  *------------------------------------------*/
5921 BUILDIN_FUNC(warpguild)
5922 {
5923         TBL_PC *sd = NULL;
5924         TBL_PC *pl_sd;
5925         struct guild* g;
5926         struct s_mapiterator* iter;
5927         int type, mapindex = 0, m = -1;
5928
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);
5933
5934         g = guild_search(gid);
5935         if( g == NULL )
5936                 return SCRIPT_CMD_SUCCESS;
5937
5938         type = ( strcmp(str,"Random")==0 ) ? 0
5939              : ( strcmp(str,"SavePointAll")==0 ) ? 1
5940                  : ( strcmp(str,"SavePoint")==0 ) ? 2
5941                  : 3;
5942
5943         if( type == 2 && !script_rid2sd(sd) )
5944         {// "SavePoint" uses save point of the currently attached player
5945                 return SCRIPT_CMD_SUCCESS;
5946         }
5947
5948         switch (type) {
5949                 case 3:
5950                         mapindex = mapindex_name2id(str);
5951                         if (!mapindex)
5952                                 return SCRIPT_CMD_FAILURE;
5953                         m = map_mapindex2mapid(mapindex);
5954                         break;
5955         }
5956
5957         iter = mapit_getallusers();
5958         for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
5959         {
5960                 if( pl_sd->status.guild_id != gid )
5961                         continue;
5962
5963                 switch( type )
5964                 {
5965                 case 0: // Random
5966                         if(!map[pl_sd->bl.m].flag.nowarp)
5967                                 pc_randomwarp(pl_sd,CLR_TELEPORT);
5968                 break;
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);
5972                 break;
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);
5976                 break;
5977                 case 3: // m,x,y
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);
5980                 break;
5981                 }
5982         }
5983         mapit_free(iter);
5984
5985         return SCRIPT_CMD_SUCCESS;
5986 }
5987
5988 /*==========================================
5989  * Force Heal a player (hp and sp)
5990  *------------------------------------------*/
5991 BUILDIN_FUNC(heal)
5992 {
5993         TBL_PC *sd;
5994         int hp,sp;
5995
5996         if (!script_charid2sd(4,sd))
5997                 return SCRIPT_CMD_SUCCESS;
5998
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;
6003 }
6004
6005 /*==========================================
6006  * Heal a player by item (get vit bonus etc)
6007  *------------------------------------------*/
6008 BUILDIN_FUNC(itemheal)
6009 {
6010         TBL_PC *sd;
6011         int hp,sp;
6012
6013         hp=script_getnum(st,2);
6014         sp=script_getnum(st,3);
6015
6016         if(potion_flag==1) {
6017                 potion_hp = hp;
6018                 potion_sp = sp;
6019                 return SCRIPT_CMD_SUCCESS;
6020         }
6021
6022         if (!script_charid2sd(4,sd))
6023                 return SCRIPT_CMD_SUCCESS;
6024
6025         pc_itemheal(sd,sd->itemid,hp,sp);
6026         return SCRIPT_CMD_SUCCESS;
6027 }
6028
6029 /*==========================================
6030  *
6031  *------------------------------------------*/
6032 BUILDIN_FUNC(percentheal)
6033 {
6034         int hp,sp;
6035         TBL_PC* sd;
6036
6037         hp=script_getnum(st,2);
6038         sp=script_getnum(st,3);
6039
6040         if(potion_flag==1) {
6041                 potion_per_hp = hp;
6042                 potion_per_sp = sp;
6043                 return SCRIPT_CMD_SUCCESS;
6044         }
6045
6046         if (!script_charid2sd(4,sd))
6047                 return SCRIPT_CMD_SUCCESS;
6048
6049 #ifdef RENEWAL
6050         if( sd->sc.data[SC_EXTREMITYFIST2] )
6051                 sp = 0;
6052 #endif
6053
6054         if (sd->sc.data[SC_NORECOVER_STATE]) {
6055                 hp = 0;
6056                 sp = 0;
6057         }
6058
6059         if (sd->sc.data[SC_BITESCAR])
6060                 hp = 0;
6061
6062         pc_percentheal(sd,hp,sp);
6063         return SCRIPT_CMD_SUCCESS;
6064 }
6065
6066 /*==========================================
6067  *
6068  *------------------------------------------*/
6069 BUILDIN_FUNC(jobchange)
6070 {
6071         int job, upper=-1;
6072
6073         job=script_getnum(st,2);
6074         if( script_hasdata(st,3) )
6075                 upper=script_getnum(st,3);
6076
6077         if (pcdb_checkid(job))
6078         {
6079                 TBL_PC* sd;
6080
6081                 if (!script_charid2sd(4,sd))
6082                         return SCRIPT_CMD_SUCCESS;
6083
6084                 pc_jobchange(sd, job, upper);
6085         }
6086
6087         return SCRIPT_CMD_SUCCESS;
6088 }
6089
6090 /*==========================================
6091  *
6092  *------------------------------------------*/
6093 BUILDIN_FUNC(jobname)
6094 {
6095         int class_=script_getnum(st,2);
6096         script_pushconststr(st, (char*)job_name(class_));
6097         return SCRIPT_CMD_SUCCESS;
6098 }
6099
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.
6105 ///
6106 /// input(<var>{,<min>{,<max>}}) -> <int>
6107 BUILDIN_FUNC(input)
6108 {
6109         TBL_PC* sd;
6110         struct script_data* data;
6111         int64 uid;
6112         const char* name;
6113         int min;
6114         int max;
6115
6116         if( !script_rid2sd(sd) )
6117                 return SCRIPT_CMD_SUCCESS;
6118
6119         data = script_getdata(st,2);
6120         if( !data_isreference(data) ){
6121                 ShowError("script:input: not a variable\n");
6122                 script_reportdata(data);
6123                 st->state = END;
6124                 return SCRIPT_CMD_FAILURE;
6125         }
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);
6130
6131 #ifdef SECURE_NPCTIMEOUT
6132         sd->npc_idle_type = NPCT_WAIT;
6133 #endif
6134
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);
6141                 else
6142                         clif_scriptinput(sd,st->oid);
6143         }
6144         else
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) )
6148                 {
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));
6152                 }
6153                 else
6154                 {
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));
6158                 }
6159                 st->state = RUN;
6160         }
6161         return SCRIPT_CMD_SUCCESS;
6162 }
6163
6164 // declare the copyarray method here for future reference
6165 BUILDIN_FUNC(copyarray);
6166
6167 /// Sets the value of a variable.
6168 /// The value is converted to the type of the variable.
6169 ///
6170 /// set(<variable>,<value>{,<charid>})
6171 BUILDIN_FUNC(setr)
6172 {
6173         TBL_PC* sd = NULL;
6174         struct script_data* data;
6175         //struct script_data* datavalue;
6176         int64 num;
6177         uint8 pos = 4;
6178         const char* name, *command = script_getfuncname(st);
6179         char prefix;
6180
6181         data = script_getdata(st,2);
6182         //datavalue = script_getdata(st,3);
6183         if( !data_isreference(data) )
6184         {
6185                 ShowError("script:set: not a variable\n");
6186                 script_reportdata(script_getdata(st,2));
6187                 st->state = END;
6188                 return SCRIPT_CMD_FAILURE;
6189         }
6190
6191         num = reference_getuid(data);
6192         name = reference_getname(data);
6193         prefix = *name;
6194
6195         if (!strcmp(command, "setr"))
6196                 pos = 5;
6197
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;
6201         }
6202
6203 #if 0
6204         if( data_isreference(datavalue) )
6205         {// the value being referenced is a variable
6206                 const char* namevalue = reference_getname(datavalue);
6207
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;
6214                         }
6215
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;
6220                         }
6221
6222                         // push the maximum number of array values to the stack
6223                         push_val(st->stack, C_INT, SCRIPT_MAX_ARRAYSIZE);
6224
6225                         // call the copy array method directly
6226                         return buildin_copyarray(st);
6227                 }
6228         }
6229 #endif
6230
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));
6234                 else
6235                         script_pushint(st,script_getnum(st, 4));
6236         } else // Return a copy of the variable reference
6237                 script_pushcopy(st, 2);
6238
6239         if( is_string_variable(name) )
6240                 set_reg(st,sd,num,name,(void*)script_getstr(st,3),script_getref(st,2));
6241         else
6242                 set_reg(st,sd,num,name,(void*)__64BPRTSIZE(script_getnum(st,3)),script_getref(st,2));
6243
6244         return SCRIPT_CMD_SUCCESS;
6245 }
6246
6247 /////////////////////////////////////////////////////////////////////
6248 /// Array variables
6249 ///
6250
6251 /// Sets values of an array, from the starting index.
6252 /// ex: setarray arr[1],1,2,3;
6253 ///
6254 /// setarray <array variable>,<value1>{,<value2>...};
6255 BUILDIN_FUNC(setarray)
6256 {
6257         struct script_data* data;
6258         const char* name;
6259         uint32 start;
6260         uint32 end;
6261         int32 id;
6262         int32 i;
6263         TBL_PC* sd = NULL;
6264
6265         data = script_getdata(st, 2);
6266         if( !data_isreference(data) )
6267         {
6268                 ShowError("script:setarray: not a variable\n");
6269                 script_reportdata(data);
6270                 st->state = END;
6271                 return SCRIPT_CMD_FAILURE;// not a variable
6272         }
6273
6274         id = reference_getid(data);
6275         start = reference_getindex(data);
6276         name = reference_getname(data);
6277
6278         if( not_server_variable(*name) )
6279         {
6280                 if( !script_rid2sd(sd) )
6281                         return SCRIPT_CMD_SUCCESS;// no player attached
6282         }
6283
6284         end = start + script_lastdata(st) - 2;
6285         if( end > SCRIPT_MAX_ARRAYSIZE )
6286                 end = SCRIPT_MAX_ARRAYSIZE;
6287
6288         if( is_string_variable(name) )
6289         {// string array
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));
6292         }
6293         else
6294         {// int array
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));
6297         }
6298         return SCRIPT_CMD_SUCCESS;
6299 }
6300
6301 /// Sets count values of an array, from the starting index.
6302 /// ex: cleararray arr[0],0,1;
6303 ///
6304 /// cleararray <array variable>,<value>,<count>;
6305 BUILDIN_FUNC(cleararray)
6306 {
6307         struct script_data* data;
6308         const char* name;
6309         uint32 start;
6310         uint32 end;
6311         int32 id;
6312         void* v;
6313         TBL_PC* sd = NULL;
6314
6315         data = script_getdata(st, 2);
6316         if( !data_isreference(data) )
6317         {
6318                 ShowError("script:cleararray: not a variable\n");
6319                 script_reportdata(data);
6320                 st->state = END;
6321                 return SCRIPT_CMD_FAILURE;// not a variable
6322         }
6323
6324         id = reference_getid(data);
6325         start = reference_getindex(data);
6326         name = reference_getname(data);
6327
6328         if( not_server_variable(*name) )
6329         {
6330                 if( !script_rid2sd(sd) )
6331                         return SCRIPT_CMD_SUCCESS;// no player attached
6332         }
6333
6334         if( is_string_variable(name) )
6335                 v = (void*)script_getstr(st, 3);
6336         else
6337                 v = (void*)__64BPRTSIZE(script_getnum(st, 3));
6338
6339         end = start + script_getnum(st, 4);
6340         if( end > SCRIPT_MAX_ARRAYSIZE )
6341                 end = SCRIPT_MAX_ARRAYSIZE;
6342
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;
6346 }
6347
6348 /// Copies data from one array to another.
6349 /// ex: copyarray arr[0],arr[2],2;
6350 ///
6351 /// copyarray <destination array variable>,<source array variable>,<count>;
6352 BUILDIN_FUNC(copyarray)
6353 {
6354         struct script_data* data1;
6355         struct script_data* data2;
6356         const char* name1;
6357         const char* name2;
6358         int32 idx1;
6359         int32 idx2;
6360         int32 id1;
6361         int32 id2;
6362         void* v;
6363         int32 i;
6364         uint32 count;
6365         TBL_PC* sd = NULL;
6366
6367         data1 = script_getdata(st, 2);
6368         data2 = script_getdata(st, 3);
6369         if( !data_isreference(data1) || !data_isreference(data2) )
6370         {
6371                 ShowError("script:copyarray: not a variable\n");
6372                 script_reportdata(data1);
6373                 script_reportdata(data2);
6374                 st->state = END;
6375                 return SCRIPT_CMD_FAILURE;// not a variable
6376         }
6377
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);
6384
6385         if( is_string_variable(name1) != is_string_variable(name2) )
6386         {
6387                 ShowError("script:copyarray: type mismatch\n");
6388                 script_reportdata(data1);
6389                 script_reportdata(data2);
6390                 st->state = END;
6391                 return SCRIPT_CMD_FAILURE;// data type mismatch
6392         }
6393
6394         if( not_server_variable(*name1) || not_server_variable(*name2) )
6395         {
6396                 if( !script_rid2sd(sd) )
6397                         return SCRIPT_CMD_SUCCESS;// no player attached
6398         }
6399
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
6405
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 )
6409                 {
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);
6413                 }
6414         }
6415         else
6416         {// normal copy
6417                 for( i = 0; i < count; ++i )
6418                 {
6419                         if( idx2 + i < SCRIPT_MAX_ARRAYSIZE )
6420                         {
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);
6424                         }
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));
6427                 }
6428         }
6429         return SCRIPT_CMD_SUCCESS;
6430 }
6431
6432 /// Returns the size of the array.
6433 /// Assumes that everything before the starting index exists.
6434 /// ex: getarraysize(arr[3])
6435 ///
6436 /// getarraysize(<array variable>) -> <int>
6437 BUILDIN_FUNC(getarraysize)
6438 {
6439         struct script_data* data;
6440         const char* name;
6441         struct map_session_data* sd = NULL;
6442
6443         data = script_getdata(st, 2);
6444         if( !data_isreference(data) )
6445         {
6446                 ShowError("script:getarraysize: not a variable\n");
6447                 script_reportdata(data);
6448                 script_pushnil(st);
6449                 st->state = END;
6450                 return SCRIPT_CMD_FAILURE;// not a variable
6451         }
6452
6453         name = reference_getname(data);
6454
6455         if( not_server_variable(*name) ){
6456                 if (!script_rid2sd(sd))
6457                         return SCRIPT_CMD_SUCCESS;// no player attached
6458         }
6459
6460         script_pushint(st, script_array_highest_key(st, sd, reference_getname(data), reference_getref(data)));
6461         return SCRIPT_CMD_SUCCESS;
6462 }
6463
6464 int script_array_index_cmp(const void *a, const void *b) {
6465         return ( *(unsigned int*)a - *(unsigned int*)b );
6466 }
6467
6468 /// Deletes count or all the elements in an array, from the starting index.
6469 /// ex: deletearray arr[4],2;
6470 ///
6471 /// deletearray <array variable>;
6472 /// deletearray <array variable>,<count>;
6473 BUILDIN_FUNC(deletearray)
6474 {
6475         struct script_data* data;
6476         const char* name;
6477         unsigned int start, end, i;
6478         int id;
6479         TBL_PC *sd = NULL;
6480         struct script_array *sa = NULL;
6481         struct reg_db *src = NULL;
6482         void *value;
6483
6484         data = script_getdata(st, 2);
6485         if( !data_isreference(data) ) {
6486                 ShowError("script:deletearray: not a variable\n");
6487                 script_reportdata(data);
6488                 st->state = END;
6489                 return SCRIPT_CMD_FAILURE;// not a variable
6490         }
6491
6492         id = reference_getid(data);
6493         start = reference_getindex(data);
6494         name = reference_getname(data);
6495
6496         if( not_server_variable(*name) ) {
6497                 if( !script_rid2sd(sd) )
6498                         return SCRIPT_CMD_SUCCESS;// no player attached
6499         }
6500
6501         if (!(src = script_array_src(st, sd, name, reference_getref(data)))) {
6502                 ShowError("script:deletearray: not a array\n");
6503                 script_reportdata(data);
6504                 st->state = END;
6505                 return SCRIPT_CMD_FAILURE;// not a variable
6506         }
6507
6508         script_array_ensure_zero(st, NULL, data->u.num, reference_getref(data));
6509
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
6512         }
6513
6514         end = script_array_highest_key(st, sd, name, reference_getref(data));
6515
6516         if( start >= end )
6517                 return SCRIPT_CMD_SUCCESS;// nothing to free
6518
6519         if( is_string_variable(name) )
6520                 value = (void *)"";
6521         else
6522                 value = (void *)0;
6523
6524         if( script_hasdata(st,3) ) {
6525                 unsigned int count = script_getnum(st, 3);
6526                 if( count > end - start )
6527                         count = end - start;
6528                 if( count <= 0 )
6529                         return SCRIPT_CMD_SUCCESS;// nothing to free
6530
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);
6538                         }
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));
6542                         }
6543                 } else {
6544                         // using sa to speed up
6545                         unsigned int *list = NULL, size = 0;
6546                         list = script_array_cpy_list(sa);
6547                         size = sa->size;
6548                         qsort(list, size, sizeof(unsigned int), script_array_index_cmp);
6549                         
6550                         ARR_FIND(0, size, i, list[i] >= start);
6551                         
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));
6555                         }
6556                         
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));
6564                         }
6565                 }
6566         } else {
6567                 unsigned int *list = NULL, size = 0;
6568                 list = script_array_cpy_list(sa);
6569                 size = sa->size;
6570                 
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));
6574                 }
6575         }
6576
6577         return SCRIPT_CMD_SUCCESS;
6578 }
6579
6580 /// Returns a reference to the target index of the array variable.
6581 /// Equivalent to var[index].
6582 ///
6583 /// getelementofarray(<array variable>,<index>) -> <variable reference>
6584 BUILDIN_FUNC(getelementofarray)
6585 {
6586         struct script_data* data;
6587         int32 id;
6588         int64 i;
6589
6590         data = script_getdata(st, 2);
6591         if( !data_isreference(data) )
6592         {
6593                 ShowError("script:getelementofarray: not a variable\n");
6594                 script_reportdata(data);
6595                 script_pushnil(st);
6596                 st->state = END;
6597                 return SCRIPT_CMD_SUCCESS;// not a variable
6598         }
6599
6600         id = reference_getid(data);
6601
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);
6606                 script_pushnil(st);
6607                 st->state = END;
6608                 return SCRIPT_CMD_FAILURE;// out of range
6609         }
6610
6611         push_val2(st->stack, C_NAME, reference_uid(id, i), reference_getref(data));
6612         return SCRIPT_CMD_SUCCESS;
6613 }
6614
6615 /////////////////////////////////////////////////////////////////////
6616 /// ...
6617 ///
6618
6619 /*==========================================
6620  *
6621  *------------------------------------------*/
6622 BUILDIN_FUNC(setlook)
6623 {
6624         int type,val;
6625         TBL_PC* sd;
6626
6627         type = script_getnum(st,2);
6628         val = script_getnum(st,3);
6629
6630         if (!script_charid2sd(4,sd))
6631                 return SCRIPT_CMD_SUCCESS;
6632
6633         pc_changelook(sd,type,val);
6634
6635         return SCRIPT_CMD_SUCCESS;
6636 }
6637
6638 BUILDIN_FUNC(changelook)
6639 { // As setlook but only client side
6640         int type,val;
6641         TBL_PC* sd;
6642
6643         type = script_getnum(st,2);
6644         val = script_getnum(st,3);
6645
6646         if (!script_charid2sd(4,sd))
6647                 return SCRIPT_CMD_SUCCESS;
6648
6649         clif_changelook(&sd->bl,type,val);
6650
6651         return SCRIPT_CMD_SUCCESS;
6652 }
6653
6654 /*==========================================
6655  *
6656  *------------------------------------------*/
6657 BUILDIN_FUNC(cutin)
6658 {
6659         TBL_PC* sd;
6660
6661         if( !script_rid2sd(sd) )
6662                 return SCRIPT_CMD_SUCCESS;
6663
6664         clif_cutin(sd,script_getstr(st,2),script_getnum(st,3));
6665         return SCRIPT_CMD_SUCCESS;
6666 }
6667
6668 /*==========================================
6669  *
6670  *------------------------------------------*/
6671 BUILDIN_FUNC(viewpoint)
6672 {
6673         int type,x,y,id,color;
6674         TBL_PC* sd;
6675
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);
6681
6682         if( !script_rid2sd(sd) )
6683                 return SCRIPT_CMD_SUCCESS;
6684
6685         clif_viewpoint(sd,st->oid,type,x,y,id,color);
6686
6687         return SCRIPT_CMD_SUCCESS;
6688 }
6689
6690 /**
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
6696  **/
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;
6709
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;
6713         }
6714
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;
6718         }
6719
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;
6723         }
6724
6725         opt_id_ref = reference_getref(opt_id);
6726         opt_id_n = script_array_highest_key(st, NULL, opt_id_var, opt_id_ref);
6727
6728         if (opt_id_n < 1) {
6729                 ShowError("buildin_%s: No option id listed.\n", funcname);
6730                 return SCRIPT_CMD_FAILURE;
6731         }
6732
6733         opt_val_ref = reference_getref(opt_val);
6734         opt_param_ref = reference_getref(opt_param);
6735
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);
6738
6739         if (opt_val_n < 1) {
6740                 ShowError("buildin_%s: No option value listed.\n", funcname);
6741                 return SCRIPT_CMD_FAILURE;
6742         }
6743         if (opt_param_n < 1) {
6744                 ShowError("buildin_%s: No option parameter listed.\n", funcname);
6745                 return SCRIPT_CMD_FAILURE;
6746         }
6747
6748         opt_id_id = reference_getid(opt_id);
6749         opt_val_id = reference_getid(opt_val);
6750         opt_param_id = reference_getid(opt_param);
6751
6752         opt_id_idx = reference_getindex(opt_id);
6753         opt_val_idx = reference_getindex(opt_val);
6754         opt_param_idx = reference_getindex(opt_param);
6755         
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);
6763         }
6764         return SCRIPT_CMD_SUCCESS;
6765 }
6766
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)
6779 {
6780         int i = 0, aid = 3;
6781         struct item_data* id = NULL;
6782         struct script_data* data;
6783         char *command = (char *)script_getfuncname(st);
6784         uint8 loc = 0;
6785         uint16 size, count = 0;
6786         struct item *items;
6787         TBL_PC *sd = NULL;
6788         struct s_storage *gstor = NULL;
6789
6790         if( command[strlen(command)-1] == '2' ) {
6791                 i = 1;
6792                 aid = 10;
6793         }
6794         else if (command[strlen(command)-1] == '3') {
6795                 i = 1;
6796                 aid = 13;
6797         }
6798
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);
6802                         st->state = END;
6803                         return SCRIPT_CMD_FAILURE;
6804                 }
6805         }
6806         else {
6807                 if( !script_rid2sd(sd) )
6808                         return SCRIPT_CMD_SUCCESS;
6809         }
6810
6811         if( !strncmp(command, "cart", 4) ) {
6812                 loc = TABLE_CART;
6813                 size = MAX_CART;
6814                 items = sd->cart.u.items_cart;
6815         }
6816         else if( !strncmp(command, "storage", 7) ) {
6817                 loc = TABLE_STORAGE;
6818                 size = MAX_STORAGE;
6819                 items = sd->storage.u.items_storage;
6820         }
6821         else if( !strncmp(command, "guildstorage", 12) ) {
6822                 gstor = guild2storage2(sd->status.guild_id);
6823
6824                 if (gstor && !sd->state.storage_flag) {
6825                         loc = TABLE_GUILD_STORAGE;
6826                         size = MAX_GUILD_STORAGE;
6827                         items = gstor->u.items_guild;
6828                 } else {
6829                         script_pushint(st, -1);
6830                         return SCRIPT_CMD_SUCCESS;
6831                 }
6832         }
6833         else {
6834                 size = MAX_INVENTORY;
6835                 items = sd->inventory.u.items_inventory;
6836         }
6837
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;
6842         }
6843         
6844         data = script_getdata(st, 2);
6845         get_val(st, data); // Convert into value in case of a variable
6846
6847         if( data_isstring(data) ) // item name
6848                 id = itemdb_searchname(conv_str(st, data));
6849         else // item id
6850                 id = itemdb_exists(conv_num(st, data));
6851
6852         if( id == NULL ) {
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;
6856         }
6857
6858         if (loc == TABLE_GUILD_STORAGE)
6859                 gstor->lock = true;
6860
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;
6866         }
6867         else { // For count/cart/storagecountitem2 function
6868                 struct item it;
6869                 bool check_randomopt = false;
6870                 memset(&it, 0, sizeof(it));
6871
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);
6880
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;
6886                 }
6887
6888                 for( i = 0; i < size; i++ ) {
6889                         struct item *itm = &items[i];
6890                         if (!itm || !itm->nameid || itm->amount < 1)
6891                                 continue;
6892                         if (itm->nameid != it.nameid || itm->identify != it.identify || itm->refine != it.refine || itm->attribute != it.attribute)
6893                                 continue;
6894                         if (memcmp(it.card, itm->card, sizeof(it.card)))
6895                                 continue;
6896                         if (check_randomopt) {
6897                                 uint8 j;
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)
6900                                                 break;
6901                                 }
6902                                 if (j != MAX_ITEM_RDM_OPT)
6903                                         continue;
6904                         }
6905                         count += items[i].amount;
6906                 }
6907         }
6908
6909         if (loc == TABLE_GUILD_STORAGE) {
6910                 storage_guild_storageclose(sd);
6911                 gstor->lock = false;
6912         }
6913
6914         script_pushint(st, count);
6915         return SCRIPT_CMD_SUCCESS;
6916 }
6917
6918 /*==========================================
6919  * Check if item with this amount can fit in inventory
6920  * Checking : weight, stack amount >(MAX_AMOUNT), slots amount >(MAX_INVENTORY)
6921  * Return
6922  *      0 : fail
6923  *      1 : success (npc side only)
6924  *------------------------------------------*/
6925 BUILDIN_FUNC(checkweight)
6926 {
6927         int slots = 0;
6928         unsigned short amount2 = 0;
6929         unsigned int weight = 0, i, nbargs;
6930         struct item_data* id = NULL;
6931         struct map_session_data* sd;
6932
6933         if( !script_rid2sd(sd) )
6934                 return SCRIPT_CMD_SUCCESS;
6935
6936         nbargs = script_lastdata(st)+1;
6937         if(nbargs%2) {
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;
6941         }
6942         slots = pc_inventoryblank(sd); //nb of empty slot
6943
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));
6950                 else // item id
6951                         id = itemdb_exists(conv_num(st, data));
6952                 if( id == NULL ) {
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;
6956                 }
6957                 nameid = id->nameid;
6958
6959                 amount = script_getnum(st,i+1);
6960                 if( amount < 1 ) {
6961                         ShowError("buildin_checkweight: Invalid amount '%d'.\n", amount);
6962                         script_pushint(st,0);
6963                         return SCRIPT_CMD_FAILURE;
6964                 }
6965
6966                 weight += itemdb_weight(nameid)*amount; //total weight for all chk
6967                 if( weight + sd->weight > sd->max_weight )
6968                 {// too heavy
6969                         script_pushint(st,0);
6970                         return SCRIPT_CMD_SUCCESS;
6971                 }
6972
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
6976                                 break;
6977                         case CHKADDITEM_NEW:
6978                                 if( itemdb_isstackable(nameid) ) {
6979                                         // stackable
6980                                         amount2++;
6981                                         if( slots < amount2 ) {
6982                                                 script_pushint(st,0);
6983                                                 return SCRIPT_CMD_SUCCESS;
6984                                         }
6985                                 } else {
6986                                         // non-stackable
6987                                         amount2 += amount;
6988                                         if( slots < amount2) {
6989                                                 script_pushint(st,0);
6990                                                 return SCRIPT_CMD_SUCCESS;
6991                                         }
6992                                 }
6993                                 break;
6994                         case CHKADDITEM_OVERAMOUNT:
6995                                 script_pushint(st,0);
6996                                 return SCRIPT_CMD_SUCCESS;
6997                 }
6998         }
6999
7000         script_pushint(st,1);
7001         return SCRIPT_CMD_SUCCESS;
7002 }
7003
7004 BUILDIN_FUNC(checkweight2)
7005 {
7006         //variable sub checkweight
7007         int i = 0, slots = 0, weight = 0;
7008         short fail = 0;
7009         unsigned short amount2 = 0;
7010
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;
7016         int32 id_it, id_nb;
7017         int32 idx_it, idx_nb;
7018         int nb_it, nb_nb; //array size
7019
7020         TBL_PC *sd;
7021         
7022         if( !script_rid2sd(sd) )
7023                 return SCRIPT_CMD_SUCCESS;
7024
7025         data_it = script_getdata(st, 2);
7026         data_nb = script_getdata(st, 3);
7027
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
7032         }
7033
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);
7040
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
7045         }
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);
7050                 fail = 1;
7051         }
7052
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);
7059
7060                 if(fail)
7061                         continue; //cpntonie to depop rest
7062
7063                 if(itemdb_exists(nameid) == NULL ) {
7064                         ShowError("buildin_checkweight2: Invalid item '%d'.\n", nameid);
7065                         fail=1;
7066                         continue;
7067                 }
7068                 if(amount < 0 ) {
7069                         ShowError("buildin_checkweight2: Invalid amount '%d'.\n", amount);
7070                         fail = 1;
7071                         continue;
7072                 }
7073
7074                 weight += itemdb_weight(nameid)*amount;
7075                 if( weight + sd->weight > sd->max_weight ) {
7076                         fail = 1;
7077                         continue;
7078                 }
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
7082                                 break;
7083                         case CHKADDITEM_NEW:
7084                                 if( itemdb_isstackable(nameid) ) {// stackable
7085                                         amount2++;
7086                                         if( slots < amount2 )
7087                                                 fail = 1;
7088                                 } else {// non-stackable
7089                                         amount2 += amount;
7090                                         if( slots < amount2 ) {
7091                                                 fail = 1;
7092                                         }
7093                                 }
7094                                 break;
7095                         case CHKADDITEM_OVERAMOUNT:
7096                                 fail = 1;
7097                 } //end switch
7098         } //end loop DO NOT break it prematurly we need to depop all stack
7099
7100         fail ? script_pushint(st,0) : script_pushint(st,1);
7101         return SCRIPT_CMD_SUCCESS;
7102 }
7103
7104 /*==========================================
7105  * getitem <item id>,<amount>{,<account ID>};
7106  * getitem "<item name>",<amount>{,<account ID>};
7107  *
7108  * getitembound <item id>,<amount>,<type>{,<account ID>};
7109  * getitembound "<item id>",<amount>,<type>{,<account ID>};
7110  * Type:
7111  *      0 - No bound
7112  *      1 - Account Bound
7113  *      2 - Guild Bound
7114  *      3 - Party Bound
7115  *      4 - Character Bound
7116  *------------------------------------------*/
7117 BUILDIN_FUNC(getitem)
7118 {
7119         int get_count, i;
7120         unsigned short nameid, amount;
7121         struct item it;
7122         TBL_PC *sd;
7123         struct script_data *data;
7124         unsigned char flag = 0;
7125         const char* command = script_getfuncname(st);
7126         struct item_data *id = NULL;
7127
7128         data = script_getdata(st,2);
7129         get_val(st,data);
7130         if( data_isstring(data) ) {// "<item name>"
7131                 const char *name = conv_str(st,data);
7132                 id = itemdb_searchname(name);
7133                 if( id == NULL ){
7134                         ShowError("buildin_getitem: Nonexistant item %s requested.\n", name);
7135                         return SCRIPT_CMD_FAILURE; //No item created.
7136                 }
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.
7143                 }
7144         } else {
7145                 ShowError("buildin_getitem: invalid data type for argument #1 (%d).", data->type);
7146                 return SCRIPT_CMD_FAILURE;
7147         }
7148
7149         // <amount>
7150         if( (amount = script_getnum(st,3)) <= 0)
7151                 return SCRIPT_CMD_SUCCESS; //return if amount <=0, skip the useles iteration
7152
7153         memset(&it,0,sizeof(it));
7154         it.nameid = nameid;
7155         it.identify = 1;
7156         it.bound = BOUND_NONE;
7157
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;
7163                 }
7164                 script_mapid2sd(5,sd);
7165                 it.bound = bound;
7166         } else {
7167                 script_mapid2sd(4,sd);
7168         }
7169
7170         if( sd == NULL ) // no target
7171                 return SCRIPT_CMD_SUCCESS;
7172
7173         //Check if it's stackable.
7174         if (!itemdb_isstackable2(id))
7175                 get_count = 1;
7176         else
7177                 get_count = amount;
7178
7179         for (i = 0; i < amount; i += get_count)
7180         {
7181                 // if not pet egg
7182                 if (!pet_create_egg(sd, nameid))
7183                 {
7184                         if ((flag = pc_additem(sd, &it, get_count, LOG_TYPE_SCRIPT)))
7185                         {
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);
7189                         }
7190                 }
7191         }
7192         return SCRIPT_CMD_SUCCESS;
7193 }
7194
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>};
7198  *
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>};
7201  *
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>};
7204  *
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>};
7207  * Type:
7208  *      0 - No bound
7209  *      1 - Account Bound
7210  *      2 - Guild Bound
7211  *      3 - Party Bound
7212  *      4 - Character Bound
7213  *------------------------------------------*/
7214 BUILDIN_FUNC(getitem2)
7215 {
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;
7222         TBL_PC *sd;
7223         struct script_data *data;
7224         const char* command = script_getfuncname(st);
7225         int offset = 0;
7226
7227         if( !strncmp(command,"getitembound",12) ) {
7228                 int aid_pos = 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;
7233                 }
7234                 if (command[strlen(command)-1] == '3') {
7235                         offset = 12;
7236                         aid_pos = 15;
7237                 }
7238                 script_mapid2sd(aid_pos,sd);
7239         } else {
7240                 int aid_pos = 11;
7241                 if (strcmpi(command,"getitem3") == 0) {
7242                         offset = 11;
7243                         aid_pos = 14;
7244                 } 
7245                 script_mapid2sd(aid_pos,sd);
7246         }
7247
7248         if( sd == NULL ) // no target
7249                 return SCRIPT_CMD_SUCCESS;
7250
7251         data = script_getdata(st,2);
7252         get_val(st,data);
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.
7258                 }
7259                 nameid = item_data->nameid;
7260         } else {
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.
7265                 }
7266         }
7267
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);
7276
7277         if( item_data ) {
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)
7282                                 ref = MAX_REFINE;
7283                 }
7284                 else if( item_data->type == IT_PETEGG ) {
7285                         iden = 1;
7286                         ref = 0;
7287                 }
7288                 else {
7289                         iden = 1;
7290                         ref = attr = 0;
7291                 }
7292
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;
7302
7303                 if (offset != 0) {
7304                         int res = script_getitem_randomoption(st, &item_tmp, command, offset);
7305                         if (res == SCRIPT_CMD_FAILURE)
7306                                 return SCRIPT_CMD_FAILURE;
7307                 }
7308
7309                 //Check if it's stackable.
7310                 if (!itemdb_isstackable2(item_data))
7311                         get_count = 1;
7312                 else
7313                         get_count = amount;
7314
7315                 for (i = 0; i < amount; i += get_count)
7316                 {
7317                         // if not pet egg
7318                         if (!pet_create_egg(sd, nameid))
7319                         {
7320                                 unsigned char flag = 0;
7321                                 if ((flag = pc_additem(sd, &item_tmp, get_count, LOG_TYPE_SCRIPT)))
7322                                 {
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);
7326                                 }
7327                         }
7328                 }
7329         }
7330         return SCRIPT_CMD_SUCCESS;
7331 }
7332
7333 /** Gives rental item to player
7334  * rentitem <item id>,<seconds>{,<account_id>}
7335  * rentitem "<item name>",<seconds>{,<account_id>}
7336  */
7337 BUILDIN_FUNC(rentitem) {
7338         struct map_session_data *sd;
7339         struct script_data *data;
7340         struct item it;
7341         int seconds;
7342         unsigned short nameid = 0;
7343         unsigned char flag = 0;
7344
7345         data = script_getdata(st,2);
7346         get_val(st,data);
7347
7348         if (!script_accid2sd(4,sd))
7349                 return SCRIPT_CMD_FAILURE;
7350
7351         if( data_isstring(data) )
7352         {
7353                 const char *name = conv_str(st,data);
7354                 struct item_data *itd = itemdb_searchname(name);
7355                 if( itd == NULL )
7356                 {
7357                         ShowError("buildin_rentitem: Nonexistant item %s requested.\n", name);
7358                         return SCRIPT_CMD_FAILURE;
7359                 }
7360                 nameid = itd->nameid;
7361         }
7362         else if( data_isint(data) )
7363         {
7364                 nameid = conv_num(st,data);
7365                 if( nameid == 0 || !itemdb_exists(nameid) )
7366                 {
7367                         ShowError("buildin_rentitem: Nonexistant item %hu requested.\n", nameid);
7368                         return SCRIPT_CMD_FAILURE;
7369                 }
7370         }
7371         else
7372         {
7373                 ShowError("buildin_rentitem: invalid data type for argument #1 (%d).\n", data->type);
7374                 return SCRIPT_CMD_FAILURE;
7375         }
7376
7377         seconds = script_getnum(st,3);
7378         memset(&it, 0, sizeof(it));
7379         it.nameid = nameid;
7380         it.identify = 1;
7381         it.expire_time = (unsigned int)(time(NULL) + seconds);
7382         it.bound = BOUND_NONE;
7383
7384         if( (flag = pc_additem(sd, &it, 1, LOG_TYPE_SCRIPT)) )
7385         {
7386                 clif_additem(sd, 0, 0, flag);
7387                 return SCRIPT_CMD_FAILURE;
7388         }
7389         return SCRIPT_CMD_SUCCESS;
7390 }
7391
7392 /**
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>};
7396  *
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>};
7399  */
7400 BUILDIN_FUNC(rentitem2) {
7401         struct map_session_data *sd;
7402         struct script_data *data;
7403         struct item it;
7404         struct item_data *id;
7405         int seconds;
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);
7410
7411         data = script_getdata(st,2);
7412         get_val(st,data);
7413
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;
7419
7420         if( data_isstring(data) ) {
7421                 const char *name = conv_str(st,data);
7422                 id = itemdb_searchname(name);
7423                 if( id == NULL ) {
7424                         ShowError("buildin_rentitem2: Nonexistant item %s requested.\n", name);
7425                         return SCRIPT_CMD_FAILURE;
7426                 }
7427                 nameid = id->nameid;
7428         }
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;
7434                 }
7435         }
7436         else {
7437                 ShowError("buildin_rentitem2: invalid data type for argument #1 (%d).\n", data->type);
7438                 return SCRIPT_CMD_FAILURE;
7439         }
7440         
7441         seconds = script_getnum(st,3);
7442         iden = script_getnum(st,4);
7443         ref = script_getnum(st,5);
7444         attr = script_getnum(st,6);
7445
7446         if (id->type==IT_WEAPON || id->type==IT_ARMOR || id->type==IT_SHADOWGEAR) {
7447                 if(ref > MAX_REFINE) ref = MAX_REFINE;
7448         }
7449         else if (id->type==IT_PETEGG) {
7450                 iden = 1;
7451                 ref = 0;
7452         }
7453         else {
7454                 iden = 1;
7455                 ref = attr = 0;
7456         }
7457
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);
7462
7463         memset(&it, 0, sizeof(it));
7464         it.nameid = nameid;
7465         it.identify = iden;
7466         it.refine = ref;
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);
7473
7474         if (funcname[strlen(funcname)-1] == '3') {
7475                 int res = script_getitem_randomoption(st, &it, funcname, 11);
7476                 if (res != SCRIPT_CMD_SUCCESS)
7477                         return res;
7478         }
7479
7480         if( (flag = pc_additem(sd, &it, 1, LOG_TYPE_SCRIPT)) ) {
7481                 clif_additem(sd, 0, 0, flag);
7482                 return SCRIPT_CMD_FAILURE;
7483         }
7484
7485         return SCRIPT_CMD_SUCCESS;
7486 }
7487
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
7492  * equipment
7493  *------------------------------------------*/
7494 BUILDIN_FUNC(getnameditem)
7495 {
7496         unsigned short nameid;
7497         struct item item_tmp;
7498         TBL_PC *sd, *tsd;
7499         struct script_data *data;
7500
7501         if (!script_rid2sd(sd))
7502         {       //Player not attached!
7503                 script_pushint(st,0);
7504                 return SCRIPT_CMD_SUCCESS;
7505         }
7506
7507         data=script_getdata(st,2);
7508         get_val(st,data);
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)
7513                 {       //Failed
7514                         script_pushint(st,0);
7515                         return SCRIPT_CMD_SUCCESS;
7516                 }
7517                 nameid = item_data->nameid;
7518         }else
7519                 nameid = conv_num(st,data);
7520
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;
7525         }
7526
7527         data=script_getdata(st,3);
7528         get_val(st,data);
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));
7533
7534         if( tsd == NULL )
7535         {       //Failed
7536                 script_pushint(st,0);
7537                 return SCRIPT_CMD_SUCCESS;
7538         }
7539
7540         memset(&item_tmp,0,sizeof(item_tmp));
7541         item_tmp.nameid=nameid;
7542         item_tmp.amount=1;
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
7550         }
7551
7552         script_pushint(st,1);
7553         return SCRIPT_CMD_SUCCESS;
7554 }
7555
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;
7562         int sub_group = 1;
7563
7564         FETCH(3, sub_group);
7565         entry = itemdb_get_randgroupitem(script_getnum(st,2),sub_group);
7566         if (!entry) {
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;
7570         }
7571         script_pushint(st,entry->nameid);
7572         return SCRIPT_CMD_SUCCESS;
7573 }
7574
7575 /**
7576 * makeitem <item id>,<amount>,"<map name>",<X>,<Y>;
7577 * makeitem "<item name>",<amount>,"<map name>",<X>,<Y>;
7578 */
7579 BUILDIN_FUNC(makeitem) {
7580         uint16 nameid, amount, flag = 0, x, y;
7581         const char *mapname;
7582         int m;
7583         struct item item_tmp;
7584         struct script_data *data;
7585
7586         data = script_getdata(st,2);
7587         get_val(st,data);
7588         if( data_isstring(data) ){
7589                 const char *name = conv_str(st,data);
7590                 struct item_data *item_data = itemdb_searchname(name);
7591                 if( item_data )
7592                         nameid = item_data->nameid;
7593                 else
7594                         nameid = UNKNOWN_ITEM_ID;
7595         }
7596         else
7597                 nameid = conv_num(st,data);
7598
7599         amount = script_getnum(st,3);
7600         mapname = script_getstr(st,4);
7601         x = script_getnum(st,5);
7602         y = script_getnum(st,6);
7603
7604         if(strcmp(mapname,"this")==0) {
7605                 TBL_PC *sd;
7606                 if (!script_rid2sd(sd))
7607                         return SCRIPT_CMD_SUCCESS; //Failed...
7608                 m = sd->bl.m;
7609         } else
7610                 m = map_mapname2mapid(mapname);
7611
7612         if(nameid<0) {
7613                 nameid = -nameid;
7614                 flag = 1;
7615         }
7616
7617         if(nameid > 0) {
7618                 memset(&item_tmp,0,sizeof(item_tmp));
7619                 item_tmp.nameid = nameid;
7620                 if(!flag)
7621                         item_tmp.identify = 1;
7622                 else
7623                         item_tmp.identify = itemdb_isidentified(nameid);
7624
7625                 map_addflooritem(&item_tmp,amount,m,x,y,0,0,0,4,0);
7626         }
7627         return SCRIPT_CMD_SUCCESS;
7628 }
7629
7630 /**
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>;
7633  *
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>;
7636  */
7637 BUILDIN_FUNC(makeitem2) {
7638         uint16 nameid, amount, x, y;
7639         const char *mapname;
7640         int m;
7641         struct item item_tmp;
7642         struct script_data *data;
7643         struct item_data *id;
7644         const char *funcname = script_getfuncname(st);
7645
7646         data = script_getdata(st,2);
7647         get_val(st,data);
7648         if( data_isstring(data) ){
7649                 const char *name = conv_str(st,data);
7650                 struct item_data *item_data = itemdb_searchname(name);
7651                 if( item_data )
7652                         nameid = item_data->nameid;
7653                 else
7654                         nameid = UNKNOWN_ITEM_ID;
7655         }
7656         else
7657                 nameid = conv_num(st,data);
7658
7659         amount = script_getnum(st,3);
7660         mapname = script_getstr(st,4);
7661         x = script_getnum(st,5);
7662         y = script_getnum(st,6);
7663
7664         if (strcmp(mapname,"this")==0) {
7665                 TBL_PC *sd;
7666                 if (!script_rid2sd(sd))
7667                         return SCRIPT_CMD_SUCCESS; //Failed...
7668                 m = sd->bl.m;
7669         }
7670         else
7671                 m = map_mapname2mapid(mapname);
7672         
7673         if ((id = itemdb_search(nameid))) {
7674                 char iden, ref, attr;
7675                 memset(&item_tmp,0,sizeof(item_tmp));
7676                 item_tmp.nameid = nameid;
7677
7678                 iden = (char)script_getnum(st,7);
7679                 ref = (char)script_getnum(st,8);
7680                 attr = (char)script_getnum(st,9);               
7681
7682                 if (id->type==IT_WEAPON || id->type==IT_ARMOR || id->type==IT_SHADOWGEAR) {
7683                         if(ref > MAX_REFINE) ref = MAX_REFINE;
7684                 }
7685                 else if (id->type==IT_PETEGG) {
7686                         iden = 1;
7687                         ref = 0;
7688                 }
7689                 else {
7690                         iden = 1;
7691                         ref = attr = 0;
7692                 }
7693                 
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);
7701
7702                 if (funcname[strlen(funcname)-1] == '3') {
7703                         int res = script_getitem_randomoption(st, &item_tmp, funcname, 14);
7704                         if (res != SCRIPT_CMD_SUCCESS)
7705                                 return res;
7706                 }
7707
7708                 map_addflooritem(&item_tmp,amount,m,x,y,0,0,0,4,0);
7709         }
7710         else
7711                 return SCRIPT_CMD_FAILURE;
7712         return SCRIPT_CMD_SUCCESS;
7713 }
7714
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)
7719 {
7720         int delamount;
7721         struct item *itm = NULL;
7722         struct s_storage *gstor = NULL;
7723
7724         switch(loc) {
7725                 case TABLE_CART:
7726                         itm = &sd->cart.u.items_cart[idx];
7727                         break;
7728                 case TABLE_STORAGE:
7729                         itm = &sd->storage.u.items_storage[idx];
7730                         break;
7731                 case TABLE_GUILD_STORAGE:
7732                 {
7733                         gstor = guild2storage2(sd->status.guild_id);
7734
7735                         itm = &gstor->u.items_guild[idx];
7736                 }
7737                         break;
7738                 default: // TABLE_INVENTORY
7739                         itm = &sd->inventory.u.items_inventory[idx];
7740                         break;
7741         }
7742
7743         delamount = ( amount[0] < itm->amount ) ? amount[0] : itm->amount;
7744
7745         if( delete_items )
7746         {
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]));
7750                 }
7751                 switch(loc) {
7752                         case TABLE_CART:
7753                                 pc_cart_delitem(sd,idx,delamount,0,LOG_TYPE_SCRIPT);
7754                                 break;
7755                         case TABLE_STORAGE:
7756                                 storage_delitem(sd,&sd->storage,idx,delamount);
7757                                 log_pick_pc(sd,LOG_TYPE_SCRIPT,-delamount,itm);
7758                                 break;
7759                         case TABLE_GUILD_STORAGE:
7760                                 gstor->lock = true;
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;
7765                                 break;
7766                         default: // TABLE_INVENTORY
7767                                 pc_delitem(sd, idx, delamount, 0, 0, LOG_TYPE_SCRIPT);
7768                                 break;
7769                 }
7770         }
7771
7772         amount[0]-= delamount;
7773 }
7774
7775
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)
7785 {
7786         bool delete_items = false;
7787         int i, amount, size;
7788         struct item *items;
7789
7790         // prefer always non-equipped items
7791         it->equip = 0;
7792
7793         // when searching for nameid only, prefer additionally
7794         if( !exact_match )
7795         {
7796                 // non-refined items
7797                 it->refine = 0;
7798                 // card-less items
7799                 memset(it->card, 0, sizeof(it->card));
7800         }
7801
7802         switch(loc) {
7803                 case TABLE_CART:
7804                         size = MAX_CART;
7805                         items = sd->cart.u.items_cart;
7806                         break;
7807                 case TABLE_STORAGE:
7808                         size = MAX_STORAGE;
7809                         items = sd->storage.u.items_storage;
7810                         break;
7811                 case TABLE_GUILD_STORAGE:
7812                 {
7813                         struct s_storage *gstor = guild2storage2(sd->status.guild_id);
7814
7815                         size = MAX_GUILD_STORAGE;
7816                         items = gstor->u.items_guild;
7817                 }
7818                         break;
7819                 default: // TABLE_INVENTORY
7820                         size = MAX_INVENTORY;
7821                         items = sd->inventory.u.items_inventory;
7822                         break;
7823         }
7824
7825         for(;;)
7826         {
7827                 unsigned short important = 0;
7828                 amount = it->amount;
7829
7830                 // 1st pass -- less important items / exact match
7831                 for( i = 0; amount && i < size; i++ )
7832                 {
7833                         struct item *itm = NULL;
7834
7835                         if( !&items[i] || !(itm = &items[i])->nameid || itm->nameid != it->nameid )
7836                         {// wrong/invalid item
7837                                 continue;
7838                         }
7839
7840                         if( itm->equip != it->equip || itm->refine != it->refine )
7841                         {// not matching attributes
7842                                 important++;
7843                                 continue;
7844                         }
7845
7846                         if( exact_match )
7847                         {
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
7850                                         continue;
7851                                 }
7852                                 if (exact_match&0x2) {
7853                                         uint8 j;
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)
7856                                                         break;
7857                                         }
7858                                         if (j != MAX_ITEM_RDM_OPT)
7859                                                 continue;
7860                                 }
7861                         }
7862                         else
7863                         {
7864                                 if( itemdb_type(itm->nameid) == IT_PETEGG )
7865                                 {
7866                                         if( itm->card[0] == CARD0_PET && CheckForCharServer() )
7867                                         {// pet which cannot be deleted
7868                                                 continue;
7869                                         }
7870                                 }
7871                                 else if( memcmp(itm->card, it->card, sizeof(itm->card)) )
7872                                 {// named/carded item
7873                                         important++;
7874                                         continue;
7875                                 }
7876                         }
7877
7878                         // count / delete item
7879                         buildin_delitem_delete(sd, i, &amount, loc, delete_items);
7880                 }
7881
7882                 // 2nd pass -- any matching item
7883                 if( amount == 0 || important == 0 )
7884                 {// either everything was already consumed or no items were skipped
7885                         ;
7886                 }
7887                 else for( i = 0; amount && i < size; i++ )
7888                 {
7889                         struct item *itm = NULL;
7890
7891                         if( !&items[i] || !(itm = &items[i])->nameid || itm->nameid != it->nameid )
7892                         {// wrong/invalid item
7893                                 continue;
7894                         }
7895
7896                         if( itemdb_type(itm->nameid) == IT_PETEGG && itm->card[0] == CARD0_PET && CheckForCharServer() )
7897                         {// pet which cannot be deleted
7898                                 continue;
7899                         }
7900
7901                         if( exact_match )
7902                         {
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
7905                                         continue;
7906                                 }
7907                                 if (exact_match&0x2) {
7908                                         uint8 j;
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)
7911                                                         break;
7912                                         }
7913                                         if (j != MAX_ITEM_RDM_OPT)
7914                                                 continue;
7915                                 }
7916                         }
7917
7918                         // count / delete item
7919                         buildin_delitem_delete(sd, i, &amount, loc, delete_items);
7920                 }
7921
7922                 if( amount )
7923                 {// not enough items
7924                         return false;
7925                 }
7926                 else if( delete_items )
7927                 {// we are done with the work
7928                         return true;
7929                 }
7930                 else
7931                 {// get rid of the items now
7932                         delete_items = true;
7933                 }
7934         }
7935 }
7936
7937
7938 /// Deletes items from the target/attached player.
7939 /// Prioritizes ordinary items.
7940 ///
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)
7950 {
7951         TBL_PC *sd;
7952         struct item it;
7953         struct script_data *data;
7954         uint8 loc = 0;
7955         char* command = (char*)script_getfuncname(st);
7956
7957         if(!strncmp(command, "cart", 4))
7958                 loc = TABLE_CART;
7959         else if(!strncmp(command, "storage", 7))
7960                 loc = TABLE_STORAGE;
7961         else if(!strncmp(command, "guildstorage", 12))
7962                 loc = TABLE_GUILD_STORAGE;
7963
7964         if( !script_accid2sd(4,sd) ){
7965                 // In any case cancel script execution
7966                 st->state = END;
7967                 return SCRIPT_CMD_SUCCESS;
7968         }
7969
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;
7974         }
7975         if (loc == TABLE_GUILD_STORAGE) {
7976                 struct s_storage *gstor = guild2storage2(sd->status.guild_id);
7977
7978                 if (gstor == NULL || sd->state.storage_flag) {
7979                         script_pushint(st, -1);
7980                         return SCRIPT_CMD_FAILURE;
7981                 }
7982         }
7983
7984         data = script_getdata(st,2);
7985         get_val(st,data);
7986         if( data_isstring(data) )
7987         {
7988                 const char* item_name = conv_str(st,data);
7989                 struct item_data* id = itemdb_searchname(item_name);
7990                 if( id == NULL )
7991                 {
7992                         ShowError("buildin_%s: unknown item \"%s\".\n", command, item_name);
7993                         st->state = END;
7994                         return SCRIPT_CMD_FAILURE;
7995                 }
7996                 it.nameid = id->nameid;// "<item name>"
7997         }
7998         else
7999         {
8000                 it.nameid = conv_num(st,data);// <item id>
8001                 if( !itemdb_exists( it.nameid ) )
8002                 {
8003                         ShowError("buildin_%s: unknown item \"%hu\".\n", command, it.nameid);
8004                         st->state = END;
8005                         return SCRIPT_CMD_FAILURE;
8006                 }
8007         }
8008
8009         it.amount=script_getnum(st,3);
8010
8011         if( it.amount <= 0 )
8012                 return SCRIPT_CMD_SUCCESS;// nothing to do
8013
8014         if( buildin_delitem_search(sd, &it, 0, loc) )
8015         {// success
8016                 return SCRIPT_CMD_SUCCESS;
8017         }
8018
8019         ShowError("buildin_%s: failed to delete %d items (AID=%d item_id=%hu).\n", command, it.amount, sd->status.account_id, it.nameid);
8020         st->state = END;
8021         st->mes_active = 0;
8022         clif_scriptclose(sd, st->oid);
8023         return SCRIPT_CMD_FAILURE;
8024 }
8025
8026 /// Deletes items from the target/attached player.
8027 ///
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)
8039 {
8040         TBL_PC *sd;
8041         struct item it;
8042         struct script_data *data;
8043         uint8 loc = 0;
8044         char* command = (char*)script_getfuncname(st);
8045         int aid_pos = 11;
8046         uint8 flag = 0x1;
8047
8048         if(!strncmp(command, "cart", 4))
8049                 loc = TABLE_CART;
8050         else if(!strncmp(command, "storage", 7))
8051                 loc = TABLE_STORAGE;
8052         else if(!strncmp(command, "guildstorage", 12))
8053                 loc = TABLE_GUILD_STORAGE;
8054
8055         if (command[strlen(command)-1] == '3')
8056                 aid_pos = 14;
8057
8058         if( !script_accid2sd(aid_pos,sd) ){
8059                 // In any case cancel script execution
8060                 st->state = END;
8061                 return SCRIPT_CMD_SUCCESS;
8062         }
8063
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;
8068         }
8069         if (loc == TABLE_GUILD_STORAGE) {
8070                 struct s_storage *gstor = guild2storage2(sd->status.guild_id);
8071
8072                 if (gstor == NULL || sd->state.storage_flag) {
8073                         script_pushint(st, -1);
8074                         return SCRIPT_CMD_FAILURE;
8075                 }
8076         }
8077
8078         memset(&it, 0, sizeof(it));
8079
8080         data = script_getdata(st,2);
8081         get_val(st,data);
8082         if( data_isstring(data) )
8083         {
8084                 const char* item_name = conv_str(st,data);
8085                 struct item_data* id = itemdb_searchname(item_name);
8086                 if( id == NULL )
8087                 {
8088                         ShowError("buildin_%s: unknown item \"%s\".\n", command, item_name);
8089                         st->state = END;
8090                         return SCRIPT_CMD_FAILURE;
8091                 }
8092                 it.nameid = id->nameid;// "<item name>"
8093         }
8094         else
8095         {
8096                 it.nameid = conv_num(st,data);// <item id>
8097                 if( !itemdb_exists( it.nameid ) )
8098                 {
8099                         ShowError("buildin_%s: unknown item \"%hu\".\n", command, it.nameid);
8100                         st->state = END;
8101                         return SCRIPT_CMD_FAILURE;
8102                 }
8103         }
8104
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);
8113
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;
8118                 flag |= 0x2;
8119         }
8120
8121         if( it.amount <= 0 )
8122                 return SCRIPT_CMD_SUCCESS;// nothing to do
8123
8124         if( buildin_delitem_search(sd, &it, flag, loc) )
8125         {// success
8126                 return SCRIPT_CMD_SUCCESS;
8127         }
8128
8129         ShowError("buildin_%s: failed to delete %d items (AID=%d item_id=%hu).\n", command, it.amount, sd->status.account_id, it.nameid);
8130         st->state = END;
8131         st->mes_active = 0;
8132         clif_scriptclose(sd, st->oid);
8133         return SCRIPT_CMD_FAILURE;
8134 }
8135
8136 /*==========================================
8137  * Enables/Disables use of items while in an NPC [Skotlex]
8138  *------------------------------------------*/
8139 BUILDIN_FUNC(enableitemuse)
8140 {
8141         TBL_PC *sd;
8142         if (script_rid2sd(sd))
8143                 st->npc_item_flag = sd->npc_item_flag = 1;
8144         return SCRIPT_CMD_SUCCESS;
8145 }
8146
8147 BUILDIN_FUNC(disableitemuse)
8148 {
8149         TBL_PC *sd;
8150         if (script_rid2sd(sd))
8151                 st->npc_item_flag = sd->npc_item_flag = 0;
8152         return SCRIPT_CMD_SUCCESS;
8153 }
8154
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)
8162 {
8163         int value;
8164         struct script_data *data = script_getdata(st, 2);
8165         TBL_PC *sd = NULL;
8166
8167         if( script_hasdata(st, 3) ){
8168                 struct script_data *data2 = script_getdata(st, 3);
8169
8170                 get_val(st, data2);
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);
8175                 }
8176         }else{
8177                 script_rid2sd(sd);
8178         }
8179         
8180         if( !sd ){
8181                 script_pushint(st, -1);
8182                 return SCRIPT_CMD_FAILURE;
8183         }
8184
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;
8189         }else{
8190                 value = pc_readparam(sd,script_getnum(st, 2));
8191         }
8192
8193         script_pushint(st,value);
8194         return SCRIPT_CMD_SUCCESS;
8195 }
8196
8197 /*==========================================
8198  * Return charid identification
8199  * return by @num :
8200  *      0 : char_id
8201  *      1 : party_id
8202  *      2 : guild_id
8203  *      3 : account_id
8204  *      4 : bg_id
8205  *      5 : clan_id
8206  *------------------------------------------*/
8207 BUILDIN_FUNC(getcharid)
8208 {
8209         int num;
8210         TBL_PC *sd;
8211
8212         num = script_getnum(st,2);
8213
8214         if( !script_nick2sd(3,sd) ){
8215                 script_pushint(st,0); //return 0, according docs
8216                 return SCRIPT_CMD_SUCCESS;
8217         }
8218
8219         switch( num ) {
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;
8226         default:
8227                 ShowError("buildin_getcharid: invalid parameter (%d).\n", num);
8228                 script_pushint(st,0);
8229                 break;
8230         }
8231         return SCRIPT_CMD_SUCCESS;
8232 }
8233
8234 /*==========================================
8235  * returns the GID of an NPC
8236  *------------------------------------------*/
8237 BUILDIN_FUNC(getnpcid)
8238 {
8239         int num = script_getnum(st,2);
8240         struct npc_data* nd = NULL;
8241
8242         if( script_hasdata(st,3) )
8243         {// unique npc name
8244                 if( ( nd = npc_name2id(script_getstr(st,3)) ) == NULL )
8245                 {
8246                         ShowError("buildin_getnpcid: No such NPC '%s'.\n", script_getstr(st,3));
8247                         script_pushint(st,0);
8248                         return SCRIPT_CMD_FAILURE;
8249                 }
8250         }
8251
8252         switch (num) {
8253                 case 0:
8254                         script_pushint(st,nd ? nd->bl.id : st->oid);
8255                         break;
8256                 default:
8257                         ShowError("buildin_getnpcid: invalid parameter (%d).\n", num);
8258                         script_pushint(st,0);
8259                         return SCRIPT_CMD_FAILURE;
8260         }
8261         return SCRIPT_CMD_SUCCESS;
8262 }
8263
8264 /*==========================================
8265  * Return the name of the party_id
8266  * null if not found
8267  *------------------------------------------*/
8268 BUILDIN_FUNC(getpartyname)
8269 {
8270         int party_id;
8271         struct party_data* p;
8272
8273         party_id = script_getnum(st,2);
8274
8275         if( ( p = party_search(party_id) ) != NULL )
8276         {
8277                 script_pushstrcopy(st,p->party.name);
8278         }
8279         else
8280         {
8281                 script_pushconststr(st,"null");
8282         }
8283         return SCRIPT_CMD_SUCCESS;
8284 }
8285
8286 /*==========================================
8287  * Get the information of the members of a party by type
8288  * @party_id, @type
8289  * return by @type :
8290  *      - : nom des membres
8291  *      1 : char_id des membres
8292  *      2 : account_id des membres
8293  *------------------------------------------*/
8294 BUILDIN_FUNC(getpartymember)
8295 {
8296         struct party_data *p;
8297         uint8 j = 0;
8298
8299         p = party_search(script_getnum(st,2));
8300
8301         if (p != NULL) {
8302                 uint8 i, type = 0;
8303                 struct script_data *data = NULL;
8304                 char *varname = NULL;
8305
8306                 if (script_hasdata(st,3))
8307                         type = script_getnum(st,3);
8308
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;
8314                         }
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;
8319                         }
8320                 }
8321
8322                 for (i = 0; i < MAX_PARTY; i++) {
8323                         if (p->party.member[i].account_id) {
8324                                 switch (type) {
8325                                         case 2:
8326                                                 if (data)
8327                                                         setd_sub(st, NULL, varname, j, (void *)__64BPRTSIZE(p->party.member[i].account_id), data->ref);
8328                                                 else
8329                                                         mapreg_setreg(reference_uid(add_str("$@partymemberaid"), j),p->party.member[i].account_id);
8330                                                 break;
8331                                         case 1:
8332                                                 if (data)
8333                                                         setd_sub(st, NULL, varname, j, (void *)__64BPRTSIZE(p->party.member[i].char_id), data->ref);
8334                                                 else
8335                                                         mapreg_setreg(reference_uid(add_str("$@partymembercid"), j),p->party.member[i].char_id);
8336                                                 break;
8337                                         default:
8338                                                 if (data)
8339                                                         setd_sub(st, NULL, varname, j, (void *)__64BPRTSIZE(p->party.member[i].name), data->ref);
8340                                                 else
8341                                                         mapreg_setregstr(reference_uid(add_str("$@partymembername$"), j),p->party.member[i].name);
8342                                                 break;
8343                                 }
8344
8345                                 j++;
8346                         }
8347                 }
8348         }
8349
8350         mapreg_setreg(add_str("$@partymembercount"),j);
8351         script_pushint(st, j);
8352         return SCRIPT_CMD_SUCCESS;
8353 }
8354
8355 /*==========================================
8356  * Retrieves party leader. if flag is specified,
8357  * return some of the leader data. Otherwise, return name.
8358  *------------------------------------------*/
8359 BUILDIN_FUNC(getpartyleader)
8360 {
8361         int party_id, type = 0, i=0;
8362         struct party_data *p;
8363
8364         party_id=script_getnum(st,2);
8365         if( script_hasdata(st,3) )
8366                 type=script_getnum(st,3);
8367
8368         p=party_search(party_id);
8369
8370         if (p) //Search leader
8371         for(i = 0; i < MAX_PARTY && !p->party.member[i].leader; i++);
8372
8373         if (!p || i == MAX_PARTY) { //leader not found
8374                 if (type)
8375                         script_pushint(st,-1);
8376                 else
8377                         script_pushconststr(st,"null");
8378                 return SCRIPT_CMD_SUCCESS;
8379         }
8380
8381         switch (type) {
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;
8388         }
8389         return SCRIPT_CMD_SUCCESS;
8390 }
8391
8392 /*==========================================
8393  * Return the name of the @guild_id
8394  * null if not found
8395  *------------------------------------------*/
8396 BUILDIN_FUNC(getguildname)
8397 {
8398         int guild_id;
8399         struct guild* g;
8400
8401         guild_id = script_getnum(st,2);
8402         if( ( g = guild_search(guild_id) ) != NULL )
8403                 script_pushstrcopy(st,g->name);
8404         else 
8405                 script_pushconststr(st,"null");
8406         return SCRIPT_CMD_SUCCESS;
8407 }
8408
8409 /*==========================================
8410  * Return the name of the guild master of @guild_id
8411  * null if not found
8412  *------------------------------------------*/
8413 BUILDIN_FUNC(getguildmaster)
8414 {
8415         int guild_id;
8416         struct guild* g;
8417
8418         guild_id = script_getnum(st,2);
8419         if( ( g = guild_search(guild_id) ) != NULL )
8420                 script_pushstrcopy(st,g->member[0].name);
8421         else 
8422                 script_pushconststr(st,"null");
8423         return SCRIPT_CMD_SUCCESS;
8424 }
8425
8426 BUILDIN_FUNC(getguildmasterid)
8427 {
8428         int guild_id;
8429         struct guild* g;
8430
8431         guild_id = script_getnum(st,2);
8432         if( ( g = guild_search(guild_id) ) != NULL )
8433                 script_pushint(st,g->member[0].char_id);
8434         else
8435                 script_pushint(st,0);
8436         return SCRIPT_CMD_SUCCESS;
8437 }
8438
8439 /*==========================================
8440  * Get char string information by type :
8441  * Return by @type :
8442  *      0 : char_name
8443  *      1 : party_name or ""
8444  *      2 : guild_name or ""
8445  *      3 : map_name
8446  *      - : ""
8447  * strcharinfo(<type>{,<char_id>})
8448  *------------------------------------------*/
8449 BUILDIN_FUNC(strcharinfo)
8450 {
8451         TBL_PC *sd;
8452         int num;
8453         struct guild* g;
8454         struct party_data* p;
8455
8456         if (!script_charid2sd(3,sd)) {
8457                 script_pushconststr(st,"");
8458                 return SCRIPT_CMD_FAILURE;
8459         }
8460
8461         num=script_getnum(st,2);
8462         switch(num){
8463                 case 0:
8464                         script_pushstrcopy(st,sd->status.name);
8465                         break;
8466                 case 1:
8467                         if( ( p = party_search(sd->status.party_id) ) != NULL ) {
8468                                 script_pushstrcopy(st,p->party.name);
8469                         } else {
8470                                 script_pushconststr(st,"");
8471                         }
8472                         break;
8473                 case 2:
8474                         if( ( g = sd->guild ) != NULL ) {
8475                                 script_pushstrcopy(st,g->name);
8476                         } else {
8477                                 script_pushconststr(st,"");
8478                         }
8479                         break;
8480                 case 3:
8481                         script_pushconststr(st,map[sd->bl.m].name);
8482                         break;
8483                 default:
8484                         ShowWarning("buildin_strcharinfo: unknown parameter.\n");
8485                         script_pushconststr(st,"");
8486                         break;
8487         }
8488
8489         return SCRIPT_CMD_SUCCESS;
8490 }
8491
8492 /*==========================================
8493  * Get npc string information by type
8494  * return by @type:
8495  *      0 : name
8496  *      1 : str#
8497  *      2 : #str
8498  *      3 : ::str
8499  *      4 : map name
8500  *------------------------------------------*/
8501 BUILDIN_FUNC(strnpcinfo)
8502 {
8503         TBL_NPC* nd;
8504         int num;
8505         char *buf,*name=NULL;
8506
8507         nd = map_id2nd(st->oid);
8508         if (!nd) {
8509                 script_pushconststr(st, "");
8510                 return SCRIPT_CMD_SUCCESS;
8511         }
8512
8513         num = script_getnum(st,2);
8514         switch(num){
8515                 case 0: // display name
8516                         name = aStrdup(nd->name);
8517                         break;
8518                 case 1: // visible part of display name
8519                         if((buf = strchr(nd->name,'#')) != NULL)
8520                         {
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);
8525                         break;
8526                 case 2: // # fragment
8527                         if((buf = strchr(nd->name,'#')) != NULL)
8528                                 name = aStrdup(buf+1);
8529                         break;
8530                 case 3: // unique name
8531                         name = aStrdup(nd->exname);
8532                         break;
8533                 case 4: // map name
8534                         if (nd->bl.m >= 0)
8535                                 name = aStrdup(map[nd->bl.m].name);
8536                         break;
8537         }
8538
8539         if(name)
8540                 script_pushstr(st, name);
8541         else
8542                 script_pushconststr(st, "");
8543
8544         return SCRIPT_CMD_SUCCESS;
8545 }
8546
8547 /**
8548  * getequipid({<equipment slot>,<char_id>})
8549  **/
8550 BUILDIN_FUNC(getequipid)
8551 {
8552         int i, num;
8553         TBL_PC* sd;
8554
8555         if (!script_charid2sd(3, sd)) {
8556                 script_pushint(st,-1);
8557                 return SCRIPT_CMD_FAILURE;
8558         }
8559
8560         if (script_hasdata(st, 2))
8561                 num = script_getnum(st, 2);
8562         else
8563                 num = EQI_COMPOUND_ON;
8564
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]);
8569         else {
8570                 ShowError( "buildin_getequipid: Unknown equip index '%d'\n", num );
8571                 script_pushint(st,-1);
8572                 return SCRIPT_CMD_FAILURE;
8573         }
8574
8575         if (i >= 0 && i < MAX_INVENTORY && sd->inventory_data[i])
8576                 script_pushint(st, sd->inventory_data[i]->nameid);
8577         else
8578                 script_pushint(st, -1);
8579
8580         return SCRIPT_CMD_SUCCESS;
8581 }
8582
8583 /*==========================================
8584  * getequipuniqueid(<equipment slot>{,<char_id>})
8585  *------------------------------------------*/
8586 BUILDIN_FUNC(getequipuniqueid)
8587 {
8588         int i, num;
8589         TBL_PC* sd;
8590         struct item* item;
8591
8592         if (!script_charid2sd(3, sd)) {
8593                 script_pushconststr(st, "");
8594                 return SCRIPT_CMD_FAILURE;
8595         }
8596
8597         num = script_getnum(st,2);
8598         if ( !equip_index_check(num) ) {
8599                 script_pushconststr(st, "");
8600                 return SCRIPT_CMD_FAILURE;
8601         }
8602
8603         // get inventory position of item
8604         i = pc_checkequip(sd,equip_bitmask[num]);
8605         if (i < 0) {
8606                 script_pushconststr(st, "");
8607                 return SCRIPT_CMD_FAILURE;
8608         }
8609
8610         item = &sd->inventory.u.items_inventory[i];
8611         if (item != 0) {
8612                 int maxlen = 256;
8613                 char *buf = (char *)aMalloc(maxlen*sizeof(char));
8614
8615                 memset(buf, 0, maxlen);
8616                 snprintf(buf, maxlen-1, "%llu", (unsigned long long)item->unique_id);
8617
8618                 script_pushstr(st, buf);
8619         } else
8620                 script_pushconststr(st, "");
8621
8622         return SCRIPT_CMD_SUCCESS;
8623 }
8624
8625 /*==========================================
8626  * Get the equipement name at pos
8627  * return item jname or ""
8628  * getequipname(<equipment slot>{,<char_id>})
8629  *------------------------------------------*/
8630 BUILDIN_FUNC(getequipname)
8631 {
8632         int i, num;
8633         TBL_PC* sd;
8634         struct item_data* item;
8635
8636         if (!script_charid2sd(3, sd)) {
8637                 script_pushconststr(st, "");
8638                 return SCRIPT_CMD_FAILURE;
8639         }
8640
8641         num = script_getnum(st,2);
8642         if( !equip_index_check(num) )
8643         {
8644                 script_pushconststr(st,"");
8645                 return SCRIPT_CMD_SUCCESS;
8646         }
8647
8648         // get inventory position of item
8649         i = pc_checkequip(sd,equip_bitmask[num]);
8650         if( i < 0 )
8651         {
8652                 script_pushconststr(st,"");
8653                 return SCRIPT_CMD_SUCCESS;
8654         }
8655
8656         item = sd->inventory_data[i];
8657         if( item != 0 )
8658                 script_pushstrcopy(st,item->jname);
8659         else
8660                 script_pushconststr(st,"");
8661
8662         return SCRIPT_CMD_SUCCESS;
8663 }
8664
8665 /*==========================================
8666  * getbrokenid [Valaris]
8667  * getbrokenid(<number>{,<char_id>})
8668  *------------------------------------------*/
8669 BUILDIN_FUNC(getbrokenid)
8670 {
8671         int i,num,id = 0,brokencounter = 0;
8672         TBL_PC *sd;
8673
8674         if (!script_charid2sd(3, sd)) {
8675                 script_pushint(st,0);
8676                 return SCRIPT_CMD_FAILURE;
8677         }
8678
8679         num = script_getnum(st,2);
8680         for(i = 0; i < MAX_INVENTORY; i++) {
8681                 if(sd->inventory.u.items_inventory[i].attribute) {
8682                                 brokencounter++;
8683                                 if(num == brokencounter){
8684                                         id = sd->inventory.u.items_inventory[i].nameid;
8685                                         break;
8686                                 }
8687                 }
8688         }
8689
8690         script_pushint(st,id);
8691
8692         return SCRIPT_CMD_SUCCESS;
8693 }
8694
8695 /*==========================================
8696  * repair [Valaris]
8697  * repair <num>{,<char_id>};
8698  *------------------------------------------*/
8699 BUILDIN_FUNC(repair)
8700 {
8701         int i,num;
8702         int repaircounter = 0;
8703         TBL_PC *sd;
8704
8705         if (!script_charid2sd(3,sd))
8706                 return SCRIPT_CMD_FAILURE;
8707
8708         num = script_getnum(st,2);
8709         for(i = 0; i < MAX_INVENTORY; i++) {
8710                 if(sd->inventory.u.items_inventory[i].attribute) {
8711                                 repaircounter++;
8712                                 if(num == repaircounter) {
8713                                         sd->inventory.u.items_inventory[i].attribute = 0;
8714                                         clif_equiplist(sd);
8715                                         clif_produceeffect(sd, 0, sd->inventory.u.items_inventory[i].nameid);
8716                                         clif_misceffect(&sd->bl, 3);
8717                                         break;
8718                                 }
8719                 }
8720         }
8721
8722         return SCRIPT_CMD_SUCCESS;
8723 }
8724
8725 /*==========================================
8726  * repairall {<char_id>}
8727  *------------------------------------------*/
8728 BUILDIN_FUNC(repairall)
8729 {
8730         int i, repaircounter = 0;
8731         TBL_PC *sd;
8732
8733         if (!script_charid2sd(2,sd))
8734                 return SCRIPT_CMD_FAILURE;
8735
8736         for(i = 0; i < MAX_INVENTORY; i++)
8737         {
8738                 if(sd->inventory.u.items_inventory[i].nameid && sd->inventory.u.items_inventory[i].attribute)
8739                 {
8740                         sd->inventory.u.items_inventory[i].attribute = 0;
8741                         clif_produceeffect(sd,0,sd->inventory.u.items_inventory[i].nameid);
8742                         repaircounter++;
8743                 }
8744         }
8745
8746         if(repaircounter)
8747         {
8748                 clif_misceffect(&sd->bl, 3);
8749                 clif_equiplist(sd);
8750         }
8751
8752         return SCRIPT_CMD_SUCCESS;
8753 }
8754
8755 /*==========================================
8756  * Chk if player have something equiped at pos
8757  * getequipisequiped <pos>{,<char_id>}
8758  *------------------------------------------*/
8759 BUILDIN_FUNC(getequipisequiped)
8760 {
8761         int i = -1,num;
8762         TBL_PC *sd;
8763
8764         num = script_getnum(st,2);
8765
8766         if (!script_charid2sd(3,sd))
8767                 return SCRIPT_CMD_FAILURE;
8768
8769         if ( equip_index_check(num) )
8770                 i=pc_checkequip(sd,equip_bitmask[num]);
8771
8772         if(i >= 0)
8773                 script_pushint(st,1);
8774         else
8775                  script_pushint(st,0);
8776         return SCRIPT_CMD_SUCCESS;
8777 }
8778
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
8782  * return (npc)
8783  *      1 : true
8784  *      0 : false
8785  * getequipisenableref(<equipment slot>{,<char_id>})
8786  *------------------------------------------*/
8787 BUILDIN_FUNC(getequipisenableref)
8788 {
8789         int i = -1,num;
8790         TBL_PC *sd;
8791
8792         num = script_getnum(st,2);
8793
8794         if (!script_charid2sd(3, sd)) {
8795                 script_pushint(st,0);
8796                 return SCRIPT_CMD_FAILURE;
8797         }
8798
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);
8803         else
8804                 script_pushint(st,0);
8805
8806         return SCRIPT_CMD_SUCCESS;
8807 }
8808
8809 /*==========================================
8810  * Get the item refined value at pos
8811  * return (npc)
8812  *      x : refine amount
8813  *      0 : false (not refined)
8814  * getequiprefinerycnt(<equipment slot>{,<char_id>})
8815  *------------------------------------------*/
8816 BUILDIN_FUNC(getequiprefinerycnt)
8817 {
8818         int i = -1,num;
8819         TBL_PC *sd;
8820
8821         num = script_getnum(st,2);
8822
8823         if (!script_charid2sd(3, sd)) {
8824                 script_pushint(st,0);
8825                 return SCRIPT_CMD_FAILURE;
8826         }
8827
8828         if (equip_index_check(num))
8829                 i=pc_checkequip(sd,equip_bitmask[num]);
8830         if(i >= 0)
8831                 script_pushint(st,sd->inventory.u.items_inventory[i].refine);
8832         else
8833                 script_pushint(st,0);
8834
8835         return SCRIPT_CMD_SUCCESS;
8836 }
8837
8838 /*==========================================
8839  * Get the weapon level value at pos
8840  * (pos should normally only be EQI_HAND_L or EQI_HAND_R)
8841  * return (npc)
8842  *      x : weapon level
8843  *      0 : false
8844  * getequipweaponlv(<equipment slot>{,<char_id>})
8845  *------------------------------------------*/
8846 BUILDIN_FUNC(getequipweaponlv)
8847 {
8848         int i = -1, num;
8849         TBL_PC *sd;
8850
8851         num = script_getnum(st, 2);
8852
8853         if (!script_charid2sd(3, sd)) {
8854                 script_pushint(st, 0);
8855                 return SCRIPT_CMD_FAILURE;
8856         }
8857
8858         if (num == -1){
8859                 if( current_equip_item_index == -1 ){
8860                         script_pushint(st, 0);
8861                         return SCRIPT_CMD_FAILURE;
8862                 }
8863
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);
8869         else
8870                 script_pushint(st, 0);
8871
8872         return SCRIPT_CMD_SUCCESS;
8873 }
8874
8875 /*==========================================
8876  * Get the item refine chance (from refine.txt) for item at pos
8877  * return (npc)
8878  *      x : refine chance
8879  *      0 : false (max refine level or unequip..)
8880  * getequippercentrefinery(<equipment slot>{,<enriched>,<char_id>})
8881  *------------------------------------------*/
8882 BUILDIN_FUNC(getequippercentrefinery)
8883 {
8884         int i = -1,num;
8885         bool enriched = false;
8886         TBL_PC *sd;
8887
8888         num = script_getnum(st,2);
8889         if (script_hasdata(st, 3))
8890                 enriched = script_getnum(st, 3) != 0;
8891
8892         if (!script_charid2sd(4, sd)) {
8893                 script_pushint(st,0);
8894                 return SCRIPT_CMD_FAILURE;
8895         }
8896
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));
8904         }
8905         else
8906                 script_pushint(st,0);
8907
8908         return SCRIPT_CMD_SUCCESS;
8909 }
8910
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;
8917         int pos;
8918         TBL_PC *sd;
8919
8920         pos = script_getnum(st,2);
8921
8922         if (!script_charid2sd(4, sd)) {
8923                 script_pushint(st, -1);
8924                 return SCRIPT_CMD_FAILURE;
8925         }
8926
8927         if (script_hasdata(st, 3))
8928                 up = script_getnum(st, 3);
8929
8930         if (equip_index_check(pos))
8931                 i = pc_checkequip(sd,equip_bitmask[pos]);
8932         if (i >= 0) {
8933                 unsigned int ep = sd->inventory.u.items_inventory[i].equip;
8934
8935                 //Logs items, got from (N)PC scripts [Lupus]
8936                 log_pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->inventory.u.items_inventory[i]);
8937
8938                 if (sd->inventory.u.items_inventory[i].refine >= MAX_REFINE) {
8939                         script_pushint(st, MAX_REFINE);
8940                         return SCRIPT_CMD_SUCCESS;
8941                 }
8942
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
8946
8947                 clif_refine(sd->fd,0,i,sd->inventory.u.items_inventory[i].refine);
8948                 clif_delitem(sd,i,1,3);
8949
8950                 //Logs items, got from (N)PC scripts [Lupus]
8951                 log_pick_pc(sd, LOG_TYPE_SCRIPT, 1, &sd->inventory.u.items_inventory[i]);
8952
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){
8962                                 case 1:
8963                                         pc_addfame(sd, battle_config.fame_refine_lv1); // Success to refine to +10 a lv1 weapon you forged = +1 fame point
8964                                         break;
8965                                 case 2:
8966                                         pc_addfame(sd, battle_config.fame_refine_lv2); // Success to refine to +10 a lv2 weapon you forged = +25 fame point
8967                                         break;
8968                                 case 3:
8969                                         pc_addfame(sd, battle_config.fame_refine_lv3); // Success to refine to +10 a lv3 weapon you forged = +1000 fame point
8970                                         break;
8971                          }
8972                 }
8973                 script_pushint(st, sd->inventory.u.items_inventory[i].refine);
8974                 return SCRIPT_CMD_SUCCESS;
8975         }
8976
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;
8980 }
8981
8982 /*==========================================
8983  * Show a failed Refine +1 attempt
8984  * failedrefitem <equipment slot>{,<char_id>}
8985  *------------------------------------------*/
8986 BUILDIN_FUNC(failedrefitem) {
8987         short i = -1;
8988         int pos;
8989         TBL_PC *sd;
8990
8991         pos = script_getnum(st,2);
8992
8993         if (!script_charid2sd(3, sd)) {
8994                 script_pushint(st, 0);
8995                 return SCRIPT_CMD_FAILURE;
8996         }
8997
8998         if (equip_index_check(pos))
8999                 i = pc_checkequip(sd,equip_bitmask[pos]);
9000         if (i >= 0) {
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;
9009         }
9010
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;
9014 }
9015
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;
9022         int pos;
9023         TBL_PC *sd;
9024
9025         if (!script_charid2sd(4, sd)) {
9026                 script_pushint(st, -1);
9027                 return SCRIPT_CMD_FAILURE;
9028         }
9029
9030         pos = script_getnum(st,2);
9031         if (script_hasdata(st, 3))
9032                 down = script_getnum(st, 3);
9033
9034         if (equip_index_check(pos))
9035                 i = pc_checkequip(sd,equip_bitmask[pos]);
9036         if (i >= 0) {
9037                 unsigned int ep = sd->inventory.u.items_inventory[i].equip;
9038
9039                 //Logs items, got from (N)PC scripts [Lupus]
9040                 log_pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->inventory.u.items_inventory[i]);
9041
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);
9045
9046                 clif_refine(sd->fd,2,i,sd->inventory.u.items_inventory[i].refine);
9047                 clif_delitem(sd,i,1,3);
9048
9049                 //Logs items, got from (N)PC scripts [Lupus]
9050                 log_pick_pc(sd, LOG_TYPE_SCRIPT, 1, &sd->inventory.u.items_inventory[i]);
9051
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;
9058         }
9059
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;
9063 }
9064
9065 /**
9066  * Delete the item equipped at pos.
9067  * delequip <equipment slot>{,<char_id>};
9068  **/
9069 BUILDIN_FUNC(delequip) {
9070         short i = -1;
9071         int pos;
9072         int8 ret;
9073         TBL_PC *sd;
9074
9075         pos = script_getnum(st,2);
9076         if (!script_charid2sd(3,sd)) {
9077                 st->state = END;
9078                 return SCRIPT_CMD_FAILURE;
9079         }
9080
9081         if (equip_index_check(pos))
9082                 i = pc_checkequip(sd,equip_bitmask[pos]);
9083         if (i >= 0) {
9084                 pc_unequipitem(sd,i,3); //recalculate bonus
9085                 ret = !(pc_delitem(sd,i,1,0,2,LOG_TYPE_SCRIPT));
9086         }
9087         else {
9088                 ShowError("buildin_delequip: No item equipped at pos %d (CID=%d/AID=%d).\n", pos, sd->status.char_id, sd->status.account_id);
9089                 st->state = END;
9090                 return SCRIPT_CMD_FAILURE;
9091         }
9092
9093         script_pushint(st,ret);
9094         return SCRIPT_CMD_SUCCESS;
9095 }
9096
9097 /**
9098  * Break the item equipped at pos.
9099  * breakequip <equipment slot>{,<char_id>};
9100  **/
9101 BUILDIN_FUNC(breakequip) {
9102         short i = -1;
9103         int pos;
9104         TBL_PC *sd;
9105
9106         pos = script_getnum(st,2);
9107         if (!script_charid2sd(3,sd))
9108                 return SCRIPT_CMD_FAILURE;
9109
9110         if (equip_index_check(pos))
9111                 i = pc_checkequip(sd,equip_bitmask[pos]);
9112         if (i >= 0) {
9113                 sd->inventory.u.items_inventory[i].attribute = 1;
9114                 pc_unequipitem(sd,i,3);
9115                 clif_equiplist(sd);
9116                 script_pushint(st,1);
9117                 return SCRIPT_CMD_SUCCESS;
9118         }
9119
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;
9123 }
9124
9125 /**
9126  * statusup <stat>{,<char_id>};
9127  **/
9128 BUILDIN_FUNC(statusup)
9129 {
9130         int type;
9131         TBL_PC *sd;
9132
9133         type = script_getnum(st,2);
9134
9135         if (!script_charid2sd(3, sd))
9136                 return SCRIPT_CMD_FAILURE;
9137
9138         pc_statusup(sd, type, 1);
9139
9140         return SCRIPT_CMD_SUCCESS;
9141 }
9142
9143 /**
9144  * statusup2 <stat>,<amount>{,<char_id>};
9145  **/
9146 BUILDIN_FUNC(statusup2)
9147 {
9148         int type,val;
9149         TBL_PC *sd;
9150
9151         type=script_getnum(st,2);
9152         val=script_getnum(st,3);
9153
9154         if (!script_charid2sd(4, sd))
9155                 return SCRIPT_CMD_FAILURE;
9156
9157         pc_statusup2(sd,type,val);
9158
9159         return SCRIPT_CMD_SUCCESS;
9160 }
9161
9162 /// See 'doc/item_bonus.txt'
9163 ///
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>;
9169 BUILDIN_FUNC(bonus)
9170 {
9171         int type;
9172         int val1;
9173         int val2 = 0;
9174         int val3 = 0;
9175         int val4 = 0;
9176         int val5 = 0;
9177         TBL_PC* sd;
9178         struct script_data *data;
9179
9180         if( !script_rid2sd(sd) )
9181                 return SCRIPT_CMD_SUCCESS; // no player attached
9182
9183         type = script_getnum(st,2);
9184         switch( type ) {
9185                 case SP_AUTOSPELL:
9186                 case SP_AUTOSPELL_WHENHIT:
9187                 case SP_AUTOSPELL_ONSKILL:
9188                 case SP_SKILL_ATK:
9189                 case SP_SKILL_HEAL:
9190                 case SP_SKILL_HEAL2:
9191                 case SP_ADD_SKILL_BLOW:
9192                 case SP_CASTRATE:
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:
9201                 case SP_SUB_SKILL:
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) );
9206                         break;
9207                 default:
9208                         val1 = script_getnum(st,3);
9209                         break;
9210         }
9211
9212         switch( script_lastdata(st)-2 ) {
9213                 case 1:
9214                         pc_bonus(sd, type, val1);
9215                         break;
9216                 case 2:
9217                         val2 = script_getnum(st,4);
9218                         pc_bonus2(sd, type, val1, val2);
9219                         break;
9220                 case 3:
9221                         val2 = script_getnum(st,4);
9222                         val3 = script_getnum(st,5);
9223                         pc_bonus3(sd, type, val1, val2, val3);
9224                         break;
9225                 case 4:
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
9230                         else
9231                                 val2 = script_getnum(st,4);
9232
9233                         val3 = script_getnum(st,5);
9234                         val4 = script_getnum(st,6);
9235                         pc_bonus4(sd, type, val1, val2, val3, val4);
9236                         break;
9237                 case 5:
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
9242                         else
9243                                 val2 = script_getnum(st,4);
9244
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);
9249                         break;
9250                 default:
9251                         ShowDebug("buildin_bonus: unexpected number of arguments (%d)\n", (script_lastdata(st) - 1));
9252                         break;
9253         }
9254
9255         return SCRIPT_CMD_SUCCESS;
9256 }
9257
9258 BUILDIN_FUNC(autobonus)
9259 {
9260         unsigned int dur, pos;
9261         short rate;
9262         short atk_type = 0;
9263         TBL_PC* sd;
9264         const char *bonus_script, *other_script = NULL;
9265
9266         if( !script_rid2sd(sd) )
9267                 return SCRIPT_CMD_SUCCESS; // no player attached
9268
9269         if (current_equip_combo_pos)
9270                 pos = current_equip_combo_pos;
9271         else
9272                 pos = sd->inventory.u.items_inventory[current_equip_item_index].equip;
9273
9274         if((sd->state.autobonus&pos) == pos)
9275                 return SCRIPT_CMD_SUCCESS;
9276
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;
9282
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);
9287
9288         if( pc_addautobonus(sd->autobonus,ARRAYLENGTH(sd->autobonus),
9289                 bonus_script,rate,dur,atk_type,other_script,pos,false) )
9290         {
9291                 script_add_autobonus(bonus_script);
9292                 if( other_script )
9293                         script_add_autobonus(other_script);
9294         }
9295
9296         return SCRIPT_CMD_SUCCESS;
9297 }
9298
9299 BUILDIN_FUNC(autobonus2)
9300 {
9301         unsigned int dur, pos;
9302         short rate;
9303         short atk_type = 0;
9304         TBL_PC* sd;
9305         const char *bonus_script, *other_script = NULL;
9306
9307         if( !script_rid2sd(sd) )
9308                 return SCRIPT_CMD_SUCCESS; // no player attached
9309
9310         if (current_equip_combo_pos)
9311                 pos = current_equip_combo_pos;
9312         else
9313                 pos = sd->inventory.u.items_inventory[current_equip_item_index].equip;
9314
9315         if((sd->state.autobonus&pos) == pos)
9316                 return SCRIPT_CMD_SUCCESS;
9317
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;
9323
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);
9328
9329         if( pc_addautobonus(sd->autobonus2,ARRAYLENGTH(sd->autobonus2),
9330                 bonus_script,rate,dur,atk_type,other_script,pos,false) )
9331         {
9332                 script_add_autobonus(bonus_script);
9333                 if( other_script )
9334                         script_add_autobonus(other_script);
9335         }
9336
9337         return SCRIPT_CMD_SUCCESS;
9338 }
9339
9340 BUILDIN_FUNC(autobonus3)
9341 {
9342         unsigned int dur, pos;
9343         short rate,atk_type;
9344         TBL_PC* sd;
9345         const char *bonus_script, *other_script = NULL;
9346         struct script_data *data;
9347
9348         if( !script_rid2sd(sd) )
9349                 return SCRIPT_CMD_SUCCESS; // no player attached
9350
9351         if (current_equip_combo_pos)
9352                 pos = current_equip_combo_pos;
9353         else
9354                 pos = sd->inventory.u.items_inventory[current_equip_item_index].equip;
9355
9356         if((sd->state.autobonus&pos) == pos)
9357                 return SCRIPT_CMD_SUCCESS;
9358
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;
9367
9368         if( script_hasdata(st,6) )
9369                 other_script = script_getstr(st,6);
9370
9371         if( pc_addautobonus(sd->autobonus3,ARRAYLENGTH(sd->autobonus3),
9372                 bonus_script,rate,dur,atk_type,other_script,pos,true) )
9373         {
9374                 script_add_autobonus(bonus_script);
9375                 if( other_script )
9376                         script_add_autobonus(other_script);
9377         }
9378
9379         return SCRIPT_CMD_SUCCESS;
9380 }
9381
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
9387 ///
9388 /// skill <skill id>,<level>,<flag>
9389 /// skill <skill id>,<level>
9390 /// skill "<skill name>",<level>,<flag>
9391 /// skill "<skill name>",<level>
9392 BUILDIN_FUNC(skill)
9393 {
9394         int id;
9395         int level;
9396         int flag = ADDSKILL_TEMP;
9397         TBL_PC* sd;
9398         struct script_data *data;
9399         const char* command = script_getfuncname(st);
9400
9401         if( !script_rid2sd(sd) )
9402                 return SCRIPT_CMD_SUCCESS;// no player attached, report source
9403
9404         if (strcmpi(command, "addtoskill") == 0)
9405                 flag = ADDSKILL_TEMP_ADDLEVEL;
9406
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);
9414
9415         return SCRIPT_CMD_SUCCESS;
9416 }
9417
9418 /// Increases the level of a guild skill.
9419 ///
9420 /// guildskill <skill id>,<amount>;
9421 /// guildskill "<skill name>",<amount>;
9422 BUILDIN_FUNC(guildskill)
9423 {
9424         int id;
9425         int level;
9426         TBL_PC* sd;
9427         int i;
9428         struct script_data *data;
9429
9430         if( !script_rid2sd(sd) )
9431                 return SCRIPT_CMD_SUCCESS;// no player attached, report source
9432
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);
9439
9440         return SCRIPT_CMD_SUCCESS;
9441 }
9442
9443 /// Returns the level of the player skill.
9444 ///
9445 /// getskilllv(<skill id>) -> <level>
9446 /// getskilllv("<skill name>") -> <level>
9447 BUILDIN_FUNC(getskilllv)
9448 {
9449         int id;
9450         TBL_PC* sd;
9451         struct script_data *data;
9452
9453         if( !script_rid2sd(sd) )
9454                 return SCRIPT_CMD_SUCCESS;// no player attached, report source
9455
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));
9460
9461         return SCRIPT_CMD_SUCCESS;
9462 }
9463
9464 /// Returns the level of the guild skill.
9465 ///
9466 /// getgdskilllv(<guild id>,<skill id>) -> <level>
9467 /// getgdskilllv(<guild id>,"<skill name>") -> <level>
9468 BUILDIN_FUNC(getgdskilllv)
9469 {
9470         int guild_id;
9471         uint16 skill_id;
9472         struct guild* g;
9473         struct script_data *data;
9474
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);
9480         if( g == NULL )
9481                 script_pushint(st, -1);
9482         else
9483                 script_pushint(st, guild_checkskill(g,skill_id));
9484
9485         return SCRIPT_CMD_SUCCESS;
9486 }
9487
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.
9491 ///
9492 /// basicskillcheck() -> <bool>
9493 BUILDIN_FUNC(basicskillcheck)
9494 {
9495         script_pushint(st, battle_config.basic_skill_check);
9496         return SCRIPT_CMD_SUCCESS;
9497 }
9498
9499 /// Returns the GM level of the player.
9500 ///
9501 /// getgmlevel({<char_id>}) -> <level>
9502 BUILDIN_FUNC(getgmlevel)
9503 {
9504         TBL_PC* sd;
9505
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;
9510 }
9511
9512 /// Returns the group ID of the player.
9513 ///
9514 /// getgroupid({<char_id>}) -> <int>
9515 BUILDIN_FUNC(getgroupid)
9516 {
9517         TBL_PC* sd;
9518
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;
9523 }
9524
9525 /// Terminates the execution of this script instance.
9526 ///
9527 /// end
9528 BUILDIN_FUNC(end)
9529 {
9530         TBL_PC* sd;
9531
9532         sd = map_id2sd(st->rid);
9533
9534         st->state = END;
9535
9536         if (st->stack->defsp >= 1 && st->stack->stack_data[st->stack->defsp-1].type == C_RETINFO) {
9537                 int i;
9538
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;
9543                                 break;
9544                         }
9545                 }
9546         }
9547
9548         if( st->mes_active )
9549                 st->mes_active = 0;
9550
9551         if (sd){
9552                 if (sd->state.callshop == 0)
9553                         clif_scriptclose(sd, st->oid); // If a menu/select/prompt is active, close it.
9554                 else 
9555                         sd->state.callshop = 0;
9556         }
9557
9558         return SCRIPT_CMD_SUCCESS;
9559 }
9560
9561 /// Checks if the player has that effect state (option).
9562 ///
9563 /// checkoption(<option>{,<char_id>}) -> <bool>
9564 BUILDIN_FUNC(checkoption)
9565 {
9566         int option;
9567         TBL_PC* sd;
9568
9569         if (!script_charid2sd(3,sd))
9570                 return SCRIPT_CMD_FAILURE;
9571
9572         option = script_getnum(st,2);
9573         if( sd->sc.option&option )
9574                 script_pushint(st, 1);
9575         else
9576                 script_pushint(st, 0);
9577
9578         return SCRIPT_CMD_SUCCESS;
9579 }
9580
9581 /// Checks if the player is in that body state (opt1).
9582 ///
9583 /// checkoption1(<opt1>{,<char_id>}) -> <bool>
9584 BUILDIN_FUNC(checkoption1)
9585 {
9586         int opt1;
9587         TBL_PC* sd;
9588
9589         if (!script_charid2sd(3,sd))
9590                 return SCRIPT_CMD_FAILURE;
9591
9592         opt1 = script_getnum(st,2);
9593         if( sd->sc.opt1 == opt1 )
9594                 script_pushint(st, 1);
9595         else
9596                 script_pushint(st, 0);
9597
9598         return SCRIPT_CMD_SUCCESS;
9599 }
9600
9601 /// Checks if the player has that health state (opt2).
9602 ///
9603 /// checkoption2(<opt2>{,<char_id>}) -> <bool>
9604 BUILDIN_FUNC(checkoption2)
9605 {
9606         int opt2;
9607         TBL_PC* sd;
9608
9609         if (!script_charid2sd(3,sd))
9610                 return SCRIPT_CMD_FAILURE;
9611
9612         opt2 = script_getnum(st,2);
9613         if( sd->sc.opt2&opt2 )
9614                 script_pushint(st, 1);
9615         else
9616                 script_pushint(st, 0);
9617
9618         return SCRIPT_CMD_SUCCESS;
9619 }
9620
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
9625 ///
9626 /// setoption <option>{,<flag>{,<char_id>}};
9627 BUILDIN_FUNC(setoption)
9628 {
9629         int option;
9630         int flag = 1;
9631         TBL_PC* sd;
9632
9633         if (!script_charid2sd(4,sd))
9634                 return SCRIPT_CMD_FAILURE;
9635
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.
9640                 flag = 0;
9641                 option = OPTION_FALCON|OPTION_RIDING;
9642 #ifndef NEW_CARTS
9643                 option |= OPTION_CART;
9644 #endif
9645         }
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);
9652
9653         return SCRIPT_CMD_SUCCESS;
9654 }
9655
9656 /// Returns if the player has a cart.
9657 ///
9658 /// checkcart({char_id}) -> <bool>
9659 ///
9660 /// @author Valaris
9661 BUILDIN_FUNC(checkcart)
9662 {
9663         TBL_PC* sd;
9664
9665         if (!script_charid2sd(2,sd))
9666                 return SCRIPT_CMD_FAILURE;
9667
9668         if( pc_iscarton(sd) )
9669                 script_pushint(st, 1);
9670         else
9671                 script_pushint(st, 0);
9672
9673         return SCRIPT_CMD_SUCCESS;
9674 }
9675
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
9684 ///
9685 /// setcart {<type>{,<char_id>}};
9686 BUILDIN_FUNC(setcart)
9687 {
9688         int type = 1;
9689         TBL_PC* sd;
9690
9691         if (!script_charid2sd(3,sd))
9692                 return SCRIPT_CMD_FAILURE;
9693
9694         if( script_hasdata(st,2) )
9695                 type = script_getnum(st,2);
9696         pc_setcart(sd, type);
9697
9698         return SCRIPT_CMD_SUCCESS;
9699 }
9700
9701 /// Returns if the player has a falcon.
9702 ///
9703 /// checkfalcon({char_id}) -> <bool>
9704 ///
9705 /// @author Valaris
9706 BUILDIN_FUNC(checkfalcon)
9707 {
9708         TBL_PC* sd;
9709
9710         if (!script_charid2sd(2,sd))
9711                 return SCRIPT_CMD_FAILURE;
9712
9713         if( pc_isfalcon(sd) )
9714                 script_pushint(st, 1);
9715         else
9716                 script_pushint(st, 0);
9717
9718         return SCRIPT_CMD_SUCCESS;
9719 }
9720
9721 /// Sets if the player has a falcon or not.
9722 /// <flag> defaults to 1
9723 ///
9724 /// setfalcon {<flag>{,<char_id>}};
9725 BUILDIN_FUNC(setfalcon)
9726 {
9727         int flag = 1;
9728         TBL_PC* sd;
9729
9730         if (!script_charid2sd(3,sd))
9731                 return SCRIPT_CMD_FAILURE;
9732
9733         if( script_hasdata(st,2) )
9734                 flag = script_getnum(st,2);
9735
9736         pc_setfalcon(sd, flag);
9737
9738         return SCRIPT_CMD_SUCCESS;
9739 }
9740
9741 /// Returns if the player is riding.
9742 ///
9743 /// checkriding({char_id}) -> <bool>
9744 ///
9745 /// @author Valaris
9746 BUILDIN_FUNC(checkriding)
9747 {
9748         TBL_PC* sd;
9749
9750         if (!script_charid2sd(2,sd))
9751                 return SCRIPT_CMD_FAILURE;
9752
9753         if( pc_isriding(sd) )
9754                 script_pushint(st, 1);
9755         else
9756                 script_pushint(st, 0);
9757
9758         return SCRIPT_CMD_SUCCESS;
9759 }
9760
9761 /// Sets if the player is riding.
9762 /// <flag> defaults to 1
9763 ///
9764 /// setriding {<flag>{,<char_id>}};
9765 BUILDIN_FUNC(setriding)
9766 {
9767         int flag = 1;
9768         TBL_PC* sd;
9769
9770         if (!script_charid2sd(3,sd))
9771                 return SCRIPT_CMD_FAILURE;
9772
9773         if( script_hasdata(st,2) )
9774                 flag = script_getnum(st,2);
9775         pc_setriding(sd, flag);
9776
9777         return SCRIPT_CMD_SUCCESS;
9778 }
9779
9780 /// Returns if the player has a warg.
9781 ///
9782 /// checkwug({char_id}) -> <bool>
9783 ///
9784 BUILDIN_FUNC(checkwug)
9785 {
9786         TBL_PC* sd;
9787
9788         if (!script_charid2sd(2,sd))
9789                 return SCRIPT_CMD_FAILURE;
9790
9791         if( pc_iswug(sd) || pc_isridingwug(sd) )
9792                 script_pushint(st, 1);
9793         else
9794                 script_pushint(st, 0);
9795
9796         return SCRIPT_CMD_SUCCESS;
9797 }
9798
9799 /// Returns if the player is wearing MADO Gear.
9800 ///
9801 /// checkmadogear({<char_id>}) -> <bool>
9802 ///
9803 BUILDIN_FUNC(checkmadogear)
9804 {
9805         TBL_PC* sd;
9806
9807         if (!script_charid2sd(2,sd))
9808                 return SCRIPT_CMD_FAILURE;
9809
9810         if( pc_ismadogear(sd) )
9811                 script_pushint(st, 1);
9812         else
9813                 script_pushint(st, 0);
9814
9815         return SCRIPT_CMD_SUCCESS;
9816 }
9817
9818 /// Sets if the player is riding MADO Gear.
9819 /// <flag> defaults to 1
9820 ///
9821 /// setmadogear {<flag>{,<char_id>}};
9822 BUILDIN_FUNC(setmadogear)
9823 {
9824         int flag = 1;
9825         TBL_PC* sd;
9826
9827         if (!script_charid2sd(3,sd))
9828                 return SCRIPT_CMD_FAILURE;
9829
9830         if( script_hasdata(st,2) )
9831                 flag = script_getnum(st,2);
9832         pc_setmadogear(sd, flag);
9833
9834         return SCRIPT_CMD_SUCCESS;
9835 }
9836
9837 /// Sets the save point of the player.
9838 ///
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)
9842 {
9843         int x, y, m, cid_pos = 5;
9844         unsigned short map_idx;
9845         const char* str;
9846         TBL_PC* sd;
9847
9848         if (script_lastdata(st) > 5)
9849                 cid_pos = 7;
9850
9851         if (!script_charid2sd(cid_pos,sd))
9852                 return SCRIPT_CMD_FAILURE;// no player attached, report source
9853
9854         str = script_getstr(st, 2);
9855
9856         map_idx = mapindex_name2id(str);
9857         if( !map_idx )
9858                 return SCRIPT_CMD_FAILURE;
9859
9860         x = script_getnum(st,3);
9861         y = script_getnum(st,4);
9862         m = map_mapindex2mapid(map_idx);
9863
9864         if (cid_pos == 7) {
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;
9868                 uint8 n = 10;
9869                 do {
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));
9873         }
9874
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;
9879         }
9880
9881         pc_setsavepoint(sd, map_idx, x, y);
9882
9883         return SCRIPT_CMD_SUCCESS;
9884 }
9885
9886 /*==========================================
9887  * GetTimeTick(0: System Tick, 1: Time Second Tick, 2: Unix epoch)
9888  *------------------------------------------*/
9889 BUILDIN_FUNC(gettimetick)       /* Asgard Version */
9890 {
9891         int type;
9892         time_t timer;
9893         struct tm *t;
9894
9895         type=script_getnum(st,2);
9896
9897         switch(type){
9898         case 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));
9902                 break;
9903         case 1:
9904                 //type 1:(Second Ticks: 0-86399, 00:00:00-23:59:59)
9905                 time(&timer);
9906                 t=localtime(&timer);
9907                 script_pushint(st,((t->tm_hour)*3600+(t->tm_min)*60+t->tm_sec));
9908                 break;
9909         case 0:
9910         default:
9911                 //type 0:(System Ticks)
9912                 script_pushint(st,gettick());
9913                 break;
9914         }
9915         return SCRIPT_CMD_SUCCESS;
9916 }
9917
9918 /*==========================================
9919  * GetTime(Type)
9920  *
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
9931  *
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)
9936 {
9937         int type;
9938
9939         type = script_getnum(st,2);
9940
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);
9945         }else{
9946                 script_pushint(st,date_get((enum e_date_type)type));
9947         }
9948
9949         return SCRIPT_CMD_SUCCESS;
9950 }
9951
9952 /**
9953  * Returns the current server time or the provided time in a readable format.
9954  * gettimestr(<"time_format">,<max_length>{,<time_tick>});
9955  */
9956 BUILDIN_FUNC(gettimestr)
9957 {
9958         char *tmpstr;
9959         const char *fmtstr;
9960         int maxlen;
9961         time_t now;
9962
9963         fmtstr = script_getstr(st,2);
9964         maxlen = script_getnum(st,3);
9965
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;
9970                 } else
9971                         now = (time_t)script_getnum(st, 4);
9972         } else
9973                 now = time(NULL);
9974
9975         tmpstr = (char *)aMalloc((maxlen+1)*sizeof(char));
9976         strftime(tmpstr,maxlen,fmtstr,localtime(&now));
9977         tmpstr[maxlen] = '\0';
9978
9979         script_pushstr(st,tmpstr);
9980         return SCRIPT_CMD_SUCCESS;
9981 }
9982
9983 /*==========================================
9984  * Open player storage
9985  *------------------------------------------*/
9986 BUILDIN_FUNC(openstorage)
9987 {
9988         TBL_PC* sd;
9989
9990         if( !script_rid2sd(sd) )
9991                 return SCRIPT_CMD_SUCCESS;
9992
9993         storage_storageopen(sd);
9994         return SCRIPT_CMD_SUCCESS;
9995 }
9996
9997 BUILDIN_FUNC(guildopenstorage)
9998 {
9999         TBL_PC* sd;
10000         int ret;
10001
10002         if( !script_rid2sd(sd) )
10003                 return SCRIPT_CMD_SUCCESS;
10004
10005         ret = storage_guild_storageopen(sd);
10006         script_pushint(st,ret);
10007         return SCRIPT_CMD_SUCCESS;
10008 }
10009
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)
10016 {
10017         int id;
10018         int lv;
10019         bool keep_requirement;
10020         TBL_PC* sd;
10021         struct script_data *data;
10022
10023         if( !script_rid2sd(sd) || sd->ud.skilltimer != INVALID_TIMER )
10024                 return SCRIPT_CMD_SUCCESS;
10025
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);
10032         } else {
10033                 keep_requirement = false;
10034         }
10035
10036         sd->skillitem=id;
10037         sd->skillitemlv=lv;
10038         sd->skillitem_keep_requirement = keep_requirement;
10039         clif_item_skill(sd,id,lv);
10040         return SCRIPT_CMD_SUCCESS;
10041 }
10042 /*==========================================
10043  * Attempt to create an item
10044  *------------------------------------------*/
10045 BUILDIN_FUNC(produce)
10046 {
10047         int trigger;
10048         TBL_PC* sd;
10049
10050         if( !script_rid2sd(sd) )
10051                 return SCRIPT_CMD_SUCCESS;
10052
10053         trigger=script_getnum(st,2);
10054         clif_skill_produce_mix_list(sd, -1, trigger);
10055         return SCRIPT_CMD_SUCCESS;
10056 }
10057 /*==========================================
10058  *
10059  *------------------------------------------*/
10060 BUILDIN_FUNC(cooking)
10061 {
10062         int trigger;
10063         TBL_PC* sd;
10064
10065         if( !script_rid2sd(sd) )
10066                 return SCRIPT_CMD_SUCCESS;
10067
10068         trigger=script_getnum(st,2);
10069         clif_cooking_list(sd, trigger, AM_PHARMACY, 1, 1);
10070         return SCRIPT_CMD_SUCCESS;
10071 }
10072
10073 /*==========================================
10074  * Create a pet
10075  *------------------------------------------*/
10076 BUILDIN_FUNC(makepet)
10077 {
10078         TBL_PC* sd;
10079         int id,pet_id;
10080
10081         if( !script_rid2sd(sd) )
10082                 return SCRIPT_CMD_SUCCESS;
10083
10084         id=script_getnum(st,2);
10085
10086         pet_id = search_petDB_index(id, PET_CLASS);
10087
10088         if (pet_id < 0)
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);
10093         }
10094
10095         return SCRIPT_CMD_SUCCESS;
10096 }
10097
10098 /**
10099  * Give player exp base,job * quest_exp_rate/100
10100  * getexp <base xp>,<job xp>{,<char_id>};
10101  **/
10102 BUILDIN_FUNC(getexp)
10103 {
10104         TBL_PC* sd;
10105         int base=0,job=0;
10106         double bonus;
10107
10108         if (!script_charid2sd(4,sd))
10109                 return SCRIPT_CMD_FAILURE;
10110
10111         base=script_getnum(st,2);
10112         job =script_getnum(st,3);
10113         if(base<0 || job<0)
10114                 return SCRIPT_CMD_SUCCESS;
10115
10116         // bonus for npc-given exp
10117         bonus = battle_config.quest_exp_rate / 100.;
10118         if (base)
10119                 base = (int) cap_value(base * bonus, 0, INT_MAX);
10120         if (job)
10121                 job = (int) cap_value(job * bonus, 0, INT_MAX);
10122
10123         pc_gainexp(sd, NULL, base, job, 1);
10124
10125         return SCRIPT_CMD_SUCCESS;
10126 }
10127
10128 /*==========================================
10129  * Gain guild exp [Celest]
10130  *------------------------------------------*/
10131 BUILDIN_FUNC(guildgetexp)
10132 {
10133         TBL_PC* sd;
10134         int exp;
10135
10136         if( !script_rid2sd(sd) )
10137                 return SCRIPT_CMD_SUCCESS;
10138
10139         exp = script_getnum(st,2);
10140         if(exp < 0)
10141                 return SCRIPT_CMD_SUCCESS;
10142         if(sd && sd->status.guild_id > 0)
10143                 guild_getexp (sd, exp);
10144
10145         return SCRIPT_CMD_SUCCESS;
10146 }
10147
10148 /*==========================================
10149  * Changes the guild master of a guild [Skotlex]
10150  *------------------------------------------*/
10151 BUILDIN_FUNC(guildchangegm)
10152 {
10153         TBL_PC *sd;
10154         int guild_id;
10155         const char *name;
10156
10157         guild_id = script_getnum(st,2);
10158         name = script_getstr(st,3);
10159         sd=map_nick2sd(name,false);
10160
10161         if (!sd)
10162                 script_pushint(st,0);
10163         else
10164                 script_pushint(st,guild_gm_change(guild_id, sd->status.char_id));
10165
10166         return SCRIPT_CMD_SUCCESS;
10167 }
10168
10169 /*==========================================
10170  * Spawn a monster:
10171  * *monster "<map name>",<x>,<y>,"<name to show>",<mob id>,<amount>{,"<event label>",<size>,<ai>};
10172  *------------------------------------------*/
10173 BUILDIN_FUNC(monster)
10174 {
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;
10184
10185         struct map_session_data* sd;
10186         int16 m;
10187         int i;
10188
10189         if (script_hasdata(st, 8)) {
10190                 event = script_getstr(st, 8);
10191                 check_event(st, event);
10192         }
10193
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;
10199                 }
10200         }
10201
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;
10207                 }
10208         }
10209
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;
10213         }
10214
10215         sd = map_id2sd(st->rid);
10216
10217         if (sd && strcmp(mapn, "this") == 0)
10218                 m = sd->bl.m;
10219         else
10220                 m = map_mapname2mapid(mapn);
10221
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);
10224
10225                 if (mobid)
10226                         mapreg_setreg(reference_uid(add_str("$@mobid"), i), mobid);
10227         }
10228
10229         return SCRIPT_CMD_SUCCESS;
10230 }
10231
10232 /*==========================================
10233  * Request List of Monster Drops
10234  *------------------------------------------*/
10235 BUILDIN_FUNC(getmobdrops)
10236 {
10237         int class_ = script_getnum(st,2);
10238         int i, j = 0;
10239         struct mob_db *mob;
10240
10241         if( !mobdb_checkid(class_) )
10242         {
10243                 script_pushint(st, 0);
10244                 return SCRIPT_CMD_SUCCESS;
10245         }
10246
10247         mob = mob_db(class_);
10248
10249         for( i = 0; i < MAX_MOB_DROP_TOTAL; i++ )
10250         {
10251                 if( mob->dropitem[i].nameid < 1 )
10252                         continue;
10253                 if( itemdb_exists(mob->dropitem[i].nameid) == NULL )
10254                         continue;
10255
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);
10258
10259                 j++;
10260         }
10261
10262         mapreg_setreg(add_str("$@MobDrop_count"), j);
10263         script_pushint(st, 1);
10264
10265         return SCRIPT_CMD_SUCCESS;
10266 }
10267
10268 /*==========================================
10269  * Spawn a monster in a random location
10270  * in x0,x1,y0,y1 area.
10271  *------------------------------------------*/
10272 BUILDIN_FUNC(areamonster)
10273 {
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;
10285
10286         struct map_session_data* sd;
10287         int16 m;
10288         int i;
10289
10290         if (script_hasdata(st,10)) {
10291                 event = script_getstr(st, 10);
10292                 check_event(st, event);
10293         }
10294
10295         if (script_hasdata(st, 11)) {
10296                 size = script_getnum(st, 11);
10297                 if (size > 3) {
10298                         ShowWarning("buildin_monster: Attempted to spawn non-existing size %d for monster class %d\n", size, class_);
10299                         return SCRIPT_CMD_FAILURE;
10300                 }
10301         }
10302
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;
10308                 }
10309         }
10310
10311         sd = map_id2sd(st->rid);
10312
10313         if (sd && strcmp(mapn, "this") == 0)
10314                 m = sd->bl.m;
10315         else
10316                 m = map_mapname2mapid(mapn);
10317
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);
10320
10321                 if (mobid)
10322                         mapreg_setreg(reference_uid(add_str("$@mobid"), i), mobid);
10323         }
10324
10325         return SCRIPT_CMD_SUCCESS;
10326 }
10327
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);
10336
10337         md->state.npc_killmonster = 1;
10338
10339         if(!allflag){
10340                 if(strcmp(event,md->npc_event)==0)
10341                         status_kill(bl);
10342         }else{
10343                 if(!md->spawn)
10344                         status_kill(bl);
10345         }
10346         md->state.npc_killmonster = 0;
10347         return SCRIPT_CMD_SUCCESS;
10348 }
10349
10350 static int buildin_killmonster_sub(struct block_list *bl,va_list ap)
10351 {
10352         TBL_MOB* md = (TBL_MOB*)bl;
10353         char *event=va_arg(ap,char *);
10354         int allflag=va_arg(ap,int);
10355
10356         if(!allflag){
10357                 if(strcmp(event,md->npc_event)==0)
10358                         status_kill(bl);
10359         }else{
10360                 if(!md->spawn)
10361                         status_kill(bl);
10362         }
10363         return SCRIPT_CMD_SUCCESS;
10364 }
10365
10366 BUILDIN_FUNC(killmonster)
10367 {
10368         const char *mapname,*event;
10369         int16 m,allflag=0;
10370         mapname=script_getstr(st,2);
10371         event=script_getstr(st,3);
10372         if(strcmp(event,"All")==0)
10373                 allflag = 1;
10374         else
10375                 check_event(st, event);
10376
10377         if( (m=map_mapname2mapid(mapname))<0 )
10378                 return SCRIPT_CMD_SUCCESS;
10379
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;
10384                 }
10385         }
10386
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;
10391 }
10392
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;
10396
10397         md = BL_CAST(BL_MOB, bl);
10398         if (md->npc_event[0])
10399                 md->npc_event[0] = 0;
10400
10401         status_kill(bl);
10402         return 0;
10403 }
10404 static int buildin_killmonsterall_sub(struct block_list *bl,va_list ap)
10405 {
10406         status_kill(bl);
10407         return 0;
10408 }
10409 BUILDIN_FUNC(killmonsterall)
10410 {
10411         const char *mapname;
10412         int16 m;
10413         mapname=script_getstr(st,2);
10414
10415         if( (m = map_mapname2mapid(mapname))<0 )
10416                 return SCRIPT_CMD_SUCCESS;
10417
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;
10422                 }
10423         }
10424
10425         map_foreachinmap(buildin_killmonsterall_sub_strip,m,BL_MOB);
10426         return SCRIPT_CMD_SUCCESS;
10427 }
10428
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)
10434 {
10435         TBL_PC *sd, *msd=NULL;
10436         uint32 char_id, master_id = 0, x, y, flag = 0;
10437         int16 m;
10438         enum e_mode mode = MD_NONE;
10439
10440         unsigned int duration = 0;
10441         const char *mapname,*event;
10442
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);
10448
10449         if( script_hasdata(st,7) )
10450                 master_id=script_getnum(st,7);
10451
10452         if( script_hasdata(st,8) )
10453                 mode=static_cast<e_mode>(script_getnum(st,8));
10454
10455         if( script_hasdata(st,9) )
10456                 flag=script_getnum(st,9);
10457
10458         if( script_hasdata(st,10) )
10459                 duration=script_getnum(st,10);
10460
10461         check_event(st, event);
10462
10463         m = map_mapname2mapid(mapname);
10464         if (m < 0)
10465                 return SCRIPT_CMD_SUCCESS;
10466
10467         sd = map_charid2sd(char_id);
10468
10469         if (master_id) {
10470                 msd = map_charid2sd(master_id);
10471                 if (msd)
10472                         master_id = msd->bl.id;
10473                 else
10474                         master_id = 0;
10475         }
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);
10480
10481         return SCRIPT_CMD_SUCCESS;
10482 }
10483
10484 /*==========================================
10485  *------------------------------------------*/
10486 BUILDIN_FUNC(doevent)
10487 {
10488         const char* event;
10489         struct map_session_data* sd;
10490
10491         if( !script_rid2sd(sd) )
10492                 return SCRIPT_CMD_SUCCESS;
10493
10494         event = script_getstr(st,2);
10495
10496         check_event(st, event);
10497         npc_event(sd, event, 0);
10498         return SCRIPT_CMD_SUCCESS;
10499 }
10500
10501 /*==========================================
10502  *------------------------------------------*/
10503 BUILDIN_FUNC(donpcevent)
10504 {
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);
10511         } else
10512                 script_pushint(st, 1);
10513         return SCRIPT_CMD_SUCCESS;
10514 }
10515
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
10519 {
10520         const char* npc = script_getstr(st,2);
10521         const char* command = script_getstr(st,3);
10522         char event[EVENT_NAME_LENGTH];
10523
10524         safesnprintf(event,EVENT_NAME_LENGTH, "%s::%s%s",npc,script_config.oncommand_event_name,command);
10525         check_event(st, event);
10526
10527         if( npc_event_do(event) ){
10528                 script_pushint(st, true);
10529         }else{
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);
10533         }
10534
10535         return SCRIPT_CMD_SUCCESS;
10536 }
10537
10538 /*==========================================
10539  *------------------------------------------*/
10540 BUILDIN_FUNC(addtimer)
10541 {
10542         int tick;
10543         const char* event;
10544         TBL_PC* sd;
10545
10546         if( !script_rid2sd(sd) )
10547                 return SCRIPT_CMD_SUCCESS;
10548
10549         tick = script_getnum(st,2);
10550         event = script_getstr(st, 3);
10551
10552         check_event(st, event);
10553
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;
10557         }
10558         return SCRIPT_CMD_SUCCESS;
10559 }
10560
10561 /*==========================================
10562  *------------------------------------------*/
10563 BUILDIN_FUNC(deltimer)
10564 {
10565         const char *event;
10566         TBL_PC* sd;
10567
10568         if( !script_rid2sd(sd) )
10569                 return SCRIPT_CMD_SUCCESS;
10570
10571         event=script_getstr(st, 2);
10572
10573         check_event(st, event);
10574         pc_deleventtimer(sd,event);
10575         return SCRIPT_CMD_SUCCESS;
10576 }
10577 /*==========================================
10578  *------------------------------------------*/
10579 BUILDIN_FUNC(addtimercount)
10580 {
10581         const char *event;
10582         int tick;
10583         TBL_PC* sd;
10584
10585         if( !script_rid2sd(sd) )
10586                 return SCRIPT_CMD_SUCCESS;
10587
10588         tick=script_getnum(st,2);
10589         event=script_getstr(st,3);
10590
10591         check_event(st, event);
10592         pc_addeventtimercount(sd,event,tick);
10593         return SCRIPT_CMD_SUCCESS;
10594 }
10595
10596 /*==========================================
10597  *------------------------------------------*/
10598 BUILDIN_FUNC(initnpctimer)
10599 {
10600         struct npc_data *nd;
10601         int flag = 0;
10602
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);
10607         }
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);
10612                 get_val(st,data);
10613                 if( data_isstring(data) ) //NPC name
10614                         nd = npc_name2id(conv_str(st, data));
10615                 else if( data_isint(data) ) //Flag
10616                 {
10617                         nd = (struct npc_data *)map_id2bl(st->oid);
10618                         flag = conv_num(st,data);
10619                 }
10620                 else
10621                 {
10622                         ShowError("initnpctimer: invalid argument type #1 (needs be int or string)).\n");
10623                         return SCRIPT_CMD_FAILURE;
10624                 }
10625         }
10626         else
10627                 nd = (struct npc_data *)map_id2bl(st->oid);
10628
10629         if( !nd )
10630                 return SCRIPT_CMD_SUCCESS;
10631         if( flag ) //Attach
10632         {
10633                 TBL_PC* sd;
10634                 if( !script_rid2sd(sd) )
10635                         return SCRIPT_CMD_SUCCESS;
10636                 nd->u.scr.rid = sd->bl.id;
10637         }
10638
10639         nd->u.scr.timertick = 0;
10640         npc_settimerevent_tick(nd,0);
10641         npc_timerevent_start(nd, st->rid);
10642         return SCRIPT_CMD_SUCCESS;
10643 }
10644
10645 /*==========================================
10646  *------------------------------------------*/
10647 BUILDIN_FUNC(startnpctimer)
10648 {
10649         struct npc_data *nd;
10650         int flag = 0;
10651
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);
10656         }
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);
10661                 get_val(st,data);
10662                 if( data_isstring(data) ) //NPC name
10663                         nd = npc_name2id(conv_str(st, data));
10664                 else if( data_isint(data) ) //Flag
10665                 {
10666                         nd = (struct npc_data *)map_id2bl(st->oid);
10667                         flag = conv_num(st,data);
10668                 }
10669                 else
10670                 {
10671                         ShowError("initnpctimer: invalid argument type #1 (needs be int or string)).\n");
10672                         return SCRIPT_CMD_FAILURE;
10673                 }
10674         }
10675         else
10676                 nd=(struct npc_data *)map_id2bl(st->oid);
10677
10678         if( !nd )
10679                 return SCRIPT_CMD_SUCCESS;
10680         if( flag ) //Attach
10681         {
10682                 TBL_PC* sd;
10683                 if( !script_rid2sd(sd) )
10684                         return SCRIPT_CMD_SUCCESS;
10685                 nd->u.scr.rid = sd->bl.id;
10686         }
10687
10688         npc_timerevent_start(nd, st->rid);
10689         return SCRIPT_CMD_SUCCESS;
10690 }
10691 /*==========================================
10692  *------------------------------------------*/
10693 BUILDIN_FUNC(stopnpctimer)
10694 {
10695         struct npc_data *nd;
10696         int flag = 0;
10697
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);
10702         }
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);
10707                 get_val(st,data);
10708                 if( data_isstring(data) ) //NPC name
10709                         nd = npc_name2id(conv_str(st, data));
10710                 else if( data_isint(data) ) //Flag
10711                 {
10712                         nd = (struct npc_data *)map_id2bl(st->oid);
10713                         flag = conv_num(st,data);
10714                 }
10715                 else
10716                 {
10717                         ShowError("initnpctimer: invalid argument type #1 (needs be int or string)).\n");
10718                         return SCRIPT_CMD_FAILURE;
10719                 }
10720         }
10721         else
10722                 nd=(struct npc_data *)map_id2bl(st->oid);
10723
10724         if( !nd )
10725                 return SCRIPT_CMD_SUCCESS;
10726         if( flag ) //Detach
10727                 nd->u.scr.rid = 0;
10728
10729         npc_timerevent_stop(nd);
10730         return SCRIPT_CMD_SUCCESS;
10731 }
10732
10733 /*==========================================
10734  *------------------------------------------*/
10735 BUILDIN_FUNC(getnpctimer)
10736 {
10737         struct npc_data *nd;
10738         TBL_PC *sd;
10739         int type = script_getnum(st,2);
10740         int val = 0;
10741
10742         if( script_hasdata(st,3) )
10743                 nd = npc_name2id(script_getstr(st,3));
10744         else
10745                 nd = (struct npc_data *)map_id2bl(st->oid);
10746
10747         if( !nd || nd->bl.type != BL_NPC )
10748         {
10749                 script_pushint(st,0);
10750                 ShowError("getnpctimer: Invalid NPC.\n");
10751                 return SCRIPT_CMD_FAILURE;
10752         }
10753
10754         switch( type )
10755         {
10756         case 0: val = npc_gettimerevent_tick(nd); break;
10757         case 1:
10758                 if( nd->u.scr.rid )
10759                 {
10760                         sd = map_id2sd(nd->u.scr.rid);
10761                         if( !sd )
10762                         {
10763                                 ShowError("buildin_getnpctimer: Attached player not found!\n");
10764                                 break;
10765                         }
10766                         val = (sd->npc_timer_id != INVALID_TIMER);
10767                 }
10768                 else
10769                         val = (nd->u.scr.timerid != INVALID_TIMER);
10770                 break;
10771         case 2: val = nd->u.scr.timeramount; break;
10772         }
10773
10774         script_pushint(st,val);
10775         return SCRIPT_CMD_SUCCESS;
10776 }
10777
10778 /*==========================================
10779  *------------------------------------------*/
10780 BUILDIN_FUNC(setnpctimer)
10781 {
10782         int tick;
10783         struct npc_data *nd;
10784
10785         tick = script_getnum(st,2);
10786         if( script_hasdata(st,3) )
10787                 nd = npc_name2id(script_getstr(st,3));
10788         else
10789                 nd = (struct npc_data *)map_id2bl(st->oid);
10790
10791         if( !nd || nd->bl.type != BL_NPC )
10792         {
10793                 script_pushint(st,1);
10794                 ShowError("setnpctimer: Invalid NPC.\n");
10795                 return SCRIPT_CMD_FAILURE;
10796         }
10797
10798         npc_settimerevent_tick(nd,tick);
10799         script_pushint(st,0);
10800         return SCRIPT_CMD_SUCCESS;
10801 }
10802
10803 /*==========================================
10804  * attaches the player rid to the timer [Celest]
10805  *------------------------------------------*/
10806 BUILDIN_FUNC(attachnpctimer)
10807 {
10808         TBL_PC *sd;
10809         struct npc_data *nd = (struct npc_data *)map_id2bl(st->oid);
10810
10811         if( !nd || nd->bl.type != BL_NPC )
10812         {
10813                 script_pushint(st,1);
10814                 ShowError("setnpctimer: Invalid NPC.\n");
10815                 return SCRIPT_CMD_FAILURE;
10816         }
10817
10818         if( !script_nick2sd(2,sd) ){
10819                 script_pushint(st,1);
10820                 ShowWarning("attachnpctimer: Invalid player.\n");
10821                 return SCRIPT_CMD_FAILURE;
10822         }
10823
10824         nd->u.scr.rid = sd->bl.id;
10825         script_pushint(st,0);
10826         return SCRIPT_CMD_SUCCESS;
10827 }
10828
10829 /*==========================================
10830  * detaches a player rid from the timer [Celest]
10831  *------------------------------------------*/
10832 BUILDIN_FUNC(detachnpctimer)
10833 {
10834         struct npc_data *nd;
10835
10836         if( script_hasdata(st,2) )
10837                 nd = npc_name2id(script_getstr(st,2));
10838         else
10839                 nd = (struct npc_data *)map_id2bl(st->oid);
10840
10841         if( !nd || nd->bl.type != BL_NPC )
10842         {
10843                 script_pushint(st,1);
10844                 ShowError("detachnpctimer: Invalid NPC.\n");
10845                 return SCRIPT_CMD_FAILURE;
10846         }
10847
10848         nd->u.scr.rid = 0;
10849         script_pushint(st,0);
10850         return SCRIPT_CMD_SUCCESS;
10851 }
10852
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)
10859 {
10860         if(st->rid == 0 || map_id2sd(st->rid) == NULL)
10861                 script_pushint(st,0);
10862         else
10863                 script_pushint(st,st->rid);
10864         return SCRIPT_CMD_SUCCESS;
10865 }
10866
10867 /*==========================================
10868  *------------------------------------------*/
10869 BUILDIN_FUNC(announce)
10870 {
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
10878
10879         if (flag&(BC_TARGET_MASK|BC_SOURCE_MASK)) // Broadcast source or broadcast region defined
10880         {
10881                 send_target target;
10882                 struct block_list *bl;
10883
10884                 // If bc_npc flag is set, use NPC as broadcast source
10885                 if(flag&BC_NPC){
10886                         bl = map_id2bl(st->oid);
10887                 }else{
10888                         struct map_session_data* sd;
10889
10890                         if( script_rid2sd(sd) )
10891                                 bl = &sd->bl;
10892                         else
10893                                 bl = NULL;
10894                 }
10895                 
10896                 if (bl == NULL)
10897                         return SCRIPT_CMD_SUCCESS;
10898
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
10904                 }
10905
10906                 if (fontColor)
10907                         clif_broadcast2(bl, mes, (int)strlen(mes)+1, strtol(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY, target);
10908                 else
10909                         clif_broadcast(bl, mes, (int)strlen(mes)+1, flag&BC_COLOR_MASK, target);
10910         }
10911         else
10912         {
10913                 if (fontColor)
10914                         intif_broadcast2(mes, (int)strlen(mes)+1, strtol(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY);
10915                 else
10916                         intif_broadcast(mes, (int)strlen(mes)+1, flag&BC_COLOR_MASK);
10917         }
10918         return SCRIPT_CMD_SUCCESS;
10919 }
10920
10921 /*==========================================
10922  *------------------------------------------*/
10923 static int buildin_announce_sub(struct block_list *bl, va_list ap)
10924 {
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);
10933         if (fontColor)
10934                 clif_broadcast2(bl, mes, len, strtol(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY, SELF);
10935         else
10936                 clif_broadcast(bl, mes, len, type, SELF);
10937         return SCRIPT_CMD_SUCCESS;
10938 }
10939
10940 BUILDIN_FUNC(mapannounce)
10941 {
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
10950         int16 m;
10951
10952         if ((m = map_mapname2mapid(mapname)) < 0)
10953                 return SCRIPT_CMD_SUCCESS;
10954
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;
10958 }
10959
10960 /*==========================================
10961  *------------------------------------------*/
10962 BUILDIN_FUNC(areaannounce)
10963 {
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
10976         int16 m;
10977
10978         if ((m = map_mapname2mapid(mapname)) < 0)
10979                 return SCRIPT_CMD_SUCCESS;
10980
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;
10984 }
10985
10986 /*==========================================
10987  *------------------------------------------*/
10988 BUILDIN_FUNC(getusers)
10989 {
10990         int flag, val = 0;
10991         struct map_session_data* sd;
10992         struct block_list* bl = NULL;
10993
10994         flag = script_getnum(st,2);
10995
10996         switch(flag&0x07)
10997         {
10998                 case 0:
10999                         if(flag&0x8)
11000                         {// npc
11001                                 bl = map_id2bl(st->oid);
11002                         }
11003                         else if(script_rid2sd(sd))
11004                         {// pc
11005                                 bl = &sd->bl;
11006                         }
11007
11008                         if(bl)
11009                         {
11010                                 val = map[bl->m].users;
11011                         }
11012                         break;
11013                 case 1:
11014                         val = map_getusers();
11015                         break;
11016                 default:
11017                         ShowWarning("buildin_getusers: Unknown type %d.\n", flag);
11018                         script_pushint(st,0);
11019                         return SCRIPT_CMD_FAILURE;
11020         }
11021
11022         script_pushint(st,val);
11023         return SCRIPT_CMD_SUCCESS;
11024 }
11025
11026 /*==========================================
11027  * getmapguildusers("mapname",guild ID) Returns the number guild members present on a map [Reddozen]
11028  *------------------------------------------*/
11029 BUILDIN_FUNC(getmapguildusers)
11030 {
11031         const char *str;
11032         int16 m;
11033         int gid;
11034         int c=0;
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;
11041         }
11042         g = guild_search(gid);
11043
11044         if (g){
11045                 unsigned short i;
11046                 for(i = 0; i < g->max_member; i++)
11047                 {
11048                         if (g->member[i].sd && g->member[i].sd->bl.m == m)
11049                                 c++;
11050                 }
11051         }
11052
11053         script_pushint(st,c);
11054         return SCRIPT_CMD_SUCCESS;
11055 }
11056
11057 /*==========================================
11058  *------------------------------------------*/
11059 BUILDIN_FUNC(getmapusers)
11060 {
11061         const char *str;
11062         int16 m;
11063         str=script_getstr(st,2);
11064         if( (m=map_mapname2mapid(str))< 0){
11065                 script_pushint(st,-1);
11066                 return SCRIPT_CMD_SUCCESS;
11067         }
11068         script_pushint(st,map[m].users);
11069         return SCRIPT_CMD_SUCCESS;
11070 }
11071 /*==========================================
11072  *------------------------------------------*/
11073 static int buildin_getareausers_sub(struct block_list *bl,va_list ap)
11074 {
11075         int *users=va_arg(ap,int *);
11076         (*users)++;
11077         return SCRIPT_CMD_SUCCESS;
11078 }
11079
11080 BUILDIN_FUNC(getareausers)
11081 {
11082         const char *str;
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;
11092         }
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;
11097 }
11098
11099 /*==========================================
11100  *------------------------------------------*/
11101 static int buildin_getareadropitem_sub(struct block_list *bl,va_list ap)
11102 {
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;
11106
11107         if(drop->item.nameid==nameid)
11108                 (*amount)+=drop->item.amount;
11109
11110         return SCRIPT_CMD_SUCCESS;
11111 }
11112 BUILDIN_FUNC(getareadropitem)
11113 {
11114         const char *str;
11115         int16 m,x0,y0,x1,y1;
11116         unsigned short nameid, amount = 0;
11117         struct script_data *data;
11118
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);
11124
11125         data=script_getdata(st,7);
11126         get_val(st,data);
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;
11131                 if( item_data )
11132                         nameid=item_data->nameid;
11133         }else
11134                 nameid=conv_num(st,data);
11135
11136         if( (m=map_mapname2mapid(str))< 0){
11137                 script_pushint(st,-1);
11138                 return SCRIPT_CMD_SUCCESS;
11139         }
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;
11144 }
11145
11146 /*==========================================
11147  *------------------------------------------*/
11148 BUILDIN_FUNC(enablenpc)
11149 {
11150         const char *str;
11151         str=script_getstr(st,2);
11152         npc_enable(str,1);
11153         return SCRIPT_CMD_SUCCESS;
11154 }
11155
11156 /*==========================================
11157  *------------------------------------------*/
11158 BUILDIN_FUNC(disablenpc)
11159 {
11160         const char *str;
11161         str=script_getstr(st,2);
11162         npc_enable(str,0);
11163         return SCRIPT_CMD_SUCCESS;
11164 }
11165
11166 /*==========================================
11167  *------------------------------------------*/
11168 BUILDIN_FUNC(hideoffnpc)
11169 {
11170         const char *str;
11171         str=script_getstr(st,2);
11172         npc_enable(str,2);
11173         return SCRIPT_CMD_SUCCESS;
11174 }
11175 /*==========================================
11176  *------------------------------------------*/
11177 BUILDIN_FUNC(hideonnpc)
11178 {
11179         const char *str;
11180         str=script_getstr(st,2);
11181         npc_enable(str,4);
11182         return SCRIPT_CMD_SUCCESS;
11183 }
11184
11185 /* Starts a status effect on the target unit or on the attached player.
11186  *
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
11191  */
11192 BUILDIN_FUNC(sc_start)
11193 {
11194         TBL_NPC * nd = map_id2nd(st->oid);
11195         struct block_list* bl;
11196         enum sc_type type;
11197         int tick, val1, val2, val3, val4=0, rate, flag;
11198         char start_type;
11199         const char* command = script_getfuncname(st);
11200
11201         if(strstr(command, "4"))
11202                 start_type = 4;
11203         else if(strstr(command, "2"))
11204                 start_type = 2;
11205         else
11206                 start_type = 1;
11207
11208         type = (sc_type)script_getnum(st,2);
11209         tick = script_getnum(st,3);
11210         val1 = script_getnum(st,4);
11211
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;
11215         else
11216                 flag = script_hasdata(st,5+start_type)?script_getnum(st,5+start_type):SCSTART_NOAVOID;
11217
11218         rate = script_hasdata(st,4+start_type)?min(script_getnum(st,4+start_type),10000):10000;
11219
11220         if(script_hasdata(st,(6+start_type)))
11221                 bl = map_id2bl(script_getnum(st,(6+start_type)));
11222         else
11223                 bl = map_id2bl(st->rid);
11224
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);
11228         }
11229
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
11234         }
11235
11236         if(!bl)
11237                 return SCRIPT_CMD_SUCCESS;
11238
11239         switch(start_type) {
11240                 case 1:
11241                         status_change_start(bl, bl, type, rate, val1, 0, 0, val4, tick, flag);
11242                         break;
11243                 case 2:
11244                         val2 = script_getnum(st,5);
11245                         status_change_start(bl, bl, type, rate, val1, val2, 0, val4, tick, flag);
11246                         break;
11247                 case 4:
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);
11252                         break;
11253         }
11254         return SCRIPT_CMD_SUCCESS;
11255 }
11256
11257 /// Ends one or all status effects on the target unit or on the attached player.
11258 ///
11259 /// sc_end <effect_id>{,<unit_id>};
11260 BUILDIN_FUNC(sc_end)
11261 {
11262         struct block_list* bl;
11263         int type;
11264
11265         type = script_getnum(st, 2);
11266         if (script_hasdata(st, 3))
11267                 bl = map_id2bl(script_getnum(st, 3));
11268         else
11269                 bl = map_id2bl(st->rid);
11270
11271         if (potion_flag == 1 && potion_target) //##TODO how does this work [FlavioJS]
11272                 bl = map_id2bl(potion_target);
11273
11274         if (!bl)
11275                 return SCRIPT_CMD_SUCCESS;
11276
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;
11280
11281                 if (!sce)
11282                         return SCRIPT_CMD_SUCCESS;
11283
11284                 switch (type) {
11285                         case SC_WEIGHT50:
11286                         case SC_WEIGHT90:
11287                         case SC_NOCHAT:
11288                         case SC_PUSH_CART:
11289                         case SC_ALL_RIDING:
11290                         case SC_STYLE_CHANGE:
11291                         case SC_MONSTER_TRANSFORM:
11292                         case SC_ACTIVE_MONSTER_TRANSFORM:
11293                         case SC_MTF_ASPD:
11294                         case SC_MTF_RANGEATK:
11295                         case SC_MTF_MATK:
11296                         case SC_MTF_MLEATKED:
11297                         case SC_MTF_CRIDAMAGE:
11298                         case SC_MTF_ASPD2:
11299                         case SC_MTF_RANGEATK2:
11300                         case SC_MTF_MATK2:
11301                         case SC_MTF_MHP:
11302                         case SC_MTF_MSP:
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;
11313                         default:
11314                                 break;
11315                 }
11316
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);
11320         } else
11321                 status_change_clear(bl, 3); // remove all effects
11322
11323         return SCRIPT_CMD_SUCCESS;
11324 }
11325
11326 /**
11327  * Ends all status effects from any learned skill on the attached player.
11328  * sc_end_class {<char_id>};
11329  */
11330 BUILDIN_FUNC(sc_end_class)
11331 {
11332         struct map_session_data *sd;
11333         uint16 skill_id;
11334         int i;
11335
11336         if (!script_charid2sd(2, sd))
11337                 return SCRIPT_CMD_FAILURE;
11338
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);
11341
11342                 if (sc > SC_COMMON_MAX && sd->sc.data[sc])
11343                         status_change_end(&sd->bl, sc, INVALID_TIMER);
11344         }
11345
11346         return SCRIPT_CMD_SUCCESS;
11347 }
11348
11349 /*==========================================
11350  * @FIXME atm will return reduced tick, 0 immune, 1 no tick
11351  *------------------------------------------*/
11352 BUILDIN_FUNC(getscrate)
11353 {
11354         struct block_list *bl;
11355         int type,rate;
11356
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));
11361         else
11362                 bl = map_id2bl(st->rid);
11363
11364         if (bl)
11365                 rate = status_get_sc_def(NULL,bl, (sc_type)type, 10000, 10000, SCSTART_NONE);
11366
11367         script_pushint(st,rate);
11368         return SCRIPT_CMD_SUCCESS;
11369 }
11370
11371 /**
11372  * getstatus(<effect type>{,<type>{,<char_id>}});
11373  **/
11374 BUILDIN_FUNC(getstatus)
11375 {
11376         int id, type;
11377         struct map_session_data* sd;
11378
11379         if (!script_charid2sd(4,sd))
11380                 return SCRIPT_CMD_FAILURE;
11381
11382         id = script_getnum(st, 2);
11383         type = script_hasdata(st, 3) ? script_getnum(st, 3) : 0;
11384
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;
11389         }
11390
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;
11395         }
11396
11397         switch( type )
11398         {
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;
11403                 case 5:
11404                         {
11405                                 struct TimerData* timer = (struct TimerData*)get_timer(sd->sc.data[id]->timer);
11406
11407                                 if( timer )
11408                                 {// return the amount of time remaining
11409                                         script_pushint(st, timer->tick - gettick());
11410                                 } else {
11411                                         script_pushint(st, -1);
11412                                 }
11413                         }
11414                         break;
11415                 default: script_pushint(st, 1); break;
11416         }
11417
11418         return SCRIPT_CMD_SUCCESS;
11419 }
11420
11421 /*==========================================
11422  *
11423  *------------------------------------------*/
11424 BUILDIN_FUNC(debugmes)
11425 {
11426         const char *str;
11427         str=script_getstr(st,2);
11428         ShowDebug("script debug : %d %d : %s\n",st->rid,st->oid,str);
11429         return SCRIPT_CMD_SUCCESS;
11430 }
11431
11432 /*==========================================
11433  *------------------------------------------*/
11434 BUILDIN_FUNC(catchpet)
11435 {
11436         int pet_id;
11437         TBL_PC *sd;
11438
11439         if( !script_rid2sd(sd) )
11440                 return SCRIPT_CMD_SUCCESS;
11441
11442         pet_id= script_getnum(st,2);
11443
11444         pet_catch_process1(sd,pet_id);
11445         return SCRIPT_CMD_SUCCESS;
11446 }
11447
11448 /*==========================================
11449  * [orn]
11450  *------------------------------------------*/
11451 BUILDIN_FUNC(homunculus_evolution)
11452 {
11453         TBL_PC *sd;
11454
11455         if( !script_rid2sd(sd) )
11456                 return SCRIPT_CMD_SUCCESS;
11457
11458         if(hom_is_active(sd->hd))
11459         {
11460                 if (sd->hd->homunculus.intimacy >= battle_config.homunculus_evo_intimacy_need)
11461                         hom_evolution(sd->hd);
11462                 else
11463                         clif_emotion(&sd->hd->bl, E_SWT);
11464         }
11465         return SCRIPT_CMD_SUCCESS;
11466 }
11467
11468 /*==========================================
11469  * Checks for vaporized morph state
11470  * and deletes ITEMID_STRANGE_EMBRYO.
11471  *------------------------------------------*/
11472 BUILDIN_FUNC(homunculus_mutate)
11473 {
11474         int homun_id;
11475         TBL_PC *sd;
11476
11477         if( !script_rid2sd(sd) || sd->hd == NULL )
11478                 return SCRIPT_CMD_SUCCESS;
11479
11480         if(script_hasdata(st,2))
11481                 homun_id = script_getnum(st,2);
11482         else
11483                 homun_id = 6048 + (rnd() % 4);
11484
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);
11489
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;
11497                 } else
11498                         clif_emotion(&sd->bl, E_SWT);
11499         } else
11500                 clif_emotion(&sd->bl, E_SWT);
11501
11502         script_pushint(st, 0);
11503
11504         return SCRIPT_CMD_SUCCESS;
11505 }
11506
11507 /*==========================================
11508  * Puts homunculus into morph state
11509  * and gives ITEMID_STRANGE_EMBRYO.
11510  *------------------------------------------*/
11511 BUILDIN_FUNC(morphembryo)
11512 {
11513         struct item item_tmp;
11514         TBL_PC *sd;
11515
11516         if( !script_rid2sd(sd) || sd->hd == NULL )
11517                 return SCRIPT_CMD_SUCCESS;
11518
11519         if( hom_is_active(sd->hd) ) {
11520                 int m_class = hom_class2mapid(sd->hd->homunculus.class_);
11521
11522                 if ( m_class != -1 && m_class&HOM_EVO && sd->hd->homunculus.level >= 99 ) {
11523                         char i;
11524                         memset(&item_tmp, 0, sizeof(item_tmp));
11525                         item_tmp.nameid = ITEMID_STRANGE_EMBRYO;
11526                         item_tmp.identify = 1;
11527
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.
11531                         } else {
11532                                 hom_vaporize(sd, HOM_ST_MORPH);
11533                                 script_pushint(st, 1);
11534                                 return SCRIPT_CMD_SUCCESS;
11535                         }
11536                 } else
11537                         clif_emotion(&sd->hd->bl, E_SWT);
11538         } else
11539                 clif_emotion(&sd->bl, E_SWT);
11540
11541         script_pushint(st, 0);
11542
11543         return SCRIPT_CMD_SUCCESS;
11544 }
11545
11546 // [Zephyrus]
11547 BUILDIN_FUNC(homunculus_shuffle)
11548 {
11549         TBL_PC *sd;
11550
11551         if( !script_rid2sd(sd) )
11552                 return SCRIPT_CMD_SUCCESS;
11553
11554         if(hom_is_active(sd->hd))
11555                 hom_shuffle(sd->hd);
11556
11557         return SCRIPT_CMD_SUCCESS;
11558 }
11559
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)
11568 {
11569         TBL_PC *sd;
11570         TBL_HOM *hd;
11571
11572         if( !script_rid2sd(sd) )
11573                 return SCRIPT_CMD_SUCCESS;
11574
11575         hd = sd->hd;
11576
11577         if( !hd )
11578                 script_pushint(st, -1);
11579         else
11580                 script_pushint(st, hd->homunculus.vaporize);
11581
11582         return SCRIPT_CMD_SUCCESS;
11583 }
11584
11585 //These two functions bring the eA MAPID_* class functionality to scripts.
11586 BUILDIN_FUNC(eaclass)
11587 {
11588         int class_;
11589         if( script_hasdata(st,2) )
11590                 class_ = script_getnum(st,2);
11591         else {
11592                 TBL_PC *sd;
11593
11594                 if (!script_charid2sd(3,sd)) {
11595                         script_pushint(st,-1);
11596                         return SCRIPT_CMD_SUCCESS;
11597                 }
11598                 class_ = sd->status.class_;
11599         }
11600         script_pushint(st,pc_jobid2mapid(class_));
11601         return SCRIPT_CMD_SUCCESS;
11602 }
11603
11604 BUILDIN_FUNC(roclass)
11605 {
11606         int class_ =script_getnum(st,2);
11607         int sex;
11608         if( script_hasdata(st,3) )
11609                 sex = script_getnum(st,3);
11610         else {
11611                 TBL_PC *sd;
11612                 if (st->rid && script_rid2sd(sd))
11613                         sex = sd->status.sex;
11614                 else
11615                         sex = SEX_MALE; //Just use male when not found.
11616         }
11617         script_pushint(st,pc_mapid2jobid(class_, sex));
11618         return SCRIPT_CMD_SUCCESS;
11619 }
11620
11621 /*==========================================
11622  * Tells client to open a hatching window, used for pet incubator
11623  *------------------------------------------*/
11624 BUILDIN_FUNC(birthpet)
11625 {
11626         TBL_PC *sd;
11627         if( !script_rid2sd(sd) )
11628                 return SCRIPT_CMD_SUCCESS;
11629
11630         if( sd->status.pet_id )
11631         {// do not send egg list, when you already have a pet
11632                 return SCRIPT_CMD_SUCCESS;
11633         }
11634
11635         clif_sendegg(sd);
11636         return SCRIPT_CMD_SUCCESS;
11637 }
11638
11639 /**
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
11645  *      4 : jlvl=0
11646  * @author AppleGirl
11647  **/
11648 BUILDIN_FUNC(resetlvl)
11649 {
11650         TBL_PC *sd;
11651
11652         int type=script_getnum(st,2);
11653
11654         if (!script_charid2sd(3,sd))
11655                 return SCRIPT_CMD_FAILURE;
11656
11657         pc_resetlvl(sd,type);
11658         return SCRIPT_CMD_SUCCESS;
11659 }
11660
11661 /**
11662  * Reset a player status point
11663  * resetstatus({<char_id>});
11664  **/
11665 BUILDIN_FUNC(resetstatus)
11666 {
11667         TBL_PC *sd;
11668         if (!script_charid2sd(2,sd))
11669                 return SCRIPT_CMD_FAILURE;
11670         pc_resetstate(sd);
11671         return SCRIPT_CMD_SUCCESS;
11672 }
11673
11674 /**
11675  * Reset player's skill
11676  * resetskill({<char_id>});
11677  **/
11678 BUILDIN_FUNC(resetskill)
11679 {
11680         TBL_PC *sd;
11681         if (!script_charid2sd(2,sd))
11682                 return SCRIPT_CMD_FAILURE;
11683         pc_resetskill(sd,1);
11684         return SCRIPT_CMD_SUCCESS;
11685 }
11686
11687 /**
11688  * Counts total amount of skill points.
11689  * skillpointcount({<char_id>})
11690  **/
11691 BUILDIN_FUNC(skillpointcount)
11692 {
11693         TBL_PC *sd;
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;
11698 }
11699
11700 /*==========================================
11701  *
11702  *------------------------------------------*/
11703 BUILDIN_FUNC(changebase)
11704 {
11705         TBL_PC *sd=NULL;
11706         int vclass;
11707
11708         if( !script_mapid2sd(3,sd) )
11709                 return SCRIPT_CMD_SUCCESS;
11710
11711         vclass = script_getnum(st,2);
11712         if(vclass == JOB_WEDDING)
11713         {
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.
11716                         )
11717                 return SCRIPT_CMD_SUCCESS;
11718         }
11719
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);
11730         }
11731         return SCRIPT_CMD_SUCCESS;
11732 }
11733
11734 /**
11735  * Change account sex and unequip all item and request for a changesex to char-serv
11736  * changesex({<char_id>});
11737  */
11738 BUILDIN_FUNC(changesex)
11739 {
11740         int i;
11741         TBL_PC *sd = NULL;
11742
11743         if (!script_charid2sd(2,sd))
11744                 return SCRIPT_CMD_FAILURE;
11745
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);
11751         }
11752
11753         chrif_changesex(sd, true);
11754         return SCRIPT_CMD_SUCCESS;
11755 }
11756
11757 /**
11758  * Change character's sex and unequip all item and request for a changesex to char-serv
11759  * changecharsex({<char_id>});
11760  */
11761 BUILDIN_FUNC(changecharsex)
11762 {
11763 #if PACKETVER >= 20141016
11764         int i;
11765         TBL_PC *sd = NULL;
11766
11767         if (!script_charid2sd(2,sd))
11768                 return SCRIPT_CMD_FAILURE;
11769
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);
11775         }
11776
11777         chrif_changesex(sd, false);
11778         return SCRIPT_CMD_SUCCESS;
11779 #else
11780         return SCRIPT_CMD_FAILURE;
11781 #endif
11782 }
11783
11784 /*==========================================
11785  * Works like 'announce' but outputs in the common chat window
11786  *------------------------------------------*/
11787 BUILDIN_FUNC(globalmes)
11788 {
11789         struct block_list *bl = map_id2bl(st->oid);
11790         struct npc_data *nd = (struct npc_data *)bl;
11791         const char *name=NULL,*mes;
11792
11793         mes=script_getstr(st,2);
11794         if(mes==NULL)
11795                 return SCRIPT_CMD_SUCCESS;
11796
11797         if(script_hasdata(st,3)){       //  npc name to display
11798                 name=script_getstr(st,3);
11799         } else {
11800                 name=nd->name; //use current npc name
11801         }
11802
11803         npc_globalmessage(name,mes);    // broadcast  to all players connected
11804         return SCRIPT_CMD_SUCCESS;
11805 }
11806
11807 /////////////////////////////////////////////////////////////////////
11808 // NPC waiting room (chat room)
11809 //
11810
11811 /// Creates a waiting room (chat room) for this npc.
11812 ///
11813 /// waitingroom "<title>",<limit>{,"<event>"{,<trigger>{,<zeny>{,<minlvl>{,<maxlvl>}}}}};
11814 BUILDIN_FUNC(waitingroom)
11815 {
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;
11824
11825         nd = (struct npc_data *)map_id2bl(st->oid);
11826         if( nd != NULL )
11827                 chat_createnpcchat(nd, title, limit, 1, trigger, ev, zeny, minLvl, maxLvl);
11828
11829         return SCRIPT_CMD_SUCCESS;
11830 }
11831
11832 /// Removes the waiting room of the current or target npc.
11833 ///
11834 /// delwaitingroom "<npc_name>";
11835 /// delwaitingroom;
11836 BUILDIN_FUNC(delwaitingroom)
11837 {
11838         struct npc_data* nd;
11839         if( script_hasdata(st,2) )
11840                 nd = npc_name2id(script_getstr(st, 2));
11841         else
11842                 nd = (struct npc_data *)map_id2bl(st->oid);
11843         if( nd != NULL )
11844                 chat_deletenpcchat(nd);
11845         return SCRIPT_CMD_SUCCESS;
11846 }
11847
11848 /// Kick the specified player from the waiting room of the target npc.
11849 ///
11850 /// waitingroomkick "<npc_name>", <kickusername>;
11851 BUILDIN_FUNC(waitingroomkick)
11852 {
11853         struct npc_data* nd;
11854         struct chat_data* cd;
11855         const char* kickusername;
11856         
11857         nd = npc_name2id(script_getstr(st,2));
11858         kickusername = script_getstr(st,3);
11859
11860         if( nd != NULL && (cd=(struct chat_data *)map_id2bl(nd->chat_id)) != NULL )
11861                 chat_npckickchat(cd, kickusername);
11862         return SCRIPT_CMD_SUCCESS;
11863 }
11864
11865 /// Get Users in waiting room and stores gids in .@waitingroom_users[]
11866 /// Num users stored in .@waitingroom_usercount
11867 ///
11868 /// getwaitingroomusers "<npc_name>";
11869 BUILDIN_FUNC(getwaitingroomusers)
11870 {
11871         struct npc_data* nd;
11872         struct chat_data* cd;
11873
11874         int i, j=0;
11875
11876         if( script_hasdata(st,2) )
11877                 nd = npc_name2id(script_getstr(st, 2));
11878         else
11879                 nd = (struct npc_data *)map_id2bl(st->oid);
11880         
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);
11884                         j++;
11885                 }
11886                 setd_sub(st, NULL, ".@waitingroom_usercount", 0, (void *)__64BPRTSIZE(j), NULL);
11887         }
11888         return SCRIPT_CMD_SUCCESS;
11889 }
11890
11891 /// Kicks all the players from the waiting room of the current or target npc.
11892 ///
11893 /// kickwaitingroomall "<npc_name>";
11894 /// kickwaitingroomall;
11895 BUILDIN_FUNC(waitingroomkickall)
11896 {
11897         struct npc_data* nd;
11898         struct chat_data* cd;
11899
11900         if( script_hasdata(st,2) )
11901                 nd = npc_name2id(script_getstr(st,2));
11902         else
11903                 nd = (struct npc_data *)map_id2bl(st->oid);
11904
11905         if( nd != NULL && (cd=(struct chat_data *)map_id2bl(nd->chat_id)) != NULL )
11906                 chat_npckickall(cd);
11907         return SCRIPT_CMD_SUCCESS;
11908 }
11909
11910 /// Enables the waiting room event of the current or target npc.
11911 ///
11912 /// enablewaitingroomevent "<npc_name>";
11913 /// enablewaitingroomevent;
11914 BUILDIN_FUNC(enablewaitingroomevent)
11915 {
11916         struct npc_data* nd;
11917         struct chat_data* cd;
11918
11919         if( script_hasdata(st,2) )
11920                 nd = npc_name2id(script_getstr(st, 2));
11921         else
11922                 nd = (struct npc_data *)map_id2bl(st->oid);
11923
11924         if( nd != NULL && (cd=(struct chat_data *)map_id2bl(nd->chat_id)) != NULL )
11925                 chat_enableevent(cd);
11926         return SCRIPT_CMD_SUCCESS;
11927 }
11928
11929 /// Disables the waiting room event of the current or target npc.
11930 ///
11931 /// disablewaitingroomevent "<npc_name>";
11932 /// disablewaitingroomevent;
11933 BUILDIN_FUNC(disablewaitingroomevent)
11934 {
11935         struct npc_data *nd;
11936         struct chat_data *cd;
11937
11938         if( script_hasdata(st,2) )
11939                 nd = npc_name2id(script_getstr(st, 2));
11940         else
11941                 nd = (struct npc_data *)map_id2bl(st->oid);
11942
11943         if( nd != NULL && (cd=(struct chat_data *)map_id2bl(nd->chat_id)) != NULL )
11944                 chat_disableevent(cd);
11945         return SCRIPT_CMD_SUCCESS;
11946 }
11947
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
11959 ///
11960 /// getwaitingroomstate(<type>,"<npc_name>") -> <info>
11961 /// getwaitingroomstate(<type>) -> <info>
11962 BUILDIN_FUNC(getwaitingroomstate)
11963 {
11964         struct npc_data *nd;
11965         struct chat_data *cd;
11966         int type;
11967
11968         type = script_getnum(st,2);
11969         if( script_hasdata(st,3) )
11970                 nd = npc_name2id(script_getstr(st, 3));
11971         else
11972                 nd = (struct npc_data *)map_id2bl(st->oid);
11973
11974         if( nd == NULL || (cd=(struct chat_data *)map_id2bl(nd->chat_id)) == NULL )
11975         {
11976                 script_pushint(st, -1);
11977                 return SCRIPT_CMD_SUCCESS;
11978         }
11979
11980         switch(type)
11981         {
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;
11992         }
11993         return SCRIPT_CMD_SUCCESS;
11994 }
11995
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.
12002 ///
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
12005 ///
12006 /// warpwaitingpc "<map name>",<x>,<y>,<number of players>;
12007 /// warpwaitingpc "<map name>",<x>,<y>;
12008 BUILDIN_FUNC(warpwaitingpc)
12009 {
12010         int x;
12011         int y;
12012         int i;
12013         int n;
12014         const char* map_name;
12015         struct npc_data* nd;
12016         struct chat_data* cd;
12017
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;
12021
12022         map_name = script_getstr(st,2);
12023         x = script_getnum(st,3);
12024         y = script_getnum(st,4);
12025         n = cd->trigger&0x7f;
12026
12027         if( script_hasdata(st,5) )
12028                 n = script_getnum(st,5);
12029
12030         for( i = 0; i < n && cd->users > 0; i++ )
12031         {
12032                 TBL_PC* sd = cd->usersd[0];
12033
12034                 if( strcmp(map_name,"SavePoint") == 0 && map[sd->bl.m].flag.noteleport )
12035                 {// can't teleport on this map
12036                         break;
12037                 }
12038
12039                 if( cd->zeny )
12040                 {// fee set
12041                         if( (uint32)sd->status.zeny < cd->zeny )
12042                         {// no zeny to cover set fee
12043                                 break;
12044                         }
12045                         pc_payzeny(sd, cd->zeny, LOG_TYPE_NPC, NULL);
12046                 }
12047
12048                 mapreg_setreg(reference_uid(add_str("$@warpwaitingpc"), i), sd->bl.id);
12049
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);
12054                 else
12055                         pc_setpos(sd, mapindex_name2id(map_name), x, y, CLR_OUTSIGHT);
12056         }
12057         mapreg_setreg(add_str("$@warpwaitingpcnum"), i);
12058         return SCRIPT_CMD_SUCCESS;
12059 }
12060
12061 /////////////////////////////////////////////////////////////////////
12062 // ...
12063 //
12064
12065 /// Detaches a character from a script.
12066 ///
12067 /// @param st Script state to detach the character from.
12068 static void script_detach_rid(struct script_state* st)
12069 {
12070         if(st->rid)
12071         {
12072                 script_detach_state(st, false);
12073                 st->rid = 0;
12074         }
12075 }
12076
12077 /*=========================================================================
12078  * Attaches a set of RIDs to the current script. [digitalhamster]
12079  * addrid(<type>{,<flag>{,<parameters>}});
12080  * <type>:
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.
12092  * <flag>:
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)
12097 {
12098         int forceflag;
12099         struct map_session_data *sd = (TBL_PC *)bl;
12100         struct script_state* st;
12101
12102         st = va_arg(ap,struct script_state*);
12103         forceflag = va_arg(ap,int);
12104
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);
12108         return 0;
12109 }
12110
12111 BUILDIN_FUNC(addrid)
12112 {
12113         struct s_mapiterator* iter;
12114         struct block_list *bl;
12115         TBL_PC *sd;
12116
12117         if(st->rid < 1) {
12118                 st->state = END;
12119                 bl = map_id2bl(st->oid);
12120         } else
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();
12123
12124         switch(script_getnum(st,2)) {
12125                 case 0:
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);
12130                         }
12131                         break;
12132                 case 1:
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);
12137                         }
12138                         break;
12139                 case 2:
12140                         if(script_getnum(st,4) == 0) {
12141                                 script_pushint(st,0);
12142                                 return SCRIPT_CMD_SUCCESS;
12143                         }
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);
12148                         }
12149                         break;
12150                 case 3:
12151                         if(script_getnum(st,4) == 0) {
12152                                 script_pushint(st,0);
12153                                 return SCRIPT_CMD_SUCCESS;
12154                         }
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);
12159                         }
12160                         break;
12161                 case 4:
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
12165                         break;
12166                 case 5:
12167                         if (script_getstr(st, 4) == NULL) {
12168                                 script_pushint(st, 0);
12169                                 return SCRIPT_CMD_FAILURE;
12170                         }
12171                         if (map_mapname2mapid(script_getstr(st, 4)) < 0) {
12172                                 script_pushint(st, 0);
12173                                 return SCRIPT_CMD_FAILURE;
12174                         }
12175                         map_foreachinmap(buildin_addrid_sub, map_mapname2mapid(script_getstr(st, 4)), BL_PC, st, script_getnum(st, 3));
12176                         break;
12177                 default:
12178                         if((map_id2sd(script_getnum(st,2))) == NULL) { // Player not found.
12179                                 script_pushint(st,0);
12180                                 return SCRIPT_CMD_SUCCESS;
12181                         }
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);
12185                         }
12186                         return SCRIPT_CMD_SUCCESS;
12187         }
12188         mapit_free(iter);
12189         script_pushint(st,1);
12190         return SCRIPT_CMD_SUCCESS;
12191 }
12192
12193 /*==========================================
12194  * Attach sd char id to script and detach current one if any
12195  *------------------------------------------*/
12196 BUILDIN_FUNC(attachrid)
12197 {
12198         int rid = script_getnum(st,2);
12199
12200         if (map_id2sd(rid) != NULL) {
12201                 script_detach_rid(st);
12202
12203                 st->rid = rid;
12204                 script_attach_state(st);
12205                 script_pushint(st,1);
12206         } else
12207                 script_pushint(st,0);
12208         return SCRIPT_CMD_SUCCESS;
12209 }
12210 /*==========================================
12211  * Detach script to rid
12212  *------------------------------------------*/
12213 BUILDIN_FUNC(detachrid)
12214 {
12215         script_detach_rid(st);
12216         return SCRIPT_CMD_SUCCESS;
12217 }
12218 /*==========================================
12219  * Chk if account connected, (and charid from account if specified)
12220  *------------------------------------------*/
12221 BUILDIN_FUNC(isloggedin)
12222 {
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))
12226                 sd = NULL;
12227         push_val(st->stack,C_INT,sd!=NULL);
12228         return SCRIPT_CMD_SUCCESS;
12229 }
12230
12231
12232 /*==========================================
12233  *
12234  *------------------------------------------*/
12235 BUILDIN_FUNC(setmapflagnosave)
12236 {
12237         int16 m,x,y;
12238         unsigned short mapindex;
12239         const char *str,*str2;
12240
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);
12247
12248         if(m >= 0 && mapindex) {
12249                 map[m].flag.nosave=1;
12250                 map[m].save.map=mapindex;
12251                 map[m].save.x=x;
12252                 map[m].save.y=y;
12253         }
12254         return SCRIPT_CMD_SUCCESS;
12255 }
12256
12257 BUILDIN_FUNC(getmapflag)
12258 {
12259         int16 m,i;
12260         const char *str;
12261
12262         str=script_getstr(st,2);
12263         i=script_getnum(st,3);
12264
12265         m = map_mapname2mapid(str);
12266         if(m >= 0) {
12267                 switch(i) {
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:
12332                                 {
12333                                         int ret_val=0, type=0;
12334                                         FETCH(4,type);
12335                                         switch (type) {
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;
12342                                         }
12343                                         script_pushint(st,ret_val); break;
12344                                 } break;
12345 #endif
12346                 }
12347         }
12348         return SCRIPT_CMD_SUCCESS;
12349 }
12350
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);
12356                 sd->pvp_rank = 0;
12357                 sd->pvp_lastusers = 0;
12358                 sd->pvp_point = 5;
12359                 sd->pvp_won = 0;
12360                 sd->pvp_lost = 0;
12361         }
12362         clif_map_property(&sd->bl, MAPPROPERTY_FREEPVPZONE,SELF);
12363         return 0;
12364 }
12365
12366 BUILDIN_FUNC(setmapflag)
12367 {
12368         int16 m,i;
12369         const char *str;
12370         int val=0;
12371
12372         str=script_getstr(st,2);
12373         i=script_getnum(st,3);
12374         FETCH(4,val);
12375         m = map_mapname2mapid(str);
12376         if(m >= 0) {
12377                 switch(i) {
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;
12384                         case MF_PVP:
12385                                 map[m].flag.pvp = 1;
12386                                 if( !battle_config.pk_mode ) {
12387                                         map_foreachinmap(script_mapflag_pvp_sub,m,BL_PC);
12388                                 }
12389                                 break;
12390                         case MF_PVP_NOPARTY:            map[m].flag.pvp_noparty = 1; break;
12391                         case MF_PVP_NOGUILD:            map[m].flag.pvp_noguild = 1; break;
12392                         case MF_GVG:
12393                                 map[m].flag.gvg = 1;
12394                                 clif_map_property_mapall(m, MAPPROPERTY_AGITZONE);
12395                                 break;
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;
12423                                 break;
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;
12449                         case MF_GVG_TE:
12450                                 map[m].flag.gvg_te = 1;
12451                                 clif_map_property_mapall(m, MAPPROPERTY_AGITZONE);
12452                                 break;
12453                         case MF_HIDEMOBHPBAR:           map[m].flag.hidemobhpbar = 1; break;
12454 #ifdef ADJUST_SKILL_DAMAGE
12455                         case MF_SKILL_DAMAGE:
12456                                 {
12457                                         int type=0;
12458                                         FETCH(5,type);
12459                                         switch (type) {
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;
12465                                         }
12466                                         map[m].flag.skill_damage = 1;
12467                                 } break;
12468 #endif
12469                 }
12470         }
12471         return SCRIPT_CMD_SUCCESS;
12472 }
12473
12474 BUILDIN_FUNC(removemapflag)
12475 {
12476         int16 m,i;
12477         const char *str;
12478         int val=0;
12479
12480         str=script_getstr(st,2);
12481         i=script_getnum(st,3);
12482         FETCH(4,val);
12483         m = map_mapname2mapid(str);
12484         if(m >= 0) {
12485                 switch(i) {
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;
12492                         case MF_PVP:
12493                                 map[m].flag.pvp = 0;
12494                                 clif_map_property_mapall(m, MAPPROPERTY_NOTHING);
12495                                 break;
12496                         case MF_PVP_NOPARTY:            map[m].flag.pvp_noparty = 0; break;
12497                         case MF_PVP_NOGUILD:            map[m].flag.pvp_noguild = 0; break;
12498                         case MF_GVG:
12499                                 map[m].flag.gvg = 0;
12500                                 clif_map_property_mapall(m, MAPPROPERTY_NOTHING);
12501                                 break;
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;
12530                                 }
12531                                 break;
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;
12557                         case MF_GVG_TE:
12558                                 map[m].flag.gvg_te = 0;
12559                                 clif_map_property_mapall(m, MAPPROPERTY_NOTHING);
12560                                 break;
12561                         case MF_HIDEMOBHPBAR:           map[m].flag.hidemobhpbar = 0; break;
12562 #ifdef ADJUST_SKILL_DAMAGE
12563                         case MF_SKILL_DAMAGE:
12564                                 {
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]);
12569                                 } break;
12570 #endif
12571                 }
12572         }
12573         return SCRIPT_CMD_SUCCESS;
12574 }
12575
12576 BUILDIN_FUNC(pvpon)
12577 {
12578         int16 m;
12579         const char *str;
12580         TBL_PC* sd = NULL;
12581         struct s_mapiterator* iter;
12582
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
12587
12588         map[m].flag.pvp = 1;
12589         clif_map_property_mapall(m, MAPPROPERTY_FREEPVPZONE);
12590
12591         if(battle_config.pk_mode) // disable ranking functions if pk_mode is on [Valaris]
12592                 return SCRIPT_CMD_SUCCESS;
12593
12594         iter = mapit_getallusers();
12595         for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter) )
12596         {
12597                 if( sd->bl.m != m || sd->pvp_timer != INVALID_TIMER )
12598                         continue; // not applicable
12599
12600                 sd->pvp_timer = add_timer(gettick()+200,pc_calc_pvprank_timer,sd->bl.id,0);
12601                 sd->pvp_rank = 0;
12602                 sd->pvp_lastusers = 0;
12603                 sd->pvp_point = 5;
12604                 sd->pvp_won = 0;
12605                 sd->pvp_lost = 0;
12606         }
12607         mapit_free(iter);
12608         return SCRIPT_CMD_SUCCESS;
12609 }
12610
12611 static int buildin_pvpoff_sub(struct block_list *bl,va_list ap)
12612 {
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;
12618         }
12619         return 0;
12620 }
12621
12622 BUILDIN_FUNC(pvpoff)
12623 {
12624         int16 m;
12625         const char *str;
12626
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
12631
12632         map[m].flag.pvp = 0;
12633         clif_map_property_mapall(m, MAPPROPERTY_NOTHING);
12634
12635         if(battle_config.pk_mode) // disable ranking options if pk_mode is on [Valaris]
12636                 return SCRIPT_CMD_SUCCESS;
12637
12638         map_foreachinmap(buildin_pvpoff_sub, m, BL_PC);
12639         return SCRIPT_CMD_SUCCESS;
12640 }
12641
12642 BUILDIN_FUNC(gvgon)
12643 {
12644         int16 m;
12645         const char *str;
12646
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);
12652         }
12653         return SCRIPT_CMD_SUCCESS;
12654 }
12655
12656 BUILDIN_FUNC(gvgoff)
12657 {
12658         int16 m;
12659         const char *str;
12660
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);
12666         }
12667         return SCRIPT_CMD_SUCCESS;
12668 }
12669
12670 BUILDIN_FUNC(gvgon3)
12671 {
12672         int16 m;
12673         const char *str;
12674
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);
12680         }
12681         return SCRIPT_CMD_SUCCESS;
12682 }
12683
12684 BUILDIN_FUNC(gvgoff3)
12685 {
12686         int16 m;
12687         const char *str;
12688
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);
12694         }
12695         return SCRIPT_CMD_SUCCESS;
12696 }
12697
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)
12704 {
12705         int type;
12706         int player=0;
12707
12708         type=script_getnum(st,2);
12709         if(type < 0 || type > 100)
12710                 return SCRIPT_CMD_SUCCESS;
12711
12712         if( script_hasdata(st,3) )
12713                 player=script_getnum(st,3);
12714
12715         if (player) {
12716                 TBL_PC *sd = NULL;
12717
12718                 if( script_nick2sd(4,sd) ){
12719                         clif_emotion(&sd->bl, type);
12720                 }                       
12721         } else
12722                 if( script_hasdata(st,4) )
12723                 {
12724                         TBL_NPC *nd = npc_name2id(script_getstr(st,4));
12725                         if(nd)
12726                                 clif_emotion(&nd->bl,type);
12727                 }
12728                 else
12729                         clif_emotion(map_id2bl(st->oid),type);
12730         return SCRIPT_CMD_SUCCESS;
12731 }
12732
12733
12734 static int buildin_maprespawnguildid_sub_pc(struct map_session_data* sd, va_list ap)
12735 {
12736         int16 m=va_arg(ap,int);
12737         int g_id=va_arg(ap,int);
12738         int flag=va_arg(ap,int);
12739
12740         if(!sd || sd->bl.m != m)
12741                 return 0;
12742         if(
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
12746         )
12747                 pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
12748         return 1;
12749 }
12750
12751 static int buildin_maprespawnguildid_sub_mob(struct block_list *bl,va_list ap)
12752 {
12753         struct mob_data *md=(struct mob_data *)bl;
12754
12755         if(!md->guardian_data && md->mob_id != MOBID_EMPERIUM && ( !mob_is_clone(md->mob_id) || battle_config.guild_maprespawn_clones ))
12756                 status_kill(bl);
12757
12758         return 1;
12759 }
12760
12761 /*
12762  * Function to kick guild members out of a map and to their save points.
12763  * m : mapid
12764  * g_id : owner guild id
12765  * flag & 1 : Warp out owners
12766  * flag & 2 : Warp out outsiders
12767  * flag & 4 : reserved for mobs
12768  * */
12769 BUILDIN_FUNC(maprespawnguildid)
12770 {
12771         const char *mapname=script_getstr(st,2);
12772         int g_id=script_getnum(st,3);
12773         int flag=script_getnum(st,4);
12774
12775         int16 m=map_mapname2mapid(mapname);
12776
12777         if(m == -1)
12778                 return SCRIPT_CMD_SUCCESS;
12779
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;
12785 }
12786
12787 /// Siege commands
12788
12789 /**
12790  * Start WoE:FE
12791  * agitstart();
12792  */
12793 BUILDIN_FUNC(agitstart)
12794 {
12795         guild_agit_start();
12796
12797         return SCRIPT_CMD_SUCCESS;
12798 }
12799
12800 /**
12801  * End WoE:FE
12802  * agitend();
12803  */
12804 BUILDIN_FUNC(agitend)
12805 {
12806         guild_agit_end();
12807
12808         return SCRIPT_CMD_SUCCESS;
12809 }
12810
12811 /**
12812  * Start WoE:SE
12813  * agitstart2();
12814  */
12815 BUILDIN_FUNC(agitstart2)
12816 {
12817         guild_agit2_start();
12818
12819         return SCRIPT_CMD_SUCCESS;
12820 }
12821
12822 /**
12823  * End WoE:SE
12824  * agitend();
12825  */
12826 BUILDIN_FUNC(agitend2)
12827 {
12828         guild_agit2_end();
12829
12830         return SCRIPT_CMD_SUCCESS;
12831 }
12832
12833 /**
12834  * Start WoE:TE
12835  * agitstart3();
12836  */
12837 BUILDIN_FUNC(agitstart3)
12838 {
12839         guild_agit3_start();
12840
12841         return SCRIPT_CMD_SUCCESS;
12842 }
12843
12844 /**
12845  * End WoE:TE
12846  * agitend3();
12847  */
12848 BUILDIN_FUNC(agitend3)
12849 {
12850         guild_agit3_end();
12851
12852         return SCRIPT_CMD_SUCCESS;
12853 }
12854
12855 /**
12856  * Returns whether WoE:FE is on or off.
12857  * agitcheck();
12858  */
12859 BUILDIN_FUNC(agitcheck)
12860 {
12861         script_pushint(st, agit_flag);
12862         return SCRIPT_CMD_SUCCESS;
12863 }
12864
12865 /**
12866  * Returns whether WoE:SE is on or off.
12867  * agitcheck2();
12868  */
12869 BUILDIN_FUNC(agitcheck2)
12870 {
12871         script_pushint(st, agit2_flag);
12872         return SCRIPT_CMD_SUCCESS;
12873 }
12874
12875 /**
12876  * Returns whether WoE:TE is on or off.
12877  * agitcheck3();
12878  */
12879 BUILDIN_FUNC(agitcheck3)
12880 {
12881         script_pushint(st, agit3_flag);
12882         return SCRIPT_CMD_SUCCESS;
12883 }
12884
12885 /// Sets the guild_id of this npc.
12886 ///
12887 /// flagemblem <guild_id>;
12888 BUILDIN_FUNC(flagemblem)
12889 {
12890         TBL_NPC* nd;
12891         int g_id = script_getnum(st,2);
12892
12893         if(g_id < 0)
12894                 return SCRIPT_CMD_SUCCESS;
12895
12896         nd = (TBL_NPC*)map_id2nd(st->oid);
12897         if( nd == NULL ) {
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);
12901         } else {
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);
12910         }
12911         return SCRIPT_CMD_SUCCESS;
12912 }
12913
12914 BUILDIN_FUNC(getcastlename)
12915 {
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;
12921 }
12922
12923 BUILDIN_FUNC(getcastledata)
12924 {
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);
12928
12929         if (gc == NULL) {
12930                 script_pushint(st,0);
12931                 ShowWarning("buildin_getcastledata: guild castle for map '%s' not found\n", mapname);
12932                 return SCRIPT_CMD_FAILURE;
12933         }
12934
12935         switch (index) {
12936                 case 1:
12937                         script_pushint(st,gc->guild_id); break;
12938                 case 2:
12939                         script_pushint(st,gc->economy); break;
12940                 case 3:
12941                         script_pushint(st,gc->defense); break;
12942                 case 4:
12943                         script_pushint(st,gc->triggerE); break;
12944                 case 5:
12945                         script_pushint(st,gc->triggerD); break;
12946                 case 6:
12947                         script_pushint(st,gc->nextTime); break;
12948                 case 7:
12949                         script_pushint(st,gc->payTime); break;
12950                 case 8:
12951                         script_pushint(st,gc->createTime); break;
12952                 case 9:
12953                         script_pushint(st,gc->visibleC); break;
12954                 default:
12955                         if (index > 9 && index <= 9+MAX_GUARDIANS) {
12956                                 script_pushint(st,gc->guardian[index-10].visible);
12957                                 break;
12958                         }
12959                         script_pushint(st,0);
12960                         ShowWarning("buildin_getcastledata: index = '%d' is out of allowed range\n", index);
12961                         return SCRIPT_CMD_FAILURE;
12962         }
12963         return SCRIPT_CMD_SUCCESS;
12964 }
12965
12966 BUILDIN_FUNC(setcastledata)
12967 {
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);
12972
12973         if (gc == NULL) {
12974                 ShowWarning("buildin_setcastledata: guild castle for map '%s' not found\n", mapname);
12975                 return SCRIPT_CMD_FAILURE;
12976         }
12977
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;
12981         }
12982
12983         guild_castledatasave(gc->castle_id, index, value);
12984         return SCRIPT_CMD_SUCCESS;
12985 }
12986
12987 /* =====================================================================
12988  * ---------------------------------------------------------------------*/
12989 BUILDIN_FUNC(requestguildinfo)
12990 {
12991         int guild_id=script_getnum(st,2);
12992         const char *event=NULL;
12993
12994         if( script_hasdata(st,3) ){
12995                 event=script_getstr(st,3);
12996                 check_event(st, event);
12997         }
12998
12999         if(guild_id>0)
13000                 guild_npc_request_info(guild_id,event);
13001         return SCRIPT_CMD_SUCCESS;
13002 }
13003
13004 /// Returns the number of cards that have been compounded onto the specified equipped item.
13005 /// getequipcardcnt(<equipment slot>);
13006 BUILDIN_FUNC(getequipcardcnt)
13007 {
13008         int i=-1,j,num;
13009         TBL_PC *sd;
13010         int count;
13011
13012         if( !script_rid2sd(sd) )
13013                 return SCRIPT_CMD_SUCCESS;
13014
13015         num=script_getnum(st,2);
13016         if (equip_index_check(num))
13017                 i=pc_checkequip(sd,equip_bitmask[num]);
13018
13019         if (i < 0 || !sd->inventory_data[i]) {
13020                 script_pushint(st,0);
13021                 return SCRIPT_CMD_SUCCESS;
13022         }
13023
13024         if(itemdb_isspecial(sd->inventory.u.items_inventory[i].card[0]))
13025         {
13026                 script_pushint(st,0);
13027                 return SCRIPT_CMD_SUCCESS;
13028         }
13029
13030         count = 0;
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 )
13033                         count++;
13034
13035         script_pushint(st,count);
13036         return SCRIPT_CMD_SUCCESS;
13037 }
13038
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;
13044
13045         TBL_PC* sd;
13046         int num;
13047
13048         if( !script_rid2sd(sd) )
13049                 return SCRIPT_CMD_SUCCESS;
13050
13051         num = script_getnum(st,2);
13052
13053         if (equip_index_check(num))
13054                 i=pc_checkequip(sd,equip_bitmask[num]);
13055
13056         if (i < 0 || !sd->inventory_data[i]) {
13057                 return SCRIPT_CMD_SUCCESS;
13058         }
13059
13060         if(itemdb_isspecial(sd->inventory.u.items_inventory[i].card[0]))
13061                 return SCRIPT_CMD_SUCCESS;
13062
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));
13068                         cardflag = 1;
13069                         item_tmp.nameid   = sd->inventory.u.items_inventory[i].card[c];
13070                         item_tmp.identify = 1;
13071
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);
13075                         }
13076                 }
13077         }
13078
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));
13083
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;
13090
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];
13093                 
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;
13098                 }
13099
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);
13104                 }
13105
13106                 clif_misceffect(&sd->bl,3);
13107         }
13108         return SCRIPT_CMD_SUCCESS;
13109 }
13110
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;
13119
13120         TBL_PC* sd;
13121         int num;
13122         int typefail;
13123
13124         if( !script_rid2sd(sd) )
13125                 return SCRIPT_CMD_SUCCESS;
13126
13127         num = script_getnum(st,2);
13128         typefail = script_getnum(st,3);
13129
13130         if (equip_index_check(num))
13131                 i=pc_checkequip(sd,equip_bitmask[num]);
13132
13133         if (i < 0 || !sd->inventory_data[i])
13134                 return SCRIPT_CMD_SUCCESS;
13135
13136         if(itemdb_isspecial(sd->inventory.u.items_inventory[i].card[0]))
13137                 return SCRIPT_CMD_SUCCESS;
13138
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 ) {
13141                         cardflag = 1;
13142
13143                         if(typefail == 2) {// add cards to inventory, clear
13144                                 unsigned char flag = 0;
13145                                 struct item item_tmp;
13146
13147                                 memset(&item_tmp,0,sizeof(item_tmp));
13148
13149                                 item_tmp.nameid   = sd->inventory.u.items_inventory[i].card[c];
13150                                 item_tmp.identify = 1;
13151
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);
13155                                 }
13156                         }
13157                 }
13158         }
13159
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;
13166
13167                         memset(&item_tmp,0,sizeof(item_tmp));
13168
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;
13175
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];
13178                         
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;
13183                         }
13184
13185                         pc_delitem(sd,i,1,0,2,LOG_TYPE_SCRIPT);
13186
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);
13190                         }
13191                 }
13192                 clif_misceffect(&sd->bl,2);
13193         }
13194         return SCRIPT_CMD_SUCCESS;
13195 }
13196
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
13203 {
13204         int x,y,m,check_val=0,check_ID=0,i=0;
13205         struct guild *g = NULL;
13206         struct party_data *p = NULL;
13207         const char *str;
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);
13217         }
13218
13219         if((m=map_mapname2mapid(mapname))< 0)
13220                 return SCRIPT_CMD_SUCCESS;
13221
13222         if(!(index=mapindex_name2id(str)))
13223                 return SCRIPT_CMD_SUCCESS;
13224
13225         switch(check_val){
13226                 case 1:
13227                         g = guild_search(check_ID);
13228                         if (g){
13229                                 for( i=0; i < g->max_member; i++)
13230                                 {
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);
13233                                         }
13234                                 }
13235                         }
13236                         break;
13237                 case 2:
13238                         p = party_search(check_ID);
13239                         if(p){
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);
13243                                         }
13244                                 }
13245                         }
13246                         break;
13247                 default:
13248                         map_foreachinmap(buildin_areawarp_sub,m,BL_PC,index,x,y,0,0);
13249                         break;
13250         }
13251         return SCRIPT_CMD_SUCCESS;
13252 }
13253
13254 static int buildin_mobcount_sub(struct block_list *bl,va_list ap)       // Added by RoVeRT
13255 {
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) )
13259                 return 1;
13260         return SCRIPT_CMD_SUCCESS;
13261 }
13262
13263 BUILDIN_FUNC(mobcount)  // Added by RoVeRT
13264 {
13265         const char *mapname,*event;
13266         int16 m;
13267         mapname=script_getstr(st,2);
13268         event=script_getstr(st,3);
13269
13270         if( strcmp(event, "all") == 0 )
13271                 event = NULL;
13272         else
13273                 check_event(st, event);
13274
13275         if( strcmp(mapname, "this") == 0 ) {
13276                 struct map_session_data *sd;
13277                 if( script_rid2sd(sd) )
13278                         m = sd->bl.m;
13279                 else {
13280                         script_pushint(st,-1);
13281                         return SCRIPT_CMD_SUCCESS;
13282                 }
13283         }
13284         else if( (m = map_mapname2mapid(mapname)) < 0 ) {
13285                 script_pushint(st,-1);
13286                 return SCRIPT_CMD_SUCCESS;
13287         }
13288
13289         script_pushint(st,map_foreachinmap(buildin_mobcount_sub, m, BL_MOB, event));
13290         return SCRIPT_CMD_SUCCESS;
13291 }
13292
13293 BUILDIN_FUNC(marriage)
13294 {
13295         TBL_PC *sd;
13296         TBL_PC *p_sd;
13297
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;
13301         }
13302         script_pushint(st,1);
13303         return SCRIPT_CMD_SUCCESS;
13304 }
13305
13306 BUILDIN_FUNC(wedding_effect)
13307 {
13308         TBL_PC *sd;
13309         struct block_list *bl;
13310
13311         if(!script_rid2sd(sd)) {
13312                 bl=map_id2bl(st->oid);
13313         } else
13314                 bl=&sd->bl;
13315         clif_wedding_effect(bl);
13316         return SCRIPT_CMD_SUCCESS;
13317 }
13318
13319 /**
13320  * divorce({<char_id>})
13321  **/
13322 BUILDIN_FUNC(divorce)
13323 {
13324         TBL_PC *sd;
13325
13326         if (!script_charid2sd(2,sd) || !pc_divorce(sd)) {
13327                 script_pushint(st,0);
13328                 return SCRIPT_CMD_FAILURE;
13329         }
13330         script_pushint(st,1);
13331         return SCRIPT_CMD_SUCCESS;
13332 }
13333
13334 /**
13335  * ispartneron({<char_id>})
13336  **/
13337 BUILDIN_FUNC(ispartneron)
13338 {
13339         TBL_PC *sd;
13340
13341         if (!script_charid2sd(2,sd) || !pc_ismarried(sd) ||
13342                 map_charid2sd(sd->status.partner_id) == NULL)
13343         {
13344                 script_pushint(st,0);
13345                 return SCRIPT_CMD_FAILURE;
13346         }
13347
13348         script_pushint(st,1);
13349         return SCRIPT_CMD_SUCCESS;
13350 }
13351
13352 /**
13353  * getpartnerid({<char_id>})
13354  **/
13355 BUILDIN_FUNC(getpartnerid)
13356 {
13357         TBL_PC *sd;
13358
13359         if (!script_charid2sd(2,sd)) {
13360                 script_pushint(st,0);
13361                 return SCRIPT_CMD_FAILURE;
13362         }
13363
13364         script_pushint(st,sd->status.partner_id);
13365         return SCRIPT_CMD_SUCCESS;
13366 }
13367
13368 /**
13369  * getchildid({<char_id>})
13370  **/
13371 BUILDIN_FUNC(getchildid)
13372 {
13373         TBL_PC *sd;
13374
13375         if (!script_charid2sd(2,sd)) {
13376                 script_pushint(st,0);
13377                 return SCRIPT_CMD_FAILURE;
13378         }
13379
13380         script_pushint(st,sd->status.child);
13381         return SCRIPT_CMD_SUCCESS;
13382 }
13383
13384 /**
13385  * getmotherid({<char_id>})
13386  **/
13387 BUILDIN_FUNC(getmotherid)
13388 {
13389         TBL_PC *sd;
13390
13391         if (!script_charid2sd(2,sd)) {
13392                 script_pushint(st,0);
13393                 return SCRIPT_CMD_FAILURE;
13394         }
13395
13396         script_pushint(st,sd->status.mother);
13397         return SCRIPT_CMD_SUCCESS;
13398 }
13399
13400 /**
13401  * getfatherid({<char_id>})
13402  **/
13403 BUILDIN_FUNC(getfatherid)
13404 {
13405         TBL_PC *sd;
13406
13407         if (!script_charid2sd(2,sd)) {
13408                 script_pushint(st,0);
13409                 return SCRIPT_CMD_FAILURE;
13410         }
13411
13412         script_pushint(st,sd->status.father);
13413         return SCRIPT_CMD_SUCCESS;
13414 }
13415
13416 BUILDIN_FUNC(warppartner)
13417 {
13418         int x,y;
13419         unsigned short mapindex;
13420         const char *str;
13421         TBL_PC *sd;
13422         TBL_PC *p_sd;
13423
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;
13428         }
13429
13430         str=script_getstr(st,2);
13431         x=script_getnum(st,3);
13432         y=script_getnum(st,4);
13433
13434         mapindex = mapindex_name2id(str);
13435         if (mapindex) {
13436                 pc_setpos(p_sd,mapindex,x,y,CLR_OUTSIGHT);
13437                 script_pushint(st,1);
13438         } else
13439                 script_pushint(st,0);
13440         return SCRIPT_CMD_SUCCESS;
13441 }
13442
13443 /*================================================
13444  * Script for Displaying MOB Information [Valaris]
13445  *------------------------------------------------*/
13446 BUILDIN_FUNC(strmobinfo)
13447 {
13448
13449         int num=script_getnum(st,2);
13450         int class_=script_getnum(st,3);
13451
13452         if(!mobdb_checkid(class_))
13453         {
13454                 if (num < 3) //requested a string
13455                         script_pushconststr(st,"");
13456                 else
13457                         script_pushint(st,0);
13458                 return SCRIPT_CMD_SUCCESS;
13459         }
13460
13461         switch (num) {
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;
13469         default:
13470                 script_pushint(st,0);
13471                 break;
13472         }
13473         return SCRIPT_CMD_SUCCESS;
13474 }
13475
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)
13481 {
13482         int class_=0,x=0,y=0,guardian=0;
13483         const char *str,*mapname,*evt="";
13484         bool has_index = false;
13485
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);
13491
13492         if( script_hasdata(st,8) )
13493         {// "<event label>",<guardian index>
13494                 evt=script_getstr(st,7);
13495                 guardian=script_getnum(st,8);
13496                 has_index = true;
13497         } else if( script_hasdata(st,7) ){
13498                 struct script_data *data = script_getdata(st,7);
13499                 get_val(st,data);
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);
13506                         has_index = true;
13507                 } else {
13508                         ShowError("script:guardian: invalid data type for argument #6 (from 1)\n");
13509                         script_reportdata(data);
13510                         return SCRIPT_CMD_FAILURE;
13511                 }
13512         }
13513
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;
13517 }
13518
13519 /*==========================================
13520  * Invisible Walls [Zephyrus]
13521  *------------------------------------------*/
13522 BUILDIN_FUNC(setwall)
13523 {
13524         const char *mapname, *name;
13525         int x, y, m, size, dir;
13526         bool shootable;
13527
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);
13535
13536         if( (m = map_mapname2mapid(mapname)) < 0 )
13537                 return SCRIPT_CMD_SUCCESS; // Invalid Map
13538
13539         map_iwall_set(m, x, y, size, dir, shootable, name);
13540         return SCRIPT_CMD_SUCCESS;
13541 }
13542
13543 BUILDIN_FUNC(delwall)
13544 {
13545         const char *name = script_getstr(st,2);
13546         map_iwall_remove(name);
13547         return SCRIPT_CMD_SUCCESS;
13548 }
13549
13550 /// Retrieves various information about the specified guardian.
13551 ///
13552 /// guardianinfo("<map_name>", <index>, <type>) -> <value>
13553 /// type: 0 - whether it is deployed or not
13554 ///       1 - maximum hp
13555 ///       2 - current hp
13556 ///
13557 BUILDIN_FUNC(guardianinfo)
13558 {
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);
13562
13563         struct guild_castle* gc = guild_mapname2gc(mapname);
13564         struct mob_data* gd;
13565
13566         if( gc == NULL || id < 0 || id >= MAX_GUARDIANS )
13567         {
13568                 script_pushint(st,-1);
13569                 return SCRIPT_CMD_SUCCESS;
13570         }
13571
13572         if( type == 0 )
13573                 script_pushint(st, gc->guardian[id].visible);
13574         else
13575         if( !gc->guardian[id].visible )
13576                 script_pushint(st,-1);
13577         else
13578         if( (gd = map_id2md(gc->guardian[id].id)) == NULL )
13579                 script_pushint(st,-1);
13580         else
13581         {
13582                 if     ( type == 1 ) script_pushint(st,gd->status.max_hp);
13583                 else if( type == 2 ) script_pushint(st,gd->status.hp);
13584                 else
13585                         script_pushint(st,-1);
13586         }
13587         return SCRIPT_CMD_SUCCESS;
13588 }
13589
13590 /*==========================================
13591  * Get the item name by item_id or null
13592  *------------------------------------------*/
13593 BUILDIN_FUNC(getitemname)
13594 {
13595         unsigned short item_id = 0;
13596         struct item_data *i_data;
13597         char *item_name;
13598         struct script_data *data;
13599
13600         data=script_getdata(st,2);
13601         get_val(st,data);
13602
13603         if( data_isstring(data) ){
13604                 const char *name=conv_str(st,data);
13605                 struct item_data *item_data = itemdb_searchname(name);
13606                 if( item_data )
13607                         item_id=item_data->nameid;
13608         }else
13609                 item_id=conv_num(st,data);
13610
13611         i_data = itemdb_exists(item_id);
13612         if (i_data == NULL)
13613         {
13614                 script_pushconststr(st,"null");
13615                 return SCRIPT_CMD_SUCCESS;
13616         }
13617         item_name=(char *)aMalloc(ITEM_NAME_LENGTH*sizeof(char));
13618
13619         memcpy(item_name, i_data->jname, ITEM_NAME_LENGTH);
13620         script_pushstr(st,item_name);
13621         return SCRIPT_CMD_SUCCESS;
13622 }
13623
13624 /*==========================================
13625  * Returns number of slots an item has. [Skotlex]
13626  *------------------------------------------*/
13627 BUILDIN_FUNC(getitemslots)
13628 {
13629         unsigned short item_id;
13630         struct item_data *i_data;
13631
13632         item_id=script_getnum(st,2);
13633
13634         i_data = itemdb_exists(item_id);
13635
13636         if (i_data)
13637                 script_pushint(st,i_data->slot);
13638         else
13639                 script_pushint(st,-1);
13640         return SCRIPT_CMD_SUCCESS;
13641 }
13642
13643 // TODO: add matk here if needed/once we get rid of RENEWAL
13644
13645 /*==========================================
13646  * Returns some values of an item [Lupus]
13647  * Price, Weight, etc...
13648         getiteminfo(itemID,n), where n
13649                 0 value_buy;
13650                 1 value_sell;
13651                 2 type;
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
13655                 4 sex;
13656                 5 equip;
13657                 6 weight;
13658                 7 atk;
13659                 8 def;
13660                 9 range;
13661                 10 slot;
13662                 11 look;
13663                 12 elv;
13664                 13 wlv;
13665                 14 view id
13666                 15 eLvmax
13667                 16 matk (renewal)
13668  *------------------------------------------*/
13669 BUILDIN_FUNC(getiteminfo)
13670 {
13671         unsigned short item_id,n;
13672         struct item_data *i_data;
13673
13674         item_id = script_getnum(st,2);
13675         n       = script_getnum(st,3);
13676         i_data = itemdb_exists(item_id);
13677
13678         if (i_data && n <= 16) {
13679                 int *item_arr = (int*)&i_data->value_buy;
13680 #ifndef RENEWAL
13681                 if (n == 16)
13682                         script_pushint(st,0);
13683                 else
13684 #endif
13685                 script_pushint(st,item_arr[n]);
13686         } else
13687                 script_pushint(st,-1);
13688         return SCRIPT_CMD_SUCCESS;
13689 }
13690
13691 /*==========================================
13692  * Set some values of an item [Lupus]
13693  * Price, Weight, etc...
13694         setiteminfo(itemID,n,Value), where n
13695                 0 value_buy;
13696                 1 value_sell;
13697                 2 type;
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
13701                 4 sex;
13702                 5 equip;
13703                 6 weight;
13704                 7 atk;
13705                 8 def;
13706                 9 range;
13707                 10 slot;
13708                 11 look;
13709                 12 elv;
13710                 13 wlv;
13711                 14 view id
13712   * Returns Value or -1 if the wrong field's been set
13713  *------------------------------------------*/
13714 BUILDIN_FUNC(setiteminfo)
13715 {
13716         unsigned short item_id;
13717         int n,value;
13718         struct item_data *i_data;
13719
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);
13724
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);
13729         } else
13730                 script_pushint(st,-1);
13731         return SCRIPT_CMD_SUCCESS;
13732 }
13733
13734 /*==========================================
13735  * Returns value from equipped item slot n [Lupus]
13736         getequipcardid(num,slot)
13737         where
13738                 num = eqip position slot
13739                 slot = 0,1,2,3 (Card Slot N)
13740
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)
13747 {
13748         int i=-1,num,slot;
13749         TBL_PC *sd;
13750
13751         if( !script_rid2sd(sd) )
13752                 return SCRIPT_CMD_SUCCESS;
13753
13754         num=script_getnum(st,2);
13755         slot=script_getnum(st,3);
13756
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]);
13761         else
13762                 script_pushint(st,0);
13763         return SCRIPT_CMD_SUCCESS;
13764 }
13765
13766 /*==========================================
13767  * petskillbonus [Valaris] //Rewritten by [Skotlex]
13768  *------------------------------------------*/
13769 BUILDIN_FUNC(petskillbonus)
13770 {
13771         struct pet_data *pd;
13772         TBL_PC *sd;
13773
13774         if(!script_rid2sd(sd) || sd->pd == NULL)
13775                 return SCRIPT_CMD_FAILURE;
13776
13777         pd = sd->pd;
13778         if (pd->bonus)
13779         { //Clear previous bonus
13780                 if (pd->bonus->timer != INVALID_TIMER)
13781                         delete_timer(pd->bonus->timer, pet_skill_bonus_timer);
13782         } else //init
13783                 pd->bonus = (struct pet_bonus *) aMalloc(sizeof(struct pet_bonus));
13784
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);
13789
13790         if (pd->state.skillbonus == 1)
13791                 pd->state.skillbonus = 0;       // waiting state
13792
13793         // wait for timer to start
13794         if (battle_config.pet_equip_required && pd->pet.equip == 0)
13795                 pd->bonus->timer = INVALID_TIMER;
13796         else
13797                 pd->bonus->timer = add_timer(gettick()+pd->bonus->delay*1000, pet_skill_bonus_timer, sd->bl.id, 0);
13798         return SCRIPT_CMD_SUCCESS;
13799 }
13800
13801 /*==========================================
13802  * pet looting [Valaris] //Rewritten by [Skotlex]
13803  *------------------------------------------*/
13804 BUILDIN_FUNC(petloot)
13805 {
13806         int max;
13807         struct pet_data *pd;
13808         TBL_PC *sd;
13809
13810         if(!script_rid2sd(sd) || sd->pd==NULL)
13811                 return SCRIPT_CMD_SUCCESS;
13812
13813         max=script_getnum(st,2);
13814
13815         if(max < 1)
13816                 max = 1;        //Let'em loot at least 1 item.
13817         else if (max > MAX_PETLOOT_SIZE)
13818                 max = MAX_PETLOOT_SIZE;
13819
13820         pd = sd->pd;
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);
13825         }
13826         else
13827                 pd->loot = (struct pet_loot *)aMalloc(sizeof(struct pet_loot));
13828
13829         pd->loot->item = (struct item *)aCalloc(max,sizeof(struct item));
13830
13831         pd->loot->max=max;
13832         pd->loot->count = 0;
13833         pd->loot->weight = 0;
13834         return SCRIPT_CMD_SUCCESS;
13835 }
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)
13844 {
13845         TBL_PC *sd;
13846         char card_var[NAME_LENGTH];
13847         int i,j=0,k;
13848
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++)
13860                         {
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]);
13863                         }
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);
13866                         j++;
13867                 }
13868         }
13869         pc_setreg(sd,add_str("@inventorylist_count"),j);
13870         return SCRIPT_CMD_SUCCESS;
13871 }
13872
13873 /**
13874  * getskilllist ({<char_id>});
13875  **/
13876 BUILDIN_FUNC(getskilllist)
13877 {
13878         TBL_PC *sd;
13879         int i,j=0;
13880
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);
13888                         j++;
13889                 }
13890         }
13891         pc_setreg(sd,add_str("@skilllist_count"),j);
13892         return SCRIPT_CMD_SUCCESS;
13893 }
13894
13895 /**
13896  * clearitem ({<char_id>});
13897  **/
13898 BUILDIN_FUNC(clearitem)
13899 {
13900         TBL_PC *sd;
13901         int i;
13902
13903         if (!script_charid2sd(2,sd))
13904                 return SCRIPT_CMD_FAILURE;
13905
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);
13909                 }
13910         }
13911         return SCRIPT_CMD_SUCCESS;
13912 }
13913
13914 /**
13915  * Disguise Player (returns Mob/NPC ID if success, 0 on fail)
13916  * disguise <Monster ID>{,<char_id>};
13917  **/
13918 BUILDIN_FUNC(disguise)
13919 {
13920         int id;
13921         TBL_PC* sd;
13922
13923         if (!script_charid2sd(3,sd))
13924                 return SCRIPT_CMD_FAILURE;
13925
13926         id = script_getnum(st,2);
13927
13928         if (mobdb_checkid(id) || npcdb_checkid(id)) {
13929                 pc_disguise(sd, id);
13930                 script_pushint(st,id);
13931         } else
13932                 script_pushint(st,0);
13933         return SCRIPT_CMD_SUCCESS;
13934 }
13935
13936 /**
13937  * Undisguise Player (returns 1 if success, 0 on fail)
13938  * undisguise {<char_id>};
13939  **/
13940 BUILDIN_FUNC(undisguise)
13941 {
13942         TBL_PC* sd;
13943
13944         if (!script_charid2sd(2,sd))
13945                 return SCRIPT_CMD_FAILURE;
13946
13947         if (sd->disguise) {
13948                 pc_disguise(sd, 0);
13949                 script_pushint(st,0);
13950         } else {
13951                 script_pushint(st,1);
13952         }
13953         return SCRIPT_CMD_SUCCESS;
13954 }
13955
13956  /**
13957  * Transform an NPC to another _class
13958  *
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.
13963  */
13964 BUILDIN_FUNC(classchange)
13965 {
13966         int _class, type = 1;
13967         struct npc_data* nd = NULL;
13968         TBL_PC *sd = map_id2sd(st->rid);
13969         send_target target = AREA;
13970
13971         _class = script_getnum(st,2);
13972
13973         if (script_hasdata(st, 3) && strlen(script_getstr(st,3)) > 0)
13974                 nd = npc_name2id(script_getstr(st, 3));
13975         else
13976                 nd = (struct npc_data *)map_id2bl(st->oid);
13977
13978         if (nd == NULL)
13979                 return SCRIPT_CMD_FAILURE;
13980
13981         if (script_hasdata(st, 4)) {
13982                 switch(script_getnum(st, 4)) {
13983                         case BC_SELF:   target = SELF;                  break;
13984                         case BC_AREA:
13985                         default:                target = AREA;                  break;
13986                 }
13987         }
13988         if (target != SELF)
13989                 clif_class_change(&nd->bl,_class,type);
13990         else if (sd == NULL)
13991                 return SCRIPT_CMD_FAILURE;
13992         else
13993                 clif_class_change_target(&nd->bl,_class,type,target,sd);
13994
13995         return SCRIPT_CMD_SUCCESS;
13996 }
13997
13998 /*==========================================
13999  * Display an effect
14000  *------------------------------------------*/
14001 BUILDIN_FUNC(misceffect)
14002 {
14003         int type;
14004
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);
14008                 if (bl)
14009                         clif_specialeffect(bl,type,AREA);
14010         } else{
14011                 TBL_PC *sd;
14012                 if(script_rid2sd(sd))
14013                         clif_specialeffect(&sd->bl,type,AREA);
14014         }
14015         return SCRIPT_CMD_SUCCESS;
14016 }
14017 /*==========================================
14018  * Play a BGM on a single client [Rikter/Yommy]
14019  *------------------------------------------*/
14020 BUILDIN_FUNC(playBGM)
14021 {
14022         struct map_session_data* sd;
14023
14024         if( script_rid2sd(sd) ) {
14025                 clif_playBGM(sd, script_getstr(st,2));
14026         }
14027         return SCRIPT_CMD_SUCCESS;
14028 }
14029
14030 static int playBGM_sub(struct block_list* bl,va_list ap)
14031 {
14032         const char* name = va_arg(ap,const char*);
14033         clif_playBGM(BL_CAST(BL_PC, bl), name);
14034         return 0;
14035 }
14036
14037 static int playBGM_foreachpc_sub(struct map_session_data* sd, va_list args)
14038 {
14039         const char* name = va_arg(args, const char*);
14040         clif_playBGM(sd, name);
14041         return 0;
14042 }
14043
14044 /*==========================================
14045  * Play a BGM on multiple client [Rikter/Yommy]
14046  *------------------------------------------*/
14047 BUILDIN_FUNC(playBGMall)
14048 {
14049         const char* name;
14050         name = script_getstr(st,2);
14051
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);
14058
14059                 map_foreachinallarea(playBGM_sub, map_mapname2mapid(mapname), x0, y0, x1, y1, BL_PC, name);
14060         }
14061         else if( script_hasdata(st,3) ) {// entire map
14062                 const char* mapname = script_getstr(st,3);
14063
14064                 map_foreachinmap(playBGM_sub, map_mapname2mapid(mapname), BL_PC, name);
14065         }
14066         else {// entire server
14067                 map_foreachpc(&playBGM_foreachpc_sub, name);
14068         }
14069         return SCRIPT_CMD_SUCCESS;
14070 }
14071
14072 /*==========================================
14073  * Play a .wav sound for sd
14074  *------------------------------------------*/
14075 BUILDIN_FUNC(soundeffect)
14076 {
14077         TBL_PC* sd;
14078
14079         if(script_rid2sd(sd)){
14080                 const char* name = script_getstr(st,2);
14081                 int type = script_getnum(st,3);
14082
14083                 clif_soundeffect(sd,&sd->bl,name,type);
14084         }
14085         return SCRIPT_CMD_SUCCESS;
14086 }
14087
14088 int soundeffect_sub(struct block_list* bl,va_list ap)
14089 {
14090         char* name = va_arg(ap,char*);
14091         int type = va_arg(ap,int);
14092
14093         clif_soundeffect((TBL_PC *)bl, bl, name, type);
14094
14095         return 0;
14096 }
14097
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)
14103 {
14104         struct block_list* bl;
14105         struct map_session_data* sd;
14106         const char* name;
14107         int type;
14108
14109         if( st->rid && script_rid2sd(sd) )
14110                 bl = &sd->bl;
14111         else
14112                 bl = map_id2bl(st->oid);
14113
14114         if (!bl)
14115                 return SCRIPT_CMD_SUCCESS;
14116
14117         name = script_getstr(st,2);
14118         type = script_getnum(st,3);
14119
14120         //FIXME: enumerating map squares (map_foreach) is slower than enumerating the list of online players (map_foreachpc?) [ultramage]
14121
14122         if(!script_hasdata(st,4))
14123         {       // area around
14124                 clif_soundeffectall(bl, name, type, AREA);
14125         }
14126         else
14127         if(!script_hasdata(st,5))
14128         {       // entire map
14129                 const char* mapname = script_getstr(st,4);
14130                 map_foreachinmap(soundeffect_sub, map_mapname2mapid(mapname), BL_PC, name, type);
14131         }
14132         else
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);
14141         }
14142         else
14143         {
14144                 ShowError("buildin_soundeffectall: insufficient arguments for specific area broadcast.\n");
14145         }
14146         return SCRIPT_CMD_SUCCESS;
14147 }
14148 /*==========================================
14149  * pet status recovery [Valaris] / Rewritten by [Skotlex]
14150  *------------------------------------------*/
14151 BUILDIN_FUNC(petrecovery)
14152 {
14153         struct pet_data *pd;
14154         TBL_PC *sd;
14155         int sc;
14156
14157         if(!script_rid2sd(sd) || sd->pd == NULL)
14158                 return SCRIPT_CMD_FAILURE;
14159
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;
14164         }
14165
14166         pd = sd->pd;
14167
14168         if (pd->recovery)
14169         { //Halt previous bonus
14170                 if (pd->recovery->timer != INVALID_TIMER)
14171                         delete_timer(pd->recovery->timer, pet_recovery_timer);
14172         } else //Init
14173                 pd->recovery = (struct pet_recovery *)aMalloc(sizeof(struct pet_recovery));
14174
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;
14179 }
14180
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)
14187 {
14188         struct pet_data *pd;
14189         struct script_data *data;
14190         TBL_PC *sd;
14191         int id = 0;
14192
14193         if(!script_rid2sd(sd) || sd->pd == NULL)
14194                 return SCRIPT_CMD_FAILURE;
14195
14196         data = script_getdata(st, 2);
14197         get_val(st, data);
14198         id = (data_isstring(data) ? skill_name2id(script_getstr(st,2)) : skill_get_index(script_getnum(st,2)));
14199         if (!id) {
14200                 ShowError("buildin_petskillattack: Invalid skill defined!\n");
14201                 return SCRIPT_CMD_FAILURE;
14202         }
14203
14204         pd = sd->pd;
14205         if (pd->a_skill == NULL)
14206                 pd->a_skill = (struct pet_skill_attack *)aMalloc(sizeof(struct pet_skill_attack));
14207
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;
14215 }
14216
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)
14223 {
14224         struct pet_data *pd;
14225         struct script_data *data;
14226         TBL_PC *sd;
14227         int id = 0;
14228
14229         if(!script_rid2sd(sd) || sd->pd == NULL)
14230                 return SCRIPT_CMD_FAILURE;
14231
14232         data = script_getdata(st, 2);
14233         get_val(st, data);
14234         id = (data_isstring(data) ? skill_name2id(script_getstr(st,2)) : skill_get_index(script_getnum(st,2)));
14235         if (!id) {
14236                 ShowError("buildin_petskillattack2: Invalid skill defined!\n");
14237                 return SCRIPT_CMD_FAILURE;
14238         }
14239
14240         pd = sd->pd;
14241         if (pd->a_skill == NULL)
14242                 pd->a_skill = (struct pet_skill_attack *)aMalloc(sizeof(struct pet_skill_attack));
14243
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;
14251 }
14252
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)
14259 {
14260         struct pet_data *pd;
14261         struct script_data *data;
14262         TBL_PC *sd;
14263         int id = 0;
14264
14265         if(!script_rid2sd(sd) || sd->pd == NULL)
14266                 return SCRIPT_CMD_FAILURE;
14267
14268         data = script_getdata(st, 2);
14269         get_val(st, data);
14270         id = (data_isstring(data) ? skill_name2id(script_getstr(st,2)) : skill_get_index(script_getnum(st,2)));
14271         if (!id) {
14272                 ShowError("buildin_petskillsupport: Invalid skill defined!\n");
14273                 return SCRIPT_CMD_FAILURE;
14274         }
14275
14276         pd = sd->pd;
14277         if (pd->s_skill)
14278         { //Clear previous skill
14279                 if (pd->s_skill->timer != INVALID_TIMER)
14280                 {
14281                         if (pd->s_skill->id)
14282                                 delete_timer(pd->s_skill->timer, pet_skill_support_timer);
14283                         else
14284                                 delete_timer(pd->s_skill->timer, pet_heal_timer);
14285                 }
14286         } else //init memory
14287                 pd->s_skill = (struct pet_skill_support *) aMalloc(sizeof(struct pet_skill_support));
14288
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);
14294
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;
14298         else
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;
14301 }
14302
14303 /*==========================================
14304  * Scripted skill effects [Celest]
14305  *------------------------------------------*/
14306 /// skilleffect <skill id>,<level>
14307 /// skilleffect "<skill name>",<level>
14308 BUILDIN_FUNC(skilleffect)
14309 {
14310         TBL_PC *sd;
14311         uint16 skill_id, skill_lv;
14312         struct script_data *data;
14313         
14314         if( !script_rid2sd(sd) )
14315                 return SCRIPT_CMD_SUCCESS;
14316         
14317         data = script_getdata(st, 2);
14318
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);
14322
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) ) {
14326                 skill_sit(sd, 0);
14327                 clif_standing(&sd->bl);
14328         }
14329
14330         clif_skill_nodamage(&sd->bl,&sd->bl,skill_id,skill_lv,1);
14331         return SCRIPT_CMD_SUCCESS;
14332 }
14333
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)
14340 {
14341         struct block_list *bl= map_id2bl(st->oid);
14342         uint16 skill_id, skill_lv;
14343         int x, y;
14344         struct script_data *data = script_getdata(st, 2);
14345
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);
14351
14352         if (bl)
14353                 clif_skill_poseffect(bl,skill_id,skill_lv,x,y,gettick());
14354         return SCRIPT_CMD_SUCCESS;
14355 }
14356
14357 /*==========================================
14358  * Special effects [Valaris]
14359  *------------------------------------------*/
14360 BUILDIN_FUNC(specialeffect)
14361 {
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;
14365
14366         if(bl==NULL)
14367                 return SCRIPT_CMD_SUCCESS;
14368
14369         if( script_hasdata(st,4) )
14370         {
14371                 TBL_NPC *nd = npc_name2id(script_getstr(st,4));
14372                 if(nd)
14373                         clif_specialeffect(&nd->bl, type, target);
14374         }
14375         else
14376         {
14377                 if (target == SELF) {
14378                         TBL_PC *sd;
14379                         if (script_rid2sd(sd))
14380                                 clif_specialeffect_single(bl,type,sd->fd);
14381                 } else {
14382                         clif_specialeffect(bl, type, target);
14383                 }
14384         }
14385         return SCRIPT_CMD_SUCCESS;
14386 }
14387
14388 BUILDIN_FUNC(specialeffect2)
14389 {
14390         TBL_PC *sd;
14391
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;
14395
14396                 clif_specialeffect(&sd->bl, type, target);
14397         }
14398         return SCRIPT_CMD_SUCCESS;
14399 }
14400
14401 /**
14402  * nude({<char_id>});
14403  * @author [Valaris]
14404  **/
14405 BUILDIN_FUNC(nude)
14406 {
14407         TBL_PC *sd;
14408         int i, calcflag = 0;
14409
14410         if (!script_charid2sd(2,sd))
14411                 return SCRIPT_CMD_FAILURE;
14412
14413         for( i = 0 ; i < EQI_MAX; i++ ) {
14414                 if( sd->equip_index[ i ] >= 0 ) {
14415                         if( !calcflag )
14416                                 calcflag = 1;
14417                         pc_unequipitem( sd , sd->equip_index[ i ] , 2);
14418                 }
14419         }
14420
14421         if( calcflag )
14422                 status_calc_pc(sd,SCO_NONE);
14423         return SCRIPT_CMD_SUCCESS;
14424 }
14425
14426 int atcommand_sub(struct script_state* st,int type) {
14427         TBL_PC *sd, dummy_sd;
14428         int fd;
14429         const char *cmd;
14430
14431         cmd = script_getstr(st,2);
14432
14433         if (st->rid) {
14434                 if( !script_rid2sd(sd) )
14435                         return SCRIPT_CMD_SUCCESS;
14436
14437                 fd = sd->fd;
14438         } else { //Use a dummy character.
14439                 sd = &dummy_sd;
14440                 fd = 0;
14441
14442                 memset(&dummy_sd, 0, sizeof(TBL_PC));
14443                 if (st->oid) {
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);
14449                 }
14450
14451                 // Init Group ID, Level, & permissions
14452                 sd->group_id = sd->group_level = 99;
14453                 sd->permissions |= PC_PERM_ALLPERMISSION;
14454         }
14455
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;
14460         }
14461         return SCRIPT_CMD_SUCCESS;
14462 }
14463
14464 /*==========================================
14465  * gmcommand [MouseJstr]
14466  *------------------------------------------*/
14467 BUILDIN_FUNC(atcommand) {
14468         return atcommand_sub(st,0);
14469 }
14470
14471 /** Displays a message for the player only (like system messages like "you got an apple" )
14472 * dispbottom("<message>"{,<color>{,<char_id>}})
14473 * @param message 
14474 * @param color Hex color default (Green)
14475 */
14476 BUILDIN_FUNC(dispbottom)
14477 {
14478         TBL_PC *sd;
14479         int color = 0;
14480         const char *message;
14481
14482         if (!script_charid2sd(4,sd))
14483                 return SCRIPT_CMD_FAILURE;
14484
14485         message = script_getstr(st,2);
14486
14487         if (script_hasdata(st,3))
14488                 color = script_getnum(st,3); // <color>
14489
14490         if(sd) {
14491                 if (script_hasdata(st,3))
14492                         clif_messagecolor(&sd->bl, color, message, true, SELF);         // [Napster]
14493                 else
14494                         clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], message, false, SELF);
14495         }
14496         return SCRIPT_CMD_SUCCESS;
14497 }
14498
14499 /*===================================
14500  * Heal portion of recovery command
14501  *-----------------------------------*/
14502 int recovery_sub(struct map_session_data* sd, int revive)
14503 {
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!
14511         }
14512         return SCRIPT_CMD_SUCCESS;
14513 }
14514
14515 /*=========================================================================
14516  * Fully Recover a Character's HP/SP - [Capuche] & [Akinari]
14517  * recovery <type>{,<option>,<revive_flag>{,<map name>}};
14518  * <type> determines <option>:
14519  *      0 : char_id
14520  *      1 : party_id
14521  *      2 : guild_id
14522  *      3 : map_name
14523  *      4 : all characters
14524  * <revive_flag>:
14525  *      1 : Revive and heal all players (default)
14526  *      2 : Heal living players only
14527  *      4 : Revive dead players only
14528  * <map name>:
14529  *      for types 1-2 : map_name (null = all maps)
14530  *-------------------------------------------------------------------------*/
14531 BUILDIN_FUNC(recovery)
14532 {
14533         TBL_PC *sd;
14534         int map_idx = 0, type = 0, revive = 1;
14535
14536         type = script_getnum(st,2);
14537
14538         if(script_hasdata(st,4))
14539                 revive = script_getnum(st,4);
14540
14541         switch(type) {
14542                 case 0:
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);
14546                         break;
14547                 case 1:
14548                 {
14549                         struct party_data* p;
14550                         //When no party given, we use invoker party
14551                         int p_id = 0, i;
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;
14557                                 }
14558                         }
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);
14564                         if(p == NULL)
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))
14570                                         continue;
14571                                 recovery_sub(pl_sd, revive);
14572                         }
14573                         break;
14574                 }
14575                 case 2:
14576                 {
14577                         struct guild* g;
14578                         //When no guild given, we use invoker guild
14579                         int g_id = 0, i;
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;
14585                                 }
14586                         }
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);
14592                         if(g == NULL)
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))
14598                                         continue;
14599                                 recovery_sub(pl_sd, revive);
14600                         }
14601                         break;
14602                 }
14603                 case 3:
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;
14608                         if(map_idx < 1)
14609                                 return SCRIPT_CMD_FAILURE; //No sd and no map given - return
14610                 case 4:
14611                 {
14612                         struct s_mapiterator *iter;
14613                         struct script_data *data = script_getdata(st, 3);
14614
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)
14621                                         continue;
14622                                 recovery_sub(sd, revive);
14623                         }
14624                         mapit_free(iter);
14625                         break;
14626                 }
14627                 default:
14628                         ShowWarning("script: buildin_recovery: Invalid type %d\n", type);
14629                         script_pushint(st,-1);
14630                         return SCRIPT_CMD_FAILURE;
14631         }
14632         script_pushint(st,1); //Successfully executed without errors
14633         return SCRIPT_CMD_SUCCESS;
14634 }
14635
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,
14640  * 7:game id
14641  *------------------------------------------*/
14642 BUILDIN_FUNC(getpetinfo)
14643 {
14644         TBL_PC *sd;
14645         TBL_PET *pd;
14646         int type = script_getnum(st,2);
14647
14648         if (!script_charid2sd(3, sd) || !(pd = sd->pd)) {
14649                 if (type == 2)
14650                         script_pushconststr(st,"null");
14651                 else
14652                         script_pushint(st,0);
14653                 return SCRIPT_CMD_SUCCESS;
14654         }
14655
14656         switch(type){
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;
14665                 default:
14666                         script_pushint(st,0);
14667                         break;
14668         }
14669         return SCRIPT_CMD_SUCCESS;
14670 }
14671
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)
14679 {
14680         TBL_PC *sd;
14681         TBL_HOM *hd;
14682         int type=script_getnum(st,2);
14683
14684         if (!script_charid2sd(3, sd) || !(hd = sd->hd)) {
14685                 if (type == 2)
14686                         script_pushconststr(st,"null");
14687                 else
14688                         script_pushint(st,0);
14689                 return SCRIPT_CMD_SUCCESS;
14690         }
14691
14692         switch(type){
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;
14701                 default:
14702                         script_pushint(st,0);
14703                         break;
14704         }
14705         return SCRIPT_CMD_SUCCESS;
14706 }
14707
14708 /// Retrieves information about character's mercenary
14709 /// getmercinfo <type>[,<char id>];
14710 BUILDIN_FUNC(getmercinfo)
14711 {
14712         int type;
14713         struct map_session_data* sd;
14714         struct mercenary_data* md;
14715
14716         if( !script_charid2sd(3,sd) ){
14717                 script_pushnil(st);
14718                 return SCRIPT_CMD_FAILURE;
14719         }
14720
14721         type = script_getnum(st,2);
14722         md = sd->md;
14723
14724         if( md == NULL ){
14725                 if( type == 2 )
14726                         script_pushconststr(st,"");
14727                 else
14728                         script_pushint(st,0);
14729                 return SCRIPT_CMD_SUCCESS;
14730         }
14731
14732         switch( type )
14733         {
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;
14743                 default:
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;
14747         }
14748
14749         return SCRIPT_CMD_SUCCESS;
14750 }
14751
14752 /*==========================================
14753  * Shows wether your inventory(and equips) contain
14754    selected card or not.
14755         checkequipedcard(4001);
14756  *------------------------------------------*/
14757 BUILDIN_FUNC(checkequipedcard)
14758 {
14759         TBL_PC *sd;
14760
14761         if(script_rid2sd(sd)){
14762                 int n,i,c=0;
14763                 c=script_getnum(st,2);
14764
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]))
14768                                         continue;
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;
14773                                         }
14774                                 }
14775                         }
14776                 }
14777         }
14778         script_pushint(st,0);
14779         return SCRIPT_CMD_SUCCESS;
14780 }
14781
14782 BUILDIN_FUNC(jump_zero)
14783 {
14784         int sel;
14785         sel=script_getnum(st,2);
14786         if(!sel) {
14787                 int pos;
14788                 if( !data_islabel(script_getdata(st,3)) ){
14789                         ShowError("script: jump_zero: not label !\n");
14790                         st->state=END;
14791                         return SCRIPT_CMD_FAILURE;
14792                 }
14793
14794                 pos=script_getnum(st,3);
14795                 st->pos=pos;
14796                 st->state=GOTO;
14797         }
14798         return SCRIPT_CMD_SUCCESS;
14799 }
14800
14801 /*==========================================
14802  * movenpc [MouseJstr]
14803  *------------------------------------------*/
14804 BUILDIN_FUNC(movenpc)
14805 {
14806         TBL_NPC *nd = NULL;
14807         const char *npc;
14808         int x,y;
14809
14810         npc = script_getstr(st,2);
14811         x = script_getnum(st,3);
14812         y = script_getnum(st,4);
14813
14814         if ((nd = npc_name2id(npc)) == NULL){
14815                 ShowError("script: movenpc: NPC with ID '%s' was not found!\n", npc );
14816                 return -1;
14817         }
14818
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;
14823 }
14824
14825 /*==========================================
14826  * message [MouseJstr]
14827  *------------------------------------------*/
14828 BUILDIN_FUNC(message)
14829 {
14830         const char *msg,*player;
14831         TBL_PC *pl_sd = NULL;
14832
14833         player = script_getstr(st,2);
14834         msg = script_getstr(st,3);
14835
14836         if((pl_sd=map_nick2sd((char *) player,false)) == NULL)
14837                 return SCRIPT_CMD_SUCCESS;
14838         clif_displaymessage(pl_sd->fd, msg);
14839
14840         return SCRIPT_CMD_SUCCESS;
14841 }
14842
14843 /**
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.
14850  */
14851 BUILDIN_FUNC(npctalk)
14852 {
14853         struct npc_data* nd = NULL;
14854         const char* str = script_getstr(st,2);
14855
14856         if (script_hasdata(st, 3) && strlen(script_getstr(st,3)) > 0)
14857                 nd = npc_name2id(script_getstr(st, 3));
14858         else
14859                 nd = (struct npc_data *)map_id2bl(st->oid);
14860
14861         if (nd != NULL) {
14862                 send_target target = AREA;
14863                 char message[CHAT_SIZE_MAX];
14864
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;
14870                                 case BC_AREA:
14871                                 default:                target = AREA;                  break;
14872                         }
14873                 }
14874                 safesnprintf(message, sizeof(message), "%s", str);
14875                 if (target != SELF)
14876                         clif_messagecolor(&nd->bl, color_table[COLOR_WHITE], message, false, target);
14877                 else {
14878                         TBL_PC *sd = map_id2sd(st->rid);
14879                         if (sd == NULL)
14880                                 return SCRIPT_CMD_FAILURE;
14881                         clif_messagecolor_target(&nd->bl, color_table[COLOR_WHITE], message, false, target, sd);
14882                 }
14883         }
14884         return SCRIPT_CMD_SUCCESS;
14885 }
14886
14887 /**
14888  * Sends a message to the waitingroom of the invoking NPC.
14889  * chatmes "<message>"{,"<NPC name>"};
14890  * @author Jey
14891  */
14892 BUILDIN_FUNC(chatmes)
14893 {
14894         struct npc_data* nd = NULL;
14895         const char* str = script_getstr(st,2);
14896
14897         if (script_hasdata(st, 3))
14898                 nd = npc_name2id(script_getstr(st, 3));
14899         else
14900                 nd = (struct npc_data *)map_id2bl(st->oid);
14901
14902         if (nd != NULL && nd->chat_id) {
14903                 char message[256];
14904                 safesnprintf(message, sizeof(message), "%s", str);
14905                 clif_GlobalMessage(map_id2bl(nd->chat_id), message, CHAT_WOS);
14906         }
14907         return SCRIPT_CMD_SUCCESS;
14908 }
14909
14910 // change npc walkspeed [Valaris]
14911 BUILDIN_FUNC(npcspeed)
14912 {
14913         struct npc_data* nd;
14914         int speed;
14915
14916         speed = script_getnum(st,2);
14917         nd =(struct npc_data *)map_id2bl(st->oid);
14918
14919         if( nd ) {
14920                 nd->speed = speed;
14921                 nd->ud.state.speed_changed = 1;
14922         }
14923
14924         return SCRIPT_CMD_SUCCESS;
14925 }
14926 // make an npc walk to a position [Valaris]
14927 BUILDIN_FUNC(npcwalkto)
14928 {
14929         struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid);
14930         int x=0,y=0;
14931
14932         x=script_getnum(st,2);
14933         y=script_getnum(st,3);
14934
14935         if(nd) {
14936                 if (!nd->status.hp)
14937                         status_calc_npc(nd, SCO_FIRST);
14938                 else
14939                         status_calc_npc(nd, SCO_NONE);
14940                 unit_walktoxy(&nd->bl,x,y,0);
14941         }
14942         return SCRIPT_CMD_SUCCESS;
14943 }
14944
14945 // stop an npc's movement [Valaris]
14946 BUILDIN_FUNC(npcstop)
14947 {
14948         struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid);
14949
14950         if(nd) {
14951                 unit_stop_walking(&nd->bl,1|4);
14952         }
14953         return SCRIPT_CMD_SUCCESS;
14954 }
14955
14956
14957 /**
14958  * getlook(<type>{,<char_id>})
14959  **/
14960 BUILDIN_FUNC(getlook)
14961 {
14962         int type,val;
14963         TBL_PC *sd;
14964
14965         if (!script_charid2sd(3,sd)) {
14966                 script_pushint(st,-1);
14967                 return SCRIPT_CMD_FAILURE;
14968         }
14969
14970         type=script_getnum(st,2);
14971         val=-1;
14972         switch(type) {
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
14985         }
14986
14987         script_pushint(st,val);
14988         return SCRIPT_CMD_SUCCESS;
14989 }
14990
14991 /**
14992  * getsavepoint(<information type>{,<char_id>})
14993  * @param type 0- map name, 1- x, 2- y
14994  **/
14995 BUILDIN_FUNC(getsavepoint)
14996 {
14997         TBL_PC* sd;
14998         int type;
14999
15000         if (!script_charid2sd(3,sd)) {
15001                 script_pushint(st,0);
15002                 return SCRIPT_CMD_SUCCESS;
15003         }
15004
15005         type = script_getnum(st,2);
15006
15007         switch(type) {
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;
15011                 default:
15012                         script_pushint(st,0);
15013                         break;
15014         }
15015         return SCRIPT_CMD_SUCCESS;
15016 }
15017
15018 /**
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.
15033  */
15034 BUILDIN_FUNC(getmapxy)
15035 {
15036         struct block_list *bl = NULL;
15037         TBL_PC *sd=NULL;
15038
15039         int64 num;
15040         const char *name;
15041         char prefix;
15042
15043         int x,y,type;
15044         char mapname[MAP_NAME_LENGTH];
15045
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;
15050         }
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;
15055         }
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;
15060         }
15061
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;
15066         }
15067
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;
15072         }
15073
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;
15078         }
15079
15080         // Possible needly check function parameters on C_STR,C_INT,C_INT
15081         type=script_getnum(st,5);
15082
15083         switch (type) {
15084                 case UNITTYPE_PC:       //Get Character Position
15085                         if( script_nick2sd(6,sd) )
15086                                 bl = &sd->bl;
15087                         break;
15088                 case UNITTYPE_NPC:      //Get NPC Position
15089                         if( script_hasdata(st,6) )
15090                         {
15091                                 struct npc_data *nd;
15092                                 nd=npc_name2id(script_getstr(st,6));
15093                                 if (nd)
15094                                         bl = &nd->bl;
15095                         } else //In case the origin is not an npc?
15096                                 bl=map_id2bl(st->oid);
15097                         break;
15098                 case UNITTYPE_PET:      //Get Pet Position
15099                         if( script_nick2sd(6, sd) && sd->pd )
15100                                 bl = &sd->pd->bl;
15101                         break;
15102                 case UNITTYPE_HOM:      //Get Homun Position
15103                         if( script_nick2sd(6, sd) && sd->hd )
15104                                 bl = &sd->hd->bl;
15105                         break;
15106                 case UNITTYPE_MER: //Get Mercenary Position
15107                         if( script_nick2sd(6, sd) && sd->md )
15108                                 bl = &sd->md->bl;
15109                         break;
15110                 case UNITTYPE_ELEM: //Get Elemental Position
15111                         if( script_nick2sd(6, sd) && sd->ed )
15112                                 bl = &sd->ed->bl;
15113                         break;
15114                 default:
15115                         ShowWarning("script: buildin_getmapxy: Invalid type %d.\n", type);
15116                         script_pushint(st,-1);
15117                         return SCRIPT_CMD_FAILURE;
15118         }
15119         if (!bl) { //No object found.
15120                 script_pushint(st,-1);
15121                 return SCRIPT_CMD_SUCCESS;
15122         }
15123
15124         x= bl->x;
15125         y= bl->y;
15126         safestrncpy(mapname, map[bl->m].name, MAP_NAME_LENGTH);
15127
15128         //Set MapName$
15129         num=st->stack->stack_data[st->start+2].u.num;
15130         name=get_str(script_getvarid(num));
15131         prefix=*name;
15132
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;
15137                 }
15138         }else
15139                 sd=NULL;
15140         set_reg(st,sd,num,name,(void*)mapname,script_getref(st,2));
15141
15142         //Set MapX
15143         num=st->stack->stack_data[st->start+3].u.num;
15144         name=get_str(script_getvarid(num));
15145         prefix=*name;
15146
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;
15151                 }
15152         }else
15153                 sd=NULL;
15154         set_reg(st,sd,num,name,(void*)__64BPRTSIZE(x),script_getref(st,3));
15155
15156         //Set MapY
15157         num=st->stack->stack_data[st->start+4].u.num;
15158         name=get_str(script_getvarid(num));
15159         prefix=*name;
15160
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;
15165                 }
15166         }else
15167                 sd=NULL;
15168         set_reg(st,sd,num,name,(void*)__64BPRTSIZE(y),script_getref(st,4));
15169
15170         //Return Success value
15171         script_pushint(st,0);
15172         return SCRIPT_CMD_SUCCESS;
15173 }
15174
15175 /// Returns the map name of given map ID.
15176 ///
15177 /// mapid2name <map ID>;
15178 BUILDIN_FUNC(mapid2name)
15179 {
15180         uint16 m = script_getnum(st, 2);
15181
15182         if (m < 0 || m >= MAX_MAP_PER_SERVER) {
15183                 script_pushconststr(st, "");
15184                 return SCRIPT_CMD_FAILURE;
15185         }
15186
15187         script_pushstrcopy(st, map_mapid2mapname(m));
15188
15189         return SCRIPT_CMD_SUCCESS;
15190 }
15191
15192 /*==========================================
15193  * Allows player to write NPC logs (i.e. Bank NPC, etc) [Lupus]
15194  *------------------------------------------*/
15195 BUILDIN_FUNC(logmes)
15196 {
15197         const char *str;
15198         TBL_PC* sd;
15199
15200         if( !script_rid2sd(sd) )
15201                 return SCRIPT_CMD_FAILURE;
15202
15203         str = script_getstr(st,2);
15204         log_npc(sd,str);
15205         return SCRIPT_CMD_SUCCESS;
15206 }
15207
15208 BUILDIN_FUNC(summon)
15209 {
15210         int _class, timeout=0;
15211         const char *str,*event="";
15212         TBL_PC *sd;
15213         struct mob_data *md;
15214         int tick = gettick();
15215
15216         if (!script_rid2sd(sd))
15217                 return SCRIPT_CMD_SUCCESS;
15218
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);
15226         }
15227
15228         clif_skill_poseffect(&sd->bl,AM_CALLHOMUN,1,sd->bl.x,sd->bl.y,tick);
15229
15230         md = mob_once_spawn_sub(&sd->bl, sd->bl.m, sd->bl.x, sd->bl.y, str, _class, event, SZ_SMALL, AI_NONE);
15231         if (md) {
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);
15240         }
15241         script_pushint(st, md->bl.id);
15242
15243         return SCRIPT_CMD_SUCCESS;
15244 }
15245
15246 /*==========================================
15247  * Checks whether it is daytime/nighttime
15248  *------------------------------------------*/
15249 BUILDIN_FUNC(isnight)
15250 {
15251         script_pushint(st,(night_flag == 1));
15252         return SCRIPT_CMD_SUCCESS;
15253 }
15254
15255 BUILDIN_FUNC(isday)
15256 {
15257         script_pushint(st,(night_flag == 0));
15258         return SCRIPT_CMD_SUCCESS;
15259 }
15260
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)
15266 {
15267         TBL_PC *sd;
15268         int i, id = 1;
15269         int ret = 0;
15270
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;
15274         }
15275
15276         for (i=0; id!=0; i++) {
15277                 short j;
15278                 FETCH (i+2, id) else id = 0;
15279                 if (id <= 0)
15280                         continue;
15281
15282                 for (j=0; j<EQI_MAX; j++) {
15283                         short index = sd->equip_index[j];
15284                         if(index < 0)
15285                                 continue;
15286                         if (pc_is_same_equip_index((enum equip_index)j, sd->equip_index, index))
15287                                 continue;
15288
15289                         if(!sd->inventory_data[index])
15290                                 continue;
15291
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.
15296                                 short k;
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)
15301                                                 ret++; //[Lupus]
15302                                 }
15303                         }
15304                 }
15305         }
15306
15307         script_pushint(st,ret);
15308         return SCRIPT_CMD_SUCCESS;
15309 }
15310
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)
15318 {
15319         TBL_PC *sd;
15320         int i, id = 1;
15321         int ret = -1;
15322         //Original hash to reverse it when full check fails.
15323         unsigned int setitem_hash = 0, setitem_hash2 = 0;
15324
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;
15328         }
15329
15330         setitem_hash = sd->bonus.setitem_hash;
15331         setitem_hash2 = sd->bonus.setitem_hash2;
15332         for (i=0; id!=0; i++) {
15333                 int flag = 0;
15334                 short j;
15335                 FETCH (i+2, id) else id = 0;
15336                 if (id <= 0)
15337                         continue;
15338                 for (j=0; j<EQI_MAX; j++) {
15339                         short index = sd->equip_index[j];
15340                         if(index < 0)
15341                                 continue;
15342                         if (pc_is_same_equip_index((enum equip_index)i, sd->equip_index, index))
15343                                 continue;
15344
15345                         if(!sd->inventory_data[index])
15346                                 continue;
15347
15348                         if (itemdb_type(id) != IT_CARD) {
15349                                 if (sd->inventory_data[index]->nameid != id)
15350                                         continue;
15351                                 flag = 1;
15352                                 break;
15353                         } else { //Cards
15354                                 short k;
15355                                 if (sd->inventory_data[index]->slot == 0 ||
15356                                         itemdb_isspecial(sd->inventory.u.items_inventory[index].card[0]))
15357                                         continue;
15358
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)
15363                                                 continue;
15364
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)
15368                                                 continue;
15369
15370                                         // We have found a match
15371                                         flag = 1;
15372                                         // Set hash so this card cannot be used by another
15373                                         if (j<5)
15374                                                 sd->bonus.setitem_hash |= hash;
15375                                         else
15376                                                 sd->bonus.setitem_hash2 |= hash;
15377                                         break;
15378                                 }
15379                         }
15380                         if (flag) break; //Card found
15381                 }
15382                 if (ret == -1)
15383                         ret = flag;
15384                 else
15385                         ret &= flag;
15386                 if (!ret) break;
15387         }
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;
15391         }
15392         script_pushint(st,ret);
15393         return SCRIPT_CMD_SUCCESS;
15394 }
15395
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)
15401 {
15402         TBL_PC *sd;
15403         int i, k, id = 1;
15404         int ret = 0;
15405         int index;
15406
15407         if( !script_rid2sd(sd) ){
15408                 script_pushint(st,0);
15409                 return SCRIPT_CMD_SUCCESS;
15410         }
15411
15412         for (i=0; id!=0; i++) {
15413                 FETCH (i+2, id) else id = 0;
15414                 if (id <= 0)
15415                         continue;
15416
15417                 index = current_equip_item_index; //we get CURRENT WEAPON inventory index from status.c [Lupus]
15418                 if(index < 0) continue;
15419
15420                 if(!sd->inventory_data[index])
15421                         continue;
15422
15423                 if(itemdb_type(id) != IT_CARD) {
15424                         if (sd->inventory_data[index]->nameid == id)
15425                                 ret+= sd->inventory.u.items_inventory[index].amount;
15426                 } else {
15427                         if (itemdb_isspecial(sd->inventory.u.items_inventory[index].card[0]))
15428                                 continue;
15429                         for(k=0; k<sd->inventory_data[index]->slot; k++) {
15430                                 if (sd->inventory.u.items_inventory[index].card[k] == id)
15431                                         ret++;
15432                         }
15433                 }
15434         }
15435         script_pushint(st,ret);
15436 //      script_pushint(st,current_equip_item_index);
15437         return SCRIPT_CMD_SUCCESS;
15438 }
15439
15440 /*=======================================================
15441  * Returns the refined number of the current item, or an
15442  * item with inventory index specified
15443  *-------------------------------------------------------*/
15444 BUILDIN_FUNC(getrefine)
15445 {
15446         TBL_PC *sd;
15447         if (script_rid2sd(sd)){
15448                 if( current_equip_item_index == -1 ){
15449                         script_pushint(st, 0);
15450                         return SCRIPT_CMD_FAILURE;
15451                 }
15452
15453                 script_pushint(st,sd->inventory.u.items_inventory[current_equip_item_index].refine);
15454         }else
15455                 script_pushint(st,0);
15456         return SCRIPT_CMD_SUCCESS;
15457 }
15458
15459 /*=======================================================
15460  * Day/Night controls
15461  *-------------------------------------------------------*/
15462 BUILDIN_FUNC(night)
15463 {
15464         if (night_flag != 1) map_night_timer(night_timer_tid, 0, 0, 1);
15465         return SCRIPT_CMD_SUCCESS;
15466 }
15467 BUILDIN_FUNC(day)
15468 {
15469         if (night_flag != 0) map_day_timer(day_timer_tid, 0, 0, 1);
15470         return SCRIPT_CMD_SUCCESS;
15471 }
15472
15473 /**
15474  * unequip <equipment slot>{,<char_id>};
15475  * @author [Spectre]
15476  **/
15477 BUILDIN_FUNC(unequip) {
15478         int pos;
15479         TBL_PC *sd;
15480
15481         if (!script_charid2sd(3,sd))
15482                 return SCRIPT_CMD_FAILURE;
15483
15484         pos = script_getnum(st,2);
15485         if (equip_index_check(pos)) {
15486                 short i = pc_checkequip(sd,equip_bitmask[pos]);
15487                 if (i >= 0) {
15488                         pc_unequipitem(sd,i,1|2);
15489                         script_pushint(st, 1);
15490                         return SCRIPT_CMD_SUCCESS;
15491                 }
15492         }
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;
15496 }
15497
15498 /**
15499  * equip <item id>{,<char_id>};
15500  **/
15501 BUILDIN_FUNC(equip) {
15502         unsigned short nameid = 0;
15503         TBL_PC *sd;
15504         struct item_data *item_data;
15505
15506         if (!script_charid2sd(3,sd))
15507                 return SCRIPT_CMD_FAILURE;
15508
15509         nameid = script_getnum(st,2);
15510         if ((item_data = itemdb_exists(nameid))) {
15511                 int i;
15512
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;
15518                 }
15519         }
15520
15521         ShowError("buildin_equip: Item %hu cannot be equipped\n",nameid);
15522         script_pushint(st,0);
15523         return SCRIPT_CMD_FAILURE;
15524 }
15525
15526 BUILDIN_FUNC(autoequip)
15527 {
15528         unsigned short nameid;
15529         int flag;
15530         struct item_data *item_data;
15531         nameid=script_getnum(st,2);
15532         flag=script_getnum(st,3);
15533
15534         if( ( item_data = itemdb_exists(nameid) ) == NULL )
15535         {
15536                 ShowError("buildin_autoequip: Invalid item '%hu'.\n", nameid);
15537                 return SCRIPT_CMD_FAILURE;
15538         }
15539
15540         if( !itemdb_isequip2(item_data) )
15541         {
15542                 ShowError("buildin_autoequip: Item '%hu' cannot be equipped.\n", nameid);
15543                 return SCRIPT_CMD_FAILURE;
15544         }
15545
15546         item_data->flag.autoequip = flag>0?1:0;
15547         return SCRIPT_CMD_SUCCESS;
15548 }
15549
15550 /**
15551  * Set the value of a given battle config
15552  * setbattleflag "<battle flag>",<value>{,<reload>};
15553  */
15554 BUILDIN_FUNC(setbattleflag)
15555 {
15556         const char *flag, *value;
15557
15558         flag = script_getstr(st,2);
15559         value = script_getstr(st,3);  // HACK: Retrieve number as string (auto-converted) for battle_set_value
15560
15561         if (battle_set_value(flag, value) == 0)
15562                 ShowWarning("buildin_setbattleflag: unknown battle_config flag '%s'\n",flag);
15563         else {
15564                 ShowInfo("buildin_setbattleflag: battle_config flag '%s' is now set to '%s'.\n",flag,value);
15565
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",
15577                         };
15578                         uint8 i;
15579
15580                         for (i = 0; i < ARRAYLENGTH(expdrop_flags); i++) {
15581                                 if (!strcmpi(flag, expdrop_flags[i])) {
15582                                         mob_reload();
15583                                         break;
15584                                 }
15585                         }
15586                 }
15587         }
15588
15589         return SCRIPT_CMD_SUCCESS;
15590 }
15591
15592 /**
15593  * Get the value of a given battle config
15594  * getbattleflag("<battle flag>")
15595  */
15596 BUILDIN_FUNC(getbattleflag)
15597 {
15598         const char *flag = script_getstr(st,2);
15599
15600         script_pushint(st,battle_get_value(flag));
15601         return SCRIPT_CMD_SUCCESS;
15602 }
15603
15604 //=======================================================
15605 // strlen [Valaris]
15606 //-------------------------------------------------------
15607 BUILDIN_FUNC(getstrlen)
15608 {
15609
15610         const char *str = script_getstr(st,2);
15611         int len = (str) ? (int)strlen(str) : 0;
15612
15613         script_pushint(st,len);
15614         return SCRIPT_CMD_SUCCESS;
15615 }
15616
15617 //=======================================================
15618 // isalpha [Valaris]
15619 //-------------------------------------------------------
15620 BUILDIN_FUNC(charisalpha)
15621 {
15622         const char *str=script_getstr(st,2);
15623         int pos=script_getnum(st,3);
15624
15625         int val = ( str && pos >= 0 && (unsigned int)pos < strlen(str) ) ? ISALPHA( str[pos] ) != 0 : 0;
15626
15627         script_pushint(st,val);
15628         return SCRIPT_CMD_SUCCESS;
15629 }
15630
15631 //=======================================================
15632 // charisupper <str>, <index>
15633 //-------------------------------------------------------
15634 BUILDIN_FUNC(charisupper)
15635 {
15636         const char *str = script_getstr(st,2);
15637         int pos = script_getnum(st,3);
15638
15639         int val = ( str && pos >= 0 && (unsigned int)pos < strlen(str) ) ? ISUPPER( str[pos] ) : 0;
15640
15641         script_pushint(st,val);
15642         return SCRIPT_CMD_SUCCESS;
15643 }
15644
15645 //=======================================================
15646 // charislower <str>, <index>
15647 //-------------------------------------------------------
15648 BUILDIN_FUNC(charislower)
15649 {
15650         const char *str = script_getstr(st,2);
15651         int pos = script_getnum(st,3);
15652
15653         int val = ( str && pos >= 0 && (unsigned int)pos < strlen(str) ) ? ISLOWER( str[pos] ) : 0;
15654
15655         script_pushint(st,val);
15656         return SCRIPT_CMD_SUCCESS;
15657 }
15658
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);
15665
15666         if( pos >= 0 && (unsigned int)pos < strlen(str) ) {
15667                 char output[2];
15668                 output[0] = str[pos];
15669                 output[1] = '\0';
15670                 script_pushstrcopy(st, output);
15671         } else
15672                 script_pushconststr(st, "");
15673         return SCRIPT_CMD_SUCCESS;
15674 }
15675
15676 //=======================================================
15677 // setchar <string>, <char>, <index>
15678 //-------------------------------------------------------
15679 BUILDIN_FUNC(setchar)
15680 {
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);
15685
15686         if(index >= 0 && index < strlen(output))
15687                 output[index] = *c;
15688
15689         script_pushstr(st, output);
15690         return SCRIPT_CMD_SUCCESS;
15691 }
15692
15693 //=======================================================
15694 // insertchar <string>, <char>, <index>
15695 //-------------------------------------------------------
15696 BUILDIN_FUNC(insertchar)
15697 {
15698         const char *str = script_getstr(st,2);
15699         const char *c = script_getstr(st,3);
15700         int index = script_getnum(st,4);
15701         char *output;
15702         size_t len = strlen(str);
15703
15704         if(index < 0)
15705                 index = 0;
15706         else if(index > len)
15707                 index = len;
15708
15709         output = (char*)aMalloc(len + 2);
15710
15711         memcpy(output, str, index);
15712         output[index] = c[0];
15713         memcpy(&output[index+1], &str[index], len - index);
15714         output[len+1] = '\0';
15715
15716         script_pushstr(st, output);
15717         return SCRIPT_CMD_SUCCESS;
15718 }
15719
15720 //=======================================================
15721 // delchar <string>, <index>
15722 //-------------------------------------------------------
15723 BUILDIN_FUNC(delchar)
15724 {
15725         const char *str = script_getstr(st,2);
15726         int index = script_getnum(st,3);
15727         char *output;
15728         size_t len = strlen(str);
15729
15730         if(index < 0 || index > len) {
15731                 //return original
15732                 output = aStrdup(str);
15733                 script_pushstr(st, output);
15734                 return SCRIPT_CMD_SUCCESS;
15735         }
15736
15737         output = (char*)aMalloc(len);
15738
15739         memcpy(output, str, index);
15740         memcpy(&output[index], &str[index+1], len - index);
15741
15742         script_pushstr(st, output);
15743         return SCRIPT_CMD_SUCCESS;
15744 }
15745
15746 //=======================================================
15747 // strtoupper <str>
15748 //-------------------------------------------------------
15749 BUILDIN_FUNC(strtoupper)
15750 {
15751         const char *str = script_getstr(st,2);
15752         char *output = aStrdup(str);
15753         char *cursor = output;
15754
15755         while (*cursor != '\0') {
15756                 *cursor = TOUPPER(*cursor);
15757                 cursor++;
15758         }
15759
15760         script_pushstr(st, output);
15761         return SCRIPT_CMD_SUCCESS;
15762 }
15763
15764 //=======================================================
15765 // strtolower <str>
15766 //-------------------------------------------------------
15767 BUILDIN_FUNC(strtolower)
15768 {
15769         const char *str = script_getstr(st,2);
15770         char *output = aStrdup(str);
15771         char *cursor = output;
15772
15773         while (*cursor != '\0') {
15774                 *cursor = TOLOWER(*cursor);
15775                 cursor++;
15776         }
15777
15778         script_pushstr(st, output);
15779         return SCRIPT_CMD_SUCCESS;
15780 }
15781
15782 //=======================================================
15783 // substr <str>, <start>, <end>
15784 //-------------------------------------------------------
15785 BUILDIN_FUNC(substr)
15786 {
15787         const char *str = script_getstr(st,2);
15788         char *output;
15789         int start = script_getnum(st,3);
15790         int end = script_getnum(st,4);
15791         int len = 0;
15792
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);
15797         } else
15798                 output = (char*)aMalloc(1);
15799
15800         output[len] = '\0';
15801
15802         script_pushstr(st, output);
15803         return SCRIPT_CMD_SUCCESS;
15804 }
15805
15806 //=======================================================
15807 // explode <dest_string_array>, <str>, <delimiter>
15808 // Note: delimiter is limited to 1 char
15809 //-------------------------------------------------------
15810 BUILDIN_FUNC(explode)
15811 {
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];
15815         int32 id;
15816         size_t len = strlen(str);
15817         int i = 0, j = 0;
15818         int start;
15819         char *temp;
15820         const char* name;
15821         TBL_PC* sd = NULL;
15822
15823         temp = (char*)aMalloc(len + 1);
15824
15825         if( !data_isreference(data) ) {
15826                 ShowError("script:explode: not a variable\n");
15827                 script_reportdata(data);
15828                 st->state = END;
15829                 return SCRIPT_CMD_FAILURE;// not a variable
15830         }
15831
15832         id = reference_getid(data);
15833         start = reference_getindex(data);
15834         name = reference_getname(data);
15835
15836         if( !is_string_variable(name) ) {
15837                 ShowError("script:explode: not string array\n");
15838                 script_reportdata(data);
15839                 st->state = END;
15840                 return SCRIPT_CMD_FAILURE;// data type mismatch
15841         }
15842
15843         if( not_server_variable(*name) ) {
15844                 if( !script_rid2sd(sd) )
15845                         return SCRIPT_CMD_SUCCESS;// no player attached
15846         }
15847
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
15850                         temp[j] = '\0';
15851                         set_reg(st, sd, reference_uid(id, start++), name, (void*)temp, reference_getref(data));
15852                         j = 0;
15853                         ++i;
15854                 } else {
15855                         temp[j++] = str[i++];
15856                 }
15857         }
15858
15859         //set last string
15860         temp[j] = '\0';
15861         set_reg(st, sd, reference_uid(id, start), name, (void*)temp, reference_getref(data));
15862
15863         aFree(temp);
15864         return SCRIPT_CMD_SUCCESS;
15865 }
15866
15867 //=======================================================
15868 // implode <string_array>
15869 // implode <string_array>, <glue>
15870 //-------------------------------------------------------
15871 BUILDIN_FUNC(implode)
15872 {
15873         struct script_data* data = script_getdata(st, 2);
15874         const char *name;
15875         uint32 glue_len = 0, array_size, id;
15876         char *output;
15877         TBL_PC* sd = NULL;
15878
15879         if( !data_isreference(data) ) {
15880                 ShowError("script:implode: not a variable\n");
15881                 script_reportdata(data);
15882                 st->state = END;
15883                 return SCRIPT_CMD_FAILURE;// not a variable
15884         }
15885
15886         id = reference_getid(data);
15887         name = reference_getname(data);
15888
15889         if( !is_string_variable(name) ) {
15890                 ShowError("script:implode: not string array\n");
15891                 script_reportdata(data);
15892                 st->state = END;
15893                 return SCRIPT_CMD_FAILURE;// data type mismatch
15894         }
15895
15896         if( not_server_variable(*name) && !script_rid2sd(sd) ) {
15897                 return SCRIPT_CMD_SUCCESS;// no player attached
15898         }
15899
15900         //count chars
15901         array_size = script_array_highest_key(st, sd, name, reference_getref(data)) - 1;
15902
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");
15907         } else {
15908                 const char *glue = NULL, *temp;
15909                 size_t len = 0;
15910                 int i, k = 0;
15911
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);
15916                 }
15917
15918                 //allocate mem
15919                 if( script_hasdata(st,3) ) {
15920                         glue = script_getstr(st,3);
15921                         glue_len = strlen(glue);
15922                         len += glue_len * (array_size);
15923                 }
15924                 output = (char*)aMalloc(len + 1);
15925
15926                 //build output
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);
15931                         k += len;
15932
15933                         if(glue_len != 0) {
15934                                 memcpy(&output[k], glue, glue_len);
15935                                 k += glue_len;
15936                         }
15937
15938                         script_removetop(st, -1, 0);
15939                 }
15940
15941                 temp = (char*) get_val2(st, reference_uid(id, array_size), reference_getref(data));
15942                 len = strlen(temp);
15943                 memcpy(&output[k], temp, len);
15944                 k += len;
15945                 script_removetop(st, -1, 0);
15946                 output[k] = '\0';
15947         }
15948
15949         script_pushstr(st, output);
15950         return SCRIPT_CMD_SUCCESS;
15951 }
15952
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)
15959 {
15960         unsigned int len, argc = 0, arg = 0, buf2_len = 0;
15961         const char* format;
15962         char* p;
15963         char* q;
15964         char* buf  = NULL;
15965         char* buf2 = NULL;
15966         struct script_data* data;
15967         StringBuf final_buf;
15968
15969         // Fetch init data
15970         format = script_getstr(st, 2);
15971         argc = script_lastdata(st)-2;
15972         len = strlen(format);
15973
15974         // Skip parsing, where no parsing is required.
15975         if(len == 0) {
15976                 script_pushconststr(st,"");
15977                 return SCRIPT_CMD_SUCCESS;
15978         }
15979
15980         // Pessimistic alloc
15981         CREATE(buf, char, len+1);
15982
15983         // Need not be parsed, just solve stuff like %%.
15984         if(argc == 0) {
15985                 memcpy(buf,format,len+1);
15986                 script_pushstrcopy(st, buf);
15987                 aFree(buf);
15988                 return SCRIPT_CMD_SUCCESS;
15989         }
15990
15991         safestrncpy(buf, format, len+1);
15992
15993         // Issue sprintf for each parameter
15994         StringBuf_Init(&final_buf);
15995         q = buf;
15996         while((p = strchr(q, '%')) != NULL) {
15997                 if(p != q) {
15998                         len = p - q + 1;
15999
16000                         if(buf2_len < len) {
16001                                 RECREATE(buf2, char, len);
16002                                 buf2_len = len;
16003                         }
16004
16005                         safestrncpy(buf2, q, len);
16006                         StringBuf_AppendStr(&final_buf, buf2);
16007                         q = p;
16008                 }
16009
16010                 p = q + 1;
16011
16012                 if(*p == '%') {  // %%
16013                         StringBuf_AppendStr(&final_buf, "%");
16014                         q+=2;
16015                         continue;
16016                 }
16017
16018                 if(*p == 'n') {  // %n
16019                         ShowWarning("buildin_sprintf: Format %%n not supported! Skipping...\n");
16020                         script_reportsrc(st);
16021                         q+=2;
16022                         continue;
16023                 }
16024
16025                 if(arg >= argc) {
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;
16032                 }
16033
16034                 if((p = strchr(q+1, '%')) == NULL)
16035                         p = strchr(q, 0);  // EOS
16036
16037                 len = p - q + 1;
16038
16039                 if(buf2_len < len) {
16040                         RECREATE(buf2, char, len);
16041                         buf2_len = len;
16042                 }
16043
16044                 safestrncpy(buf2, q, len);
16045                 q = p;
16046
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);
16053
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);
16060
16061                         if(name[strlen(name)-1]=='$')  // var Str
16062                                 StringBuf_Printf(&final_buf, buf2, script_getstr(st, arg+3));
16063                         else  // var Int
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;
16072                 }
16073
16074                 arg++;
16075         }
16076
16077         // Append anything left
16078         if(*q)
16079                 StringBuf_AppendStr(&final_buf, q);
16080
16081         // Passed more, than needed
16082         if(arg < argc) {
16083                 ShowWarning("buildin_sprintf: Unused arguments passed.\n");
16084                 script_reportsrc(st);
16085         }
16086
16087         script_pushstrcopy(st, StringBuf_Value(&final_buf));
16088
16089         if(buf) aFree(buf);
16090         if(buf2) aFree(buf2);
16091         StringBuf_Destroy(&final_buf);
16092
16093         return SCRIPT_CMD_SUCCESS;
16094 }
16095
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;
16104         const char* str;
16105         const char* format;
16106         const char* p;
16107         const char* q;
16108         char* buf = NULL;
16109         char* buf_p;
16110         char* ref_str = NULL;
16111         int ref_int;
16112
16113         // Get data
16114         str = script_getstr(st, 2);
16115         format = script_getstr(st, 3);
16116         argc = script_lastdata(st)-3;
16117
16118         len = strlen(format);
16119
16120
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;
16127         }
16128
16129         CREATE(buf, char, len*2+1);
16130
16131         // Issue sscanf for each parameter
16132         *buf = 0;
16133         q = format;
16134         while((p = strchr(q, '%'))){
16135                 if(p!=q){
16136                         strncat(buf, q, (size_t)(p-q));
16137                         q = p;
16138                 }
16139                 p = q+1;
16140                 if(*p=='*' || *p=='%'){  // Skip
16141                         strncat(buf, q, 2);
16142                         q+=2;
16143                         continue;
16144                 }
16145                 if(arg>=argc){
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;
16151                 }
16152                 if((p = strchr(q+1, '%'))==NULL){
16153                         p = strchr(q, 0);  // EOS
16154                 }
16155                 len = p-q;
16156                 strncat(buf, q, len);
16157                 q = p;
16158
16159                 // Validate output
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;
16167                 }
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;
16174                 }
16175
16176                 // Save value if any
16177                 if(buf_p[strlen(buf_p)-1]=='$'){  // String
16178                         if(ref_str==NULL){
16179                                 CREATE(ref_str, char, strlen(str)+1);
16180                         }
16181                         if(sscanf(str, buf, ref_str)==0){
16182                                 break;
16183                         }
16184                         set_reg(st, sd, reference_uid( reference_getid(data), reference_getindex(data) ), buf_p, (void *)(ref_str), reference_getref(data));
16185                 } else {  // Number
16186                         if(sscanf(str, buf, &ref_int)==0){
16187                                 break;
16188                         }
16189                         set_reg(st, sd, reference_uid( reference_getid(data), reference_getindex(data) ), buf_p, (void *)__64BPRTSIZE(ref_int), reference_getref(data));
16190                 }
16191                 arg++;
16192
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) = '*';
16197         }
16198
16199         script_pushint(st, arg);
16200         if(buf) aFree(buf);
16201         if(ref_str) aFree(ref_str);
16202
16203         return SCRIPT_CMD_SUCCESS;
16204 }
16205
16206 //=======================================================
16207 // strpos(<haystack>, <needle>)
16208 // strpos(<haystack>, <needle>, <offset>)
16209 //
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);
16216         int i;
16217         size_t len;
16218
16219         if( script_hasdata(st,4) )
16220                 i = script_getnum(st,4);
16221         else
16222                 i = 0;
16223
16224         if (needle[0] == '\0') {
16225                 script_pushint(st, -1);
16226                 return SCRIPT_CMD_SUCCESS;
16227         }
16228
16229         len = strlen(haystack);
16230         for ( ; i < len; ++i ) {
16231                 if ( haystack[i] == *needle ) {
16232                         // matched starting char -- loop through remaining chars
16233                         const char *h, *n;
16234                         for ( h = &haystack[i], n = needle; *h && *n; ++h, ++n ) {
16235                                 if ( *h != *n ) {
16236                                         break;
16237                                 }
16238                         }
16239                         if ( !*n ) { // matched all of 'needle' to null termination
16240                                 script_pushint(st, i);
16241                                 return SCRIPT_CMD_SUCCESS;
16242                         }
16243                 }
16244         }
16245         script_pushint(st, -1);
16246         return SCRIPT_CMD_SUCCESS;
16247 }
16248
16249 //===============================================================
16250 // replacestr <input>, <search>, <replace>{, <usecase>{, <count>}}
16251 //
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
16255 // sensitive.
16256 //---------------------------------------------------------------
16257 BUILDIN_FUNC(replacestr)
16258 {
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;
16266
16267         int count = 0;
16268         int numFinds = 0;
16269         int i = 0, f = 0;
16270
16271         if(findlen == 0) {
16272                 ShowError("script:replacestr: Invalid search length.\n");
16273                 st->state = END;
16274                 return SCRIPT_CMD_FAILURE;
16275         }
16276
16277         if(script_hasdata(st, 5)) {
16278                 struct script_data *data = script_getdata(st, 5);
16279
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;
16283                 else {
16284                         ShowError("script:replacestr: Invalid usecase value. Expected int got string\n");
16285                         st->state = END;
16286                         return SCRIPT_CMD_FAILURE;
16287                 }
16288         }
16289
16290         if(script_hasdata(st, 6)) {
16291                 count = script_getnum(st, 6);
16292                 if(count == 0) {
16293                         ShowError("script:replacestr: Invalid count value. Expected int got string\n");
16294                         st->state = END;
16295                         return SCRIPT_CMD_FAILURE;
16296                 }
16297         }
16298
16299         StringBuf_Init(&output);
16300
16301         for(; i < inputlen; i++) {
16302                 if(count && count == numFinds) {        //found enough, stop looking
16303                         break;
16304                 }
16305
16306                 for(f = 0; f <= findlen; f++) {
16307                         if(f == findlen) { //complete match
16308                                 numFinds++;
16309                                 StringBuf_AppendStr(&output, replace);
16310
16311                                 i += findlen - 1;
16312                                 break;
16313                         } else {
16314                                 if(usecase) {
16315                                         if((i + f) > inputlen || input[i + f] != find[f]) {
16316                                                 StringBuf_Printf(&output, "%c", input[i]);
16317                                                 break;
16318                                         }
16319                                 } else {
16320                                         if(((i + f) > inputlen || input[i + f] != find[f]) && TOUPPER(input[i+f]) != TOUPPER(find[f])) {
16321                                                 StringBuf_Printf(&output, "%c", input[i]);
16322                                                 break;
16323                                         }
16324                                 }
16325                         }
16326                 }
16327         }
16328
16329         //append excess after enough found
16330         if(i < inputlen)
16331                 StringBuf_AppendStr(&output, &(input[i]));
16332
16333         script_pushstrcopy(st, StringBuf_Value(&output));
16334         StringBuf_Destroy(&output);
16335         return SCRIPT_CMD_SUCCESS;
16336 }
16337
16338 //========================================================
16339 // countstr <input>, <search>{, <usecase>}
16340 //
16341 // Note: Counts the number of times <search> occurs in
16342 // <input>. By default will be case sensitive.
16343 //--------------------------------------------------------
16344 BUILDIN_FUNC(countstr)
16345 {
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;
16351
16352         int numFinds = 0;
16353         int i = 0, f = 0;
16354
16355         if(findlen == 0) {
16356                 ShowError("script:countstr: Invalid search length.\n");
16357                 st->state = END;
16358                 return SCRIPT_CMD_FAILURE;
16359         }
16360
16361         if(script_hasdata(st, 4)) {
16362                 struct script_data *data;
16363
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;
16368                 else {
16369                         ShowError("script:countstr: Invalid usecase value. Expected int got string\n");
16370                         st->state = END;
16371                         return SCRIPT_CMD_FAILURE;
16372                 }
16373         }
16374
16375         for(; i < inputlen; i++) {
16376                 for(f = 0; f <= findlen; f++) {
16377                         if(f == findlen) { //complete match
16378                                 numFinds++;
16379                                 i += findlen - 1;
16380                                 break;
16381                         } else {
16382                                 if(usecase) {
16383                                         if((i + f) > inputlen || input[i + f] != find[f]) {
16384                                                 break;
16385                                         }
16386                                 } else {
16387                                         if(((i + f) > inputlen || input[i + f] != find[f]) && TOUPPER(input[i+f]) != TOUPPER(find[f])) {
16388                                                 break;
16389                                         }
16390                                 }
16391                         }
16392                 }
16393         }
16394         script_pushint(st, numFinds);
16395         return SCRIPT_CMD_SUCCESS;
16396 }
16397
16398
16399 /// Changes the display name and/or display class of the npc.
16400 /// Returns 0 is successful, 1 if the npc does not exist.
16401 ///
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)
16407 {
16408         const char* name;
16409         const char* newname = NULL;
16410         int class_ = -1, size = -1;
16411         struct script_data* data;
16412         struct npc_data* nd;
16413
16414         name = script_getstr(st,2);
16415         data = script_getdata(st,3);
16416
16417         if( script_hasdata(st,4) )
16418                 class_ = script_getnum(st,4);
16419         if( script_hasdata(st,5) )
16420                 size = script_getnum(st,5);
16421
16422         get_val(st, data);
16423         if( data_isstring(data) )
16424                 newname = conv_str(st,data);
16425         else if( data_isint(data) )
16426                 class_ = conv_num(st,data);
16427         else
16428         {
16429                 ShowError("script:setnpcdisplay: expected string or number\n");
16430                 script_reportdata(data);
16431                 return SCRIPT_CMD_FAILURE;
16432         }
16433
16434         nd = npc_name2id(name);
16435         if( nd == NULL )
16436         {// not found
16437                 script_pushint(st,1);
16438                 return SCRIPT_CMD_SUCCESS;
16439         }
16440
16441         // update npc
16442         if( newname )
16443                 npc_setdisplayname(nd, newname);
16444
16445         if( size != -1 && size != (int)nd->size )
16446                 nd->size = size;
16447         else
16448                 size = -1;
16449
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);
16456         }
16457
16458         script_pushint(st,0);
16459         return SCRIPT_CMD_SUCCESS;
16460 }
16461
16462 BUILDIN_FUNC(atoi)
16463 {
16464         const char *value;
16465         value = script_getstr(st,2);
16466         script_pushint(st,atoi(value));
16467         return SCRIPT_CMD_SUCCESS;
16468 }
16469
16470 BUILDIN_FUNC(axtoi)
16471 {
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);
16476 #endif
16477         script_pushint(st, (int)value);
16478         return SCRIPT_CMD_SUCCESS;
16479 }
16480
16481 BUILDIN_FUNC(strtol)
16482 {
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);
16488 #endif
16489         script_pushint(st, (int)value);
16490         return SCRIPT_CMD_SUCCESS;
16491 }
16492
16493 // case-insensitive substring search [lordalfa]
16494 BUILDIN_FUNC(compare)
16495 {
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;
16502 }
16503
16504 BUILDIN_FUNC(strcmp)
16505 {
16506         const char *str1;
16507         const char *str2;
16508         str1 = script_getstr(st,2);
16509         str2 = script_getstr(st,3);
16510         script_pushint(st,strcmp(str1, str2));
16511         return SCRIPT_CMD_SUCCESS;
16512 }
16513
16514 // [zBuffer] List of mathematics commands --->
16515 BUILDIN_FUNC(sqrt)
16516 {
16517         double i, a;
16518         i = script_getnum(st,2);
16519         a = sqrt(i);
16520         script_pushint(st,(int)a);
16521         return SCRIPT_CMD_SUCCESS;
16522 }
16523
16524 BUILDIN_FUNC(pow)
16525 {
16526         double i, a, b;
16527         a = script_getnum(st,2);
16528         b = script_getnum(st,3);
16529         i = pow(a,b);
16530         script_pushint(st,(int)i);
16531         return SCRIPT_CMD_SUCCESS;
16532 }
16533
16534 BUILDIN_FUNC(distance)
16535 {
16536         int x0, y0, x1, y1;
16537
16538         x0 = script_getnum(st,2);
16539         y0 = script_getnum(st,3);
16540         x1 = script_getnum(st,4);
16541         y1 = script_getnum(st,5);
16542
16543         script_pushint(st,distance_xy(x0,y0,x1,y1));
16544         return SCRIPT_CMD_SUCCESS;
16545 }
16546
16547 // <--- [zBuffer] List of mathematics commands
16548
16549 BUILDIN_FUNC(md5)
16550 {
16551         const char *tmpstr;
16552         char *md5str;
16553
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;
16559 }
16560
16561 // [zBuffer] List of dynamic var commands --->
16562 /**
16563  * setd "<variable name>",<value>{,<char_id>};
16564  **/
16565 BUILDIN_FUNC(setd)
16566 {
16567         TBL_PC *sd = NULL;
16568         char varname[100];
16569         const char *buffer;
16570         int elem;
16571         buffer = script_getstr(st, 2);
16572
16573         if(sscanf(buffer, "%99[^[][%11d]", varname, &elem) < 2)
16574                 elem = 0;
16575
16576         if( not_server_variable(*varname) ) {
16577                 if (!script_charid2sd(4,sd))
16578                         return SCRIPT_CMD_FAILURE;
16579         }
16580
16581         if( is_string_variable(varname) ) {
16582                 setd_sub(st, sd, varname, elem, (void *)script_getstr(st, 3), NULL);
16583         } else {
16584                 setd_sub(st, sd, varname, elem, (void *)__64BPRTSIZE(script_getnum(st, 3)), NULL);
16585         }
16586
16587         return SCRIPT_CMD_SUCCESS;
16588 }
16589
16590 int buildin_query_sql_sub(struct script_state* st, Sql* handle)
16591 {
16592         int i, j;
16593         TBL_PC* sd = NULL;
16594         const char* query;
16595         struct script_data* data;
16596         const char* name;
16597         unsigned int max_rows = SCRIPT_MAX_ARRAYSIZE; // maximum number of rows
16598         int num_vars;
16599         int num_cols;
16600
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);
16609                                         st->state = END;
16610                                         return SCRIPT_CMD_FAILURE;
16611                                 }
16612                         }
16613                 } else {
16614                         ShowError("script:query_sql: not a variable\n");
16615                         script_reportdata(data);
16616                         st->state = END;
16617                         return SCRIPT_CMD_FAILURE;
16618                 }
16619         }
16620         num_vars = i - 3;
16621
16622         // Execute the query
16623         query = script_getstr(st,2);
16624
16625         if( SQL_ERROR == Sql_QueryStr(handle, query) ) {
16626                 Sql_ShowDebug(handle);
16627                 script_pushint(st, -1);
16628                 return SCRIPT_CMD_FAILURE;
16629         }
16630
16631         if( Sql_NumRows(handle) == 0 ) { // No data received
16632                 Sql_FreeResult(handle);
16633                 script_pushint(st, 0);
16634                 return SCRIPT_CMD_SUCCESS;
16635         }
16636
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);
16645         }
16646
16647         // Store data
16648         for( i = 0; i < max_rows && SQL_SUCCESS == Sql_NextRow(handle); ++i ) {
16649                 for( j = 0; j < num_vars; ++j ) {
16650                         char* str = NULL;
16651
16652                         if( j < num_cols )
16653                                 Sql_GetData(handle, j, &str, NULL);
16654
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));
16659                         else
16660                                 setd_sub(st, sd, name, i, (void *)__64BPRTSIZE((str?atoi(str):0)), reference_getref(data));
16661                 }
16662         }
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);
16666         }
16667
16668         // Free data
16669         Sql_FreeResult(handle);
16670         script_pushint(st, i);
16671         return SCRIPT_CMD_SUCCESS;
16672 }
16673
16674 BUILDIN_FUNC(query_sql) {
16675 #ifdef BETA_THREAD_TEST
16676         if( st->state != RERUNLINE ) {
16677                 queryThread_add(st,false);
16678
16679                 st->state = RERUNLINE;/* will continue when the query is finished running. */
16680         } else
16681                 st->state = RUN;
16682
16683         return SCRIPT_CMD_SUCCESS;
16684 #else
16685         return buildin_query_sql_sub(st, qsmysql_handle);
16686 #endif
16687 }
16688
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;
16694         }
16695 #ifdef BETA_THREAD_TEST
16696         if( st->state != RERUNLINE ) {
16697                 queryThread_add(st,true);
16698
16699                 st->state = RERUNLINE;/* will continue when the query is finished running. */
16700         } else
16701                 st->state = RUN;
16702
16703         return SCRIPT_CMD_SUCCESS;
16704 #else
16705         return buildin_query_sql_sub(st, logmysql_handle);
16706 #endif
16707 }
16708
16709 //Allows escaping of a given string.
16710 BUILDIN_FUNC(escape_sql)
16711 {
16712         const char *str;
16713         char *esc_str;
16714         size_t len;
16715
16716         str = script_getstr(st,2);
16717         len = strlen(str);
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;
16722 }
16723
16724 BUILDIN_FUNC(getd)
16725 {
16726         char varname[100];
16727         const char *buffer;
16728         int elem;
16729
16730         buffer = script_getstr(st, 2);
16731
16732         if(sscanf(buffer, "%99[^[][%11d]", varname, &elem) < 2)
16733                 elem = 0;
16734
16735         // Push the 'pointer' so it's more flexible [Lance]
16736         push_val(st->stack, C_NAME, reference_uid(add_str(varname), elem));
16737
16738         return SCRIPT_CMD_SUCCESS;
16739 }
16740
16741 BUILDIN_FUNC(callshop)
16742 {
16743         TBL_PC *sd = NULL;
16744         struct npc_data *nd;
16745         const char *shopname;
16746         int flag = 0;
16747         if (!script_rid2sd(sd)) {
16748                 script_pushint(st,0);
16749                 return SCRIPT_CMD_SUCCESS;
16750         }
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;
16759         }
16760
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;
16764
16765                 switch (flag) {
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
16769                 }
16770         }
16771 #if PACKETVER >= 20131223
16772         else if (nd->subtype == NPCTYPE_MARKETSHOP) {
16773                 unsigned short i;
16774
16775                 for (i = 0; i < nd->u.shop.count; i++) {
16776                         if (nd->u.shop.shop_item[i].qty)
16777                                 break;
16778                 }
16779
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;
16783                 }
16784
16785                 sd->npc_shopid = nd->bl.id;
16786                 clif_npc_market_open(sd, nd);
16787                 script_pushint(st,1);
16788                 return SCRIPT_CMD_SUCCESS;
16789         }
16790 #endif
16791         else
16792                 clif_cashshop_show(sd, nd);
16793
16794         sd->npc_shopid = nd->bl.id;
16795         script_pushint(st,1);
16796         return SCRIPT_CMD_SUCCESS;
16797 }
16798
16799 BUILDIN_FUNC(npcshopitem)
16800 {
16801         const char* npcname = script_getstr(st, 2);
16802         struct npc_data* nd = npc_name2id(npcname);
16803         int n, i;
16804         int amount;
16805         uint16 offs = 2;
16806
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;
16810         }
16811
16812 #if PACKETVER >= 20131223
16813         if (nd->subtype == NPCTYPE_MARKETSHOP) {
16814                 offs = 3;
16815                 npc_market_delfromsql_(nd->exname, 0, true);
16816         }
16817 #endif
16818
16819         // get the count of new entries
16820         amount = (script_lastdata(st)-2)/offs;
16821
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]);
16832                 }
16833 #endif
16834         }
16835         nd->u.shop.count = n;
16836
16837         script_pushint(st,1);
16838         return SCRIPT_CMD_SUCCESS;
16839 }
16840
16841 BUILDIN_FUNC(npcshopadditem)
16842 {
16843         const char* npcname = script_getstr(st,2);
16844         struct npc_data* nd = npc_name2id(npcname);
16845         int n, i;
16846         uint16 offs = 2, amount;
16847
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;
16851         }
16852
16853         if (nd->subtype == NPCTYPE_MARKETSHOP)
16854                 offs = 3;
16855
16856         // get the count of new entries
16857         amount = (script_lastdata(st)-2)/offs;
16858
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;
16863
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++;
16871                         }
16872
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);
16876
16877                         npc_market_tosql(nd->exname, &nd->u.shop.shop_item[j]);
16878                 }
16879                 script_pushint(st,1);
16880                 return SCRIPT_CMD_SUCCESS;
16881         }
16882 #endif
16883
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)
16887         {
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);
16890         }
16891         nd->u.shop.count = n;
16892
16893         script_pushint(st,1);
16894         return SCRIPT_CMD_SUCCESS;
16895 }
16896
16897 BUILDIN_FUNC(npcshopdelitem)
16898 {
16899         const char* npcname = script_getstr(st,2);
16900         struct npc_data* nd = npc_name2id(npcname);
16901         int n, i, size;
16902         unsigned short amount;
16903
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;
16907         }
16908
16909         amount = script_lastdata(st)-2;
16910         size = nd->u.shop.count;
16911
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);
16915
16916                 ARR_FIND( 0, size, n, nd->u.shop.shop_item[n].nameid == nameid );
16917                 if( n < size ) {
16918                         if (n+1 != size)
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);
16923 #endif
16924                         size--;
16925                 }
16926         }
16927
16928         RECREATE(nd->u.shop.shop_item, struct npc_item_list, size);
16929         nd->u.shop.count = size;
16930
16931         script_pushint(st,1);
16932         return SCRIPT_CMD_SUCCESS;
16933 }
16934
16935 /**
16936  * Sets a script to attach to a shop npc.
16937  * npcshopattach "<npc_name>";
16938  **/
16939 BUILDIN_FUNC(npcshopattach)
16940 {
16941         const char* npcname = script_getstr(st,2);
16942         struct npc_data* nd = npc_name2id(npcname);
16943         int flag = 1;
16944
16945         if( script_hasdata(st,3) )
16946                 flag = script_getnum(st,3);
16947
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;
16951         }
16952
16953         if (flag)
16954                 nd->master_nd = ((struct npc_data *)map_id2bl(st->oid));
16955         else
16956                 nd->master_nd = NULL;
16957
16958         script_pushint(st,1);
16959         return SCRIPT_CMD_SUCCESS;
16960 }
16961
16962 /*==========================================
16963  * Returns some values of an item [Lupus]
16964  * Price, Weight, etc...
16965         setitemscript(itemID,"{new item bonus script}",[n]);
16966    Where n:
16967         0 - script
16968         1 - Equip script
16969         2 - Unequip script
16970  *------------------------------------------*/
16971 BUILDIN_FUNC(setitemscript)
16972 {
16973         unsigned short item_id;
16974         int n = 0;
16975         const char *script;
16976         struct item_data *i_data;
16977         struct script_code **dstscript;
16978
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);
16984
16985         if (!i_data || script==NULL || ( script[0] && script[0]!='{' )) {
16986                 script_pushint(st,0);
16987                 return SCRIPT_CMD_SUCCESS;
16988         }
16989         switch (n) {
16990         case 2:
16991                 dstscript = &i_data->unequip_script;
16992                 break;
16993         case 1:
16994                 dstscript = &i_data->equip_script;
16995                 break;
16996         default:
16997                 dstscript = &i_data->script;
16998                 break;
16999         }
17000         if(*dstscript)
17001                 script_free_code(*dstscript);
17002
17003         *dstscript = script[0] ? parse_script(script, "script_setitemscript", 0, 0) : NULL;
17004         script_pushint(st,1);
17005         return SCRIPT_CMD_SUCCESS;
17006 }
17007
17008 /*=======================================================
17009  * Add or Update a mob drop temporarily [Akinari]
17010  * Original Idea By: [Lupus]
17011  *
17012  * addmonsterdrop <mob_id or name>,<item_id>,<rate>;
17013  *
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)
17019 {
17020         struct mob_db *mob;
17021         struct script_data *data;
17022         unsigned short item_id;
17023         int rate;
17024
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)));
17029         else
17030                 mob = mob_db(script_getnum(st,2));
17031
17032         item_id=script_getnum(st,3);
17033         rate=script_getnum(st,4);
17034
17035         if(!itemdb_exists(item_id)){
17036                 ShowError("addmonsterdrop: Nonexistant item %hu requested.\n", item_id );
17037                 return SCRIPT_CMD_FAILURE;
17038         }
17039
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
17045                                         c = i;
17046                                         break;
17047                                 }
17048                                 continue;
17049                         }
17050                         if(!c) //Accept first available slot only
17051                                 c = i;
17052                 }
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);
17060         } else {
17061                 ShowWarning("addmonsterdrop: bad mob id given %d\n",script_getnum(st,2));
17062                 return SCRIPT_CMD_FAILURE;
17063         }
17064         return SCRIPT_CMD_SUCCESS;
17065
17066 }
17067
17068 /*=======================================================
17069  * Delete a mob drop temporarily [Akinari]
17070  * Original Idea By: [Lupus]
17071  *
17072  * delmonsterdrop <mob_id or name>,<item_id>;
17073  *
17074  * Returns 1 if succeeded (deleted a mob drop)
17075  *-------------------------------------------------------*/
17076 BUILDIN_FUNC(delmonsterdrop)
17077 {
17078         struct mob_db *mob;
17079         struct script_data *data;
17080         unsigned short item_id;
17081
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)));
17086         else
17087                 mob = mob_db(script_getnum(st,2));
17088
17089         item_id=script_getnum(st,3);
17090
17091         if(!itemdb_exists(item_id)){
17092                 ShowError("delmonsterdrop: Nonexistant item %hu requested.\n", item_id );
17093                 return SCRIPT_CMD_FAILURE;
17094         }
17095
17096         if(mob) { //We got a valid monster, check for item drop on monster
17097                 unsigned char i;
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;
17105                         }
17106                 }
17107                 //No drop on that monster
17108                 script_pushint(st,0);
17109         } else {
17110                 ShowWarning("delmonsterdrop: bad mob id given %d\n",script_getnum(st,2));
17111                 return SCRIPT_CMD_FAILURE;
17112         }
17113         return SCRIPT_CMD_SUCCESS;
17114 }
17115
17116
17117 /*==========================================
17118  * Returns some values of a monster [Lupus]
17119  * Name, Level, race, size, etc...
17120         getmonsterinfo(monsterID,queryIndex);
17121  *------------------------------------------*/
17122 BUILDIN_FUNC(getmonsterinfo)
17123 {
17124         struct mob_db *mob;
17125         int mob_id;
17126
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");
17132                 else
17133                         script_pushint(st,-1);
17134                 return SCRIPT_CMD_SUCCESS;
17135         }
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
17162         }
17163         return SCRIPT_CMD_SUCCESS;
17164 }
17165
17166 /**
17167  * Check player's vending/buyingstore/autotrade state
17168  * checkvending({"<Player Name>"})
17169  * @author [Nab4]
17170  */
17171 BUILDIN_FUNC(checkvending) {
17172         TBL_PC *sd = NULL;
17173
17174         if (!script_nick2sd(2,sd) ) {
17175                 script_pushint(st,0);
17176                 return SCRIPT_CMD_SUCCESS;
17177         }
17178         else {
17179                 int8 ret = 0;
17180                 if (sd->state.vending)
17181                         ret = 1;
17182                 else if (sd->state.buyingstore)
17183                         ret = 4;
17184
17185                 if (sd->state.autotrade)
17186                         ret |= 2;
17187                 script_pushint(st, ret);
17188         }
17189         return SCRIPT_CMD_SUCCESS;
17190 }
17191
17192
17193 BUILDIN_FUNC(checkchatting) // check chatting [Marka]
17194 {
17195         TBL_PC *sd = NULL;
17196
17197         if( script_nick2sd(2,sd) )
17198                 script_pushint(st,(sd->chatID != 0));
17199         else
17200                 script_pushint(st,0);
17201         return SCRIPT_CMD_SUCCESS;
17202 }
17203
17204 BUILDIN_FUNC(checkidle)
17205 {
17206         TBL_PC *sd = NULL;
17207
17208         if( script_nick2sd(2,sd) )
17209                 script_pushint(st, DIFF_TICK(last_tick, sd->idletime));
17210         else
17211                 script_pushint(st, 0);
17212         return SCRIPT_CMD_SUCCESS;
17213 }
17214
17215 BUILDIN_FUNC(searchitem)
17216 {
17217         struct script_data* data = script_getdata(st, 2);
17218         const char *itemname = script_getstr(st,3);
17219         struct item_data *items[MAX_SEARCH];
17220         int count;
17221
17222         char* name;
17223         int32 start;
17224         int32 id;
17225         int32 i;
17226         TBL_PC* sd = NULL;
17227
17228         if ((items[0] = itemdb_exists(atoi(itemname))))
17229                 count = 1;
17230         else
17231                 count = itemdb_searchname_array(items, ARRAYLENGTH(items), itemname);
17232
17233         if (!count) {
17234                 script_pushint(st, 0);
17235                 return SCRIPT_CMD_SUCCESS;
17236         }
17237
17238         if( !data_isreference(data) )
17239         {
17240                 ShowError("script:searchitem: not a variable\n");
17241                 script_reportdata(data);
17242                 st->state = END;
17243                 return SCRIPT_CMD_FAILURE;// not a variable
17244         }
17245
17246         id = reference_getid(data);
17247         start = reference_getindex(data);
17248         name = reference_getname(data);
17249
17250         if( not_server_variable(*name) && !script_rid2sd(sd) )
17251         {
17252                 return SCRIPT_CMD_SUCCESS;// no player attached
17253         }
17254
17255         if( is_string_variable(name) )
17256         {// string array
17257                 ShowError("script:searchitem: not an integer array reference\n");
17258                 script_reportdata(data);
17259                 st->state = END;
17260                 return SCRIPT_CMD_FAILURE;// not supported
17261         }
17262
17263         for( i = 0; i < count; ++start, ++i )
17264         {// Set array
17265                 void* v = (void*)__64BPRTSIZE((int)items[i]->nameid);
17266                 set_reg(st, sd, reference_uid(id, start), name, v, reference_getref(data));
17267         }
17268
17269         script_pushint(st, count);
17270         return SCRIPT_CMD_SUCCESS;
17271 }
17272
17273 // [zBuffer] List of player cont commands --->
17274 BUILDIN_FUNC(rid2name)
17275 {
17276         struct block_list *bl = NULL;
17277         int rid = script_getnum(st,2);
17278         if((bl = map_id2bl(rid)))
17279         {
17280                 switch(bl->type) {
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;
17287                         default:
17288                                 ShowError("buildin_rid2name: BL type unknown.\n");
17289                                 script_pushconststr(st,"");
17290                                 break;
17291                 }
17292         } else {
17293                 ShowError("buildin_rid2name: invalid RID\n");
17294                 script_pushconststr(st,"(null)");
17295         }
17296         return SCRIPT_CMD_SUCCESS;
17297 }
17298
17299 /**
17300  * Toggle a unit from moving.
17301  * pcblockmove(<unit_id>,<option>);
17302  */
17303 BUILDIN_FUNC(pcblockmove)
17304 {
17305         struct block_list *bl = NULL;
17306
17307         if (script_getnum(st, 2))
17308                 bl = map_id2bl(script_getnum(st,2));
17309         else
17310                 bl = map_id2bl(st->rid);
17311
17312         if (bl) {
17313                 struct unit_data *ud = unit_bl2ud(bl);
17314
17315                 if (ud)
17316                         ud->state.blockedmove = script_getnum(st,3) > 0;
17317         }
17318
17319         return SCRIPT_CMD_SUCCESS;
17320 }
17321
17322 /**
17323  * Toggle a unit from casting skills.
17324  * pcblockskill(<unit_id>,<option>);
17325  */
17326 BUILDIN_FUNC(pcblockskill)
17327 {
17328         struct block_list *bl = NULL;
17329
17330         if (script_getnum(st, 2))
17331                 bl = map_id2bl(script_getnum(st,2));
17332         else
17333                 bl = map_id2bl(st->rid);
17334
17335         if (bl) {
17336                 struct unit_data *ud = unit_bl2ud(bl);
17337
17338                 if (ud)
17339                         ud->state.blockedskill = script_getnum(st, 3) > 0;
17340         }
17341
17342         return SCRIPT_CMD_SUCCESS;
17343 }
17344
17345 BUILDIN_FUNC(pcfollow)
17346 {
17347         TBL_PC *sd;
17348
17349         if( script_mapid2sd(2,sd) )
17350                 pc_follow(sd, script_getnum(st,3));
17351
17352         return SCRIPT_CMD_SUCCESS;
17353 }
17354
17355 BUILDIN_FUNC(pcstopfollow)
17356 {
17357         TBL_PC *sd;
17358
17359         if(script_mapid2sd(2,sd))
17360                 pc_stop_following(sd);
17361
17362         return SCRIPT_CMD_SUCCESS;
17363 }
17364 // <--- [zBuffer] List of player cont commands
17365 // [zBuffer] List of unit control commands --->
17366
17367 /// Checks to see if the unit exists.
17368 ///
17369 /// unitexists <unit id>;
17370 BUILDIN_FUNC(unitexists)
17371 {
17372         struct block_list* bl;
17373
17374         bl = map_id2bl(script_getnum(st, 2));
17375
17376         if (!bl)
17377                 script_pushint(st, false);
17378         else
17379                 script_pushint(st, true);
17380
17381         return SCRIPT_CMD_SUCCESS;
17382 }
17383
17384 /// Gets the type of the given Game ID.
17385 ///
17386 /// getunittype <unit id>;
17387 BUILDIN_FUNC(getunittype)
17388 {
17389         struct block_list* bl;
17390         uint8 value = 0;
17391
17392         if(!script_rid2bl(2,bl))
17393         {
17394                 script_pushint(st, -1);
17395                 return SCRIPT_CMD_FAILURE;
17396         }
17397
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;
17407         }
17408
17409         script_pushint(st, value);
17410         return SCRIPT_CMD_SUCCESS;
17411 }
17412
17413 /// Gets specific live information of a bl.
17414 ///
17415 /// getunitdata <unit id>,<arrayname>;
17416 BUILDIN_FUNC(getunitdata)
17417 {
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;
17426         char* name;
17427         struct script_data *data = script_getdata(st, 3);
17428
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;
17432         }
17433
17434         if(!script_rid2bl(2,bl))
17435         {
17436                 script_pushint(st, -1);
17437                 return SCRIPT_CMD_FAILURE;
17438         }
17439
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;
17447                 default:
17448                         ShowWarning("buildin_getunitdata: Invalid object type!\n");
17449                         return SCRIPT_CMD_FAILURE;
17450         }
17451
17452         name = reference_getname(data);
17453
17454 #define getunitdata_sub(idx__,var__) setd_sub(st,sd,name,(idx__),(void *)__64BPRTSIZE((int)(var__)),data->ref)
17455
17456         switch(bl->type) {
17457                 case BL_MOB:
17458                         if (!md) {
17459                                 ShowWarning("buildin_getunitdata: Error in finding object BL_MOB!\n");
17460                                 return SCRIPT_CMD_FAILURE;
17461                         }
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);
17511                         break;
17512
17513                 case BL_HOM:
17514                         if (!hd) {
17515                                 ShowWarning("buildin_getunitdata: Error in finding object BL_HOM!\n");
17516                                 return SCRIPT_CMD_FAILURE;
17517                         }
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);
17557                         break;
17558
17559                 case BL_PET:
17560                         if (!pd) {
17561                                 ShowWarning("buildin_getunitdata: Error in finding object BL_PET!\n");
17562                                 return SCRIPT_CMD_FAILURE;
17563                         }
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);
17601                         break;
17602
17603                 case BL_MER:
17604                         if (!mc) {
17605                                 ShowWarning("buildin_getunitdata: Error in finding object BL_MER!\n");
17606                                 return SCRIPT_CMD_FAILURE;
17607                         }
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);
17644                         break;
17645
17646                 case BL_ELEM:
17647                         if (!ed) {
17648                                 ShowWarning("buildin_getunitdata: Error in finding object BL_ELEM!\n");
17649                                 return SCRIPT_CMD_FAILURE;
17650                         }
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);
17689                         break;
17690
17691                 case BL_NPC:
17692                         if (!nd) {
17693                                 ShowWarning("buildin_getunitdata: Error in finding object BL_NPC!\n");
17694                                 return SCRIPT_CMD_FAILURE;
17695                         }
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);
17729                         break;
17730
17731                 default:
17732                         ShowWarning("buildin_getunitdata: Unknown object type!\n");
17733                         return SCRIPT_CMD_FAILURE;
17734         }
17735
17736 #undef getunitdata_sub
17737
17738         return SCRIPT_CMD_SUCCESS;
17739 }
17740
17741 /// Changes the live data of a bl.
17742 ///
17743 /// setunitdata <unit id>,<type>,<value>;
17744 BUILDIN_FUNC(setunitdata)
17745 {
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;
17757
17758         if(!script_rid2bl(2,bl))
17759         {
17760                 script_pushint(st, -1);
17761                 return SCRIPT_CMD_FAILURE;
17762         }
17763
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;
17770                 case BL_NPC:
17771                         nd = map_id2nd(bl->id);
17772                         if (!nd->status.hp)
17773                                 status_calc_npc(nd, SCO_FIRST);
17774                         else
17775                                 status_calc_npc(nd, SCO_NONE);
17776                         break;
17777                 default:
17778                         ShowError("buildin_setunitdata: Invalid object!\n");
17779                         return SCRIPT_CMD_FAILURE;
17780         }
17781
17782         type = script_getnum(st, 3);
17783         data = script_getdata(st, 4);
17784         get_val(st, data);
17785
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);
17790         else {
17791                 ShowError("buildin_setunitdata: Invalid data type for argument #3 (%d).\n", data->type);
17792                 return SCRIPT_CMD_FAILURE;
17793         }
17794
17795         switch (bl->type) {
17796         case BL_MOB:
17797                 if (!md) {
17798                         ShowWarning("buildin_setunitdata: Error in finding object BL_MOB!\n");
17799                         return SCRIPT_CMD_FAILURE;
17800                 }
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));
17804                 }
17805
17806                 // Check if the view data will be modified
17807                 switch( type ){
17808                         case UMOB_SEX:
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:
17814                         case UMOB_HEADTOP:
17815                         case UMOB_CLOTHCOLOR:
17816                         case UMOB_SHIELD:
17817                         case UMOB_WEAPON:
17818                                 mob_set_dynamic_viewdata( md );
17819                                 break;
17820                 }
17821
17822                 switch (type) {
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:
17854                                 if (value > 0) {
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");
17858                                                 break;
17859                                         }
17860                                         md->base_status->mode = md2->status.mode;
17861                                         md->state.copy_master_mode = 1;
17862                                 } else
17863                                         md->state.copy_master_mode = 0;
17864                                 calc_status = true;
17865                                 break;
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;
17884                         default:
17885                                 ShowError("buildin_setunitdata: Unknown data identifier %d for BL_MOB.\n", type);
17886                                 return SCRIPT_CMD_FAILURE;
17887                         }
17888                         if (calc_status)
17889                                 status_calc_bl(&md->bl, SCB_BATTLE);
17890                 break;
17891
17892         case BL_HOM:
17893                 if (!hd) {
17894                         ShowWarning("buildin_setunitdata: Error in finding object BL_HOM!\n");
17895                         return SCRIPT_CMD_FAILURE;
17896                 }
17897                 switch (type) {
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;
17937                         default:
17938                                 ShowError("buildin_setunitdata: Unknown data identifier %d for BL_HOM.\n", type);
17939                                 return SCRIPT_CMD_FAILURE;
17940                         }
17941                         if (calc_status)
17942                                 status_calc_bl(&hd->bl, SCB_BATTLE);
17943                 break;
17944
17945         case BL_PET:
17946                 if (!pd) {
17947                         ShowWarning("buildin_setunitdata: Error in finding object BL_PET!\n");
17948                         return SCRIPT_CMD_FAILURE;
17949                 }
17950                 switch (type) {
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;
17988                         default:
17989                                 ShowError("buildin_setunitdata: Unknown data identifier %d for BL_PET.\n", type);
17990                                 return SCRIPT_CMD_FAILURE;
17991                         }
17992                 break;
17993
17994         case BL_MER:
17995                 if (!mc) {
17996                         ShowWarning("buildin_setunitdata: Error in finding object BL_MER!\n");
17997                         return SCRIPT_CMD_FAILURE;
17998                 }
17999                 switch (type) {
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;
18036                         default:
18037                                 ShowError("buildin_setunitdata: Unknown data identifier %d for BL_MER.\n", type);
18038                                 return SCRIPT_CMD_FAILURE;
18039                         }
18040                         if (calc_status)
18041                                 status_calc_bl(&mc->bl, SCB_BATTLE);
18042                 break;
18043
18044         case BL_ELEM:
18045                 if (!ed) {
18046                         ShowWarning("buildin_setunitdata: Error in finding object BL_ELEM!\n");
18047                         return SCRIPT_CMD_FAILURE;
18048                 }
18049                 switch (type) {
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;
18088                         default:
18089                                 ShowError("buildin_setunitdata: Unknown data identifier %d for BL_ELEM.\n", type);
18090                                 return SCRIPT_CMD_FAILURE;
18091                         }
18092                         if (calc_status)
18093                                 status_calc_bl(&ed->bl, SCB_BATTLE);
18094                 break;
18095
18096         case BL_NPC:
18097                 if (!nd) {
18098                         ShowWarning("buildin_setunitdata: Error in finding object BL_NPC!\n");
18099                         return SCRIPT_CMD_FAILURE;
18100                 }
18101                 switch (type) {
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;
18134                         default:
18135                                 ShowError("buildin_setunitdata: Unknown data identifier %d for BL_NPC.\n", type);
18136                                 return SCRIPT_CMD_FAILURE;
18137                         }
18138                 break;
18139
18140         default:
18141                 ShowWarning("buildin_setunitdata: Unknown object type!\n");
18142                 return SCRIPT_CMD_FAILURE;
18143         }
18144
18145         // Client information updates
18146         switch (bl->type) {
18147                 case BL_HOM:
18148                         clif_send_homdata(hd->master, SP_ACK, 0);
18149                         break;
18150                 case BL_PET:
18151                         clif_send_petstatus(pd->master);
18152                         break;
18153                 case BL_MER:
18154                         clif_mercenary_info(map_charid2sd(mc->mercenary.char_id));
18155                         clif_mercenary_skillblock(map_charid2sd(mc->mercenary.char_id));
18156                         break;
18157                 case BL_ELEM:
18158                         clif_elemental_info(ed->master);
18159                         break;
18160                 default:
18161                         ShowWarning("buildin_setunitdata: Invalid object type!\n");
18162                         return SCRIPT_CMD_FAILURE;
18163         }
18164
18165         return SCRIPT_CMD_SUCCESS;
18166 }
18167
18168 /// Gets the name of a bl.
18169 /// Supported types are [MOB|HOM|PET|NPC].
18170 /// MER and ELEM don't support custom names.
18171 ///
18172 /// getunitname <unit id>;
18173 BUILDIN_FUNC(getunitname)
18174 {
18175         struct block_list* bl = NULL;
18176
18177         if(!script_rid2bl(2,bl)){
18178                 script_pushconststr(st, "Unknown");
18179                 return SCRIPT_CMD_FAILURE;
18180         }
18181
18182         script_pushstrcopy(st, status_get_name(bl));
18183
18184         return SCRIPT_CMD_SUCCESS;
18185 }
18186
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.
18190 ///
18191 /// setunitname <unit id>,<name>;
18192 BUILDIN_FUNC(setunitname)
18193 {
18194         struct block_list* bl = NULL;
18195         TBL_MOB* md = NULL;
18196         TBL_HOM* hd = NULL;
18197         TBL_PET* pd = NULL;
18198
18199         if(!script_rid2bl(2,bl))
18200         {
18201                 script_pushconststr(st, "Unknown");
18202                 return SCRIPT_CMD_FAILURE;
18203         }
18204
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;
18209                 default:
18210                         ShowWarning("buildin_setunitname: Invalid object type!\n");
18211                         return SCRIPT_CMD_FAILURE;
18212         }
18213
18214         switch (bl->type) {
18215                 case BL_MOB:
18216                         if (!md) {
18217                                 ShowWarning("buildin_setunitname: Error in finding object BL_MOB!\n");
18218                                 return SCRIPT_CMD_FAILURE;
18219                         }
18220                         safestrncpy(md->name, script_getstr(st, 3), NAME_LENGTH);
18221                         break;
18222                 case BL_HOM:
18223                         if (!hd) {
18224                                 ShowWarning("buildin_setunitname: Error in finding object BL_HOM!\n");
18225                                 return SCRIPT_CMD_FAILURE;
18226                         }
18227                         safestrncpy(hd->homunculus.name, script_getstr(st, 3), NAME_LENGTH);
18228                         break;
18229                 case BL_PET:
18230                         if (!pd) {
18231                                 ShowWarning("buildin_setunitname: Error in finding object BL_PET!\n");
18232                                 return SCRIPT_CMD_FAILURE;
18233                         }
18234                         safestrncpy(pd->pet.name, script_getstr(st, 3), NAME_LENGTH);
18235                         break;
18236                 default:
18237                         ShowWarning("buildin_setunitname: Unknown object type!\n");
18238                         return SCRIPT_CMD_FAILURE;
18239         }
18240         clif_name_area(bl); // Send update to client.
18241
18242         return SCRIPT_CMD_SUCCESS;
18243 }
18244
18245 /// Makes the unit walk to target position or map.
18246 /// Returns if it was successful.
18247 ///
18248 /// unitwalk(<unit_id>,<x>,<y>{,<event_label>}) -> <bool>
18249 /// unitwalkto(<unit_id>,<target_id>{,<event_label>}) -> <bool>
18250 BUILDIN_FUNC(unitwalk)
18251 {
18252         struct block_list* bl;
18253         struct unit_data *ud = NULL;
18254         const char *cmd = script_getfuncname(st), *done_label = "";
18255         uint8 off = 5;
18256         
18257         if(!script_rid2bl(2,bl))
18258         {
18259                 script_pushint(st, 0);
18260                 return SCRIPT_CMD_FAILURE;
18261         }
18262
18263         ud = unit_bl2ud(bl);
18264
18265         if (!strcmp(cmd,"unitwalk")) {
18266                 int x = script_getnum(st,3);
18267                 int y = script_getnum(st,4);
18268
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
18271         } else {
18272                 struct block_list* tbl = map_id2bl(script_getnum(st,3));
18273
18274                 if (!tbl) {
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
18280                 off = 4;
18281         }
18282
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));
18287         }
18288
18289         return SCRIPT_CMD_SUCCESS;
18290 }
18291
18292 /// Kills the unit.
18293 ///
18294 /// unitkill <unit_id>;
18295 BUILDIN_FUNC(unitkill)
18296 {
18297         struct block_list* bl;
18298
18299         if(script_rid2bl(2,bl))
18300                 status_kill(bl);
18301
18302         return SCRIPT_CMD_SUCCESS;
18303 }
18304
18305 /// Warps the unit to the target position in the target map.
18306 /// Returns if it was successful.
18307 ///
18308 /// unitwarp(<unit_id>,"<map name>",<x>,<y>) -> <bool>
18309 BUILDIN_FUNC(unitwarp)
18310 {
18311         int map_idx;
18312         short x;
18313         short y;
18314         struct block_list* bl;
18315         const char *mapname;
18316
18317         mapname = script_getstr(st, 3);
18318         x = (short)script_getnum(st,4);
18319         y = (short)script_getnum(st,5);
18320
18321         if(!script_rid2bl(2,bl))
18322         {
18323                 script_pushint(st, 0);
18324                 return SCRIPT_CMD_SUCCESS;
18325         }
18326
18327         if (!strcmp(mapname,"this"))
18328                 map_idx = bl?bl->m:-1;
18329         else
18330                 map_idx = map_mapname2mapid(mapname);
18331
18332         if (map_idx >= 0 && bl != NULL)
18333                 script_pushint(st, unit_warp(bl,map_idx,x,y,CLR_OUTSIGHT));
18334         else
18335                 script_pushint(st, 0);
18336
18337         return SCRIPT_CMD_SUCCESS;
18338 }
18339
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.
18344 ///
18345 /// unitattack(<unit_id>,"<target name>"{,<action type>}) -> <bool>
18346 /// unitattack(<unit_id>,<target_id>{,<action type>}) -> <bool>
18347 BUILDIN_FUNC(unitattack)
18348 {
18349         struct block_list* unit_bl;
18350         struct block_list* target_bl = NULL;
18351         struct script_data* data;
18352         int actiontype = 0;
18353
18354         if (!script_rid2bl(2,unit_bl)) {
18355                 script_pushint(st, false);
18356                 return SCRIPT_CMD_FAILURE;
18357         }
18358
18359         data = script_getdata(st, 3);
18360         get_val(st, data);
18361
18362         if (data_isstring(data)) {
18363                 TBL_PC* sd = map_nick2sd(conv_str(st, data),false);
18364                 if( sd != NULL )
18365                         target_bl = &sd->bl;
18366         } else
18367                 target_bl = map_id2bl(conv_num(st, data));
18368
18369         if (!target_bl) {
18370                 script_pushint(st, false);
18371                 return SCRIPT_CMD_FAILURE;
18372         }
18373
18374         if (script_hasdata(st,4))
18375                 actiontype = script_getnum(st,4);
18376
18377         switch(unit_bl->type) {
18378                 case BL_PC: {
18379                         struct map_session_data* sd = (struct map_session_data*)unit_bl;
18380
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;
18384                 }
18385                 case BL_MOB:
18386                         ((TBL_MOB *)unit_bl)->target_id = target_bl->id;
18387                         break;
18388                 case BL_PET:
18389                         ((TBL_PET *)unit_bl)->target_id = target_bl->id;
18390                         break;
18391                 default:
18392                         ShowError("buildin_unitattack: Unsupported source unit type %d.\n", unit_bl->type);
18393                         script_pushint(st, false);
18394                         return SCRIPT_CMD_FAILURE;
18395         }
18396
18397         script_pushint(st, unit_walktobl(unit_bl, target_bl, 65025, 2));
18398         return SCRIPT_CMD_SUCCESS;
18399 }
18400
18401 /// Makes the unit stop attacking.
18402 ///
18403 /// unitstopattack <unit_id>;
18404 BUILDIN_FUNC(unitstopattack)
18405 {
18406         struct block_list* bl;
18407
18408         if(script_rid2bl(2,bl))
18409         {
18410                 unit_stop_attack(bl);
18411                 if (bl->type == BL_MOB)
18412                         ((TBL_MOB*)bl)->target_id = 0;
18413         }
18414
18415         return SCRIPT_CMD_SUCCESS;
18416 }
18417
18418 /// Makes the unit stop walking.
18419 ///
18420 /// unitstopwalk <unit_id>{,<flag>};
18421 BUILDIN_FUNC(unitstopwalk)
18422 {
18423         struct block_list* bl;
18424         int flag = USW_NONE;
18425
18426         if (script_hasdata(st, 3))
18427                 flag = script_getnum(st, 3);
18428
18429         if(script_rid2bl(2,bl))
18430                 unit_stop_walking(bl, flag);
18431
18432         return SCRIPT_CMD_SUCCESS;
18433 }
18434
18435 /**
18436  * Makes the unit say the given message.
18437  *
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.
18442  */
18443 BUILDIN_FUNC(unittalk)
18444 {
18445         const char* message;
18446         struct block_list* bl;
18447
18448         message = script_getstr(st, 3);
18449
18450         if(script_rid2bl(2,bl))
18451         {
18452                 send_target target = AREA;
18453                 struct StringBuf sbuf;
18454
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;
18460                                 }
18461                                 target = SELF;
18462                         }
18463                 }
18464
18465                 StringBuf_Init(&sbuf);
18466                 StringBuf_Printf(&sbuf, "%s", message);
18467                 clif_disp_overhead_(bl, StringBuf_Value(&sbuf), target);
18468                 StringBuf_Destroy(&sbuf);
18469         }
18470
18471         return SCRIPT_CMD_SUCCESS;
18472 }
18473
18474 /// Makes the unit do an emotion.
18475 ///
18476 /// unitemote <unit_id>,<emotion>;
18477 ///
18478 /// @see e_* in db/const.txt
18479 BUILDIN_FUNC(unitemote)
18480 {
18481         int emotion;
18482         struct block_list* bl;
18483
18484         emotion = script_getnum(st,3);
18485
18486         if(script_rid2bl(2,bl))
18487                 clif_emotion(bl, emotion);
18488
18489         return SCRIPT_CMD_SUCCESS;
18490 }
18491
18492 /// Makes the unit cast the skill on the target or self if no target is specified.
18493 ///
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)
18497 {
18498         int unit_id, target_id, casttime;
18499         uint16 skill_id, skill_lv;
18500         struct block_list* bl;
18501         struct script_data *data;
18502
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 );
18510         
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);
18515                         else
18516                                 status_calc_npc(((TBL_NPC*)bl), SCO_NONE);
18517                 }
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));
18519         }
18520
18521         return SCRIPT_CMD_SUCCESS;
18522 }
18523
18524 /// Makes the unit cast the skill on the target position.
18525 ///
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)
18529 {
18530         int skill_x, skill_y, casttime;
18531         uint16 skill_id, skill_lv;
18532         struct block_list* bl;
18533         struct script_data *data;
18534
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 );
18542
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);
18547                         else
18548                                 status_calc_npc(((TBL_NPC*)bl), SCO_NONE);
18549                 }
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));
18551         }
18552
18553         return SCRIPT_CMD_SUCCESS;
18554 }
18555
18556 // <--- [zBuffer] List of unit control commands
18557
18558 /// Pauses the execution of the script, detaching the player
18559 ///
18560 /// sleep <mili seconds>;
18561 BUILDIN_FUNC(sleep)
18562 {
18563         // First call(by function call)
18564         if (st->sleep.tick == 0) {
18565                 int ticks;
18566
18567                 ticks = script_getnum(st, 2);
18568
18569                 if (ticks <= 0) {
18570                         ShowError("buildin_sleep2: negative amount('%d') of milli seconds is not supported\n", ticks);
18571                         return SCRIPT_CMD_FAILURE;
18572                 }
18573
18574                 // detach the player
18575                 script_detach_rid(st);
18576
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)
18581         } else {                
18582                 // Continue the script
18583                 st->state = RUN;
18584                 st->sleep.tick = 0;
18585         }
18586
18587         return SCRIPT_CMD_SUCCESS;
18588 }
18589
18590 /// Pauses the execution of the script, keeping the unit attached
18591 /// Stops the script if no unit is attached
18592 ///
18593 /// sleep2(<milli seconds>)
18594 BUILDIN_FUNC(sleep2)
18595 {
18596         // First call(by function call)
18597         if (st->sleep.tick == 0) {
18598                 int ticks;
18599
18600                 ticks = script_getnum(st, 2);
18601
18602                 if (ticks <= 0) {
18603                         ShowError( "buildin_sleep2: negative amount('%d') of milli seconds is not supported\n", ticks );
18604                         return SCRIPT_CMD_FAILURE;
18605                 }
18606
18607                 if (map_id2bl(st->rid) == NULL) {
18608                         ShowError( "buildin_sleep2: no unit is attached\n" );
18609                         return SCRIPT_CMD_FAILURE;
18610                 }
18611                 
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)
18616         } else {                
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
18621                         st->rid = 0;
18622                         st->state = END;
18623                 } else {
18624                         // The unit is still attached - continue the script
18625                         st->state = RUN;
18626                         st->sleep.tick = 0;
18627                 }
18628         }
18629
18630         return SCRIPT_CMD_SUCCESS;
18631 }
18632
18633 /// Awakes all the sleep timers of the target npc
18634 ///
18635 /// awake "<npc name>";
18636 BUILDIN_FUNC(awake)
18637 {
18638         DBIterator *iter;
18639         struct script_state *tst;
18640         struct npc_data* nd;
18641
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;
18645         }
18646
18647         iter = db_iterator(st_db);
18648
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 ???
18652                                 continue;
18653                         }
18654
18655                         delete_timer(tst->sleep.timer, run_script_timer);
18656
18657                         // Trigger the timer function
18658                         run_script_timer(INVALID_TIMER, gettick(), tst->sleep.charid, (intptr_t)tst);
18659                 }
18660         }
18661         dbi_destroy(iter);
18662
18663         return SCRIPT_CMD_SUCCESS;
18664 }
18665
18666 /// Returns a reference to a variable of the target NPC.
18667 /// Returns 0 if an error occurs.
18668 ///
18669 /// getvariableofnpc(<variable>, "<npc name>") -> <reference>
18670 BUILDIN_FUNC(getvariableofnpc)
18671 {
18672         struct script_data* data;
18673         const char* name;
18674         struct npc_data* nd;
18675
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);
18682                 st->state = END;
18683                 return SCRIPT_CMD_FAILURE;
18684         }
18685
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);
18692                 st->state = END;
18693                 return SCRIPT_CMD_FAILURE;
18694         }
18695
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);
18701                 st->state = END;
18702                 return SCRIPT_CMD_FAILURE;
18703         }
18704
18705         if (!nd->u.scr.script->local.vars)
18706                 nd->u.scr.script->local.vars = i64db_alloc(DB_OPT_RELEASE_DATA);
18707
18708         push_val2(st->stack, C_NAME, reference_getuid(data), &nd->u.scr.script->local);
18709         return SCRIPT_CMD_SUCCESS;
18710 }
18711
18712 /// Opens a warp portal.
18713 /// Has no "portal opening" effect/sound, it opens the portal immediately.
18714 ///
18715 /// warpportal <source x>,<source y>,"<target map>",<target x>,<target y>;
18716 ///
18717 /// @author blackhole89
18718 BUILDIN_FUNC(warpportal)
18719 {
18720         int spx;
18721         int spy;
18722         unsigned short mapindex;
18723         int tpx;
18724         int tpy;
18725         struct skill_unit_group* group;
18726         struct block_list* bl;
18727
18728         bl = map_id2bl(st->oid);
18729         if( bl == NULL ) {
18730                 ShowError("buildin_warpportal: NPC is needed\n");
18731                 return SCRIPT_CMD_FAILURE;
18732         }
18733
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);
18739
18740         if( mapindex == 0 ) {
18741                 ShowError("buildin_warpportal: Target map not found %s.\n", script_getstr(st, 4));
18742                 return SCRIPT_CMD_FAILURE;
18743         }
18744
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;
18751
18752         return SCRIPT_CMD_SUCCESS;
18753 }
18754
18755 /**
18756  * openmail({<char_id>});
18757  **/
18758 BUILDIN_FUNC(openmail)
18759 {
18760         TBL_PC* sd;
18761
18762         if (!script_charid2sd(2,sd))
18763                 return SCRIPT_CMD_FAILURE;
18764
18765         mail_openmail(sd);
18766
18767         return SCRIPT_CMD_SUCCESS;
18768 }
18769
18770 /**
18771  * openauction({<char_id>});
18772  **/
18773 BUILDIN_FUNC(openauction)
18774 {
18775         TBL_PC* sd;
18776
18777         if (!script_charid2sd(2,sd))
18778                 return SCRIPT_CMD_FAILURE;
18779
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;
18783         }
18784
18785         clif_Auction_openwindow(sd);
18786
18787         return SCRIPT_CMD_SUCCESS;
18788 }
18789
18790 /// Retrieves the value of the specified flag of the specified cell.
18791 ///
18792 /// checkcell("<map name>",<x>,<y>,<type>) -> <bool>
18793 ///
18794 /// @see cell_chk* constants in const.txt for the types
18795 BUILDIN_FUNC(checkcell)
18796 {
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);
18801
18802         script_pushint(st, map_getcell(m, x, y, type));
18803
18804         return SCRIPT_CMD_SUCCESS;
18805 }
18806
18807 /// Modifies flags of cells in the specified area.
18808 ///
18809 /// setcell "<map name>",<x1>,<y1>,<x2>,<y2>,<type>,<flag>;
18810 ///
18811 /// @see cell_* constants in const.txt for the types
18812 BUILDIN_FUNC(setcell)
18813 {
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;
18821
18822         int x,y;
18823
18824         if( x1 > x2 ) SWAP(x1,x2);
18825         if( y1 > y2 ) SWAP(y1,y2);
18826
18827         for( y = y1; y <= y2; ++y )
18828                 for( x = x1; x <= x2; ++x )
18829                         map_setcell(m, x, y, type, flag);
18830
18831         return SCRIPT_CMD_SUCCESS;
18832 }
18833
18834 /**
18835  * Gets a free cell in the specified area.
18836  * getfreecell "<map name>",<rX>,<rY>{,<x>,<y>,<rangeX>,<rangeY>,<flag>};
18837  */
18838 BUILDIN_FUNC(getfreecell)
18839 {
18840         const char *mapn = script_getstr(st, 2), *name;
18841         char prefix;
18842         struct map_session_data *sd;
18843         int64 num;
18844         int16 m, x = 0, y = 0;
18845         int rx = -1, ry = -1, flag = 1;
18846
18847         sd = map_id2sd(st->rid);
18848
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;
18853         }
18854
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;
18859         }
18860
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;
18865         }
18866
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;
18871         }
18872
18873         if (script_hasdata(st, 5))
18874                 x = script_getnum(st, 5);
18875
18876         if (script_hasdata(st, 6))
18877                 y = script_getnum(st, 6);
18878
18879         if (script_hasdata(st, 7))
18880                 rx = script_getnum(st, 7);
18881
18882         if (script_hasdata(st, 8))
18883                 ry = script_getnum(st, 8);
18884
18885         if (script_hasdata(st, 9))
18886                 flag = script_getnum(st, 9);
18887
18888         if (sd && strcmp(mapn, "this") == 0)
18889                 m = sd->bl.m;
18890         else
18891                 m = map_mapname2mapid(mapn);
18892
18893         map_search_freecell(NULL, m, &x, &y, rx, ry, flag);
18894
18895         // Set MapX
18896         num = st->stack->stack_data[st->start + 3].u.num;
18897         name = get_str(num&0x00ffffff);
18898         prefix = *name;
18899
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;
18904                 }
18905         }else
18906                 sd = NULL;
18907
18908         set_reg(st, sd, num, name, (void*)__64BPRTSIZE((int)x), script_getref(st, 3));
18909
18910         // Set MapY
18911         num = st->stack->stack_data[st->start + 4].u.num;
18912         name = get_str(num&0x00ffffff);
18913         prefix = *name;
18914
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;
18919                 }
18920         }else
18921                 sd = NULL;
18922
18923         set_reg(st, sd, num, name, (void*)__64BPRTSIZE((int)y), script_getref(st, 4));
18924
18925         return SCRIPT_CMD_SUCCESS;
18926 }
18927
18928 /*==========================================
18929  * Mercenary Commands
18930  *------------------------------------------*/
18931 BUILDIN_FUNC(mercenary_create)
18932 {
18933         struct map_session_data *sd;
18934         int class_, contract_time;
18935
18936         if( !script_rid2sd(sd) || sd->md || sd->status.mer_id != 0 )
18937                 return SCRIPT_CMD_SUCCESS;
18938
18939         class_ = script_getnum(st,2);
18940
18941         if( !mercenary_class(class_) )
18942                 return SCRIPT_CMD_SUCCESS;
18943
18944         contract_time = script_getnum(st,3);
18945         mercenary_create(sd, class_, contract_time);
18946
18947         return SCRIPT_CMD_SUCCESS;
18948 }
18949
18950 BUILDIN_FUNC(mercenary_heal)
18951 {
18952         struct map_session_data *sd;
18953         int hp, sp;
18954
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);
18959
18960         status_heal(&sd->md->bl, hp, sp, 0);
18961         return SCRIPT_CMD_SUCCESS;
18962 }
18963
18964 BUILDIN_FUNC(mercenary_sc_start)
18965 {
18966         struct map_session_data *sd;
18967         enum sc_type type;
18968         int tick, val1;
18969
18970         if( !script_rid2sd(sd) || sd->md == NULL )
18971                 return SCRIPT_CMD_SUCCESS;
18972
18973         type = (sc_type)script_getnum(st,2);
18974         tick = script_getnum(st,3);
18975         val1 = script_getnum(st,4);
18976
18977         status_change_start(NULL, &sd->md->bl, type, 10000, val1, 0, 0, 0, tick, SCSTART_NOTICKDEF);
18978         return SCRIPT_CMD_SUCCESS;
18979 }
18980
18981 BUILDIN_FUNC(mercenary_get_calls)
18982 {
18983         struct map_session_data *sd;
18984         int guild;
18985
18986         if( !script_rid2sd(sd) )
18987                 return SCRIPT_CMD_SUCCESS;
18988
18989         guild = script_getnum(st,2);
18990         switch( guild )
18991         {
18992                 case ARCH_MERC_GUILD:
18993                         script_pushint(st,sd->status.arch_calls);
18994                         break;
18995                 case SPEAR_MERC_GUILD:
18996                         script_pushint(st,sd->status.spear_calls);
18997                         break;
18998                 case SWORD_MERC_GUILD:
18999                         script_pushint(st,sd->status.sword_calls);
19000                         break;
19001                 default:
19002                         script_pushint(st,0);
19003                         break;
19004         }
19005         return SCRIPT_CMD_SUCCESS;
19006 }
19007
19008 BUILDIN_FUNC(mercenary_set_calls)
19009 {
19010         struct map_session_data *sd;
19011         int guild, value, *calls;
19012
19013         if( !script_rid2sd(sd) )
19014                 return SCRIPT_CMD_SUCCESS;
19015
19016         guild = script_getnum(st,2);
19017         value = script_getnum(st,3);
19018
19019         switch( guild )
19020         {
19021                 case ARCH_MERC_GUILD:
19022                         calls = &sd->status.arch_calls;
19023                         break;
19024                 case SPEAR_MERC_GUILD:
19025                         calls = &sd->status.spear_calls;
19026                         break;
19027                 case SWORD_MERC_GUILD:
19028                         calls = &sd->status.sword_calls;
19029                         break;
19030                 default:
19031                         ShowError("buildin_mercenary_set_calls: Invalid guild '%d'.\n", guild);
19032                         return SCRIPT_CMD_SUCCESS; // Invalid Guild
19033         }
19034
19035         *calls += value;
19036         *calls = cap_value(*calls, 0, INT_MAX);
19037         return SCRIPT_CMD_SUCCESS;
19038 }
19039
19040 BUILDIN_FUNC(mercenary_get_faith)
19041 {
19042         struct map_session_data *sd;
19043         int guild;
19044
19045         if( !script_rid2sd(sd) )
19046                 return SCRIPT_CMD_SUCCESS;
19047
19048         guild = script_getnum(st,2);
19049         switch( guild )
19050         {
19051                 case ARCH_MERC_GUILD:
19052                         script_pushint(st,sd->status.arch_faith);
19053                         break;
19054                 case SPEAR_MERC_GUILD:
19055                         script_pushint(st,sd->status.spear_faith);
19056                         break;
19057                 case SWORD_MERC_GUILD:
19058                         script_pushint(st,sd->status.sword_faith);
19059                         break;
19060                 default:
19061                         script_pushint(st,0);
19062                         break;
19063         }
19064         return SCRIPT_CMD_SUCCESS;
19065 }
19066
19067 BUILDIN_FUNC(mercenary_set_faith)
19068 {
19069         struct map_session_data *sd;
19070         int guild, value, *calls;
19071
19072         if( !script_rid2sd(sd) )
19073                 return SCRIPT_CMD_SUCCESS;
19074
19075         guild = script_getnum(st,2);
19076         value = script_getnum(st,3);
19077
19078         switch( guild )
19079         {
19080                 case ARCH_MERC_GUILD:
19081                         calls = &sd->status.arch_faith;
19082                         break;
19083                 case SPEAR_MERC_GUILD:
19084                         calls = &sd->status.spear_faith;
19085                         break;
19086                 case SWORD_MERC_GUILD:
19087                         calls = &sd->status.sword_faith;
19088                         break;
19089                 default:
19090                         ShowError("buildin_mercenary_set_faith: Invalid guild '%d'.\n", guild);
19091                         return SCRIPT_CMD_SUCCESS; // Invalid Guild
19092         }
19093
19094         *calls += value;
19095         *calls = cap_value(*calls, 0, INT_MAX);
19096         if( mercenary_get_guild(sd->md) == guild )
19097                 clif_mercenary_updatestatus(sd,SP_MERCFAITH);
19098
19099         return SCRIPT_CMD_SUCCESS;
19100 }
19101
19102 /*------------------------------------------
19103  * Book Reading
19104  *------------------------------------------*/
19105 BUILDIN_FUNC(readbook)
19106 {
19107         struct map_session_data *sd;
19108         int book_id, page;
19109
19110         if( !script_rid2sd(sd) )
19111                 return SCRIPT_CMD_SUCCESS;
19112
19113         book_id = script_getnum(st,2);
19114         page = script_getnum(st,3);
19115
19116         clif_readbook(sd->fd, book_id, page);
19117         return SCRIPT_CMD_SUCCESS;
19118 }
19119
19120 /******************
19121 Questlog script commands
19122 *******************/
19123  /**
19124  * Add job criteria to questinfo
19125  * @param qi Quest Info
19126  * @param job
19127  * @author [Cydh]
19128  **/
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;
19132 }
19133 /**
19134  * questinfo <Quest ID>,<Icon>{,<Map Mark Color>{,<Job Class>}};
19135  **/
19136 BUILDIN_FUNC(questinfo)
19137 {
19138         TBL_NPC* nd = map_id2nd(st->oid);
19139         int quest_id, icon, color = 0;
19140         struct questinfo qi, *q2;
19141
19142         if( nd == NULL || nd->bl.m == -1 ) {
19143                 ShowError("buildin_questinfo: No NPC attached.\n");
19144                 return SCRIPT_CMD_FAILURE;
19145         }
19146
19147         quest_id = script_getnum(st, 2);
19148         icon = script_getnum(st, 3);
19149
19150 #if PACKETVER >= 20120410
19151         switch(icon){
19152                 case QTYPE_QUEST:
19153                 case QTYPE_QUEST2:
19154                 case QTYPE_JOB:
19155                 case QTYPE_JOB2:
19156                 case QTYPE_EVENT:
19157                 case QTYPE_EVENT2:
19158                 case QTYPE_WARG:
19159                 case QTYPE_WARG2:
19160                         // Leave everything as it is
19161                         break;
19162                 case QTYPE_NONE:
19163                 default:
19164                         // Default to nothing if icon id is invalid.
19165                         icon = QTYPE_NONE;
19166                         break;
19167         }
19168 #else
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;
19171         else
19172                 icon = icon + 1;
19173 #endif
19174
19175         qi.quest_id = quest_id;
19176         qi.icon = (unsigned char)icon;
19177         qi.nd = nd;
19178
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);
19184                         color = 0;
19185                 }
19186         }
19187         qi.color = (unsigned char)color;
19188
19189         qi.min_level = 1;
19190         qi.max_level = MAX_LEVEL;
19191
19192         q2 = map_add_questinfo(nd->bl.m, &qi);
19193         q2->req = NULL;
19194         q2->req_count = 0;
19195         q2->jobid = NULL;
19196         q2->jobid_count = 0;
19197
19198         if(script_hasdata(st, 5)) {
19199                 int job = script_getnum(st, 5);
19200
19201                 if (!pcdb_checkid(job))
19202                         ShowError("buildin_questinfo: Nonexistant Job Class.\n");
19203                 else {
19204                         buildin_questinfo_setjob(q2, job);
19205                 }
19206         }
19207
19208         return SCRIPT_CMD_SUCCESS;
19209 }
19210
19211 /**
19212  * setquest <ID>{,<char_id>};
19213  **/
19214 BUILDIN_FUNC(setquest)
19215 {
19216         struct map_session_data *sd;
19217         int quest_id;
19218
19219         quest_id = script_getnum(st, 2);
19220
19221         if (!script_charid2sd(3,sd))
19222                 return SCRIPT_CMD_FAILURE;
19223
19224         if( quest_add(sd, quest_id)  == -1 ){
19225                 script_reportsrc(st);
19226                 script_reportfunc(st);
19227         }
19228
19229         //20120410 or 20090218 ? no reason that shouldn't work for 2009
19230         pc_show_questinfo(sd); 
19231         return SCRIPT_CMD_SUCCESS;
19232 }
19233
19234 /**
19235  * erasequest <ID>{,<char_id>};
19236  **/
19237 BUILDIN_FUNC(erasequest)
19238 {
19239         struct map_session_data *sd;
19240
19241         if (!script_charid2sd(3,sd))
19242                 return SCRIPT_CMD_FAILURE;
19243
19244         if( quest_delete(sd, script_getnum(st, 2))  == -1 ){
19245                 script_reportsrc(st);
19246                 script_reportfunc(st);
19247         }
19248
19249         return SCRIPT_CMD_SUCCESS;
19250 }
19251
19252 /**
19253  * completequest <ID>{,<char_id>};
19254  **/
19255 BUILDIN_FUNC(completequest)
19256 {
19257         struct map_session_data *sd;
19258
19259         if (!script_charid2sd(3,sd))
19260                 return SCRIPT_CMD_FAILURE;
19261
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;
19266 }
19267
19268 /**
19269  * changequest <ID>,<ID2>{,<char_id>};
19270  **/
19271 BUILDIN_FUNC(changequest)
19272 {
19273         struct map_session_data *sd;
19274         
19275         if (!script_charid2sd(4,sd))
19276                 return SCRIPT_CMD_FAILURE;
19277
19278         if( quest_change(sd, script_getnum(st, 2),script_getnum(st, 3)) == -1 ){
19279                 script_reportsrc(st);
19280                 script_reportfunc(st);
19281         }
19282
19283         //20120410 or 20090218
19284         pc_show_questinfo(sd);
19285         return SCRIPT_CMD_SUCCESS;
19286 }
19287
19288 /**
19289  * checkquest(<ID>{,PLAYTIME|HUNTING{,<char_id>}})
19290  **/
19291 BUILDIN_FUNC(checkquest)
19292 {
19293         struct map_session_data *sd;
19294         enum quest_check_type type = HAVEQUEST;
19295
19296         if( script_hasdata(st, 3) )
19297                 type = (enum quest_check_type)script_getnum(st, 3);
19298
19299         if (!script_charid2sd(4,sd))
19300                 return SCRIPT_CMD_FAILURE;
19301
19302         script_pushint(st, quest_check(sd, script_getnum(st, 2), type));
19303
19304         return SCRIPT_CMD_SUCCESS;
19305 }
19306
19307 /**
19308  * isbegin_quest(<ID>{,<char_id>})
19309  **/
19310 BUILDIN_FUNC(isbegin_quest)
19311 {
19312         struct map_session_data *sd;
19313         int i;
19314
19315         if (!script_charid2sd(3,sd))
19316                 return SCRIPT_CMD_FAILURE;
19317
19318         i = quest_check(sd, script_getnum(st, 2), (enum quest_check_type) HAVEQUEST);
19319         script_pushint(st, i + (i < 1));
19320
19321         return SCRIPT_CMD_SUCCESS;
19322 }
19323
19324 /**
19325  * showevent <icon>{,<mark color>{,<char_id>}}
19326  **/
19327 BUILDIN_FUNC(showevent)
19328 {
19329         TBL_PC *sd;
19330         struct npc_data *nd = map_id2nd(st->oid);
19331         int icon, color = 0;
19332
19333         if (!script_charid2sd(4,sd))
19334                 return SCRIPT_CMD_FAILURE;
19335
19336         if( sd == NULL || nd == NULL )
19337                 return SCRIPT_CMD_SUCCESS;
19338
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);
19345                         color = 0;
19346                 }
19347         }
19348
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.
19352 #else
19353         if(icon < 0 || icon > 7)
19354                 icon = 0;
19355         else
19356                 icon = icon + 1;
19357 #endif
19358
19359         clif_quest_show_event(sd, &nd->bl, icon, color);
19360         return SCRIPT_CMD_SUCCESS;
19361 }
19362
19363 /*==========================================
19364  * BattleGround System
19365  *------------------------------------------*/
19366 BUILDIN_FUNC(waitingroom2bg)
19367 {
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;
19373
19374         if( script_hasdata(st,7) )
19375                 nd = npc_name2id(script_getstr(st,7));
19376         else
19377                 nd = (struct npc_data *)map_id2bl(st->oid);
19378
19379         if( nd == NULL || (cd = (struct chat_data *)map_id2bl(nd->chat_id)) == NULL )
19380         {
19381                 script_pushint(st,0);
19382                 return SCRIPT_CMD_SUCCESS;
19383         }
19384
19385         map_name = script_getstr(st,2);
19386         if (strcmp(map_name, "-") != 0 && (mapindex = mapindex_name2id(map_name)) == 0)
19387         { // Invalid Map
19388                 script_pushint(st, 0);
19389                 return SCRIPT_CMD_SUCCESS;
19390         }
19391
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
19398
19399         check_event(st, ev);
19400         check_event(st, dev);
19401
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;
19406         }
19407
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);
19412                         ++c;
19413                 }
19414         }
19415
19416         mapreg_setreg(add_str("$@arenamembersnum"), c);
19417         script_pushint(st,bg_id);
19418         return SCRIPT_CMD_SUCCESS;
19419 }
19420
19421 BUILDIN_FUNC(waitingroom2bg_single)
19422 {
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;
19429
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;
19434         }
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
19440                 }
19441                 x = script_getnum(st, 4);
19442                 y = script_getnum(st, 5);
19443         }
19444         else {
19445                 mapindex = bg->mapindex;
19446                 x = bg->x;
19447                 y = bg->y;
19448         }
19449
19450         nd = npc_name2id(script_getstr(st,6));
19451
19452         if( nd == NULL || (cd = (struct chat_data *)map_id2bl(nd->chat_id)) == NULL || cd->users <= 0 )
19453                 return SCRIPT_CMD_SUCCESS;
19454
19455         if( (sd = cd->usersd[0]) == NULL )
19456                 return SCRIPT_CMD_SUCCESS;
19457
19458         if( bg_team_join(bg_id, sd) && pc_setpos(sd, mapindex, x, y, CLR_TELEPORT) == SETPOS_OK)
19459         {
19460                 script_pushint(st, true);
19461         }
19462         else
19463                 script_pushint(st, false);
19464
19465         return SCRIPT_CMD_SUCCESS;
19466 }
19467
19468
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;
19475
19476         map_name = script_getstr(st, 2);
19477         if (strcmp(map_name, "-") != 0 && (mapindex = mapindex_name2id(map_name)) == 0)
19478         { // Invalid Map
19479                 script_pushint(st, 0);
19480                 return SCRIPT_CMD_SUCCESS;
19481         }
19482
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
19489
19490         check_event(st, ev);
19491         check_event(st, dev);
19492
19493         script_pushint(st, bg_create(mapindex, x, y, ev, dev));
19494         return SCRIPT_CMD_SUCCESS;
19495 }
19496
19497 /// Adds attached player or <char id> (if specified) to an existing 
19498 /// battleground group and warps it to the specified coordinates on
19499 /// the given map.
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;
19507
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;
19512         }
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
19518                 }
19519                 x = script_getnum(st, 4);
19520                 y = script_getnum(st, 5);
19521         } else {
19522                 mapindex = bg->mapindex;
19523                 x = bg->x;
19524                 y = bg->y;
19525         }
19526
19527         if (!script_charid2sd(6, sd)) {
19528                 script_pushint(st, false);
19529                 return SCRIPT_CMD_FAILURE;
19530         }
19531
19532         if (bg_team_join(bg_id, sd) && pc_setpos(sd, mapindex, x, y, CLR_TELEPORT) == SETPOS_OK)
19533         {
19534                 script_pushint(st, true);
19535         }
19536         else
19537                 script_pushint(st, false);
19538
19539         return SCRIPT_CMD_SUCCESS;
19540 }
19541
19542 BUILDIN_FUNC(bg_team_setxy)
19543 {
19544         struct battleground_data *bg;
19545         int bg_id;
19546
19547         bg_id = script_getnum(st,2);
19548         if( (bg = bg_team_search(bg_id)) == NULL )
19549                 return SCRIPT_CMD_SUCCESS;
19550
19551         bg->x = script_getnum(st,3);
19552         bg->y = script_getnum(st,4);
19553         return SCRIPT_CMD_SUCCESS;
19554 }
19555
19556 BUILDIN_FUNC(bg_warp)
19557 {
19558         int x, y, mapindex, bg_id;
19559         const char* map_name;
19560
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;
19569 }
19570
19571 BUILDIN_FUNC(bg_monster)
19572 {
19573         int class_ = 0, x = 0, y = 0, bg_id = 0;
19574         const char *str,*mapname, *evt="";
19575
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;
19586 }
19587
19588 BUILDIN_FUNC(bg_monster_set_team)
19589 {
19590         struct mob_data *md;
19591         struct block_list *mbl;
19592         int id = script_getnum(st,2),
19593                 bg_id = script_getnum(st,3);
19594
19595         if( id == 0 || (mbl = map_id2bl(id)) == NULL || mbl->type != BL_MOB )
19596                 return SCRIPT_CMD_SUCCESS;
19597         md = (TBL_MOB *)mbl;
19598         md->bg_id = bg_id;
19599
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);
19604
19605         return SCRIPT_CMD_SUCCESS;
19606 }
19607
19608 BUILDIN_FUNC(bg_leave)
19609 {
19610         struct map_session_data *sd = NULL;
19611         if( !script_charid2sd(2,sd) || !sd->bg_id )
19612                 return SCRIPT_CMD_SUCCESS;
19613
19614         bg_team_leave(sd,0);
19615         return SCRIPT_CMD_SUCCESS;
19616 }
19617
19618 BUILDIN_FUNC(bg_destroy)
19619 {
19620         int bg_id = script_getnum(st,2);
19621         bg_team_delete(bg_id);
19622         return SCRIPT_CMD_SUCCESS;
19623 }
19624
19625 BUILDIN_FUNC(bg_getareausers)
19626 {
19627         const char *str;
19628         int16 m, x0, y0, x1, y1;
19629         int bg_id;
19630         int i = 0, c = 0;
19631         struct battleground_data *bg = NULL;
19632
19633         bg_id = script_getnum(st,2);
19634         str = script_getstr(st,3);
19635
19636         if( (bg = bg_team_search(bg_id)) == NULL || (m = map_mapname2mapid(str)) < 0 )
19637         {
19638                 script_pushint(st,0);
19639                 return SCRIPT_CMD_SUCCESS;
19640         }
19641
19642         x0 = script_getnum(st,4);
19643         y0 = script_getnum(st,5);
19644         x1 = script_getnum(st,6);
19645         y1 = script_getnum(st,7);
19646
19647         for( i = 0; i < MAX_BG_MEMBERS; i++ )
19648         {
19649                 struct map_session_data *sd;
19650                 if( (sd = bg->members[i].sd) == NULL )
19651                         continue;
19652                 if( sd->bl.m != m || sd->bl.x < x0 || sd->bl.y < y0 || sd->bl.x > x1 || sd->bl.y > y1 )
19653                         continue;
19654                 c++;
19655         }
19656
19657         script_pushint(st,c);
19658         return SCRIPT_CMD_SUCCESS;
19659 }
19660
19661 BUILDIN_FUNC(bg_updatescore)
19662 {
19663         const char *str;
19664         int16 m;
19665
19666         str = script_getstr(st,2);
19667         if( (m = map_mapname2mapid(str)) < 0 )
19668                 return SCRIPT_CMD_SUCCESS;
19669
19670         map[m].bgscore_lion = script_getnum(st,3);
19671         map[m].bgscore_eagle = script_getnum(st,4);
19672
19673         clif_bg_updatescore(m);
19674         return SCRIPT_CMD_SUCCESS;
19675 }
19676
19677 BUILDIN_FUNC(bg_get_data)
19678 {
19679         struct battleground_data *bg;
19680         int bg_id = script_getnum(st,2),
19681                 type = script_getnum(st,3), i;
19682
19683         if( (bg = bg_team_search(bg_id)) == NULL )
19684         {
19685                 script_pushint(st,0);
19686                 return SCRIPT_CMD_SUCCESS;
19687         }
19688
19689         switch( type )
19690         {
19691                 case 0: script_pushint(st, bg->count); break;
19692                 case 1:
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);
19697                         break;
19698                 default:
19699                         ShowError("script:bg_get_data: unknown data identifier %d\n", type);
19700                         break;
19701         }
19702
19703         return SCRIPT_CMD_SUCCESS;
19704 }
19705
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)
19712 {
19713         unsigned short instance_id = 0;
19714         struct npc_data *nd;
19715
19716         if( (nd = map_id2nd(st->oid)) && nd->instance_id > 0 )
19717                 instance_id = nd->instance_id;
19718         else {
19719                 struct map_session_data *sd = NULL;
19720                 struct party_data *pd = NULL;
19721                 struct guild *gd = NULL;
19722                 struct clan *cd = NULL;
19723
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;
19733                 }
19734         }
19735
19736         return instance_id;
19737 }
19738
19739 /*==========================================
19740  * Creates the instance
19741  * Returns Instance ID if created successfully
19742  *------------------------------------------*/
19743 BUILDIN_FUNC(instance_create)
19744 {
19745         enum instance_mode mode = IM_PARTY;
19746         int owner_id = 0;
19747
19748         if (script_hasdata(st, 3)) {
19749                 mode = static_cast<instance_mode>(script_getnum(st, 3));
19750
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;
19754                 }
19755         }
19756         if (script_hasdata(st, 4))
19757                 owner_id = script_getnum(st, 4);
19758         else {
19759                 // If sd is NULL, instance_create will return -2.
19760                 struct map_session_data *sd = NULL;
19761
19762                 switch(mode) {
19763                         case IM_NONE:
19764                                 owner_id = st->oid;
19765                                 break;
19766                         case IM_CHAR:
19767                                 if (script_rid2sd(sd))
19768                                         owner_id = sd->status.char_id;
19769                                 break;
19770                         case IM_PARTY:
19771                                 if (script_rid2sd(sd))
19772                                         owner_id = sd->status.party_id;
19773                                 break;
19774                         case IM_GUILD:
19775                                 if (script_rid2sd(sd))
19776                                         owner_id = sd->status.guild_id;
19777                                 break;
19778                         case IM_CLAN:
19779                                 if (script_rid2sd(sd))
19780                                         owner_id = sd->status.clan_id;
19781                                 break;
19782                         default:
19783                                 ShowError("buildin_instance_create: Invalid instance mode (instance name: %s)\n", script_getstr(st, 2));
19784                                 return SCRIPT_CMD_FAILURE;
19785                 }
19786         }
19787
19788         script_pushint(st, instance_create(owner_id, script_getstr(st, 2), mode));
19789         return SCRIPT_CMD_SUCCESS;
19790 }
19791
19792 /*==========================================
19793  * Destroys an instance (unofficial)
19794  * Officially instances are only destroyed by timeout
19795  *
19796  * instance_destroy {<instance_id>};
19797  *------------------------------------------*/
19798 BUILDIN_FUNC(instance_destroy)
19799 {
19800         unsigned short instance_id;
19801
19802         if( script_hasdata(st,2) )
19803                 instance_id = script_getnum(st,2);
19804         else
19805                 instance_id = script_instancegetid(st);
19806
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;
19810         }
19811
19812         instance_destroy(instance_id);
19813         return SCRIPT_CMD_SUCCESS;
19814 }
19815
19816 /*==========================================
19817  * Warps player to instance
19818  * Results:
19819  *      IE_OK: Success
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)
19825 {
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;
19830
19831         if (script_hasdata(st, 6))
19832                 instance_id = script_getnum(st, 6);
19833         else
19834                 instance_id = script_instancegetid(st);
19835
19836         if (!script_charid2sd(5,sd))
19837                 return SCRIPT_CMD_FAILURE;
19838
19839         script_pushint(st, instance_enter(sd, instance_id, script_getstr(st, 2), x, y));
19840
19841         return SCRIPT_CMD_SUCCESS;
19842 }
19843
19844 /*==========================================
19845  * Returns the name of a duplicated NPC
19846  *
19847  * instance_npcname <npc_name>{,<instance_id>};
19848  * <npc_name> is the full name of an NPC.
19849  *------------------------------------------*/
19850 BUILDIN_FUNC(instance_npcname)
19851 {
19852         const char *str;
19853         unsigned short instance_id = 0;
19854         struct npc_data *nd;
19855
19856         str = script_getstr(st,2);
19857         if( script_hasdata(st,3) )
19858                 instance_id = script_getnum(st,3);
19859         else
19860                 instance_id = script_instancegetid(st);
19861
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);
19866         } else {
19867                 ShowError("buildin_instance_npcname: Invalid instance NPC (instance_id: %hu, NPC name: \"%s\".)\n", instance_id, str);
19868                 st->state = END;
19869                 return SCRIPT_CMD_FAILURE;
19870         }
19871
19872         return SCRIPT_CMD_SUCCESS;
19873 }
19874
19875 /*==========================================
19876  * Returns the name of a duplicated map
19877  *
19878  * instance_mapname <map_name>{,<instance_id>};
19879  *------------------------------------------*/
19880 BUILDIN_FUNC(instance_mapname)
19881 {
19882         const char *str;
19883         int16 m;
19884         unsigned short instance_id = 0;
19885
19886         str = script_getstr(st,2);
19887
19888         if( script_hasdata(st,3) )
19889                 instance_id = script_getnum(st,3);
19890         else
19891                 instance_id = script_instancegetid(st);
19892
19893         // Check that instance mapname is a valid map
19894         if(!instance_id || (m = instance_mapname2mapid(str,instance_id)) < 0)
19895                 script_pushconststr(st, "");
19896         else
19897                 script_pushconststr(st, map[m].name);
19898
19899         return SCRIPT_CMD_SUCCESS;
19900 }
19901
19902 /*==========================================
19903  * Returns an Instance ID
19904  *------------------------------------------*/
19905 BUILDIN_FUNC(instance_id)
19906 {
19907         script_pushint(st, script_instancegetid(st));
19908         return SCRIPT_CMD_SUCCESS;
19909 }
19910
19911 /*==========================================
19912  * Warps all players inside an instance
19913  *
19914  * instance_warpall <map_name>,<x>,<y>{,<instance_id>};
19915  *------------------------------------------*/
19916 static int buildin_instance_warpall_sub(struct block_list *bl, va_list ap)
19917 {
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;
19923         int owner_id = 0;
19924
19925         nullpo_retr(0, bl);
19926
19927         if (bl->type != BL_PC)
19928                 return 0;
19929
19930         sd = (TBL_PC *)bl;
19931         owner_id = instance_data[instance_id].owner_id;
19932         switch(instance_data[instance_id].mode) {
19933                 case IM_NONE:
19934                         break;
19935                 case IM_CHAR:
19936                         if (sd->status.char_id != owner_id)
19937                                 return 0;
19938                         break;
19939                 case IM_PARTY:
19940                         if (sd->status.party_id != owner_id)
19941                                 return 0;
19942                         break;
19943                 case IM_GUILD:
19944                         if (sd->status.guild_id != owner_id)
19945                                 return 0;
19946                 case IM_CLAN:
19947                         if (sd->status.clan_id != owner_id)
19948                                 return 0;
19949         }
19950
19951         pc_setpos(sd, m, x, y, CLR_TELEPORT);
19952
19953         return 1;
19954 }
19955
19956 BUILDIN_FUNC(instance_warpall)
19957 {
19958         int16 m, i;
19959         unsigned short instance_id;
19960         const char *mapn;
19961         int x, y;
19962
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);
19968         else
19969                 instance_id = script_instancegetid(st);
19970
19971         if( !instance_id || (m = map_mapname2mapid(mapn)) < 0 || (m = instance_mapname2mapid(map[m].name,instance_id)) < 0)
19972                 return SCRIPT_CMD_FAILURE;
19973
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);
19976
19977         return SCRIPT_CMD_SUCCESS;
19978 }
19979
19980 /*==========================================
19981  * Broadcasts to all maps inside an instance
19982  *
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
19995         int i;
19996
19997         if( instance_id == 0 ) {
19998                 instance_id = script_instancegetid(st);
19999         }
20000
20001         if( !instance_id && &instance_data[instance_id] != NULL) {
20002                 ShowError("buildin_instance_announce: Intance is not found.\n");
20003                 return SCRIPT_CMD_FAILURE;
20004         }
20005
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);
20009
20010         return SCRIPT_CMD_SUCCESS;
20011 }
20012
20013 /*==========================================
20014  * instance_check_party [malufett]
20015  * Values:
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)
20024 {
20025         int amount, min, max, i, party_id, c = 0;
20026         struct party_data *p = NULL;
20027
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.
20031
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;
20038         }
20039
20040         if( script_hasdata(st,2) )
20041                 party_id = script_getnum(st,2);
20042         else return SCRIPT_CMD_FAILURE;
20043
20044         if( !(p = party_search(party_id)) ) {
20045                 script_pushint(st, 0); // Returns false if party does not exist.
20046                 return SCRIPT_CMD_FAILURE;
20047         }
20048
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;
20059                                 }
20060                                         c++;
20061                         }
20062         }
20063
20064         if(c < amount)
20065                 script_pushint(st, 0); // Not enough Members in the Party to join Instance.
20066         else
20067                 script_pushint(st, 1);
20068
20069         return SCRIPT_CMD_SUCCESS;
20070 }
20071
20072 /*==========================================
20073  * instance_check_guild
20074  * Values:
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)
20083 {
20084         int amount, min, max, i, guild_id = 0, c = 0;
20085         struct guild *g = NULL;
20086
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.
20090
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;
20097         }
20098
20099         if (script_hasdata(st,2))
20100                 guild_id = script_getnum(st,2);
20101         else
20102                 return SCRIPT_CMD_FAILURE;
20103
20104         if (!(g = guild_search(guild_id))) {
20105                 script_pushint(st, 0); // Returns false if guild does not exist.
20106                 return SCRIPT_CMD_FAILURE;
20107         }
20108
20109         for(i = 0; i < MAX_GUILD; i++) {
20110                 struct map_session_data *pl_sd;
20111
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;
20120                                 }
20121                                 c++;
20122                         }
20123                 }
20124         }
20125
20126         if (c < amount)
20127                 script_pushint(st, 0); // Not enough Members in the Guild to join Instance.
20128         else
20129                 script_pushint(st, 1);
20130
20131         return SCRIPT_CMD_SUCCESS;
20132 }
20133
20134 /*==========================================
20135  * instance_check_clan
20136  * Values:
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)
20145 {
20146         int amount, min, max, i, clan_id = 0, c = 0;
20147         struct clan *cd = NULL;
20148
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.
20152
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;
20159         }
20160
20161         if (script_hasdata(st,2))
20162                 clan_id = script_getnum(st,2);
20163         else
20164                 return SCRIPT_CMD_FAILURE;
20165
20166         if (!(cd = clan_search(clan_id))) {
20167                 script_pushint(st, 0); // Returns false if clan does not exist.
20168                 return SCRIPT_CMD_FAILURE;
20169         }
20170
20171         for(i = 0; i < MAX_CLAN; i++) {
20172                 struct map_session_data *pl_sd;
20173
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;
20182                                 }
20183                                 c++;
20184                         }
20185                 }
20186         }
20187
20188         if (c < amount)
20189                 script_pushint(st, 0); // Not enough Members in the Clan to join Instance.
20190         else
20191                 script_pushint(st, 1);
20192
20193         return SCRIPT_CMD_SUCCESS;
20194 }
20195
20196 /*==========================================
20197 * instance_info
20198 * Values:
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)
20204 {
20205         const char* name = script_getstr(st, 2);
20206         int type = script_getnum(st, 3);
20207         int index = 0;
20208         struct instance_db *db = instance_searchname_db(name);
20209
20210         if( !db ){
20211                 ShowError( "buildin_instance_info: Unknown instance name \"%s\".\n", name );
20212                 script_pushint(st, -1);
20213                 return SCRIPT_CMD_FAILURE;
20214         }
20215
20216         switch( type ){
20217                 case IIT_ID:
20218                         script_pushint(st, db->id);
20219                         break;
20220                 case IIT_TIME_LIMIT:
20221                         script_pushint(st, db->limit);
20222                         break;
20223                 case IIT_IDLE_TIMEOUT:
20224                         script_pushint(st, db->timeout);
20225                         break;
20226                 case IIT_ENTER_MAP:
20227                         script_pushstrcopy(st, StringBuf_Value(db->enter.mapname));
20228                         break;
20229                 case IIT_ENTER_X:
20230                         script_pushint(st, db->enter.x);
20231                         break;
20232                 case IIT_ENTER_Y:
20233                         script_pushint(st, db->enter.y);
20234                         break;
20235                 case IIT_MAPCOUNT:
20236                         script_pushint(st, db->maplist_count);
20237                         break;
20238                 case IIT_MAP:
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;
20243                         }
20244                         
20245                         index = script_getnum(st, 4);
20246
20247                         if( index < 0 ){
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;
20251                         }
20252
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;
20257                         }
20258
20259                         script_pushstrcopy(st, StringBuf_Value(db->maplist[index]));
20260                         break;
20261
20262                 default:
20263                         ShowError("buildin_instance_info: Unknown instance information type \"%d\".\n", type );
20264                         script_pushint(st, -1);
20265                         return SCRIPT_CMD_FAILURE;
20266         }
20267
20268         return SCRIPT_CMD_SUCCESS;
20269 }
20270
20271 /*==========================================
20272  * Custom Fonts
20273  *------------------------------------------*/
20274 BUILDIN_FUNC(setfont)
20275 {
20276         struct map_session_data *sd;
20277         int font;
20278
20279         if( !script_rid2sd(sd) )
20280                 return SCRIPT_CMD_SUCCESS;
20281
20282         font = script_getnum(st,2);
20283
20284         if( sd->status.font != font )
20285                 sd->status.font = font;
20286         else
20287                 sd->status.font = 0;
20288
20289         clif_font(sd);
20290         return SCRIPT_CMD_SUCCESS;
20291 }
20292
20293 static int buildin_mobuseskill_sub(struct block_list *bl,va_list ap)
20294 {
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);
20304
20305         if( md->mob_id != mobid )
20306                 return 0;
20307
20308         // 0:self, 1:target, 2:master, default:random
20309         switch( target ) {
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;
20314         }
20315
20316         if( !tbl )
20317                 return 0;
20318
20319         if( md->ud.skilltimer != INVALID_TIMER ) // Cancel the casting skill.
20320                 unit_skillcastcancel(bl,0);
20321
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);
20324         else
20325                 unit_skilluse_id2(&md->bl, tbl->id, skill_id, skill_lv, casttime, cancel);
20326
20327         clif_emotion(&md->bl, emotion);
20328
20329         return 1;
20330 }
20331
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)
20336 {
20337         struct block_list center;
20338         struct script_data *data;
20339         int16 m;
20340         int range,mobid,skill_id,skill_lv,casttime,emotion,target,cancel;
20341
20342         if( (m = map_mapname2mapid(script_getstr(st,2))) < 0 ) {
20343                 ShowError("areamobuseskill: invalid map name.\n");
20344                 return SCRIPT_CMD_SUCCESS;
20345         }
20346
20347         center.m = m;
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;
20357
20358         casttime = script_getnum(st,9);
20359         cancel = script_getnum(st,10);
20360         emotion = script_getnum(st,11);
20361         target = script_getnum(st,12);
20362
20363         map_foreachinallrange(buildin_mobuseskill_sub, &center, range, BL_MOB, mobid, skill_id, skill_lv, casttime, cancel, emotion, target);
20364         return SCRIPT_CMD_SUCCESS;
20365 }
20366
20367 /**
20368  * Display a progress bar above a character
20369  * progressbar "<color>",<seconds>;
20370  */
20371 BUILDIN_FUNC(progressbar)
20372 {
20373         struct map_session_data * sd;
20374         const char * color;
20375         unsigned int second;
20376
20377         if( !script_rid2sd(sd) )
20378                 return SCRIPT_CMD_SUCCESS;
20379
20380         st->state = STOP;
20381
20382         color = script_getstr(st,2);
20383         second = script_getnum(st,3);
20384
20385         sd->progressbar.npc_id = st->oid;
20386         sd->progressbar.timeout = gettick() + second*1000;
20387         sd->state.workinprogress = WIP_DISABLE_ALL;
20388
20389         clif_progressbar(sd, strtol(color, (char **)NULL, 0), second);
20390         return SCRIPT_CMD_SUCCESS;
20391 }
20392
20393 /**
20394  * Display a progress bar above an NPC
20395  * progressbar_npc "<color>",<seconds>{,<"NPC Name">};
20396  */
20397 BUILDIN_FUNC(progressbar_npc){
20398         struct npc_data* nd = NULL;
20399
20400         if( script_hasdata(st, 4) ){
20401                 const char* name = script_getstr(st, 4);
20402
20403                 nd = npc_name2id(name);
20404
20405                 if( !nd ){
20406                         ShowError( "buildin_progressbar_npc: NPC \"%s\" was not found.\n", name );
20407                         return SCRIPT_CMD_FAILURE;
20408                 }
20409         }else{
20410                 nd = map_id2nd(st->oid);
20411         }
20412
20413         // First call(by function call)
20414         if( !nd->progressbar.timeout ){
20415                 const char *color;
20416                 int second;
20417
20418                 color = script_getstr(st, 2);
20419                 second = script_getnum(st, 3);
20420
20421                 if( second < 0 ){
20422                         ShowError( "buildin_progressbar_npc: negative amount('%d') of seconds is not supported\n", second );
20423                         return SCRIPT_CMD_FAILURE;
20424                 }
20425
20426                 // detach the player
20427                 script_detach_rid(st);
20428
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);
20434
20435                 clif_progressbar_npc_area(nd);
20436         // Second call(by timer after sleeping time is over)
20437         } else {
20438                 // Continue the script
20439                 st->state = RUN;
20440                 st->sleep.tick = 0;
20441                 nd->progressbar.timeout = nd->progressbar.color = 0;
20442         }
20443
20444         return SCRIPT_CMD_SUCCESS;
20445 }
20446
20447 BUILDIN_FUNC(pushpc)
20448 {
20449         uint8 dir;
20450         int cells, dx, dy;
20451         struct map_session_data* sd;
20452
20453         if(!script_rid2sd(sd))
20454         {
20455                 return SCRIPT_CMD_SUCCESS;
20456         }
20457
20458         dir = script_getnum(st,2);
20459         cells     = script_getnum(st,3);
20460
20461         if(dir >= DIR_MAX)
20462         {
20463                 ShowWarning("buildin_pushpc: Invalid direction %d specified.\n", dir);
20464                 script_reportsrc(st);
20465
20466                 dir%= DIR_MAX;  // trim spin-over
20467         }
20468
20469         if(!cells)
20470         {// zero distance
20471                 return SCRIPT_CMD_SUCCESS;
20472         }
20473         else if(cells<0)
20474         {// pushing backwards
20475                 dir = (dir+DIR_MAX/2)%DIR_MAX;  // turn around
20476                 cells     = -cells;
20477         }
20478
20479         dx = dirx[dir];
20480         dy = diry[dir];
20481
20482         unit_blown(&sd->bl, dx, dy, cells, BLOWN_NONE);
20483         return SCRIPT_CMD_SUCCESS;
20484 }
20485
20486
20487 /// Invokes buying store preparation window
20488 /// buyingstore <slots>;
20489 BUILDIN_FUNC(buyingstore)
20490 {
20491         struct map_session_data* sd;
20492
20493         if( !script_rid2sd(sd) )
20494         {
20495                 return SCRIPT_CMD_SUCCESS;
20496         }
20497
20498         if( npc_isnear(&sd->bl) ) {
20499                 char output[150];
20500                 sprintf(output, msg_txt(sd,662), battle_config.min_npc_vendchat_distance);
20501                 clif_displaymessage(sd->fd, output);
20502                 return SCRIPT_CMD_SUCCESS;
20503         }
20504
20505         buyingstore_setup(sd, script_getnum(st,2));
20506         return SCRIPT_CMD_SUCCESS;
20507 }
20508
20509
20510 /// Invokes search store info window
20511 /// searchstores <uses>,<effect>;
20512 BUILDIN_FUNC(searchstores)
20513 {
20514         unsigned short effect;
20515         unsigned int uses;
20516         struct map_session_data* sd;
20517
20518         if( !script_rid2sd(sd) )
20519         {
20520                 return SCRIPT_CMD_SUCCESS;
20521         }
20522
20523         uses   = script_getnum(st,2);
20524         effect = script_getnum(st,3);
20525
20526         if( !uses )
20527         {
20528                 ShowError("buildin_searchstores: Amount of uses cannot be zero.\n");
20529                 return SCRIPT_CMD_FAILURE;
20530         }
20531
20532         if( effect > 1 )
20533         {
20534                 ShowError("buildin_searchstores: Invalid effect id %hu, specified.\n", effect);
20535                 return SCRIPT_CMD_FAILURE;
20536         }
20537
20538         searchstore_open(sd, uses, effect);
20539         return SCRIPT_CMD_SUCCESS;
20540 }
20541 /// Displays a number as large digital clock.
20542 /// showdigit <value>[,<type>];
20543 BUILDIN_FUNC(showdigit)
20544 {
20545         unsigned int type = 0;
20546         int value;
20547         struct map_session_data* sd;
20548
20549         if( !script_rid2sd(sd) )
20550         {
20551                 return SCRIPT_CMD_SUCCESS;
20552         }
20553
20554         value = script_getnum(st,2);
20555
20556         if( script_hasdata(st,3) ){
20557                 type = script_getnum(st,3);
20558         }
20559
20560         switch( type ){
20561                 case 0:
20562                         break;
20563                 case 1:
20564                 case 2:
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);
20568                         break;
20569                 case 3:
20570                         value = abs(value);
20571                         if( value > 99 ){
20572                                 ShowWarning("buildin_showdigit: type 3 can display 2 digits at max. Capping value %d to 99...\n", value);
20573                                 script_reportsrc(st);
20574                                 value = 99;
20575                         }
20576                         break;
20577                 default:
20578                         ShowError("buildin_showdigit: Invalid type %u.\n", type);
20579                         return SCRIPT_CMD_FAILURE;
20580         }
20581
20582         clif_showdigit(sd, (unsigned char)type, value);
20583         return SCRIPT_CMD_SUCCESS;
20584 }
20585 /**
20586  * Rune Knight
20587  * makerune <% success bonus>{,<char_id>};
20588  **/
20589 BUILDIN_FUNC(makerune) {
20590         TBL_PC* sd;
20591         
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;
20597 }
20598 /**
20599  * checkdragon({<char_id>}) returns 1 if mounting a dragon or 0 otherwise.
20600  **/
20601 BUILDIN_FUNC(checkdragon) {
20602         TBL_PC* sd;
20603         
20604         if (!script_charid2sd(2,sd))
20605                 return SCRIPT_CMD_FAILURE;
20606         if( pc_isridingdragon(sd) )
20607                 script_pushint(st,1);
20608         else
20609                 script_pushint(st,0);
20610         return SCRIPT_CMD_SUCCESS;
20611 }
20612 /**
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
20620  * - 5 : Red Dragon
20621  **/
20622 BUILDIN_FUNC(setdragon) {
20623         TBL_PC* sd;
20624         int color = script_hasdata(st,2) ? script_getnum(st,2) : 0;
20625
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;
20635                 if( color ) {
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);
20641                         if( !option ) {
20642                                 ShowWarning("script_setdragon: Unknown Color %d used; changing to green (1)\n",color);
20643                                 option = OPTION_DRAGON1;
20644                         }
20645                 }
20646                 pc_setoption(sd, sd->sc.option|option);
20647                 script_pushint(st,1);
20648         }
20649         return SCRIPT_CMD_SUCCESS;
20650 }
20651
20652 /**
20653  * ismounting({<char_id>}) returns 1 if mounting a new mount or 0 otherwise
20654  **/
20655 BUILDIN_FUNC(ismounting) {
20656         TBL_PC* sd;
20657         
20658         if (!script_charid2sd(2,sd))
20659                 return SCRIPT_CMD_FAILURE;
20660         if( sd->sc.data[SC_ALL_RIDING] )
20661                 script_pushint(st,1);
20662         else
20663                 script_pushint(st,0);
20664         return SCRIPT_CMD_SUCCESS;
20665 }
20666
20667 /**
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
20672  **/
20673 BUILDIN_FUNC(setmounting) {
20674         TBL_PC* sd;
20675         
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
20681         } else {
20682                 if( sd->sc.data[SC_ALL_RIDING] )
20683                         status_change_end(&sd->bl, SC_ALL_RIDING, INVALID_TIMER); //release mount
20684                 else
20685                         sc_start(NULL, &sd->bl, SC_ALL_RIDING, 10000, 1, INVALID_TIMER); //mount
20686                 script_pushint(st,1);//in both cases, return 1.
20687         }
20688         return SCRIPT_CMD_SUCCESS;
20689 }
20690 /**
20691  * Retrieves quantity of arguments provided to callfunc/callsub.
20692  * getargcount() -> amount of arguments received in a function
20693  **/
20694 BUILDIN_FUNC(getargcount) {
20695         struct script_retinfo* ri;
20696
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");
20699                 st->state = END;
20700                 return SCRIPT_CMD_FAILURE;
20701         }
20702         ri = st->stack->stack_data[st->stack->defsp - 1].u.ri;
20703
20704         script_pushint(st, ri->nargs);
20705         return SCRIPT_CMD_SUCCESS;
20706 }
20707 /**
20708  * getcharip(<account ID>/<character ID>/<character name>)
20709  **/
20710 BUILDIN_FUNC(getcharip)
20711 {
20712         struct map_session_data* sd = NULL;
20713
20714         /* check if a character name is specified */
20715         if( script_hasdata(st, 2) )
20716         {
20717                 struct script_data *data;
20718
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))
20724                 {
20725                         int id = 0;
20726                         id = script_getnum(st, 2);
20727                         sd = (map_id2sd(id) ? map_id2sd(id) : map_charid2sd(id));
20728                 }
20729         }
20730         else
20731                 script_rid2sd(sd);
20732
20733         /* check for sd and IP */
20734         if (!sd || !session[sd->fd]->client_addr)
20735         {
20736                 script_pushconststr(st, "");
20737                 return SCRIPT_CMD_SUCCESS;
20738         }
20739
20740         /* return the client ip_addr converted for output */
20741         if (sd && sd->fd && session[sd->fd])
20742         {
20743                 /* initiliaze */
20744                 const char *ip_addr = NULL;
20745                 uint32 ip;
20746
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);
20751         }
20752         return SCRIPT_CMD_SUCCESS;
20753 }
20754 /**
20755  * is_function(<function name>) -> 1 if function exists, 0 otherwise
20756  **/
20757 BUILDIN_FUNC(is_function) {
20758         const char* str = script_getstr(st,2);
20759
20760         if( strdb_exists(userfunc_db, str) )
20761                 script_pushint(st,1);
20762         else
20763                 script_pushint(st,0);
20764         return SCRIPT_CMD_SUCCESS;
20765 }
20766 /**
20767  * get_revision() -> retrieves the current svn revision (if available)
20768  **/
20769 BUILDIN_FUNC(get_revision) {
20770         const char *svn = get_svn_revision();
20771
20772         if ( svn[0] != UNKNOWN_VERSION )
20773                 script_pushint(st,atoi(svn));
20774         else
20775                 script_pushint(st,-1); //unknown
20776         return SCRIPT_CMD_SUCCESS;
20777 }
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);
20783
20784         if ( git[0] != UNKNOWN_VERSION )
20785                 script_pushstr(st,buf);
20786         else
20787                 script_pushconststr(st,"Unknown"); //unknown
20788         return SCRIPT_CMD_SUCCESS;
20789 }
20790 /**
20791  * freeloop(<toggle>) -> toggles this script instance's looping-check ability
20792  **/
20793 BUILDIN_FUNC(freeloop) {
20794
20795         if( script_hasdata(st,2) ) {
20796                 if( script_getnum(st,2) )
20797                         st->freeloop = 1;
20798                 else
20799                         st->freeloop = 0;
20800         }
20801
20802         script_pushint(st, st->freeloop);
20803         return SCRIPT_CMD_SUCCESS;
20804 }
20805
20806 /**
20807  * @commands (script based)
20808  **/
20809 BUILDIN_FUNC(bindatcmd) {
20810         const char* atcmd;
20811         const char* eventName;
20812         int i, level = 0, level2 = 0;
20813         bool create = false;
20814
20815         atcmd = script_getstr(st,2);
20816         eventName = script_getstr(st,3);
20817
20818         if( *atcmd == atcommand_symbol || *atcmd == charcommand_symbol )
20819                 atcmd++;
20820
20821         if( script_hasdata(st,4) ) level = script_getnum(st,4);
20822         if( script_hasdata(st,5) ) level2 = script_getnum(st,5);
20823
20824         if( atcmd_binding_count == 0 ) {
20825                 CREATE(atcmd_binding,struct atcmd_binding_data*,1);
20826
20827                 create = true;
20828         } else {
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;
20834                 } else
20835                         create = true;
20836         }
20837
20838         if( create ) {
20839                 i = atcmd_binding_count;
20840
20841                 if( atcmd_binding_count++ != 0 )
20842                         RECREATE(atcmd_binding,struct atcmd_binding_data*,atcmd_binding_count);
20843
20844                 CREATE(atcmd_binding[i],struct atcmd_binding_data,1);
20845
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;
20850         }
20851         return SCRIPT_CMD_SUCCESS;
20852 }
20853
20854 BUILDIN_FUNC(unbindatcmd) {
20855         const char* atcmd;
20856         int i =  0;
20857
20858         atcmd = script_getstr(st, 2);
20859
20860         if( *atcmd == atcommand_symbol || *atcmd == charcommand_symbol )
20861                 atcmd++;
20862
20863         if( atcmd_binding_count == 0 ) {
20864                 script_pushint(st, 0);
20865                 return SCRIPT_CMD_SUCCESS;
20866         }
20867
20868         ARR_FIND(0, atcmd_binding_count, i, strcmp(atcmd_binding[i]->command, atcmd) == 0);
20869         if( i < atcmd_binding_count ) {
20870                 int cursor = 0;
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 )
20876                                 continue;
20877
20878                         if( cursor != i ) {
20879                                 memmove(&atcmd_binding[cursor], &atcmd_binding[i], sizeof(struct atcmd_binding_data*));
20880                         }
20881
20882                         cursor++;
20883                 }
20884
20885                 if( (atcmd_binding_count = cursor) == 0 )
20886                         aFree(atcmd_binding);
20887
20888                 script_pushint(st, 1);
20889         } else
20890                 script_pushint(st, 0);/* not found */
20891
20892         return SCRIPT_CMD_SUCCESS;
20893 }
20894
20895 BUILDIN_FUNC(useatcmd) {
20896         return atcommand_sub(st,3);
20897 }
20898
20899 BUILDIN_FUNC(checkre)
20900 {
20901         int num;
20902
20903         num=script_getnum(st,2);
20904         switch(num){
20905                 case 0:
20906                         #ifdef RENEWAL
20907                                 script_pushint(st, 1);
20908                         #else
20909                                 script_pushint(st, 0);
20910                         #endif
20911                         break;
20912                 case 1:
20913                         #ifdef RENEWAL_CAST
20914                                 script_pushint(st, 1);
20915                         #else
20916                                 script_pushint(st, 0);
20917                         #endif
20918                         break;
20919                 case 2:
20920                         #ifdef RENEWAL_DROP
20921                                 script_pushint(st, 1);
20922                         #else
20923                                 script_pushint(st, 0);
20924                         #endif
20925                         break;
20926                 case 3:
20927                         #ifdef RENEWAL_EXP
20928                                 script_pushint(st, 1);
20929                         #else
20930                                 script_pushint(st, 0);
20931                         #endif
20932                         break;
20933                 case 4:
20934                         #ifdef RENEWAL_LVDMG
20935                                 script_pushint(st, 1);
20936                         #else
20937                                 script_pushint(st, 0);
20938                         #endif
20939                         break;
20940                 case 5:
20941                         #ifdef RENEWAL_ASPD
20942                                 script_pushint(st, 1);
20943                         #else
20944                                 script_pushint(st, 0);
20945                         #endif
20946                         break;
20947                 default:
20948                         ShowWarning("buildin_checkre: unknown parameter.\n");
20949                         break;
20950         }
20951         return SCRIPT_CMD_SUCCESS;
20952 }
20953
20954 /* getrandgroupitem <group_id>{,<quantity>{,<sub_group>}} */
20955 BUILDIN_FUNC(getrandgroupitem) {
20956         TBL_PC* sd;
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;
20962
20963         if (!script_rid2sd(sd))
20964                 return SCRIPT_CMD_SUCCESS;
20965
20966         group = script_getnum(st,2);
20967
20968         if (!group) {
20969                 ShowError("buildin_getrandgroupitem: Invalid group id (%d)!\n",script_getnum(st,2));
20970                 return SCRIPT_CMD_FAILURE;
20971         }
20972
20973         FETCH(3, qty);
20974         FETCH(4, sub_group);
20975
20976         entry = itemdb_get_randgroupitem(group,sub_group);
20977         if (!entry)
20978                 return SCRIPT_CMD_FAILURE; //ensure valid itemid
20979
20980         memset(&item_tmp,0,sizeof(item_tmp));
20981         item_tmp.nameid   = entry->nameid;
20982         item_tmp.identify = itemdb_isidentified(entry->nameid);
20983
20984         if (!qty)
20985                 qty = entry->amount;
20986
20987         //Check if it's stackable.
20988         if (!itemdb_isstackable(entry->nameid)) {
20989                 item_tmp.amount = 1;
20990                 get_count = qty;
20991         }
20992         else {
20993                 item_tmp.amount = qty;
20994                 get_count = 1;
20995         }
20996
20997         for (i = 0; i < get_count; i++) {
20998                 // if not pet egg
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);
21005                         }
21006                 }
21007         }
21008
21009         return SCRIPT_CMD_SUCCESS;
21010 }
21011
21012 /* getgroupitem <group_id>{,<char_id>};
21013  * Gives item(s) to the attached player based on item group contents
21014  */
21015 BUILDIN_FUNC(getgroupitem) {
21016         TBL_PC *sd;
21017         int group_id = script_getnum(st,2);
21018         
21019         if (!script_charid2sd(3,sd))
21020                 return SCRIPT_CMD_SUCCESS;
21021         
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;
21025         }
21026
21027         return SCRIPT_CMD_SUCCESS;
21028 }
21029
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)
21033 {
21034         nullpo_ret(bl);
21035         map_clearflooritem(bl);
21036
21037         return SCRIPT_CMD_SUCCESS;
21038 }
21039
21040 BUILDIN_FUNC(cleanmap)
21041 {
21042         const char *mapname;
21043         int16 m;
21044
21045         mapname = script_getstr(st, 2);
21046         m = map_mapname2mapid(mapname);
21047         if (!m)
21048                 return SCRIPT_CMD_FAILURE;
21049
21050         if ((script_lastdata(st) - 2) < 4) {
21051                 map_foreachinmap(atcommand_cleanfloor_sub, m, BL_ITEM);
21052         } else {
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);
21059                 } else {
21060                         ShowError("cleanarea: invalid coordinate defined!\n");
21061                         return SCRIPT_CMD_FAILURE;
21062                 }
21063         }
21064         return SCRIPT_CMD_SUCCESS;
21065 }
21066
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)
21071 {
21072         uint16 skill_id;
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;
21079
21080         if( !script_rid2sd(sd) )
21081                 return SCRIPT_CMD_SUCCESS;
21082         
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);
21090
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;
21094         }
21095         if (npc_level > MAX_LEVEL) {
21096                 ShowError("npcskill: level exceeded maximum of %d.\n", MAX_LEVEL);
21097                 return SCRIPT_CMD_FAILURE;
21098         }
21099         if (nd == NULL) { //ain't possible, but I don't trust people.
21100                 return SCRIPT_CMD_FAILURE;
21101         }
21102
21103         nd->level = npc_level;
21104         nd->stat_point = stat_point;
21105
21106         if (!nd->status.hp)
21107                 status_calc_npc(nd, SCO_FIRST);
21108         else
21109                 status_calc_npc(nd, SCO_NONE);
21110
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);
21113         else
21114                 unit_skilluse_id2(&nd->bl, sd->bl.id, skill_id, skill_level,0,0);
21115
21116         return SCRIPT_CMD_SUCCESS;
21117 }
21118
21119 /* Consumes an item.
21120  * consumeitem <item id>{,<char_id>};
21121  * consumeitem "<item name>"{,<char_id>};
21122  * @param item: Item ID or name
21123  */
21124 BUILDIN_FUNC(consumeitem)
21125 {
21126         TBL_PC *sd;
21127         struct script_data *data;
21128         struct item_data *item_data;
21129
21130         if (!script_charid2sd(3, sd))
21131                 return SCRIPT_CMD_FAILURE;
21132
21133         data = script_getdata( st, 2 );
21134         get_val( st, data );
21135
21136         if( data_isstring( data ) ){
21137                 const char *name = conv_str( st, data );
21138
21139                 if( ( item_data = itemdb_searchname( name ) ) == NULL ){
21140                         ShowError( "buildin_consumeitem: Nonexistant item %s requested.\n", name );
21141                         return SCRIPT_CMD_FAILURE;
21142                 }
21143         }else if( data_isint( data ) ){
21144                 unsigned short nameid = conv_num( st, data );
21145
21146                 if( ( item_data = itemdb_exists( nameid ) ) == NULL ){
21147                         ShowError("buildin_consumeitem: Nonexistant item %hu requested.\n", nameid );
21148                         return SCRIPT_CMD_FAILURE;
21149                 }
21150         }else{
21151                 ShowError("buildin_consumeitem: invalid data type for argument #1 (%d).\n", data->type );
21152                 return SCRIPT_CMD_FAILURE;
21153         }
21154
21155         run_script( item_data->script, 0, sd->bl.id, 0 );
21156         return SCRIPT_CMD_SUCCESS;
21157 }
21158
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
21164  */
21165 BUILDIN_FUNC(sit)
21166 {
21167         TBL_PC *sd;
21168
21169         if( !script_nick2sd(2,sd) )
21170                 return SCRIPT_CMD_FAILURE;
21171
21172         if( !pc_issit(sd) ) {
21173                 pc_setsit(sd);
21174                 skill_sit(sd, 1);
21175                 clif_sitting(&sd->bl);
21176         }
21177         return SCRIPT_CMD_SUCCESS;
21178 }
21179
21180 /** Makes player to stand
21181 * @param name: Player name that will be set
21182 */
21183 BUILDIN_FUNC(stand)
21184 {
21185         TBL_PC *sd;
21186
21187         if( !script_nick2sd(2,sd) )
21188                 return SCRIPT_CMD_FAILURE;
21189
21190         if( pc_issit(sd) && pc_setstand(sd, false)) {
21191                 skill_sit(sd, 0);
21192                 clif_standing(&sd->bl);
21193         }
21194
21195         return SCRIPT_CMD_SUCCESS;
21196 }
21197
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
21202  */
21203 BUILDIN_FUNC(countbound)
21204 {
21205         int i, type, j = 0, k = 0;
21206         TBL_PC *sd;
21207
21208         if (!script_charid2sd(3,sd))
21209                 return SCRIPT_CMD_FAILURE;
21210
21211         type = script_getnum(st,2);
21212
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)
21216                         ))
21217                 {
21218                         pc_setreg(sd,reference_uid(add_str("@bound_items"), k),sd->inventory.u.items_inventory[i].nameid);
21219                         k++;
21220                         j += sd->inventory.u.items_inventory[i].amount;
21221                 }
21222         }
21223
21224         script_pushint(st,j);
21225         return SCRIPT_CMD_SUCCESS;
21226 }
21227
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
21240  */
21241 BUILDIN_FUNC(party_create)
21242 {
21243         char party_name[NAME_LENGTH];
21244         int item1 = 0, item2 = 0;
21245         TBL_PC *sd = NULL;
21246
21247         if (!script_charid2sd(3, sd)) {
21248                 script_pushint(st,-1);
21249                 return SCRIPT_CMD_FAILURE;
21250         }
21251
21252         if( sd->status.party_id ) {
21253                 script_pushint(st,-2);
21254                 return SCRIPT_CMD_FAILURE;
21255         }
21256
21257         safestrncpy(party_name,script_getstr(st,2),NAME_LENGTH);
21258         trim(party_name);
21259         if( party_searchname(party_name) ) {
21260                 script_pushint(st,-3);
21261                 return SCRIPT_CMD_FAILURE;
21262         }
21263         if( script_getnum(st,4) )
21264                 item1 = 1;
21265         if( script_getnum(st,5) )
21266                 item2 = 1;
21267
21268         party_create_byscript = 1;
21269         script_pushint(st,party_create(sd,party_name,item1,item2));
21270         return SCRIPT_CMD_SUCCESS;
21271 }
21272
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
21284  *      1       - success
21285  */
21286 BUILDIN_FUNC(party_addmember)
21287 {
21288         int party_id = script_getnum(st,2);
21289         TBL_PC *sd;
21290         struct party_data *party;
21291
21292         if( !(sd = map_charid2sd(script_getnum(st,3))) ) {
21293                 script_pushint(st,-1);
21294                 return SCRIPT_CMD_FAILURE;
21295         }
21296
21297         if( sd->status.party_id ) {
21298                 script_pushint(st,-2);
21299                 return SCRIPT_CMD_FAILURE;
21300         }
21301
21302         if( !(party = party_search(party_id)) ) {
21303                 script_pushint(st,-3);
21304                 return SCRIPT_CMD_FAILURE;
21305         }
21306
21307         if (battle_config.block_account_in_same_party) {
21308                 int i;
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;
21313                 }
21314         }
21315
21316         if( party->party.count >= MAX_PARTY ) {
21317                 script_pushint(st,-4);
21318                 return SCRIPT_CMD_FAILURE;
21319         }
21320         sd->party_invite = party_id;
21321         script_pushint(st,party_add_member(party_id,sd));
21322         return SCRIPT_CMD_SUCCESS;
21323 }
21324
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>};
21327  * @param: char_id
21328  * @param: 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
21334  *      1       - success
21335  */
21336 BUILDIN_FUNC(party_delmember)
21337 {
21338         TBL_PC *sd = NULL;
21339
21340         if( !script_hasdata(st,2) && !script_hasdata(st,3) && !script_rid2sd(sd) ) {
21341                 script_pushint(st,-1);
21342                 return SCRIPT_CMD_FAILURE;
21343         }
21344         if( sd || script_charid2sd(2,sd) )
21345                 script_pushint(st,party_removemember2(sd,0,0));
21346         else
21347                 script_pushint(st,party_removemember2(NULL,script_getnum(st,2),script_getnum(st,3)));
21348         return SCRIPT_CMD_SUCCESS;
21349 }
21350
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
21361  *      1       - success */
21362 BUILDIN_FUNC(party_changeleader)
21363 {
21364         int i, party_id = script_getnum(st,2);
21365         TBL_PC *sd = NULL;
21366         TBL_PC *tsd = NULL;
21367         struct party_data *party = NULL;
21368
21369         if( !(party = party_search(party_id)) ) {
21370                 script_pushint(st,-1);
21371                 return SCRIPT_CMD_FAILURE;
21372         }
21373
21374         if( !(tsd = map_charid2sd(script_getnum(st,3))) ) {
21375                 script_pushint(st,-2);
21376                 return SCRIPT_CMD_FAILURE;
21377         }
21378
21379         if( tsd->status.party_id != party_id ) {
21380                 script_pushint(st,-3);
21381                 return SCRIPT_CMD_FAILURE;
21382         }
21383
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;
21388         }
21389         if( party->data[i].sd == tsd ) {
21390                 script_pushint(st,-4);
21391                 return SCRIPT_CMD_FAILURE;
21392         }
21393
21394         script_pushint(st,party_changeleader(sd,tsd,party));
21395         return SCRIPT_CMD_SUCCESS;
21396 }
21397
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
21403  */
21404 BUILDIN_FUNC(party_changeoption)
21405 {
21406         struct party_data *party;
21407
21408         if( !(party = party_search(script_getnum(st,2))) ) {
21409                 script_pushint(st,-1);
21410                 return SCRIPT_CMD_FAILURE;
21411         }
21412         script_pushint(st,party_setoption(party,script_getnum(st,3),script_getnum(st,4)));
21413         return SCRIPT_CMD_SUCCESS;
21414 }
21415
21416 /** Destroys party with party id.
21417  * party_destroy <party id>;
21418  * @param party_id: ID of party that will be destroyed
21419  */
21420 BUILDIN_FUNC(party_destroy)
21421 {
21422         int i;
21423         struct party_data *party;
21424
21425         if( !(party = party_search(script_getnum(st,2))) ) {
21426                 script_pushint(st,0);
21427                 return SCRIPT_CMD_FAILURE;
21428         }
21429
21430         ARR_FIND(0,MAX_PARTY,i,party->party.member[i].leader);
21431         if( i >= MAX_PARTY || !party->data[i].sd ) { //leader not online
21432                 int j;
21433                 for( j = 0; j < MAX_PARTY; j++ ) {
21434                         TBL_PC *sd = party->data[j].sd;
21435                         if(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);
21439                 }
21440                 party_broken(party->party.party_id);
21441                 script_pushint(st,1);
21442         }
21443         else //leader leave = party broken
21444                 script_pushint(st,party_leave(party->data[i].sd));
21445         return SCRIPT_CMD_SUCCESS;
21446 }
21447
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)
21452  */
21453 BUILDIN_FUNC(vip_status) {
21454 #ifdef VIP_ENABLE
21455         TBL_PC *sd;
21456         int type;
21457
21458         if( !script_nick2sd(3,sd) )
21459                 return SCRIPT_CMD_FAILURE;
21460
21461         type = script_getnum(st, 2);
21462
21463         switch(type) {
21464                 case VIP_STATUS_ACTIVE: // Get VIP status.
21465                         script_pushint(st, pc_isvip(sd));
21466                         break;
21467                 case VIP_STATUS_EXPIRE: // Get VIP expire date.
21468                         if (pc_isvip(sd)) {
21469                                 script_pushint(st, sd->vip.time);
21470                         } else
21471                                 script_pushint(st, 0);
21472                         break;
21473                 case VIP_STATUS_REMAINING: // Get remaining time.
21474                         if (pc_isvip(sd)) {
21475                                 script_pushint(st, sd->vip.time - time(NULL));
21476                         } else
21477                                 script_pushint(st, 0);
21478                         break;
21479                 default:
21480                         ShowError( "buildin_vip_status: Unsupported type %d.\n", type );
21481                         return SCRIPT_CMD_FAILURE;
21482         }
21483 #else
21484         script_pushint(st, 0);
21485 #endif
21486         return SCRIPT_CMD_SUCCESS;
21487 }
21488
21489
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)
21494  */
21495 BUILDIN_FUNC(vip_time) {
21496 #ifdef VIP_ENABLE //would be a pain for scripting npc otherwise
21497         TBL_PC *sd;
21498         int viptime = script_getnum(st, 2) * 60; // Convert since it's given in minutes.
21499
21500         if( !script_nick2sd(3,sd) )
21501                 return SCRIPT_CMD_FAILURE;
21502
21503         chrif_req_login_operation(sd->status.account_id, sd->status.name, CHRIF_OP_LOGIN_VIP, viptime, 7, 0); 
21504 #endif
21505         return SCRIPT_CMD_SUCCESS;
21506 }
21507
21508
21509 /**
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
21521  */
21522 BUILDIN_FUNC(montransform) {
21523         TBL_PC *sd;
21524         enum sc_type type;
21525         int tick, mob_id, val1, val2, val3, val4;
21526         struct script_data *data;
21527         val1 = val2 = val3 = val4 = 0;
21528
21529         if( !script_rid2sd(sd) )
21530                 return SCRIPT_CMD_FAILURE;
21531
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));
21536         else
21537                 mob_id = mobdb_checkid(script_getnum(st, 2));
21538
21539         tick = script_getnum(st, 3);
21540
21541         if (script_hasdata(st, 4))
21542                 type = (sc_type)script_getnum(st, 4);
21543         else
21544                 type = SC_NONE;
21545
21546         if (mob_id == 0) {
21547                 if( data_isstring(data) )
21548                         ShowWarning("buildin_montransform: Attempted to use non-existing monster '%s'.\n", script_getstr(st, 2));
21549                 else
21550                         ShowWarning("buildin_montransform: Attempted to use non-existing monster of ID '%d'.\n", script_getnum(st, 2));
21551                 return SCRIPT_CMD_FAILURE;
21552         }
21553
21554         if (mob_id == MOBID_EMPERIUM) {
21555                 ShowWarning("buildin_montransform: Monster 'Emperium' cannot be used.\n");
21556                 return SCRIPT_CMD_FAILURE;
21557         }
21558
21559         if (!(type >= SC_NONE && type < SC_MAX)) {
21560                 ShowWarning("buildin_montransform: Unsupported status change id %d\n", type);
21561                 return SCRIPT_CMD_FAILURE;
21562         }
21563
21564         if (script_hasdata(st, 5))
21565                 val1 = script_getnum(st, 5);
21566
21567         if (script_hasdata(st, 6))
21568                 val2 = script_getnum(st, 6);
21569
21570         if (script_hasdata(st, 7))
21571                 val3 = script_getnum(st, 7);
21572
21573         if (script_hasdata(st, 8))
21574                 val4 = script_getnum(st, 8);
21575
21576         if (tick != 0) {
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;
21580                 }
21581
21582                 if (sd->disguise){
21583                         clif_displaymessage(sd->fd, msg_txt(sd,729)); // Cannot transform into monster while in disguise.
21584                         return SCRIPT_CMD_FAILURE;
21585                 }
21586
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);
21590                 } else {
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);
21593                 }
21594                 if (type != SC_NONE)
21595                         sc_start4(NULL, &sd->bl, type, 100, val1, val2, val3, val4, tick);
21596         }
21597
21598         return SCRIPT_CMD_SUCCESS;
21599 }
21600
21601 /**
21602  * Attach script to player for certain duration
21603  * bonus_script "<script code>",<duration>{,<flag>{,<type>{,<status_icon>{,<char_id>}}}};
21604  * @param "script code"
21605  * @param duration
21606  * @param flag
21607  * @param icon
21608  * @param char_id
21609 * @author [Cydh]
21610  **/
21611 BUILDIN_FUNC(bonus_script) {
21612         uint16 flag = 0;
21613         int16 icon = SI_BLANK;
21614         uint32 dur;
21615         uint8 type = 0;
21616         TBL_PC* sd;
21617         const char *script_str = NULL;
21618         struct s_bonus_script_entry *entry = NULL;
21619
21620         if ( !script_charid2sd(7,sd) )
21621                 return SCRIPT_CMD_FAILURE;
21622         
21623         script_str = script_getstr(st,2);
21624         dur = 1000 * abs(script_getnum(st,3));
21625         FETCH(4, flag);
21626         FETCH(5, type);
21627         FETCH(6, icon);
21628
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;
21633         }
21634
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;
21638         }
21639
21640         if (icon <= SI_BLANK || icon >= SI_MAX)
21641                 icon = SI_BLANK;
21642
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);
21646         }
21647         return SCRIPT_CMD_SUCCESS;
21648 }
21649
21650 /**
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
21655 * @author [Cydh]
21656 */
21657 BUILDIN_FUNC(bonus_script_clear) {
21658         TBL_PC* sd;
21659         bool flag = false;
21660
21661         if (!script_charid2sd(3,sd))
21662                 return SCRIPT_CMD_FAILURE;
21663
21664         if (script_hasdata(st,2))
21665                 flag = script_getnum(st,2) != 0;
21666
21667         pc_bonus_script_clear(sd,(flag ? BSF_PERMANENT : BSF_REM_ALL));
21668         return SCRIPT_CMD_SUCCESS;
21669 }
21670
21671 /** Allows player to use atcommand while talking with NPC
21672 * enable_command;
21673 * @author [Cydh], [Kichi]
21674 */
21675 BUILDIN_FUNC(enable_command) {
21676         TBL_PC* sd;
21677
21678         if (!script_rid2sd(sd))
21679                 return SCRIPT_CMD_FAILURE;
21680         sd->state.disable_atcommand_on_npc = 0;
21681         return SCRIPT_CMD_SUCCESS;
21682 }
21683
21684 /** Prevents player to use atcommand while talking with NPC
21685 * disable_command;
21686 * @author [Cydh], [Kichi]
21687 */
21688 BUILDIN_FUNC(disable_command) {
21689         TBL_PC* sd;
21690
21691         if (!script_rid2sd(sd))
21692                 return SCRIPT_CMD_FAILURE;
21693         sd->state.disable_atcommand_on_npc = 1;
21694         return SCRIPT_CMD_SUCCESS;
21695 }
21696
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)
21701  */
21702 BUILDIN_FUNC(getguildmember)
21703 {
21704         struct guild *g = NULL;
21705         uint8 j = 0;
21706
21707         g = guild_search(script_getnum(st,2));
21708
21709         if (g) {
21710                 uint8 i, type = 0;
21711                 struct script_data *data = NULL;
21712                 char *varname = NULL;
21713
21714                 if (script_hasdata(st,3))
21715                         type = script_getnum(st,3);
21716
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;
21722                         }
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;
21727                         }
21728                 }
21729
21730                 for (i = 0; i < MAX_GUILD; i++) {
21731                         if (g->member[i].account_id) {
21732                                 switch (type) {
21733                                         case 2:
21734                                                 if (data)
21735                                                         setd_sub(st, NULL, varname, j, (void *)__64BPRTSIZE(g->member[i].account_id), data->ref);
21736                                                 else
21737                                                         mapreg_setreg(reference_uid(add_str("$@guildmemberaid"), j),g->member[i].account_id);
21738                                                 break;
21739                                         case 1:
21740                                                 if (data)
21741                                                         setd_sub(st, NULL, varname, j, (void *)__64BPRTSIZE(g->member[i].char_id), data->ref);
21742                                                 else
21743                                                         mapreg_setreg(reference_uid(add_str("$@guildmembercid"), j), g->member[i].char_id);
21744                                                 break;
21745                                         default:
21746                                                 if (data)
21747                                                         setd_sub(st, NULL, varname, j, (void *)__64BPRTSIZE(g->member[i].name), data->ref);
21748                                                 else
21749                                                         mapreg_setregstr(reference_uid(add_str("$@guildmembername$"), j), g->member[i].name);
21750                                                 break;
21751                                 }
21752                                 j++;
21753                         }
21754                 }
21755         }
21756         mapreg_setreg(add_str("$@guildmembercount"), j);
21757         script_pushint(st, j);
21758         return SCRIPT_CMD_SUCCESS;
21759 }
21760
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)
21766 * @author [Cydh]
21767 */
21768 BUILDIN_FUNC(addspiritball) {
21769         uint8 i, count;
21770         uint16 duration;
21771         struct map_session_data *sd = NULL;
21772
21773         if (script_hasdata(st,4)) {
21774                 if (!script_isstring(st,4))
21775                         sd = map_charid2sd(script_getnum(st,4));
21776                 else
21777                         sd = map_nick2sd(script_getstr(st,4),false);
21778         }
21779         else
21780                 script_rid2sd(sd);
21781         if (!sd)
21782                 return SCRIPT_CMD_FAILURE;
21783
21784         count = script_getnum(st,2);
21785
21786         if (count == 0)
21787                 return SCRIPT_CMD_SUCCESS;
21788
21789         duration = script_getnum(st,3);
21790
21791         for (i = 0; i < count; i++)
21792                 pc_addspiritball(sd,duration,10);
21793         return SCRIPT_CMD_SUCCESS;
21794 }
21795
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)
21800 * @author [Cydh]
21801 */
21802 BUILDIN_FUNC(delspiritball) {
21803         uint8 count;
21804         struct map_session_data *sd = NULL;
21805         
21806         if (script_hasdata(st,3)) {
21807                 if (!script_isstring(st,3))
21808                         sd = map_charid2sd(script_getnum(st,3));
21809                 else
21810                         sd = map_nick2sd(script_getstr(st,3),false);
21811         }
21812         else
21813                 script_rid2sd(sd);
21814         if (!sd)
21815                 return SCRIPT_CMD_FAILURE;
21816
21817         count = script_getnum(st,2);
21818
21819         if (count == 0)
21820                 count = 1;
21821
21822         pc_delspiritball(sd,count,0);
21823         return SCRIPT_CMD_SUCCESS;
21824 }
21825
21826 /** Counts the spirit ball that player has
21827 * countspiritball {<char_id>};
21828 * @param char_id Target player (Optional)
21829 * @author [Cydh]
21830 */
21831 BUILDIN_FUNC(countspiritball) {
21832         struct map_session_data *sd;
21833
21834         if (script_hasdata(st,2)) {
21835                 if (!script_isstring(st,2))
21836                         sd = map_charid2sd(script_getnum(st,2));
21837                 else
21838                         sd = map_nick2sd(script_getstr(st,2),false);
21839         }
21840         else
21841                 script_rid2sd(sd);
21842         if (!sd)
21843                 return SCRIPT_CMD_FAILURE;
21844         script_pushint(st,sd->spiritball);
21845         return SCRIPT_CMD_SUCCESS;
21846 }
21847
21848 /** Merges separated stackable items because of guid
21849 * mergeitem {<char_id>};
21850 * @param char_id Char ID (Optional)
21851 * @author [Cydh]
21852 */
21853 BUILDIN_FUNC(mergeitem) {
21854         struct map_session_data *sd;
21855
21856         if (!script_charid2sd(2, sd))
21857                 return SCRIPT_CMD_FAILURE;
21858
21859         clif_merge_item_open(sd);
21860         return SCRIPT_CMD_SUCCESS;
21861 }
21862
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)
21867 * @author [Cydh]
21868 */
21869 BUILDIN_FUNC(mergeitem2) {
21870         struct map_session_data *sd;
21871         struct item *items = NULL;
21872         uint16 i, count = 0, nameid = 0;
21873
21874         if (!script_charid2sd(3, sd))
21875                 return SCRIPT_CMD_FAILURE;
21876
21877         if (script_hasdata(st, 2)) {
21878                 struct script_data *data = script_getdata(st, 2);
21879                 get_val(st, data);
21880
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;
21888                         }
21889                         nameid = id->nameid;
21890                 }
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;
21897                         }
21898                 }
21899         }
21900
21901         for (i = 0; i < MAX_INVENTORY; i++) {
21902                 struct item *it = &sd->inventory.u.items_inventory[i];
21903
21904                 if (!it || !it->unique_id || it->expire_time || !itemdb_isstackable(it->nameid))
21905                         continue;
21906                 if ((!nameid || (nameid == it->nameid))) {
21907                         uint8 k;
21908                         if (!count) {
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);
21912                                 continue;
21913                         }
21914                         for (k = 0; k < count; k++) {
21915                                 // Find Match
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);
21919                                         break;
21920                                 }
21921                         }
21922                         if (k >= count) {
21923                                 // New entry
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);
21927                         }
21928                 }
21929         }
21930
21931         if (!items) // Nothing todo here
21932                 return SCRIPT_CMD_SUCCESS;
21933
21934         // Retrieve the items
21935         for (i = 0; i < count; i++) {
21936                 uint8 flag = 0;
21937                 if (!&items[i])
21938                         continue;
21939                 items[i].id = 0;
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);
21943         }
21944         aFree(items);
21945         script_pushint(st, count);
21946         return SCRIPT_CMD_SUCCESS;
21947 }
21948
21949 /**
21950  * Update an entry from NPC shop.
21951  * npcshopupdate "<name>",<item_id>,<price>{,<stock>}
21952  **/
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;
21960 #endif
21961         int i;
21962
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;
21966         }
21967         
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;
21972         }
21973
21974         for (i = 0; i < nd->u.shop.count; i++) {
21975                 if (nd->u.shop.shop_item[i].nameid == nameid) {
21976
21977                         if (price != 0)
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]);
21983                         }
21984 #endif
21985                 }
21986         }
21987
21988         script_pushint(st,1);
21989         return SCRIPT_CMD_SUCCESS;
21990 }
21991
21992 // Clan System
21993 BUILDIN_FUNC(clan_join){
21994         struct map_session_data *sd;
21995         int clan_id = script_getnum(st,2);
21996
21997         if( !script_charid2sd( 3, sd ) ){
21998                 script_pushint(st, false);
21999                 return SCRIPT_CMD_FAILURE;
22000         }
22001
22002         if( clan_member_join( sd, clan_id, sd->status.account_id, sd->status.char_id ) )
22003                 script_pushint(st, true);
22004         else
22005                 script_pushint(st, false);
22006
22007         return SCRIPT_CMD_SUCCESS;
22008 }
22009
22010 BUILDIN_FUNC(clan_leave){
22011         struct map_session_data *sd;
22012
22013         if( !script_charid2sd( 2, sd ) ){
22014                 script_pushint(st, false);
22015                 return SCRIPT_CMD_FAILURE;
22016         }
22017
22018         if( clan_member_leave( sd, sd->status.clan_id, sd->status.account_id, sd->status.char_id ) )
22019                 script_pushint(st, true);
22020         else
22021                 script_pushint(st, false);
22022
22023         return SCRIPT_CMD_SUCCESS;
22024 }
22025
22026 /**
22027  * Get rid from running script.
22028  * getattachedrid();
22029  **/
22030 BUILDIN_FUNC(getattachedrid) {
22031         script_pushint(st, st->rid);
22032         return SCRIPT_CMD_SUCCESS;
22033 }
22034
22035 /**
22036  * Get variable from a Player
22037  * getvar <variable>,<char_id>;
22038  */
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;
22044
22045         if (!sd) {
22046                 ShowError("buildin_getvar: No player found with char id '%d'.\n", char_id);
22047                 return SCRIPT_CMD_FAILURE;
22048         }
22049
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);
22055                 st->state = END;
22056                 return SCRIPT_CMD_FAILURE;
22057         }
22058
22059         name = reference_getname(data);
22060
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);
22065                 st->state = END;
22066                 return SCRIPT_CMD_FAILURE;
22067         }
22068
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);
22073                 st->state = END;
22074                 return SCRIPT_CMD_FAILURE;
22075         }
22076
22077         get_val_(st, data, sd);
22078         if (data_isint(data))
22079                 script_pushint(st, conv_num_(st, data, sd));
22080         else
22081                 script_pushstrcopy(st, conv_str_(st, data, sd));
22082
22083         push_val2(st->stack, C_NAME, reference_getuid(data), reference_getref(data));
22084         return SCRIPT_CMD_SUCCESS;
22085 }
22086
22087 /**
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.
22093  **/
22094 BUILDIN_FUNC(showscript) {
22095         struct block_list *bl = NULL;
22096         const char *msg = script_getstr(st,2);
22097         int id = 0;
22098         send_target target = AREA;
22099
22100         if (script_hasdata(st,3)) {
22101                 id = script_getnum(st,3);
22102                 bl = map_id2bl(id);
22103         }
22104         else {
22105                 bl = st->rid ? map_id2bl(st->rid) : map_id2bl(st->oid);
22106         }
22107
22108         if (!bl) {
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;
22112         }
22113
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;
22119                 }
22120         }
22121
22122         clif_showscript(bl, msg, target);
22123
22124         script_pushint(st,1);
22125         return SCRIPT_CMD_SUCCESS;
22126 }
22127
22128 /**
22129  * Ignore the SECURE_NPCTIMEOUT function.
22130  * ignoretimeout <flag>{,<char_id>};
22131  */
22132 BUILDIN_FUNC(ignoretimeout)
22133 {
22134 #ifdef SECURE_NPCTIMEOUT
22135         struct map_session_data *sd = NULL;
22136
22137         if (script_hasdata(st,3)) {
22138                 if (!script_isstring(st,3))
22139                         sd = map_charid2sd(script_getnum(st,3));
22140                 else
22141                         sd = map_nick2sd(script_getstr(st,3),false);
22142         } else
22143                 script_rid2sd(sd);
22144
22145         if (!sd)
22146                 return SCRIPT_CMD_FAILURE;
22147
22148         sd->state.ignoretimeout = script_getnum(st,2) > 0;
22149 #endif
22150         return SCRIPT_CMD_SUCCESS;
22151 }
22152
22153 /**
22154  * geteleminfo <type>{,<char_id>};
22155  **/
22156 BUILDIN_FUNC(geteleminfo) {
22157         TBL_ELEM *ed = NULL;
22158         TBL_PC *sd = NULL;
22159         int type = script_getnum(st,2);
22160
22161         if (!script_charid2sd(3, sd)) {
22162                 script_pushint(st, 0);
22163                 return SCRIPT_CMD_SUCCESS;
22164         }
22165
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;
22170         }
22171
22172         switch (type) {
22173                 case 0: script_pushint(st, ed->elemental.elemental_id); break;
22174                 case 1: script_pushint(st, ed->bl.id); break;
22175                 default:
22176                         ShowError("buildin_geteleminfo: Invalid type '%d'.\n", type);
22177                         script_pushint(st, 0);
22178                         return SCRIPT_CMD_FAILURE;
22179         }
22180
22181         return SCRIPT_CMD_SUCCESS;
22182 }
22183
22184
22185 /**
22186  * Set the quest info of quest_id only showed on player in level range.
22187  * setquestinfo_level <quest_id>,<min_level>,<max_level>
22188  * @author [Cydh]
22189  **/
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);
22194
22195         if (!qi) {
22196                 ShowError("buildin_setquestinfo_level: Quest with ID '%d' is not defined yet.\n", quest_id);
22197                 return SCRIPT_CMD_FAILURE;
22198         }
22199
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;
22204
22205         return SCRIPT_CMD_SUCCESS;
22206 }
22207
22208 /**
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>,...};
22211  * @author [Cydh]
22212  **/
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);
22217         uint8 i = 0;
22218         uint8 num = script_lastdata(st);
22219
22220         if (!qi) {
22221                 ShowError("buildin_setquestinfo_req: Quest with ID '%d' is not defined yet.\n", quest_id);
22222                 return SCRIPT_CMD_FAILURE;
22223         }
22224
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;
22228         }
22229
22230         if (num%2) {
22231                 ShowError("buildin_setquestinfo_req: Odd number of parameters(%d) - pairs of requirements are expected.\n", num-2);
22232                 return SCRIPT_CMD_FAILURE;
22233         }
22234
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;
22239                 qi->req_count++;
22240         }
22241
22242         return SCRIPT_CMD_SUCCESS;
22243 }
22244
22245 /**
22246  * Set the quest info of quest_id only showed for player that has specified Job
22247  * setquestinfo_job <quest_id>,<job>{,<job>...};
22248  * @author [Cydh]
22249  **/
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);
22254         int job_id = 0;
22255         uint8 i = 0;
22256         uint8 num = script_lastdata(st)+1;
22257
22258         if (!qi) {
22259                 ShowError("buildin_setquestinfo_job: Quest with ID '%d' is not defined yet.\n", quest_id);
22260                 return SCRIPT_CMD_FAILURE;
22261         }
22262
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);
22267                         continue;
22268                 }
22269                 buildin_questinfo_setjob(qi, job_id);
22270         }
22271
22272         return SCRIPT_CMD_SUCCESS;
22273 }
22274
22275 /**
22276  * opendressroom(<flag>{,<char_id>});
22277  */
22278 BUILDIN_FUNC(opendressroom)
22279 {
22280 #if PACKETVER >= 20150513
22281         int flag = 1;
22282     TBL_PC* sd;
22283
22284         if( script_hasdata(st,2) )
22285                 flag = script_getnum(st,2);
22286
22287     if (!script_charid2sd(3, sd))
22288         return SCRIPT_CMD_FAILURE;
22289
22290     clif_dressing_room(sd, flag);
22291
22292     return SCRIPT_CMD_SUCCESS;
22293 #else
22294     return SCRIPT_CMD_FAILURE;
22295 #endif
22296 }
22297
22298 /**
22299  * navigateto("<map>"{,<x>,<y>,<flag>,<hide_window>,<monster_id>,<char_id>});
22300  */
22301 BUILDIN_FUNC(navigateto){
22302 #if PACKETVER >= 20111010
22303         TBL_PC* sd;
22304         const char *mapname;
22305         uint16 x = 0, y = 0, monster_id = 0;
22306         uint8 flag = NAV_KAFRA_AND_AIRSHIP;
22307         bool hideWindow = true;
22308
22309         mapname = script_getstr(st,2);
22310
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);
22321
22322         if (!script_charid2sd(8, sd))
22323         return SCRIPT_CMD_FAILURE;
22324
22325         clif_navigateTo(sd,mapname,x,y,flag,hideWindow,monster_id);
22326
22327         return SCRIPT_CMD_SUCCESS;
22328 #else
22329         return SCRIPT_CMD_FAILURE;
22330 #endif
22331 }
22332
22333 /**
22334  * adopt("<parent_name>","<baby_name>");
22335  * adopt(<parent_id>,<baby_id>);
22336  * https://rathena.org/board/topic/104014-suggestion-add-adopt-or-etc/
22337  */
22338 BUILDIN_FUNC(adopt)
22339 {
22340         TBL_PC *sd, *b_sd;
22341         struct script_data *data;
22342         enum adopt_responses response;
22343
22344         data = script_getdata(st, 2);
22345         get_val(st, data);
22346
22347         if (data_isstring(data)) {
22348                 const char *name = conv_str(st, data);
22349
22350                 sd = map_nick2sd(name,false);
22351                 if (sd == NULL) {
22352                         ShowError("buildin_adopt: Non-existant parent character %s requested.\n", name);
22353                         return SCRIPT_CMD_FAILURE;
22354                 }
22355         } else if (data_isint(data)) {
22356                 uint32 char_id = conv_num(st, data);
22357
22358                 sd = map_charid2sd(char_id);
22359                 if (sd == NULL) {
22360                         ShowError("buildin_adopt: Non-existant parent character %d requested.\n", char_id);
22361                         return SCRIPT_CMD_FAILURE;
22362                 }
22363         } else {
22364                 ShowError("buildin_adopt: Invalid data type for argument #1 (%d).", data->type);
22365                 return SCRIPT_CMD_FAILURE;
22366         }
22367
22368         data = script_getdata(st, 3);
22369         get_val(st, data);
22370
22371         if (data_isstring(data)) {
22372                 const char *name = conv_str(st, data);
22373
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;
22378                 }
22379         } else if (data_isint(data)) {
22380                 uint32 char_id = conv_num(st, data);
22381
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;
22386                 }
22387         } else {
22388                 ShowError("buildin_adopt: Invalid data type for argument #2 (%d).", data->type);
22389                 return SCRIPT_CMD_FAILURE;
22390         }
22391
22392         response = pc_try_adopt(sd, map_charid2sd(sd->status.partner_id), b_sd);
22393
22394         if (response == ADOPT_ALLOWED) {
22395                 TBL_PC *p_sd = map_charid2sd(sd->status.partner_id);
22396
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;
22401         }
22402
22403         script_pushint(st, response);
22404         return SCRIPT_CMD_FAILURE;
22405 }
22406
22407 /**
22408  * Returns the minimum or maximum of all the given parameters for integer variables.
22409  *
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,...} );
22414 */
22415 BUILDIN_FUNC(minmax){
22416         char *functionname;
22417         unsigned int i;
22418         int value;
22419         // Function pointer for our comparison function (either min or max at the moment)
22420         int32 (*func)(int32, int32);
22421         
22422         // Get the real function name
22423         functionname = script_getfuncname(st);
22424         
22425         // Our data should start at offset 2
22426         i = 2;
22427
22428         if( !script_hasdata( st, i ) ){
22429                 ShowError( "buildin_%s: no arguments given!\n", functionname );
22430                 st->state = END;
22431                 return SCRIPT_CMD_FAILURE;
22432         }
22433
22434         if( strnicmp( functionname, "min", strlen( "min" ) ) == 0 ){
22435                 value = INT_MAX;
22436                 func = i32min;
22437         }else if( strnicmp( functionname, "max", strlen( "max" ) ) == 0 ){
22438                 value = INT_MIN;
22439                 func = i32max;
22440         }else{
22441                 ShowError( "buildin_%s: Unknown call case for min/max!\n", functionname );
22442                 st->state = END;
22443                 return SCRIPT_CMD_FAILURE;
22444         }
22445
22446         // As long as we have data on our script stack
22447         while( script_hasdata(st,i) ){
22448                 struct script_data *data;
22449                 
22450                 // Get the next piece of data from the script stack
22451                 data = script_getdata( st, i );
22452
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 ) ){
22458                         const char *name;
22459                         struct map_session_data* sd;
22460                         unsigned int start, end;
22461
22462                         // Get the name of the variable
22463                         name = reference_getname(data);
22464
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 );
22469                                 st->state = END;
22470                                 return SCRIPT_CMD_FAILURE;
22471                         }
22472
22473                         // Get the session data, if a player is attached
22474                         sd = st->rid ? map_id2sd(st->rid) : NULL;
22475
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 );
22480                                 st->state = END;
22481                                 return SCRIPT_CMD_FAILURE;
22482                         }
22483
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 ) );
22487
22488                         // Skip empty arrays
22489                         if( start < end ){
22490                                 int id;
22491                                 
22492                                 // For getting the values we need the id of the array
22493                                 id = reference_getid( data );
22494
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 ) ) ) );
22498
22499                                         script_removetop( st, -1, 0 );
22500                                 }
22501                         }
22502                 }else{
22503                         ShowError( "buildin_%s: not a supported data type!\n", functionname );
22504                         script_reportdata( data );
22505                         st->state = END;
22506                         return SCRIPT_CMD_FAILURE;
22507                 }
22508
22509                 // Continue with the next stack entry
22510                 i++;
22511         }
22512
22513         script_pushint( st, value );
22514
22515         return SCRIPT_CMD_SUCCESS;
22516 }
22517
22518 /**
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>};
22522  * @author [Cydh]
22523  **/
22524 BUILDIN_FUNC(getexp2) {
22525         TBL_PC *sd = NULL;
22526         int base_exp = script_getnum(st, 2);
22527         int job_exp = script_getnum(st, 3);
22528
22529         if (!script_charid2sd(4, sd))
22530                 return SCRIPT_CMD_FAILURE;
22531
22532         if (base_exp == 0 && job_exp == 0)
22533                 return SCRIPT_CMD_SUCCESS;
22534
22535         if (base_exp > 0)
22536                 pc_gainexp(sd, NULL, base_exp, 0, 2);
22537         else if (base_exp < 0)
22538                 pc_lostexp(sd, base_exp * -1, 0);
22539
22540         if (job_exp > 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;
22545 }
22546
22547 /**
22548 * Force stat recalculation of sd
22549 * recalculatestat;
22550 * @author [secretdataz]
22551 **/
22552 BUILDIN_FUNC(recalculatestat) {
22553         TBL_PC* sd;
22554
22555         if (!script_rid2sd(sd))
22556                 return SCRIPT_CMD_FAILURE;
22557
22558         status_calc_pc(sd, SCO_FORCE);
22559         return SCRIPT_CMD_SUCCESS;
22560 }
22561
22562 BUILDIN_FUNC(hateffect){
22563 #if PACKETVER >= 20150513
22564         struct map_session_data* sd;
22565         bool enable;
22566         int i, effectID;
22567
22568         if( !script_rid2sd(sd) )
22569                 return SCRIPT_CMD_FAILURE;
22570
22571         effectID = script_getnum(st,2);
22572         enable = script_getnum(st,3) ? true : false;
22573
22574         ARR_FIND( 0, sd->hatEffectCount, i, sd->hatEffectIDs[i] == effectID );
22575
22576         if( enable ){
22577                 if( i < sd->hatEffectCount ){
22578                         return SCRIPT_CMD_SUCCESS;
22579                 }
22580
22581                 RECREATE(sd->hatEffectIDs,uint32,sd->hatEffectCount+1);
22582                 sd->hatEffectIDs[sd->hatEffectCount] = effectID;
22583                 sd->hatEffectCount++;
22584         }else{
22585                 if( i == sd->hatEffectCount ){
22586                         return SCRIPT_CMD_SUCCESS;
22587                 }
22588
22589                 for( ; i < sd->hatEffectCount - 1; i++ ){
22590                         sd->hatEffectIDs[i] = sd->hatEffectIDs[i+1];
22591                 }
22592
22593                 sd->hatEffectCount--;
22594
22595                 if( !sd->hatEffectCount ){
22596                         aFree(sd->hatEffectIDs);
22597                         sd->hatEffectIDs = NULL;
22598                 }
22599         }
22600
22601         if( !sd->state.connect_new ){
22602                 clif_hat_effect_single( sd, effectID, enable );
22603         }
22604
22605 #endif
22606         return SCRIPT_CMD_SUCCESS;
22607 }
22608
22609 /**
22610 * Retrieves param of current random option. Intended for random option script only.
22611 * getrandomoptinfo(<type>);
22612 * @author [secretdataz]
22613 **/
22614 BUILDIN_FUNC(getrandomoptinfo) {
22615         struct map_session_data *sd;
22616         int val;
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);
22619
22620                 switch (param) {
22621                         case ROA_ID:
22622                                 val = sd->inventory.u.items_inventory[current_equip_item_index].option[current_equip_opt_index].id;
22623                                 break;
22624                         case ROA_VALUE:
22625                                 val = sd->inventory.u.items_inventory[current_equip_item_index].option[current_equip_opt_index].value;
22626                                 break;
22627                         case ROA_PARAM:
22628                                 val = sd->inventory.u.items_inventory[current_equip_item_index].option[current_equip_opt_index].param;
22629                                 break;
22630                         default:
22631                                 ShowWarning("buildin_getrandomoptinfo: Invalid attribute type %d (Max %d).\n", param, MAX_ITEM_RDM_OPT);
22632                                 val = 0;
22633                                 break;
22634                 }
22635                 script_pushint(st, val);
22636         }
22637         else {
22638                 script_pushint(st, 0);
22639         }
22640         return SCRIPT_CMD_SUCCESS;
22641 }
22642
22643 /**
22644 * Retrieves a random option on an equipped item.
22645 * getequiprandomoption(<equipment slot>,<index>,<type>{,<char id>});
22646 * @author [secretdataz]
22647 */
22648 BUILDIN_FUNC(getequiprandomoption) {
22649         struct map_session_data *sd;
22650         int val;
22651         short i = -1;
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;
22658         }
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;
22663         }
22664         if (equip_index_check(pos))
22665                 i = pc_checkequip(sd, equip_bitmask[pos]);
22666         if (i < 0) {
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;
22670         }
22671
22672         switch (type) {
22673                 case ROA_ID:
22674                         val = sd->inventory.u.items_inventory[i].option[index].id;
22675                         break;
22676                 case ROA_VALUE:
22677                         val = sd->inventory.u.items_inventory[i].option[index].value;
22678                         break;
22679                 case ROA_PARAM:
22680                         val = sd->inventory.u.items_inventory[i].option[index].param;
22681                         break;
22682                 default:
22683                         ShowWarning("buildin_getequiprandomoption: Invalid attribute type %d (Max %d).\n", type, MAX_ITEM_RDM_OPT);
22684                         val = 0;
22685                         break;
22686         }
22687         script_pushint(st, val);
22688         return SCRIPT_CMD_SUCCESS;
22689 }
22690
22691 /**
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]
22696 */
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;
22701         int i = -1;
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);
22709
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;
22714         }
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;
22719         }
22720         if (equip_index_check(pos))
22721                 i = pc_checkequip(sd, equip_bitmask[pos]);
22722         if (i >= 0) {
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;
22735         }
22736
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;
22740 }
22741
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;
22749         int type, val;
22750         if (!script_charid2sd(4, sd))
22751                 return SCRIPT_CMD_FAILURE;
22752         type = script_getnum(st, 2);
22753         val = script_getnum(st, 3);
22754
22755         script_pushint(st, pc_need_status_point(sd, type, val));
22756         return SCRIPT_CMD_SUCCESS;
22757 }
22758
22759 /**
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)
22764  **/
22765 BUILDIN_FUNC(jobcanentermap) {
22766         const char *mapname = script_getstr(st, 2);
22767         int mapidx = mapindex_name2id(mapname), m = -1;
22768         int jobid = 0;
22769         TBL_PC *sd = NULL;
22770
22771         if (!mapidx) {// Invalid map
22772                 script_pushint(st, false);
22773                 return SCRIPT_CMD_FAILURE;
22774         }
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;
22780         }
22781
22782         if (script_hasdata(st, 3)) {
22783                 jobid = script_getnum(st, 3);
22784         } else {
22785                 if (!script_rid2sd(sd)) {
22786                         script_pushint(st, false);
22787                         return SCRIPT_CMD_FAILURE;
22788                 }
22789                 jobid = sd->status.class_;
22790         }
22791
22792         script_pushint(st, pc_job_can_entermap((enum e_job)jobid, m, sd ? sd->group_level : 0));
22793         return SCRIPT_CMD_SUCCESS;
22794 }
22795
22796 /**
22797  * Return alliance information between the two guilds.
22798  * getguildalliance(<guild id1>,<guild id2>);
22799  * Return values:
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
22805  */
22806 BUILDIN_FUNC(getguildalliance)
22807 {
22808         struct guild *guild_data1, *guild_data2;
22809         int guild_id1, guild_id2, i = 0;
22810
22811         guild_id1 = script_getnum(st,2);
22812         guild_id2 = script_getnum(st,3);
22813
22814         if (guild_id1 < 1 || guild_id2 < 1) {
22815                 script_pushint(st, 0);
22816                 return SCRIPT_CMD_SUCCESS;
22817         }
22818
22819         if (guild_id1 == guild_id2) {
22820                 script_pushint(st, 1);
22821                 return SCRIPT_CMD_SUCCESS;
22822         }
22823
22824         guild_data1 = guild_search(guild_id1);
22825         guild_data2 = guild_search(guild_id2);
22826
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;
22831         }
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;
22836         }
22837
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;
22842         }
22843
22844         if (guild_data1->alliance[i].opposition)
22845                 script_pushint(st, 2);
22846         else
22847                 script_pushint(st, 1);
22848         return SCRIPT_CMD_SUCCESS;
22849 }
22850
22851 /*
22852  * openstorage2 <storage_id>,<mode>{,<account_id>}
22853  * mode @see enum e_storage_mode
22854  **/
22855 BUILDIN_FUNC(openstorage2) {
22856         int stor_id = script_getnum(st, 2);
22857         TBL_PC *sd = NULL;
22858
22859         if (!script_accid2sd(4, sd)) {
22860                 script_pushint(st, 0);
22861                 return SCRIPT_CMD_FAILURE;
22862         }
22863
22864         if (!storage_exists(stor_id)) {
22865                 ShowError("buildin_openstorage2: Invalid storage_id '%d'!\n", stor_id);
22866                 return SCRIPT_CMD_FAILURE;
22867         }
22868
22869         script_pushint(st, storage_premiumStorage_load(sd, stor_id, script_getnum(st, 3)));
22870         return SCRIPT_CMD_SUCCESS;
22871 }
22872
22873 /**
22874  * Create a new channel
22875  * channel_create "<chname>","<alias>"{,"<password>"{<option>{,<delay>{,<color>{,<char_id>}}}}};
22876  * @author [Cydh]
22877  **/
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);
22882         TBL_PC *sd = NULL;
22883
22884         if (i != 0) {
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;
22888         }
22889
22890         memset(&tmp_chan, 0, sizeof(struct Channel));
22891
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;
22898                 }
22899                 tmp_chan.type = CHAN_TYPE_PRIVATE;
22900                 i = 1;
22901         }
22902         else {
22903                 tmp_chan.type = CHAN_TYPE_PUBLIC;
22904                 i = 0;
22905         }
22906
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);
22913         else
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);
22917         else
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);
22921         else
22922                 tmp_chan.color = i ? channel_config.private_channel.color : channel_getColor("Default");
22923
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;
22928         }
22929         if (tmp_chan.char_id)
22930                 channel_join(ch, sd);
22931         script_pushint(st,1);
22932         return SCRIPT_CMD_SUCCESS;
22933 }
22934
22935 /**
22936  * Set channel option
22937  * channel_setopt "<chname>",<option>,<value>;
22938  * @author [Cydh]
22939  **/
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);
22944
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;
22949         }
22950
22951         switch (opt) {
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:
22959                         if (value)
22960                                 ch->opt |= opt;
22961                         else
22962                                 ch->opt &= ~opt;
22963                         break;
22964                 case CHAN_OPT_MSG_DELAY:
22965                         ch->msg_delay = value;
22966                         break;
22967                 default:
22968                         ShowError("buildin_channel_setopt: Invalid option %d!\n", opt);
22969                         script_pushint(st,0);
22970                         return SCRIPT_CMD_FAILURE;
22971         }
22972
22973         script_pushint(st,1);
22974         return SCRIPT_CMD_SUCCESS;
22975 }
22976
22977 /**
22978  * Set channel color
22979  * channel_setcolor "<chname>",<color>;
22980  * @author [Cydh]
22981  **/
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);
22986
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;
22991         }
22992
22993         ch->color = (color & 0x0000FF) << 16 | (color & 0x00FF00) | (color & 0xFF0000) >> 16;//RGB to BGR
22994
22995         script_pushint(st,1);
22996         return SCRIPT_CMD_SUCCESS;
22997 }
22998
22999 /**
23000  * Set channel password
23001  * channel_setpass "<chname>","<password>";
23002  * @author [Cydh]
23003  **/
23004 BUILDIN_FUNC(channel_setpass) {
23005         struct Channel *ch = NULL;
23006         const char *chname = script_getstr(st,2), *passwd = script_getstr(st,3);
23007
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;
23012         }
23013
23014         if (!passwd || !strcmpi(passwd,"null"))
23015                 memset(ch->pass, '\0', sizeof(ch->pass));
23016         else
23017                 safestrncpy(ch->pass, passwd, sizeof(ch->pass));
23018         script_pushint(st,1);
23019         return SCRIPT_CMD_SUCCESS;
23020 }
23021
23022 /**
23023  * Set authorized groups
23024  * channel_setgroup "<chname>",<group_id>{,...,<group_id>};
23025  * @author [Cydh]
23026  **/
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;
23031
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;
23036         }
23037
23038         if (funcname[strlen(funcname)-1] == '2') {
23039                 struct script_data *data = script_getdata(st,3);
23040                 const char *varname = reference_getname(data);
23041                 int32 id, idx;
23042
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;
23047                 }
23048
23049                 n = script_array_highest_key(st, NULL, reference_getname(data), reference_getref(data));
23050                 if (n < 1) {
23051                         ShowError("buildin_channel_setgroup: No group id listed.\n");
23052                         script_pushint(st,0);
23053                         return SCRIPT_CMD_FAILURE;
23054                 }
23055
23056                 if (ch->groups)
23057                         aFree(ch->groups);
23058                 ch->groups = NULL;
23059                 ch->group_count = 0;
23060
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)));
23065                         if (group == 0) {
23066                                 script_pushint(st,1);
23067                                 return SCRIPT_CMD_SUCCESS;
23068                         }
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);
23072                 }
23073         }
23074         else {
23075                 group = script_getnum(st,3);
23076                 n = script_lastdata(st)-1;
23077
23078                 if (n < 1) {
23079                         ShowError("buildin_channel_setgroup: Please input at least 1 group_id.\n");
23080                         script_pushint(st,0);
23081                         return SCRIPT_CMD_FAILURE;
23082                 }
23083
23084                 if (ch->groups)
23085                         aFree(ch->groups);
23086                 ch->groups = NULL;
23087                 ch->group_count = 0;
23088
23089                 if (group == 0) { // Removed group list
23090                         script_pushint(st,1);
23091                         return SCRIPT_CMD_SUCCESS;
23092                 }
23093
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);
23098                 }
23099         }
23100         script_pushint(st,n);
23101         return SCRIPT_CMD_SUCCESS;
23102 }
23103
23104 /**
23105  * Send message on channel
23106  * channel_chat "<chname>","<message>"{,<color>};
23107  * @author [Cydh]
23108  **/
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;
23114
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;
23122                 }
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;
23127                 }
23128         }
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;
23135                 }
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;
23140                 }
23141         }
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;
23146         }
23147
23148         if (!ch) {
23149                 script_pushint(st,0);
23150                 return SCRIPT_CMD_FAILURE;
23151         }
23152
23153         color = ch->color;
23154         FETCH(4, color);
23155
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;
23160 }
23161
23162 /**
23163  * Ban player from a channel
23164  * channel_ban "<chname>",<char_id>;
23165  * @author [Cydh]
23166  **/
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);
23171         TBL_PC *tsd;
23172
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;
23177         }
23178
23179         if (ch->char_id == char_id) {
23180                 script_pushint(st,0);
23181                 return SCRIPT_CMD_SUCCESS;
23182         }
23183
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;
23188         }
23189
23190         if (!idb_exists(ch->banned, char_id)) {
23191                 struct chan_banentry *cbe;
23192                 char output[CHAT_SIZE_MAX+1];
23193
23194                 CREATE(cbe, struct chan_banentry, 1);
23195                 cbe->char_id = char_id;
23196                 if (tsd) {
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.
23200                 }
23201                 else
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);
23205         }
23206
23207         script_pushint(st,1);
23208         return SCRIPT_CMD_SUCCESS;
23209 }
23210
23211 /**
23212  * Ban player from a channel
23213  * channel_unban "<chname>",<char_id>;
23214  * @author [Cydh]
23215  **/
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);
23220
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;
23225         }
23226
23227         if (ch->char_id == char_id) {
23228                 script_pushint(st,0);
23229                 return SCRIPT_CMD_SUCCESS;
23230         }
23231
23232         if (idb_exists(ch->banned, char_id)) {
23233                 char output[CHAT_SIZE_MAX+1];
23234                 TBL_PC *tsd = map_charid2sd(char_id);
23235                 if (tsd)
23236                         safesnprintf(output, CHAT_SIZE_MAX, msg_txt(tsd,770), ch->alias, tsd->status.name); // %s %s has been unbanned
23237                 else
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);
23241         }
23242
23243         script_pushint(st,1);
23244         return SCRIPT_CMD_SUCCESS;
23245 }
23246
23247 /**
23248  * Kick player from a channel
23249  * channel_kick "<chname>",<char_id>;
23250  * channel_kick "<chname>","<char_name>";
23251  * @author [Cydh]
23252  **/
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;
23258         int res = 1;
23259
23260         get_val(st, data);
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;
23266                 }
23267         }
23268         else {
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;
23273                 }
23274         }
23275
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;
23280         }
23281
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;
23285         }
23286
23287         switch(ch->type){
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;
23291         }
23292         
23293         if (res == 0) {
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);
23297         }
23298
23299         script_pushint(st,1);
23300         return SCRIPT_CMD_SUCCESS;
23301 }
23302
23303 /**
23304  * Delete a channel
23305  * channel_delete "<chname>";
23306  * @author [Cydh]
23307  **/
23308 BUILDIN_FUNC(channel_delete) {
23309         struct Channel *ch = NULL;
23310         const char *chname = script_getstr(st,2);
23311
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;
23316         }
23317
23318         script_pushint(st,channel_delete(ch,true));
23319         return SCRIPT_CMD_SUCCESS;
23320 }
23321
23322 BUILDIN_FUNC(unloadnpc) {
23323         const char *name;
23324         struct npc_data* nd;
23325
23326         name = script_getstr(st, 2);
23327         nd = npc_name2id(name);
23328
23329         if( nd == NULL ){
23330                 ShowError( "buildin_unloadnpc: npc '%s' was not found.\n", name );
23331                 return SCRIPT_CMD_FAILURE;
23332         }
23333
23334         npc_unload_duplicates(nd);
23335         npc_unload(nd, true);
23336         npc_read_event_script();
23337
23338         return SCRIPT_CMD_SUCCESS;
23339 }
23340
23341 /**
23342  * Add an achievement to the player's log
23343  * achievementadd(<achievement ID>{,<char ID>});
23344  */
23345 BUILDIN_FUNC(achievementadd) {
23346         struct map_session_data *sd;
23347         int achievement_id = script_getnum(st, 2);
23348
23349         if (!script_charid2sd(3, sd)) {
23350                 script_pushint(st, false);
23351                 return SCRIPT_CMD_FAILURE;
23352         }
23353
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;
23358         }
23359
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;
23364                 }else{
23365                         // Simply ignore it on the first call, because the status will be recalculated after loading anyway
23366                         return SCRIPT_CMD_SUCCESS;
23367                 }
23368         }
23369
23370         if (achievement_add(sd, achievement_id))
23371                 script_pushint(st, true);
23372         else
23373                 script_pushint(st, false);
23374         return SCRIPT_CMD_SUCCESS;
23375 }
23376
23377 /**
23378  * Removes an achievement on a player.
23379  * achievementremove(<achievement ID>{,<char ID>});
23380  * Just for Atemo. ;)
23381  */
23382 BUILDIN_FUNC(achievementremove) {
23383         struct map_session_data *sd;
23384         int achievement_id = script_getnum(st, 2);
23385
23386         if (!script_charid2sd(3, sd)) {
23387                 script_pushint(st, false);
23388                 return SCRIPT_CMD_FAILURE;
23389         }
23390
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;
23395         }
23396
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;
23401                 }else{
23402                         // Simply ignore it on the first call, because the status will be recalculated after loading anyway
23403                         return SCRIPT_CMD_SUCCESS;
23404                 }
23405         }
23406
23407         if (achievement_remove(sd, achievement_id))
23408                 script_pushint(st, true);
23409         else
23410                 script_pushint(st, false);
23411         return SCRIPT_CMD_SUCCESS;
23412 }
23413
23414 /**
23415  * Returns achievement progress
23416  * achievementinfo(<achievement ID>,<type>{,<char ID>});
23417  */
23418 BUILDIN_FUNC(achievementinfo) {
23419         struct map_session_data *sd;
23420         int achievement_id = script_getnum(st, 2);
23421
23422         if (!script_charid2sd(4, sd)) {
23423                 script_pushint(st, false);
23424                 return SCRIPT_CMD_FAILURE;
23425         }
23426
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;
23431         }
23432
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;
23438                 }else{
23439                         // Simply ignore it on the first call, because the status will be recalculated after loading anyway
23440                         return SCRIPT_CMD_SUCCESS;
23441                 }
23442         }
23443
23444         script_pushint(st, achievement_check_progress(sd, achievement_id, script_getnum(st, 3)));
23445         return SCRIPT_CMD_SUCCESS;
23446 }
23447
23448 /**
23449  * Award an achievement; Ignores requirements
23450  * achievementcomplete(<achievement ID>{,<char ID>});
23451  */
23452 BUILDIN_FUNC(achievementcomplete) {
23453         struct map_session_data *sd;
23454         int i, achievement_id = script_getnum(st, 2);
23455
23456         if (!script_charid2sd(3, sd)) {
23457                 script_pushint(st, false);
23458                 return SCRIPT_CMD_FAILURE;
23459         }
23460
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;
23465         }
23466         
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;
23471                 }else{
23472                         // Simply ignore it on the first call, because the status will be recalculated after loading anyway
23473                         return SCRIPT_CMD_SUCCESS;
23474                 }
23475         }
23476
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;
23483 }
23484
23485 /**
23486  * Checks if the achievement exists on player.
23487  * achievementexists(<achievement ID>{,<char ID>});
23488  */
23489 BUILDIN_FUNC(achievementexists) {
23490         struct map_session_data *sd;
23491         int i, achievement_id = script_getnum(st, 2);
23492
23493         if (!script_charid2sd(3, sd)) {
23494                 script_pushint(st, false);
23495                 return SCRIPT_CMD_FAILURE;
23496         }
23497
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;
23502         }
23503
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;
23509                 }else{
23510                         // Simply ignore it on the first call, because the status will be recalculated after loading anyway
23511                         return SCRIPT_CMD_SUCCESS;
23512                 }
23513         }
23514
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;
23518 }
23519
23520 /**
23521  * Updates an achievement's value.
23522  * achievementupdate(<achievement ID>,<type>,<value>{,<char ID>});
23523  */
23524 BUILDIN_FUNC(achievementupdate) {
23525         struct map_session_data *sd;
23526         int i, achievement_id, type, value;
23527
23528         achievement_id = script_getnum(st, 2);
23529         type = script_getnum(st, 3);
23530         value = script_getnum(st, 4);
23531
23532         if (!script_charid2sd(5, sd)) {
23533                 script_pushint(st, false);
23534                 return SCRIPT_CMD_FAILURE;
23535         }
23536
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;
23541         }
23542
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;
23547                 }else{
23548                         // Simply ignore it on the first call, because the status will be recalculated after loading anyway
23549                         return SCRIPT_CMD_SUCCESS;
23550                 }
23551         }
23552
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);
23556
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;
23561         }
23562
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;
23569         else {
23570                 ShowWarning("buildin_achievementupdate: Unknown type '%d'.\n", type);
23571                 script_pushint(st, false);
23572                 return SCRIPT_CMD_FAILURE;
23573         }
23574
23575         achievement_update_achievement(sd, achievement_id, false);
23576         script_pushint(st, true);
23577         return SCRIPT_CMD_SUCCESS;
23578 }
23579
23580 /**
23581  * Get an equipment's refine cost
23582  * getequiprefinecost(<equipment slot>,<type>,<information>{,<char id>})
23583  * returns -1 on fail
23584  */
23585 BUILDIN_FUNC(getequiprefinecost) {
23586         int i = -1, slot, type, info;
23587         map_session_data *sd;
23588
23589         slot = script_getnum(st, 2);
23590         type = script_getnum(st, 3);
23591         info = script_getnum(st, 4);
23592
23593         if (!script_charid2sd(5, sd)) {
23594                 script_pushint(st, 0);
23595                 return SCRIPT_CMD_FAILURE;
23596         }
23597
23598         if (type < 0 || type >= REFINE_COST_MAX) {
23599                 script_pushint(st, -1);
23600                 return SCRIPT_CMD_SUCCESS;
23601         }
23602
23603         if (equip_index_check(slot))
23604                 i = pc_checkequip(sd, equip_bitmask[slot]);
23605
23606         if (i < 0) {
23607                 script_pushint(st, -1);
23608                 return SCRIPT_CMD_SUCCESS;
23609         }
23610
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;
23615                 else
23616                         weapon_lv = REFINE_TYPE_SHADOW;
23617         }
23618
23619         script_pushint(st, status_get_refine_cost(weapon_lv, type, info != 0));
23620
23621         return SCRIPT_CMD_SUCCESS;
23622 }
23623
23624 #include "../custom/script.inc"
23625
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);
23632 #endif
23633
23634 /** Regular expression matching
23635  * preg_match(<pattern>,<string>{,<offset>})
23636  */
23637 BUILDIN_FUNC(preg_match) {
23638 #ifdef PCRE_SUPPORT
23639         pcre *re;
23640         pcre_extra *pcreExtra;
23641         const char *error;
23642         int erroffset, r, offset = 0;
23643         int subStrVec[30];
23644
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);
23649
23650         re = pcre_compile(pattern, 0, &error, &erroffset, NULL);
23651         pcreExtra = pcre_study(re, 0, &error);
23652
23653         r = pcre_exec(re, pcreExtra, subject, (int)strlen(subject), offset, 0, subStrVec, 30);
23654
23655         pcre_free(re);
23656         if (pcreExtra != NULL)
23657                 pcre_free(pcreExtra);
23658
23659         if (r < 0)
23660                 script_pushint(st,0);
23661         else
23662                 script_pushint(st,(r > 0) ? r : 30 / 3);
23663
23664         return SCRIPT_CMD_SUCCESS;
23665 #else
23666         ShowDebug("script:preg_match: cannot run without PCRE library enabled.\n");
23667         script_pushint(st,0);
23668         return SCRIPT_CMD_SUCCESS;
23669 #endif
23670 }
23671
23672 /// script command definitions
23673 /// for an explanation on args, see add_buildin_func
23674 struct script_function buildin_func[] = {
23675         // NPC interaction
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*"),
23683         //
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]
23961 #endif
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?"),
24097         // WoE SE
24098         BUILDIN_DEF(agitstart2,""),
24099         BUILDIN_DEF(agitend2,""),
24100         BUILDIN_DEF(agitcheck2,""),
24101         // BattleGround
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??"),
24116
24117         // Instancing
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?"),
24130         /**
24131          * 3rd-related
24132          **/
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"),
24139         /**
24140          * rAthena and beyond!
24141          **/
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"),
24161
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??"),
24171
24172         //Bound items [Xantara] & [Akinari]
24173         BUILDIN_DEF2(getitem,"getitembound","vii?"),
24174         BUILDIN_DEF2(getitem2,"getitembound2","viiiiiiiii?"),
24175         BUILDIN_DEF(countbound, "??"),
24176
24177         // Party related
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"),
24184
24185         // Clan system
24186         BUILDIN_DEF(clan_join,"i?"),
24187         BUILDIN_DEF(clan_leave,"?"),
24188
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"),
24227
24228         // WoE TE
24229         BUILDIN_DEF(agitstart3,""),
24230         BUILDIN_DEF(agitend3,""),
24231         BUILDIN_DEF(agitcheck3,""),
24232         BUILDIN_DEF(gvgon3,"s"),
24233         BUILDIN_DEF(gvgoff3,"s"),
24234
24235         // Channel System
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"),
24247
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?"),
24255
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?"),
24263
24264
24265         BUILDIN_DEF(getequiprefinecost,"iii?"),
24266 #include "../custom/script_def.inc"
24267
24268         {NULL,NULL,NULL},
24269 };
24270
24271 #ifdef __cplusplus
24272 }
24273 #endif