· 8 years ago · May 13, 2018, 03:36 AM
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#include "../common/cbasetypes.h"
11
12#include "../common/malloc.h"
13#include "../common/md5calc.h"
14#include "../common/lock.h"
15#include "../common/nullpo.h"
16#include "../common/showmsg.h"
17#include "../common/strlib.h"
18#include "../common/timer.h"
19#include "../common/utils.h"
20#include "../common/socket.h"
21
22#include "map.h"
23#include "path.h"
24#include "clif.h"
25#include "chrif.h"
26#include "itemdb.h"
27#include "pc.h"
28#include "status.h"
29#include "storage.h"
30#include "mob.h"
31#include "npc.h"
32#include "pet.h"
33#include "mapreg.h"
34#include "homunculus.h"
35#include "instance.h"
36#include "mercenary.h"
37#include "intif.h"
38#include "skill.h"
39#include "status.h"
40#include "chat.h"
41#include "channel.h"
42#include "battle.h"
43#include "battleground.h"
44#include "party.h"
45#include "guild.h"
46#include "guild_castle.h"
47#include "guild_expcache.h"
48#include "atcommand.h"
49#include "log.h"
50#include "unit.h"
51#include "pet.h"
52#include "mail.h"
53#include "script.h"
54#include "quest.h"
55#include "achievement.h"
56#include "faction.h"
57
58#include <stdio.h>
59#include <stdlib.h>
60#include <string.h>
61#include <math.h>
62#ifndef WIN32
63 #include <sys/time.h>
64#endif
65#include <time.h>
66#include <setjmp.h>
67#include <errno.h>
68
69
70///////////////////////////////////////////////////////////////////////////////
71//## TODO possible enhancements: [FlavioJS]
72// - 'callfunc' supporting labels in the current npc "::LabelName"
73// - 'callfunc' supporting labels in other npcs "NpcName::LabelName"
74// - 'function FuncName;' function declarations reverting to global functions
75// if local label isn't found
76// - join callfunc and callsub's functionality
77// - remove dynamic allocation in add_word()
78// - remove GETVALUE / SETVALUE
79// - clean up the set_reg / set_val / setd_sub mess
80// - detect invalid label references at parse-time
81
82//
83// struct script_state* st;
84//
85
86/// Returns the script_data at the target index
87#define script_getdata(st,i) ( &((st)->stack->stack_data[(st)->start + (i)]) )
88/// Returns if the stack contains data at the target index
89#define script_hasdata(st,i) ( (st)->end > (st)->start + (i) )
90/// Returns the index of the last data in the stack
91#define script_lastdata(st) ( (st)->end - (st)->start - 1 )
92/// Pushes an int into the stack
93#define script_pushint(st,val) push_val((st)->stack, C_INT, (val))
94/// Pushes a string into the stack (script engine frees it automatically)
95#define script_pushstr(st,val) push_str((st)->stack, C_STR, (val))
96/// Pushes a copy of a string into the stack
97#define script_pushstrcopy(st,val) push_str((st)->stack, C_STR, aStrdup(val))
98/// Pushes a constant string into the stack (must never change or be freed)
99#define script_pushconststr(st,val) push_str((st)->stack, C_CONSTSTR, (val))
100/// Pushes a nil into the stack
101#define script_pushnil(st) push_val((st)->stack, C_NOP, 0)
102/// Pushes a copy of the data in the target index
103#define script_pushcopy(st,i) push_copy((st)->stack, (st)->start + (i))
104
105#define script_isstring(st,i) data_isstring(script_getdata(st,i))
106#define script_isint(st,i) data_isint(script_getdata(st,i))
107
108#define script_getnum(st,val) conv_num(st, script_getdata(st,val))
109#define script_getstr(st,val) conv_str(st, script_getdata(st,val))
110#define script_getref(st,val) ( script_getdata(st,val)->ref )
111
112// Note: "top" functions/defines use indexes relative to the top of the stack
113// -1 is the index of the data at the top
114
115/// Returns the script_data at the target index relative to the top of the stack
116#define script_getdatatop(st,i) ( &((st)->stack->stack_data[(st)->stack->sp + (i)]) )
117/// Pushes a copy of the data in the target index relative to the top of the stack
118#define script_pushcopytop(st,i) push_copy((st)->stack, (st)->stack->sp + (i))
119/// Removes the range of values [start,end[ relative to the top of the stack
120#define script_removetop(st,start,end) ( pop_stack((st), ((st)->stack->sp + (start)), (st)->stack->sp + (end)) )
121
122//
123// struct script_data* data;
124//
125
126/// Returns if the script data is a string
127#define data_isstring(data) ( (data)->type == C_STR || (data)->type == C_CONSTSTR )
128/// Returns if the script data is an int
129#define data_isint(data) ( (data)->type == C_INT )
130/// Returns if the script data is a reference
131#define data_isreference(data) ( (data)->type == C_NAME )
132/// Returns if the script data is a label
133#define data_islabel(data) ( (data)->type == C_POS )
134/// Returns if the script data is an internal script function label
135#define data_isfunclabel(data) ( (data)->type == C_USERFUNC_POS )
136
137/// Returns if this is a reference to a constant
138#define reference_toconstant(data) ( str_data[reference_getid(data)].type == C_INT )
139/// Returns if this a reference to a param
140#define reference_toparam(data) ( str_data[reference_getid(data)].type == C_PARAM )
141/// Returns if this a reference to a variable
142//##TODO confirm it's C_NAME [FlavioJS]
143#define reference_tovariable(data) ( str_data[reference_getid(data)].type == C_NAME )
144/// Returns if this a reference to nil (unused name, is probably supposed to be a variable)
145#define reference_tonil(data) ( str_data[reference_getid(data)].type == C_NOP )
146/// Returns the unique id of the reference (id and index)
147#define reference_getuid(data) ( (data)->u.num )
148/// Returns the id of the reference
149#define reference_getid(data) ( (int32)(reference_getuid(data) & 0x00ffffff) )
150/// Returns the array index of the reference
151#define reference_getindex(data) ( (int32)(((uint32)(reference_getuid(data) & 0xff000000)) >> 24) )
152/// Returns the name of the reference
153#define reference_getname(data) ( str_buf + str_data[reference_getid(data)].str )
154/// Returns the linked list of uid-value pairs of the reference (can be NULL)
155#define reference_getref(data) ( (data)->ref )
156/// Returns the value of the constant
157#define reference_getconstant(data) ( str_data[reference_getid(data)].val )
158/// Returns the type of param
159#define reference_getparamtype(data) ( str_data[reference_getid(data)].val )
160
161/// Composes the uid of a reference from the id and the index
162#define reference_uid(id,idx) ( (int32)((((uint32)(id)) & 0x00ffffff) | (((uint32)(idx)) << 24)) )
163
164#define not_server_variable(prefix) ( (prefix) != '$' && (prefix) != '.' && (prefix) != '\'')
165#define not_array_variable(prefix) ( (prefix) != '$' && (prefix) != '@' && (prefix) != '.' && (prefix) != '\'' )
166#define is_string_variable(name) ( (name)[strlen(name) - 1] == '$' )
167
168#define FETCH(n, t) \
169 if( script_hasdata(st,n) ) \
170 (t)=script_getnum(st,n);
171
172#define SCRIPT_BLOCK_SIZE 512
173enum { LABEL_NEXTLINE=1,LABEL_START };
174
175/// temporary buffer for passing around compiled bytecode
176/// @see add_scriptb, set_label, parse_script
177static unsigned char* script_buf = NULL;
178static int script_pos = 0, script_size = 0;
179
180static inline int GETVALUE(const unsigned char* buf, int i)
181{
182 return (int)MakeDWord(MakeWord(buf[i], buf[i+1]), MakeWord(buf[i+2], 0));
183}
184static inline void SETVALUE(unsigned char* buf, int i, int n)
185{
186 buf[i] = GetByte(n, 0);
187 buf[i+1] = GetByte(n, 1);
188 buf[i+2] = GetByte(n, 2);
189}
190
191// String buffer structures.
192// str_data stores string information
193static struct str_data_struct {
194 enum c_op type;
195 int str;
196 int backpatch;
197 int label;
198 int (*func)(struct script_state *st);
199 int val;
200 int next;
201} *str_data = NULL;
202static int str_data_size = 0; // size of the data
203static int str_num = LABEL_START; // next id to be assigned
204
205// str_buf holds the strings themselves
206static char *str_buf;
207static int str_size = 0; // size of the buffer
208static int str_pos = 0; // next position to be assigned
209
210
211// Using a prime number for SCRIPT_HASH_SIZE should give better distributions
212#define SCRIPT_HASH_SIZE 1021
213int str_hash[SCRIPT_HASH_SIZE];
214// Specifies which string hashing method to use
215//#define SCRIPT_HASH_DJB2
216//#define SCRIPT_HASH_SDBM
217#define SCRIPT_HASH_ELF
218
219static DBMap* scriptlabel_db=NULL; // const char* label_name -> int script_pos
220static DBMap* userfunc_db=NULL; // const char* func_name -> struct script_code*
221static int parse_options=0;
222DBMap* script_get_label_db(){ return scriptlabel_db; }
223DBMap* script_get_userfunc_db(){ return userfunc_db; }
224
225// Caches compiled autoscript item code.
226// Note: This is not cleared when reloading itemdb.
227static DBMap* autobonus_db=NULL; // char* script -> char* bytecode
228
229struct Script_Config script_config = {
230 1, // warn_func_mismatch_argtypes
231 1, 65535, 2048, //warn_func_mismatch_paramnum/check_cmdcount/check_gotocount
232 0, INT_MAX, // input_min_value/input_max_value
233 "OnPCDieEvent", //die_event_name
234 "OnPCKillEvent", //kill_pc_event_name
235 "OnNPCKillEvent", //kill_mob_event_name
236 "OnPCLoginEvent", //login_event_name
237 "OnPCLogoutEvent", //logout_event_name
238 "OnPCLoadMapEvent", //loadmap_event_name
239 "OnPCBaseLvUpEvent", //baselvup_event_name
240 "OnPCJobLvUpEvent", //joblvup_event_name
241 "OnPCConsumeEvent", //consume_event_name [ by Emistry ]
242 "OnTouch_", //ontouch_name (runs on first visible char to enter area, picks another char if the first char leaves)
243 "OnTouch", //ontouch2_name (run whenever a char walks into the OnTouch area)
244};
245
246static jmp_buf error_jump;
247static char* error_msg;
248static const char* error_pos;
249static int error_report; // if the error should produce output
250
251// for advanced scripting support ( nested if, switch, while, for, do-while, function, etc )
252// [Eoe / jA 1080, 1081, 1094, 1164]
253enum curly_type {
254 TYPE_NULL = 0,
255 TYPE_IF,
256 TYPE_SWITCH,
257 TYPE_WHILE,
258 TYPE_FOR,
259 TYPE_DO,
260 TYPE_USERFUNC,
261 TYPE_ARGLIST // function argument list
262};
263
264enum e_arglist
265{
266 ARGLIST_UNDEFINED = 0,
267 ARGLIST_NO_PAREN = 1,
268 ARGLIST_PAREN = 2,
269};
270
271static struct {
272 struct {
273 enum curly_type type;
274 int index;
275 int count;
276 int flag;
277 struct linkdb_node *case_label;
278 } curly[256]; // å³ã‚«ãƒƒã‚³ã®æƒ…å ±
279 int curly_count; // å³ã‚«ãƒƒã‚³ã®æ•°
280 int index; // スクリプト内ã§ä½¿ç”¨ã—ãŸæ§‹æ–‡ã®æ•°
281} syntax;
282
283const char* parse_curly_close(const char* p);
284const char* parse_syntax_close(const char* p);
285const char* parse_syntax_close_sub(const char* p,int* flag);
286const char* parse_syntax(const char* p);
287static int parse_syntax_for_flag = 0;
288
289extern int current_equip_item_index; //for New CARDS Scripts. It contains Inventory Index of the EQUIP_SCRIPT caller item. [Lupus]
290int potion_flag=0; //For use on Alchemist improved potions/Potion Pitcher. [Skotlex]
291int potion_hp=0, potion_per_hp=0, potion_sp=0, potion_per_sp=0;
292int potion_target=0;
293
294
295c_op get_com(unsigned char *script,int *pos);
296int get_num(unsigned char *script,int *pos);
297
298typedef struct script_function {
299 int (*func)(struct script_state *st);
300 const char *name;
301 const char *arg;
302} script_function;
303
304extern script_function buildin_func[];
305
306static struct linkdb_node* sleep_db;// int oid -> struct script_state*
307
308/*==========================================
309 * ãƒãƒ¼ã‚«ãƒ«ãƒ—ãƒãƒˆã‚¿ã‚¤ãƒ—宣言 (å¿…è¦ãªç‰©ã®ã¿)
310 *------------------------------------------*/
311const char* parse_subexpr(const char* p,int limit);
312int run_func(struct script_state *st);
313
314enum {
315 MF_NOMEMO, //0
316 MF_NOTELEPORT,
317 MF_NOSAVE,
318 MF_NOBRANCH,
319 MF_NOPENALTY,
320 MF_NOZENYPENALTY,
321 MF_PVP,
322 MF_PVP_NOPARTY,
323 MF_PVP_NOGUILD,
324 MF_GVG,
325 MF_GVG_NOPARTY, //10
326 MF_NOTRADE,
327 MF_NOSKILL,
328 MF_NOWARP,
329 MF_PARTYLOCK,
330 MF_NOICEWALL,
331 MF_SNOW,
332 MF_FOG,
333 MF_SAKURA,
334 MF_LEAVES,
335 MF_RAIN, //20
336 // 21 free
337 MF_NOGO = 22,
338 MF_CLOUDS,
339 MF_CLOUDS2,
340 MF_FIREWORKS,
341 MF_GVG_CASTLE,
342 MF_GVG_DUNGEON,
343 MF_NIGHTENABLED,
344 MF_NOBASEEXP,
345 MF_NOJOBEXP, //30
346 MF_NOMOBLOOT,
347 MF_NOMVPLOOT,
348 MF_NORETURN,
349 MF_NOWARPTO,
350 MF_NIGHTMAREDROP,
351 MF_RESTRICTED,
352 MF_NOCOMMAND,
353 MF_NODROP,
354 MF_JEXP,
355 MF_BEXP, //40
356 MF_NOVENDING,
357 MF_LOADEVENT,
358 MF_NOCHAT,
359 MF_NOEXPPENALTY,
360 MF_GUILDLOCK,
361 MF_TOWN,
362 MF_AUTOTRADE,
363 MF_ALLOWKS,
364 MF_MONSTER_NOTELEPORT,
365 MF_PVP_NOCALCRANK, //50
366 MF_BATTLEGROUND,
367 MF_RESET,
368 MF_NOPVPMODE = 70,
369 MF_PVPMODE,
370 MF_WOE_SET,
371 MF_BLOCKED,
372 MF_NOSTORAGE,
373 MF_NOGUILDSTORAGE,
374};
375
376const char* script_op2name(int op)
377{
378#define RETURN_OP_NAME(type) case type: return #type
379 switch( op )
380 {
381 RETURN_OP_NAME(C_NOP);
382 RETURN_OP_NAME(C_POS);
383 RETURN_OP_NAME(C_INT);
384 RETURN_OP_NAME(C_PARAM);
385 RETURN_OP_NAME(C_FUNC);
386 RETURN_OP_NAME(C_STR);
387 RETURN_OP_NAME(C_CONSTSTR);
388 RETURN_OP_NAME(C_ARG);
389 RETURN_OP_NAME(C_NAME);
390 RETURN_OP_NAME(C_EOL);
391 RETURN_OP_NAME(C_RETINFO);
392 RETURN_OP_NAME(C_USERFUNC);
393 RETURN_OP_NAME(C_USERFUNC_POS);
394
395 // operators
396 RETURN_OP_NAME(C_OP3);
397 RETURN_OP_NAME(C_LOR);
398 RETURN_OP_NAME(C_LAND);
399 RETURN_OP_NAME(C_LE);
400 RETURN_OP_NAME(C_LT);
401 RETURN_OP_NAME(C_GE);
402 RETURN_OP_NAME(C_GT);
403 RETURN_OP_NAME(C_EQ);
404 RETURN_OP_NAME(C_NE);
405 RETURN_OP_NAME(C_XOR);
406 RETURN_OP_NAME(C_OR);
407 RETURN_OP_NAME(C_AND);
408 RETURN_OP_NAME(C_ADD);
409 RETURN_OP_NAME(C_SUB);
410 RETURN_OP_NAME(C_MUL);
411 RETURN_OP_NAME(C_DIV);
412 RETURN_OP_NAME(C_MOD);
413 RETURN_OP_NAME(C_NEG);
414 RETURN_OP_NAME(C_LNOT);
415 RETURN_OP_NAME(C_NOT);
416 RETURN_OP_NAME(C_R_SHIFT);
417 RETURN_OP_NAME(C_L_SHIFT);
418
419 default:
420 ShowDebug("script_op2name: unexpected op=%d\n", op);
421 return "???";
422 }
423#undef RETURN_OP_NAME
424}
425
426/// Reports on the console the src of a script error.
427static void script_reportsrc(struct script_state *st)
428{
429 struct block_list* bl;
430
431 if( st->oid == 0 )
432 return; //Can't report source.
433
434 bl = map_id2bl(st->oid);
435 if( bl == NULL )
436 return;
437
438 switch( bl->type )
439 {
440 case BL_NPC:
441 if( bl->m >= 0 )
442 ShowDebug("Source (NPC): %s at %s (%d,%d)\n", ((struct npc_data *)bl)->name, map[bl->m].name, bl->x, bl->y);
443 else
444 ShowDebug("Source (NPC): %s (invisible/not on a map)\n", ((struct npc_data *)bl)->name);
445 break;
446 default:
447 if( bl->m >= 0 )
448 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);
449 else
450 ShowDebug("Source (Non-NPC type %d): name %s (invisible/not on a map)\n", bl->type, status_get_name(bl));
451 break;
452 }
453}
454
455/// Reports on the console information about the script data.
456static void script_reportdata(struct script_data* data)
457{
458 if( data == NULL )
459 return;
460 switch( data->type )
461 {
462 case C_NOP:// no value
463 ShowDebug("Data: nothing (nil)\n");
464 break;
465 case C_INT:// number
466 ShowDebug("Data: number value=%d\n", data->u.num);
467 break;
468 case C_STR:
469 case C_CONSTSTR:// string
470 if( data->u.str )
471 {
472 ShowDebug("Data: string value=\"%s\"\n", data->u.str);
473 }
474 else
475 {
476 ShowDebug("Data: string value=NULL\n");
477 }
478 break;
479 case C_NAME:// reference
480 if( reference_tovariable(data) )
481 {// variable
482 const char* name = reference_getname(data);
483 if( not_array_variable(*name) )
484 ShowDebug("Data: variable name='%s'\n", name);
485 else
486 ShowDebug("Data: variable name='%s' index=%d\n", name, reference_getindex(data));
487 }
488 else if( reference_toconstant(data) )
489 {// constant
490 ShowDebug("Data: constant name='%s' value=%d\n", reference_getname(data), reference_getconstant(data));
491 }
492 else if( reference_toparam(data) )
493 {// param
494 ShowDebug("Data: param name='%s' type=%d\n", reference_getname(data), reference_getparamtype(data));
495 }
496 else
497 {// ???
498 ShowDebug("Data: reference name='%s' type=%s\n", reference_getname(data), script_op2name(data->type));
499 ShowDebug("Please report this!!! - str_data.type=%s\n", script_op2name(str_data[reference_getid(data)].type));
500 }
501 break;
502 case C_POS:// label
503 ShowDebug("Data: label pos=%d\n", data->u.num);
504 break;
505 default:
506 ShowDebug("Data: %s\n", script_op2name(data->type));
507 break;
508 }
509}
510
511
512/// Reports on the console information about the current built-in function.
513static void script_reportfunc(struct script_state* st)
514{
515 int i, params, id;
516 struct script_data* data;
517
518 if( !script_hasdata(st,0) )
519 {// no stack
520 return;
521 }
522
523 data = script_getdata(st,0);
524
525 if( !data_isreference(data) || str_data[reference_getid(data)].type != C_FUNC )
526 {// script currently not executing a built-in function or corrupt stack
527 return;
528 }
529
530 id = reference_getid(data);
531 params = script_lastdata(st)-1;
532
533 if( params > 0 )
534 {
535 ShowDebug("Function: %s (%d parameter%s):\n", get_str(id), params, ( params == 1 ) ? "" : "s");
536
537 for( i = 2; i <= script_lastdata(st); i++ )
538 {
539 script_reportdata(script_getdata(st,i));
540 }
541 }
542 else
543 {
544 ShowDebug("Function: %s (no parameters)\n", get_str(id));
545 }
546}
547
548
549/*==========================================
550 * エラーメッセージ出力
551 *------------------------------------------*/
552static void disp_error_message2(const char *mes,const char *pos,int report)
553{
554 error_msg = aStrdup(mes);
555 error_pos = pos;
556 error_report = report;
557 longjmp( error_jump, 1 );
558}
559#define disp_error_message(mes,pos) disp_error_message2(mes,pos,1)
560
561/// Checks event parameter validity
562static void check_event(struct script_state *st, const char *evt)
563{
564 if( evt && evt[0] && !stristr(evt, "::On") )
565 {
566 if( npc_event_isspecial(evt) )
567 {
568 ; // portable small/large monsters or other attributes
569 }
570 else
571 {
572 ShowWarning("NPC event parameter deprecated! Please use 'NPCNAME::OnEVENT' instead of '%s'.\n", evt);
573 script_reportsrc(st);
574 }
575 }
576}
577
578/*==========================================
579 * Hashes the input string
580 *------------------------------------------*/
581static unsigned int calc_hash(const char* p)
582{
583 unsigned int h;
584
585#if defined(SCRIPT_HASH_DJB2)
586 h = 5381;
587 while( *p ) // hash*33 + c
588 h = ( h << 5 ) + h + ((unsigned char)TOLOWER(*p++));
589#elif defined(SCRIPT_HASH_SDBM)
590 h = 0;
591 while( *p ) // hash*65599 + c
592 h = ( h << 6 ) + ( h << 16 ) - h + ((unsigned char)TOLOWER(*p++));
593#elif defined(SCRIPT_HASH_ELF) // UNIX ELF hash
594 h = 0;
595 while( *p ){
596 unsigned int g;
597 h = ( h << 4 ) + ((unsigned char)TOLOWER(*p++));
598 g = h & 0xF0000000;
599 if( g )
600 {
601 h ^= g >> 24;
602 h &= ~g;
603 }
604 }
605#else // athena hash
606 h = 0;
607 while( *p )
608 h = ( h << 1 ) + ( h >> 3 ) + ( h >> 5 ) + ( h >> 8 ) + (unsigned char)TOLOWER(*p++);
609#endif
610
611 return h % SCRIPT_HASH_SIZE;
612}
613
614
615/*==========================================
616 * str_data manipulation functions
617 *------------------------------------------*/
618
619/// Looks up string using the provided id.
620const char* get_str(int id)
621{
622 Assert( id >= LABEL_START && id < str_size );
623 return str_buf+str_data[id].str;
624}
625
626/// Returns the uid of the string, or -1.
627static int search_str(const char* p)
628{
629 int i;
630
631 for( i = str_hash[calc_hash(p)]; i != 0; i = str_data[i].next )
632 if( strcasecmp(get_str(i),p) == 0 )
633 return i;
634
635 return -1;
636}
637
638/// Stores a copy of the string and returns its id.
639/// If an identical string is already present, returns its id instead.
640int add_str(const char* p)
641{
642 int i, h;
643 int len;
644
645 h = calc_hash(p);
646
647 if( str_hash[h] == 0 )
648 {// empty bucket, add new node here
649 str_hash[h] = str_num;
650 }
651 else
652 {// scan for end of list, or occurence of identical string
653 for( i = str_hash[h]; ; i = str_data[i].next )
654 {
655 if( strcasecmp(get_str(i),p) == 0 )
656 return i; // string already in list
657 if( str_data[i].next == 0 )
658 break; // reached the end
659 }
660
661 // append node to end of list
662 str_data[i].next = str_num;
663 }
664
665 // grow list if neccessary
666 if( str_num >= str_data_size )
667 {
668 str_data_size += 128;
669 RECREATE(str_data,struct str_data_struct,str_data_size);
670 memset(str_data + (str_data_size - 128), '\0', 128);
671 }
672
673 len=(int)strlen(p);
674
675 // grow string buffer if neccessary
676 while( str_pos+len+1 >= str_size )
677 {
678 str_size += 256;
679 RECREATE(str_buf,char,str_size);
680 memset(str_buf + (str_size - 256), '\0', 256);
681 }
682
683 safestrncpy(str_buf+str_pos, p, len+1);
684 str_data[str_num].type = C_NOP;
685 str_data[str_num].str = str_pos;
686 str_data[str_num].next = 0;
687 str_data[str_num].func = NULL;
688 str_data[str_num].backpatch = -1;
689 str_data[str_num].label = -1;
690 str_pos += len+1;
691
692 return str_num++;
693}
694
695
696/// Appends 1 byte to the script buffer.
697static void add_scriptb(int a)
698{
699 if( script_pos+1 >= script_size )
700 {
701 script_size += SCRIPT_BLOCK_SIZE;
702 RECREATE(script_buf,unsigned char,script_size);
703 }
704 script_buf[script_pos++] = (uint8)(a);
705}
706
707/// Appends a c_op value to the script buffer.
708/// The value is variable-length encoded into 8-bit blocks.
709/// The encoding scheme is ( 01?????? )* 00??????, LSB first.
710/// All blocks but the last hold 7 bits of data, topmost bit is always 1 (carries).
711static void add_scriptc(int a)
712{
713 while( a >= 0x40 )
714 {
715 add_scriptb((a&0x3f)|0x40);
716 a = (a - 0x40) >> 6;
717 }
718
719 add_scriptb(a);
720}
721
722/// Appends an integer value to the script buffer.
723/// The value is variable-length encoded into 8-bit blocks.
724/// The encoding scheme is ( 11?????? )* 10??????, LSB first.
725/// All blocks but the last hold 7 bits of data, topmost bit is always 1 (carries).
726static void add_scripti(int a)
727{
728 while( a >= 0x40 )
729 {
730 add_scriptb((a&0x3f)|0xc0);
731 a = (a - 0x40) >> 6;
732 }
733 add_scriptb(a|0x80);
734}
735
736/// Appends a str_data object (label/function/variable/integer) to the script buffer.
737
738///
739/// @param l The id of the str_data entry
740// 最大16Mã¾ã§
741static void add_scriptl(int l)
742{
743 int backpatch = str_data[l].backpatch;
744
745 switch(str_data[l].type){
746 case C_POS:
747 case C_USERFUNC_POS:
748 add_scriptc(C_POS);
749 add_scriptb(str_data[l].label);
750 add_scriptb(str_data[l].label>>8);
751 add_scriptb(str_data[l].label>>16);
752 break;
753 case C_NOP:
754 case C_USERFUNC:
755 // ラベルã®å¯èƒ½æ€§ãŒã‚ã‚‹ã®ã§backpatch用データ埋ã‚è¾¼ã¿
756 add_scriptc(C_NAME);
757 str_data[l].backpatch = script_pos;
758 add_scriptb(backpatch);
759 add_scriptb(backpatch>>8);
760 add_scriptb(backpatch>>16);
761 break;
762 case C_INT:
763 add_scripti(abs(str_data[l].val));
764 if( str_data[l].val < 0 ) //Notice that this is negative, from jA (Rayce)
765 add_scriptc(C_NEG);
766 break;
767 default: // assume C_NAME
768 add_scriptc(C_NAME);
769 add_scriptb(l);
770 add_scriptb(l>>8);
771 add_scriptb(l>>16);
772 break;
773 }
774}
775
776/*==========================================
777 * ラベルを解決ã™ã‚‹
778 *------------------------------------------*/
779void set_label(int l,int pos, const char* script_pos)
780{
781 int i,next;
782
783 if(str_data[l].type==C_INT || str_data[l].type==C_PARAM || str_data[l].type==C_FUNC)
784 { //Prevent overwriting constants values, parameters and built-in functions [Skotlex]
785 disp_error_message("set_label: invalid label name",script_pos);
786 return;
787 }
788 if(str_data[l].label!=-1){
789 disp_error_message("set_label: dup label ",script_pos);
790 return;
791 }
792 str_data[l].type=(str_data[l].type == C_USERFUNC ? C_USERFUNC_POS : C_POS);
793 str_data[l].label=pos;
794 for(i=str_data[l].backpatch;i>=0 && i!=0x00ffffff;){
795 next=GETVALUE(script_buf,i);
796 script_buf[i-1]=(str_data[l].type == C_USERFUNC ? C_USERFUNC_POS : C_POS);
797 SETVALUE(script_buf,i,pos);
798 i=next;
799 }
800}
801
802/// Skips spaces and/or comments.
803const char* skip_space(const char* p)
804{
805 if( p == NULL )
806 return NULL;
807 for(;;)
808 {
809 while( ISSPACE(*p) )
810 ++p;
811 if( *p == '/' && p[1] == '/' )
812 {// line comment
813 while(*p && *p!='\n')
814 ++p;
815 }
816 else if( *p == '/' && p[1] == '*' )
817 {// block comment
818 p += 2;
819 for(;;)
820 {
821 if( *p == '\0' )
822 return p;//disp_error_message("script:skip_space: end of file while parsing block comment. expected "CL_BOLD"*/"CL_NORM, p);
823 if( *p == '*' && p[1] == '/' )
824 {// end of block comment
825 p += 2;
826 break;
827 }
828 ++p;
829 }
830 }
831 else
832 break;
833 }
834 return p;
835}
836
837/// Skips a word.
838/// A word consists of undercores and/or alfanumeric characters,
839/// and valid variable prefixes/postfixes.
840static
841const char* skip_word(const char* p)
842{
843 // prefix
844 switch( *p )
845 {
846 case '@':// temporary char variable
847 ++p; break;
848 case '#':// account variable
849 p += ( p[1] == '#' ? 2 : 1 ); break;
850 case '\'':// instance variable
851 ++p; break;
852 case '.':// npc variable
853 p += ( p[1] == '@' ? 2 : 1 ); break;
854 case '$':// global variable
855 p += ( p[1] == '@' ? 2 : 1 ); break;
856 }
857
858 while( ISALNUM(*p) || *p == '_' )
859 ++p;
860
861 // postfix
862 if( *p == '$' )// string
863 p++;
864
865 return p;
866}
867
868/// Adds a word to str_data.
869/// @see skip_word
870/// @see add_str
871static
872int add_word(const char* p)
873{
874 char* word;
875 int len;
876 int i;
877
878 // Check for a word
879 len = skip_word(p) - p;
880 if( len == 0 )
881 disp_error_message("script:add_word: invalid word. A word consists of undercores and/or alfanumeric characters, and valid variable prefixes/postfixes.", p);
882
883 // Duplicate the word
884 word = (char*)aMalloc(len+1);
885 memcpy(word, p, len);
886 word[len] = 0;
887
888 // add the word
889 i = add_str(word);
890 aFree(word);
891 return i;
892}
893
894/// Parses a function call.
895/// The argument list can have parenthesis or not.
896/// The number of arguments is checked.
897static
898const char* parse_callfunc(const char* p, int require_paren)
899{
900 const char* p2;
901 const char* arg=NULL;
902 int func;
903
904 func = add_word(p);
905 if( str_data[func].type == C_FUNC ){
906 // buildin function
907 add_scriptl(func);
908 add_scriptc(C_ARG);
909 arg = buildin_func[str_data[func].val].arg;
910 } else if( str_data[func].type == C_USERFUNC || str_data[func].type == C_USERFUNC_POS ){
911 // script defined function
912 int callsub = search_str("callsub");
913 add_scriptl(callsub);
914 add_scriptc(C_ARG);
915 add_scriptl(func);
916 arg = buildin_func[str_data[callsub].val].arg;
917 if( *arg == 0 )
918 disp_error_message("parse_callfunc: callsub has no arguments, please review it's definition",p);
919 if( *arg != '*' )
920 ++arg; // count func as argument
921 } else
922 disp_error_message("parse_line: expect command, missing function name or calling undeclared function",p);
923
924 p = skip_word(p);
925 p = skip_space(p);
926 syntax.curly[syntax.curly_count].type = TYPE_ARGLIST;
927 syntax.curly[syntax.curly_count].count = 0;
928 if( *p == ';' )
929 {// <func name> ';'
930 syntax.curly[syntax.curly_count].flag = ARGLIST_NO_PAREN;
931 } else if( *p == '(' && *(p2=skip_space(p+1)) == ')' )
932 {// <func name> '(' ')'
933 syntax.curly[syntax.curly_count].flag = ARGLIST_PAREN;
934 p = p2;
935 /*
936 } else if( 0 && require_paren && *p != '(' )
937 {// <func name>
938 syntax.curly[syntax.curly_count].flag = ARGLIST_NO_PAREN;
939 */
940 } else
941 {// <func name> <arg list>
942 if( require_paren ){
943 if( *p != '(' )
944 disp_error_message("need '('",p);
945 ++p; // skip '('
946 syntax.curly[syntax.curly_count].flag = ARGLIST_PAREN;
947 } else if( *p == '(' ){
948 syntax.curly[syntax.curly_count].flag = ARGLIST_UNDEFINED;
949 } else {
950 syntax.curly[syntax.curly_count].flag = ARGLIST_NO_PAREN;
951 }
952 ++syntax.curly_count;
953 while( *arg ) {
954 p2=parse_subexpr(p,-1);
955 if( p == p2 )
956 break; // not an argument
957 if( *arg != '*' )
958 ++arg; // next argument
959
960 p=skip_space(p2);
961 if( *arg == 0 || *p != ',' )
962 break; // no more arguments
963 ++p; // skip comma
964 }
965 --syntax.curly_count;
966 }
967 if( *arg && *arg != '?' && *arg != '*' )
968 disp_error_message2("parse_callfunc: not enough arguments, expected ','", p, script_config.warn_func_mismatch_paramnum);
969 if( syntax.curly[syntax.curly_count].type != TYPE_ARGLIST )
970 disp_error_message("parse_callfunc: DEBUG last curly is not an argument list",p);
971 if( syntax.curly[syntax.curly_count].flag == ARGLIST_PAREN ){
972 if( *p != ')' )
973 disp_error_message("parse_callfunc: expected ')' to close argument list",p);
974 ++p;
975 }
976 add_scriptc(C_FUNC);
977 return p;
978}
979
980/// Processes end of logical script line.
981/// @param first When true, only fix up scheduling data is initialized
982/// @param p Script position for error reporting in set_label
983static void parse_nextline(bool first, const char* p)
984{
985 if( !first )
986 {
987 add_scriptc(C_EOL); // mark end of line for stack cleanup
988 set_label(LABEL_NEXTLINE, script_pos, p); // fix up '-' labels
989 }
990
991 // initialize data for new '-' label fix up scheduling
992 str_data[LABEL_NEXTLINE].type = C_NOP;
993 str_data[LABEL_NEXTLINE].backpatch = -1;
994 str_data[LABEL_NEXTLINE].label = -1;
995}
996
997/*==========================================
998 * é …ã®è§£æž
999 *------------------------------------------*/
1000const char* parse_simpleexpr(const char *p)
1001{
1002 int i;
1003 p=skip_space(p);
1004
1005 if(*p==';' || *p==',')
1006 disp_error_message("parse_simpleexpr: unexpected expr end",p);
1007 if(*p=='('){
1008 if( (i=syntax.curly_count-1) >= 0 && syntax.curly[i].type == TYPE_ARGLIST )
1009 ++syntax.curly[i].count;
1010 p=parse_subexpr(p+1,-1);
1011 p=skip_space(p);
1012 if( (i=syntax.curly_count-1) >= 0 && syntax.curly[i].type == TYPE_ARGLIST &&
1013 syntax.curly[i].flag == ARGLIST_UNDEFINED && --syntax.curly[i].count == 0
1014 ){
1015 if( *p == ',' ){
1016 syntax.curly[i].flag = ARGLIST_PAREN;
1017 return p;
1018 } else
1019 syntax.curly[i].flag = ARGLIST_NO_PAREN;
1020 }
1021 if( *p != ')' )
1022 disp_error_message("parse_simpleexpr: unmatch ')'",p);
1023 ++p;
1024 } else if(ISDIGIT(*p) || ((*p=='-' || *p=='+') && ISDIGIT(p[1]))){
1025 char *np;
1026 i=strtoul(p,&np,0);
1027 add_scripti(i);
1028 p=np;
1029 } else if(*p=='"'){
1030 add_scriptc(C_STR);
1031 p++;
1032 while( *p && *p != '"' ){
1033 if( (unsigned char)p[-1] <= 0x7e && *p == '\\' )
1034 {
1035 char buf[8];
1036 size_t len = skip_escaped_c(p) - p;
1037 size_t n = sv_unescape_c(buf, p, len);
1038 if( n != 1 )
1039 ShowDebug("parse_simpleexpr: unexpected length %d after unescape (\"%.*s\" -> %.*s)\n", (int)n, (int)len, p, (int)n, buf);
1040 p += len;
1041 add_scriptb(*buf);
1042 continue;
1043 }
1044 else if( *p == '\n' )
1045 disp_error_message("parse_simpleexpr: unexpected newline @ string",p);
1046 add_scriptb(*p++);
1047 }
1048 if(!*p)
1049 disp_error_message("parse_simpleexpr: unexpected eof @ string",p);
1050 add_scriptb(0);
1051 p++; //'"'
1052 } else {
1053 int l;
1054 // label , register , function etc
1055 if(skip_word(p)==p)
1056 disp_error_message("parse_simpleexpr: unexpected character",p);
1057
1058 l=add_word(p);
1059 if( str_data[l].type == C_FUNC || str_data[l].type == C_USERFUNC || str_data[l].type == C_USERFUNC_POS)
1060 return parse_callfunc(p,1);
1061
1062 p=skip_word(p);
1063 if( *p == '[' ){
1064 // array(name[i] => getelementofarray(name,i) )
1065 add_scriptl(search_str("getelementofarray"));
1066 add_scriptc(C_ARG);
1067 add_scriptl(l);
1068
1069 p=parse_subexpr(p+1,-1);
1070 p=skip_space(p);
1071 if( *p != ']' )
1072 disp_error_message("parse_simpleexpr: unmatch ']'",p);
1073 ++p;
1074 add_scriptc(C_FUNC);
1075 }else
1076 add_scriptl(l);
1077
1078 }
1079
1080 return p;
1081}
1082
1083/*==========================================
1084 * å¼ã®è§£æž
1085 *------------------------------------------*/
1086const char* parse_subexpr(const char* p,int limit)
1087{
1088 int op,opl,len;
1089 const char* tmpp;
1090
1091 p=skip_space(p);
1092
1093 if(*p=='-'){
1094 tmpp=skip_space(p+1);
1095 if(*tmpp==';' || *tmpp==','){
1096 add_scriptl(LABEL_NEXTLINE);
1097 p++;
1098 return p;
1099 }
1100 }
1101 tmpp=p;
1102 if((op=C_NEG,*p=='-') || (op=C_LNOT,*p=='!') || (op=C_NOT,*p=='~')){
1103 p=parse_subexpr(p+1,10);
1104 add_scriptc(op);
1105 } else
1106 p=parse_simpleexpr(p);
1107 p=skip_space(p);
1108 while((
1109 (op=C_OP3,opl=0,len=1,*p=='?') ||
1110 (op=C_ADD,opl=8,len=1,*p=='+') ||
1111 (op=C_SUB,opl=8,len=1,*p=='-') ||
1112 (op=C_MUL,opl=9,len=1,*p=='*') ||
1113 (op=C_DIV,opl=9,len=1,*p=='/') ||
1114 (op=C_MOD,opl=9,len=1,*p=='%') ||
1115 (op=C_LAND,opl=2,len=2,*p=='&' && p[1]=='&') ||
1116 (op=C_AND,opl=6,len=1,*p=='&') ||
1117 (op=C_LOR,opl=1,len=2,*p=='|' && p[1]=='|') ||
1118 (op=C_OR,opl=5,len=1,*p=='|') ||
1119 (op=C_XOR,opl=4,len=1,*p=='^') ||
1120 (op=C_EQ,opl=3,len=2,*p=='=' && p[1]=='=') ||
1121 (op=C_NE,opl=3,len=2,*p=='!' && p[1]=='=') ||
1122 (op=C_R_SHIFT,opl=7,len=2,*p=='>' && p[1]=='>') ||
1123 (op=C_GE,opl=3,len=2,*p=='>' && p[1]=='=') ||
1124 (op=C_GT,opl=3,len=1,*p=='>') ||
1125 (op=C_L_SHIFT,opl=7,len=2,*p=='<' && p[1]=='<') ||
1126 (op=C_LE,opl=3,len=2,*p=='<' && p[1]=='=') ||
1127 (op=C_LT,opl=3,len=1,*p=='<')) && opl>limit){
1128 p+=len;
1129 if(op == C_OP3) {
1130 p=parse_subexpr(p,-1);
1131 p=skip_space(p);
1132 if( *(p++) != ':')
1133 disp_error_message("parse_subexpr: need ':'", p-1);
1134 p=parse_subexpr(p,-1);
1135 } else {
1136 p=parse_subexpr(p,opl);
1137 }
1138 add_scriptc(op);
1139 p=skip_space(p);
1140 }
1141
1142 return p; /* return first untreated operator */
1143}
1144
1145/*==========================================
1146 * å¼ã®è©•価
1147 *------------------------------------------*/
1148const char* parse_expr(const char *p)
1149{
1150 switch(*p){
1151 case ')': case ';': case ':': case '[': case ']':
1152 case '}':
1153 disp_error_message("parse_expr: unexpected char",p);
1154 }
1155 p=parse_subexpr(p,-1);
1156 return p;
1157}
1158
1159/*==========================================
1160 * 行ã®è§£æž
1161 *------------------------------------------*/
1162const char* parse_line(const char* p)
1163{
1164 const char* p2;
1165
1166 p=skip_space(p);
1167 if(*p==';') {
1168 // if(); for(); while(); ã®ãŸã‚ã«é–‰ã˜åˆ¤å®š
1169 p = parse_syntax_close(p + 1);
1170 return p;
1171 }
1172 if(*p==')' && parse_syntax_for_flag)
1173 return p+1;
1174
1175 p = skip_space(p);
1176 if(p[0] == '{') {
1177 syntax.curly[syntax.curly_count].type = TYPE_NULL;
1178 syntax.curly[syntax.curly_count].count = -1;
1179 syntax.curly[syntax.curly_count].index = -1;
1180 syntax.curly_count++;
1181 return p + 1;
1182 } else if(p[0] == '}') {
1183 return parse_curly_close(p);
1184 }
1185
1186 // 構文関連ã®å‡¦ç†
1187 p2 = parse_syntax(p);
1188 if(p2 != NULL)
1189 return p2;
1190
1191 p = parse_callfunc(p,0);
1192 p = skip_space(p);
1193
1194 if(parse_syntax_for_flag) {
1195 if( *p != ')' )
1196 disp_error_message("parse_line: need ')'",p);
1197 } else {
1198 if( *p != ';' )
1199 disp_error_message("parse_line: need ';'",p);
1200 }
1201
1202 // if, for , while ã®é–‰ã˜åˆ¤å®š
1203 p = parse_syntax_close(p+1);
1204
1205 return p;
1206}
1207
1208// { ... } ã®é–‰ã˜å‡¦ç†
1209const char* parse_curly_close(const char* p)
1210{
1211 if(syntax.curly_count <= 0) {
1212 disp_error_message("parse_curly_close: unexpected string",p);
1213 return p + 1;
1214 } else if(syntax.curly[syntax.curly_count-1].type == TYPE_NULL) {
1215 syntax.curly_count--;
1216 // if, for , while ã®é–‰ã˜åˆ¤å®š
1217 p = parse_syntax_close(p + 1);
1218 return p;
1219 } else if(syntax.curly[syntax.curly_count-1].type == TYPE_SWITCH) {
1220 // switch() é–‰ã˜åˆ¤å®š
1221 int pos = syntax.curly_count-1;
1222 char label[256];
1223 int l;
1224 // 一時変数を消ã™
1225 sprintf(label,"set $@__SW%x_VAL,0;",syntax.curly[pos].index);
1226 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1227 parse_line(label);
1228 syntax.curly_count--;
1229
1230 // ç„¡æ¡ä»¶ã§çµ‚了ãƒã‚¤ãƒ³ã‚¿ã«ç§»å‹•
1231 sprintf(label,"goto __SW%x_FIN;",syntax.curly[pos].index);
1232 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1233 parse_line(label);
1234 syntax.curly_count--;
1235
1236 // ç¾åœ¨åœ°ã®ãƒ©ãƒ™ãƒ«ã‚’付ã‘ã‚‹
1237 sprintf(label,"__SW%x_%x",syntax.curly[pos].index,syntax.curly[pos].count);
1238 l=add_str(label);
1239 set_label(l,script_pos, p);
1240
1241 if(syntax.curly[pos].flag) {
1242 // default ãŒå˜åœ¨ã™ã‚‹
1243 sprintf(label,"goto __SW%x_DEF;",syntax.curly[pos].index);
1244 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1245 parse_line(label);
1246 syntax.curly_count--;
1247 }
1248
1249 // 終了ラベルを付ã‘ã‚‹
1250 sprintf(label,"__SW%x_FIN",syntax.curly[pos].index);
1251 l=add_str(label);
1252 set_label(l,script_pos, p);
1253 linkdb_final(&syntax.curly[pos].case_label); // free the list of case label
1254 syntax.curly_count--;
1255 // if, for , while ã®é–‰ã˜åˆ¤å®š
1256 p = parse_syntax_close(p + 1);
1257 return p;
1258 } else {
1259 disp_error_message("parse_curly_close: unexpected string",p);
1260 return p + 1;
1261 }
1262}
1263
1264// 構文関連ã®å‡¦ç†
1265// break, case, continue, default, do, for, function,
1266// if, switch, while ã‚’ã“ã®å†…部ã§å‡¦ç†ã—ã¾ã™ã€‚
1267const char* parse_syntax(const char* p)
1268{
1269 const char *p2 = skip_word(p);
1270
1271 switch(*p) {
1272 case 'B':
1273 case 'b':
1274 if(p2 - p == 5 && !strncasecmp(p,"break",5)) {
1275 // break ã®å‡¦ç†
1276 char label[256];
1277 int pos = syntax.curly_count - 1;
1278 while(pos >= 0) {
1279 if(syntax.curly[pos].type == TYPE_DO) {
1280 sprintf(label,"goto __DO%x_FIN;",syntax.curly[pos].index);
1281 break;
1282 } else if(syntax.curly[pos].type == TYPE_FOR) {
1283 sprintf(label,"goto __FR%x_FIN;",syntax.curly[pos].index);
1284 break;
1285 } else if(syntax.curly[pos].type == TYPE_WHILE) {
1286 sprintf(label,"goto __WL%x_FIN;",syntax.curly[pos].index);
1287 break;
1288 } else if(syntax.curly[pos].type == TYPE_SWITCH) {
1289 sprintf(label,"goto __SW%x_FIN;",syntax.curly[pos].index);
1290 break;
1291 }
1292 pos--;
1293 }
1294 if(pos < 0) {
1295 disp_error_message("parse_syntax: unexpected 'break'",p);
1296 } else {
1297 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1298 parse_line(label);
1299 syntax.curly_count--;
1300 }
1301 p = skip_space(p2);
1302 if(*p != ';')
1303 disp_error_message("parse_syntax: need ';'",p);
1304 // if, for , while ã®é–‰ã˜åˆ¤å®š
1305 p = parse_syntax_close(p + 1);
1306 return p;
1307 }
1308 break;
1309 case 'c':
1310 case 'C':
1311 if(p2 - p == 4 && !strncasecmp(p,"case",4)) {
1312 // case ã®å‡¦ç†
1313 int pos = syntax.curly_count-1;
1314 if(pos < 0 || syntax.curly[pos].type != TYPE_SWITCH) {
1315 disp_error_message("parse_syntax: unexpected 'case' ",p);
1316 return p+1;
1317 } else {
1318 char label[256];
1319 int l,v;
1320 char *np;
1321 if(syntax.curly[pos].count != 1) {
1322 // FALLTHRU 用ã®ã‚¸ãƒ£ãƒ³ãƒ—
1323 sprintf(label,"goto __SW%x_%xJ;",syntax.curly[pos].index,syntax.curly[pos].count);
1324 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1325 parse_line(label);
1326 syntax.curly_count--;
1327
1328 // ç¾åœ¨åœ°ã®ãƒ©ãƒ™ãƒ«ã‚’付ã‘ã‚‹
1329 sprintf(label,"__SW%x_%x",syntax.curly[pos].index,syntax.curly[pos].count);
1330 l=add_str(label);
1331 set_label(l,script_pos, p);
1332 }
1333 // switch 判定文
1334 p = skip_space(p2);
1335 if(p == p2) {
1336 disp_error_message("parse_syntax: expect space ' '",p);
1337 }
1338 // check whether case label is integer or not
1339 v = strtol(p,&np,0);
1340 if(np == p) { //Check for constants
1341 p2 = skip_word(p);
1342 v = p2-p; // length of word at p2
1343 memcpy(label,p,v);
1344 label[v]='\0';
1345 if( !script_get_constant(label, &v) )
1346 disp_error_message("parse_syntax: 'case' label not integer",p);
1347 p = skip_word(p);
1348 } else { //Numeric value
1349 if((*p == '-' || *p == '+') && ISDIGIT(p[1])) // pre-skip because '-' can not skip_word
1350 p++;
1351 p = skip_word(p);
1352 if(np != p)
1353 disp_error_message("parse_syntax: 'case' label not integer",np);
1354 }
1355 p = skip_space(p);
1356 if(*p != ':')
1357 disp_error_message("parse_syntax: expect ':'",p);
1358 sprintf(label,"if(%d != $@__SW%x_VAL) goto __SW%x_%x;",
1359 v,syntax.curly[pos].index,syntax.curly[pos].index,syntax.curly[pos].count+1);
1360 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1361 // 2回parse ã—ãªã„ã¨ãƒ€ãƒ¡
1362 p2 = parse_line(label);
1363 parse_line(p2);
1364 syntax.curly_count--;
1365 if(syntax.curly[pos].count != 1) {
1366 // FALLTHRU 終了後ã®ãƒ©ãƒ™ãƒ«
1367 sprintf(label,"__SW%x_%xJ",syntax.curly[pos].index,syntax.curly[pos].count);
1368 l=add_str(label);
1369 set_label(l,script_pos,p);
1370 }
1371 // check duplication of case label [Rayce]
1372 if(linkdb_search(&syntax.curly[pos].case_label, (void*)v) != NULL)
1373 disp_error_message("parse_syntax: dup 'case'",p);
1374 linkdb_insert(&syntax.curly[pos].case_label, (void*)v, (void*)1);
1375
1376 sprintf(label,"set $@__SW%x_VAL,0;",syntax.curly[pos].index);
1377 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1378
1379 parse_line(label);
1380 syntax.curly_count--;
1381 syntax.curly[pos].count++;
1382 }
1383 return p + 1;
1384 } else if(p2 - p == 8 && !strncasecmp(p,"continue",8)) {
1385 // continue ã®å‡¦ç†
1386 char label[256];
1387 int pos = syntax.curly_count - 1;
1388 while(pos >= 0) {
1389 if(syntax.curly[pos].type == TYPE_DO) {
1390 sprintf(label,"goto __DO%x_NXT;",syntax.curly[pos].index);
1391 syntax.curly[pos].flag = 1; // continue 用ã®ãƒªãƒ³ã‚¯å¼µã‚‹ãƒ•ラグ
1392 break;
1393 } else if(syntax.curly[pos].type == TYPE_FOR) {
1394 sprintf(label,"goto __FR%x_NXT;",syntax.curly[pos].index);
1395 break;
1396 } else if(syntax.curly[pos].type == TYPE_WHILE) {
1397 sprintf(label,"goto __WL%x_NXT;",syntax.curly[pos].index);
1398 break;
1399 }
1400 pos--;
1401 }
1402 if(pos < 0) {
1403 disp_error_message("parse_syntax: unexpected 'continue'",p);
1404 } else {
1405 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1406 parse_line(label);
1407 syntax.curly_count--;
1408 }
1409 p = skip_space(p2);
1410 if(*p != ';')
1411 disp_error_message("parse_syntax: need ';'",p);
1412 // if, for , while ã®é–‰ã˜åˆ¤å®š
1413 p = parse_syntax_close(p + 1);
1414 return p;
1415 }
1416 break;
1417 case 'd':
1418 case 'D':
1419 if(p2 - p == 7 && !strncasecmp(p,"default",7)) {
1420 // switch - default ã®å‡¦ç†
1421 int pos = syntax.curly_count-1;
1422 if(pos < 0 || syntax.curly[pos].type != TYPE_SWITCH) {
1423 disp_error_message("parse_syntax: unexpected 'default'",p);
1424 } else if(syntax.curly[pos].flag) {
1425 disp_error_message("parse_syntax: dup 'default'",p);
1426 } else {
1427 char label[256];
1428 int l;
1429 // ç¾åœ¨åœ°ã®ãƒ©ãƒ™ãƒ«ã‚’付ã‘ã‚‹
1430 p = skip_space(p2);
1431 if(*p != ':') {
1432 disp_error_message("parse_syntax: need ':'",p);
1433 }
1434 sprintf(label,"__SW%x_%x",syntax.curly[pos].index,syntax.curly[pos].count);
1435 l=add_str(label);
1436 set_label(l,script_pos,p);
1437
1438 // ç„¡æ¡ä»¶ã§æ¬¡ã®ãƒªãƒ³ã‚¯ã«é£›ã°ã™
1439 sprintf(label,"goto __SW%x_%x;",syntax.curly[pos].index,syntax.curly[pos].count+1);
1440 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1441 parse_line(label);
1442 syntax.curly_count--;
1443
1444 // default ã®ãƒ©ãƒ™ãƒ«ã‚’付ã‘ã‚‹
1445 sprintf(label,"__SW%x_DEF",syntax.curly[pos].index);
1446 l=add_str(label);
1447 set_label(l,script_pos,p);
1448
1449 syntax.curly[syntax.curly_count - 1].flag = 1;
1450 syntax.curly[pos].count++;
1451 }
1452 return p + 1;
1453 } else if(p2 - p == 2 && !strncasecmp(p,"do",2)) {
1454 int l;
1455 char label[256];
1456 p=skip_space(p2);
1457
1458 syntax.curly[syntax.curly_count].type = TYPE_DO;
1459 syntax.curly[syntax.curly_count].count = 1;
1460 syntax.curly[syntax.curly_count].index = syntax.index++;
1461 syntax.curly[syntax.curly_count].flag = 0;
1462 // ç¾åœ¨åœ°ã®ãƒ©ãƒ™ãƒ«å½¢æˆã™ã‚‹
1463 sprintf(label,"__DO%x_BGN",syntax.curly[syntax.curly_count].index);
1464 l=add_str(label);
1465 set_label(l,script_pos,p);
1466 syntax.curly_count++;
1467 return p;
1468 }
1469 break;
1470 case 'f':
1471 case 'F':
1472 if(p2 - p == 3 && !strncasecmp(p,"for",3)) {
1473 int l;
1474 char label[256];
1475 int pos = syntax.curly_count;
1476 syntax.curly[syntax.curly_count].type = TYPE_FOR;
1477 syntax.curly[syntax.curly_count].count = 1;
1478 syntax.curly[syntax.curly_count].index = syntax.index++;
1479 syntax.curly[syntax.curly_count].flag = 0;
1480 syntax.curly_count++;
1481
1482 p=skip_space(p2);
1483
1484 if(*p != '(')
1485 disp_error_message("parse_syntax: need '('",p);
1486 p++;
1487
1488 // åˆæœŸåŒ–文を実行ã™ã‚‹
1489 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1490 p=parse_line(p);
1491 syntax.curly_count--;
1492
1493 // æ¡ä»¶åˆ¤æ–é–‹å§‹ã®ãƒ©ãƒ™ãƒ«å½¢æˆã™ã‚‹
1494 sprintf(label,"__FR%x_J",syntax.curly[pos].index);
1495 l=add_str(label);
1496 set_label(l,script_pos,p);
1497
1498 p=skip_space(p);
1499 if(*p == ';') {
1500 // for(;;) ã®ãƒ‘ターンãªã®ã§å¿…ãšçœŸ
1501 ;
1502 } else {
1503 // æ¡ä»¶ãŒå½ãªã‚‰çµ‚了地点ã«é£›ã°ã™
1504 sprintf(label,"__FR%x_FIN",syntax.curly[pos].index);
1505 add_scriptl(add_str("jump_zero"));
1506 add_scriptc(C_ARG);
1507 p=parse_expr(p);
1508 p=skip_space(p);
1509 add_scriptl(add_str(label));
1510 add_scriptc(C_FUNC);
1511 }
1512 if(*p != ';')
1513 disp_error_message("parse_syntax: need ';'",p);
1514 p++;
1515
1516 // ループ開始ã«é£›ã°ã™
1517 sprintf(label,"goto __FR%x_BGN;",syntax.curly[pos].index);
1518 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1519 parse_line(label);
1520 syntax.curly_count--;
1521
1522 // 次ã®ãƒ«ãƒ¼ãƒ—ã¸ã®ãƒ©ãƒ™ãƒ«å½¢æˆã™ã‚‹
1523 sprintf(label,"__FR%x_NXT",syntax.curly[pos].index);
1524 l=add_str(label);
1525 set_label(l,script_pos,p);
1526
1527 // 次ã®ãƒ«ãƒ¼ãƒ—ã«å…¥ã‚‹æ™‚ã®å‡¦ç†
1528 // for 最後㮠')' ã‚’ ';' ã¨ã—ã¦æ‰±ã†ãƒ•ラグ
1529 parse_syntax_for_flag = 1;
1530 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1531 p=parse_line(p);
1532 syntax.curly_count--;
1533 parse_syntax_for_flag = 0;
1534
1535 // æ¡ä»¶åˆ¤å®šå‡¦ç†ã«é£›ã°ã™
1536 sprintf(label,"goto __FR%x_J;",syntax.curly[pos].index);
1537 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1538 parse_line(label);
1539 syntax.curly_count--;
1540
1541 // ループ開始ã®ãƒ©ãƒ™ãƒ«ä»˜ã‘
1542 sprintf(label,"__FR%x_BGN",syntax.curly[pos].index);
1543 l=add_str(label);
1544 set_label(l,script_pos,p);
1545 return p;
1546 }
1547 else if( p2 - p == 8 && strncasecmp(p,"function",8) == 0 )
1548 {// internal script function
1549 const char *func_name;
1550
1551 func_name = skip_space(p2);
1552 p = skip_word(func_name);
1553 if( p == func_name )
1554 disp_error_message("parse_syntax:function: function name is missing or invalid", p);
1555 p2 = skip_space(p);
1556 if( *p2 == ';' )
1557 {// function <name> ;
1558 // function declaration - just register the name
1559 int l;
1560 l = add_word(func_name);
1561 if( str_data[l].type == C_NOP )// register only, if the name was not used by something else
1562 str_data[l].type = C_USERFUNC;
1563 else if( str_data[l].type == C_USERFUNC )
1564 ; // already registered
1565 else
1566 disp_error_message("parse_syntax:function: function name is invalid", func_name);
1567
1568 // if, for , while ã®é–‰ã˜åˆ¤å®š
1569 p = parse_syntax_close(p2 + 1);
1570 return p;
1571 }
1572 else if(*p2 == '{')
1573 {// function <name> <line/block of code>
1574 char label[256];
1575 int l;
1576
1577 syntax.curly[syntax.curly_count].type = TYPE_USERFUNC;
1578 syntax.curly[syntax.curly_count].count = 1;
1579 syntax.curly[syntax.curly_count].index = syntax.index++;
1580 syntax.curly[syntax.curly_count].flag = 0;
1581 ++syntax.curly_count;
1582
1583 // Jump over the function code
1584 sprintf(label, "goto __FN%x_FIN;", syntax.curly[syntax.curly_count-1].index);
1585 syntax.curly[syntax.curly_count].type = TYPE_NULL;
1586 ++syntax.curly_count;
1587 parse_line(label);
1588 --syntax.curly_count;
1589
1590 // Set the position of the function (label)
1591 l=add_word(func_name);
1592 if( str_data[l].type == C_NOP || str_data[l].type == C_USERFUNC )// register only, if the name was not used by something else
1593 {
1594 str_data[l].type = C_USERFUNC;
1595 set_label(l, script_pos, p);
1596 if( parse_options&SCRIPT_USE_LABEL_DB )
1597 strdb_put(scriptlabel_db, get_str(l), (void*)script_pos);
1598 }
1599 else
1600 disp_error_message("parse_syntax:function: function name is invalid", func_name);
1601
1602 return skip_space(p);
1603 }
1604 else
1605 {
1606 disp_error_message("expect ';' or '{' at function syntax",p);
1607 }
1608 }
1609 break;
1610 case 'i':
1611 case 'I':
1612 if(p2 - p == 2 && !strncasecmp(p,"if",2)) {
1613 // if() ã®å‡¦ç†
1614 char label[256];
1615 p=skip_space(p2);
1616 if(*p != '(') { //Prevent if this {} non-c syntax. from Rayce (jA)
1617 disp_error_message("need '('",p);
1618 }
1619 syntax.curly[syntax.curly_count].type = TYPE_IF;
1620 syntax.curly[syntax.curly_count].count = 1;
1621 syntax.curly[syntax.curly_count].index = syntax.index++;
1622 syntax.curly[syntax.curly_count].flag = 0;
1623 sprintf(label,"__IF%x_%x",syntax.curly[syntax.curly_count].index,syntax.curly[syntax.curly_count].count);
1624 syntax.curly_count++;
1625 add_scriptl(add_str("jump_zero"));
1626 add_scriptc(C_ARG);
1627 p=parse_expr(p);
1628 p=skip_space(p);
1629 add_scriptl(add_str(label));
1630 add_scriptc(C_FUNC);
1631 return p;
1632 }
1633 break;
1634 case 's':
1635 case 'S':
1636 if(p2 - p == 6 && !strncasecmp(p,"switch",6)) {
1637 // switch() ã®å‡¦ç†
1638 char label[256];
1639 p=skip_space(p2);
1640 if(*p != '(') {
1641 disp_error_message("need '('",p);
1642 }
1643 syntax.curly[syntax.curly_count].type = TYPE_SWITCH;
1644 syntax.curly[syntax.curly_count].count = 1;
1645 syntax.curly[syntax.curly_count].index = syntax.index++;
1646 syntax.curly[syntax.curly_count].flag = 0;
1647 sprintf(label,"$@__SW%x_VAL",syntax.curly[syntax.curly_count].index);
1648 syntax.curly_count++;
1649 add_scriptl(add_str("set"));
1650 add_scriptc(C_ARG);
1651 add_scriptl(add_str(label));
1652 p=parse_expr(p);
1653 p=skip_space(p);
1654 if(*p != '{') {
1655 disp_error_message("parse_syntax: need '{'",p);
1656 }
1657 add_scriptc(C_FUNC);
1658 return p + 1;
1659 }
1660 break;
1661 case 'w':
1662 case 'W':
1663 if(p2 - p == 5 && !strncasecmp(p,"while",5)) {
1664 int l;
1665 char label[256];
1666 p=skip_space(p2);
1667 if(*p != '(') {
1668 disp_error_message("need '('",p);
1669 }
1670 syntax.curly[syntax.curly_count].type = TYPE_WHILE;
1671 syntax.curly[syntax.curly_count].count = 1;
1672 syntax.curly[syntax.curly_count].index = syntax.index++;
1673 syntax.curly[syntax.curly_count].flag = 0;
1674 // æ¡ä»¶åˆ¤æ–é–‹å§‹ã®ãƒ©ãƒ™ãƒ«å½¢æˆã™ã‚‹
1675 sprintf(label,"__WL%x_NXT",syntax.curly[syntax.curly_count].index);
1676 l=add_str(label);
1677 set_label(l,script_pos,p);
1678
1679 // æ¡ä»¶ãŒå½ãªã‚‰çµ‚了地点ã«é£›ã°ã™
1680 sprintf(label,"__WL%x_FIN",syntax.curly[syntax.curly_count].index);
1681 syntax.curly_count++;
1682 add_scriptl(add_str("jump_zero"));
1683 add_scriptc(C_ARG);
1684 p=parse_expr(p);
1685 p=skip_space(p);
1686 add_scriptl(add_str(label));
1687 add_scriptc(C_FUNC);
1688 return p;
1689 }
1690 break;
1691 }
1692 return NULL;
1693}
1694
1695const char* parse_syntax_close(const char *p) {
1696 // if(...) for(...) hoge(); ã®ã‚ˆã†ã«ã€ï¼‘度閉ã˜ã‚‰ã‚ŒãŸã‚‰å†åº¦é–‰ã˜ã‚‰ã‚Œã‚‹ã‹ç¢ºèªã™ã‚‹
1697 int flag;
1698
1699 do {
1700 p = parse_syntax_close_sub(p,&flag);
1701 } while(flag);
1702 return p;
1703}
1704
1705// if, for , while , do ã®é–‰ã˜åˆ¤å®š
1706// flag == 1 : é–‰ã˜ã‚‰ã‚ŒãŸ
1707// flag == 0 : é–‰ã˜ã‚‰ã‚Œãªã„
1708const char* parse_syntax_close_sub(const char* p,int* flag)
1709{
1710 char label[256];
1711 int pos = syntax.curly_count - 1;
1712 int l;
1713 *flag = 1;
1714
1715 if(syntax.curly_count <= 0) {
1716 *flag = 0;
1717 return p;
1718 } else if(syntax.curly[pos].type == TYPE_IF) {
1719 const char *bp = p;
1720 const char *p2;
1721
1722 // if-block and else-block end is a new line
1723 parse_nextline(false, p);
1724
1725 // if æœ€çµ‚å ´æ‰€ã¸é£›ã°ã™
1726 sprintf(label,"goto __IF%x_FIN;",syntax.curly[pos].index);
1727 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1728 parse_line(label);
1729 syntax.curly_count--;
1730
1731 // ç¾åœ¨åœ°ã®ãƒ©ãƒ™ãƒ«ã‚’付ã‘ã‚‹
1732 sprintf(label,"__IF%x_%x",syntax.curly[pos].index,syntax.curly[pos].count);
1733 l=add_str(label);
1734 set_label(l,script_pos,p);
1735
1736 syntax.curly[pos].count++;
1737 p = skip_space(p);
1738 p2 = skip_word(p);
1739 if(!syntax.curly[pos].flag && p2 - p == 4 && !strncasecmp(p,"else",4)) {
1740 // else or else - if
1741 p = skip_space(p2);
1742 p2 = skip_word(p);
1743 if(p2 - p == 2 && !strncasecmp(p,"if",2)) {
1744 // else - if
1745 p=skip_space(p2);
1746 if(*p != '(') {
1747 disp_error_message("need '('",p);
1748 }
1749 sprintf(label,"__IF%x_%x",syntax.curly[pos].index,syntax.curly[pos].count);
1750 add_scriptl(add_str("jump_zero"));
1751 add_scriptc(C_ARG);
1752 p=parse_expr(p);
1753 p=skip_space(p);
1754 add_scriptl(add_str(label));
1755 add_scriptc(C_FUNC);
1756 *flag = 0;
1757 return p;
1758 } else {
1759 // else
1760 if(!syntax.curly[pos].flag) {
1761 syntax.curly[pos].flag = 1;
1762 *flag = 0;
1763 return p;
1764 }
1765 }
1766 }
1767 // if é–‰ã˜
1768 syntax.curly_count--;
1769 // 最終地ã®ãƒ©ãƒ™ãƒ«ã‚’付ã‘ã‚‹
1770 sprintf(label,"__IF%x_FIN",syntax.curly[pos].index);
1771 l=add_str(label);
1772 set_label(l,script_pos,p);
1773 if(syntax.curly[pos].flag == 1) {
1774 // ã“ã®ifã«å¯¾ã™ã‚‹elseã˜ã‚ƒãªã„ã®ã§ãƒã‚¤ãƒ³ã‚¿ã®ä½ç½®ã¯åŒã˜
1775 return bp;
1776 }
1777 return p;
1778 } else if(syntax.curly[pos].type == TYPE_DO) {
1779 int l;
1780 char label[256];
1781 const char *p2;
1782
1783 if(syntax.curly[pos].flag) {
1784 // ç¾åœ¨åœ°ã®ãƒ©ãƒ™ãƒ«å½¢æˆã™ã‚‹(continue ã§ã“ã“ã«æ¥ã‚‹)
1785 sprintf(label,"__DO%x_NXT",syntax.curly[pos].index);
1786 l=add_str(label);
1787 set_label(l,script_pos,p);
1788 }
1789
1790 // æ¡ä»¶ãŒå½ãªã‚‰çµ‚了地点ã«é£›ã°ã™
1791 p = skip_space(p);
1792 p2 = skip_word(p);
1793 if(p2 - p != 5 || strncasecmp(p,"while",5))
1794 disp_error_message("parse_syntax: need 'while'",p);
1795
1796 p = skip_space(p2);
1797 if(*p != '(') {
1798 disp_error_message("need '('",p);
1799 }
1800
1801 // do-block end is a new line
1802 parse_nextline(false, p);
1803
1804 sprintf(label,"__DO%x_FIN",syntax.curly[pos].index);
1805 add_scriptl(add_str("jump_zero"));
1806 add_scriptc(C_ARG);
1807 p=parse_expr(p);
1808 p=skip_space(p);
1809 add_scriptl(add_str(label));
1810 add_scriptc(C_FUNC);
1811
1812 // 開始地点ã«é£›ã°ã™
1813 sprintf(label,"goto __DO%x_BGN;",syntax.curly[pos].index);
1814 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1815 parse_line(label);
1816 syntax.curly_count--;
1817
1818 // æ¡ä»¶çµ‚了地点ã®ãƒ©ãƒ™ãƒ«å½¢æˆã™ã‚‹
1819 sprintf(label,"__DO%x_FIN",syntax.curly[pos].index);
1820 l=add_str(label);
1821 set_label(l,script_pos,p);
1822 p = skip_space(p);
1823 if(*p != ';') {
1824 disp_error_message("parse_syntax: need ';'",p);
1825 return p+1;
1826 }
1827 p++;
1828 syntax.curly_count--;
1829 return p;
1830 } else if(syntax.curly[pos].type == TYPE_FOR) {
1831 // for-block end is a new line
1832 parse_nextline(false, p);
1833
1834 // 次ã®ãƒ«ãƒ¼ãƒ—ã«é£›ã°ã™
1835 sprintf(label,"goto __FR%x_NXT;",syntax.curly[pos].index);
1836 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1837 parse_line(label);
1838 syntax.curly_count--;
1839
1840 // for 終了ã®ãƒ©ãƒ™ãƒ«ä»˜ã‘
1841 sprintf(label,"__FR%x_FIN",syntax.curly[pos].index);
1842 l=add_str(label);
1843 set_label(l,script_pos,p);
1844 syntax.curly_count--;
1845 return p;
1846 } else if(syntax.curly[pos].type == TYPE_WHILE) {
1847 // while-block end is a new line
1848 parse_nextline(false, p);
1849
1850 // while æ¡ä»¶åˆ¤æ–ã¸é£›ã°ã™
1851 sprintf(label,"goto __WL%x_NXT;",syntax.curly[pos].index);
1852 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1853 parse_line(label);
1854 syntax.curly_count--;
1855
1856 // while 終了ã®ãƒ©ãƒ™ãƒ«ä»˜ã‘
1857 sprintf(label,"__WL%x_FIN",syntax.curly[pos].index);
1858 l=add_str(label);
1859 set_label(l,script_pos,p);
1860 syntax.curly_count--;
1861 return p;
1862 } else if(syntax.curly[syntax.curly_count-1].type == TYPE_USERFUNC) {
1863 int pos = syntax.curly_count-1;
1864 char label[256];
1865 int l;
1866 // 戻ã™
1867 sprintf(label,"return;");
1868 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1869 parse_line(label);
1870 syntax.curly_count--;
1871
1872 // ç¾åœ¨åœ°ã®ãƒ©ãƒ™ãƒ«ã‚’付ã‘ã‚‹
1873 sprintf(label,"__FN%x_FIN",syntax.curly[pos].index);
1874 l=add_str(label);
1875 set_label(l,script_pos,p);
1876 syntax.curly_count--;
1877 return p;
1878 } else {
1879 *flag = 0;
1880 return p;
1881 }
1882}
1883
1884/*==========================================
1885 * 組ã¿è¾¼ã¿é–¢æ•°ã®è¿½åŠ
1886 *------------------------------------------*/
1887static void add_buildin_func(void)
1888{
1889 int i,n;
1890 const char* p;
1891 for( i = 0; buildin_func[i].func; i++ )
1892 {
1893 // arg must follow the pattern: (v|s|i|r|l)*\?*\*?
1894 // 'v' - value (either string or int or reference)
1895 // 's' - string
1896 // 'i' - int
1897 // 'r' - reference (of a variable)
1898 // 'l' - label
1899 // '?' - one optional parameter
1900 // '*' - unknown number of optional parameters
1901 p = buildin_func[i].arg;
1902 while( *p == 'v' || *p == 's' || *p == 'i' || *p == 'r' || *p == 'l' ) ++p;
1903 while( *p == '?' ) ++p;
1904 if( *p == '*' ) ++p;
1905 if( *p != 0){
1906 ShowWarning("add_buildin_func: ignoring function \"%s\" with invalid arg \"%s\".\n", buildin_func[i].name, buildin_func[i].arg);
1907 } else if( *skip_word(buildin_func[i].name) != 0 ){
1908 ShowWarning("add_buildin_func: ignoring function with invalid name \"%s\" (must be a word).\n", buildin_func[i].name);
1909 } else {
1910 n = add_str(buildin_func[i].name);
1911 str_data[n].type = C_FUNC;
1912 str_data[n].val = i;
1913 str_data[n].func = buildin_func[i].func;
1914 }
1915 }
1916}
1917
1918/// Retrieves the value of a constant.
1919bool script_get_constant(const char* name, int* value)
1920{
1921 int n = search_str(name);
1922
1923 if( n == -1 || str_data[n].type != C_INT )
1924 {// not found or not a constant
1925 return false;
1926 }
1927 value[0] = str_data[n].val;
1928
1929 return true;
1930}
1931
1932/// Creates new constant or parameter with given value.
1933void script_set_constant(const char* name, int value, bool isparameter)
1934{
1935 int n = add_str(name);
1936
1937 if( str_data[n].type == C_NOP )
1938 {// new
1939 str_data[n].type = isparameter ? C_PARAM : C_INT;
1940 str_data[n].val = value;
1941 }
1942 else if( str_data[n].type == C_PARAM || str_data[n].type == C_INT )
1943 {// existing parameter or constant
1944 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);
1945 }
1946 else
1947 {// existing name
1948 ShowError("script_set_constant: Invalid name for %s '%s' (already defined as %s).\n", isparameter ? "parameter" : "constant", name, script_op2name(str_data[n].type));
1949 }
1950}
1951
1952/*==========================================
1953 * 定数データベースã®èªã¿è¾¼ã¿
1954 *------------------------------------------*/
1955static void read_constdb(void)
1956{
1957 FILE *fp;
1958 char line[1024],name[1024],val[1024];
1959 int type;
1960
1961 sprintf(line, "%s/const.txt", db_path);
1962 fp=fopen(line, "r");
1963 if(fp==NULL){
1964 ShowError("can't read %s\n", line);
1965 return ;
1966 }
1967 while(fgets(line, sizeof(line), fp))
1968 {
1969 if(line[0]=='/' && line[1]=='/')
1970 continue;
1971 type=0;
1972 if(sscanf(line,"%[A-Za-z0-9_],%[-0-9xXA-Fa-f],%d",name,val,&type)>=2 ||
1973 sscanf(line,"%[A-Za-z0-9_] %[-0-9xXA-Fa-f] %d",name,val,&type)>=2){
1974 script_set_constant(name, (int)strtol(val, NULL, 0), (bool)type);
1975 }
1976 }
1977
1978 /* CreativeSD Restock System */
1979 script_set_constant("MAX_RESTOCK_ITEM",MAX_RESTOCK, false);
1980 fclose(fp);
1981}
1982
1983/*==========================================
1984 * エラー表示
1985 *------------------------------------------*/
1986static const char* script_print_line(StringBuf* buf, const char* p, const char* mark, int line)
1987{
1988 int i;
1989 if( p == NULL || !p[0] ) return NULL;
1990 if( line < 0 )
1991 StringBuf_Printf(buf, "*% 5d : ", -line);
1992 else
1993 StringBuf_Printf(buf, " % 5d : ", line);
1994 for(i=0;p[i] && p[i] != '\n';i++){
1995 if(p + i != mark)
1996 StringBuf_Printf(buf, "%c", p[i]);
1997 else
1998 StringBuf_Printf(buf, "\'%c\'", p[i]);
1999 }
2000 StringBuf_AppendStr(buf, "\n");
2001 return p+i+(p[i] == '\n' ? 1 : 0);
2002}
2003
2004void script_error(const char* src, const char* file, int start_line, const char* error_msg, const char* error_pos)
2005{
2006 // エラーãŒç™ºç”Ÿã—ãŸè¡Œã‚’求ã‚ã‚‹
2007 int j;
2008 int line = start_line;
2009 const char *p;
2010 const char *linestart[5] = { NULL, NULL, NULL, NULL, NULL };
2011 StringBuf buf;
2012
2013 for(p=src;p && *p;line++){
2014 const char *lineend=strchr(p,'\n');
2015 if(lineend==NULL || error_pos<lineend){
2016 break;
2017 }
2018 for( j = 0; j < 4; j++ ) {
2019 linestart[j] = linestart[j+1];
2020 }
2021 linestart[4] = p;
2022 p=lineend+1;
2023 }
2024
2025 StringBuf_Init(&buf);
2026 StringBuf_AppendStr(&buf, "\a\n");
2027 StringBuf_Printf(&buf, "script error on %s line %d\n", file, line);
2028 StringBuf_Printf(&buf, " %s\n", error_msg);
2029 for(j = 0; j < 5; j++ ) {
2030 script_print_line(&buf, linestart[j], NULL, line + j - 5);
2031 }
2032 p = script_print_line(&buf, p, error_pos, -line);
2033 for(j = 0; j < 5; j++) {
2034 p = script_print_line(&buf, p, NULL, line + j + 1 );
2035 }
2036 ShowError("%s", StringBuf_Value(&buf));
2037 StringBuf_Destroy(&buf);
2038}
2039
2040/*==========================================
2041 * スクリプトã®è§£æž
2042 *------------------------------------------*/
2043struct script_code* parse_script(const char *src,const char *file,int line,int options)
2044{
2045 const char *p,*tmpp;
2046 int i;
2047 struct script_code* code = NULL;
2048 static int first=1;
2049 char end;
2050 bool unresolved_names = false;
2051
2052 if( src == NULL )
2053 return NULL;// empty script
2054
2055 memset(&syntax,0,sizeof(syntax));
2056 if(first){
2057 add_buildin_func();
2058 read_constdb();
2059 first=0;
2060 }
2061
2062 script_buf=(unsigned char *)aMalloc(SCRIPT_BLOCK_SIZE*sizeof(unsigned char));
2063 script_pos=0;
2064 script_size=SCRIPT_BLOCK_SIZE;
2065 parse_nextline(true, NULL);
2066
2067 // who called parse_script is responsible for clearing the database after using it, but just in case... lets clear it here
2068 if( options&SCRIPT_USE_LABEL_DB )
2069 scriptlabel_db->clear(scriptlabel_db, NULL);
2070 parse_options = options;
2071
2072 if( setjmp( error_jump ) != 0 ) {
2073 //Restore program state when script has problems. [from jA]
2074 int i;
2075 const int size = ARRAYLENGTH(syntax.curly);
2076 if( error_report )
2077 script_error(src,file,line,error_msg,error_pos);
2078 aFree( error_msg );
2079 aFree( script_buf );
2080 script_pos = 0;
2081 script_size = 0;
2082 script_buf = NULL;
2083 for(i=LABEL_START;i<str_num;i++)
2084 if(str_data[i].type == C_NOP) str_data[i].type = C_NAME;
2085 for(i=0; i<size; i++)
2086 linkdb_final(&syntax.curly[i].case_label);
2087 return NULL;
2088 }
2089
2090 parse_syntax_for_flag=0;
2091 p=src;
2092 p=skip_space(p);
2093 if( options&SCRIPT_IGNORE_EXTERNAL_BRACKETS )
2094 {// does not require brackets around the script
2095 if( *p == '\0' && !(options&SCRIPT_RETURN_EMPTY_SCRIPT) )
2096 {// empty script and can return NULL
2097 aFree( script_buf );
2098 script_pos = 0;
2099 script_size = 0;
2100 script_buf = NULL;
2101 return NULL;
2102 }
2103 end = '\0';
2104 }
2105 else
2106 {// requires brackets around the script
2107 if( *p != '{' )
2108 disp_error_message("not found '{'",p);
2109 p = skip_space(p+1);
2110 if( *p == '}' && !(options&SCRIPT_RETURN_EMPTY_SCRIPT) )
2111 {// empty script and can return NULL
2112 aFree( script_buf );
2113 script_pos = 0;
2114 script_size = 0;
2115 script_buf = NULL;
2116 return NULL;
2117 }
2118 end = '}';
2119 }
2120
2121 // clear references of labels, variables and internal functions
2122 for(i=LABEL_START;i<str_num;i++){
2123 if(
2124 str_data[i].type==C_POS || str_data[i].type==C_NAME ||
2125 str_data[i].type==C_USERFUNC || str_data[i].type == C_USERFUNC_POS
2126 ){
2127 str_data[i].type=C_NOP;
2128 str_data[i].backpatch=-1;
2129 str_data[i].label=-1;
2130 }
2131 }
2132
2133 while( syntax.curly_count != 0 || *p != end )
2134 {
2135 if( *p == '\0' )
2136 disp_error_message("unexpected end of script",p);
2137 // labelã ã‘特殊処ç†
2138 tmpp=skip_space(skip_word(p));
2139 if(*tmpp==':' && !(!strncasecmp(p,"default:",8) && p + 7 == tmpp)){
2140 i=add_word(p);
2141 set_label(i,script_pos,p);
2142 if( parse_options&SCRIPT_USE_LABEL_DB )
2143 strdb_put(scriptlabel_db, get_str(i), (void*)script_pos);
2144 p=tmpp+1;
2145 p=skip_space(p);
2146 continue;
2147 }
2148
2149 // ä»–ã¯å…¨éƒ¨ä¸€ç·’ããŸ
2150 p=parse_line(p);
2151 p=skip_space(p);
2152
2153 parse_nextline(false, p);
2154 }
2155
2156 add_scriptc(C_NOP);
2157
2158 // trim code to size
2159 script_size = script_pos;
2160 RECREATE(script_buf,unsigned char,script_pos);
2161
2162 // default unknown references to variables
2163 for(i=LABEL_START;i<str_num;i++){
2164 if(str_data[i].type==C_NOP){
2165 int j,next;
2166 str_data[i].type=C_NAME;
2167 str_data[i].label=i;
2168 for(j=str_data[i].backpatch;j>=0 && j!=0x00ffffff;){
2169 next=GETVALUE(script_buf,j);
2170 SETVALUE(script_buf,j,i);
2171 j=next;
2172 }
2173 }
2174 else if( str_data[i].type == C_USERFUNC )
2175 {// 'function name;' without follow-up code
2176 ShowError("parse_script: function '%s' declared but not defined.\n", str_buf+str_data[i].str);
2177 unresolved_names = true;
2178 }
2179 }
2180
2181 if( unresolved_names )
2182 {
2183 disp_error_message("parse_script: unresolved function references", p);
2184 }
2185
2186#ifdef DEBUG_DISP
2187 for(i=0;i<script_pos;i++){
2188 if((i&15)==0) ShowMessage("%04x : ",i);
2189 ShowMessage("%02x ",script_buf[i]);
2190 if((i&15)==15) ShowMessage("\n");
2191 }
2192 ShowMessage("\n");
2193#endif
2194#ifdef DEBUG_DISASM
2195 {
2196 int i = 0,j;
2197 while(i < script_pos) {
2198 c_op op = get_com(script_buf,&i);
2199
2200 ShowMessage("%06x %s", i, script_op2name(op));
2201 j = i;
2202 switch(op) {
2203 case C_INT:
2204 ShowMessage(" %d", get_num(script_buf,&i));
2205 break;
2206 case C_POS:
2207 ShowMessage(" 0x%06x", *(int*)(script_buf+i)&0xffffff);
2208 i += 3;
2209 break;
2210 case C_NAME:
2211 j = (*(int*)(script_buf+i)&0xffffff);
2212 ShowMessage(" %s", ( j == 0xffffff ) ? "?? unknown ??" : get_str(j));
2213 i += 3;
2214 break;
2215 case C_STR:
2216 j = strlen(script_buf + i);
2217 ShowMessage(" %s", script_buf + i);
2218 i += j+1;
2219 break;
2220 }
2221 ShowMessage(CL_CLL"\n");
2222 }
2223 }
2224#endif
2225
2226 CREATE(code,struct script_code,1);
2227 code->script_buf = script_buf;
2228 code->script_size = script_size;
2229 code->script_vars = NULL;
2230 return code;
2231}
2232
2233/// Returns the player attached to this script, identified by the rid.
2234/// If there is no player attached, the script is terminated.
2235TBL_PC *script_rid2sd(struct script_state *st)
2236{
2237 TBL_PC *sd=map_id2sd(st->rid);
2238 if(!sd){
2239 ShowError("script_rid2sd: fatal error ! player not attached!\n");
2240 script_reportfunc(st);
2241 script_reportsrc(st);
2242 st->state = END;
2243 }
2244 return sd;
2245}
2246
2247/// Dereferences a variable/constant, replacing it with a copy of the value.
2248///
2249/// @param st Script state
2250/// @param data Variable/constant
2251void get_val(struct script_state* st, struct script_data* data)
2252{
2253 const char* name;
2254 char prefix;
2255 char postfix;
2256 TBL_PC* sd = NULL;
2257
2258 if( !data_isreference(data) )
2259 return;// not a variable/constant
2260
2261 name = reference_getname(data);
2262 prefix = name[0];
2263 postfix = name[strlen(name) - 1];
2264
2265 //##TODO use reference_tovariable(data) when it's confirmed that it works [FlavioJS]
2266 if( !reference_toconstant(data) && not_server_variable(prefix) )
2267 {
2268 sd = script_rid2sd(st);
2269 if( sd == NULL )
2270 {// needs player attached
2271 if( postfix == '$' )
2272 {// string variable
2273 ShowWarning("script:get_val: cannot access player variable '%s', defaulting to \"\"\n", name);
2274 data->type = C_CONSTSTR;
2275 data->u.str = "";
2276 }
2277 else
2278 {// integer variable
2279 ShowWarning("script:get_val: cannot access player variable '%s', defaulting to 0\n", name);
2280 data->type = C_INT;
2281 data->u.num = 0;
2282 }
2283 return;
2284 }
2285 }
2286
2287 if( postfix == '$' )
2288 {// string variable
2289
2290 switch( prefix )
2291 {
2292 case '@':
2293 data->u.str = pc_readregstr(sd, data->u.num);
2294 break;
2295 case '$':
2296 data->u.str = mapreg_readregstr(data->u.num);
2297 break;
2298 case '#':
2299 if( name[1] == '#' )
2300 data->u.str = pc_readaccountreg2str(sd, name);// global
2301 else
2302 data->u.str = pc_readaccountregstr(sd, name);// local
2303 break;
2304 case '.':
2305 {
2306 struct linkdb_node** n =
2307 data->ref ? data->ref:
2308 name[1] == '@' ? st->stack->var_function:// instance/scope variable
2309 &st->script->script_vars;// npc variable
2310 data->u.str = (char*)linkdb_search(n, (void*)reference_getuid(data));
2311 }
2312 break;
2313 case '\'':
2314 {
2315 struct linkdb_node** n = NULL;
2316 if( st->instance_id )
2317 n = &instance[st->instance_id].svar;
2318 data->u.str = (char*)linkdb_search(n, (void*)reference_getuid(data));
2319 }
2320 break;
2321 default:
2322 data->u.str = pc_readglobalreg_str(sd, name);
2323 break;
2324 }
2325
2326 if( data->u.str == NULL || data->u.str[0] == '\0' )
2327 {// empty string
2328 data->type = C_CONSTSTR;
2329 data->u.str = "";
2330 }
2331 else
2332 {// duplicate string
2333 data->type = C_STR;
2334 data->u.str = aStrdup(data->u.str);
2335 }
2336
2337 }
2338 else
2339 {// integer variable
2340
2341 data->type = C_INT;
2342
2343 if( reference_toconstant(data) )
2344 {
2345 data->u.num = reference_getconstant(data);
2346 }
2347 else if( reference_toparam(data) )
2348 {
2349 data->u.num = pc_readparam(sd, reference_getparamtype(data));
2350 }
2351 else
2352 switch( prefix )
2353 {
2354 case '@':
2355 data->u.num = pc_readreg(sd, data->u.num);
2356 break;
2357 case '$':
2358 data->u.num = mapreg_readreg(data->u.num);
2359 break;
2360 case '#':
2361 if( name[1] == '#' )
2362 data->u.num = pc_readaccountreg2(sd, name);// global
2363 else
2364 data->u.num = pc_readaccountreg(sd, name);// local
2365 break;
2366 case '.':
2367 {
2368 struct linkdb_node** n =
2369 data->ref ? data->ref:
2370 name[1] == '@' ? st->stack->var_function:// instance/scope variable
2371 &st->script->script_vars;// npc variable
2372 data->u.num = (int)linkdb_search(n, (void*)reference_getuid(data));
2373 }
2374 break;
2375 case '\'':
2376 {
2377 struct linkdb_node** n = NULL;
2378 if( st->instance_id )
2379 n = &instance[st->instance_id].ivar;
2380 data->u.num = (int)linkdb_search(n, (void*)reference_getuid(data));
2381 }
2382 break;
2383 default:
2384 data->u.num = pc_readglobalreg(sd, name);
2385 break;
2386 }
2387
2388 }
2389
2390 return;
2391}
2392
2393struct script_data* push_val2(struct script_stack* stack, enum c_op type, int val, struct linkdb_node** ref);
2394
2395/// Retrieves the value of a reference identified by uid (variable, constant, param)
2396/// The value is left in the top of the stack and needs to be removed manually.
2397void* get_val2(struct script_state* st, int uid, struct linkdb_node** ref)
2398{
2399 struct script_data* data;
2400 push_val2(st->stack, C_NAME, uid, ref);
2401 data = script_getdatatop(st, -1);
2402 get_val(st, data);
2403 return (data->type == C_INT ? (void*)data->u.num : (void*)data->u.str);
2404}
2405
2406/*==========================================
2407 * Stores the value of a script variable
2408 * Return value is 0 on fail, 1 on success.
2409 *------------------------------------------*/
2410static int set_reg(struct script_state* st, TBL_PC* sd, int num, const char* name, const void* value, struct linkdb_node** ref)
2411{
2412 char prefix = name[0];
2413
2414 if( is_string_variable(name) )
2415 {// string variable
2416 const char* str = (const char*)value;
2417 switch (prefix) {
2418 case '@':
2419 return pc_setregstr(sd, num, str);
2420 case '$':
2421 return mapreg_setregstr(num, str);
2422 case '#':
2423 return (name[1] == '#') ?
2424 pc_setaccountreg2str(sd, name, str) :
2425 pc_setaccountregstr(sd, name, str);
2426 case '.': {
2427 char* p;
2428 struct linkdb_node** n;
2429 n = (ref) ? ref : (name[1] == '@') ? st->stack->var_function : &st->script->script_vars;
2430 p = (char*)linkdb_erase(n, (void*)num);
2431 if (p) aFree(p);
2432 if (str[0]) linkdb_insert(n, (void*)num, aStrdup(str));
2433 }
2434 return 1;
2435 case '\'': {
2436 char *p;
2437 struct linkdb_node** n = NULL;
2438 if( st->instance_id )
2439 n = &instance[st->instance_id].svar;
2440
2441 p = (char*)linkdb_erase(n, (void*)num);
2442 if (p) aFree(p);
2443 if( str[0] ) linkdb_insert(n, (void*)num, aStrdup(str));
2444 }
2445 return 1;
2446 default:
2447 return pc_setglobalreg_str(sd, name, str);
2448 }
2449 }
2450 else
2451 {// integer variable
2452 int val = (int)value;
2453 if(str_data[num&0x00ffffff].type == C_PARAM)
2454 {
2455 if( pc_setparam(sd, str_data[num&0x00ffffff].val, val) == 0 )
2456 {
2457 if( st != NULL )
2458 {
2459 ShowError("script:set_reg: failed to set param '%s' to %d.\n", name, val);
2460 script_reportsrc(st);
2461 st->state = END;
2462 }
2463 return 0;
2464 }
2465 return 1;
2466 }
2467
2468 switch (prefix) {
2469 case '@':
2470 return pc_setreg(sd, num, val);
2471 case '$':
2472 return mapreg_setreg(num, val);
2473 case '#':
2474 return (name[1] == '#') ?
2475 pc_setaccountreg2(sd, name, val) :
2476 pc_setaccountreg(sd, name, val);
2477 case '.': {
2478 struct linkdb_node** n;
2479 n = (ref) ? ref : (name[1] == '@') ? st->stack->var_function : &st->script->script_vars;
2480 if (val == 0)
2481 linkdb_erase(n, (void*)num);
2482 else
2483 linkdb_replace(n, (void*)num, (void*)val);
2484 }
2485 return 1;
2486 case '\'':
2487 {
2488 struct linkdb_node** n = NULL;
2489 if( st->instance_id )
2490 n = &instance[st->instance_id].ivar;
2491
2492 if( val == 0 )
2493 linkdb_erase(n, (void*)num);
2494 else
2495 linkdb_replace(n, (void*)num, (void*)val);
2496 return 1;
2497 }
2498 default:
2499 return pc_setglobalreg(sd, name, val);
2500 }
2501 }
2502}
2503
2504int set_var(TBL_PC* sd, char* name, void* val)
2505{
2506 return set_reg(NULL, sd, reference_uid(add_str(name),0), name, val, NULL);
2507}
2508
2509void setd_sub(struct script_state *st, TBL_PC *sd, const char *varname, int elem, void *value, struct linkdb_node **ref)
2510{
2511 set_reg(st, sd, reference_uid(add_str(varname),elem), varname, value, ref);
2512}
2513
2514/// Converts the data to a string
2515const char* conv_str(struct script_state* st, struct script_data* data)
2516{
2517 char* p;
2518
2519 get_val(st, data);
2520 if( data_isstring(data) )
2521 {// nothing to convert
2522 }
2523 else if( data_isint(data) )
2524 {// int -> string
2525 CREATE(p, char, ITEM_NAME_LENGTH);
2526 snprintf(p, ITEM_NAME_LENGTH, "%d", data->u.num);
2527 p[ITEM_NAME_LENGTH-1] = '\0';
2528 data->type = C_STR;
2529 data->u.str = p;
2530 }
2531 else if( data_isreference(data) )
2532 {// reference -> string
2533 //##TODO when does this happen (check get_val) [FlavioJS]
2534 data->type = C_CONSTSTR;
2535 data->u.str = reference_getname(data);
2536 }
2537 else
2538 {// unsupported data type
2539 ShowError("script:conv_str: cannot convert to string, defaulting to \"\"\n");
2540 script_reportdata(data);
2541 script_reportsrc(st);
2542 data->type = C_CONSTSTR;
2543 data->u.str = "";
2544 }
2545 return data->u.str;
2546}
2547
2548/// Converts the data to an int
2549int conv_num(struct script_state* st, struct script_data* data)
2550{
2551 char* p;
2552 long num;
2553
2554 get_val(st, data);
2555 if( data_isint(data) )
2556 {// nothing to convert
2557 }
2558 else if( data_isstring(data) )
2559 {// string -> int
2560 // the result does not overflow or underflow, it is capped instead
2561 // ex: 999999999999 is capped to INT_MAX (2147483647)
2562 p = data->u.str;
2563 errno = 0;
2564 num = strtol(data->u.str, NULL, 10);// change radix to 0 to support octal numbers "o377" and hex numbers "0xFF"
2565 if( errno == ERANGE
2566#if LONG_MAX > INT_MAX
2567 || num < INT_MIN || num > INT_MAX
2568#endif
2569 )
2570 {
2571 if( num <= INT_MIN )
2572 {
2573 num = INT_MIN;
2574 ShowError("script:conv_num: underflow detected, capping to %ld\n", num);
2575 }
2576 else//if( num >= INT_MAX )
2577 {
2578 num = INT_MAX;
2579 ShowError("script:conv_num: overflow detected, capping to %ld\n", num);
2580 }
2581 script_reportdata(data);
2582 script_reportsrc(st);
2583 }
2584 if( data->type == C_STR )
2585 aFree(p);
2586 data->type = C_INT;
2587 data->u.num = (int)num;
2588 }
2589#if 0
2590 // FIXME this function is being used to retrieve the position of labels and
2591 // probably other stuff [FlavioJS]
2592 else
2593 {// unsupported data type
2594 ShowError("script:conv_num: cannot convert to number, defaulting to 0\n");
2595 script_reportdata(data);
2596 script_reportsrc(st);
2597 data->type = C_INT;
2598 data->u.num = 0;
2599 }
2600#endif
2601 return data->u.num;
2602}
2603
2604//
2605// Stack operations
2606//
2607
2608/// Increases the size of the stack
2609void stack_expand(struct script_stack* stack)
2610{
2611 stack->sp_max += 64;
2612 stack->stack_data = (struct script_data*)aRealloc(stack->stack_data,
2613 stack->sp_max * sizeof(stack->stack_data[0]) );
2614 memset(stack->stack_data + (stack->sp_max - 64), 0,
2615 64 * sizeof(stack->stack_data[0]) );
2616}
2617
2618/// Pushes a value into the stack
2619#define push_val(stack,type,val) push_val2(stack, type, val, NULL)
2620
2621/// Pushes a value into the stack (with reference)
2622struct script_data* push_val2(struct script_stack* stack, enum c_op type, int val, struct linkdb_node** ref)
2623{
2624 if( stack->sp >= stack->sp_max )
2625 stack_expand(stack);
2626 stack->stack_data[stack->sp].type = type;
2627 stack->stack_data[stack->sp].u.num = val;
2628 stack->stack_data[stack->sp].ref = ref;
2629 stack->sp++;
2630 return &stack->stack_data[stack->sp-1];
2631}
2632
2633/// Pushes a string into the stack
2634struct script_data* push_str(struct script_stack* stack, enum c_op type, char* str)
2635{
2636 if( stack->sp >= stack->sp_max )
2637 stack_expand(stack);
2638 stack->stack_data[stack->sp].type = type;
2639 stack->stack_data[stack->sp].u.str = str;
2640 stack->stack_data[stack->sp].ref = NULL;
2641 stack->sp++;
2642 return &stack->stack_data[stack->sp-1];
2643}
2644
2645/// Pushes a retinfo into the stack
2646struct script_data* push_retinfo(struct script_stack* stack, struct script_retinfo* ri)
2647{
2648 if( stack->sp >= stack->sp_max )
2649 stack_expand(stack);
2650 stack->stack_data[stack->sp].type = C_RETINFO;
2651 stack->stack_data[stack->sp].u.ri = ri;
2652 stack->stack_data[stack->sp].ref = NULL;
2653 stack->sp++;
2654 return &stack->stack_data[stack->sp-1];
2655}
2656
2657/// Pushes a copy of the target position into the stack
2658struct script_data* push_copy(struct script_stack* stack, int pos)
2659{
2660 switch( stack->stack_data[pos].type )
2661 {
2662 case C_CONSTSTR:
2663 return push_str(stack, C_CONSTSTR, stack->stack_data[pos].u.str);
2664 break;
2665 case C_STR:
2666 return push_str(stack, C_STR, aStrdup(stack->stack_data[pos].u.str));
2667 break;
2668 case C_RETINFO:
2669 ShowFatalError("script:push_copy: can't create copies of C_RETINFO. Exiting...\n");
2670 exit(1);
2671 break;
2672 default:
2673 return push_val2(
2674 stack,stack->stack_data[pos].type,
2675 stack->stack_data[pos].u.num,
2676 stack->stack_data[pos].ref
2677 );
2678 break;
2679 }
2680}
2681
2682/// Removes the values in indexes [start,end[ from the stack.
2683/// Adjusts all stack pointers.
2684void pop_stack(struct script_state* st, int start, int end)
2685{
2686 struct script_stack* stack = st->stack;
2687 struct script_data* data;
2688 int i;
2689
2690 if( start < 0 )
2691 start = 0;
2692 if( end > stack->sp )
2693 end = stack->sp;
2694 if( start >= end )
2695 return;// nothing to pop
2696
2697 // free stack elements
2698 for( i = start; i < end; i++ )
2699 {
2700 data = &stack->stack_data[i];
2701 if( data->type == C_STR )
2702 aFree(data->u.str);
2703 if( data->type == C_RETINFO )
2704 {
2705 struct script_retinfo* ri = data->u.ri;
2706 if( ri->var_function )
2707 {
2708 script_free_vars(ri->var_function);
2709 aFree(ri->var_function);
2710 }
2711 aFree(ri);
2712 }
2713 data->type = C_NOP;
2714 }
2715 // move the rest of the elements
2716 if( stack->sp > end )
2717 {
2718 memmove(&stack->stack_data[start], &stack->stack_data[end], sizeof(stack->stack_data[0])*(stack->sp - end));
2719 for( i = start + stack->sp - end; i < stack->sp; ++i )
2720 stack->stack_data[i].type = C_NOP;
2721 }
2722 // adjust stack pointers
2723 if( st->start > end ) st->start -= end - start;
2724 else if( st->start > start ) st->start = start;
2725 if( st->end > end ) st->end -= end - start;
2726 else if( st->end > start ) st->end = start;
2727 if( stack->defsp > end ) stack->defsp -= end - start;
2728 else if( stack->defsp > start ) stack->defsp = start;
2729 stack->sp -= end - start;
2730}
2731
2732///
2733///
2734///
2735
2736/*==========================================
2737 * スクリプトä¾å˜å¤‰æ•°ã€é–¢æ•°ä¾å˜å¤‰æ•°ã®è§£æ”¾
2738 *------------------------------------------*/
2739void script_free_vars(struct linkdb_node **node)
2740{
2741 struct linkdb_node* n = *node;
2742 while( n != NULL)
2743 {
2744 const char* name = get_str((int)(n->key)&0x00ffffff);
2745 if( is_string_variable(name) )
2746 aFree(n->data); // æ–‡å—型変数ãªã®ã§ã€ãƒ‡ãƒ¼ã‚¿å‰Šé™¤
2747 n = n->next;
2748 }
2749 linkdb_final( node );
2750}
2751
2752void script_free_code(struct script_code* code)
2753{
2754 script_free_vars( &code->script_vars );
2755 aFree( code->script_buf );
2756 aFree( code );
2757}
2758
2759/// Creates a new script state.
2760///
2761/// @param script Script code
2762/// @param pos Position in the code
2763/// @param rid Who is running the script (attached player)
2764/// @param oid Where the code is being run (npc 'object')
2765/// @return Script state
2766struct script_state* script_alloc_state(struct script_code* script, int pos, int rid, int oid)
2767{
2768 struct script_state* st;
2769 CREATE(st, struct script_state, 1);
2770 st->stack = (struct script_stack*)aMalloc(sizeof(struct script_stack));
2771 st->stack->sp = 0;
2772 st->stack->sp_max = 64;
2773 CREATE(st->stack->stack_data, struct script_data, st->stack->sp_max);
2774 st->stack->defsp = st->stack->sp;
2775 CREATE(st->stack->var_function, struct linkdb_node*, 1);
2776 st->state = RUN;
2777 st->script = script;
2778 //st->scriptroot = script;
2779 st->pos = pos;
2780 st->rid = rid;
2781 st->oid = oid;
2782 st->sleep.timer = INVALID_TIMER;
2783 return st;
2784}
2785
2786/// Frees a script state.
2787///
2788/// @param st Script state
2789void script_free_state(struct script_state* st)
2790{
2791 if(st->bk_st)
2792 {// backup was not restored
2793 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);
2794 }
2795 if( st->sleep.timer != INVALID_TIMER )
2796 delete_timer(st->sleep.timer, run_script_timer);
2797 script_free_vars(st->stack->var_function);
2798 aFree(st->stack->var_function);
2799 pop_stack(st, 0, st->stack->sp);
2800 aFree(st->stack->stack_data);
2801 aFree(st->stack);
2802 st->pos = -1;
2803 aFree(st);
2804}
2805
2806//
2807// 実行部main
2808//
2809/*==========================================
2810 * コマンドã®èªã¿å–り
2811 *------------------------------------------*/
2812c_op get_com(unsigned char *script,int *pos)
2813{
2814 int i = 0, j = 0;
2815
2816 if(script[*pos]>=0x80){
2817 return C_INT;
2818 }
2819 while(script[*pos]>=0x40){
2820 i=script[(*pos)++]<<j;
2821 j+=6;
2822 }
2823 return (c_op)(i+(script[(*pos)++]<<j));
2824}
2825
2826/*==========================================
2827 * æ•°å€¤ã®æ‰€å¾—
2828 *------------------------------------------*/
2829int get_num(unsigned char *script,int *pos)
2830{
2831 int i,j;
2832 i=0; j=0;
2833 while(script[*pos]>=0xc0){
2834 i+=(script[(*pos)++]&0x7f)<<j;
2835 j+=6;
2836 }
2837 return i+((script[(*pos)++]&0x7f)<<j);
2838}
2839
2840/*==========================================
2841 * スタックã‹ã‚‰å€¤ã‚’å–り出ã™
2842 *------------------------------------------*/
2843int pop_val(struct script_state* st)
2844{
2845 if(st->stack->sp<=0)
2846 return 0;
2847 st->stack->sp--;
2848 get_val(st,&(st->stack->stack_data[st->stack->sp]));
2849 if(st->stack->stack_data[st->stack->sp].type==C_INT)
2850 return st->stack->stack_data[st->stack->sp].u.num;
2851 return 0;
2852}
2853
2854/// Ternary operators
2855/// test ? if_true : if_false
2856void op_3(struct script_state* st, int op)
2857{
2858 struct script_data* data;
2859 int flag = 0;
2860
2861 data = script_getdatatop(st, -3);
2862 get_val(st, data);
2863
2864 if( data_isstring(data) )
2865 flag = data->u.str[0];// "" -> false
2866 else if( data_isint(data) )
2867 flag = data->u.num;// 0 -> false
2868 else
2869 {
2870 ShowError("script:op_3: invalid data for the ternary operator test\n");
2871 script_reportdata(data);
2872 script_reportsrc(st);
2873 script_removetop(st, -3, 0);
2874 script_pushnil(st);
2875 return;
2876 }
2877 if( flag )
2878 script_pushcopytop(st, -2);
2879 else
2880 script_pushcopytop(st, -1);
2881 script_removetop(st, -4, -1);
2882}
2883
2884/// Binary string operators
2885/// s1 EQ s2 -> i
2886/// s1 NE s2 -> i
2887/// s1 GT s2 -> i
2888/// s1 GE s2 -> i
2889/// s1 LT s2 -> i
2890/// s1 LE s2 -> i
2891/// s1 ADD s2 -> s
2892void op_2str(struct script_state* st, int op, const char* s1, const char* s2)
2893{
2894 int a = 0;
2895
2896 switch(op){
2897 case C_EQ: a = (strcmp(s1,s2) == 0); break;
2898 case C_NE: a = (strcmp(s1,s2) != 0); break;
2899 case C_GT: a = (strcmp(s1,s2) > 0); break;
2900 case C_GE: a = (strcmp(s1,s2) >= 0); break;
2901 case C_LT: a = (strcmp(s1,s2) < 0); break;
2902 case C_LE: a = (strcmp(s1,s2) <= 0); break;
2903 case C_ADD:
2904 {
2905 char* buf = (char *)aMallocA((strlen(s1)+strlen(s2)+1)*sizeof(char));
2906 strcpy(buf, s1);
2907 strcat(buf, s2);
2908 script_pushstr(st, buf);
2909 return;
2910 }
2911 default:
2912 ShowError("script:op2_str: unexpected string operator %s\n", script_op2name(op));
2913 script_reportsrc(st);
2914 script_pushnil(st);
2915 st->state = END;
2916 return;
2917 }
2918
2919 script_pushint(st,a);
2920}
2921
2922/// Binary number operators
2923/// i OP i -> i
2924void op_2num(struct script_state* st, int op, int i1, int i2)
2925{
2926 int ret;
2927 double ret_double;
2928
2929 switch( op )
2930 {
2931 case C_AND: ret = i1 & i2; break;
2932 case C_OR: ret = i1 | i2; break;
2933 case C_XOR: ret = i1 ^ i2; break;
2934 case C_LAND: ret = (i1 && i2); break;
2935 case C_LOR: ret = (i1 || i2); break;
2936 case C_EQ: ret = (i1 == i2); break;
2937 case C_NE: ret = (i1 != i2); break;
2938 case C_GT: ret = (i1 > i2); break;
2939 case C_GE: ret = (i1 >= i2); break;
2940 case C_LT: ret = (i1 < i2); break;
2941 case C_LE: ret = (i1 <= i2); break;
2942 case C_R_SHIFT: ret = i1>>i2; break;
2943 case C_L_SHIFT: ret = i1<<i2; break;
2944 case C_DIV:
2945 case C_MOD:
2946 if( i2 == 0 )
2947 {
2948 ShowError("script:op_2num: division by zero detected op=%s i1=%d i2=%d\n", script_op2name(op), i1, i2);
2949 script_reportsrc(st);
2950 script_pushnil(st);
2951 st->state = END;
2952 return;
2953 }
2954 else if( op == C_DIV )
2955 ret = i1 / i2;
2956 else//if( op == C_MOD )
2957 ret = i1 % i2;
2958 break;
2959 default:
2960 switch( op )
2961 {// operators that can overflow/underflow
2962 case C_ADD: ret = i1 + i2; ret_double = (double)i1 + (double)i2; break;
2963 case C_SUB: ret = i1 - i2; ret_double = (double)i1 - (double)i2; break;
2964 case C_MUL: ret = i1 * i2; ret_double = (double)i1 * (double)i2; break;
2965 default:
2966 ShowError("script:op_2num: unexpected number operator %s i1=%d i2=%d\n", script_op2name(op), i1, i2);
2967 script_reportsrc(st);
2968 script_pushnil(st);
2969 return;
2970 }
2971 if( ret_double < (double)INT_MIN )
2972 {
2973 ShowWarning("script:op_2num: underflow detected op=%s i1=%d i2=%d\n", script_op2name(op), i1, i2);
2974 script_reportsrc(st);
2975 ret = INT_MIN;
2976 }
2977 else if( ret_double > (double)INT_MAX )
2978 {
2979 ShowWarning("script:op_2num: overflow detected op=%s i1=%d i2=%d\n", script_op2name(op), i1, i2);
2980 script_reportsrc(st);
2981 ret = INT_MAX;
2982 }
2983 }
2984 script_pushint(st, ret);
2985}
2986
2987/// Binary operators
2988void op_2(struct script_state *st, int op)
2989{
2990 struct script_data* left;
2991 struct script_data* right;
2992
2993 left = script_getdatatop(st, -2);
2994 right = script_getdatatop(st, -1);
2995
2996 get_val(st, left);
2997 get_val(st, right);
2998
2999 // automatic conversions
3000 switch( op )
3001 {
3002 case C_ADD:
3003 if( data_isint(left) && data_isstring(right) )
3004 {// convert int-string to string-string
3005 conv_str(st, left);
3006 }
3007 else if( data_isstring(left) && data_isint(right) )
3008 {// convert string-int to string-string
3009 conv_str(st, right);
3010 }
3011 break;
3012 }
3013
3014 if( data_isstring(left) && data_isstring(right) )
3015 {// ss => op_2str
3016 op_2str(st, op, left->u.str, right->u.str);
3017 script_removetop(st, -3, -1);// pop the two values before the top one
3018 }
3019 else if( data_isint(left) && data_isint(right) )
3020 {// ii => op_2num
3021 int i1 = left->u.num;
3022 int i2 = right->u.num;
3023 script_removetop(st, -2, 0);
3024 op_2num(st, op, i1, i2);
3025 }
3026 else
3027 {// invalid argument
3028 ShowError("script:op_2: invalid data for operator %s\n", script_op2name(op));
3029 script_reportdata(left);
3030 script_reportdata(right);
3031 script_reportsrc(st);
3032 script_removetop(st, -2, 0);
3033 script_pushnil(st);
3034 st->state = END;
3035 }
3036}
3037
3038/// Unary operators
3039/// NEG i -> i
3040/// NOT i -> i
3041/// LNOT i -> i
3042void op_1(struct script_state* st, int op)
3043{
3044 struct script_data* data;
3045 int i1;
3046
3047 data = script_getdatatop(st, -1);
3048 get_val(st, data);
3049
3050 if( !data_isint(data) )
3051 {// not a number
3052 ShowError("script:op_1: argument is not a number (op=%s)\n", script_op2name(op));
3053 script_reportdata(data);
3054 script_reportsrc(st);
3055 script_pushnil(st);
3056 st->state = END;
3057 return;
3058 }
3059
3060 i1 = data->u.num;
3061 script_removetop(st, -1, 0);
3062 switch( op )
3063 {
3064 case C_NEG: i1 = -i1; break;
3065 case C_NOT: i1 = ~i1; break;
3066 case C_LNOT: i1 = !i1; break;
3067 default:
3068 ShowError("script:op_1: unexpected operator %s i1=%d\n", script_op2name(op), i1);
3069 script_reportsrc(st);
3070 script_pushnil(st);
3071 st->state = END;
3072 return;
3073 }
3074 script_pushint(st, i1);
3075}
3076
3077
3078/// Checks the type of all arguments passed to a built-in function.
3079///
3080/// @param st Script state whose stack arguments should be inspected.
3081/// @param func Built-in function for which the arguments are intended.
3082static void script_check_buildin_argtype(struct script_state* st, int func)
3083{
3084 char type;
3085 int idx, invalid = 0;
3086 script_function* sf = &buildin_func[str_data[func].val];
3087
3088 for( idx = 2; script_hasdata(st, idx); idx++ )
3089 {
3090 struct script_data* data = script_getdata(st, idx);
3091
3092 type = sf->arg[idx-2];
3093
3094 if( type == '?' || type == '*' )
3095 {// optional argument or unknown number of optional parameters ( no types are after this )
3096 break;
3097 }
3098 else if( type == 0 )
3099 {// more arguments than necessary ( should not happen, as it is checked before )
3100 ShowWarning("Found more arguments than necessary.\n");
3101 invalid++;
3102 break;
3103 }
3104 else
3105 {
3106 const char* name = NULL;
3107
3108 if( data_isreference(data) )
3109 {// get name for variables to determine the type they refer to
3110 name = reference_getname(data);
3111 }
3112
3113 switch( type )
3114 {
3115 case 'v':
3116 if( !data_isstring(data) && !data_isint(data) && !data_isreference(data) )
3117 {// variant
3118 ShowWarning("Unexpected type for argument %d. Expected string, number or variable.\n", idx-1);
3119 script_reportdata(data);
3120 invalid++;
3121 }
3122 break;
3123 case 's':
3124 if( !data_isstring(data) && !( data_isreference(data) && is_string_variable(name) ) )
3125 {// string
3126 ShowWarning("Unexpected type for argument %d. Expected string.\n", idx-1);
3127 script_reportdata(data);
3128 invalid++;
3129 }
3130 break;
3131 case 'i':
3132 if( !data_isint(data) && !( data_isreference(data) && ( reference_toparam(data) || reference_toconstant(data) || !is_string_variable(name) ) ) )
3133 {// int ( params and constants are always int )
3134 ShowWarning("Unexpected type for argument %d. Expected number.\n", idx-1);
3135 script_reportdata(data);
3136 invalid++;
3137 }
3138 break;
3139 case 'r':
3140 if( !data_isreference(data) )
3141 {// variables
3142 ShowWarning("Unexpected type for argument %d. Expected variable.\n", idx-1);
3143 script_reportdata(data);
3144 invalid++;
3145 }
3146 break;
3147 case 'l':
3148 if( !data_islabel(data) && !data_isfunclabel(data) )
3149 {// label
3150 ShowWarning("Unexpected type for argument %d. Expected label.\n", idx-1);
3151 script_reportdata(data);
3152 invalid++;
3153 }
3154 break;
3155 }
3156 }
3157 }
3158
3159 if(invalid)
3160 {
3161 ShowDebug("Function: %s\n", get_str(func));
3162 script_reportsrc(st);
3163 }
3164}
3165
3166
3167/// Executes a buildin command.
3168/// Stack: C_NAME(<command>) C_ARG <arg0> <arg1> ... <argN>
3169int run_func(struct script_state *st)
3170{
3171 struct script_data* data;
3172 int i,start_sp,end_sp,func;
3173
3174 end_sp = st->stack->sp;// position after the last argument
3175 for( i = end_sp-1; i > 0 ; --i )
3176 if( st->stack->stack_data[i].type == C_ARG )
3177 break;
3178 if( i == 0 )
3179 {
3180 ShowError("script:run_func: C_ARG not found. please report this!!!\n");
3181 st->state = END;
3182 script_reportsrc(st);
3183 return 1;
3184 }
3185 start_sp = i-1;// C_NAME of the command
3186 st->start = start_sp;
3187 st->end = end_sp;
3188
3189 data = &st->stack->stack_data[st->start];
3190 if( data->type == C_NAME && str_data[data->u.num].type == C_FUNC )
3191 func = data->u.num;
3192 else
3193 {
3194 ShowError("script:run_func: not a buildin command.\n");
3195 script_reportdata(data);
3196 script_reportsrc(st);
3197 st->state = END;
3198 return 1;
3199 }
3200
3201 if( script_config.warn_func_mismatch_argtypes )
3202 {
3203 script_check_buildin_argtype(st, func);
3204 }
3205
3206 if(str_data[func].func){
3207 if (str_data[func].func(st)) //Report error
3208 script_reportsrc(st);
3209 } else {
3210 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));
3211 script_reportsrc(st);
3212 st->state = END;
3213 }
3214
3215 // Stack's datum are used when re-running functions [Eoe]
3216 if( st->state == RERUNLINE )
3217 return 0;
3218
3219 pop_stack(st, st->start, st->end);
3220 if( st->state == RETFUNC )
3221 {// return from a user-defined function
3222 struct script_retinfo* ri;
3223 int olddefsp = st->stack->defsp;
3224 int nargs;
3225
3226 pop_stack(st, st->stack->defsp, st->start);// pop distractions from the stack
3227 if( st->stack->defsp < 1 || st->stack->stack_data[st->stack->defsp-1].type != C_RETINFO )
3228 {
3229 ShowWarning("script:run_func: return without callfunc or callsub!\n");
3230 script_reportsrc(st);
3231 st->state = END;
3232 return 1;
3233 }
3234 script_free_vars( st->stack->var_function );
3235 aFree(st->stack->var_function);
3236
3237 ri = st->stack->stack_data[st->stack->defsp-1].u.ri;
3238 nargs = ri->nargs;
3239 st->pos = ri->pos;
3240 st->script = ri->script;
3241 st->stack->var_function = ri->var_function;
3242 st->stack->defsp = ri->defsp;
3243 memset(ri, 0, sizeof(struct script_retinfo));
3244
3245 pop_stack(st, olddefsp-nargs-1, olddefsp);// pop arguments and retinfo
3246
3247 st->state = GOTO;
3248 }
3249
3250 return 0;
3251}
3252
3253/*==========================================
3254 * script execution
3255 *------------------------------------------*/
3256void run_script(struct script_code *rootscript,int pos,int rid,int oid)
3257{
3258 struct script_state *st;
3259
3260 if( rootscript == NULL || pos < 0 )
3261 return;
3262
3263 // TODO In jAthena, this function can take over the pending script in the player. [FlavioJS]
3264 // It is unclear how that can be triggered, so it needs the be traced/checked in more detail.
3265 // NOTE At the time of this change, this function wasn't capable of taking over the script state because st->scriptroot was never set.
3266 st = script_alloc_state(rootscript, pos, rid, oid);
3267 run_script_main(st);
3268}
3269
3270void script_stop_sleeptimers(int id)
3271{
3272 struct script_state* st;
3273 for(;;)
3274 {
3275 st = (struct script_state*)linkdb_erase(&sleep_db,(void*)id);
3276 if( st == NULL )
3277 break; // no more sleep timers
3278 script_free_state(st);
3279 }
3280}
3281
3282/*==========================================
3283 * 指定ノードをsleep_dbã‹ã‚‰å‰Šé™¤
3284 *------------------------------------------*/
3285struct linkdb_node* script_erase_sleepdb(struct linkdb_node *n)
3286{
3287 struct linkdb_node *retnode;
3288
3289 if( n == NULL)
3290 return NULL;
3291 if( n->prev == NULL )
3292 sleep_db = n->next;
3293 else
3294 n->prev->next = n->next;
3295 if( n->next )
3296 n->next->prev = n->prev;
3297 retnode = n->next;
3298 aFree( n );
3299 return retnode; // 次ã®ãƒŽãƒ¼ãƒ‰ã‚’è¿”ã™
3300}
3301
3302/*==========================================
3303 * sleep用タイマー関数
3304 *------------------------------------------*/
3305int run_script_timer(int tid, unsigned int tick, int id, intptr_t data)
3306{
3307 struct script_state *st = (struct script_state *)data;
3308 struct linkdb_node *node = (struct linkdb_node *)sleep_db;
3309 TBL_PC *sd = map_id2sd(st->rid);
3310
3311 if((sd && sd->status.char_id != id) || (st->rid && !sd))
3312 { //Character mismatch. Cancel execution.
3313 st->rid = 0;
3314 st->state = END;
3315 }
3316 while( node && st->sleep.timer != INVALID_TIMER ) {
3317 if( (int)node->key == st->oid && ((struct script_state *)node->data)->sleep.timer == st->sleep.timer ) {
3318 script_erase_sleepdb(node);
3319 st->sleep.timer = INVALID_TIMER;
3320 break;
3321 }
3322 node = node->next;
3323 }
3324 if(st->state != RERUNLINE)
3325 st->sleep.tick = 0;
3326 run_script_main(st);
3327 return 0;
3328}
3329
3330/// Detaches script state from possibly attached character and restores it's previous script if any.
3331///
3332/// @param st Script state to detach.
3333/// @param dequeue_event Whether to schedule any queued events, when there was no previous script.
3334static void script_detach_state(struct script_state* st, bool dequeue_event)
3335{
3336 struct map_session_data* sd;
3337
3338 if(st->rid && (sd = map_id2sd(st->rid))!=NULL)
3339 {
3340 sd->st = st->bk_st;
3341 sd->npc_id = st->bk_npcid;
3342
3343 if(st->bk_st)
3344 {
3345 //Remove tag for removal.
3346 st->bk_st = NULL;
3347 st->bk_npcid = 0;
3348 }
3349 else if(dequeue_event)
3350 {
3351 npc_event_dequeue(sd);
3352 }
3353 }
3354 else if(st->bk_st)
3355 {// rid was set to 0, before detaching the script state
3356 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);
3357 script_reportsrc(st->bk_st);
3358
3359 script_free_state(st->bk_st);
3360 st->bk_st = NULL;
3361 }
3362}
3363
3364/// Attaches script state to possibly attached character and backups it's previous script, if any.
3365///
3366/// @param st Script state to attach.
3367static void script_attach_state(struct script_state* st)
3368{
3369 struct map_session_data* sd;
3370
3371 if(st->rid && (sd = map_id2sd(st->rid))!=NULL)
3372 {
3373 if(st!=sd->st)
3374 {
3375 if(st->bk_st)
3376 {// there is already a backup
3377 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);
3378 }
3379 st->bk_st = sd->st;
3380 st->bk_npcid = sd->npc_id;
3381 }
3382 sd->st = st;
3383 sd->npc_id = st->oid;
3384 }
3385}
3386
3387/*==========================================
3388 * スクリプトã®å®Ÿè¡Œãƒ¡ã‚¤ãƒ³éƒ¨åˆ†
3389 *------------------------------------------*/
3390void run_script_main(struct script_state *st)
3391{
3392 int cmdcount=script_config.check_cmdcount;
3393 int gotocount=script_config.check_gotocount;
3394 TBL_PC *sd;
3395 struct script_stack *stack=st->stack;
3396 struct npc_data *nd;
3397
3398 script_attach_state(st);
3399
3400 nd = map_id2nd(st->oid);
3401 if( nd && map[nd->bl.m].instance_id > 0 )
3402 st->instance_id = map[nd->bl.m].instance_id;
3403
3404 if(st->state == RERUNLINE) {
3405 run_func(st);
3406 if(st->state == GOTO)
3407 st->state = RUN;
3408 } else if(st->state != END)
3409 st->state = RUN;
3410
3411 while(st->state == RUN)
3412 {
3413 enum c_op c = get_com(st->script->script_buf,&st->pos);
3414 switch(c){
3415 case C_EOL:
3416 if( stack->defsp > stack->sp )
3417 ShowError("script:run_script_main: unexpected stack position (defsp=%d sp=%d). please report this!!!\n", stack->defsp, stack->sp);
3418 else
3419 pop_stack(st, stack->defsp, stack->sp);// pop unused stack data. (unused return value)
3420 break;
3421 case C_INT:
3422 push_val(stack,C_INT,get_num(st->script->script_buf,&st->pos));
3423 break;
3424 case C_POS:
3425 case C_NAME:
3426 push_val(stack,c,GETVALUE(st->script->script_buf,st->pos));
3427 st->pos+=3;
3428 break;
3429 case C_ARG:
3430 push_val(stack,c,0);
3431 break;
3432 case C_STR:
3433 push_str(stack,C_CONSTSTR,(char*)(st->script->script_buf+st->pos));
3434 while(st->script->script_buf[st->pos++]);
3435 break;
3436 case C_FUNC:
3437 run_func(st);
3438 if(st->state==GOTO){
3439 st->state = RUN;
3440 if( gotocount>0 && (--gotocount)<=0 ){
3441 ShowError("run_script: infinity loop !\n");
3442 script_reportsrc(st);
3443 st->state=END;
3444 }
3445 }
3446 break;
3447
3448 case C_NEG:
3449 case C_NOT:
3450 case C_LNOT:
3451 op_1(st ,c);
3452 break;
3453
3454 case C_ADD:
3455 case C_SUB:
3456 case C_MUL:
3457 case C_DIV:
3458 case C_MOD:
3459 case C_EQ:
3460 case C_NE:
3461 case C_GT:
3462 case C_GE:
3463 case C_LT:
3464 case C_LE:
3465 case C_AND:
3466 case C_OR:
3467 case C_XOR:
3468 case C_LAND:
3469 case C_LOR:
3470 case C_R_SHIFT:
3471 case C_L_SHIFT:
3472 op_2(st, c);
3473 break;
3474
3475 case C_OP3:
3476 op_3(st, c);
3477 break;
3478
3479 case C_NOP:
3480 st->state=END;
3481 break;
3482
3483 default:
3484 ShowError("unknown command : %d @ %d\n",c,st->pos);
3485 st->state=END;
3486 break;
3487 }
3488 if( cmdcount>0 && (--cmdcount)<=0 ){
3489 ShowError("run_script: infinity loop !\n");
3490 script_reportsrc(st);
3491 st->state=END;
3492 }
3493 }
3494
3495 if(st->sleep.tick > 0) {
3496 //Restore previous script
3497 script_detach_state(st, false);
3498 //Delay execution
3499 sd = map_id2sd(st->rid); // Get sd since script might have attached someone while running. [Inkfish]
3500 st->sleep.charid = sd?sd->status.char_id:0;
3501 st->sleep.timer = add_timer(gettick()+st->sleep.tick,
3502 run_script_timer, st->sleep.charid, (intptr_t)st);
3503 linkdb_insert(&sleep_db, (void*)st->oid, st);
3504 }
3505 else if(st->state != END && st->rid){
3506 //Resume later (st is already attached to player).
3507 if(st->bk_st) {
3508 ShowWarning("Unable to restore stack! Double continuation!\n");
3509 //Report BOTH scripts to see if that can help somehow.
3510 ShowDebug("Previous script (lost):\n");
3511 script_reportsrc(st->bk_st);
3512 ShowDebug("Current script:\n");
3513 script_reportsrc(st);
3514
3515 script_free_state(st->bk_st);
3516 st->bk_st = NULL;
3517 }
3518 } else {
3519 //Dispose of script.
3520 if ((sd = map_id2sd(st->rid))!=NULL)
3521 { //Restore previous stack and save char.
3522 if(sd->state.using_fake_npc){
3523 clif_clearunit_single(sd->npc_id, CLR_OUTSIGHT, sd->fd);
3524 sd->state.using_fake_npc = 0;
3525 }
3526 //Restore previous script if any.
3527 script_detach_state(st, true);
3528 if (sd->state.reg_dirty&2)
3529 intif_saveregistry(sd,2);
3530 if (sd->state.reg_dirty&1)
3531 intif_saveregistry(sd,1);
3532 }
3533 script_free_state(st);
3534 st = NULL;
3535 }
3536}
3537
3538int script_config_read(char *cfgName)
3539{
3540 int i;
3541 char line[1024],w1[1024],w2[1024];
3542 FILE *fp;
3543
3544
3545 fp=fopen(cfgName,"r");
3546 if(fp==NULL){
3547 ShowError("file not found: [%s]\n", cfgName);
3548 return 1;
3549 }
3550 while(fgets(line, sizeof(line), fp))
3551 {
3552 if(line[0] == '/' && line[1] == '/')
3553 continue;
3554 i=sscanf(line,"%[^:]: %[^\r\n]",w1,w2);
3555 if(i!=2)
3556 continue;
3557
3558 if(strcmpi(w1,"warn_func_mismatch_paramnum")==0) {
3559 script_config.warn_func_mismatch_paramnum = config_switch(w2);
3560 }
3561 else if(strcmpi(w1,"check_cmdcount")==0) {
3562 script_config.check_cmdcount = config_switch(w2);
3563 }
3564 else if(strcmpi(w1,"check_gotocount")==0) {
3565 script_config.check_gotocount = config_switch(w2);
3566 }
3567 else if(strcmpi(w1,"input_min_value")==0) {
3568 script_config.input_min_value = config_switch(w2);
3569 }
3570 else if(strcmpi(w1,"input_max_value")==0) {
3571 script_config.input_max_value = config_switch(w2);
3572 }
3573 else if(strcmpi(w1,"warn_func_mismatch_argtypes")==0) {
3574 script_config.warn_func_mismatch_argtypes = config_switch(w2);
3575 }
3576 else if(strcmpi(w1,"import")==0){
3577 script_config_read(w2);
3578 }
3579 }
3580 fclose(fp);
3581
3582 return 0;
3583}
3584
3585static int do_final_userfunc_sub (DBKey key,void *data,va_list ap)
3586{
3587 struct script_code *code = (struct script_code *)data;
3588 if(code){
3589 script_free_vars( &code->script_vars );
3590 aFree( code->script_buf );
3591 aFree( code );
3592 }
3593 return 0;
3594}
3595
3596static int do_final_autobonus_sub (DBKey key,void *data,va_list ap)
3597{
3598 struct script_code *script = (struct script_code *)data;
3599
3600 if( script )
3601 script_free_code(script);
3602
3603 return 0;
3604}
3605
3606void script_run_autobonus(const char *autobonus, int id, int pos)
3607{
3608 struct script_code *script = (struct script_code *)strdb_get(autobonus_db, autobonus);
3609
3610 if( script )
3611 {
3612 current_equip_item_index = pos;
3613 run_script(script,0,id,0);
3614 }
3615}
3616
3617void script_add_autobonus(const char *autobonus)
3618{
3619 if( strdb_get(autobonus_db, autobonus) == NULL )
3620 {
3621 struct script_code *script = parse_script(autobonus, "autobonus", 0, 0);
3622
3623 if( script )
3624 strdb_put(autobonus_db, autobonus, script);
3625 }
3626}
3627
3628
3629/// resets a temporary character array variable to given value
3630void script_cleararray_pc(struct map_session_data* sd, const char* varname, void* value)
3631{
3632 int key;
3633 uint8 idx;
3634
3635 if( not_array_variable(varname[0]) || !not_server_variable(varname[0]) )
3636 {
3637 ShowError("script_cleararray_pc: Variable '%s' has invalid scope (char_id=%d).\n", varname, sd->status.char_id);
3638 return;
3639 }
3640
3641 key = add_str(varname);
3642
3643 if( is_string_variable(varname) )
3644 {
3645 for( idx = 0; idx < SCRIPT_MAX_ARRAYSIZE; idx++ )
3646 {
3647 pc_setregstr(sd, reference_uid(key, idx), (const char*)value);
3648 }
3649 }
3650 else
3651 {
3652 for( idx = 0; idx < SCRIPT_MAX_ARRAYSIZE; idx++ )
3653 {
3654 pc_setreg(sd, reference_uid(key, idx), (int)value);
3655 }
3656 }
3657}
3658
3659
3660/// sets a temporary character array variable element idx to given value
3661/// @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.
3662void script_setarray_pc(struct map_session_data* sd, const char* varname, uint8 idx, void* value, int* refcache)
3663{
3664 int key;
3665
3666 if( not_array_variable(varname[0]) || !not_server_variable(varname[0]) )
3667 {
3668 ShowError("script_setarray_pc: Variable '%s' has invalid scope (char_id=%d).\n", varname, sd->status.char_id);
3669 return;
3670 }
3671
3672 if( idx >= SCRIPT_MAX_ARRAYSIZE )
3673 {
3674 ShowError("script_setarray_pc: Variable '%s' has invalid index '%d' (char_id=%d).\n", varname, (int)idx, sd->status.char_id);
3675 return;
3676 }
3677
3678 key = ( refcache && refcache[0] ) ? refcache[0] : add_str(varname);
3679
3680 if( is_string_variable(varname) )
3681 {
3682 pc_setregstr(sd, reference_uid(key, idx), (const char*)value);
3683 }
3684 else
3685 {
3686 pc_setreg(sd, reference_uid(key, idx), (int)value);
3687 }
3688
3689 if( refcache )
3690 {// save to avoid repeated add_str calls
3691 refcache[0] = key;
3692 }
3693}
3694
3695
3696/*==========================================
3697 * 終了
3698 *------------------------------------------*/
3699int do_final_script()
3700{
3701#ifdef DEBUG_HASH
3702 if (battle_config.etc_log)
3703 {
3704 FILE *fp = fopen("hash_dump.txt","wt");
3705 if(fp) {
3706 int i,count[SCRIPT_HASH_SIZE];
3707 int count2[SCRIPT_HASH_SIZE]; // number of buckets with a certain number of items
3708 int n=0;
3709 int min=INT_MAX,max=0,zero=0;
3710 double mean=0.0f;
3711 double median=0.0f;
3712
3713 ShowNotice("Dumping script str hash information to hash_dump.txt\n");
3714 memset(count, 0, sizeof(count));
3715 fprintf(fp,"num : hash : data_name\n");
3716 fprintf(fp,"---------------------------------------------------------------\n");
3717 for(i=LABEL_START; i<str_num; i++) {
3718 unsigned int h = calc_hash(get_str(i));
3719 fprintf(fp,"%04d : %4u : %s\n",i,h, get_str(i));
3720 ++count[h];
3721 }
3722 fprintf(fp,"--------------------\n\n");
3723 memset(count2, 0, sizeof(count2));
3724 for(i=0; i<SCRIPT_HASH_SIZE; i++) {
3725 fprintf(fp," hash %3d = %d\n",i,count[i]);
3726 if(min > count[i])
3727 min = count[i]; // minimun count of collision
3728 if(max < count[i])
3729 max = count[i]; // maximun count of collision
3730 if(count[i] == 0)
3731 zero++;
3732 ++count2[count[i]];
3733 }
3734 fprintf(fp,"\n--------------------\n items : buckets\n--------------------\n");
3735 for( i=min; i <= max; ++i ){
3736 fprintf(fp," %5d : %7d\n",i,count2[i]);
3737 mean += 1.0f*i*count2[i]/SCRIPT_HASH_SIZE; // Note: this will always result in <nr labels>/<nr buckets>
3738 }
3739 for( i=min; i <= max; ++i ){
3740 n += count2[i];
3741 if( n*2 >= SCRIPT_HASH_SIZE )
3742 {
3743 if( SCRIPT_HASH_SIZE%2 == 0 && SCRIPT_HASH_SIZE/2 == n )
3744 median = (i+i+1)/2.0f;
3745 else
3746 median = i;
3747 break;
3748 }
3749 }
3750 fprintf(fp,"--------------------\n min = %d, max = %d, zero = %d\n mean = %lf, median = %lf\n",min,max,zero,mean,median);
3751 fclose(fp);
3752 }
3753 }
3754#endif
3755
3756 mapreg_final();
3757
3758 scriptlabel_db->destroy(scriptlabel_db,NULL);
3759 userfunc_db->destroy(userfunc_db,do_final_userfunc_sub);
3760 autobonus_db->destroy(autobonus_db, do_final_autobonus_sub);
3761 if(sleep_db) {
3762 struct linkdb_node *n = (struct linkdb_node *)sleep_db;
3763 while(n) {
3764 struct script_state *st = (struct script_state *)n->data;
3765 script_free_state(st);
3766 n = n->next;
3767 }
3768 linkdb_final(&sleep_db);
3769 }
3770
3771 if (str_data)
3772 aFree(str_data);
3773 if (str_buf)
3774 aFree(str_buf);
3775
3776 return 0;
3777}
3778/*==========================================
3779 * åˆæœŸåŒ–
3780 *------------------------------------------*/
3781int do_init_script()
3782{
3783 userfunc_db=strdb_alloc(DB_OPT_DUP_KEY,0);
3784 scriptlabel_db=strdb_alloc((DBOptions)(DB_OPT_DUP_KEY|DB_OPT_ALLOW_NULL_DATA),50);
3785 autobonus_db = strdb_alloc(DB_OPT_DUP_KEY,0);
3786
3787 mapreg_init();
3788
3789 return 0;
3790}
3791
3792int script_reload()
3793{
3794 userfunc_db->clear(userfunc_db,do_final_userfunc_sub);
3795 scriptlabel_db->clear(scriptlabel_db, NULL);
3796 npc_clear_bind_clock();
3797
3798 // clear atcmd bindings
3799 memset(atcmd_binding,0,sizeof(atcmd_binding));
3800
3801 if(sleep_db) {
3802 struct linkdb_node *n = (struct linkdb_node *)sleep_db;
3803 while(n) {
3804 struct script_state *st = (struct script_state *)n->data;
3805 script_free_state(st);
3806 n = n->next;
3807 }
3808 linkdb_final(&sleep_db);
3809 }
3810
3811 mapreg_reload();
3812 return 0;
3813}
3814
3815//-----------------------------------------------------------------------------
3816// buildin functions
3817//
3818
3819#define BUILDIN_DEF(x,args) { buildin_ ## x , #x , args }
3820#define BUILDIN_DEF2(x,x2,args) { buildin_ ## x , x2 , args }
3821#define BUILDIN_FUNC(x) int buildin_ ## x (struct script_state* st)
3822
3823/////////////////////////////////////////////////////////////////////
3824// NPC interaction
3825//
3826
3827/// Appends a message to the npc dialog.
3828/// If a dialog doesn't exist yet, one is created.
3829///
3830/// mes "<message>";
3831BUILDIN_FUNC(mes)
3832{
3833 TBL_PC* sd = script_rid2sd(st);
3834 if( sd == NULL )
3835 return 0;
3836
3837 clif_scriptmes(sd, st->oid, script_getstr(st, 2));
3838 return 0;
3839}
3840
3841/// Displays the button 'next' in the npc dialog.
3842/// The dialog text is cleared and the script continues when the button is pressed.
3843///
3844/// next;
3845BUILDIN_FUNC(next)
3846{
3847 TBL_PC* sd;
3848
3849 sd = script_rid2sd(st);
3850 if( sd == NULL )
3851 return 0;
3852
3853 st->state = STOP;
3854 clif_scriptnext(sd, st->oid);
3855 return 0;
3856}
3857
3858/// Ends the script and displays the button 'close' on the npc dialog.
3859/// The dialog is closed when the button is pressed.
3860///
3861/// close;
3862BUILDIN_FUNC(close)
3863{
3864 TBL_PC* sd;
3865
3866 sd = script_rid2sd(st);
3867 if( sd == NULL )
3868 return 0;
3869
3870 st->state = END;
3871 clif_scriptclose(sd, st->oid);
3872 return 0;
3873}
3874
3875/// Displays the button 'close' on the npc dialog.
3876/// The dialog is closed and the script continues when the button is pressed.
3877///
3878/// close2;
3879BUILDIN_FUNC(close2)
3880{
3881 TBL_PC* sd;
3882
3883 sd = script_rid2sd(st);
3884 if( sd == NULL )
3885 return 0;
3886
3887 st->state = STOP;
3888 clif_scriptclose(sd, st->oid);
3889 return 0;
3890}
3891
3892/// Counts the number of valid and total number of options in 'str'
3893/// If max_count > 0 the counting stops when that valid option is reached
3894/// total is incremented for each option (NULL is supported)
3895static int menu_countoptions(const char* str, int max_count, int* total)
3896{
3897 int count = 0;
3898 int bogus_total;
3899
3900 if( total == NULL )
3901 total = &bogus_total;
3902 ++(*total);
3903
3904 // initial empty options
3905 while( *str == ':' )
3906 {
3907 ++str;
3908 ++(*total);
3909 }
3910 // count menu options
3911 while( *str != '\0' )
3912 {
3913 ++count;
3914 --max_count;
3915 if( max_count == 0 )
3916 break;
3917 while( *str != ':' && *str != '\0' )
3918 ++str;
3919 while( *str == ':' )
3920 {
3921 ++str;
3922 ++(*total);
3923 }
3924 }
3925 return count;
3926}
3927
3928/// Displays a menu with options and goes to the target label.
3929/// The script is stopped if cancel is pressed.
3930/// Options with no text are not displayed in the client.
3931///
3932/// Options can be grouped together, separated by the character ':' in the text:
3933/// ex: menu "A:B:C",L_target;
3934/// All these options go to the specified target label.
3935///
3936/// The index of the selected option is put in the variable @menu.
3937/// Indexes start with 1 and are consistent with grouped and empty options.
3938/// ex: menu "A::B",-,"",L_Impossible,"C",-;
3939/// // displays "A", "B" and "C", corresponding to indexes 1, 3 and 5
3940///
3941/// NOTE: the client closes the npc dialog when cancel is pressed
3942///
3943/// menu "<option_text>",<target_label>{,"<option_text>",<target_label>,...};
3944BUILDIN_FUNC(menu)
3945{
3946 int i;
3947 const char* text;
3948 TBL_PC* sd;
3949
3950 sd = script_rid2sd(st);
3951 if( sd == NULL )
3952 return 0;
3953
3954 // TODO detect multiple scripts waiting for input at the same time, and what to do when that happens
3955 if( sd->state.menu_or_input == 0 )
3956 {
3957 struct StringBuf buf;
3958 struct script_data* data;
3959
3960 if( script_lastdata(st) % 2 == 0 )
3961 {// argument count is not even (1st argument is at index 2)
3962 ShowError("script:menu: illegal number of arguments (%d).\n", (script_lastdata(st) - 1));
3963 st->state = END;
3964 return 1;
3965 }
3966
3967 StringBuf_Init(&buf);
3968 sd->npc_menu = 0;
3969 for( i = 2; i < script_lastdata(st); i += 2 )
3970 {
3971 // menu options
3972 text = script_getstr(st, i);
3973
3974 // target label
3975 data = script_getdata(st, i+1);
3976 if( !data_islabel(data) )
3977 {// not a label
3978 StringBuf_Destroy(&buf);
3979 ShowError("script:menu: argument #%d (from 1) is not a label or label not found.\n", i);
3980 script_reportdata(data);
3981 st->state = END;
3982 return 1;
3983 }
3984
3985 // append option(s)
3986 if( text[0] == '\0' )
3987 continue;// empty string, ignore
3988 if( sd->npc_menu > 0 )
3989 StringBuf_AppendStr(&buf, ":");
3990 StringBuf_AppendStr(&buf, text);
3991 sd->npc_menu += menu_countoptions(text, 0, NULL);
3992 }
3993 st->state = RERUNLINE;
3994 sd->state.menu_or_input = 1;
3995 clif_scriptmenu(sd, st->oid, StringBuf_Value(&buf));
3996 StringBuf_Destroy(&buf);
3997
3998 if( sd->npc_menu >= 0xff )
3999 {// 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
4000 ShowWarning("buildin_menu: Too many options specified (current=%d, max=254).\n", sd->npc_menu);
4001 script_reportsrc(st);
4002 }
4003 }
4004 else if( sd->npc_menu == 0xff )
4005 {// Cancel was pressed
4006 sd->state.menu_or_input = 0;
4007 st->state = END;
4008 }
4009 else
4010 {// goto target label
4011 int menu = 0;
4012
4013 sd->state.menu_or_input = 0;
4014 if( sd->npc_menu <= 0 )
4015 {
4016 ShowDebug("script:menu: unexpected selection (%d)\n", sd->npc_menu);
4017 st->state = END;
4018 return 1;
4019 }
4020
4021 // get target label
4022 for( i = 2; i < script_lastdata(st); i += 2 )
4023 {
4024 text = script_getstr(st, i);
4025 sd->npc_menu -= menu_countoptions(text, sd->npc_menu, &menu);
4026 if( sd->npc_menu <= 0 )
4027 break;// entry found
4028 }
4029 if( sd->npc_menu > 0 )
4030 {// Invalid selection
4031 ShowDebug("script:menu: selection is out of range (%d pairs are missing?) - please report this\n", sd->npc_menu);
4032 st->state = END;
4033 return 1;
4034 }
4035 if( !data_islabel(script_getdata(st, i + 1)) )
4036 {// TODO remove this temporary crash-prevention code (fallback for multiple scripts requesting user input)
4037 ShowError("script:menu: unexpected data in label argument\n");
4038 script_reportdata(script_getdata(st, i + 1));
4039 st->state = END;
4040 return 1;
4041 }
4042 pc_setreg(sd, add_str("@menu"), menu);
4043 st->pos = script_getnum(st, i + 1);
4044 st->state = GOTO;
4045 }
4046 return 0;
4047}
4048
4049/// Displays a menu with options and returns the selected option.
4050/// Behaves like 'menu' without the target labels.
4051///
4052/// select(<option_text>{,<option_text>,...}) -> <selected_option>
4053///
4054/// @see menu
4055BUILDIN_FUNC(select)
4056{
4057 int i;
4058 const char* text;
4059 TBL_PC* sd;
4060
4061 sd = script_rid2sd(st);
4062 if( sd == NULL )
4063 return 0;
4064
4065 if( sd->state.menu_or_input == 0 )
4066 {
4067 struct StringBuf buf;
4068
4069 StringBuf_Init(&buf);
4070 sd->npc_menu = 0;
4071 for( i = 2; i <= script_lastdata(st); ++i )
4072 {
4073 text = script_getstr(st, i);
4074 if( sd->npc_menu > 0 )
4075 StringBuf_AppendStr(&buf, ":");
4076 StringBuf_AppendStr(&buf, text);
4077 sd->npc_menu += menu_countoptions(text, 0, NULL);
4078 }
4079
4080 st->state = RERUNLINE;
4081 sd->state.menu_or_input = 1;
4082 clif_scriptmenu(sd, st->oid, StringBuf_Value(&buf));
4083 StringBuf_Destroy(&buf);
4084
4085 if( sd->npc_menu >= 0xff )
4086 {
4087 ShowWarning("buildin_select: Too many options specified (current=%d, max=254).\n", sd->npc_menu);
4088 script_reportsrc(st);
4089 }
4090 }
4091 else if( sd->npc_menu == 0xff )
4092 {// Cancel was pressed
4093 sd->state.menu_or_input = 0;
4094 st->state = END;
4095 }
4096 else
4097 {// return selected option
4098 int menu = 0;
4099
4100 sd->state.menu_or_input = 0;
4101 for( i = 2; i <= script_lastdata(st); ++i )
4102 {
4103 text = script_getstr(st, i);
4104 sd->npc_menu -= menu_countoptions(text, sd->npc_menu, &menu);
4105 if( sd->npc_menu <= 0 )
4106 break;// entry found
4107 }
4108 pc_setreg(sd, add_str("@menu"), menu);
4109 script_pushint(st, menu);
4110 st->state = RUN;
4111 }
4112 return 0;
4113}
4114
4115/// Displays a menu with options and returns the selected option.
4116/// Behaves like 'menu' without the target labels, except when cancel is
4117/// pressed.
4118/// When cancel is pressed, the script continues and 255 is returned.
4119///
4120/// prompt(<option_text>{,<option_text>,...}) -> <selected_option>
4121///
4122/// @see menu
4123BUILDIN_FUNC(prompt)
4124{
4125 int i;
4126 const char *text;
4127 TBL_PC* sd;
4128
4129 sd = script_rid2sd(st);
4130 if( sd == NULL )
4131 return 0;
4132
4133 if( sd->state.menu_or_input == 0 )
4134 {
4135 struct StringBuf buf;
4136
4137 StringBuf_Init(&buf);
4138 sd->npc_menu = 0;
4139 for( i = 2; i <= script_lastdata(st); ++i )
4140 {
4141 text = script_getstr(st, i);
4142 if( sd->npc_menu > 0 )
4143 StringBuf_AppendStr(&buf, ":");
4144 StringBuf_AppendStr(&buf, text);
4145 sd->npc_menu += menu_countoptions(text, 0, NULL);
4146 }
4147
4148 st->state = RERUNLINE;
4149 sd->state.menu_or_input = 1;
4150 clif_scriptmenu(sd, st->oid, StringBuf_Value(&buf));
4151 StringBuf_Destroy(&buf);
4152
4153 if( sd->npc_menu >= 0xff )
4154 {
4155 ShowWarning("buildin_prompt: Too many options specified (current=%d, max=254).\n", sd->npc_menu);
4156 script_reportsrc(st);
4157 }
4158 }
4159 else if( sd->npc_menu == 0xff )
4160 {// Cancel was pressed
4161 sd->state.menu_or_input = 0;
4162 pc_setreg(sd, add_str("@menu"), 0xff);
4163 script_pushint(st, 0xff);
4164 st->state = RUN;
4165 }
4166 else
4167 {// return selected option
4168 int menu = 0;
4169
4170 sd->state.menu_or_input = 0;
4171 for( i = 2; i <= script_lastdata(st); ++i )
4172 {
4173 text = script_getstr(st, i);
4174 sd->npc_menu -= menu_countoptions(text, sd->npc_menu, &menu);
4175 if( sd->npc_menu <= 0 )
4176 break;// entry found
4177 }
4178 pc_setreg(sd, add_str("@menu"), menu);
4179 script_pushint(st, menu);
4180 st->state = RUN;
4181 }
4182 return 0;
4183}
4184
4185/////////////////////////////////////////////////////////////////////
4186// ...
4187//
4188
4189/// Jumps to the target script label.
4190///
4191/// goto <label>;
4192BUILDIN_FUNC(goto)
4193{
4194 if( !data_islabel(script_getdata(st,2)) )
4195 {
4196 ShowError("script:goto: not a label\n");
4197 script_reportdata(script_getdata(st,2));
4198 st->state = END;
4199 return 1;
4200 }
4201
4202 st->pos = script_getnum(st,2);
4203 st->state = GOTO;
4204 return 0;
4205}
4206
4207/*==========================================
4208 * user-defined function call
4209 *------------------------------------------*/
4210BUILDIN_FUNC(callfunc)
4211{
4212 int i, j;
4213 struct script_retinfo* ri;
4214 struct script_code* scr;
4215 const char* str = script_getstr(st,2);
4216
4217 scr = (struct script_code*)strdb_get(userfunc_db, str);
4218 if( !scr )
4219 {
4220 ShowError("script:callfunc: function not found! [%s]\n", str);
4221 st->state = END;
4222 return 1;
4223 }
4224
4225 for( i = st->start+3, j = 0; i < st->end; i++, j++ )
4226 {
4227 struct script_data* data = push_copy(st->stack,i);
4228 if( data_isreference(data) && !data->ref )
4229 {
4230 const char* name = reference_getname(data);
4231 if( name[0] == '.' && name[1] == '@' )
4232 data->ref = st->stack->var_function;
4233 else if( name[0] == '.' )
4234 data->ref = &st->script->script_vars;
4235 }
4236 }
4237
4238 CREATE(ri, struct script_retinfo, 1);
4239 ri->script = st->script;// script code
4240 ri->var_function = st->stack->var_function;// scope variables
4241 ri->pos = st->pos;// script location
4242 ri->nargs = j;// argument count
4243 ri->defsp = st->stack->defsp;// default stack pointer
4244 push_retinfo(st->stack, ri);
4245
4246 st->pos = 0;
4247 st->script = scr;
4248 st->stack->defsp = st->stack->sp;
4249 st->state = GOTO;
4250 st->stack->var_function = (struct linkdb_node**)aCalloc(1, sizeof(struct linkdb_node*));
4251
4252 return 0;
4253}
4254/*==========================================
4255 * subroutine call
4256 *------------------------------------------*/
4257BUILDIN_FUNC(callsub)
4258{
4259 int i,j;
4260 struct script_retinfo* ri;
4261 int pos = script_getnum(st,2);
4262
4263 if( !data_islabel(script_getdata(st,2)) && !data_isfunclabel(script_getdata(st,2)) )
4264 {
4265 ShowError("script:callsub: argument is not a label\n");
4266 script_reportdata(script_getdata(st,2));
4267 st->state = END;
4268 return 1;
4269 }
4270
4271 for( i = st->start+3, j = 0; i < st->end; i++, j++ )
4272 {
4273 struct script_data* data = push_copy(st->stack,i);
4274 if( data_isreference(data) && !data->ref )
4275 {
4276 const char* name = reference_getname(data);
4277 if( name[0] == '.' && name[1] == '@' )
4278 data->ref = st->stack->var_function;
4279 }
4280 }
4281
4282 CREATE(ri, struct script_retinfo, 1);
4283 ri->script = st->script;// script code
4284 ri->var_function = st->stack->var_function;// scope variables
4285 ri->pos = st->pos;// script location
4286 ri->nargs = j;// argument count
4287 ri->defsp = st->stack->defsp;// default stack pointer
4288 push_retinfo(st->stack, ri);
4289
4290 st->pos = pos;
4291 st->stack->defsp = st->stack->sp;
4292 st->state = GOTO;
4293 st->stack->var_function = (struct linkdb_node**)aCalloc(1, sizeof(struct linkdb_node*));
4294
4295 return 0;
4296}
4297
4298/// Retrieves an argument provided to callfunc/callsub.
4299/// If the argument doesn't exist
4300///
4301/// getarg(<index>{,<default_value>}) -> <value>
4302BUILDIN_FUNC(getarg)
4303{
4304 struct script_retinfo* ri;
4305 int idx;
4306
4307 if( st->stack->defsp < 1 || st->stack->stack_data[st->stack->defsp - 1].type != C_RETINFO )
4308 {
4309 ShowError("script:getarg: no callfunc or callsub!\n");
4310 st->state = END;
4311 return 1;
4312 }
4313 ri = st->stack->stack_data[st->stack->defsp - 1].u.ri;
4314
4315 idx = script_getnum(st,2);
4316
4317 if( idx >= 0 && idx < ri->nargs )
4318 push_copy(st->stack, st->stack->defsp - 1 - ri->nargs + idx);
4319 else if( script_hasdata(st,3) )
4320 script_pushcopy(st, 3);
4321 else
4322 {
4323 ShowError("script:getarg: index (idx=%d) out of range (nargs=%d) and no default value found\n", idx, ri->nargs);
4324 st->state = END;
4325 return 1;
4326 }
4327
4328 return 0;
4329}
4330
4331/// Returns from the current function, optionaly returning a value from the functions.
4332/// Don't use outside script functions.
4333///
4334/// return;
4335/// return <value>;
4336BUILDIN_FUNC(return)
4337{
4338 if( script_hasdata(st,2) )
4339 {// return value
4340 struct script_data* data;
4341 script_pushcopy(st, 2);
4342 data = script_getdatatop(st, -1);
4343 if( data_isreference(data) )
4344 {
4345 const char* name = reference_getname(data);
4346 if( name[0] == '.' && name[1] == '@' )
4347 {// scope variable
4348 if( !data->ref || data->ref == st->stack->var_function )
4349 get_val(st, data);// current scope, convert to value
4350 }
4351 else if( name[0] == '.' && !data->ref )
4352 {// script variable, link to current script
4353 data->ref = &st->script->script_vars;
4354 }
4355 }
4356 }
4357 else
4358 {// no return value
4359 script_pushnil(st);
4360 }
4361 st->state = RETFUNC;
4362 return 0;
4363}
4364
4365/// Returns a random number from 0 to <range>-1.
4366/// Or returns a random number from <min> to <max>.
4367/// If <min> is greater than <max>, their numbers are switched.
4368/// rand(<range>) -> <int>
4369/// rand(<min>,<max>) -> <int>
4370BUILDIN_FUNC(rand)
4371{
4372 int range;
4373 int min;
4374 int max;
4375
4376 if( script_hasdata(st,3) )
4377 {// min,max
4378 min = script_getnum(st,2);
4379 max = script_getnum(st,3);
4380 if( max < min )
4381 swap(min, max);
4382 range = max - min + 1;
4383 }
4384 else
4385 {// range
4386 min = 0;
4387 range = script_getnum(st,2);
4388 }
4389 if( range <= 1 )
4390 script_pushint(st, min);
4391 else
4392 script_pushint(st, rand()%range + min);
4393
4394 return 0;
4395}
4396
4397/*==========================================
4398 *
4399 *------------------------------------------*/
4400BUILDIN_FUNC(warp)
4401{
4402 int ret;
4403 int x,y;
4404 const char* str;
4405 TBL_PC* sd;
4406
4407 sd = script_rid2sd(st);
4408 if( sd == NULL )
4409 return 0;
4410
4411 str = script_getstr(st,2);
4412 x = script_getnum(st,3);
4413 y = script_getnum(st,4);
4414
4415 if(strcmp(str,"Random")==0)
4416 ret = pc_randomwarp(sd,CLR_TELEPORT);
4417 else if(strcmp(str,"SavePoint")==0 || strcmp(str,"Save")==0)
4418 ret = pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
4419 else
4420 ret = pc_setpos(sd,mapindex_name2id(str),x,y,CLR_OUTSIGHT);
4421
4422 if( ret ) {
4423 ShowError("buildin_warp: moving player '%s' to \"%s\",%d,%d failed.\n", sd->status.name, str, x, y);
4424 script_reportsrc(st);
4425 }
4426
4427 return 0;
4428}
4429/*==========================================
4430 * エリア指定ワープ
4431 *------------------------------------------*/
4432static int buildin_areawarp_sub(struct block_list *bl,va_list ap)
4433{
4434 int x,y,ax,ay;
4435 unsigned int map;
4436 map=va_arg(ap, unsigned int);
4437 x=va_arg(ap,int);
4438 y=va_arg(ap,int);
4439 ax=va_arg(ap,int);
4440 ay=va_arg(ap,int);
4441
4442 if( map == 0 )
4443 pc_randomwarp((TBL_PC *)bl,CLR_TELEPORT);
4444 else if( ax && ay )
4445 {
4446 int tx, ty, max, j = 0;
4447 if( (max = (ay-y+1)*(ax-x+1)*3) > 1000 )
4448 max = 1000;
4449
4450 do {
4451 tx = rand()%(ax-x+1)+x;
4452 ty = rand()%(ay-y+1)+y;
4453 j++;
4454 } while( map_getcell(map,tx,ty,CELL_CHKNOPASS) && j < max );
4455 pc_setpos((TBL_PC *)bl,map,tx,ty,CLR_OUTSIGHT);
4456 }
4457 else
4458 pc_setpos((TBL_PC *)bl,map,x,y,CLR_OUTSIGHT);
4459 return 0;
4460}
4461BUILDIN_FUNC(areawarp)
4462{
4463 int x,y,m;
4464 unsigned int index;
4465 const char *str;
4466 const char *mapname;
4467 int x0,y0,x1,y1,ax = 0,ay = 0;
4468
4469 mapname=script_getstr(st,2);
4470 x0=script_getnum(st,3);
4471 y0=script_getnum(st,4);
4472 x1=script_getnum(st,5);
4473 y1=script_getnum(st,6);
4474 str=script_getstr(st,7);
4475 x=script_getnum(st,8);
4476 y=script_getnum(st,9);
4477 if( script_hasdata(st,10) && script_hasdata(st,11) )
4478 { // Area Warp to Area
4479 if( (ax = script_getnum(st,10)) < 0 )
4480 ax = 0;
4481 if( (ay = script_getnum(st,11)) < 0 )
4482 ay = 0;
4483 if( ax && ay )
4484 {
4485 if( ax < x ) swap(ax,x);
4486 if( ay < y ) swap(ay,y);
4487 }
4488 else
4489 {
4490 ax = 0;
4491 ay = 0;
4492 }
4493 }
4494
4495 if( (m=map_mapname2mapid(mapname))< 0)
4496 return 0;
4497
4498 if(strcmp(str,"Random")==0)
4499 index = 0;
4500 else if(!(index=mapindex_name2id(str)))
4501 return 0;
4502
4503 map_foreachinarea(buildin_areawarp_sub, m,x0,y0,x1,y1,BL_PC, index,x,y,ax,ay);
4504 return 0;
4505}
4506
4507/*==========================================
4508 * areapercentheal <map>,<x1>,<y1>,<x2>,<y2>,<hp>,<sp>
4509 *------------------------------------------*/
4510static int buildin_areapercentheal_sub(struct block_list *bl,va_list ap)
4511{
4512 int hp, sp;
4513 hp = va_arg(ap, int);
4514 sp = va_arg(ap, int);
4515 pc_percentheal((TBL_PC *)bl,hp,sp);
4516 return 0;
4517}
4518BUILDIN_FUNC(areapercentheal)
4519{
4520 int hp,sp,m;
4521 const char *mapname;
4522 int x0,y0,x1,y1;
4523
4524 mapname=script_getstr(st,2);
4525 x0=script_getnum(st,3);
4526 y0=script_getnum(st,4);
4527 x1=script_getnum(st,5);
4528 y1=script_getnum(st,6);
4529 hp=script_getnum(st,7);
4530 sp=script_getnum(st,8);
4531
4532 if( (m=map_mapname2mapid(mapname))< 0)
4533 return 0;
4534
4535 map_foreachinarea(buildin_areapercentheal_sub,m,x0,y0,x1,y1,BL_PC,hp,sp);
4536 return 0;
4537}
4538
4539/*==========================================
4540 * warpchar [LuzZza]
4541 * Useful for warp one player from
4542 * another player npc-session.
4543 * Using: warpchar "mapname",x,y,Char_ID;
4544 *------------------------------------------*/
4545BUILDIN_FUNC(warpchar)
4546{
4547 int x,y,a;
4548 const char *str;
4549 TBL_PC *sd;
4550
4551 str=script_getstr(st,2);
4552 x=script_getnum(st,3);
4553 y=script_getnum(st,4);
4554 a=script_getnum(st,5);
4555
4556 sd = map_charid2sd(a);
4557 if( sd == NULL )
4558 return 0;
4559
4560 if(strcmp(str, "Random") == 0)
4561 pc_randomwarp(sd, CLR_TELEPORT);
4562 else
4563 if(strcmp(str, "SavePoint") == 0)
4564 pc_setpos(sd, sd->status.save_point.map,sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT);
4565 else
4566 pc_setpos(sd, mapindex_name2id(str), x, y, CLR_TELEPORT);
4567
4568 return 0;
4569}
4570/*==========================================
4571 * Warpparty - [Fredzilla] [Paradox924X]
4572 * Syntax: warpparty "to_mapname",x,y,Party_ID,{"from_mapname"};
4573 * If 'from_mapname' is specified, only the party members on that map will be warped
4574 *------------------------------------------*/
4575BUILDIN_FUNC(warpparty)
4576{
4577 TBL_PC *sd = NULL;
4578 TBL_PC *pl_sd;
4579 struct party_data* p;
4580 int type;
4581 int mapindex;
4582 int i;
4583
4584 const char* str = script_getstr(st,2);
4585 int x = script_getnum(st,3);
4586 int y = script_getnum(st,4);
4587 int p_id = script_getnum(st,5);
4588 const char* str2 = NULL;
4589 if ( script_hasdata(st,6) )
4590 str2 = script_getstr(st,6);
4591
4592 p = party_search(p_id);
4593 if(!p)
4594 return 0;
4595
4596 type = ( strcmp(str,"Random")==0 ) ? 0
4597 : ( strcmp(str,"SavePointAll")==0 ) ? 1
4598 : ( strcmp(str,"SavePoint")==0 ) ? 2
4599 : ( strcmp(str,"Leader")==0 ) ? 3
4600 : 4;
4601
4602 switch (type)
4603 {
4604 case 3:
4605 for(i = 0; i < MAX_PARTY && !p->party.member[i].leader; i++);
4606 if (i == MAX_PARTY || !p->data[i].sd) //Leader not found / not online
4607 return 0;
4608 pl_sd = p->data[i].sd;
4609 mapindex = pl_sd->mapindex;
4610 x = pl_sd->bl.x;
4611 y = pl_sd->bl.y;
4612 break;
4613 case 4:
4614 mapindex = mapindex_name2id(str);
4615 break;
4616 case 2:
4617 //"SavePoint" uses save point of the currently attached player
4618 if (( sd = script_rid2sd(st) ) == NULL )
4619 return 0;
4620 default:
4621 mapindex = 0;
4622 break;
4623 }
4624
4625 for (i = 0; i < MAX_PARTY; i++)
4626 {
4627 if( !(pl_sd = p->data[i].sd) || pl_sd->status.party_id != p_id )
4628 continue;
4629
4630 if( str2 && strcmp(str2, map[pl_sd->bl.m].name) != 0 )
4631 continue;
4632
4633 if( pc_isdead(pl_sd) )
4634 continue;
4635
4636 switch( type )
4637 {
4638 case 0: // Random
4639 if(!map[pl_sd->bl.m].flag.nowarp)
4640 pc_randomwarp(pl_sd,CLR_TELEPORT);
4641 break;
4642 case 1: // SavePointAll
4643 if(!map[pl_sd->bl.m].flag.noreturn)
4644 pc_setpos(pl_sd,pl_sd->status.save_point.map,pl_sd->status.save_point.x,pl_sd->status.save_point.y,CLR_TELEPORT);
4645 break;
4646 case 2: // SavePoint
4647 if(!map[pl_sd->bl.m].flag.noreturn)
4648 pc_setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
4649 break;
4650 case 3: // Leader
4651 case 4: // m,x,y
4652 if(!map[pl_sd->bl.m].flag.noreturn && !map[pl_sd->bl.m].flag.nowarp)
4653 pc_setpos(pl_sd,mapindex,x,y,CLR_TELEPORT);
4654 break;
4655 }
4656 }
4657
4658 return 0;
4659}
4660/*==========================================
4661 * Warpguild - [Fredzilla]
4662 * Syntax: warpguild "mapname",x,y,Guild_ID;
4663 *------------------------------------------*/
4664BUILDIN_FUNC(warpguild)
4665{
4666 TBL_PC *sd = NULL;
4667 TBL_PC *pl_sd;
4668 struct guild* g;
4669 struct s_mapiterator* iter;
4670 int type;
4671
4672 const char* str = script_getstr(st,2);
4673 int x = script_getnum(st,3);
4674 int y = script_getnum(st,4);
4675 int gid = script_getnum(st,5);
4676
4677 g = guild_search(gid);
4678 if( g == NULL )
4679 return 0;
4680
4681 type = ( strcmp(str,"Random")==0 ) ? 0
4682 : ( strcmp(str,"SavePointAll")==0 ) ? 1
4683 : ( strcmp(str,"SavePoint")==0 ) ? 2
4684 : 3;
4685
4686 if( type == 2 && ( sd = script_rid2sd(st) ) == NULL )
4687 {// "SavePoint" uses save point of the currently attached player
4688 return 0;
4689 }
4690
4691 iter = mapit_getallusers();
4692 for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
4693 {
4694 if( pl_sd->status.guild_id != gid )
4695 continue;
4696
4697 switch( type )
4698 {
4699 case 0: // Random
4700 if(!map[pl_sd->bl.m].flag.nowarp)
4701 pc_randomwarp(pl_sd,CLR_TELEPORT);
4702 break;
4703 case 1: // SavePointAll
4704 if(!map[pl_sd->bl.m].flag.noreturn)
4705 pc_setpos(pl_sd,pl_sd->status.save_point.map,pl_sd->status.save_point.x,pl_sd->status.save_point.y,CLR_TELEPORT);
4706 break;
4707 case 2: // SavePoint
4708 if(!map[pl_sd->bl.m].flag.noreturn)
4709 pc_setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
4710 break;
4711 case 3: // m,x,y
4712 if(!map[pl_sd->bl.m].flag.noreturn && !map[pl_sd->bl.m].flag.nowarp)
4713 pc_setpos(pl_sd,mapindex_name2id(str),x,y,CLR_TELEPORT);
4714 break;
4715 }
4716 }
4717 mapit_free(iter);
4718
4719 return 0;
4720}
4721/*==========================================
4722 *
4723 *------------------------------------------*/
4724BUILDIN_FUNC(heal)
4725{
4726 TBL_PC *sd;
4727 int hp,sp;
4728
4729 sd = script_rid2sd(st);
4730 if (!sd) return 0;
4731
4732 hp=script_getnum(st,2);
4733 sp=script_getnum(st,3);
4734 status_heal(&sd->bl, hp, sp, 1);
4735 return 0;
4736}
4737/*==========================================
4738 *
4739 *------------------------------------------*/
4740BUILDIN_FUNC(itemheal)
4741{
4742 TBL_PC *sd;
4743 int hp,sp;
4744
4745 hp=script_getnum(st,2);
4746 sp=script_getnum(st,3);
4747
4748 if(potion_flag==1) {
4749 potion_hp = hp;
4750 potion_sp = sp;
4751 return 0;
4752 }
4753
4754 sd = script_rid2sd(st);
4755 if (!sd) return 0;
4756 pc_itemheal(sd,sd->itemid,hp,sp);
4757 return 0;
4758}
4759/*==========================================
4760 *
4761 *------------------------------------------*/
4762BUILDIN_FUNC(percentheal)
4763{
4764 int hp,sp;
4765 TBL_PC* sd;
4766
4767 hp=script_getnum(st,2);
4768 sp=script_getnum(st,3);
4769
4770 if(potion_flag==1) {
4771 potion_per_hp = hp;
4772 potion_per_sp = sp;
4773 return 0;
4774 }
4775
4776 sd = script_rid2sd(st);
4777 if( sd == NULL )
4778 return 0;
4779
4780 pc_percentheal(sd,hp,sp);
4781 return 0;
4782}
4783
4784/*==========================================
4785 *
4786 *------------------------------------------*/
4787BUILDIN_FUNC(jobchange)
4788{
4789 int job, upper=-1;
4790
4791 job=script_getnum(st,2);
4792 if( script_hasdata(st,3) )
4793 upper=script_getnum(st,3);
4794
4795 if (pcdb_checkid(job))
4796 {
4797 TBL_PC* sd;
4798
4799 sd = script_rid2sd(st);
4800 if( sd == NULL )
4801 return 0;
4802
4803 pc_jobchange(sd, job, upper);
4804 }
4805
4806 return 0;
4807}
4808
4809/*==========================================
4810 *
4811 *------------------------------------------*/
4812BUILDIN_FUNC(jobname)
4813{
4814 int class_=script_getnum(st,2);
4815 script_pushconststr(st, (char*)job_name(class_));
4816 return 0;
4817}
4818
4819/// Get input from the player.
4820/// For numeric inputs the value is capped to the range [min,max]. Returns 1 if
4821/// the value was higher than 'max', -1 if lower than 'min' and 0 otherwise.
4822/// For string inputs it returns 1 if the string was longer than 'max', -1 is
4823/// shorter than 'min' and 0 otherwise.
4824///
4825/// input(<var>{,<min>{,<max>}}) -> <int>
4826BUILDIN_FUNC(input)
4827{
4828 TBL_PC* sd;
4829 struct script_data* data;
4830 int uid;
4831 const char* name;
4832 int min;
4833 int max;
4834
4835 sd = script_rid2sd(st);
4836 if( sd == NULL )
4837 return 0;
4838
4839 data = script_getdata(st,2);
4840 if( !data_isreference(data) ){
4841 ShowError("script:input: not a variable\n");
4842 script_reportdata(data);
4843 st->state = END;
4844 return 1;
4845 }
4846 uid = reference_getuid(data);
4847 name = reference_getname(data);
4848 min = (script_hasdata(st,3) ? script_getnum(st,3) : script_config.input_min_value);
4849 max = (script_hasdata(st,4) ? script_getnum(st,4) : script_config.input_max_value);
4850
4851 if( !sd->state.menu_or_input )
4852 { // first invocation, display npc input box
4853 sd->state.menu_or_input = 1;
4854 st->state = RERUNLINE;
4855 if( is_string_variable(name) )
4856 clif_scriptinputstr(sd,st->oid);
4857 else
4858 clif_scriptinput(sd,st->oid);
4859 }
4860 else
4861 { // take received text/value and store it in the designated variable
4862 sd->state.menu_or_input = 0;
4863 if( is_string_variable(name) )
4864 {
4865 int len = (int)strlen(sd->npc_str);
4866 set_reg(st, sd, uid, name, (void*)sd->npc_str, script_getref(st,2));
4867 script_pushint(st, (len > max ? 1 : len < min ? -1 : 0));
4868 }
4869 else
4870 {
4871 int amount = sd->npc_amount;
4872 set_reg(st, sd, uid, name, (void*)cap_value(amount,min,max), script_getref(st,2));
4873 script_pushint(st, (amount > max ? 1 : amount < min ? -1 : 0));
4874 }
4875 st->state = RUN;
4876 }
4877 return 0;
4878}
4879
4880/// Sets the value of a variable.
4881/// The value is converted to the type of the variable.
4882///
4883/// set(<variable>,<value>) -> <variable>
4884BUILDIN_FUNC(set)
4885{
4886 TBL_PC* sd = NULL;
4887 struct script_data* data;
4888 int num;
4889 const char* name;
4890 char prefix;
4891
4892 data = script_getdata(st,2);
4893 if( !data_isreference(data) )
4894 {
4895 ShowError("script:set: not a variable\n");
4896 script_reportdata(script_getdata(st,2));
4897 st->state = END;
4898 return 1;
4899 }
4900
4901 num = reference_getuid(data);
4902 name = reference_getname(data);
4903 prefix = *name;
4904
4905 if( not_server_variable(prefix) )
4906 {
4907 sd = script_rid2sd(st);
4908 if( sd == NULL )
4909 {
4910 ShowError("script:set: no player attached for player variable '%s'\n", name);
4911 return 0;
4912 }
4913 }
4914
4915 if( is_string_variable(name) )
4916 set_reg(st,sd,num,name,(void*)script_getstr(st,3),script_getref(st,2));
4917 else
4918 set_reg(st,sd,num,name,(void*)script_getnum(st,3),script_getref(st,2));
4919
4920 // return a copy of the variable reference
4921 script_pushcopy(st,2);
4922
4923 return 0;
4924}
4925
4926/////////////////////////////////////////////////////////////////////
4927/// Array variables
4928///
4929
4930/// Returns the size of the specified array
4931static int32 getarraysize(struct script_state* st, int32 id, int32 idx, int isstring, struct linkdb_node** ref)
4932{
4933 int32 ret = idx;
4934
4935 if( isstring )
4936 {
4937 for( ; idx < SCRIPT_MAX_ARRAYSIZE; ++idx )
4938 {
4939 char* str = (char*)get_val2(st, reference_uid(id, idx), ref);
4940 if( str && *str )
4941 ret = idx + 1;
4942 script_removetop(st, -1, 0);
4943 }
4944 }
4945 else
4946 {
4947 for( ; idx < SCRIPT_MAX_ARRAYSIZE; ++idx )
4948 {
4949 int32 num = (int32)get_val2(st, reference_uid(id, idx), ref);
4950 if( num )
4951 ret = idx + 1;
4952 script_removetop(st, -1, 0);
4953 }
4954 }
4955 return ret;
4956}
4957
4958/// Sets values of an array, from the starting index.
4959/// ex: setarray arr[1],1,2,3;
4960///
4961/// setarray <array variable>,<value1>{,<value2>...};
4962BUILDIN_FUNC(setarray)
4963{
4964 struct script_data* data;
4965 const char* name;
4966 int32 start;
4967 int32 end;
4968 int32 id;
4969 int32 i;
4970 TBL_PC* sd = NULL;
4971
4972 data = script_getdata(st, 2);
4973 if( !data_isreference(data) )
4974 {
4975 ShowError("script:setarray: not a variable\n");
4976 script_reportdata(data);
4977 st->state = END;
4978 return 1;// not a variable
4979 }
4980
4981 id = reference_getid(data);
4982 start = reference_getindex(data);
4983 name = reference_getname(data);
4984 if( not_array_variable(*name) )
4985 {
4986 ShowError("script:setarray: illegal scope\n");
4987 script_reportdata(data);
4988 st->state = END;
4989 return 1;// not supported
4990 }
4991
4992 if( not_server_variable(*name) )
4993 {
4994 sd = script_rid2sd(st);
4995 if( sd == NULL )
4996 return 0;// no player attached
4997 }
4998
4999 end = start + script_lastdata(st) - 2;
5000 if( end > SCRIPT_MAX_ARRAYSIZE )
5001 end = SCRIPT_MAX_ARRAYSIZE;
5002
5003 if( is_string_variable(name) )
5004 {// string array
5005 for( i = 3; start < end; ++start, ++i )
5006 set_reg(st, sd, reference_uid(id, start), name, (void*)script_getstr(st,i), reference_getref(data));
5007 }
5008 else
5009 {// int array
5010 for( i = 3; start < end; ++start, ++i )
5011 set_reg(st, sd, reference_uid(id, start), name, (void*)script_getnum(st,i), reference_getref(data));
5012 }
5013 return 0;
5014}
5015
5016/// Sets count values of an array, from the starting index.
5017/// ex: cleararray arr[0],0,1;
5018///
5019/// cleararray <array variable>,<value>,<count>;
5020BUILDIN_FUNC(cleararray)
5021{
5022 struct script_data* data;
5023 const char* name;
5024 int32 start;
5025 int32 end;
5026 int32 id;
5027 void* v;
5028 TBL_PC* sd = NULL;
5029
5030 data = script_getdata(st, 2);
5031 if( !data_isreference(data) )
5032 {
5033 ShowError("script:cleararray: not a variable\n");
5034 script_reportdata(data);
5035 st->state = END;
5036 return 1;// not a variable
5037 }
5038
5039 id = reference_getid(data);
5040 start = reference_getindex(data);
5041 name = reference_getname(data);
5042 if( not_array_variable(*name) )
5043 {
5044 ShowError("script:cleararray: illegal scope\n");
5045 script_reportdata(data);
5046 st->state = END;
5047 return 1;// not supported
5048 }
5049
5050 if( not_server_variable(*name) )
5051 {
5052 sd = script_rid2sd(st);
5053 if( sd == NULL )
5054 return 0;// no player attached
5055 }
5056
5057 if( is_string_variable(name) )
5058 v = (void*)script_getstr(st, 3);
5059 else
5060 v = (void*)script_getnum(st, 3);
5061
5062 end = start + script_getnum(st, 4);
5063 if( end > SCRIPT_MAX_ARRAYSIZE )
5064 end = SCRIPT_MAX_ARRAYSIZE;
5065
5066 for( ; start < end; ++start )
5067 set_reg(st, sd, reference_uid(id, start), name, v, script_getref(st,2));
5068 return 0;
5069}
5070
5071/// Copies data from one array to another.
5072/// ex: copyarray arr[0],arr[2],2;
5073///
5074/// copyarray <destination array variable>,<source array variable>,<count>;
5075BUILDIN_FUNC(copyarray)
5076{
5077 struct script_data* data1;
5078 struct script_data* data2;
5079 const char* name1;
5080 const char* name2;
5081 int32 idx1;
5082 int32 idx2;
5083 int32 id1;
5084 int32 id2;
5085 void* v;
5086 int32 i;
5087 int32 count;
5088 TBL_PC* sd = NULL;
5089
5090 data1 = script_getdata(st, 2);
5091 data2 = script_getdata(st, 3);
5092 if( !data_isreference(data1) || !data_isreference(data2) )
5093 {
5094 ShowError("script:copyarray: not a variable\n");
5095 script_reportdata(data1);
5096 script_reportdata(data2);
5097 st->state = END;
5098 return 1;// not a variable
5099 }
5100
5101 id1 = reference_getid(data1);
5102 id2 = reference_getid(data2);
5103 idx1 = reference_getindex(data1);
5104 idx2 = reference_getindex(data2);
5105 name1 = reference_getname(data1);
5106 name2 = reference_getname(data2);
5107 if( not_array_variable(*name1) || not_array_variable(*name2) )
5108 {
5109 ShowError("script:copyarray: illegal scope\n");
5110 script_reportdata(data1);
5111 script_reportdata(data2);
5112 st->state = END;
5113 return 1;// not supported
5114 }
5115
5116 if( is_string_variable(name1) != is_string_variable(name2) )
5117 {
5118 ShowError("script:copyarray: type mismatch\n");
5119 script_reportdata(data1);
5120 script_reportdata(data2);
5121 st->state = END;
5122 return 1;// data type mismatch
5123 }
5124
5125 if( not_server_variable(*name1) || not_server_variable(*name2) )
5126 {
5127 sd = script_rid2sd(st);
5128 if( sd == NULL )
5129 return 0;// no player attached
5130 }
5131
5132 count = script_getnum(st, 4);
5133 if( count > SCRIPT_MAX_ARRAYSIZE - idx1 )
5134 count = SCRIPT_MAX_ARRAYSIZE - idx1;
5135 if( count <= 0 || (id1 == id2 && idx1 == idx2) )
5136 return 0;// nothing to copy
5137
5138 if( id1 == id2 && idx1 > idx2 )
5139 {// destination might be overlapping the source - copy in reverse order
5140 for( i = count - 1; i >= 0; --i )
5141 {
5142 v = get_val2(st, reference_uid(id2, idx2 + i), reference_getref(data2));
5143 set_reg(st, sd, reference_uid(id1, idx1 + i), name1, v, reference_getref(data1));
5144 script_removetop(st, -1, 0);
5145 }
5146 }
5147 else
5148 {// normal copy
5149 for( i = 0; i < count; ++i )
5150 {
5151 if( idx2 + i < SCRIPT_MAX_ARRAYSIZE )
5152 {
5153 v = get_val2(st, reference_uid(id2, idx2 + i), reference_getref(data2));
5154 set_reg(st, sd, reference_uid(id1, idx1 + i), name1, v, reference_getref(data1));
5155 script_removetop(st, -1, 0);
5156 }
5157 else// out of range - assume ""/0
5158 set_reg(st, sd, reference_uid(id1, idx1 + i), name1, (is_string_variable(name1)?(void*)"":(void*)0), reference_getref(data1));
5159 }
5160 }
5161 return 0;
5162}
5163
5164/// Returns the size of the array.
5165/// Assumes that everything before the starting index exists.
5166/// ex: getarraysize(arr[3])
5167///
5168/// getarraysize(<array variable>) -> <int>
5169BUILDIN_FUNC(getarraysize)
5170{
5171 struct script_data* data;
5172 const char* name;
5173
5174 data = script_getdata(st, 2);
5175 if( !data_isreference(data) )
5176 {
5177 ShowError("script:getarraysize: not a variable\n");
5178 script_reportdata(data);
5179 script_pushnil(st);
5180 st->state = END;
5181 return 1;// not a variable
5182 }
5183
5184 name = reference_getname(data);
5185 if( not_array_variable(*name) )
5186 {
5187 ShowError("script:getarraysize: illegal scope\n");
5188 script_reportdata(data);
5189 script_pushnil(st);
5190 st->state = END;
5191 return 1;// not supported
5192 }
5193
5194 script_pushint(st, getarraysize(st, reference_getid(data), reference_getindex(data), is_string_variable(name), reference_getref(data)));
5195 return 0;
5196}
5197
5198/// Deletes count or all the elements in an array, from the starting index.
5199/// ex: deletearray arr[4],2;
5200///
5201/// deletearray <array variable>;
5202/// deletearray <array variable>,<count>;
5203BUILDIN_FUNC(deletearray)
5204{
5205 struct script_data* data;
5206 const char* name;
5207 int start;
5208 int end;
5209 int id;
5210 TBL_PC *sd = NULL;
5211
5212 data = script_getdata(st, 2);
5213 if( !data_isreference(data) )
5214 {
5215 ShowError("script:deletearray: not a variable\n");
5216 script_reportdata(data);
5217 st->state = END;
5218 return 1;// not a variable
5219 }
5220
5221 id = reference_getid(data);
5222 start = reference_getindex(data);
5223 name = reference_getname(data);
5224 if( not_array_variable(*name) )
5225 {
5226 ShowError("script:deletearray: illegal scope\n");
5227 script_reportdata(data);
5228 st->state = END;
5229 return 1;// not supported
5230 }
5231
5232 if( not_server_variable(*name) )
5233 {
5234 sd = script_rid2sd(st);
5235 if( sd == NULL )
5236 return 0;// no player attached
5237 }
5238
5239 end = SCRIPT_MAX_ARRAYSIZE;
5240
5241 if( start >= end )
5242 return 0;// nothing to free
5243
5244 if( script_hasdata(st,3) )
5245 {
5246 int count = script_getnum(st, 3);
5247 if( count > end - start )
5248 count = end - start;
5249 if( count <= 0 )
5250 return 0;// nothing to free
5251
5252 // move rest of the elements backward
5253 for( ; start + count < end; ++start )
5254 {
5255 void* v = get_val2(st, reference_uid(id, start + count), reference_getref(data));
5256 set_reg(st, sd, reference_uid(id, start), name, v, reference_getref(data));
5257 script_removetop(st, -1, 0);
5258 }
5259 }
5260
5261 // clear the rest of the array
5262 if( is_string_variable(name) )
5263 {
5264 for( ; start < end; ++start )
5265 set_reg(st, sd, reference_uid(id, start), name, (void *)"", reference_getref(data));
5266 }
5267 else
5268 {
5269 for( ; start < end; ++start )
5270 set_reg(st, sd, reference_uid(id, start), name, (void*)0, reference_getref(data));
5271 }
5272 return 0;
5273}
5274
5275/// Returns a reference to the target index of the array variable.
5276/// Equivalent to var[index].
5277///
5278/// getelementofarray(<array variable>,<index>) -> <variable reference>
5279BUILDIN_FUNC(getelementofarray)
5280{
5281 struct script_data* data;
5282 const char* name;
5283 int32 id;
5284 int i;
5285
5286 data = script_getdata(st, 2);
5287 if( !data_isreference(data) )
5288 {
5289 ShowError("script:getelementofarray: not a variable\n");
5290 script_reportdata(data);
5291 script_pushnil(st);
5292 st->state = END;
5293 return 1;// not a variable
5294 }
5295
5296 id = reference_getid(data);
5297 name = reference_getname(data);
5298 if( not_array_variable(*name) )
5299 {
5300 ShowError("script:getelementofarray: illegal scope\n");
5301 script_reportdata(data);
5302 script_pushnil(st);
5303 st->state = END;
5304 return 1;// not supported
5305 }
5306
5307 i = script_getnum(st, 3);
5308 if( i < 0 || i >= SCRIPT_MAX_ARRAYSIZE )
5309 {
5310 ShowWarning("script:getelementofarray: index out of range (%d)\n", i);
5311 script_reportdata(data);
5312 script_pushnil(st);
5313 st->state = END;
5314 return 1;// out of range
5315 }
5316
5317 push_val2(st->stack, C_NAME, reference_uid(id, i), reference_getref(data));
5318 return 0;
5319}
5320
5321/////////////////////////////////////////////////////////////////////
5322/// ...
5323///
5324
5325/*==========================================
5326 *
5327 *------------------------------------------*/
5328BUILDIN_FUNC(setlook)
5329{
5330 int type,val;
5331 TBL_PC* sd;
5332
5333 type=script_getnum(st,2);
5334 val=script_getnum(st,3);
5335
5336 sd = script_rid2sd(st);
5337 if( sd == NULL )
5338 return 0;
5339
5340 pc_changelook(sd,type,val);
5341
5342 return 0;
5343}
5344
5345BUILDIN_FUNC(changelook)
5346{ // As setlook but only client side
5347 int type,val;
5348 TBL_PC* sd;
5349
5350 type=script_getnum(st,2);
5351 val=script_getnum(st,3);
5352
5353 sd = script_rid2sd(st);
5354 if( sd == NULL )
5355 return 0;
5356
5357 clif_changelook(&sd->bl,type,val);
5358
5359 return 0;
5360}
5361
5362/*==========================================
5363 *
5364 *------------------------------------------*/
5365BUILDIN_FUNC(cutin)
5366{
5367 TBL_PC* sd;
5368
5369 sd = script_rid2sd(st);
5370 if( sd == NULL )
5371 return 0;
5372
5373 clif_cutin(sd,script_getstr(st,2),script_getnum(st,3));
5374 return 0;
5375}
5376
5377/*==========================================
5378 *
5379 *------------------------------------------*/
5380BUILDIN_FUNC(viewpoint)
5381{
5382 int type,x,y,id,color;
5383 TBL_PC* sd;
5384
5385 type=script_getnum(st,2);
5386 x=script_getnum(st,3);
5387 y=script_getnum(st,4);
5388 id=script_getnum(st,5);
5389 color=script_getnum(st,6);
5390
5391 sd = script_rid2sd(st);
5392 if( sd == NULL )
5393 return 0;
5394
5395 clif_viewpoint(sd,st->oid,type,x,y,id,color);
5396
5397 return 0;
5398}
5399
5400int viewpointmap_sub(struct block_list *bl, va_list ap)
5401{
5402 struct map_session_data *sd;
5403 int npc_id, type, x, y, id, color;
5404 npc_id = va_arg(ap,int);
5405 type = va_arg(ap,int);
5406 x = va_arg(ap,int);
5407 y = va_arg(ap,int);
5408 id = va_arg(ap,int);
5409 color = va_arg(ap,int);
5410 sd = (struct map_session_data *)bl;
5411 clif_viewpoint(sd,npc_id,type,x,y,id,color);
5412 return 0;
5413}
5414
5415BUILDIN_FUNC(viewpointmap)
5416{
5417 int type,x,y,id,color,m;
5418 const char *map_name;
5419
5420 map_name = script_getstr(st,2);
5421 if( (m = map_mapname2mapid(map_name)) < 0 )
5422 return 0; // Invalid Map
5423
5424 type=script_getnum(st,3);
5425 x=script_getnum(st,4);
5426 y=script_getnum(st,5);
5427 id=script_getnum(st,6);
5428 color=script_getnum(st,7);
5429
5430 map_foreachinmap(viewpointmap_sub,m,BL_PC,st->oid,type,x,y,id,color);
5431 return 0;
5432}
5433
5434/*==========================================
5435 *
5436 *------------------------------------------*/
5437BUILDIN_FUNC(countitem)
5438{
5439 int nameid, i;
5440 int count = 0, char_id;
5441 struct item_data* id = NULL;
5442 struct script_data* data;
5443
5444 TBL_PC* sd = script_rid2sd(st);
5445 if (!sd) {
5446 script_pushint(st,0);
5447 return 0;
5448 }
5449
5450 data = script_getdata(st,2);
5451 get_val(st, data); // convert into value in case of a variable
5452
5453 if( data_isstring(data) )
5454 {// item name
5455 id = itemdb_searchname(conv_str(st, data));
5456 }
5457 else
5458 {// item id
5459 id = itemdb_exists(conv_num(st, data));
5460 }
5461
5462 if( id == NULL )
5463 {
5464 ShowError("buildin_countitem: Invalid item '%s'.\n", script_getstr(st,2)); // returns string, regardless of what it was
5465 script_pushint(st,0);
5466 return 1;
5467 }
5468
5469 nameid = id->nameid;
5470
5471 for(i = 0; i < MAX_INVENTORY; i++)
5472 {
5473 if( sd->status.inventory[i].nameid != nameid )
5474 continue;
5475
5476 if( sd->status.inventory[i].card[0] == CARD0_CREATE )
5477 {
5478 char_id = MakeDWord(sd->status.inventory[i].card[2],sd->status.inventory[i].card[3]);
5479 if( battle_config.bg_reserved_char_id && char_id == battle_config.bg_reserved_char_id && !map_bg_items(sd->bl.m) )
5480 continue;
5481 if( battle_config.ancient_reserved_char_id && char_id == battle_config.ancient_reserved_char_id && !map[sd->bl.m].flag.ancient )
5482 continue;
5483 if( battle_config.woe_reserved_char_id && char_id == battle_config.woe_reserved_char_id && !map_gvg_items(sd->bl.m) )
5484 continue;
5485 }
5486
5487 count += sd->status.inventory[i].amount;
5488 }
5489
5490 script_pushint(st,count);
5491 return 0;
5492}
5493
5494/*==========================================
5495 * countitem2(nameID,Identified,Refine,Attribute,Card0,Card1,Card2,Card3) [Lupus]
5496 * returns number of items that meet the conditions
5497 *------------------------------------------*/
5498BUILDIN_FUNC(countitem2)
5499{
5500 int nameid, iden, ref, attr, c1, c2, c3, c4;
5501 int count = 0;
5502 int i;
5503 struct item_data* id = NULL;
5504 struct script_data* data;
5505
5506 TBL_PC* sd = script_rid2sd(st);
5507 if (!sd) {
5508 script_pushint(st,0);
5509 return 0;
5510 }
5511
5512 data = script_getdata(st,2);
5513 get_val(st, data); // convert into value in case of a variable
5514
5515 if( data_isstring(data) )
5516 {// item name
5517 id = itemdb_searchname(conv_str(st, data));
5518 }
5519 else
5520 {// item id
5521 id = itemdb_exists(conv_num(st, data));
5522 }
5523
5524 if( id == NULL )
5525 {
5526 ShowError("buildin_countitem2: Invalid item '%s'.\n", script_getstr(st,2)); // returns string, regardless of what it was
5527 script_pushint(st,0);
5528 return 1;
5529 }
5530
5531 nameid = id->nameid;
5532 iden = script_getnum(st,3);
5533 ref = script_getnum(st,4);
5534 attr = script_getnum(st,5);
5535 c1 = (short)script_getnum(st,6);
5536 c2 = (short)script_getnum(st,7);
5537 c3 = (short)script_getnum(st,8);
5538 c4 = (short)script_getnum(st,9);
5539
5540 for(i = 0; i < MAX_INVENTORY; i++)
5541 if (sd->status.inventory[i].nameid > 0 && sd->inventory_data[i] != NULL &&
5542 sd->status.inventory[i].amount > 0 && sd->status.inventory[i].nameid == nameid &&
5543 sd->status.inventory[i].identify == iden && sd->status.inventory[i].refine == ref &&
5544 sd->status.inventory[i].attribute == attr && sd->status.inventory[i].card[0] == c1 &&
5545 sd->status.inventory[i].card[1] == c2 && sd->status.inventory[i].card[2] == c3 &&
5546 sd->status.inventory[i].card[3] == c4
5547 )
5548 count += sd->status.inventory[i].amount;
5549
5550 script_pushint(st,count);
5551 return 0;
5552}
5553
5554/*==========================================
5555 * é‡é‡ãƒã‚§ãƒƒã‚¯
5556 *------------------------------------------*/
5557BUILDIN_FUNC(checkweight)
5558{
5559 int nameid, amount, slots;
5560 unsigned int weight;
5561 struct item_data* id = NULL;
5562 struct map_session_data* sd;
5563 struct script_data* data;
5564
5565 if( ( sd = script_rid2sd(st) ) == NULL )
5566 {
5567 return 0;
5568 }
5569
5570 data = script_getdata(st,2);
5571 get_val(st, data); // convert into value in case of a variable
5572
5573 if( data_isstring(data) )
5574 {// item name
5575 id = itemdb_searchname(conv_str(st, data));
5576 }
5577 else
5578 {// item id
5579 id = itemdb_exists(conv_num(st, data));
5580 }
5581
5582 if( id == NULL )
5583 {
5584 ShowError("buildin_checkweight: Invalid item '%s'.\n", script_getstr(st,2)); // returns string, regardless of what it was
5585 script_pushint(st,0);
5586 return 1;
5587 }
5588
5589 nameid = id->nameid;
5590 amount = script_getnum(st,3);
5591
5592 if( amount < 1 )
5593 {
5594 ShowError("buildin_checkweight: Invalid amount '%d'.\n", amount);
5595 script_pushint(st,0);
5596 return 1;
5597 }
5598
5599 weight = itemdb_weight(nameid)*amount;
5600
5601 if( weight + sd->weight > sd->max_weight )
5602 {// too heavy
5603 script_pushint(st,0);
5604 return 0;
5605 }
5606
5607 switch( pc_checkadditem(sd, nameid, amount) )
5608 {
5609 case ADDITEM_EXIST:
5610 // item is already in inventory, but there is still space for the requested amount
5611 break;
5612 case ADDITEM_NEW:
5613 slots = pc_inventoryblank(sd);
5614
5615 if( itemdb_isstackable(nameid) )
5616 {// stackable
5617 if( slots < 1 )
5618 {
5619 script_pushint(st,0);
5620 return 0;
5621 }
5622 }
5623 else
5624 {// non-stackable
5625 if( slots < amount )
5626 {
5627 script_pushint(st,0);
5628 return 0;
5629 }
5630 }
5631 break;
5632 case ADDITEM_OVERAMOUNT:
5633 script_pushint(st,0);
5634 return 0;
5635 }
5636
5637 script_pushint(st,1);
5638 return 0;
5639}
5640
5641/*==========================================
5642 * getitem <item id>,<amount>{,<account ID>};
5643 * getitem "<item name>",<amount>{,<account ID>};
5644 *------------------------------------------*/
5645BUILDIN_FUNC(getitem)
5646{
5647 int nameid,amount,get_count,i,flag = 0;
5648 struct item it;
5649 TBL_PC *sd;
5650 struct script_data *data;
5651
5652 data=script_getdata(st,2);
5653 get_val(st,data);
5654 if( data_isstring(data) )
5655 {// "<item name>"
5656 const char *name=conv_str(st,data);
5657 struct item_data *item_data = itemdb_searchname(name);
5658 if( item_data == NULL ){
5659 ShowError("buildin_getitem: Nonexistant item %s requested.\n", name);
5660 return 1; //No item created.
5661 }
5662 nameid=item_data->nameid;
5663 } else if( data_isint(data) )
5664 {// <item id>
5665 nameid=conv_num(st,data);
5666 //Violet Box, Blue Box, etc - random item pick
5667 if( nameid < 0 ) {
5668 nameid=itemdb_searchrandomid(-nameid);
5669 flag = 1;
5670 }
5671 if( nameid <= 0 || !itemdb_exists(nameid) ){
5672 ShowError("buildin_getitem: Nonexistant item %d requested.\n", nameid);
5673 return 1; //No item created.
5674 }
5675 } else {
5676 ShowError("buildin_getitem: invalid data type for argument #1 (%d).", data->type);
5677 return 1;
5678 }
5679
5680 // <amount>
5681 if( (amount=script_getnum(st,3)) <= 0)
5682 return 0; //return if amount <=0, skip the useles iteration
5683
5684 memset(&it,0,sizeof(it));
5685 it.nameid=nameid;
5686 if(!flag)
5687 it.identify=1;
5688 else
5689 it.identify=itemdb_isidentified(nameid);
5690
5691 if( script_hasdata(st,4) )
5692 sd=map_id2sd(script_getnum(st,4)); // <Account ID>
5693 else
5694 sd=script_rid2sd(st); // Attached player
5695
5696 if( sd == NULL ) // no target
5697 return 0;
5698
5699 //Check if it's stackable.
5700 if (!itemdb_isstackable(nameid))
5701 get_count = 1;
5702 else
5703 get_count = amount;
5704
5705 for (i = 0; i < amount; i += get_count)
5706 {
5707 // if not pet egg
5708 if (!pet_create_egg(sd, nameid))
5709 {
5710 if ((flag = pc_additem(sd, &it, get_count, LOG_TYPE_SCRIPT)))
5711 {
5712 clif_additem(sd, 0, 0, flag);
5713 if( pc_candrop(sd,&it) )
5714 map_addflooritem(&it,get_count,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0);
5715 }
5716 }
5717 }
5718
5719 return 0;
5720}
5721
5722/*==========================================
5723 *
5724 *------------------------------------------*/
5725BUILDIN_FUNC(getitem2)
5726{
5727 int nameid,amount,get_count,i,flag = 0;
5728 int iden,ref,attr,c1,c2,c3,c4;
5729 struct item_data *item_data;
5730 struct item item_tmp;
5731 TBL_PC *sd;
5732 struct script_data *data;
5733
5734 if( script_hasdata(st,11) )
5735 sd=map_id2sd(script_getnum(st,11)); // <Account ID>
5736 else
5737 sd=script_rid2sd(st); // Attached player
5738
5739 if( sd == NULL ) // no target
5740 return 0;
5741
5742 data=script_getdata(st,2);
5743 get_val(st,data);
5744 if( data_isstring(data) ){
5745 const char *name=conv_str(st,data);
5746 struct item_data *item_data = itemdb_searchname(name);
5747 if( item_data )
5748 nameid=item_data->nameid;
5749 else
5750 nameid=UNKNOWN_ITEM_ID;
5751 }else
5752 nameid=conv_num(st,data);
5753
5754 amount=script_getnum(st,3);
5755 iden=script_getnum(st,4);
5756 ref=script_getnum(st,5);
5757 attr=script_getnum(st,6);
5758 c1=(short)script_getnum(st,7);
5759 c2=(short)script_getnum(st,8);
5760 c3=(short)script_getnum(st,9);
5761 c4=(short)script_getnum(st,10);
5762
5763 if(nameid<0) { // ランダãƒ
5764 nameid=itemdb_searchrandomid(-nameid);
5765 flag = 1;
5766 }
5767
5768 if(nameid > 0) {
5769 memset(&item_tmp,0,sizeof(item_tmp));
5770 item_data=itemdb_exists(nameid);
5771 if (item_data == NULL)
5772 return -1;
5773 if(item_data->type==IT_WEAPON || item_data->type==IT_ARMOR){
5774 if(ref > MAX_REFINE) ref = MAX_REFINE;
5775 }
5776 else if(item_data->type==IT_PETEGG) {
5777 iden = 1;
5778 ref = 0;
5779 }
5780 else {
5781 iden = 1;
5782 ref = attr = 0;
5783 }
5784
5785 item_tmp.nameid=nameid;
5786 if(!flag)
5787 item_tmp.identify=iden;
5788 else if(item_data->type==IT_WEAPON || item_data->type==IT_ARMOR)
5789 item_tmp.identify=0;
5790 item_tmp.refine=ref;
5791 item_tmp.attribute=attr;
5792 item_tmp.card[0]=(short)c1;
5793 item_tmp.card[1]=(short)c2;
5794 item_tmp.card[2]=(short)c3;
5795 item_tmp.card[3]=(short)c4;
5796
5797 //Check if it's stackable.
5798 if (!itemdb_isstackable(nameid))
5799 get_count = 1;
5800 else
5801 get_count = amount;
5802
5803 for (i = 0; i < amount; i += get_count)
5804 {
5805 // if not pet egg
5806 if (!pet_create_egg(sd, nameid))
5807 {
5808 if ((flag = pc_additem(sd, &item_tmp, get_count, LOG_TYPE_SCRIPT)))
5809 {
5810 clif_additem(sd, 0, 0, flag);
5811 if( pc_candrop(sd,&item_tmp) )
5812 map_addflooritem(&item_tmp,get_count,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0);
5813 }
5814 }
5815 }
5816 }
5817
5818 return 0;
5819}
5820
5821/*==========================================
5822 * Items to Storage [Zephyrus]
5823 *------------------------------------------*/
5824BUILDIN_FUNC(checkspace)
5825{
5826 int nameid = 0, amount;
5827 struct map_session_data *sd;
5828
5829 if( (sd = script_rid2sd(st)) == NULL )
5830 script_pushint(st,0);
5831 else if( sd->status.storage.storage_amount > MAX_STORAGE )
5832 script_pushint(st,0); // Storage at max
5833 else
5834 {
5835 struct script_data *data = script_getdata(st,2);
5836 struct item_data *id;
5837 struct item it;
5838 int i;
5839
5840 get_val(st,data);
5841 if( data_isstring(data) )
5842 {
5843 const char *name = conv_str(st,data);
5844 struct item_data *id = itemdb_searchname(name);
5845 if( id )
5846 nameid = id->nameid;
5847 }
5848 else
5849 nameid = conv_num(st,data);
5850
5851 memset(&it,0,sizeof(it));
5852 amount = script_getnum(st,3);
5853 it.nameid = nameid;
5854 it.identify = script_getnum(st,4);
5855 it.refine = script_getnum(st,5);
5856 it.attribute = script_getnum(st,6);
5857 it.card[0] = (short)script_getnum(st,7);
5858 it.card[1] = (short)script_getnum(st,8);
5859 it.card[2] = (short)script_getnum(st,9);
5860 it.card[3] = (short)script_getnum(st,10);
5861
5862 if( nameid < 500 || amount <= 0 || (id = itemdb_exists(nameid)) == NULL || !itemdb_canstore(&it, pc_isGM(sd)) || !itemdb_isstackable2(id) )
5863 {
5864 script_pushint(st,0);
5865 return 0;
5866 }
5867
5868 if( itemdb_isstackable2(id) )
5869 {
5870 ARR_FIND(0,MAX_STORAGE,i,compare_item(&sd->status.storage.items[i],&it));
5871 if( i < MAX_STORAGE )
5872 { // Item on Storage
5873 script_pushint(st,amount + sd->status.storage.items[i].amount > MAX_AMOUNT ? 0 : 1);
5874 return 0;
5875 }
5876 }
5877
5878 ARR_FIND(0,MAX_STORAGE,i,sd->status.storage.items[i].nameid == 0);
5879 if( i >= MAX_STORAGE )
5880 {
5881 script_pushint(st,0);
5882 return 0;
5883 }
5884
5885 script_pushint(st,1); // Can be Stored
5886 }
5887
5888 return 0;
5889}
5890
5891BUILDIN_FUNC(storeitem)
5892{
5893 int nameid = 0, amount;
5894 struct item it;
5895 struct map_session_data *sd;
5896 struct script_data *data;
5897 int result = 1;
5898
5899 data = script_getdata(st,2);
5900 get_val(st,data);
5901 if( data_isstring(data) )
5902 { // "<item name>"
5903 const char *name = conv_str(st,data);
5904 struct item_data *item_data = itemdb_searchname(name);
5905 if( item_data == NULL )
5906 {
5907 ShowError("buildin_storeitem: Nonexistant item %s requested.\n", name);
5908 result = 0; //No item created.
5909 }
5910 else
5911 nameid = item_data->nameid;
5912 }
5913 else if( data_isint(data) )
5914 { // <item id>
5915 nameid = conv_num(st,data);
5916 if( nameid <= 0 || !itemdb_exists(nameid) )
5917 {
5918 ShowError("buildin_storeitem: Nonexistant item %d requested.\n", nameid);
5919 result = 0;
5920 }
5921 }
5922 else
5923 {
5924 ShowError("buildin_storeitem: invalid data type for argument #1 (%d).", data->type);
5925 result = 0;
5926 }
5927
5928 if( !itemdb_isstackable(nameid) )
5929 result = 0;
5930 if( (amount = script_getnum(st,3)) <= 0 )
5931 result = 0;
5932
5933 if( script_hasdata(st,4) )
5934 sd = map_id2sd(script_getnum(st,4)); // <Account ID>
5935 else
5936 sd = script_rid2sd(st); // Attached player
5937
5938 if( sd == NULL ) // no target
5939 result = 0;
5940
5941 if( result )
5942 {
5943 memset(&it,0,sizeof(it));
5944 it.nameid = nameid;
5945 it.identify = 1;
5946 result = storage_additem2(sd,&it,amount);
5947
5948 if( result )
5949 log_pick(&sd->bl, LOG_TYPE_SCRIPT, nameid, amount, &it);
5950 }
5951
5952 script_pushint(st,result);
5953 return 0;
5954}
5955
5956BUILDIN_FUNC(storeitem2)
5957{
5958 int nameid = 0, amount = 0;
5959 int iden = 0,ref = 0,attr = 0,c1 = 0,c2 = 0,c3 = 0,c4 = 0;
5960 struct map_session_data *sd;
5961 struct script_data *data;
5962 struct item it;
5963 int result = 1;
5964
5965 data = script_getdata(st,2);
5966 get_val(st,data);
5967 if( data_isstring(data) )
5968 {
5969 const char *name = conv_str(st,data);
5970 struct item_data *item_data = itemdb_searchname(name);
5971 if( item_data == NULL )
5972 {
5973 ShowError("buildin_storeitem2: Nonexistant item %s requested.\n", name);
5974 result = 0;
5975 }
5976 else
5977 nameid = item_data->nameid;
5978 }
5979 else if( data_isint(data) )
5980 {
5981 nameid = conv_num(st,data);
5982 if( nameid <= 0 || !itemdb_exists(nameid) )
5983 {
5984 ShowError("buildin_storeitem2: Nonexistant item %d requested.\n", nameid);
5985 result = 0;
5986 }
5987 }
5988 else
5989 {
5990 ShowError("buildin_storeitem2: invalid data type for argument #1 (%d).", data->type);
5991 result = 0;
5992 }
5993
5994 if( !itemdb_isstackable(nameid) )
5995 result = 0;
5996 else if( (amount = script_getnum(st,3)) <= 0 )
5997 result = 0;
5998 else
5999 {
6000 iden = script_getnum(st,4);
6001 ref = script_getnum(st,5);
6002 attr = script_getnum(st,6);
6003 c1 = (short)script_getnum(st,7);
6004 c2 = (short)script_getnum(st,8);
6005 c3 = (short)script_getnum(st,9);
6006 c4 = (short)script_getnum(st,10);
6007 }
6008
6009 if( script_hasdata(st,11) )
6010 sd = map_id2sd(script_getnum(st,11));
6011 else
6012 sd = script_rid2sd(st);
6013
6014 if( sd == NULL )
6015 result = 0;
6016
6017 if( result )
6018 {
6019 memset(&it,0,sizeof(it));
6020 it.nameid = nameid;
6021 it.identify = 1; // always Identify
6022 it.refine = ref;
6023 it.attribute = attr;
6024 it.card[0] = (short)c1;
6025 it.card[1] = (short)c2;
6026 it.card[2] = (short)c3;
6027 it.card[3] = (short)c4;
6028 result = storage_additem2(sd,&it,amount);
6029 if( result )
6030 log_pick(&sd->bl, LOG_TYPE_SCRIPT, nameid, amount, &it);
6031 }
6032
6033 script_pushint(st,result);
6034 return 0;
6035}
6036
6037/*==========================================
6038 * rentitem <item id>,<seconds>
6039 * rentitem "<item name>",<seconds>
6040 *------------------------------------------*/
6041BUILDIN_FUNC(rentitem)
6042{
6043 struct map_session_data *sd;
6044 struct script_data *data;
6045 struct item it;
6046 int seconds;
6047 int nameid = 0, flag;
6048
6049 data = script_getdata(st,2);
6050 get_val(st,data);
6051
6052 if( (sd = script_rid2sd(st)) == NULL )
6053 return 0;
6054
6055 if( data_isstring(data) )
6056 {
6057 const char *name = conv_str(st,data);
6058 struct item_data *itd = itemdb_searchname(name);
6059 if( itd == NULL )
6060 {
6061 ShowError("buildin_rentitem: Nonexistant item %s requested.\n", name);
6062 return 1;
6063 }
6064 nameid = itd->nameid;
6065 }
6066 else if( data_isint(data) )
6067 {
6068 nameid = conv_num(st,data);
6069 if( nameid <= 0 || !itemdb_exists(nameid) )
6070 {
6071 ShowError("buildin_rentitem: Nonexistant item %d requested.\n", nameid);
6072 return 1;
6073 }
6074 }
6075 else
6076 {
6077 ShowError("buildin_rentitem: invalid data type for argument #1 (%d).\n", data->type);
6078 return 1;
6079 }
6080
6081 seconds = script_getnum(st,3);
6082 memset(&it, 0, sizeof(it));
6083 it.nameid = nameid;
6084 it.identify = 1;
6085 it.expire_time = (unsigned int)(time(NULL) + seconds);
6086 it.bound = 0;
6087
6088 if( (flag = pc_additem(sd, &it, 1, LOG_TYPE_SCRIPT)) )
6089 {
6090 clif_additem(sd, 0, 0, flag);
6091 return 1;
6092 }
6093
6094 clif_rental_time(sd->fd, nameid, seconds);
6095 pc_inventory_rental_add(sd, seconds);
6096 return 0;
6097}
6098
6099BUILDIN_FUNC(rentitem2)
6100{
6101 struct map_session_data *sd;
6102 struct script_data *data;
6103 struct item_data *itd;
6104 struct item it;
6105 int seconds;
6106 int nameid = 0, iden, ref, attr, c1, c2, c3, c4, flag;
6107
6108 data = script_getdata(st,2);
6109 get_val(st,data);
6110
6111 if( (sd = script_rid2sd(st)) == NULL )
6112 return 0;
6113
6114 if( data_isstring(data) )
6115 {
6116 const char *name = conv_str(st,data);
6117 itd = itemdb_searchname(name);
6118 if( itd == NULL )
6119 {
6120 ShowError("buildin_rentitem2: Nonexistant item %s requested.\n", name);
6121 return 1;
6122 }
6123 nameid = itd->nameid;
6124 }
6125 else if( data_isint(data) )
6126 {
6127 nameid = conv_num(st,data);
6128 if( nameid <= 0 || (itd = itemdb_exists(nameid)) == NULL )
6129 {
6130 ShowError("buildin_rentitem2: Nonexistant item %d requested.\n", nameid);
6131 return 1;
6132 }
6133 }
6134 else
6135 {
6136 ShowError("buildin_rentitem2: invalid data type for argument #1 (%d).\n", data->type);
6137 return 1;
6138 }
6139
6140 iden = script_getnum(st,3);
6141 ref = script_getnum(st,4);
6142 attr = script_getnum(st,5);
6143 c1 = (short)script_getnum(st,6);
6144 c2 = (short)script_getnum(st,7);
6145 c3 = (short)script_getnum(st,8);
6146 c4 = (short)script_getnum(st,9);
6147 seconds = script_getnum(st,10);
6148
6149 memset(&it, 0, sizeof(it));
6150 it.nameid = nameid;
6151 if( itd->type == IT_WEAPON || itd->type == IT_ARMOR )
6152 ref = cap_value(ref,0,MAX_REFINE);
6153 else if( itd->type == IT_PETEGG )
6154 {
6155 ShowError("buildin_rentitem2: invalid item type. Pet Egg cannot be set as rental items.\n");
6156 return 1;
6157 }
6158 else
6159 {
6160 iden = 1;
6161 ref = attr = 0;
6162 }
6163
6164 it.identify = iden;
6165 it.refine=ref;
6166 it.attribute=attr;
6167 it.card[0]=(short)c1;
6168 it.card[1]=(short)c2;
6169 it.card[2]=(short)c3;
6170 it.card[3]=(short)c4;
6171 it.expire_time = (unsigned int)(time(NULL) + seconds);
6172
6173 if( (flag = pc_additem(sd, &it, 1, LOG_TYPE_SCRIPT)) )
6174 {
6175 clif_additem(sd, 0, 0, flag);
6176 return 1;
6177 }
6178
6179 clif_rental_time(sd->fd, nameid, seconds);
6180 pc_inventory_rental_add(sd, seconds);
6181 return 0;
6182}
6183
6184/*==========================================
6185 * itembound <item id>,<amount>{,<character ID>};
6186 * itembound "<item name>",<amount>{,<character ID>};
6187 *------------------------------------------*/
6188BUILDIN_FUNC(itembound)
6189{
6190 int nameid,amount,i,flag;
6191 struct item it;
6192 TBL_PC *sd;
6193 struct script_data *data;
6194
6195 data=script_getdata(st,2);
6196 get_val(st,data);
6197 if( data_isstring(data) )
6198 { // "<item name>"
6199 const char *name=conv_str(st,data);
6200 struct item_data *item_data = itemdb_searchname(name);
6201 if( item_data == NULL ){
6202 ShowError("buildin_itembound: Nonexistant item %s requested.\n", name);
6203 return 1; //No item created.
6204 }
6205 nameid=item_data->nameid;
6206 }
6207 else if( data_isint(data) )
6208 { // <item id>
6209 nameid=conv_num(st,data);
6210 if( nameid <= 0 || !itemdb_exists(nameid) )
6211 {
6212 ShowError("buildin_getitem: Nonexistant item %d requested.\n", nameid);
6213 return 1; //No item created.
6214 }
6215 }
6216 else
6217 {
6218 ShowError("buildin_itembound: invalid data type for argument #1 (%d).", data->type);
6219 return 1;
6220 }
6221
6222 if( itemdb_isstackable(nameid) || itemdb_type(nameid) == IT_PETEGG )
6223 {
6224 ShowError("buildin_itembound: invalid item type. Bound only work for non stackeable items (Item %d).", nameid);
6225 return 1;
6226 }
6227
6228 // <amount>
6229 if( (amount=script_getnum(st,3)) <= 0)
6230 return 0; //return if amount <=0, skip the useles iteration
6231
6232 memset(&it,0,sizeof(it));
6233 it.nameid = nameid;
6234 it.bound = 1;
6235 it.identify = 1;
6236
6237 if( script_hasdata(st,4) )
6238 sd = map_id2sd(script_getnum(st,4)); // <Account ID>
6239 else
6240 sd = script_rid2sd(st); // Attached player
6241
6242 if( sd == NULL ) // no target
6243 return 0;
6244
6245 for( i = 0; i < amount; i++ )
6246 {
6247 if( (flag = pc_additem(sd, &it, 1, LOG_TYPE_SCRIPT)) )
6248 {
6249 clif_additem(sd, 0, 0, flag);
6250 if( pc_candrop(sd,&it) )
6251 map_addflooritem(&it,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0);
6252 }
6253 }
6254
6255 return 0;
6256}
6257
6258BUILDIN_FUNC(itembound2)
6259{
6260 int nameid,amount,i,flag;
6261 int iden,ref,attr,c1,c2,c3,c4;
6262 struct item_data *item_data;
6263 struct item item_tmp;
6264 TBL_PC *sd;
6265 struct script_data *data;
6266
6267 if( script_hasdata(st,11) )
6268 sd = map_id2sd(script_getnum(st,11)); // <Account ID>
6269 else
6270 sd = script_rid2sd(st); // Attached player
6271
6272 if( sd == NULL ) // no target
6273 return 0;
6274
6275 data = script_getdata(st,2);
6276 get_val(st,data);
6277 if( data_isstring(data) )
6278 {
6279 const char *name = conv_str(st,data);
6280 struct item_data *item_data = itemdb_searchname(name);
6281 if( item_data )
6282 nameid = item_data->nameid;
6283 else
6284 nameid = UNKNOWN_ITEM_ID;
6285 }
6286 else
6287 nameid = conv_num(st,data);
6288
6289 amount = script_getnum(st,3);
6290 iden = script_getnum(st,4);
6291 ref = script_getnum(st,5);
6292 attr = script_getnum(st,6);
6293 c1 = (short)script_getnum(st,7);
6294 c2 = (short)script_getnum(st,8);
6295 c3 = (short)script_getnum(st,9);
6296 c4 = (short)script_getnum(st,10);
6297
6298 if( nameid < 0 || (item_data = itemdb_exists(nameid)) == NULL || itemdb_isstackable2(item_data) )
6299 return 0;
6300
6301 memset(&item_tmp,0,sizeof(item_tmp));
6302 item_tmp.nameid = nameid;
6303 if( item_data->type == IT_WEAPON || item_data->type == IT_ARMOR )
6304 ref = cap_value(ref,0,MAX_REFINE);
6305 else if( item_data->type == IT_PETEGG )
6306 {
6307 ShowError("buildin_itembound2: invalid item type. Pet Egg cannot be set as rental items.\n");
6308 return 1;
6309 }
6310 else
6311 { // Should not happen
6312 iden = 1;
6313 ref = attr = 0;
6314 }
6315
6316 item_tmp.identify = iden;
6317 item_tmp.refine = ref;
6318 item_tmp.attribute = attr;
6319 item_tmp.card[0] = (short)c1;
6320 item_tmp.card[1] = (short)c2;
6321 item_tmp.card[2] = (short)c3;
6322 item_tmp.card[3] = (short)c4;
6323 item_tmp.bound = 1;
6324
6325 for( i = 0; i < amount; i++ )
6326 {
6327 if ((flag = pc_additem(sd, &item_tmp, 1, LOG_TYPE_SCRIPT)))
6328 {
6329 clif_additem(sd, 0, 0, flag);
6330 if( pc_candrop(sd,&item_tmp) )
6331 map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0);
6332 }
6333 }
6334
6335 return 0;
6336}
6337
6338/*==========================================
6339 * gets an item with someone's name inscribed [Skotlex]
6340 * getinscribeditem item_num, character_name
6341 * Returned Qty is always 1, only works on equip-able
6342 * equipment
6343 *------------------------------------------*/
6344BUILDIN_FUNC(getnameditem)
6345{
6346 int nameid;
6347 struct item item_tmp;
6348 TBL_PC *sd, *tsd;
6349 struct script_data *data;
6350
6351 sd = script_rid2sd(st);
6352 if (sd == NULL)
6353 { //Player not attached!
6354 script_pushint(st,0);
6355 return 0;
6356 }
6357
6358 data=script_getdata(st,2);
6359 get_val(st,data);
6360 if( data_isstring(data) ){
6361 const char *name=conv_str(st,data);
6362 struct item_data *item_data = itemdb_searchname(name);
6363 if( item_data == NULL)
6364 { //Failed
6365 script_pushint(st,0);
6366 return 0;
6367 }
6368 nameid = item_data->nameid;
6369 }else
6370 nameid = conv_num(st,data);
6371
6372 if(!itemdb_exists(nameid)/* || itemdb_isstackable(nameid)*/)
6373 { //Even though named stackable items "could" be risky, they are required for certain quests.
6374 script_pushint(st,0);
6375 return 0;
6376 }
6377
6378 data=script_getdata(st,3);
6379 get_val(st,data);
6380 if( data_isstring(data) ) //Char Name
6381 tsd=map_nick2sd(conv_str(st,data));
6382 else //Char Id was given
6383 tsd=map_charid2sd(conv_num(st,data));
6384
6385 if( tsd == NULL )
6386 { //Failed
6387 script_pushint(st,0);
6388 return 0;
6389 }
6390
6391 memset(&item_tmp,0,sizeof(item_tmp));
6392 item_tmp.nameid=nameid;
6393 item_tmp.amount=1;
6394 item_tmp.identify=1;
6395 item_tmp.card[0]=CARD0_CREATE; //we don't use 255! because for example SIGNED WEAPON shouldn't get TOP10 BS Fame bonus [Lupus]
6396 item_tmp.card[2]=tsd->status.char_id;
6397 item_tmp.card[3]=tsd->status.char_id >> 16;
6398 if(pc_additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT)) {
6399 script_pushint(st,0);
6400 return 0; //Failed to add item, we will not drop if they don't fit
6401 }
6402
6403 script_pushint(st,1);
6404 return 0;
6405}
6406
6407/*==========================================
6408 * gets a random item ID from an item group [Skotlex]
6409 * groupranditem group_num
6410 *------------------------------------------*/
6411BUILDIN_FUNC(grouprandomitem)
6412{
6413 int group;
6414
6415 group = script_getnum(st,2);
6416 script_pushint(st,itemdb_searchrandomid(group));
6417 return 0;
6418}
6419
6420/*==========================================
6421 *
6422 *------------------------------------------*/
6423BUILDIN_FUNC(makeitem)
6424{
6425 int nameid,amount,flag = 0;
6426 int x,y,m;
6427 const char *mapname;
6428 struct item item_tmp;
6429 struct script_data *data;
6430
6431 data=script_getdata(st,2);
6432 get_val(st,data);
6433 if( data_isstring(data) ){
6434 const char *name=conv_str(st,data);
6435 struct item_data *item_data = itemdb_searchname(name);
6436 if( item_data )
6437 nameid=item_data->nameid;
6438 else
6439 nameid=UNKNOWN_ITEM_ID;
6440 }else
6441 nameid=conv_num(st,data);
6442
6443 amount=script_getnum(st,3);
6444 mapname =script_getstr(st,4);
6445 x =script_getnum(st,5);
6446 y =script_getnum(st,6);
6447
6448 if(strcmp(mapname,"this")==0)
6449 {
6450 TBL_PC *sd;
6451 sd = script_rid2sd(st);
6452 if (!sd) return 0; //Failed...
6453 m=sd->bl.m;
6454 } else
6455 m=map_mapname2mapid(mapname);
6456
6457 if(nameid<0) { // ランダãƒ
6458 nameid=itemdb_searchrandomid(-nameid);
6459 flag = 1;
6460 }
6461
6462 if(nameid > 0) {
6463 memset(&item_tmp,0,sizeof(item_tmp));
6464 item_tmp.nameid=nameid;
6465 if(!flag)
6466 item_tmp.identify=1;
6467 else
6468 item_tmp.identify=itemdb_isidentified(nameid);
6469
6470 map_addflooritem(&item_tmp,amount,m,x,y,0,0,0,0,0);
6471 }
6472
6473 return 0;
6474}
6475
6476
6477/// Counts / deletes the current item given by idx.
6478/// Used by buildin_delitem_search
6479/// Relies on all input data being already fully valid.
6480static void buildin_delitem_delete(struct map_session_data* sd, int idx, int* amount, bool delete_items)
6481{
6482 int delamount;
6483 struct item* inv = &sd->status.inventory[idx];
6484
6485 delamount = ( amount[0] < inv->amount ) ? amount[0] : inv->amount;
6486
6487 if( delete_items )
6488 {
6489 if( sd->inventory_data[idx]->type == IT_PETEGG && inv->card[0] == CARD0_PET )
6490 {// delete associated pet
6491 intif_delete_petdata(MakeDWord(inv->card[1], inv->card[2]));
6492 }
6493
6494 pc_delitem(sd, idx, delamount, 0, 0, LOG_TYPE_SCRIPT);
6495 }
6496
6497 amount[0]-= delamount;
6498}
6499
6500
6501/// Searches for item(s) and checks, if there is enough of them.
6502/// Used by delitem and delitem2
6503/// Relies on all input data being already fully valid.
6504/// @param exact_match will also match item attributes and cards, not just name id
6505/// @return true when all items could be deleted, false when there were not enough items to delete
6506static bool buildin_delitem_search(struct map_session_data* sd, struct item* it, bool exact_match)
6507{
6508 bool delete_items = false;
6509 int i, amount, important;
6510 struct item* inv;
6511
6512 // prefer always non-equipped items
6513 it->equip = 0;
6514
6515 // when searching for nameid only, prefer additionally
6516 if( !exact_match )
6517 {
6518 // non-refined items
6519 it->refine = 0;
6520 // card-less items
6521 memset(it->card, 0, sizeof(it->card));
6522 }
6523
6524 for(;;)
6525 {
6526 amount = it->amount;
6527 important = 0;
6528
6529 // 1st pass -- less important items / exact match
6530 for( i = 0; amount && i < ARRAYLENGTH(sd->status.inventory); i++ )
6531 {
6532 inv = &sd->status.inventory[i];
6533
6534 if( !inv->nameid || !sd->inventory_data[i] || inv->nameid != it->nameid )
6535 {// wrong/invalid item
6536 continue;
6537 }
6538
6539 if( inv->equip != it->equip || inv->refine != it->refine )
6540 {// not matching attributes
6541 important++;
6542 continue;
6543 }
6544
6545 if( exact_match )
6546 {
6547 if( inv->identify != it->identify || inv->attribute != it->attribute || memcmp(inv->card, it->card, sizeof(inv->card)) )
6548 {// not matching exact attributes
6549 continue;
6550 }
6551 }
6552 else
6553 {
6554 if( sd->inventory_data[i]->type == IT_PETEGG )
6555 {
6556 if( inv->card[0] == CARD0_PET && CheckForCharServer() )
6557 {// pet which cannot be deleted
6558 continue;
6559 }
6560 }
6561 else if( memcmp(inv->card, it->card, sizeof(inv->card)) )
6562 {// named/carded item
6563 important++;
6564 continue;
6565 }
6566 }
6567
6568 // count / delete item
6569 buildin_delitem_delete(sd, i, &amount, delete_items);
6570 }
6571
6572 // 2nd pass -- any matching item
6573 if( amount == 0 || important == 0 )
6574 {// either everything was already consumed or no items were skipped
6575 ;
6576 }
6577 else for( i = 0; amount && i < ARRAYLENGTH(sd->status.inventory); i++ )
6578 {
6579 inv = &sd->status.inventory[i];
6580
6581 if( !inv->nameid || !sd->inventory_data[i] || inv->nameid != it->nameid )
6582 {// wrong/invalid item
6583 continue;
6584 }
6585
6586 if( sd->inventory_data[i]->type == IT_PETEGG && inv->card[0] == CARD0_PET && CheckForCharServer() )
6587 {// pet which cannot be deleted
6588 continue;
6589 }
6590
6591 if( exact_match )
6592 {
6593 if( inv->refine != it->refine || inv->identify != it->identify || inv->attribute != it->attribute || memcmp(inv->card, it->card, sizeof(inv->card)) )
6594 {// not matching attributes
6595 continue;
6596 }
6597 }
6598 else if( inv->card[0] == CARD0_CREATE )
6599 {
6600 int char_id = MakeDWord(inv->card[2],inv->card[3]);
6601 if( battle_config.bg_reserved_char_id && char_id == battle_config.bg_reserved_char_id && !map_bg_items(sd->bl.m) )
6602 continue;
6603 if( battle_config.ancient_reserved_char_id && char_id == battle_config.ancient_reserved_char_id && !map[sd->bl.m].flag.ancient )
6604 continue;
6605 if( battle_config.woe_reserved_char_id && char_id == battle_config.woe_reserved_char_id && !map_gvg_items(sd->bl.m) )
6606 continue;
6607 }
6608
6609 // count / delete item
6610 buildin_delitem_delete(sd, i, &amount, delete_items);
6611 }
6612
6613 if( amount )
6614 {// not enough items
6615 return false;
6616 }
6617 else if( delete_items )
6618 {// we are done with the work
6619 return true;
6620 }
6621 else
6622 {// get rid of the items now
6623 delete_items = true;
6624 }
6625 }
6626}
6627
6628
6629/// Deletes items from the target/attached player.
6630/// Prioritizes ordinary items.
6631///
6632/// delitem <item id>,<amount>{,<account id>}
6633/// delitem "<item name>",<amount>{,<account id>}
6634BUILDIN_FUNC(delitem)
6635{
6636 TBL_PC *sd;
6637 struct item it;
6638 struct script_data *data;
6639
6640 if( script_hasdata(st,4) )
6641 {
6642 int account_id = script_getnum(st,4);
6643 sd = map_id2sd(account_id); // <account id>
6644 if( sd == NULL )
6645 {
6646 ShowError("script:delitem: player not found (AID=%d).\n", account_id);
6647 st->state = END;
6648 return 1;
6649 }
6650 }
6651 else
6652 {
6653 sd = script_rid2sd(st);// attached player
6654 if( sd == NULL )
6655 return 0;
6656 }
6657
6658 data = script_getdata(st,2);
6659 get_val(st,data);
6660 if( data_isstring(data) )
6661 {
6662 const char* item_name = conv_str(st,data);
6663 struct item_data* id = itemdb_searchname(item_name);
6664 if( id == NULL )
6665 {
6666 ShowError("script:delitem: unknown item \"%s\".\n", item_name);
6667 st->state = END;
6668 return 1;
6669 }
6670 it.nameid = id->nameid;// "<item name>"
6671 }
6672 else
6673 {
6674 it.nameid = conv_num(st,data);// <item id>
6675 if( !itemdb_exists( it.nameid ) )
6676 {
6677 ShowError("script:delitem: unknown item \"%d\".\n", it.nameid);
6678 st->state = END;
6679 return 1;
6680 }
6681 }
6682
6683 it.amount=script_getnum(st,3);
6684
6685 if( it.amount <= 0 )
6686 return 0;// nothing to do
6687
6688 if( buildin_delitem_search(sd, &it, false) )
6689 {// success
6690 return 0;
6691 }
6692
6693 ShowError("script:delitem: failed to delete %d items (AID=%d item_id=%d).\n", it.amount, sd->status.account_id, it.nameid);
6694 st->state = END;
6695 clif_scriptclose(sd, st->oid);
6696 return 1;
6697}
6698
6699/// Deletes items from the target/attached player.
6700///
6701/// delitem2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
6702/// delitem2 "<Item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
6703BUILDIN_FUNC(delitem2)
6704{
6705 TBL_PC *sd;
6706 struct item it;
6707 struct script_data *data;
6708
6709 if( script_hasdata(st,11) )
6710 {
6711 int account_id = script_getnum(st,11);
6712 sd = map_id2sd(account_id); // <account id>
6713 if( sd == NULL )
6714 {
6715 ShowError("script:delitem2: player not found (AID=%d).\n", account_id);
6716 st->state = END;
6717 return 1;
6718 }
6719 }
6720 else
6721 {
6722 sd = script_rid2sd(st);// attached player
6723 if( sd == NULL )
6724 return 0;
6725 }
6726
6727 data = script_getdata(st,2);
6728 get_val(st,data);
6729 if( data_isstring(data) )
6730 {
6731 const char* item_name = conv_str(st,data);
6732 struct item_data* id = itemdb_searchname(item_name);
6733 if( id == NULL )
6734 {
6735 ShowError("script:delitem2: unknown item \"%s\".\n", item_name);
6736 st->state = END;
6737 return 1;
6738 }
6739 it.nameid = id->nameid;// "<item name>"
6740 }
6741 else
6742 {
6743 it.nameid = conv_num(st,data);// <item id>
6744 if( !itemdb_exists( it.nameid ) )
6745 {
6746 ShowError("script:delitem: unknown item \"%d\".\n", it.nameid);
6747 st->state = END;
6748 return 1;
6749 }
6750 }
6751
6752 it.amount=script_getnum(st,3);
6753 it.identify=script_getnum(st,4);
6754 it.refine=script_getnum(st,5);
6755 it.attribute=script_getnum(st,6);
6756 it.card[0]=(short)script_getnum(st,7);
6757 it.card[1]=(short)script_getnum(st,8);
6758 it.card[2]=(short)script_getnum(st,9);
6759 it.card[3]=(short)script_getnum(st,10);
6760
6761 if( it.amount <= 0 )
6762 return 0;// nothing to do
6763
6764 if( buildin_delitem_search(sd, &it, true) )
6765 {// success
6766 return 0;
6767 }
6768
6769 ShowError("script:delitem2: failed to delete %d items (AID=%d item_id=%d).\n", it.amount, sd->status.account_id, it.nameid);
6770 st->state = END;
6771 clif_scriptclose(sd, st->oid);
6772 return 1;
6773}
6774
6775/*==========================================
6776 * Enables/Disables use of items while in an NPC [Skotlex]
6777 *------------------------------------------*/
6778BUILDIN_FUNC(enableitemuse)
6779{
6780 TBL_PC *sd;
6781 sd=script_rid2sd(st);
6782 if (sd)
6783 sd->npc_item_flag = st->oid;
6784 return 0;
6785}
6786
6787BUILDIN_FUNC(disableitemuse)
6788{
6789 TBL_PC *sd;
6790 sd=script_rid2sd(st);
6791 if (sd)
6792 sd->npc_item_flag = 0;
6793 return 0;
6794}
6795
6796/*==========================================
6797 *ã‚ャラ関係ã®ãƒ‘ラメータå–å¾—
6798 *------------------------------------------*/
6799BUILDIN_FUNC(readparam)
6800{
6801 int type;
6802 TBL_PC *sd;
6803
6804 type=script_getnum(st,2);
6805 if( script_hasdata(st,3) )
6806 sd=map_nick2sd(script_getstr(st,3));
6807 else
6808 sd=script_rid2sd(st);
6809
6810 if(sd==NULL){
6811 script_pushint(st,-1);
6812 return 0;
6813 }
6814
6815 script_pushint(st,pc_readparam(sd,type));
6816
6817 return 0;
6818}
6819/*==========================================
6820 *ã‚ャラ関係ã®IDå–å¾—
6821 *------------------------------------------*/
6822BUILDIN_FUNC(getcharid)
6823{
6824 int num;
6825 TBL_PC *sd;
6826
6827 num = script_getnum(st,2);
6828 if( script_hasdata(st,3) )
6829 sd=map_nick2sd(script_getstr(st,3));
6830 else
6831 sd=script_rid2sd(st);
6832
6833 if(sd==NULL){
6834 script_pushint(st,0); //return 0, according docs
6835 return 0;
6836 }
6837
6838 switch( num ) {
6839 case 0: script_pushint(st,sd->status.char_id); break;
6840 case 1: script_pushint(st,sd->status.party_id); break;
6841 case 2: script_pushint(st,sd->status.guild_id); break;
6842 case 3: script_pushint(st,sd->status.account_id); break;
6843 case 4: script_pushint(st,sd->bg_id); break;
6844 case 5: script_pushint(st,sd->status.faction_id); break;
6845 default:
6846 ShowError("buildin_getcharid: invalid parameter (%d).\n", num);
6847 script_pushint(st,0);
6848 break;
6849 }
6850
6851 return 0;
6852}
6853/*==========================================
6854 * [Paradox924X]
6855 *------------------------------------------*/
6856BUILDIN_FUNC(getnpcid)
6857{
6858 int num = script_getnum(st,2);
6859 struct npc_data* nd = NULL;
6860
6861 if( script_hasdata(st,3) )
6862 {// unique npc name
6863 if( ( nd = npc_name2id(script_getstr(st,3)) ) == NULL )
6864 {
6865 ShowError("buildin_getnpcid: No such NPC '%s'.\n", script_getstr(st,3));
6866 script_pushint(st,0);
6867 return 1;
6868 }
6869 }
6870
6871 switch (num) {
6872 case 0:
6873 script_pushint(st,nd ? nd->bl.id : st->oid);
6874 break;
6875 default:
6876 ShowError("buildin_getnpcid: invalid parameter (%d).\n", num);
6877 script_pushint(st,0);
6878 return 1;
6879 }
6880
6881 return 0;
6882}
6883/*==========================================
6884 *指定IDã®PTåå–å¾—
6885 *------------------------------------------*/
6886BUILDIN_FUNC(getpartyname)
6887{
6888 int party_id;
6889 struct party_data* p;
6890
6891 party_id = script_getnum(st,2);
6892
6893 if( ( p = party_search(party_id) ) != NULL )
6894 {
6895 script_pushstrcopy(st,p->party.name);
6896 }
6897 else
6898 {
6899 script_pushconststr(st,"null");
6900 }
6901 return 0;
6902}
6903/*==========================================
6904 *指定IDã®PT人数ã¨ãƒ¡ãƒ³ãƒãƒ¼IDå–å¾—
6905 *------------------------------------------*/
6906BUILDIN_FUNC(getpartymember)
6907{
6908 struct party_data *p;
6909 int i,j=0,type=0;
6910
6911 p=party_search(script_getnum(st,2));
6912
6913 if( script_hasdata(st,3) )
6914 type=script_getnum(st,3);
6915
6916 if(p!=NULL){
6917 for(i=0;i<MAX_PARTY;i++){
6918 if(p->party.member[i].account_id){
6919 switch (type) {
6920 case 2:
6921 mapreg_setreg(reference_uid(add_str("$@partymemberaid"), j),p->party.member[i].account_id);
6922 break;
6923 case 1:
6924 mapreg_setreg(reference_uid(add_str("$@partymembercid"), j),p->party.member[i].char_id);
6925 break;
6926 default:
6927 mapreg_setregstr(reference_uid(add_str("$@partymembername$"), j),p->party.member[i].name);
6928 }
6929 j++;
6930 }
6931 }
6932 }
6933 mapreg_setreg(add_str("$@partymembercount"),j);
6934
6935 return 0;
6936}
6937
6938/*==========================================
6939 * Retrieves party leader. if flag is specified,
6940 * return some of the leader data. Otherwise, return name.
6941 *------------------------------------------*/
6942
6943 // [ by Emistry ]
6944BUILDIN_FUNC(restock)
6945{
6946 int i,get_itemid,get_amount;
6947 TBL_PC *sd;
6948 struct storage_data *stor;
6949
6950 sd = script_rid2sd(st);
6951 if( sd == NULL ) return 0;
6952
6953 stor = &sd->status.storage;
6954
6955 get_itemid = script_getnum(st,2);
6956 get_amount = script_getnum(st,3);
6957
6958 if( get_itemid <= 0 || get_amount <= 0 ){
6959 ShowError( "buildin_restock: parameter(s) value must not less than 1.\n" );
6960 return 1;
6961 }
6962
6963 for( i = 0; i < MAX_STORAGE; i++ )
6964 if( stor->items[i].nameid == get_itemid ){
6965 if( stor->items[i].amount >= 1 ){
6966 if( stor->items[i].amount < get_amount ) get_amount = stor->items[i].amount;
6967 storage_storageget(sd, i, get_amount);
6968 }
6969 break;
6970 }
6971
6972 return 0;
6973}
6974BUILDIN_FUNC(getpartyleader)
6975{
6976 int party_id, type = 0, i=0;
6977 struct party_data *p;
6978
6979 party_id=script_getnum(st,2);
6980 if( script_hasdata(st,3) )
6981 type=script_getnum(st,3);
6982
6983 p=party_search(party_id);
6984
6985 if (p) //Search leader
6986 for(i = 0; i < MAX_PARTY && !p->party.member[i].leader; i++);
6987
6988 if (!p || i == MAX_PARTY) { //leader not found
6989 if (type)
6990 script_pushint(st,-1);
6991 else
6992 script_pushconststr(st,"null");
6993 return 0;
6994 }
6995
6996 switch (type) {
6997 case 1: script_pushint(st,p->party.member[i].account_id); break;
6998 case 2: script_pushint(st,p->party.member[i].char_id); break;
6999 case 3: script_pushint(st,p->party.member[i].class_); break;
7000 case 4: script_pushstrcopy(st,mapindex_id2name(p->party.member[i].map)); break;
7001 case 5: script_pushint(st,p->party.member[i].lv); break;
7002 default: script_pushstrcopy(st,p->party.member[i].name); break;
7003 }
7004 return 0;
7005}
7006
7007/*==========================================
7008 *指定IDã®ã‚®ãƒ«ãƒ‰åå–å¾—
7009 *------------------------------------------*/
7010BUILDIN_FUNC(getguildname)
7011{
7012 int guild_id;
7013 struct guild* g;
7014
7015 guild_id = script_getnum(st,2);
7016
7017 if( ( g = guild_search(guild_id) ) != NULL )
7018 {
7019 script_pushstrcopy(st,g->name);
7020 }
7021 else
7022 {
7023 script_pushconststr(st,"null");
7024 }
7025 return 0;
7026}
7027
7028/*==========================================
7029 *指定IDã®GuildMasteråå–å¾—
7030 *------------------------------------------*/
7031BUILDIN_FUNC(getguildmaster)
7032{
7033 int guild_id;
7034 struct guild* g;
7035
7036 guild_id = script_getnum(st,2);
7037
7038 if( ( g = guild_search(guild_id) ) != NULL )
7039 {
7040 script_pushstrcopy(st,g->member[0].name);
7041 }
7042 else
7043 {
7044 script_pushconststr(st,"null");
7045 }
7046 return 0;
7047}
7048
7049BUILDIN_FUNC(getguildmasterid)
7050{
7051 int guild_id;
7052 struct guild* g;
7053
7054 guild_id = script_getnum(st,2);
7055
7056 if( ( g = guild_search(guild_id) ) != NULL )
7057 {
7058 script_pushint(st,g->member[0].char_id);
7059 }
7060 else
7061 {
7062 script_pushint(st,0);
7063 }
7064 return 0;
7065}
7066
7067/*==========================================
7068 * ã‚ャラクタã®åå‰
7069 *------------------------------------------*/
7070BUILDIN_FUNC(strcharinfo)
7071{
7072 TBL_PC *sd;
7073 int num;
7074 struct guild* g;
7075 struct party_data* p;
7076
7077 sd=script_rid2sd(st);
7078 if (!sd) { //Avoid crashing....
7079 script_pushconststr(st,"");
7080 return 0;
7081 }
7082 num=script_getnum(st,2);
7083 switch(num){
7084 case 0:
7085 script_pushstrcopy(st,sd->status.name);
7086 break;
7087 case 1:
7088 if( ( p = party_search(sd->status.party_id) ) != NULL )
7089 {
7090 script_pushstrcopy(st,p->party.name);
7091 }
7092 else
7093 {
7094 script_pushconststr(st,"");
7095 }
7096 break;
7097 case 2:
7098 if( ( g = guild_search(sd->status.guild_id) ) != NULL )
7099 {
7100 script_pushstrcopy(st,g->name);
7101 }
7102 else
7103 {
7104 script_pushconststr(st,"");
7105 }
7106 break;
7107 case 3:
7108 script_pushconststr(st,map[sd->bl.m].name);
7109 break;
7110 default:
7111 ShowWarning("buildin_strcharinfo: unknown parameter.\n");
7112 script_pushconststr(st,"");
7113 break;
7114 }
7115
7116 return 0;
7117}
7118
7119/*==========================================
7120 * 呼ã³å‡ºã—å…ƒã®NPCæƒ…å ±ã‚’å–å¾—ã™ã‚‹
7121 *------------------------------------------*/
7122BUILDIN_FUNC(strnpcinfo)
7123{
7124 TBL_NPC* nd;
7125 int num;
7126 char *buf,*name=NULL;
7127
7128 nd = map_id2nd(st->oid);
7129 if (!nd) {
7130 script_pushconststr(st, "");
7131 return 0;
7132 }
7133
7134 num = script_getnum(st,2);
7135 switch(num){
7136 case 0: // display name
7137 name = aStrdup(nd->name);
7138 break;
7139 case 1: // visible part of display name
7140 if((buf = strchr(nd->name,'#')) != NULL)
7141 {
7142 name = aStrdup(nd->name);
7143 name[buf - nd->name] = 0;
7144 } else // Return the name, there is no '#' present
7145 name = aStrdup(nd->name);
7146 break;
7147 case 2: // # fragment
7148 if((buf = strchr(nd->name,'#')) != NULL)
7149 name = aStrdup(buf+1);
7150 break;
7151 case 3: // unique name
7152 name = aStrdup(nd->exname);
7153 break;
7154 case 4: // map name
7155 name = aStrdup(map[nd->bl.m].name);
7156 break;
7157 }
7158
7159 if(name)
7160 script_pushstr(st, name);
7161 else
7162 script_pushconststr(st, "");
7163
7164 return 0;
7165}
7166
7167
7168// aegis->athena slot position conversion table
7169static unsigned int equip[] = {EQP_HEAD_TOP,EQP_ARMOR,EQP_HAND_L,EQP_HAND_R,EQP_GARMENT,EQP_SHOES,EQP_ACC_L,EQP_ACC_R,EQP_HEAD_MID,EQP_HEAD_LOW};
7170
7171/*==========================================
7172 * GetEquipID(Pos); Pos: 1-10
7173 *------------------------------------------*/
7174BUILDIN_FUNC(getequipid)
7175{
7176 int i, num;
7177 TBL_PC* sd;
7178 struct item_data* item;
7179
7180 sd = script_rid2sd(st);
7181 if( sd == NULL )
7182 return 0;
7183
7184 num = script_getnum(st,2) - 1;
7185 if( num < 0 || num >= ARRAYLENGTH(equip) )
7186 {
7187 script_pushint(st,-1);
7188 return 0;
7189 }
7190
7191 // get inventory position of item
7192 i = pc_checkequip(sd,equip[num]);
7193 if( i < 0 )
7194 {
7195 script_pushint(st,-1);
7196 return 0;
7197 }
7198
7199 item = sd->inventory_data[i];
7200 if( item != 0 )
7201 script_pushint(st,item->nameid);
7202 else
7203 script_pushint(st,0);
7204
7205 return 0;
7206}
7207
7208/*==========================================
7209 * è£…å‚™åæ–‡å—列(精錬メニュー用)
7210 *------------------------------------------*/
7211BUILDIN_FUNC(getequipname)
7212{
7213 int i, num;
7214 TBL_PC* sd;
7215 struct item_data* item;
7216
7217 sd = script_rid2sd(st);
7218 if( sd == NULL )
7219 return 0;
7220
7221 num = script_getnum(st,2) - 1;
7222 if( num < 0 || num >= ARRAYLENGTH(equip) )
7223 {
7224 script_pushconststr(st,"");
7225 return 0;
7226 }
7227
7228 // get inventory position of item
7229 i = pc_checkequip(sd,equip[num]);
7230 if( i < 0 )
7231 {
7232 script_pushint(st,-1);
7233 return 0;
7234 }
7235
7236 item = sd->inventory_data[i];
7237 if( item != 0 )
7238 script_pushstrcopy(st,item->jname);
7239 else
7240 script_pushconststr(st,"");
7241
7242 return 0;
7243}
7244
7245/*==========================================
7246 * getbrokenid [Valaris]
7247 *------------------------------------------*/
7248BUILDIN_FUNC(getbrokenid)
7249{
7250 int i,num,id=0,brokencounter=0;
7251 TBL_PC *sd;
7252
7253 sd = script_rid2sd(st);
7254 if( sd == NULL )
7255 return 0;
7256
7257 num=script_getnum(st,2);
7258 for(i=0; i<MAX_INVENTORY; i++) {
7259 if(sd->status.inventory[i].attribute){
7260 brokencounter++;
7261 if(num==brokencounter){
7262 id=sd->status.inventory[i].nameid;
7263 break;
7264 }
7265 }
7266 }
7267
7268 script_pushint(st,id);
7269
7270 return 0;
7271}
7272
7273/*==========================================
7274 * repair [Valaris]
7275 *------------------------------------------*/
7276BUILDIN_FUNC(repair)
7277{
7278 int i,num;
7279 int repaircounter=0;
7280 TBL_PC *sd;
7281
7282 sd = script_rid2sd(st);
7283 if( sd == NULL )
7284 return 0;
7285
7286 num=script_getnum(st,2);
7287 for(i=0; i<MAX_INVENTORY; i++) {
7288 if(sd->status.inventory[i].attribute){
7289 repaircounter++;
7290 if(num==repaircounter){
7291 sd->status.inventory[i].attribute=0;
7292 clif_equiplist(sd);
7293 clif_produceeffect(sd, 0, sd->status.inventory[i].nameid);
7294 clif_misceffect(&sd->bl, 3);
7295 break;
7296 }
7297 }
7298 }
7299
7300 return 0;
7301}
7302
7303BUILDIN_FUNC(repairall)
7304{
7305 int i, repaircounter = 0;
7306 TBL_PC *sd;
7307
7308 sd = script_rid2sd(st);
7309 if( sd == NULL )
7310 return 0;
7311
7312 for( i = 0; i < MAX_INVENTORY; i++ )
7313 {
7314 if( sd->status.inventory[i].nameid && sd->status.inventory[i].attribute )
7315 {
7316 sd->status.inventory[i].attribute = 0;
7317 clif_produceeffect(sd,0,sd->status.inventory[i].nameid);
7318 repaircounter++;
7319 }
7320 }
7321
7322 if( repaircounter )
7323 {
7324 clif_misceffect(&sd->bl, 3);
7325 clif_equiplist(sd);
7326 }
7327
7328 return 0;
7329}
7330
7331/*==========================================
7332 * 装備ãƒã‚§ãƒƒã‚¯
7333 *------------------------------------------*/
7334BUILDIN_FUNC(getequipisequiped)
7335{
7336 int i=-1,num;
7337 TBL_PC *sd;
7338
7339 num=script_getnum(st,2);
7340 sd = script_rid2sd(st);
7341 if( sd == NULL )
7342 return 0;
7343
7344 if (num > 0 && num <= ARRAYLENGTH(equip))
7345 i=pc_checkequip(sd,equip[num-1]);
7346
7347 if(i >= 0)
7348 script_pushint(st,1);
7349 else
7350 script_pushint(st,0);
7351 return 0;
7352}
7353
7354/*==========================================
7355 * 装備å“精錬å¯èƒ½ãƒã‚§ãƒƒã‚¯
7356 *------------------------------------------*/
7357BUILDIN_FUNC(getequipisenableref)
7358{
7359 int i=-1,num;
7360 TBL_PC *sd;
7361
7362 num=script_getnum(st,2);
7363 sd = script_rid2sd(st);
7364 if( sd == NULL )
7365 return 0;
7366
7367 if( num > 0 && num <= ARRAYLENGTH(equip) )
7368 i = pc_checkequip(sd,equip[num-1]);
7369 if( i >= 0 && sd->inventory_data[i] && !sd->inventory_data[i]->flag.no_refine && !sd->status.inventory[i].expire_time )
7370 script_pushint(st,1);
7371 else
7372 script_pushint(st,0);
7373
7374 return 0;
7375}
7376
7377/*==========================================
7378 * 装備å“鑑定ãƒã‚§ãƒƒã‚¯
7379 *------------------------------------------*/
7380BUILDIN_FUNC(getequipisidentify)
7381{
7382 int i=-1,num;
7383 TBL_PC *sd;
7384
7385 num=script_getnum(st,2);
7386 sd = script_rid2sd(st);
7387 if( sd == NULL )
7388 return 0;
7389
7390 if (num > 0 && num <= ARRAYLENGTH(equip))
7391 i=pc_checkequip(sd,equip[num-1]);
7392 if(i >= 0)
7393 script_pushint(st,sd->status.inventory[i].identify);
7394 else
7395 script_pushint(st,0);
7396
7397 return 0;
7398}
7399
7400/*==========================================
7401 * 装備å“精錬度
7402 *------------------------------------------*/
7403BUILDIN_FUNC(getequiprefinerycnt)
7404{
7405 int i=-1,num;
7406 TBL_PC *sd;
7407
7408 num=script_getnum(st,2);
7409 sd = script_rid2sd(st);
7410 if( sd == NULL )
7411 return 0;
7412
7413 if (num > 0 && num <= ARRAYLENGTH(equip))
7414 i=pc_checkequip(sd,equip[num-1]);
7415 if(i >= 0)
7416 script_pushint(st,sd->status.inventory[i].refine);
7417 else
7418 script_pushint(st,0);
7419
7420 return 0;
7421}
7422
7423/*==========================================
7424 * è£…å‚™å“æ¦å™¨LV
7425 *------------------------------------------*/
7426BUILDIN_FUNC(getequipweaponlv)
7427{
7428 int i=-1,num;
7429 TBL_PC *sd;
7430
7431 num=script_getnum(st,2);
7432 sd = script_rid2sd(st);
7433 if( sd == NULL )
7434 return 0;
7435
7436 if (num > 0 && num <= ARRAYLENGTH(equip))
7437 i=pc_checkequip(sd,equip[num-1]);
7438 if(i >= 0 && sd->inventory_data[i])
7439 script_pushint(st,sd->inventory_data[i]->wlv);
7440 else
7441 script_pushint(st,0);
7442
7443 return 0;
7444}
7445
7446BUILDIN_FUNC(getequipisrental)
7447{
7448 int i=-1,num;
7449 TBL_PC *sd;
7450
7451 num=script_getnum(st,2);
7452 sd = script_rid2sd(st);
7453 if( sd == NULL )
7454 return 0;
7455
7456 if (num > 0 && num <= ARRAYLENGTH(equip))
7457 i=pc_checkequip(sd,equip[num-1]);
7458
7459 if(i >= 0 && sd->status.inventory[i].expire_time)
7460 script_pushint(st,1);
7461 else
7462 script_pushint(st,0);
7463
7464 return 0;
7465}
7466
7467BUILDIN_FUNC(getequipisbounded)
7468{
7469 int i=-1,num;
7470 TBL_PC *sd;
7471
7472 num=script_getnum(st,2);
7473 sd = script_rid2sd(st);
7474 if( sd == NULL )
7475 return 0;
7476
7477 if (num > 0 && num <= ARRAYLENGTH(equip))
7478 i=pc_checkequip(sd,equip[num-1]);
7479
7480 if(i >= 0 && sd->status.inventory[i].bound)
7481 script_pushint(st,1);
7482 else
7483 script_pushint(st,0);
7484
7485 return 0;
7486}
7487
7488/*==========================================
7489 * 装備å“精錬æˆåŠŸçŽ‡
7490 *------------------------------------------*/
7491BUILDIN_FUNC(getequippercentrefinery)
7492{
7493 int i=-1,num;
7494 TBL_PC *sd;
7495
7496 num=script_getnum(st,2);
7497 sd = script_rid2sd(st);
7498 if( sd == NULL )
7499 return 0;
7500
7501 if (num > 0 && num <= ARRAYLENGTH(equip))
7502 i=pc_checkequip(sd,equip[num-1]);
7503 if(i >= 0 && sd->status.inventory[i].nameid && sd->status.inventory[i].refine < MAX_REFINE)
7504 script_pushint(st,percentrefinery[itemdb_wlv(sd->status.inventory[i].nameid)][(int)sd->status.inventory[i].refine]);
7505 else
7506 script_pushint(st,0);
7507
7508 return 0;
7509}
7510
7511/*==========================================
7512 * Costume Items
7513 *------------------------------------------*/
7514BUILDIN_FUNC(costume)
7515{
7516 int i = -1, num, ep;
7517 TBL_PC *sd;
7518
7519 num = script_getnum(st,2); // Equip Slot
7520 sd = script_rid2sd(st);
7521
7522 if( sd == NULL )
7523 return 0;
7524 if( num > 0 && num <= ARRAYLENGTH(equip) )
7525 i = pc_checkequip(sd, equip[num - 1]);
7526 if( i < 0 )
7527 return 0;
7528
7529 ep = sd->status.inventory[i].equip;
7530 if( !(ep&EQP_HEAD_LOW) && !(ep&EQP_HEAD_MID) && !(ep&EQP_HEAD_TOP) )
7531 return 0;
7532
7533 log_pick(&sd->bl, LOG_TYPE_SCRIPT, sd->status.inventory[i].nameid, -1, &sd->status.inventory[i]);
7534 pc_unequipitem(sd,i,2);
7535 clif_delitem(sd,i,1,3);
7536 // --------------------------------------------------------------------
7537 sd->status.inventory[i].refine = 0;
7538 sd->status.inventory[i].card[0] = CARD0_CREATE;
7539 sd->status.inventory[i].card[1] = 0;
7540 sd->status.inventory[i].card[2] = GetWord(battle_config.costume_reserved_char_id, 0);
7541 sd->status.inventory[i].card[3] = GetWord(battle_config.costume_reserved_char_id, 1);
7542
7543 if( ep&EQP_HEAD_TOP ) { ep &= ~EQP_HEAD_TOP; ep |= EQP_COS_HEAD_TOP; }
7544 if( ep&EQP_HEAD_LOW ) { ep &= ~EQP_HEAD_LOW; ep |= EQP_COS_HEAD_LOW; }
7545 if( ep&EQP_HEAD_MID ) { ep &= ~EQP_HEAD_MID; ep |= EQP_COS_HEAD_MID; }
7546 // --------------------------------------------------------------------
7547 log_pick(&sd->bl, LOG_TYPE_SCRIPT, sd->status.inventory[i].nameid, 1, &sd->status.inventory[i]);
7548
7549 clif_additem(sd,i,1,0);
7550 pc_equipitem(sd,i,ep);
7551 clif_misceffect(&sd->bl,3);
7552
7553 return 0;
7554}
7555
7556/*==========================================
7557 * æ¤rmor Enchanting
7558 *------------------------------------------*/
7559BUILDIN_FUNC(successenchant)
7560{
7561 int i = -1, j, num, enchant, ep;
7562 char chat_announce[256];
7563 TBL_PC *sd;
7564
7565 num = script_getnum(st,2); // Equip Slot
7566 enchant = script_getnum(st,3); // Equip Enchant
7567 sd = script_rid2sd(st);
7568 if( sd == NULL || !itemdb_isenchant(enchant) )
7569 return 0;
7570 if( num > 0 && num <= ARRAYLENGTH(equip) )
7571 i = pc_checkequip(sd, equip[num - 1]);
7572 if( i < 0 )
7573 return 0;
7574 if( !sd->inventory_data[i] || sd->inventory_data[i]->slot >= MAX_SLOTS )
7575 return 0; // Cannot enchant an item with 4 slots. Enchant uses last slot.
7576
7577 ep = sd->status.inventory[i].equip;
7578 log_pick(&sd->bl, LOG_TYPE_SCRIPT, sd->status.inventory[i].nameid, -1, &sd->status.inventory[i]);
7579
7580 // By Official Info: Item will lose cards, refine and previus enchants.
7581 for( j = 0; j < MAX_SLOTS; j++ )
7582 sd->status.inventory[i].card[j] = 0;
7583 sd->status.inventory[i].refine = 0;
7584 // --------------------------------------------------------------------
7585
7586 pc_unequipitem(sd,i,2);
7587 clif_delitem(sd,i,1,3);
7588 sd->status.inventory[i].card[MAX_SLOTS - 1] = enchant;
7589 log_pick(&sd->bl, LOG_TYPE_SCRIPT, sd->status.inventory[i].nameid, 1, &sd->status.inventory[i]);
7590
7591 clif_additem(sd,i,1,0);
7592 pc_equipitem(sd,i,ep);
7593 clif_misceffect(&sd->bl,3);
7594
7595 if( battle_config.channel_announces&8 && server_channel[CHN_VENDING] )
7596 {
7597 sprintf(chat_announce, msg_txt(892), server_channel[CHN_VENDING]->name, sd->status.name, sd->inventory_data[i]->jname, sd->inventory_data[i]->slot, itemdb_search(enchant)->jname);
7598 clif_channel_message(server_channel[CHN_VENDING], chat_announce, 26);
7599 }
7600
7601 return 0;
7602}
7603
7604BUILDIN_FUNC(failedenchant)
7605{
7606 int i = -1, num;
7607 TBL_PC *sd;
7608
7609 num = script_getnum(st,2);
7610 sd = script_rid2sd(st);
7611 if( sd == NULL )
7612 return 0;
7613 if( num > 0 && num <= ARRAYLENGTH(equip) )
7614 i = pc_checkequip(sd, equip[num - 1]);
7615 if( i >= 0 )
7616 {
7617 pc_unequipitem(sd,i,3);
7618 pc_delitem(sd,i,1,0,2,LOG_TYPE_SCRIPT);
7619 clif_misceffect(&sd->bl,2);
7620 }
7621
7622 return 0;
7623}
7624
7625/*==========================================
7626 * 精錬æˆåŠŸ
7627 *------------------------------------------*/
7628BUILDIN_FUNC(successrefitem)
7629{
7630 int i=-1,num,ep;
7631 TBL_PC *sd;
7632
7633 num=script_getnum(st,2);
7634 sd = script_rid2sd(st);
7635 if( sd == NULL )
7636 return 0;
7637
7638 if (num > 0 && num <= ARRAYLENGTH(equip))
7639 i=pc_checkequip(sd,equip[num-1]);
7640 if(i >= 0) {
7641 short announce_refine[] = { 7, 9, 8, 7, 5 };
7642
7643 ep=sd->status.inventory[i].equip;
7644
7645 //Logs items, got from (N)PC scripts [Lupus]
7646 log_pick(&sd->bl, LOG_TYPE_SCRIPT, sd->status.inventory[i].nameid, -1, &sd->status.inventory[i]);
7647
7648 sd->status.inventory[i].refine++;
7649 pc_unequipitem(sd,i,2); // status calc will happen in pc_equipitem() below
7650
7651 clif_refine(sd->fd,0,i,sd->status.inventory[i].refine);
7652 clif_delitem(sd,i,1,3);
7653
7654 //Logs items, got from (N)PC scripts [Lupus]
7655 log_pick(&sd->bl, LOG_TYPE_SCRIPT, sd->status.inventory[i].nameid, 1, &sd->status.inventory[i]);
7656
7657 clif_additem(sd,i,1,0);
7658 pc_equipitem(sd,i,ep);
7659 clif_misceffect(&sd->bl,3);
7660
7661 if( battle_config.channel_announces&4 && server_channel[CHN_VENDING] && sd->inventory_data[i]->wlv >= 0 && sd->inventory_data[i]->wlv <= 4 && sd->status.inventory[i].refine >= announce_refine[sd->inventory_data[i]->wlv] )
7662 { // Announces Refines to Chat
7663 char chat_announce[256];
7664 sprintf(chat_announce, msg_txt(821), server_channel[CHN_VENDING]->name, sd->status.name, sd->status.inventory[i].refine, sd->inventory_data[i]->jname, sd->inventory_data[i]->slot);
7665 clif_channel_message(server_channel[CHN_VENDING], chat_announce, 26);
7666 }
7667
7668 if(sd->status.inventory[i].refine == MAX_REFINE &&
7669 sd->status.inventory[i].card[0] == CARD0_FORGE &&
7670 sd->status.char_id == (int)MakeDWord(sd->status.inventory[i].card[2],sd->status.inventory[i].card[3])
7671 ){ // Fame point system [DracoRPG]
7672 switch (sd->inventory_data[i]->wlv){
7673 case 1:
7674 pc_addfame(sd,1,0); // Success to refine to +10 a lv1 weapon you forged = +1 fame point
7675 break;
7676 case 2:
7677 pc_addfame(sd,25,0); // Success to refine to +10 a lv2 weapon you forged = +25 fame point
7678 break;
7679 case 3:
7680 pc_addfame(sd,1000,0); // Success to refine to +10 a lv3 weapon you forged = +1000 fame point
7681 break;
7682 }
7683 }
7684 }
7685
7686 return 0;
7687}
7688
7689/*==========================================
7690 * 精錬失敗
7691 *------------------------------------------*/
7692BUILDIN_FUNC(failedrefitem)
7693{
7694 int i=-1,num;
7695 TBL_PC *sd;
7696
7697 num=script_getnum(st,2);
7698 sd = script_rid2sd(st);
7699 if( sd == NULL )
7700 return 0;
7701
7702 if (num > 0 && num <= ARRAYLENGTH(equip))
7703 i=pc_checkequip(sd,equip[num-1]);
7704 if(i >= 0) {
7705 short announce_refine[] = { 7, 9, 8, 7, 5 };
7706
7707 if( battle_config.channel_announces&4 && server_channel[CHN_VENDING] && sd->inventory_data[i]->wlv >= 0 && sd->inventory_data[i]->wlv <= 4 && sd->status.inventory[i].refine >= announce_refine[sd->inventory_data[i]->wlv] )
7708 { // Announces Refines to Chat
7709 char chat_announce[256];
7710 sprintf(chat_announce, msg_txt(822), server_channel[CHN_VENDING]->name, sd->status.name, sd->status.inventory[i].refine, sd->inventory_data[i]->jname, sd->inventory_data[i]->slot);
7711 clif_channel_message(server_channel[CHN_VENDING], chat_announce, 1);
7712 }
7713
7714 sd->status.inventory[i].refine = 0;
7715 pc_unequipitem(sd,i,3);
7716 // 精錬失敗エフェクトã®ãƒ‘ケット
7717 clif_refine(sd->fd,1,i,sd->status.inventory[i].refine);
7718
7719 pc_delitem(sd,i,1,0,2,LOG_TYPE_SCRIPT);
7720 // ä»–ã®äººã«ã‚‚失敗を通知
7721 clif_misceffect(&sd->bl,2);
7722 }
7723
7724 return 0;
7725}
7726
7727BUILDIN_FUNC(failedrefitemR) // by jakeRed
7728{
7729 int i=-1,num,ep,ref;
7730 TBL_PC *sd;
7731
7732 num = script_getnum(st,2); // Equip Slot
7733 ref = script_getnum(st,3); // Refine Points Lost
7734 sd = script_rid2sd(st);
7735
7736 if( sd == NULL )
7737 return 0;
7738
7739 if( num > 0 && num <= ARRAYLENGTH(equip) )
7740 i = pc_checkequip(sd,equip[num-1]);
7741 if( i >= 0 )
7742 {
7743 short announce_refine[] = { 7, 9, 8, 7, 5 };
7744 ep = sd->status.inventory[i].equip;
7745
7746 //Logs items, got from (N)PC scripts [Lupus]
7747 log_pick(&sd->bl, LOG_TYPE_SCRIPT, sd->status.inventory[i].nameid, -1, &sd->status.inventory[i]);
7748
7749 if( battle_config.channel_announces&4 && server_channel[CHN_VENDING] && sd->inventory_data[i]->wlv >= 0 && sd->inventory_data[i]->wlv <= 4 && sd->status.inventory[i].refine >= announce_refine[sd->inventory_data[i]->wlv] )
7750 { // Announces Refines to Chat
7751 char chat_announce[256];
7752 sprintf(chat_announce, msg_txt(904), server_channel[CHN_VENDING]->name, sd->status.name, sd->status.inventory[i].refine, sd->inventory_data[i]->jname, sd->inventory_data[i]->slot,(sd->status.inventory[i].refine - ref));
7753 clif_channel_message(server_channel[CHN_VENDING], chat_announce, 1);
7754 }
7755
7756 ref = min(ref,sd->status.inventory[i].refine); // To avoid negative Refine
7757 sd->status.inventory[i].refine = sd->status.inventory[i].refine - ref;
7758
7759 pc_unequipitem(sd,i,2); // status calc will happen in pc_equipitem() below
7760 clif_refine(sd->fd,0,i,sd->status.inventory[i].refine);
7761 clif_delitem(sd,i,1,3);
7762 log_pick(&sd->bl, LOG_TYPE_SCRIPT, sd->status.inventory[i].nameid, 1, &sd->status.inventory[i]);
7763
7764 clif_additem(sd,i,1,0);
7765 pc_equipitem(sd,i,ep);
7766 clif_misceffect(&sd->bl,2);
7767 }
7768
7769 return 0;
7770}
7771
7772/*==========================================
7773 *
7774 *------------------------------------------*/
7775BUILDIN_FUNC(statusup)
7776{
7777 int type;
7778 TBL_PC *sd;
7779
7780 type=script_getnum(st,2);
7781 sd = script_rid2sd(st);
7782 if( sd == NULL )
7783 return 0;
7784
7785 pc_statusup(sd,type);
7786
7787 return 0;
7788}
7789/*==========================================
7790 *
7791 *------------------------------------------*/
7792BUILDIN_FUNC(statusup2)
7793{
7794 int type,val;
7795 TBL_PC *sd;
7796
7797 type=script_getnum(st,2);
7798 val=script_getnum(st,3);
7799 sd = script_rid2sd(st);
7800 if( sd == NULL )
7801 return 0;
7802
7803 pc_statusup2(sd,type,val);
7804
7805 return 0;
7806}
7807
7808/// See 'doc/item_bonus.txt'
7809///
7810/// bonus <bonus type>,<val1>;
7811/// bonus2 <bonus type>,<val1>,<val2>;
7812/// bonus3 <bonus type>,<val1>,<val2>,<val3>;
7813/// bonus4 <bonus type>,<val1>,<val2>,<val3>,<val4>;
7814/// bonus5 <bonus type>,<val1>,<val2>,<val3>,<val4>,<val5>;
7815BUILDIN_FUNC(bonus)
7816{
7817 int type;
7818 int val1;
7819 int val2 = 0;
7820 int val3 = 0;
7821 int val4 = 0;
7822 int val5 = 0;
7823 TBL_PC* sd;
7824
7825 sd = script_rid2sd(st);
7826 if( sd == NULL )
7827 return 0; // no player attached
7828
7829 type = script_getnum(st,2);
7830 switch( type )
7831 {
7832 case SP_AUTOSPELL:
7833 case SP_AUTOSPELL_WHENHIT:
7834 case SP_AUTOSPELL_ONSKILL:
7835 case SP_SKILL_ATK:
7836 case SP_SKILL_HEAL:
7837 case SP_SKILL_HEAL2:
7838 case SP_ADD_SKILL_BLOW:
7839 case SP_CASTRATE:
7840 case SP_ADDEFF_ONSKILL:
7841 // these bonuses support skill names
7842 val1 = ( script_isstring(st,3) ? skill_name2id(script_getstr(st,3)) : script_getnum(st,3) );
7843 break;
7844 default:
7845 val1 = script_getnum(st,3);
7846 break;
7847 }
7848
7849 switch( script_lastdata(st)-2 )
7850 {
7851 case 1:
7852 pc_bonus(sd, type, val1);
7853 break;
7854 case 2:
7855 val2 = script_getnum(st,4);
7856 pc_bonus2(sd, type, val1, val2);
7857 break;
7858 case 3:
7859 val2 = script_getnum(st,4);
7860 val3 = script_getnum(st,5);
7861 pc_bonus3(sd, type, val1, val2, val3);
7862 break;
7863 case 4:
7864 if( type == SP_AUTOSPELL_ONSKILL && script_isstring(st,4) )
7865 val2 = skill_name2id(script_getstr(st,4)); // 2nd value can be skill name
7866 else
7867 val2 = script_getnum(st,4);
7868
7869 val3 = script_getnum(st,5);
7870 val4 = script_getnum(st,6);
7871 pc_bonus4(sd, type, val1, val2, val3, val4);
7872 break;
7873 case 5:
7874 if( type == SP_AUTOSPELL_ONSKILL && script_isstring(st,4) )
7875 val2 = skill_name2id(script_getstr(st,4)); // 2nd value can be skill name
7876 else
7877 val2 = script_getnum(st,4);
7878
7879 val3 = script_getnum(st,5);
7880 val4 = script_getnum(st,6);
7881 val5 = script_getnum(st,7);
7882 pc_bonus5(sd, type, val1, val2, val3, val4, val5);
7883 break;
7884 default:
7885 ShowDebug("buildin_bonus: unexpected number of arguments (%d)\n", (script_lastdata(st) - 1));
7886 break;
7887 }
7888
7889 return 0;
7890}
7891
7892BUILDIN_FUNC(autobonus)
7893{
7894 unsigned int dur;
7895 short rate;
7896 short atk_type = 0;
7897 TBL_PC* sd;
7898 const char *bonus_script, *other_script = NULL;
7899
7900 sd = script_rid2sd(st);
7901 if( sd == NULL )
7902 return 0; // no player attached
7903
7904 if( sd->state.autobonus&sd->status.inventory[current_equip_item_index].equip )
7905 return 0;
7906
7907 rate = script_getnum(st,3);
7908 dur = script_getnum(st,4);
7909 bonus_script = script_getstr(st,2);
7910 if( !rate || !dur || !bonus_script )
7911 return 0;
7912
7913 if( script_hasdata(st,5) )
7914 atk_type = script_getnum(st,5);
7915 if( script_hasdata(st,6) )
7916 other_script = script_getstr(st,6);
7917
7918 if( pc_addautobonus(sd->autobonus,ARRAYLENGTH(sd->autobonus),
7919 bonus_script,rate,dur,atk_type,other_script,sd->status.inventory[current_equip_item_index].equip,false) )
7920 {
7921 script_add_autobonus(bonus_script);
7922 if( other_script )
7923 script_add_autobonus(other_script);
7924 }
7925
7926 return 0;
7927}
7928
7929BUILDIN_FUNC(autobonus2)
7930{
7931 unsigned int dur;
7932 short rate;
7933 short atk_type = 0;
7934 TBL_PC* sd;
7935 const char *bonus_script, *other_script = NULL;
7936
7937 sd = script_rid2sd(st);
7938 if( sd == NULL )
7939 return 0; // no player attached
7940
7941 if( sd->state.autobonus&sd->status.inventory[current_equip_item_index].equip )
7942 return 0;
7943
7944 rate = script_getnum(st,3);
7945 dur = script_getnum(st,4);
7946 bonus_script = script_getstr(st,2);
7947 if( !rate || !dur || !bonus_script )
7948 return 0;
7949
7950 if( script_hasdata(st,5) )
7951 atk_type = script_getnum(st,5);
7952 if( script_hasdata(st,6) )
7953 other_script = script_getstr(st,6);
7954
7955 if( pc_addautobonus(sd->autobonus2,ARRAYLENGTH(sd->autobonus2),
7956 bonus_script,rate,dur,atk_type,other_script,sd->status.inventory[current_equip_item_index].equip,false) )
7957 {
7958 script_add_autobonus(bonus_script);
7959 if( other_script )
7960 script_add_autobonus(other_script);
7961 }
7962
7963 return 0;
7964}
7965
7966BUILDIN_FUNC(autobonus3)
7967{
7968 unsigned int dur;
7969 short rate,atk_type;
7970 TBL_PC* sd;
7971 const char *bonus_script, *other_script = NULL;
7972
7973 sd = script_rid2sd(st);
7974 if( sd == NULL )
7975 return 0; // no player attached
7976
7977 if( sd->state.autobonus&sd->status.inventory[current_equip_item_index].equip )
7978 return 0;
7979
7980 rate = script_getnum(st,3);
7981 dur = script_getnum(st,4);
7982 atk_type = ( script_isstring(st,5) ? skill_name2id(script_getstr(st,5)) : script_getnum(st,5) );
7983 bonus_script = script_getstr(st,2);
7984 if( !rate || !dur || !atk_type || !bonus_script )
7985 return 0;
7986
7987 if( script_hasdata(st,6) )
7988 other_script = script_getstr(st,6);
7989
7990 if( pc_addautobonus(sd->autobonus3,ARRAYLENGTH(sd->autobonus3),
7991 bonus_script,rate,dur,atk_type,other_script,sd->status.inventory[current_equip_item_index].equip,true) )
7992 {
7993 script_add_autobonus(bonus_script);
7994 if( other_script )
7995 script_add_autobonus(other_script);
7996 }
7997
7998 return 0;
7999}
8000
8001/// Changes the level of a player skill.
8002/// <flag> defaults to 1
8003/// <flag>=0 : set the level of the skill
8004/// <flag>=1 : set the temporary level of the skill
8005/// <flag>=2 : add to the level of the skill
8006///
8007/// skill <skill id>,<level>,<flag>
8008/// skill <skill id>,<level>
8009/// skill "<skill name>",<level>,<flag>
8010/// skill "<skill name>",<level>
8011BUILDIN_FUNC(skill)
8012{
8013 int id;
8014 int level;
8015 int flag = 1;
8016 TBL_PC* sd;
8017
8018 sd = script_rid2sd(st);
8019 if( sd == NULL )
8020 return 0;// no player attached, report source
8021
8022 id = ( script_isstring(st,2) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
8023 level = script_getnum(st,3);
8024 if( script_hasdata(st,4) )
8025 flag = script_getnum(st,4);
8026 pc_skill(sd, id, level, flag);
8027
8028 return 0;
8029}
8030
8031/// Changes the level of a player skill.
8032/// like skill, but <flag> defaults to 2
8033///
8034/// addtoskill <skill id>,<amount>,<flag>
8035/// addtoskill <skill id>,<amount>
8036/// addtoskill "<skill name>",<amount>,<flag>
8037/// addtoskill "<skill name>",<amount>
8038///
8039/// @see skill
8040BUILDIN_FUNC(addtoskill)
8041{
8042 int id;
8043 int level;
8044 int flag = 2;
8045 TBL_PC* sd;
8046
8047 sd = script_rid2sd(st);
8048 if( sd == NULL )
8049 return 0;// no player attached, report source
8050
8051 id = ( script_isstring(st,2) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
8052 level = script_getnum(st,3);
8053 if( script_hasdata(st,4) )
8054 flag = script_getnum(st,4);
8055 pc_skill(sd, id, level, flag);
8056
8057 return 0;
8058}
8059
8060/// Increases the level of a guild skill.
8061///
8062/// guildskill <skill id>,<amount>;
8063/// guildskill "<skill name>",<amount>;
8064BUILDIN_FUNC(guildskill)
8065{
8066 int id;
8067 int level;
8068 TBL_PC* sd;
8069 int i;
8070
8071 sd = script_rid2sd(st);
8072 if( sd == NULL )
8073 return 0;// no player attached, report source
8074
8075 id = ( script_isstring(st,2) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
8076 level = script_getnum(st,3);
8077 for( i=0; i < level; i++ )
8078 guild_skillup(sd, id);
8079
8080 return 0;
8081}
8082
8083/// Returns the level of the player skill.
8084///
8085/// getskilllv(<skill id>) -> <level>
8086/// getskilllv("<skill name>") -> <level>
8087BUILDIN_FUNC(getskilllv)
8088{
8089 int id;
8090 TBL_PC* sd;
8091
8092 sd = script_rid2sd(st);
8093 if( sd == NULL )
8094 return 0;// no player attached, report source
8095
8096 id = ( script_isstring(st,2) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
8097 script_pushint(st, pc_checkskill(sd,id));
8098
8099 return 0;
8100}
8101
8102/// Returns the level of the guild skill.
8103///
8104/// getgdskilllv(<guild id>,<skill id>) -> <level>
8105/// getgdskilllv(<guild id>,"<skill name>") -> <level>
8106BUILDIN_FUNC(getgdskilllv)
8107{
8108 int guild_id;
8109 int skill_id;
8110 struct guild* g;
8111
8112 guild_id = script_getnum(st,2);
8113 skill_id = ( script_isstring(st,3) ? skill_name2id(script_getstr(st,3)) : script_getnum(st,3) );
8114 g = guild_search(guild_id);
8115 if( g == NULL )
8116 script_pushint(st, -1);
8117 else
8118 script_pushint(st, guild_checkskill(g,skill_id));
8119
8120 return 0;
8121}
8122
8123/// Returns the 'basic_skill_check' setting.
8124/// This config determines if the server checks the skill level of NV_BASIC
8125/// before allowing the basic actions.
8126///
8127/// basicskillcheck() -> <bool>
8128BUILDIN_FUNC(basicskillcheck)
8129{
8130 script_pushint(st, battle_config.basic_skill_check);
8131 return 0;
8132}
8133
8134/// Returns the GM level of the player.
8135///
8136/// getgmlevel() -> <level>
8137BUILDIN_FUNC(getgmlevel)
8138{
8139 TBL_PC* sd;
8140
8141 sd = script_rid2sd(st);
8142 if( sd == NULL )
8143 return 0;// no player attached, report source
8144
8145 script_pushint(st, pc_isGM(sd));
8146
8147 return 0;
8148}
8149
8150/// Terminates the execution of this script instance.
8151///
8152/// end
8153BUILDIN_FUNC(end)
8154{
8155 st->state = END;
8156 return 0;
8157}
8158
8159/// Checks if the player has that effect state (option).
8160///
8161/// checkoption(<option>) -> <bool>
8162BUILDIN_FUNC(checkoption)
8163{
8164 int option;
8165 TBL_PC* sd;
8166
8167 sd = script_rid2sd(st);
8168 if( sd == NULL )
8169 return 0;// no player attached, report source
8170
8171 option = script_getnum(st,2);
8172 if( sd->sc.option&option )
8173 script_pushint(st, 1);
8174 else
8175 script_pushint(st, 0);
8176
8177 return 0;
8178}
8179
8180/// Checks if the player is in that body state (opt1).
8181///
8182/// checkoption1(<opt1>) -> <bool>
8183BUILDIN_FUNC(checkoption1)
8184{
8185 int opt1;
8186 TBL_PC* sd;
8187
8188 sd = script_rid2sd(st);
8189 if( sd == NULL )
8190 return 0;// no player attached, report source
8191
8192 opt1 = script_getnum(st,2);
8193 if( sd->sc.opt1 == opt1 )
8194 script_pushint(st, 1);
8195 else
8196 script_pushint(st, 0);
8197
8198 return 0;
8199}
8200
8201/// Checks if the player has that health state (opt2).
8202///
8203/// checkoption2(<opt2>) -> <bool>
8204BUILDIN_FUNC(checkoption2)
8205{
8206 int opt2;
8207 TBL_PC* sd;
8208
8209 sd = script_rid2sd(st);
8210 if( sd == NULL )
8211 return 0;// no player attached, report source
8212
8213 opt2 = script_getnum(st,2);
8214 if( sd->sc.opt2&opt2 )
8215 script_pushint(st, 1);
8216 else
8217 script_pushint(st, 0);
8218
8219 return 0;
8220}
8221
8222/// Changes the effect state (option) of the player.
8223/// <flag> defaults to 1
8224/// <flag>=0 : removes the option
8225/// <flag>=other : adds the option
8226///
8227/// setoption <option>,<flag>;
8228/// setoption <option>;
8229BUILDIN_FUNC(setoption)
8230{
8231 int option;
8232 int flag = 1;
8233 TBL_PC* sd;
8234
8235 sd = script_rid2sd(st);
8236 if( sd == NULL )
8237 return 0;// no player attached, report source
8238
8239 option = script_getnum(st,2);
8240 if( script_hasdata(st,3) )
8241 flag = script_getnum(st,3);
8242 else if( !option ){// Request to remove everything.
8243 flag = 0;
8244 option = OPTION_CART|OPTION_FALCON|OPTION_RIDING;
8245 }
8246 if( flag ){// Add option
8247 if( option&OPTION_WEDDING && !battle_config.wedding_modifydisplay )
8248 option &= ~OPTION_WEDDING;// Do not show the wedding sprites
8249 pc_setoption(sd, sd->sc.option|option);
8250 } else// Remove option
8251 pc_setoption(sd, sd->sc.option&~option);
8252
8253 return 0;
8254}
8255
8256/// Returns if the player has a cart.
8257///
8258/// checkcart() -> <bool>
8259///
8260/// @author Valaris
8261BUILDIN_FUNC(checkcart)
8262{
8263 TBL_PC* sd;
8264
8265 sd = script_rid2sd(st);
8266 if( sd == NULL )
8267 return 0;// no player attached, report source
8268
8269 if( pc_iscarton(sd) )
8270 script_pushint(st, 1);
8271 else
8272 script_pushint(st, 0);
8273
8274 return 0;
8275}
8276
8277/// Sets the cart of the player.
8278/// <type> defaults to 1
8279/// <type>=0 : removes the cart
8280/// <type>=1 : Normal cart
8281/// <type>=2 : Wooden cart
8282/// <type>=3 : Covered cart with flowers and ferns
8283/// <type>=4 : Wooden cart with a Panda doll on the back
8284/// <type>=5 : Normal cart with bigger wheels, a roof and a banner on the back
8285///
8286/// setcart <type>;
8287/// setcart;
8288BUILDIN_FUNC(setcart)
8289{
8290 int type = 1;
8291 TBL_PC* sd;
8292
8293 sd = script_rid2sd(st);
8294 if( sd == NULL )
8295 return 0;// no player attached, report source
8296
8297 if( script_hasdata(st,2) )
8298 type = script_getnum(st,2);
8299 pc_setcart(sd, type);
8300
8301 return 0;
8302}
8303
8304/// Returns if the player has a falcon.
8305///
8306/// checkfalcon() -> <bool>
8307///
8308/// @author Valaris
8309BUILDIN_FUNC(checkfalcon)
8310{
8311 TBL_PC* sd;
8312
8313 sd = script_rid2sd(st);
8314 if( sd == NULL )
8315 return 0;// no player attached, report source
8316
8317 if( pc_isfalcon(sd) )
8318 script_pushint(st, 1);
8319 else
8320 script_pushint(st, 0);
8321
8322 return 0;
8323}
8324
8325/// Sets if the player has a falcon or not.
8326/// <flag> defaults to 1
8327///
8328/// setfalcon <flag>;
8329/// setfalcon;
8330BUILDIN_FUNC(setfalcon)
8331{
8332 int flag = 1;
8333 TBL_PC* sd;
8334
8335 sd = script_rid2sd(st);
8336 if( sd == NULL )
8337 return 0;// no player attached, report source
8338
8339 if( script_hasdata(st,2) )
8340 flag = script_getnum(st,2);
8341
8342 pc_setfalcon(sd, flag);
8343
8344 return 0;
8345}
8346
8347/// Returns if the player is riding.
8348///
8349/// checkriding() -> <bool>
8350///
8351/// @author Valaris
8352BUILDIN_FUNC(checkriding)
8353{
8354 TBL_PC* sd;
8355
8356 sd = script_rid2sd(st);
8357 if( sd == NULL )
8358 return 0;// no player attached, report source
8359
8360 if( pc_isriding(sd) )
8361 script_pushint(st, 1);
8362 else
8363 script_pushint(st, 0);
8364
8365 return 0;
8366}
8367
8368/// Sets if the player is riding.
8369/// <flag> defaults to 1
8370///
8371/// setriding <flag>;
8372/// setriding;
8373BUILDIN_FUNC(setriding)
8374{
8375 int flag = 1;
8376 TBL_PC* sd;
8377
8378 sd = script_rid2sd(st);
8379 if( sd == NULL )
8380 return 0;// no player attached, report source
8381
8382 if( script_hasdata(st,2) )
8383 flag = script_getnum(st,2);
8384 pc_setriding(sd, flag);
8385
8386 return 0;
8387}
8388
8389/// Sets the save point of the player.
8390///
8391/// save "<map name>",<x>,<y>
8392/// savepoint "<map name>",<x>,<y>
8393BUILDIN_FUNC(savepoint)
8394{
8395 int x;
8396 int y;
8397 short map;
8398 const char* str;
8399 TBL_PC* sd;
8400
8401 sd = script_rid2sd(st);
8402 if( sd == NULL )
8403 return 0;// no player attached, report source
8404
8405 str = script_getstr(st, 2);
8406 x = script_getnum(st,3);
8407 y = script_getnum(st,4);
8408 map = mapindex_name2id(str);
8409 if( map )
8410 pc_setsavepoint(sd, map, x, y);
8411
8412 return 0;
8413}
8414
8415/*==========================================
8416 * GetTimeTick(0: System Tick, 1: Time Second Tick)
8417 *------------------------------------------*/
8418BUILDIN_FUNC(gettimetick) /* Asgard Version */
8419{
8420 int type;
8421 time_t timer;
8422 struct tm *t;
8423
8424 type=script_getnum(st,2);
8425
8426 switch(type){
8427 case 2:
8428 //type 2:(Get the number of seconds elapsed since 00:00 hours, Jan 1, 1970 UTC
8429 // from the system clock.)
8430 script_pushint(st,(int)time(NULL));
8431 break;
8432 case 1:
8433 //type 1:(Second Ticks: 0-86399, 00:00:00-23:59:59)
8434 time(&timer);
8435 t=localtime(&timer);
8436 script_pushint(st,((t->tm_hour)*3600+(t->tm_min)*60+t->tm_sec));
8437 break;
8438 case 0:
8439 default:
8440 //type 0:(System Ticks)
8441 script_pushint(st,gettick());
8442 break;
8443 }
8444 return 0;
8445}
8446
8447/*==========================================
8448 * GetTime(Type);
8449 * 1: Sec 2: Min 3: Hour
8450 * 4: WeekDay 5: MonthDay 6: Month
8451 * 7: Year
8452 *------------------------------------------*/
8453BUILDIN_FUNC(gettime) /* Asgard Version */
8454{
8455 int type;
8456 time_t timer;
8457 struct tm *t;
8458
8459 type=script_getnum(st,2);
8460
8461 time(&timer);
8462 t=localtime(&timer);
8463
8464 switch(type){
8465 case 1://Sec(0~59)
8466 script_pushint(st,t->tm_sec);
8467 break;
8468 case 2://Min(0~59)
8469 script_pushint(st,t->tm_min);
8470 break;
8471 case 3://Hour(0~23)
8472 script_pushint(st,t->tm_hour);
8473 break;
8474 case 4://WeekDay(0~6)
8475 script_pushint(st,t->tm_wday);
8476 break;
8477 case 5://MonthDay(01~31)
8478 script_pushint(st,t->tm_mday);
8479 break;
8480 case 6://Month(01~12)
8481 script_pushint(st,t->tm_mon+1);
8482 break;
8483 case 7://Year(20xx)
8484 script_pushint(st,t->tm_year+1900);
8485 break;
8486 case 8://Year Day(01~366)
8487 script_pushint(st,t->tm_yday+1);
8488 break;
8489 default://(format error)
8490 script_pushint(st,-1);
8491 break;
8492 }
8493 return 0;
8494}
8495
8496/*==========================================
8497 * GetTimeStr("TimeFMT", Length);
8498 *------------------------------------------*/
8499BUILDIN_FUNC(gettimestr)
8500{
8501 char *tmpstr;
8502 const char *fmtstr;
8503 int maxlen;
8504 time_t now = time(NULL);
8505
8506 fmtstr=script_getstr(st,2);
8507 maxlen=script_getnum(st,3);
8508
8509 tmpstr=(char *)aMallocA((maxlen+1)*sizeof(char));
8510 strftime(tmpstr,maxlen,fmtstr,localtime(&now));
8511 tmpstr[maxlen]='\0';
8512
8513 script_pushstr(st,tmpstr);
8514 return 0;
8515}
8516
8517/*==========================================
8518 * カプラ倉庫を開ã
8519 *------------------------------------------*/
8520BUILDIN_FUNC(openstorage)
8521{
8522 TBL_PC* sd;
8523
8524 sd = script_rid2sd(st);
8525 if( sd == NULL )
8526 return 0;
8527
8528 storage_storageopen(sd);
8529 return 0;
8530}
8531
8532BUILDIN_FUNC(guildopenstorage)
8533{
8534 TBL_PC* sd;
8535 int ret;
8536
8537 sd = script_rid2sd(st);
8538 if( sd == NULL )
8539 return 0;
8540
8541 ret = storage_guild_storageopen(sd);
8542 script_pushint(st,ret);
8543 return 0;
8544}
8545
8546BUILDIN_FUNC(openrentstorage) // [ZephStorage]
8547{
8548 TBL_PC* sd;
8549
8550 sd = script_rid2sd(st);
8551 if( sd == NULL )
8552 return 0;
8553
8554 ext_storage_open(sd);
8555 return 0;
8556}
8557/*==========================================
8558 * アイテムã«ã‚ˆã‚‹ã‚¹ã‚ル発動
8559 *------------------------------------------*/
8560/// itemskill <skill id>,<level>
8561/// itemskill "<skill name>",<level>
8562BUILDIN_FUNC(itemskill)
8563{
8564 int id;
8565 int lv;
8566 TBL_PC* sd;
8567
8568 sd = script_rid2sd(st);
8569 if( sd == NULL || sd->ud.skilltimer != INVALID_TIMER )
8570 return 0;
8571
8572 id = ( script_isstring(st,2) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
8573 lv = script_getnum(st,3);
8574
8575 sd->skillitem=id;
8576 sd->skillitemlv=lv;
8577 clif_item_skill(sd,id,lv);
8578 return 0;
8579}
8580/*==========================================
8581 * アイテム作æˆ
8582 *------------------------------------------*/
8583BUILDIN_FUNC(produce)
8584{
8585 int trigger;
8586 TBL_PC* sd;
8587
8588 sd = script_rid2sd(st);
8589 if( sd == NULL )
8590 return 0;
8591
8592 trigger=script_getnum(st,2);
8593 clif_skill_produce_mix_list(sd, trigger);
8594 return 0;
8595}
8596/*==========================================
8597 *
8598 *------------------------------------------*/
8599BUILDIN_FUNC(cooking)
8600{
8601 int trigger;
8602 TBL_PC* sd;
8603
8604 sd = script_rid2sd(st);
8605 if( sd == NULL )
8606 return 0;
8607
8608 trigger=script_getnum(st,2);
8609 clif_cooking_list(sd, trigger);
8610 return 0;
8611}
8612/*==========================================
8613 * NPCã§ãƒšãƒƒãƒˆä½œã‚‹
8614 *------------------------------------------*/
8615BUILDIN_FUNC(makepet)
8616{
8617 TBL_PC* sd;
8618 int id,pet_id;
8619
8620 id=script_getnum(st,2);
8621 sd = script_rid2sd(st);
8622 if( sd == NULL )
8623 return 0;
8624
8625 pet_id = search_petDB_index(id, PET_CLASS);
8626
8627 if (pet_id < 0)
8628 pet_id = search_petDB_index(id, PET_EGG);
8629 if (pet_id >= 0 && sd) {
8630 sd->catch_target_class = pet_db[pet_id].class_;
8631 intif_create_pet(
8632 sd->status.account_id, sd->status.char_id,
8633 (short)pet_db[pet_id].class_, (short)mob_db(pet_db[pet_id].class_)->lv,
8634 (short)pet_db[pet_id].EggID, 0, (short)pet_db[pet_id].intimate,
8635 100, 0, 1, pet_db[pet_id].jname);
8636 }
8637
8638 return 0;
8639}
8640/*==========================================
8641 * NPCã§çµŒé¨“値上ã’ã‚‹
8642 *------------------------------------------*/
8643BUILDIN_FUNC(getexp)
8644{
8645 TBL_PC* sd;
8646 int base=0,job=0;
8647 double bonus;
8648
8649 sd = script_rid2sd(st);
8650 if( sd == NULL )
8651 return 0;
8652
8653 base=script_getnum(st,2);
8654 job =script_getnum(st,3);
8655 if(base<0 || job<0)
8656 return 0;
8657
8658 // bonus for npc-given exp
8659 bonus = (script_hasdata(st,4) ? script_getnum(st,4) : battle_config.quest_exp_rate) / 100.;
8660 base = (int) cap_value(base * bonus, 0, INT_MAX);
8661 job = (int) cap_value(job * bonus, 0, INT_MAX);
8662
8663 pc_gainexp(sd, NULL, base, job, true);
8664
8665 return 0;
8666}
8667
8668/*==========================================
8669 * Gain guild exp [Celest]
8670 *------------------------------------------*/
8671BUILDIN_FUNC(guildgetexp)
8672{
8673 TBL_PC* sd = script_rid2sd(st);
8674 int exp = script_getnum(st,2);
8675
8676 if( exp < 0 || sd == NULL || sd->status.guild_id == 0 )
8677 return 0;
8678
8679 guild_addexp(sd->status.guild_id, sd->status.account_id, sd->status.char_id, exp);
8680 return 0;
8681}
8682
8683/*==========================================
8684 * Changes the guild master of a guild [Skotlex]
8685 *------------------------------------------*/
8686BUILDIN_FUNC(guildchangegm)
8687{
8688 TBL_PC *sd;
8689 int guild_id;
8690 const char *name;
8691
8692 guild_id = script_getnum(st,2);
8693 name = script_getstr(st,3);
8694 sd=map_nick2sd(name);
8695
8696 if (!sd)
8697 script_pushint(st,0);
8698 else
8699 script_pushint(st,guild_gm_change(guild_id, sd));
8700
8701 return 0;
8702}
8703
8704/*==========================================
8705 * モンスター発生
8706 *------------------------------------------*/
8707BUILDIN_FUNC(monster)
8708{
8709 const char* mapn = script_getstr(st,2);
8710 int x = script_getnum(st,3);
8711 int y = script_getnum(st,4);
8712 const char* str = script_getstr(st,5);
8713 int class_ = script_getnum(st,6);
8714 int amount = script_getnum(st,7);
8715 const char* event = "";
8716
8717 struct map_session_data* sd;
8718 int m;
8719
8720 if( script_hasdata(st,8) )
8721 {
8722 event = script_getstr(st,8);
8723 check_event(st, event);
8724 }
8725
8726 if (class_ >= 0 && !mobdb_checkid(class_)) {
8727 ShowWarning("buildin_monster: Attempted to spawn non-existing monster class %d\n", class_);
8728 return 1;
8729 }
8730
8731 sd = map_id2sd(st->rid);
8732
8733 if( sd && strcmp(mapn,"this") == 0 )
8734 m = sd->bl.m;
8735 else
8736 {
8737 m = map_mapname2mapid(mapn);
8738 if( map[m].flag.src4instance && st->instance_id )
8739 { // Try to redirect to the instance map, not the src map
8740 if( (m = instance_mapid2imapid(m, st->instance_id)) < 0 )
8741 {
8742 ShowError("buildin_monster: Trying to spawn monster (%d) on instance map (%s) without instance attached.\n", class_, mapn);
8743 return 1;
8744 }
8745 }
8746 }
8747
8748 mob_once_spawn(sd,m,x,y,str,class_,amount,event);
8749 return 0;
8750}
8751/*==========================================
8752 * Creacin de Mobs Aliados - Invocacin por Item
8753 *------------------------------------------*/
8754BUILDIN_FUNC(invocar)
8755{
8756 TBL_PC *sd;
8757 struct mob_data *md;
8758 int timeout, class_, k, tick = gettick();
8759
8760 sd = script_rid2sd(st);
8761 if( sd == NULL )
8762 return 0;
8763
8764 class_ = script_getnum(st,2);
8765 timeout = script_getnum(st,3);
8766
8767 if( map_flag_vs(sd->bl.m) )
8768 return 0;
8769
8770 if( class_ >= 0 && !mobdb_checkid(class_) )
8771 {
8772 ShowWarning("buildin_monster: Attempted to spawn non-existing monster class %d\n", class_);
8773 return 1;
8774 }
8775
8776 k = mob_once_spawn_especial((struct map_session_data*)sd, "this", sd->bl.x, sd->bl.y, "--ja--", class_, 1, "", 0, 0, 1, false, 0, 1, false, false, true, 0, 0, 0, false, 0, 0);
8777
8778 if( (md = (struct mob_data *)map_id2bl(k)) )
8779 {
8780 md->deletetimer = add_timer(tick + (timeout > 0 ? timeout * 1000 : 60000), mob_timer_delete, md->bl.id, 0);
8781 clif_misceffect(&md->bl,344);
8782 }
8783
8784 return 0;
8785}
8786
8787/*==========================================
8788 * Cdigo Zephyrus para mob con IDdeParty para Map Dominacion
8789 *------------------------------------------*/
8790BUILDIN_FUNC(mobdemolition)
8791{
8792 short x,y,ratio;
8793 const char *map;
8794 int type,power,amount,m;
8795
8796 map = script_getstr(st,2);
8797 x = script_getnum(st,3);
8798 y = script_getnum(st,4);
8799 ratio = script_getnum(st,5);
8800 type = script_getnum(st,6);
8801 amount = script_getnum(st,7);
8802 power = script_getnum(st,8);
8803
8804 m = map_mapname2mapid(map);
8805
8806 if (m < 0)
8807 return 1; // mapa no encontrado
8808
8809 mob_demolition(m,x,y,ratio,type,amount,power);
8810
8811 return 0;
8812}
8813
8814/*==========================================
8815 * Cdigo Zephyrus para mob con IDdeParty para Map Dominacion
8816 *------------------------------------------*/
8817BUILDIN_FUNC(mobevent)
8818{
8819 int class_,size,amount,x,y,partyid,mostrarhp,hpmas,allied,noslaves,noexpnodrop,k,iswar,exp_boost,drop_boost;
8820 int item_drop, item_amount;
8821 const char *str,*map,*event="";
8822
8823 map = script_getstr(st,2);
8824 x = script_getnum(st,3);
8825 y = script_getnum(st,4);
8826 str = script_getstr(st,5);
8827 class_ = script_getnum(st,6);
8828 size = script_getnum(st,7);
8829 amount = script_getnum(st,8);
8830 partyid = script_getnum(st,9);
8831 mostrarhp = script_getnum(st,10);
8832 hpmas = script_getnum(st,11);
8833 allied = script_getnum(st,12);
8834 noslaves = script_getnum(st,13);
8835 noexpnodrop = script_getnum(st,14);
8836 item_drop = script_getnum(st,15);
8837 item_amount = script_getnum(st,16);
8838 iswar = script_getnum(st,17);
8839 exp_boost = script_getnum(st,18);
8840 drop_boost = script_getnum(st,19);
8841
8842 if( script_hasdata(st,20) )
8843 {
8844 event = script_getstr(st,20);
8845 check_event(st, event);
8846 }
8847
8848 if( class_ >= 0 && !mobdb_checkid(class_) )
8849 {
8850 ShowWarning("buildin_monster: Attempted to spawn non-existing monster class %d\n", class_);
8851 return 1;
8852 }
8853
8854 k = mob_once_spawn_especial(map_id2sd(st->rid),map,x,y,str,class_,amount,event,hpmas,size,allied,noslaves,0,mostrarhp,0,0,noexpnodrop,partyid,item_drop,item_amount,iswar,exp_boost,drop_boost);
8855 script_pushint(st,1); // Confirmando creacion
8856
8857 return 0;
8858}
8859/*==========================================
8860 * Get a Random mob ID
8861 *------------------------------------------*/
8862BUILDIN_FUNC(getmobrandid)
8863{
8864 int level = script_getnum(st,2);
8865 int range = script_getnum(st,3);
8866
8867 script_pushint(st, mob_get_random_id_lv(level, range));
8868 return 0;
8869}
8870/*==========================================
8871 * Request List of Monster Drops
8872 *------------------------------------------*/
8873BUILDIN_FUNC(getmobdrops)
8874{
8875 int class_ = script_getnum(st,2);
8876 int i, j = 0;
8877 struct mob_db *mob;
8878
8879 if( !mobdb_checkid(class_) )
8880 {
8881 script_pushint(st, 0);
8882 return 0;
8883 }
8884
8885 mob = mob_db(class_);
8886
8887 for( i = 0; i < MAX_MOB_DROP; i++ )
8888 {
8889 if( mob->dropitem[i].nameid < 1 )
8890 continue;
8891 if( itemdb_exists(mob->dropitem[i].nameid) == NULL )
8892 continue;
8893
8894 mapreg_setreg(reference_uid(add_str("$@MobDrop_item"), j), mob->dropitem[i].nameid);
8895 mapreg_setreg(reference_uid(add_str("$@MobDrop_rate"), j), mob->dropitem[i].p);
8896
8897 j++;
8898 }
8899
8900 mapreg_setreg(add_str("$@MobDrop_count"), j);
8901 script_pushint(st, 1);
8902
8903 return 0;
8904}
8905/*==========================================
8906 * モンスター発生
8907 *------------------------------------------*/
8908BUILDIN_FUNC(areamonster)
8909{
8910 const char* mapn = script_getstr(st,2);
8911 int x0 = script_getnum(st,3);
8912 int y0 = script_getnum(st,4);
8913 int x1 = script_getnum(st,5);
8914 int y1 = script_getnum(st,6);
8915 const char* str = script_getstr(st,7);
8916 int class_ = script_getnum(st,8);
8917 int amount = script_getnum(st,9);
8918 const char* event = "";
8919
8920 struct map_session_data* sd;
8921 int m;
8922
8923 if( script_hasdata(st,10) )
8924 {
8925 event = script_getstr(st,10);
8926 check_event(st, event);
8927 }
8928
8929 sd = map_id2sd(st->rid);
8930
8931 if( sd && strcmp(mapn,"this") == 0 )
8932 m = sd->bl.m;
8933 else
8934 {
8935 m = map_mapname2mapid(mapn);
8936 if( map[m].flag.src4instance && st->instance_id )
8937 { // Try to redirect to the instance map, not the src map
8938 if( (m = instance_mapid2imapid(m, st->instance_id)) < 0 )
8939 {
8940 ShowError("buildin_areamonster: Trying to spawn monster (%d) on instance map (%s) without instance attached.\n", class_, mapn);
8941 return 1;
8942 }
8943 }
8944 }
8945
8946 mob_once_spawn_area(sd,m,x0,y0,x1,y1,str,class_,amount,event);
8947 return 0;
8948}
8949/*==========================================
8950 * モンスター削除
8951 *------------------------------------------*/
8952 static int buildin_killmonster_sub_strip(struct block_list *bl,va_list ap)
8953{ //same fix but with killmonster instead - stripping events from mobs.
8954 TBL_MOB* md = (TBL_MOB*)bl;
8955 char *event=va_arg(ap,char *);
8956 int allflag=va_arg(ap,int);
8957
8958 md->state.npc_killmonster = 1;
8959
8960 if(!allflag){
8961 if(strcmp(event,md->npc_event)==0)
8962 status_kill(bl);
8963 }else{
8964 if(!md->spawn)
8965 status_kill(bl);
8966 }
8967 md->state.npc_killmonster = 0;
8968 return 0;
8969}
8970static int buildin_killmonster_sub(struct block_list *bl,va_list ap)
8971{
8972 TBL_MOB* md = (TBL_MOB*)bl;
8973 char *event=va_arg(ap,char *);
8974 int allflag=va_arg(ap,int);
8975
8976 if(!allflag){
8977 if(strcmp(event,md->npc_event)==0)
8978 status_kill(bl);
8979 }else{
8980 if(!md->spawn)
8981 status_kill(bl);
8982 }
8983 return 0;
8984}
8985BUILDIN_FUNC(killmonster)
8986{
8987 const char *mapname,*event;
8988 int m,allflag=0;
8989 mapname=script_getstr(st,2);
8990 event=script_getstr(st,3);
8991 if(strcmp(event,"All")==0)
8992 allflag = 1;
8993 else
8994 check_event(st, event);
8995
8996 if( (m=map_mapname2mapid(mapname))<0 )
8997 return 0;
8998
8999 if( map[m].flag.src4instance && st->instance_id && (m = instance_mapid2imapid(m, st->instance_id)) < 0 )
9000 return 0;
9001
9002 if( script_hasdata(st,4) ) {
9003 if ( script_getnum(st,4) == 1 ) {
9004 map_foreachinmap(buildin_killmonster_sub, m, BL_MOB, event ,allflag);
9005 return 0;
9006 }
9007 }
9008
9009 map_freeblock_lock();
9010 map_foreachinmap(buildin_killmonster_sub_strip, m, BL_MOB, event ,allflag);
9011 map_freeblock_unlock();
9012 return 0;
9013}
9014
9015static int buildin_killmonsterall_sub_strip(struct block_list *bl,va_list ap)
9016{ //Strips the event from the mob if it's killed the old method.
9017 struct mob_data *md;
9018
9019 md = BL_CAST(BL_MOB, bl);
9020 if (md->npc_event[0])
9021 md->npc_event[0] = 0;
9022
9023 status_kill(bl);
9024 return 0;
9025}
9026static int buildin_killmonsterall_sub(struct block_list *bl,va_list ap)
9027{
9028 status_kill(bl);
9029 return 0;
9030}
9031BUILDIN_FUNC(killmonsterall)
9032{
9033 const char *mapname;
9034 int m;
9035 mapname=script_getstr(st,2);
9036
9037 if( (m = map_mapname2mapid(mapname))<0 )
9038 return 0;
9039
9040 if( map[m].flag.src4instance && st->instance_id && (m = instance_mapid2imapid(m, st->instance_id)) < 0 )
9041 return 0;
9042
9043 if( script_hasdata(st,3) ) {
9044 if ( script_getnum(st,3) == 1 ) {
9045 map_foreachinmap(buildin_killmonsterall_sub,m,BL_MOB);
9046 return 0;
9047 }
9048 }
9049
9050 map_foreachinmap(buildin_killmonsterall_sub_strip,m,BL_MOB);
9051 return 0;
9052}
9053
9054/*==========================================
9055 * Creates a clone of a player.
9056 * clone map, x, y, event, char_id, master_id, mode, flag, duration
9057 *------------------------------------------*/
9058BUILDIN_FUNC(clone)
9059{
9060 TBL_PC *sd, *msd=NULL;
9061 int char_id,master_id=0,x,y, mode = 0, flag = 0, m;
9062 unsigned int duration = 0;
9063 const char *map,*event="";
9064
9065 map=script_getstr(st,2);
9066 x=script_getnum(st,3);
9067 y=script_getnum(st,4);
9068 event=script_getstr(st,5);
9069 char_id=script_getnum(st,6);
9070
9071 if( script_hasdata(st,7) )
9072 master_id=script_getnum(st,7);
9073
9074 if( script_hasdata(st,8) )
9075 mode=script_getnum(st,8);
9076
9077 if( script_hasdata(st,9) )
9078 flag=script_getnum(st,9);
9079
9080 if( script_hasdata(st,10) )
9081 duration=script_getnum(st,10);
9082
9083 check_event(st, event);
9084
9085 m = map_mapname2mapid(map);
9086 if (m < 0) return 0;
9087
9088 sd = map_charid2sd(char_id);
9089
9090 if (master_id) {
9091 msd = map_charid2sd(master_id);
9092 if (msd)
9093 master_id = msd->bl.id;
9094 else
9095 master_id = 0;
9096 }
9097 if (sd) //Return ID of newly crafted clone.
9098 script_pushint(st,mob_clone_spawn(sd, m, x, y, event, master_id, mode, flag, 1000*duration));
9099 else //Failed to create clone.
9100 script_pushint(st,0);
9101
9102 return 0;
9103}
9104/*==========================================
9105 * イベント実行
9106 *------------------------------------------*/
9107BUILDIN_FUNC(doevent)
9108{
9109 const char* event = script_getstr(st,2);
9110 struct map_session_data* sd;
9111
9112 if( ( sd = script_rid2sd(st) ) == NULL )
9113 {
9114 return 0;
9115 }
9116
9117 check_event(st, event);
9118 npc_event(sd, event, 0);
9119 return 0;
9120}
9121/*==========================================
9122 * NPC主体イベント実行
9123 *------------------------------------------*/
9124BUILDIN_FUNC(donpcevent)
9125{
9126 const char* event = script_getstr(st,2);
9127 check_event(st, event);
9128 npc_event_do(event);
9129 return 0;
9130}
9131
9132/// for Aegis compatibility
9133/// basically a specialized 'donpcevent', with the event specified as two arguments instead of one
9134BUILDIN_FUNC(cmdothernpc) // Added by RoVeRT
9135{
9136 const char* npc = script_getstr(st,2);
9137 const char* command = script_getstr(st,3);
9138 char event[EVENT_NAME_LENGTH];
9139 snprintf(event, sizeof(event), "%s::OnCommand%s", npc, command);
9140 check_event(st, event);
9141 npc_event_do(event);
9142 return 0;
9143}
9144
9145/*==========================================
9146 * イベントタイマー追åŠ
9147 *------------------------------------------*/
9148BUILDIN_FUNC(addtimer)
9149{
9150 int tick = script_getnum(st,2);
9151 const char* event = script_getstr(st, 3);
9152 TBL_PC* sd;
9153
9154 check_event(st, event);
9155 sd = script_rid2sd(st);
9156 if( sd == NULL )
9157 return 0;
9158
9159 pc_addeventtimer(sd,tick,event);
9160 return 0;
9161}
9162/*==========================================
9163 * イベントタイマー削除
9164 *------------------------------------------*/
9165BUILDIN_FUNC(deltimer)
9166{
9167 const char *event;
9168 TBL_PC* sd;
9169
9170 event=script_getstr(st, 2);
9171 sd = script_rid2sd(st);
9172 if( sd == NULL )
9173 return 0;
9174
9175 check_event(st, event);
9176 pc_deleventtimer(sd,event);
9177 return 0;
9178}
9179/*==========================================
9180 * イベントタイマーã®ã‚«ã‚¦ãƒ³ãƒˆå€¤è¿½åŠ
9181 *------------------------------------------*/
9182BUILDIN_FUNC(addtimercount)
9183{
9184 const char *event;
9185 int tick;
9186 TBL_PC* sd;
9187
9188 event=script_getstr(st, 2);
9189 tick=script_getnum(st,3);
9190 sd = script_rid2sd(st);
9191 if( sd == NULL )
9192 return 0;
9193
9194 check_event(st, event);
9195 pc_addeventtimercount(sd,event,tick);
9196 return 0;
9197}
9198
9199/*==========================================
9200 * NPCã‚¿ã‚¤ãƒžãƒ¼åˆæœŸåŒ–
9201 *------------------------------------------*/
9202BUILDIN_FUNC(initnpctimer)
9203{
9204 struct npc_data *nd;
9205 int flag = 0;
9206
9207 if( script_hasdata(st,3) )
9208 { //Two arguments: NPC name and attach flag.
9209 nd = npc_name2id(script_getstr(st, 2));
9210 flag = script_getnum(st,3);
9211 }
9212 else if( script_hasdata(st,2) )
9213 { //Check if argument is numeric (flag) or string (npc name)
9214 struct script_data *data;
9215 data = script_getdata(st,2);
9216 get_val(st,data);
9217 if( data_isstring(data) ) //NPC name
9218 nd = npc_name2id(conv_str(st, data));
9219 else if( data_isint(data) ) //Flag
9220 {
9221 nd = (struct npc_data *)map_id2bl(st->oid);
9222 flag = conv_num(st,data);
9223 }
9224 else
9225 {
9226 ShowError("initnpctimer: invalid argument type #1 (needs be int or string)).\n");
9227 return 1;
9228 }
9229 }
9230 else
9231 nd = (struct npc_data *)map_id2bl(st->oid);
9232
9233 if( !nd )
9234 return 0;
9235 if( flag ) //Attach
9236 {
9237 TBL_PC* sd = script_rid2sd(st);
9238 if( sd == NULL )
9239 return 0;
9240 nd->u.scr.rid = sd->bl.id;
9241 }
9242
9243 npc_settimerevent_tick(nd,0);
9244 npc_timerevent_start(nd, st->rid);
9245 return 0;
9246}
9247/*==========================================
9248 * NPCタイマー開始
9249 *------------------------------------------*/
9250BUILDIN_FUNC(startnpctimer)
9251{
9252 struct npc_data *nd;
9253 int flag = 0;
9254
9255 if( script_hasdata(st,3) )
9256 { //Two arguments: NPC name and attach flag.
9257 nd = npc_name2id(script_getstr(st, 2));
9258 flag = script_getnum(st,3);
9259 }
9260 else if( script_hasdata(st,2) )
9261 { //Check if argument is numeric (flag) or string (npc name)
9262 struct script_data *data;
9263 data = script_getdata(st,2);
9264 get_val(st,data);
9265 if( data_isstring(data) ) //NPC name
9266 nd = npc_name2id(conv_str(st, data));
9267 else if( data_isint(data) ) //Flag
9268 {
9269 nd = (struct npc_data *)map_id2bl(st->oid);
9270 flag = conv_num(st,data);
9271 }
9272 else
9273 {
9274 ShowError("initnpctimer: invalid argument type #1 (needs be int or string)).\n");
9275 return 1;
9276 }
9277 }
9278 else
9279 nd=(struct npc_data *)map_id2bl(st->oid);
9280
9281 if( !nd )
9282 return 0;
9283 if( flag ) //Attach
9284 {
9285 TBL_PC* sd = script_rid2sd(st);
9286 if( sd == NULL )
9287 return 0;
9288 nd->u.scr.rid = sd->bl.id;
9289 }
9290
9291 npc_timerevent_start(nd, st->rid);
9292 return 0;
9293}
9294/*==========================================
9295 * NPCã‚¿ã‚¤ãƒžãƒ¼åœæ¢
9296 *------------------------------------------*/
9297BUILDIN_FUNC(stopnpctimer)
9298{
9299 struct npc_data *nd;
9300 int flag = 0;
9301
9302 if( script_hasdata(st,3) )
9303 { //Two arguments: NPC name and attach flag.
9304 nd = npc_name2id(script_getstr(st, 2));
9305 flag = script_getnum(st,3);
9306 }
9307 else if( script_hasdata(st,2) )
9308 { //Check if argument is numeric (flag) or string (npc name)
9309 struct script_data *data;
9310 data = script_getdata(st,2);
9311 get_val(st,data);
9312 if( data_isstring(data) ) //NPC name
9313 nd = npc_name2id(conv_str(st, data));
9314 else if( data_isint(data) ) //Flag
9315 {
9316 nd = (struct npc_data *)map_id2bl(st->oid);
9317 flag = conv_num(st,data);
9318 }
9319 else
9320 {
9321 ShowError("initnpctimer: invalid argument type #1 (needs be int or string)).\n");
9322 return 1;
9323 }
9324 }
9325 else
9326 nd=(struct npc_data *)map_id2bl(st->oid);
9327
9328 if( !nd )
9329 return 0;
9330 if( flag ) //Detach
9331 nd->u.scr.rid = 0;
9332
9333 npc_timerevent_stop(nd);
9334 return 0;
9335}
9336/*==========================================
9337 * NPCã‚¿ã‚¤ãƒžãƒ¼æƒ…å ±æ‰€å¾—
9338 *------------------------------------------*/
9339BUILDIN_FUNC(getnpctimer)
9340{
9341 struct npc_data *nd;
9342 TBL_PC *sd;
9343 int type = script_getnum(st,2);
9344 int val = 0;
9345
9346 if( script_hasdata(st,3) )
9347 nd = npc_name2id(script_getstr(st,3));
9348 else
9349 nd = (struct npc_data *)map_id2bl(st->oid);
9350
9351 if( !nd || nd->bl.type != BL_NPC )
9352 {
9353 script_pushint(st,0);
9354 ShowError("getnpctimer: Invalid NPC.\n");
9355 return 1;
9356 }
9357
9358 switch( type )
9359 {
9360 case 0: val = npc_gettimerevent_tick(nd); break;
9361 case 1:
9362 if( nd->u.scr.rid )
9363 {
9364 sd = map_id2sd(nd->u.scr.rid);
9365 if( !sd )
9366 {
9367 ShowError("buildin_getnpctimer: Attached player not found!\n");
9368 break;
9369 }
9370 val = (sd->npc_timer_id != INVALID_TIMER);
9371 }
9372 else
9373 val = (nd->u.scr.timerid != INVALID_TIMER);
9374 break;
9375 case 2: val = nd->u.scr.timeramount; break;
9376 }
9377
9378 script_pushint(st,val);
9379 return 0;
9380}
9381/*==========================================
9382 * NPCタイマー値è¨å®š
9383 *------------------------------------------*/
9384BUILDIN_FUNC(setnpctimer)
9385{
9386 int tick;
9387 struct npc_data *nd;
9388
9389 tick = script_getnum(st,2);
9390 if( script_hasdata(st,3) )
9391 nd = npc_name2id(script_getstr(st,3));
9392 else
9393 nd = (struct npc_data *)map_id2bl(st->oid);
9394
9395 if( !nd || nd->bl.type != BL_NPC )
9396 {
9397 script_pushint(st,1);
9398 ShowError("setnpctimer: Invalid NPC.\n");
9399 return 1;
9400 }
9401
9402 npc_settimerevent_tick(nd,tick);
9403 script_pushint(st,0);
9404 return 0;
9405}
9406
9407/*==========================================
9408 * attaches the player rid to the timer [Celest]
9409 *------------------------------------------*/
9410BUILDIN_FUNC(attachnpctimer)
9411{
9412 TBL_PC *sd;
9413 struct npc_data *nd = (struct npc_data *)map_id2bl(st->oid);
9414
9415 if( !nd || nd->bl.type != BL_NPC )
9416 {
9417 script_pushint(st,1);
9418 ShowError("setnpctimer: Invalid NPC.\n");
9419 return 1;
9420 }
9421
9422 if( script_hasdata(st,2) )
9423 sd = map_nick2sd(script_getstr(st,2));
9424 else
9425 sd = script_rid2sd(st);
9426
9427 if( !sd )
9428 {
9429 script_pushint(st,1);
9430 ShowWarning("attachnpctimer: Invalid player.\n");
9431 return 1;
9432 }
9433
9434 nd->u.scr.rid = sd->bl.id;
9435 script_pushint(st,0);
9436 return 0;
9437}
9438
9439/*==========================================
9440 * detaches a player rid from the timer [Celest]
9441 *------------------------------------------*/
9442BUILDIN_FUNC(detachnpctimer)
9443{
9444 struct npc_data *nd;
9445
9446 if( script_hasdata(st,2) )
9447 nd = npc_name2id(script_getstr(st,2));
9448 else
9449 nd = (struct npc_data *)map_id2bl(st->oid);
9450
9451 if( !nd || nd->bl.type != BL_NPC )
9452 {
9453 script_pushint(st,1);
9454 ShowError("detachnpctimer: Invalid NPC.\n");
9455 return 1;
9456 }
9457
9458 nd->u.scr.rid = 0;
9459 script_pushint(st,0);
9460 return 0;
9461}
9462
9463/*==========================================
9464 * To avoid "player not attached" script errors, this function is provided,
9465 * it checks if there is a player attached to the current script. [Skotlex]
9466 * If no, returns 0, if yes, returns the account_id of the attached player.
9467 *------------------------------------------*/
9468BUILDIN_FUNC(playerattached)
9469{
9470 if(st->rid == 0 || map_id2sd(st->rid) == NULL)
9471 script_pushint(st,0);
9472 else
9473 script_pushint(st,st->rid);
9474 return 0;
9475}
9476
9477/*==========================================
9478 * 天ã®å£°ã‚¢ãƒŠã‚¦ãƒ³ã‚¹
9479 *------------------------------------------*/
9480BUILDIN_FUNC(announce)
9481{
9482 const char *mes = script_getstr(st,2);
9483 int flag = script_getnum(st,3);
9484 const char *fontColor = script_hasdata(st,4) ? script_getstr(st,4) : NULL;
9485 int fontType = script_hasdata(st,5) ? script_getnum(st,5) : 0x190; // default fontType (FW_NORMAL)
9486 int fontSize = script_hasdata(st,6) ? script_getnum(st,6) : 12; // default fontSize
9487 int fontAlign = script_hasdata(st,7) ? script_getnum(st,7) : 0; // default fontAlign
9488 int fontY = script_hasdata(st,8) ? script_getnum(st,8) : 0; // default fontY
9489
9490 if (flag&0x0f) // Broadcast source or broadcast region defined
9491 {
9492 send_target target;
9493 struct block_list *bl = (flag&0x08) ? map_id2bl(st->oid) : (struct block_list *)script_rid2sd(st); // If bc_npc flag is set, use NPC as broadcast source
9494 if (bl == NULL)
9495 return 0;
9496
9497 flag &= 0x07;
9498 target = (flag == 1) ? ALL_SAMEMAP :
9499 (flag == 2) ? AREA :
9500 (flag == 3) ? SELF :
9501 ALL_CLIENT;
9502 if (fontColor)
9503 clif_broadcast2(bl, mes, (int)strlen(mes)+1, strtol(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY, target);
9504 else
9505 clif_broadcast(bl, mes, (int)strlen(mes)+1, flag&0xf0, target);
9506 }
9507 else
9508 {
9509 if (fontColor)
9510 intif_broadcast2(mes, (int)strlen(mes)+1, strtol(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY);
9511 else
9512 intif_broadcast(mes, (int)strlen(mes)+1, flag&0xf0);
9513 }
9514 return 0;
9515}
9516
9517/*==========================================
9518 * Battleground only announcements
9519 *------------------------------------------*/
9520BUILDIN_FUNC(bgannounce)
9521{
9522 const char *mes = script_getstr(st,2);
9523 const char *fontColor = script_hasdata(st,3) ? script_getstr(st,3) : "0xFFFFFF";
9524 int fontType = script_hasdata(st,4) ? script_getnum(st,4) : 0x190; // default fontType (FW_NORMAL)
9525 int fontSize = script_hasdata(st,5) ? script_getnum(st,5) : 12; // default fontSize
9526 int fontAlign = script_hasdata(st,6) ? script_getnum(st,6) : 0; // default fontAlign
9527 int fontY = script_hasdata(st,7) ? script_getnum(st,7) : 0; // default fontY
9528
9529 clif_broadcast2(NULL, mes, (int)strlen(mes)+1, strtol(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY, BG_LISTEN);
9530 return 0;
9531}
9532
9533/*==========================================
9534 * 天ã®å£°ã‚¢ãƒŠã‚¦ãƒ³ã‚¹ï¼ˆç‰¹å®šãƒžãƒƒãƒ—)
9535 *------------------------------------------*/
9536static int buildin_announce_sub(struct block_list *bl, va_list ap)
9537{
9538 char *mes = va_arg(ap, char *);
9539 int len = va_arg(ap, int);
9540 int type = va_arg(ap, int);
9541 char *fontColor = va_arg(ap, char *);
9542 short fontType = (short)va_arg(ap, int);
9543 short fontSize = (short)va_arg(ap, int);
9544 short fontAlign = (short)va_arg(ap, int);
9545 short fontY = (short)va_arg(ap, int);
9546 if (fontColor)
9547 clif_broadcast2(bl, mes, len, strtol(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY, SELF);
9548 else
9549 clif_broadcast(bl, mes, len, type, SELF);
9550 return 0;
9551}
9552
9553BUILDIN_FUNC(mapannounce)
9554{
9555 const char *mapname = script_getstr(st,2);
9556 const char *mes = script_getstr(st,3);
9557 int flag = script_getnum(st,4);
9558 const char *fontColor = script_hasdata(st,5) ? script_getstr(st,5) : NULL;
9559 int fontType = script_hasdata(st,6) ? script_getnum(st,6) : 0x190; // default fontType (FW_NORMAL)
9560 int fontSize = script_hasdata(st,7) ? script_getnum(st,7) : 12; // default fontSize
9561 int fontAlign = script_hasdata(st,8) ? script_getnum(st,8) : 0; // default fontAlign
9562 int fontY = script_hasdata(st,9) ? script_getnum(st,9) : 0; // default fontY
9563 int m;
9564
9565 if ((m = map_mapname2mapid(mapname)) < 0)
9566 return 0;
9567
9568 map_foreachinmap(buildin_announce_sub, m, BL_PC,
9569 mes, strlen(mes)+1, flag&0xf0, fontColor, fontType, fontSize, fontAlign, fontY);
9570 return 0;
9571}
9572/*==========================================
9573 * 天ã®å£°ã‚¢ãƒŠã‚¦ãƒ³ã‚¹ï¼ˆç‰¹å®šã‚¨ãƒªã‚¢ï¼‰
9574 *------------------------------------------*/
9575BUILDIN_FUNC(areaannounce)
9576{
9577 const char *mapname = script_getstr(st,2);
9578 int x0 = script_getnum(st,3);
9579 int y0 = script_getnum(st,4);
9580 int x1 = script_getnum(st,5);
9581 int y1 = script_getnum(st,6);
9582 const char *mes = script_getstr(st,7);
9583 int flag = script_getnum(st,8);
9584 const char *fontColor = script_hasdata(st,9) ? script_getstr(st,9) : NULL;
9585 int fontType = script_hasdata(st,10) ? script_getnum(st,10) : 0x190; // default fontType (FW_NORMAL)
9586 int fontSize = script_hasdata(st,11) ? script_getnum(st,11) : 12; // default fontSize
9587 int fontAlign = script_hasdata(st,12) ? script_getnum(st,12) : 0; // default fontAlign
9588 int fontY = script_hasdata(st,13) ? script_getnum(st,13) : 0; // default fontY
9589 int m;
9590
9591 if ((m = map_mapname2mapid(mapname)) < 0)
9592 return 0;
9593
9594 map_foreachinarea(buildin_announce_sub, m, x0, y0, x1, y1, BL_PC,
9595 mes, strlen(mes)+1, flag&0xf0, fontColor, fontType, fontSize, fontAlign, fontY);
9596 return 0;
9597}
9598
9599/*==========================================
9600 * ユーザー数所得
9601 *------------------------------------------*/
9602BUILDIN_FUNC(getusers)
9603{
9604 int flag, val = 0;
9605 struct map_session_data* sd;
9606 struct block_list* bl = NULL;
9607
9608 flag = script_getnum(st,2);
9609
9610 switch(flag&0x07)
9611 {
9612 case 0:
9613 if(flag&0x8)
9614 {// npc
9615 bl = map_id2bl(st->oid);
9616 }
9617 else if((sd = script_rid2sd(st))!=NULL)
9618 {// pc
9619 bl = &sd->bl;
9620 }
9621
9622 if(bl)
9623 {
9624 val = map[bl->m].users;
9625 }
9626 break;
9627 case 1:
9628 val = map_getusers();
9629 break;
9630 default:
9631 ShowWarning("buildin_getusers: Unknown type %d.\n", flag);
9632 script_pushint(st,0);
9633 return 1;
9634 }
9635
9636 script_pushint(st,val);
9637 return 0;
9638}
9639/*==========================================
9640 * Works like @WHO - displays all online users names in window
9641 *------------------------------------------*/
9642BUILDIN_FUNC(getusersname)
9643{
9644 TBL_PC *sd, *pl_sd;
9645 int disp_num=1;
9646 struct s_mapiterator* iter;
9647
9648 sd = script_rid2sd(st);
9649 if (!sd) return 0;
9650
9651 iter = mapit_getallusers();
9652 for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
9653 {
9654 if( battle_config.hide_GM_session && pc_isGM(pl_sd) )
9655 continue; // skip hidden GMs
9656
9657 if((disp_num++)%10==0)
9658 clif_scriptnext(sd,st->oid);
9659 clif_scriptmes(sd,st->oid,pl_sd->status.name);
9660 }
9661 mapit_free(iter);
9662
9663 return 0;
9664}
9665/*==========================================
9666 * getmapguildusers("mapname",guild ID) Returns the number guild members present on a map [Reddozen]
9667 *------------------------------------------*/
9668BUILDIN_FUNC(getmapguildusers)
9669{
9670 const char *str;
9671 int m, gid;
9672 int i=0,c=0;
9673 struct guild *g = NULL;
9674 str=script_getstr(st,2);
9675 gid=script_getnum(st,3);
9676 if ((m = map_mapname2mapid(str)) < 0) { // map id on this server (m == -1 if not in actual map-server)
9677 script_pushint(st,-1);
9678 return 0;
9679 }
9680 g = guild_search(gid);
9681
9682 if (g){
9683 for(i = 0; i < g->max_member; i++)
9684 {
9685 if (g->member[i].sd && g->member[i].sd->bl.m == m)
9686 c++;
9687 }
9688 }
9689
9690 script_pushint(st,c);
9691 return 0;
9692}
9693/*==========================================
9694 * マップ指定ユーザー数所得
9695 *------------------------------------------*/
9696BUILDIN_FUNC(getmapusers)
9697{
9698 const char *str;
9699 int m;
9700 str=script_getstr(st,2);
9701 if( (m=map_mapname2mapid(str))< 0){
9702 script_pushint(st,-1);
9703 return 0;
9704 }
9705 script_pushint(st,map[m].users);
9706 return 0;
9707}
9708/*==========================================
9709 * エリア指定ユーザー数所得
9710 *------------------------------------------*/
9711static int buildin_getareausers_sub(struct block_list *bl,va_list ap)
9712{
9713 int *users=va_arg(ap,int *);
9714 (*users)++;
9715 return 0;
9716}
9717BUILDIN_FUNC(getareausers)
9718{
9719 const char *str;
9720 int m,x0,y0,x1,y1,users=0;
9721 str=script_getstr(st,2);
9722 x0=script_getnum(st,3);
9723 y0=script_getnum(st,4);
9724 x1=script_getnum(st,5);
9725 y1=script_getnum(st,6);
9726 if( (m=map_mapname2mapid(str))< 0){
9727 script_pushint(st,-1);
9728 return 0;
9729 }
9730 map_foreachinarea(buildin_getareausers_sub,
9731 m,x0,y0,x1,y1,BL_PC,&users);
9732 script_pushint(st,users);
9733 return 0;
9734}
9735
9736/*==========================================
9737 * エリア指定ドãƒãƒƒãƒ—アイテム数所得
9738 *------------------------------------------*/
9739static int buildin_getareadropitem_sub(struct block_list *bl,va_list ap)
9740{
9741 int item=va_arg(ap,int);
9742 int *amount=va_arg(ap,int *);
9743 struct flooritem_data *drop=(struct flooritem_data *)bl;
9744
9745 if(drop->item_data.nameid==item)
9746 (*amount)+=drop->item_data.amount;
9747
9748 return 0;
9749}
9750BUILDIN_FUNC(getareadropitem)
9751{
9752 const char *str;
9753 int m,x0,y0,x1,y1,item,amount=0;
9754 struct script_data *data;
9755
9756 str=script_getstr(st,2);
9757 x0=script_getnum(st,3);
9758 y0=script_getnum(st,4);
9759 x1=script_getnum(st,5);
9760 y1=script_getnum(st,6);
9761
9762 data=script_getdata(st,7);
9763 get_val(st,data);
9764 if( data_isstring(data) ){
9765 const char *name=conv_str(st,data);
9766 struct item_data *item_data = itemdb_searchname(name);
9767 item=UNKNOWN_ITEM_ID;
9768 if( item_data )
9769 item=item_data->nameid;
9770 }else
9771 item=conv_num(st,data);
9772
9773 if( (m=map_mapname2mapid(str))< 0){
9774 script_pushint(st,-1);
9775 return 0;
9776 }
9777 map_foreachinarea(buildin_getareadropitem_sub,
9778 m,x0,y0,x1,y1,BL_ITEM,item,&amount);
9779 script_pushint(st,amount);
9780 return 0;
9781}
9782/*==========================================
9783 * NPCã®æœ‰åŠ¹åŒ–
9784 *------------------------------------------*/
9785BUILDIN_FUNC(enablenpc)
9786{
9787 const char *str;
9788 str=script_getstr(st,2);
9789 npc_enable(str,1);
9790 return 0;
9791}
9792/*==========================================
9793 * NPCã®ç„¡åŠ¹åŒ–
9794 *------------------------------------------*/
9795BUILDIN_FUNC(disablenpc)
9796{
9797 const char *str;
9798 str=script_getstr(st,2);
9799 npc_enable(str,0);
9800 return 0;
9801}
9802
9803/*==========================================
9804 * éš ã‚Œã¦ã„ã‚‹NPCã®è¡¨ç¤º
9805 *------------------------------------------*/
9806BUILDIN_FUNC(hideoffnpc)
9807{
9808 const char *str;
9809 str=script_getstr(st,2);
9810 npc_enable(str,2);
9811 return 0;
9812}
9813/*==========================================
9814 * NPCã‚’ãƒã‚¤ãƒ‡ã‚£ãƒ³ã‚°
9815 *------------------------------------------*/
9816BUILDIN_FUNC(hideonnpc)
9817{
9818 const char *str;
9819 str=script_getstr(st,2);
9820 npc_enable(str,4);
9821 return 0;
9822}
9823
9824/// Starts a status effect on the target unit or on the attached player.
9825///
9826/// sc_start <effect_id>,<duration>,<val1>{,<unit_id>};
9827BUILDIN_FUNC(sc_start)
9828{
9829 struct block_list* bl;
9830 enum sc_type type;
9831 int tick;
9832 int val1;
9833 int val4 = 0;
9834
9835 type = (sc_type)script_getnum(st,2);
9836 tick = script_getnum(st,3);
9837 val1 = script_getnum(st,4);
9838 if( script_hasdata(st,5) )
9839 bl = map_id2bl(script_getnum(st,5));
9840 else
9841 bl = map_id2bl(st->rid);
9842
9843 if( tick == 0 && val1 > 0 && type > SC_NONE && type < SC_MAX && status_sc2skill(type) != 0 )
9844 {// When there isn't a duration specified, try to get it from the skill_db
9845 tick = skill_get_time(status_sc2skill(type), val1);
9846 }
9847
9848 if( potion_flag == 1 && potion_target )
9849 { //skill.c set the flags before running the script, this must be a potion-pitched effect.
9850 bl = map_id2bl(potion_target);
9851 tick /= 2;// Thrown potions only last half.
9852 val4 = 1;// Mark that this was a thrown sc_effect
9853 }
9854
9855 if( bl )
9856 status_change_start(bl, type, 10000, val1, 0, 0, val4, tick, 2);
9857
9858 return 0;
9859}
9860
9861/// Starts a status effect on the target unit or on the attached player.
9862///
9863/// sc_start2 <effect_id>,<duration>,<val1>,<percent chance>{,<unit_id>};
9864BUILDIN_FUNC(sc_start2)
9865{
9866 struct block_list* bl;
9867 enum sc_type type;
9868 int tick;
9869 int val1;
9870 int val4 = 0;
9871 int rate;
9872
9873 type = (sc_type)script_getnum(st,2);
9874 tick = script_getnum(st,3);
9875 val1 = script_getnum(st,4);
9876 rate = script_getnum(st,5);
9877 if( script_hasdata(st,6) )
9878 bl = map_id2bl(script_getnum(st,6));
9879 else
9880 bl = map_id2bl(st->rid);
9881
9882 if( tick == 0 && val1 > 0 && type > SC_NONE && type < SC_MAX && status_sc2skill(type) != 0 )
9883 {// When there isn't a duration specified, try to get it from the skill_db
9884 tick = skill_get_time(status_sc2skill(type), val1);
9885 }
9886
9887 if( potion_flag == 1 && potion_target )
9888 { //skill.c set the flags before running the script, this must be a potion-pitched effect.
9889 bl = map_id2bl(potion_target);
9890 tick /= 2;// Thrown potions only last half.
9891 val4 = 1;// Mark that this was a thrown sc_effect
9892 }
9893
9894 if( bl )
9895 status_change_start(bl, type, rate, val1, 0, 0, val4, tick, 2);
9896
9897 return 0;
9898}
9899
9900/// Starts a status effect on the target unit or on the attached player.
9901///
9902/// sc_start4 <effect_id>,<duration>,<val1>,<val2>,<val3>,<val4>{,<unit_id>};
9903BUILDIN_FUNC(sc_start4)
9904{
9905 struct block_list* bl;
9906 enum sc_type type;
9907 int tick;
9908 int val1;
9909 int val2;
9910 int val3;
9911 int val4;
9912
9913 type = (sc_type)script_getnum(st,2);
9914 tick = script_getnum(st,3);
9915 val1 = script_getnum(st,4);
9916 val2 = script_getnum(st,5);
9917 val3 = script_getnum(st,6);
9918 val4 = script_getnum(st,7);
9919 if( script_hasdata(st,8) )
9920 bl = map_id2bl(script_getnum(st,8));
9921 else
9922 bl = map_id2bl(st->rid);
9923
9924 if( tick == 0 && val1 > 0 && type > SC_NONE && type < SC_MAX && status_sc2skill(type) != 0 )
9925 {// When there isn't a duration specified, try to get it from the skill_db
9926 tick = skill_get_time(status_sc2skill(type), val1);
9927 }
9928
9929 if( potion_flag == 1 && potion_target )
9930 { //skill.c set the flags before running the script, this must be a potion-pitched effect.
9931 bl = map_id2bl(potion_target);
9932 tick /= 2;// Thrown potions only last half.
9933 }
9934
9935 if( bl )
9936 status_change_start(bl, type, 10000, val1, val2, val3, val4, tick, 2);
9937
9938 return 0;
9939}
9940
9941/// Ends one or all status effects on the target unit or on the attached player.
9942///
9943/// sc_end <effect_id>{,<unit_id>};
9944BUILDIN_FUNC(sc_end)
9945{
9946 struct block_list* bl;
9947 int type;
9948
9949 type = script_getnum(st,2);
9950 if( script_hasdata(st,3) )
9951 bl = map_id2bl(script_getnum(st,3));
9952 else
9953 bl = map_id2bl(st->rid);
9954
9955 if( potion_flag==1 && potion_target )
9956 {//##TODO how does this work [FlavioJS]
9957 bl = map_id2bl(potion_target);
9958 }
9959
9960 if( !bl ) return 0;
9961
9962 if( type >= 0 && type < SC_MAX )
9963 {
9964 struct status_change *sc = status_get_sc(bl);
9965 struct status_change_entry *sce = sc?sc->data[type]:NULL;
9966 if (!sce) return 0;
9967 //This should help status_change_end force disabling the SC in case it has no limit.
9968 sce->val1 = sce->val2 = sce->val3 = sce->val4 = 0;
9969 status_change_end(bl, (sc_type)type, INVALID_TIMER);
9970 } else
9971 status_change_clear(bl, 2);// remove all effects
9972 return 0;
9973}
9974
9975/*==========================================
9976 * çŠ¶æ…‹ç•°å¸¸è€æ€§ã‚’計算ã—ãŸç¢ºçŽ‡ã‚’è¿”ã™
9977 *------------------------------------------*/
9978BUILDIN_FUNC(getscrate)
9979{
9980 struct block_list *bl;
9981 int type,rate;
9982
9983 type=script_getnum(st,2);
9984 rate=script_getnum(st,3);
9985 if( script_hasdata(st,4) ) //指定ã—ãŸã‚ャラã®è€æ€§ã‚’計算ã™ã‚‹
9986 bl = map_id2bl(script_getnum(st,4));
9987 else
9988 bl = map_id2bl(st->rid);
9989
9990 if (bl)
9991 rate = status_get_sc_def(bl, (sc_type)type, 10000, 10000, 0);
9992
9993 script_pushint(st,rate);
9994 return 0;
9995}
9996
9997/*==========================================
9998 *
9999 *------------------------------------------*/
10000BUILDIN_FUNC(debugmes)
10001{
10002 const char *str;
10003 str=script_getstr(st,2);
10004 ShowDebug("script debug : %d %d : %s\n",st->rid,st->oid,str);
10005 return 0;
10006}
10007
10008/*==========================================
10009 *æ•ç²ã‚¢ã‚¤ãƒ†ãƒ 使用
10010 *------------------------------------------*/
10011BUILDIN_FUNC(catchpet)
10012{
10013 int pet_id;
10014 TBL_PC *sd;
10015
10016 pet_id= script_getnum(st,2);
10017 sd=script_rid2sd(st);
10018 if( sd == NULL )
10019 return 0;
10020
10021 pet_catch_process1(sd,pet_id);
10022 return 0;
10023}
10024
10025/*==========================================
10026 * [orn]
10027 *------------------------------------------*/
10028BUILDIN_FUNC(homunculus_evolution)
10029{
10030 TBL_PC *sd;
10031
10032 sd=script_rid2sd(st);
10033 if( sd == NULL )
10034 return 0;
10035
10036 if(merc_is_hom_active(sd->hd))
10037 {
10038 if (sd->hd->homunculus.intimacy > 91000)
10039 merc_hom_evolution(sd->hd);
10040 else
10041 clif_emotion(&sd->hd->bl, E_SWT);
10042 }
10043 return 0;
10044}
10045
10046// [Zephyrus]
10047BUILDIN_FUNC(homunculus_shuffle)
10048{
10049 TBL_PC *sd;
10050
10051 sd=script_rid2sd(st);
10052 if( sd == NULL )
10053 return 0;
10054
10055 if(merc_is_hom_active(sd->hd))
10056 merc_hom_shuffle(sd->hd);
10057
10058 return 0;
10059}
10060
10061//These two functions bring the eA MAPID_* class functionality to scripts.
10062BUILDIN_FUNC(eaclass)
10063{
10064 int class_;
10065 if( script_hasdata(st,2) )
10066 class_ = script_getnum(st,2);
10067 else {
10068 TBL_PC *sd;
10069 sd=script_rid2sd(st);
10070 if (!sd) {
10071 script_pushint(st,-1);
10072 return 0;
10073 }
10074 class_ = sd->status.class_;
10075 }
10076 script_pushint(st,pc_jobid2mapid(class_));
10077 return 0;
10078}
10079
10080BUILDIN_FUNC(roclass)
10081{
10082 int class_ =script_getnum(st,2);
10083 int sex;
10084 if( script_hasdata(st,3) )
10085 sex = script_getnum(st,3);
10086 else {
10087 TBL_PC *sd;
10088 if (st->rid && (sd=script_rid2sd(st)))
10089 sex = sd->status.sex;
10090 else
10091 sex = 1; //Just use male when not found.
10092 }
10093 script_pushint(st,pc_mapid2jobid(class_, sex));
10094 return 0;
10095}
10096
10097/*==========================================
10098 *æºå¸¯åµåµåŒ–機使用
10099 *------------------------------------------*/
10100BUILDIN_FUNC(birthpet)
10101{
10102 TBL_PC *sd;
10103 sd=script_rid2sd(st);
10104 if( sd == NULL )
10105 return 0;
10106
10107 if( sd->status.pet_id )
10108 {// do not send egg list, when you already have a pet
10109 return 0;
10110 }
10111
10112 clif_sendegg(sd);
10113 return 0;
10114}
10115
10116/*==========================================
10117 * Added - AppleGirl For Advanced Classes, (Updated for Cleaner Script Purposes)
10118 *------------------------------------------*/
10119BUILDIN_FUNC(resetlvl)
10120{
10121 TBL_PC *sd;
10122
10123 int type=script_getnum(st,2);
10124
10125 sd=script_rid2sd(st);
10126 if( sd == NULL )
10127 return 0;
10128
10129 pc_resetlvl(sd,type);
10130 return 0;
10131}
10132/*==========================================
10133 * ステータスリセット
10134 *------------------------------------------*/
10135BUILDIN_FUNC(resetstatus)
10136{
10137 TBL_PC *sd;
10138 sd=script_rid2sd(st);
10139 pc_resetstate(sd);
10140 return 0;
10141}
10142
10143/*==========================================
10144 * script command resetskill
10145 *------------------------------------------*/
10146BUILDIN_FUNC(resetskill)
10147{
10148 TBL_PC *sd;
10149 sd=script_rid2sd(st);
10150 pc_resetskill(sd,1);
10151 return 0;
10152}
10153
10154/*==========================================
10155 * Counts total amount of skill points.
10156 *------------------------------------------*/
10157BUILDIN_FUNC(skillpointcount)
10158{
10159 TBL_PC *sd;
10160 sd=script_rid2sd(st);
10161 script_pushint(st,sd->status.skill_point + pc_resetskill(sd,2));
10162 return 0;
10163}
10164
10165/*==========================================
10166 *
10167 *------------------------------------------*/
10168BUILDIN_FUNC(changebase)
10169{
10170 TBL_PC *sd=NULL;
10171 int vclass;
10172
10173 if( script_hasdata(st,3) )
10174 sd=map_id2sd(script_getnum(st,3));
10175 else
10176 sd=script_rid2sd(st);
10177
10178 if(sd == NULL)
10179 return 0;
10180
10181 vclass = script_getnum(st,2);
10182 if(vclass == JOB_WEDDING)
10183 {
10184 if (!battle_config.wedding_modifydisplay || //Do not show the wedding sprites
10185 sd->class_&JOBL_BABY //Baby classes screw up when showing wedding sprites. [Skotlex] They don't seem to anymore.
10186 )
10187 return 0;
10188 }
10189
10190 if(!sd->disguise && vclass != sd->vd.class_) {
10191 status_set_viewdata(&sd->bl, vclass);
10192 //Updated client view. Base, Weapon and Cloth Colors.
10193 clif_changelook(&sd->bl,LOOK_BASE,sd->vd.class_);
10194 clif_changelook(&sd->bl,LOOK_WEAPON,sd->status.weapon);
10195 if (sd->vd.cloth_color)
10196 clif_changelook(&sd->bl,LOOK_CLOTHES_COLOR,sd->vd.cloth_color);
10197 clif_skillinfoblock(sd);
10198 }
10199
10200 return 0;
10201}
10202
10203/*==========================================
10204 * 性別変æ›
10205 *------------------------------------------*/
10206BUILDIN_FUNC(changesex)
10207{
10208 TBL_PC *sd = NULL;
10209 sd = script_rid2sd(st);
10210
10211 chrif_changesex(sd);
10212 return 0;
10213}
10214
10215/*==========================================
10216 * Works like 'announce' but outputs in the common chat window
10217 *------------------------------------------*/
10218BUILDIN_FUNC(globalmes)
10219{
10220 struct block_list *bl = map_id2bl(st->oid);
10221 struct npc_data *nd = (struct npc_data *)bl;
10222 const char *name=NULL,*mes;
10223
10224 mes=script_getstr(st,2); // メッセージã®å–å¾—
10225 if(mes==NULL) return 0;
10226
10227 if(script_hasdata(st,3)){ // NPCåã®å–å¾—(123#456)
10228 name=script_getstr(st,3);
10229 } else {
10230 name=nd->name;
10231 }
10232
10233 npc_globalmessage(name,mes); // ã‚°ãƒãƒ¼ãƒãƒ«ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸é€ä¿¡
10234
10235 return 0;
10236}
10237
10238/////////////////////////////////////////////////////////////////////
10239// NPC waiting room (chat room)
10240//
10241
10242/// Creates a waiting room (chat room) for this npc.
10243///
10244/// waitingroom "<title>",<limit>{,"<event>"{,<trigger>{,<zeny>{,<minlvl>{,<maxlvl>}}}}};
10245BUILDIN_FUNC(waitingroom)
10246{
10247 struct npc_data* nd;
10248 int pub = 1;
10249 const char* title = script_getstr(st, 2);
10250 int limit = script_getnum(st, 3);
10251 const char* ev = script_hasdata(st,4) ? script_getstr(st,4) : "";
10252 int trigger = script_hasdata(st,5) ? script_getnum(st,5) : limit;
10253 int zeny = script_hasdata(st,6) ? script_getnum(st,6) : 0;
10254 int minLvl = script_hasdata(st,7) ? script_getnum(st,7) : 1;
10255 int maxLvl = script_hasdata(st,8) ? script_getnum(st,8) : MAX_LEVEL;
10256
10257 nd = (struct npc_data *)map_id2bl(st->oid);
10258 if( nd != NULL )
10259 chat_createnpcchat(nd, title, limit, pub, trigger, ev, zeny, minLvl, maxLvl);
10260
10261 return 0;
10262}
10263
10264/// Removes the waiting room of the current or target npc.
10265///
10266/// delwaitingroom "<npc_name>";
10267/// delwaitingroom;
10268BUILDIN_FUNC(delwaitingroom)
10269{
10270 struct npc_data* nd;
10271 if( script_hasdata(st,2) )
10272 nd = npc_name2id(script_getstr(st, 2));
10273 else
10274 nd = (struct npc_data *)map_id2bl(st->oid);
10275 if( nd != NULL )
10276 chat_deletenpcchat(nd);
10277 return 0;
10278}
10279
10280/// Kicks all the players from the waiting room of the current or target npc.
10281///
10282/// kickwaitingroomall "<npc_name>";
10283/// kickwaitingroomall;
10284BUILDIN_FUNC(waitingroomkickall)
10285{
10286 struct npc_data* nd;
10287 struct chat_data* cd;
10288
10289 if( script_hasdata(st,2) )
10290 nd = npc_name2id(script_getstr(st,2));
10291 else
10292 nd = (struct npc_data *)map_id2bl(st->oid);
10293
10294 if( nd != NULL && (cd=(struct chat_data *)map_id2bl(nd->chat_id)) != NULL )
10295 chat_npckickall(cd);
10296 return 0;
10297}
10298
10299/// Enables the waiting room event of the current or target npc.
10300///
10301/// enablewaitingroomevent "<npc_name>";
10302/// enablewaitingroomevent;
10303BUILDIN_FUNC(enablewaitingroomevent)
10304{
10305 struct npc_data* nd;
10306 struct chat_data* cd;
10307
10308 if( script_hasdata(st,2) )
10309 nd = npc_name2id(script_getstr(st, 2));
10310 else
10311 nd = (struct npc_data *)map_id2bl(st->oid);
10312
10313 if( nd != NULL && (cd=(struct chat_data *)map_id2bl(nd->chat_id)) != NULL )
10314 chat_enableevent(cd);
10315 return 0;
10316}
10317
10318/// Disables the waiting room event of the current or target npc.
10319///
10320/// disablewaitingroomevent "<npc_name>";
10321/// disablewaitingroomevent;
10322BUILDIN_FUNC(disablewaitingroomevent)
10323{
10324 struct npc_data *nd;
10325 struct chat_data *cd;
10326
10327 if( script_hasdata(st,2) )
10328 nd = npc_name2id(script_getstr(st, 2));
10329 else
10330 nd = (struct npc_data *)map_id2bl(st->oid);
10331
10332 if( nd != NULL && (cd=(struct chat_data *)map_id2bl(nd->chat_id)) != NULL )
10333 chat_disableevent(cd);
10334 return 0;
10335}
10336
10337/// Returns info on the waiting room of the current or target npc.
10338/// Returns -1 if the type unknown
10339/// <type>=0 : current number of users
10340/// <type>=1 : maximum number of users allowed
10341/// <type>=2 : the number of users that trigger the event
10342/// <type>=3 : if the trigger is disabled
10343/// <type>=4 : the title of the waiting room
10344/// <type>=5 : the password of the waiting room
10345/// <type>=16 : the name of the waiting room event
10346/// <type>=32 : if the waiting room is full
10347/// <type>=33 : if there are enough users to trigger the event
10348///
10349/// getwaitingroomstate(<type>,"<npc_name>") -> <info>
10350/// getwaitingroomstate(<type>) -> <info>
10351BUILDIN_FUNC(getwaitingroomstate)
10352{
10353 struct npc_data *nd;
10354 struct chat_data *cd;
10355 int type;
10356
10357 type = script_getnum(st,2);
10358 if( script_hasdata(st,3) )
10359 nd = npc_name2id(script_getstr(st, 3));
10360 else
10361 nd = (struct npc_data *)map_id2bl(st->oid);
10362
10363 if( nd == NULL || (cd=(struct chat_data *)map_id2bl(nd->chat_id)) == NULL )
10364 {
10365 script_pushint(st, -1);
10366 return 0;
10367 }
10368
10369 switch(type)
10370 {
10371 case 0: script_pushint(st, cd->users); break;
10372 case 1: script_pushint(st, cd->limit); break;
10373 case 2: script_pushint(st, cd->trigger&0x7f); break;
10374 case 3: script_pushint(st, ((cd->trigger&0x80)!=0)); break;
10375 case 4: script_pushstrcopy(st, cd->title); break;
10376 case 5: script_pushstrcopy(st, cd->pass); break;
10377 case 6: // Users and List
10378 {
10379 int i, j = 0;
10380 struct map_session_data *sd;
10381 for( i = 0; i < cd->users; i++ )
10382 {
10383 if( (sd = cd->usersd[i]) == NULL )
10384 continue; // Should be a bug
10385 mapreg_setregstr(reference_uid(add_str("$@waitingroommembers$"),j),sd->status.name);
10386 j++;
10387 }
10388 script_pushint(st, j);
10389 }
10390 break;
10391 case 16: script_pushstrcopy(st, cd->npc_event);break;
10392 case 32: script_pushint(st, (cd->users >= cd->limit)); break;
10393 case 33: script_pushint(st, (cd->users >= cd->trigger)); break;
10394 default: script_pushint(st, -1); break;
10395 }
10396 return 0;
10397}
10398
10399/// Warps the trigger or target amount of players to the target map and position.
10400/// Players are automatically removed from the waiting room.
10401/// Those waiting the longest will get warped first.
10402/// The target map can be "Random" for a random position in the current map,
10403/// and "SavePoint" for the savepoint map+position.
10404/// The map flag noteleport of the current map is only considered when teleporting to the savepoint.
10405///
10406/// The id's of the teleported players are put into the array $@warpwaitingpc[]
10407/// The total number of teleported players is put into $@warpwaitingpcnum
10408///
10409/// warpwaitingpc "<map name>",<x>,<y>,<number of players>;
10410/// warpwaitingpc "<map name>",<x>,<y>;
10411BUILDIN_FUNC(warpwaitingpc)
10412{
10413 int x;
10414 int y;
10415 int i;
10416 int n;
10417 const char* map_name;
10418 struct npc_data* nd;
10419 struct chat_data* cd;
10420 TBL_PC* sd;
10421
10422 nd = (struct npc_data *)map_id2bl(st->oid);
10423 if( nd == NULL || (cd=(struct chat_data *)map_id2bl(nd->chat_id)) == NULL )
10424 return 0;
10425
10426 map_name = script_getstr(st,2);
10427 x = script_getnum(st,3);
10428 y = script_getnum(st,4);
10429 n = cd->trigger&0x7f;
10430
10431 if( script_hasdata(st,5) )
10432 n = script_getnum(st,5);
10433
10434 for( i = 0; i < n && cd->users > 0; i++ )
10435 {
10436 sd = cd->usersd[0];
10437
10438 if( strcmp(map_name,"SavePoint") == 0 && map[sd->bl.m].flag.noteleport )
10439 {// can't teleport on this map
10440 break;
10441 }
10442
10443 if( cd->zeny )
10444 {// fee set
10445 if( (uint32)sd->status.zeny < cd->zeny )
10446 {// no zeny to cover set fee
10447 break;
10448 }
10449 pc_payzeny(sd, cd->zeny);
10450 }
10451
10452 mapreg_setreg(reference_uid(add_str("$@warpwaitingpc"), i), sd->bl.id);
10453
10454 if( strcmp(map_name,"Random") == 0 )
10455 pc_randomwarp(sd,CLR_TELEPORT);
10456 else if( strcmp(map_name,"SavePoint") == 0 )
10457 pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT);
10458 else
10459 pc_setpos(sd, mapindex_name2id(map_name), x, y, CLR_OUTSIGHT);
10460 }
10461 mapreg_setreg(add_str("$@warpwaitingpcnum"), i);
10462 return 0;
10463}
10464
10465
10466
10467/////////////////////////////////////////////////////////////////////
10468// ...
10469//
10470
10471/// Detaches a character from a script.
10472///
10473/// @param st Script state to detach the character from.
10474static void script_detach_rid(struct script_state* st)
10475{
10476 if(st->rid)
10477 {
10478 script_detach_state(st, false);
10479 st->rid = 0;
10480 }
10481}
10482
10483/*=========================================================================
10484 * Attaches a set of RIDs to the current script. [digitalhamster]
10485 * addrid(<type>{,<flag>{,<parameters>}});
10486 * <type>:
10487 * 0 : All players in the server.
10488 * 1 : All players in the map of the invoking player, or the invoking NPC if no player is attached.
10489 * 2 : Party members of a specified party ID.
10490 * [ Parameters: <party id> ]
10491 * 3 : Guild members of a specified guild ID.
10492 * [ Parameters: <guild id> ]
10493 * 4 : All players in a specified area of the map of the invoking player (or NPC).
10494 * [ Parameters: <x0>,<y0>,<x1>,<y1> ]
10495 * 5 : All players in the map.
10496 * [ Parameters: "<map name>" ]
10497 * Account ID: The specified account ID.
10498 * <flag>:
10499 * 0 : Players are always attached. (default)
10500 * 1 : Players currently running another script will not be attached.
10501 *-------------------------------------------------------------------------*/
10502static int buildin_addrid_sub(struct block_list *bl,va_list ap)
10503{
10504 int forceflag;
10505 struct map_session_data *sd = (TBL_PC *)bl;
10506 struct script_state* st;
10507
10508 st = va_arg(ap,struct script_state*);
10509 forceflag = va_arg(ap,int);
10510
10511 if(!forceflag || !sd->st)
10512 if(sd->status.account_id != st->rid)
10513 run_script(st->script,st->pos,sd->status.account_id,st->oid);
10514 return 0;
10515}
10516
10517BUILDIN_FUNC(addrid)
10518{
10519 struct s_mapiterator* iter;
10520 struct block_list *bl;
10521 TBL_PC *sd;
10522
10523 if(st->rid < 1) {
10524 st->state = END;
10525 bl = map_id2bl(st->oid);
10526 } else
10527 bl = map_id2bl(st->rid); //if run without rid it'd error,also oid if npc, else rid for map
10528 iter = mapit_getallusers();
10529
10530 switch(script_getnum(st,2)) {
10531 case 0:
10532 for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter)) {
10533 if(!script_getnum(st,3) || !sd->st)
10534 if(sd->status.account_id != st->rid) //attached player already runs.
10535 run_script(st->script,st->pos,sd->status.account_id,st->oid);
10536 }
10537 break;
10538 case 1:
10539 for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter)) {
10540 if(!script_getnum(st,3) || !sd->st)
10541 if((sd->bl.m == bl->m) && (sd->status.account_id != st->rid))
10542 run_script(st->script,st->pos,sd->status.account_id,st->oid);
10543 }
10544 break;
10545 case 2:
10546 if(script_getnum(st,4) == 0) {
10547 script_pushint(st,0);
10548 return 0;
10549 }
10550 for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter)) {
10551 if(!script_getnum(st,3) || !sd->st)
10552 if((sd->status.account_id != st->rid) && (sd->status.party_id == script_getnum(st,4))) //attached player already runs.
10553 run_script(st->script,st->pos,sd->status.account_id,st->oid);
10554 }
10555 break;
10556 case 3:
10557 if(script_getnum(st,4) == 0) {
10558 script_pushint(st,0);
10559 return 0;
10560 }
10561 for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter)) {
10562 if(!script_getnum(st,3) || !sd->st)
10563 if((sd->status.account_id != st->rid) && (sd->status.guild_id == script_getnum(st,4))) //attached player already runs.
10564 run_script(st->script,st->pos,sd->status.account_id,st->oid);
10565 }
10566 break;
10567 case 4:
10568 map_foreachinallarea(buildin_addrid_sub,
10569 bl->m,script_getnum(st,4),script_getnum(st,5),script_getnum(st,6),script_getnum(st,7),BL_PC,
10570 st,script_getnum(st,3));//4-x0 , 5-y0 , 6-x1, 7-y1
10571 break;
10572 case 5:
10573 if (script_getstr(st, 4) == NULL) {
10574 script_pushint(st, 0);
10575 return 1;
10576 }
10577 if (map_mapname2mapid(script_getstr(st, 4)) < 0) {
10578 script_pushint(st, 0);
10579 return 1;
10580 }
10581 map_foreachinmap(buildin_addrid_sub, map_mapname2mapid(script_getstr(st, 4)), BL_PC, st, script_getnum(st, 3));
10582 break;
10583 default:
10584 if((map_id2sd(script_getnum(st,2))) == NULL) { // Player not found.
10585 script_pushint(st,0);
10586 return 0;
10587 }
10588 if(!script_getnum(st,3) || !map_id2sd(script_getnum(st,2))->st) {
10589 run_script(st->script,st->pos,script_getnum(st,2),st->oid);
10590 script_pushint(st,1);
10591 }
10592 return 0;
10593 }
10594 mapit_free(iter);
10595 script_pushint(st,1);
10596 return 0;
10597}
10598
10599
10600/*==========================================
10601 * RIDã®ã‚¢ã‚¿ãƒƒãƒ
10602 *------------------------------------------*/
10603BUILDIN_FUNC(attachrid)
10604{
10605 int rid = script_getnum(st,2);
10606 struct map_session_data* sd;
10607
10608 if ((sd = map_id2sd(rid))!=NULL) {
10609 script_detach_rid(st);
10610
10611 st->rid = rid;
10612 script_attach_state(st);
10613 script_pushint(st,1);
10614 } else
10615 script_pushint(st,0);
10616 return 0;
10617}
10618/*==========================================
10619 * RIDã®ãƒ‡ã‚¿ãƒƒãƒ
10620 *------------------------------------------*/
10621BUILDIN_FUNC(detachrid)
10622{
10623 script_detach_rid(st);
10624 return 0;
10625}
10626/*==========================================
10627 * å˜åœ¨ãƒã‚§ãƒƒã‚¯
10628 *------------------------------------------*/
10629BUILDIN_FUNC(isloggedin)
10630{
10631 TBL_PC* sd = map_id2sd(script_getnum(st,2));
10632 if (script_hasdata(st,3) && sd &&
10633 sd->status.char_id != script_getnum(st,3))
10634 sd = NULL;
10635 push_val(st->stack,C_INT,sd!=NULL);
10636 return 0;
10637}
10638
10639
10640/*==========================================
10641 *
10642 *------------------------------------------*/
10643BUILDIN_FUNC(setmapflagnosave)
10644{
10645 int m,x,y;
10646 unsigned short mapindex;
10647 const char *str,*str2;
10648
10649 str=script_getstr(st,2);
10650 str2=script_getstr(st,3);
10651 x=script_getnum(st,4);
10652 y=script_getnum(st,5);
10653 m = map_mapname2mapid(str);
10654 mapindex = mapindex_name2id(str2);
10655
10656 if(m >= 0 && mapindex) {
10657 map[m].flag.nosave=1;
10658 map[m].save.map=mapindex;
10659 map[m].save.x=x;
10660 map[m].save.y=y;
10661 }
10662
10663 return 0;
10664}
10665
10666BUILDIN_FUNC(getmapflag)
10667{
10668 int m,i;
10669 const char *str;
10670
10671 str=script_getstr(st,2);
10672 i=script_getnum(st,3);
10673
10674 m = map_mapname2mapid(str);
10675 if(m >= 0) {
10676 switch(i) {
10677 case MF_NOMEMO: script_pushint(st,map[m].flag.nomemo); break;
10678 case MF_NOTELEPORT: script_pushint(st,map[m].flag.noteleport); break;
10679 case MF_NOBRANCH: script_pushint(st,map[m].flag.nobranch); break;
10680 case MF_NOPENALTY: script_pushint(st,map[m].flag.noexppenalty); break;
10681 case MF_NOZENYPENALTY: script_pushint(st,map[m].flag.nozenypenalty); break;
10682 case MF_PVP: script_pushint(st,map[m].flag.pvp); break;
10683 case MF_PVP_NOPARTY: script_pushint(st,map[m].flag.pvp_noparty); break;
10684 case MF_PVP_NOGUILD: script_pushint(st,map[m].flag.pvp_noguild); break;
10685 case MF_GVG: script_pushint(st,map[m].flag.gvg); break;
10686 case MF_GVG_NOPARTY: script_pushint(st,map[m].flag.gvg_noparty); break;
10687 case MF_GVG_DUNGEON: script_pushint(st,map[m].flag.gvg_dungeon); break;
10688 case MF_GVG_CASTLE: script_pushint(st,map[m].flag.gvg_castle); break;
10689 case MF_NOTRADE: script_pushint(st,map[m].flag.notrade); break;
10690 case MF_NODROP: script_pushint(st,map[m].flag.nodrop); break;
10691 case MF_NOSKILL: script_pushint(st,map[m].flag.noskill); break;
10692 case MF_NOWARP: script_pushint(st,map[m].flag.nowarp); break;
10693 case MF_NOICEWALL: script_pushint(st,map[m].flag.noicewall); break;
10694 case MF_SNOW: script_pushint(st,map[m].flag.snow); break;
10695 case MF_CLOUDS: script_pushint(st,map[m].flag.clouds); break;
10696 case MF_CLOUDS2: script_pushint(st,map[m].flag.clouds2); break;
10697 case MF_FOG: script_pushint(st,map[m].flag.fog); break;
10698 case MF_FIREWORKS: script_pushint(st,map[m].flag.fireworks); break;
10699 case MF_SAKURA: script_pushint(st,map[m].flag.sakura); break;
10700 case MF_LEAVES: script_pushint(st,map[m].flag.leaves); break;
10701 case MF_RAIN: script_pushint(st,map[m].flag.rain); break;
10702 case MF_NIGHTENABLED: script_pushint(st,map[m].flag.nightenabled); break;
10703 case MF_NOGO: script_pushint(st,map[m].flag.nogo); break;
10704 case MF_NOBASEEXP: script_pushint(st,map[m].flag.nobaseexp); break;
10705 case MF_NOJOBEXP: script_pushint(st,map[m].flag.nojobexp); break;
10706 case MF_NOMOBLOOT: script_pushint(st,map[m].flag.nomobloot); break;
10707 case MF_NOMVPLOOT: script_pushint(st,map[m].flag.nomvploot); break;
10708 case MF_NORETURN: script_pushint(st,map[m].flag.noreturn); break;
10709 case MF_NOWARPTO: script_pushint(st,map[m].flag.nowarpto); break;
10710 case MF_NIGHTMAREDROP: script_pushint(st,map[m].flag.pvp_nightmaredrop); break;
10711 case MF_RESTRICTED: script_pushint(st,map[m].flag.restricted); break;
10712 case MF_NOCOMMAND: script_pushint(st,map[m].nocommand); break;
10713 case MF_JEXP: script_pushint(st,map[m].jexp); break;
10714 case MF_BEXP: script_pushint(st,map[m].bexp); break;
10715 case MF_NOVENDING: script_pushint(st,map[m].flag.novending); break;
10716 case MF_LOADEVENT: script_pushint(st,map[m].flag.loadevent); break;
10717 case MF_NOCHAT: script_pushint(st,map[m].flag.nochat); break;
10718 case MF_PARTYLOCK: script_pushint(st,map[m].flag.partylock); break;
10719 case MF_GUILDLOCK: script_pushint(st,map[m].flag.guildlock); break;
10720 case MF_TOWN: script_pushint(st,map[m].flag.town); break;
10721 case MF_AUTOTRADE: script_pushint(st,map[m].flag.autotrade); break;
10722 case MF_ALLOWKS: script_pushint(st,map[m].flag.allowks); break;
10723 case MF_MONSTER_NOTELEPORT: script_pushint(st,map[m].flag.monster_noteleport); break;
10724 case MF_PVP_NOCALCRANK: script_pushint(st,map[m].flag.pvp_nocalcrank); break;
10725 case MF_BATTLEGROUND: script_pushint(st,map[m].flag.battleground); break;
10726 case MF_RESET: script_pushint(st,map[m].flag.reset); break;
10727 case MF_NOPVPMODE: script_pushint(st,map[m].flag.nopvpmode); break;
10728 case MF_WOE_SET: script_pushint(st,map[m].flag.woe_set); break;
10729 case MF_BLOCKED: script_pushint(st,map[m].flag.blocked); break;
10730 case MF_NOSTORAGE: script_pushint(st,map[m].flag.nostorage); break;
10731 case MF_NOGUILDSTORAGE: script_pushint(st,map[m].flag.noguildstorage); break;
10732 }
10733 }
10734
10735 return 0;
10736}
10737
10738BUILDIN_FUNC(setmapflag)
10739{
10740 int m,i;
10741 const char *str;
10742 const char *val=NULL;
10743
10744 str=script_getstr(st,2);
10745 i=script_getnum(st,3);
10746 if(script_hasdata(st,4)){
10747 val=script_getstr(st,4);
10748 }
10749 m = map_mapname2mapid(str);
10750 if(m >= 0) {
10751 switch(i) {
10752 case MF_NOMEMO: map[m].flag.nomemo=1; break;
10753 case MF_NOTELEPORT: map[m].flag.noteleport=1; break;
10754 case MF_NOBRANCH: map[m].flag.nobranch=1; break;
10755 case MF_NOPENALTY: map[m].flag.noexppenalty=1; map[m].flag.nozenypenalty=1; break;
10756 case MF_NOZENYPENALTY: map[m].flag.nozenypenalty=1; break;
10757 case MF_PVP: map[m].flag.pvp=1; break;
10758 case MF_PVP_NOPARTY: map[m].flag.pvp_noparty=1; break;
10759 case MF_PVP_NOGUILD: map[m].flag.pvp_noguild=1; break;
10760 case MF_GVG: map[m].flag.gvg=1; break;
10761 case MF_GVG_NOPARTY: map[m].flag.gvg_noparty=1; break;
10762 case MF_GVG_DUNGEON: map[m].flag.gvg_dungeon=1; break;
10763 case MF_GVG_CASTLE: map[m].flag.gvg_castle=1; break;
10764 case MF_NOTRADE: map[m].flag.notrade=1; break;
10765 case MF_NODROP: map[m].flag.nodrop=1; break;
10766 case MF_NOSKILL: map[m].flag.noskill=1; break;
10767 case MF_NOWARP: map[m].flag.nowarp=1; break;
10768 case MF_NOICEWALL: map[m].flag.noicewall=1; break;
10769 case MF_SNOW: map[m].flag.snow=1; break;
10770 case MF_CLOUDS: map[m].flag.clouds=1; break;
10771 case MF_CLOUDS2: map[m].flag.clouds2=1; break;
10772 case MF_FOG: map[m].flag.fog=1; break;
10773 case MF_FIREWORKS: map[m].flag.fireworks=1; break;
10774 case MF_SAKURA: map[m].flag.sakura=1; break;
10775 case MF_LEAVES: map[m].flag.leaves=1; break;
10776 case MF_RAIN: map[m].flag.rain=1; break;
10777 case MF_NIGHTENABLED: map[m].flag.nightenabled=1; break;
10778 case MF_NOGO: map[m].flag.nogo=1; break;
10779 case MF_NOBASEEXP: map[m].flag.nobaseexp=1; break;
10780 case MF_NOJOBEXP: map[m].flag.nojobexp=1; break;
10781 case MF_NOMOBLOOT: map[m].flag.nomobloot=1; break;
10782 case MF_NOMVPLOOT: map[m].flag.nomvploot=1; break;
10783 case MF_NORETURN: map[m].flag.noreturn=1; break;
10784 case MF_NOWARPTO: map[m].flag.nowarpto=1; break;
10785 case MF_NIGHTMAREDROP: map[m].flag.pvp_nightmaredrop=1; break;
10786 case MF_RESTRICTED: map[m].flag.restricted=1; break;
10787 case MF_NOCOMMAND: map[m].nocommand = (!val || atoi(val) <= 0) ? 100 : atoi(val); break;
10788 case MF_JEXP: map[m].jexp = (!val || atoi(val) < 0) ? 100 : atoi(val); break;
10789 case MF_BEXP: map[m].bexp = (!val || atoi(val) < 0) ? 100 : atoi(val); break;
10790 case MF_NOVENDING: map[m].flag.novending=1; break;
10791 case MF_LOADEVENT: map[m].flag.loadevent=1; break;
10792 case MF_NOCHAT: map[m].flag.nochat=1; break;
10793 case MF_PARTYLOCK: map[m].flag.partylock=1; break;
10794 case MF_GUILDLOCK: map[m].flag.guildlock=1; break;
10795 case MF_TOWN: map[m].flag.town=1; break;
10796 case MF_AUTOTRADE: map[m].flag.autotrade=1; break;
10797 case MF_ALLOWKS: map[m].flag.allowks=1; break;
10798 case MF_MONSTER_NOTELEPORT: map[m].flag.monster_noteleport=1; break;
10799 case MF_PVP_NOCALCRANK: map[m].flag.pvp_nocalcrank=1; break;
10800 case MF_BATTLEGROUND: map[m].flag.battleground = (!val || atoi(val) < 0 || atoi(val) > 2) ? 1 : atoi(val); break;
10801 case MF_RESET: map[m].flag.reset=1; break;
10802 case MF_NOPVPMODE: map[m].flag.nopvpmode=1; break;
10803 case MF_WOE_SET: if( val && atoi(val) > 0 ) map[m].flag.woe_set = atoi(val); break;
10804 case MF_BLOCKED: map[m].flag.blocked=1; break;
10805 case MF_NOSTORAGE: map[m].flag.nostorage=1; break;
10806 case MF_NOGUILDSTORAGE: map[m].flag.noguildstorage=1; break;
10807 }
10808 }
10809
10810 return 0;
10811}
10812
10813BUILDIN_FUNC(removemapflag)
10814{
10815 int m,i;
10816 const char *str;
10817
10818 str=script_getstr(st,2);
10819 i=script_getnum(st,3);
10820 m = map_mapname2mapid(str);
10821 if(m >= 0) {
10822 switch(i) {
10823 case MF_NOMEMO: map[m].flag.nomemo=0; break;
10824 case MF_NOTELEPORT: map[m].flag.noteleport=0; break;
10825 case MF_NOSAVE: map[m].flag.nosave=0; break;
10826 case MF_NOBRANCH: map[m].flag.nobranch=0; break;
10827 case MF_NOPENALTY: map[m].flag.noexppenalty=0; map[m].flag.nozenypenalty=0; break;
10828 case MF_PVP: map[m].flag.pvp=0; break;
10829 case MF_PVP_NOPARTY: map[m].flag.pvp_noparty=0; break;
10830 case MF_PVP_NOGUILD: map[m].flag.pvp_noguild=0; break;
10831 case MF_GVG: map[m].flag.gvg=0; break;
10832 case MF_GVG_NOPARTY: map[m].flag.gvg_noparty=0; break;
10833 case MF_GVG_DUNGEON: map[m].flag.gvg_dungeon=0; break;
10834 case MF_GVG_CASTLE: map[m].flag.gvg_castle=0; break;
10835 case MF_NOZENYPENALTY: map[m].flag.nozenypenalty=0; break;
10836 case MF_NOTRADE: map[m].flag.notrade=0; break;
10837 case MF_NODROP: map[m].flag.nodrop=0; break;
10838 case MF_NOSKILL: map[m].flag.noskill=0; break;
10839 case MF_NOWARP: map[m].flag.nowarp=0; break;
10840 case MF_NOICEWALL: map[m].flag.noicewall=0; break;
10841 case MF_SNOW: map[m].flag.snow=0; break;
10842 case MF_CLOUDS: map[m].flag.clouds=0; break;
10843 case MF_CLOUDS2: map[m].flag.clouds2=0; break;
10844 case MF_FOG: map[m].flag.fog=0; break;
10845 case MF_FIREWORKS: map[m].flag.fireworks=0; break;
10846 case MF_SAKURA: map[m].flag.sakura=0; break;
10847 case MF_LEAVES: map[m].flag.leaves=0; break;
10848 case MF_RAIN: map[m].flag.rain=0; break;
10849 case MF_NIGHTENABLED: map[m].flag.nightenabled=0; break;
10850 case MF_NOGO: map[m].flag.nogo=0; break;
10851 case MF_NOBASEEXP: map[m].flag.nobaseexp=0; break;
10852 case MF_NOJOBEXP: map[m].flag.nojobexp=0; break;
10853 case MF_NOMOBLOOT: map[m].flag.nomobloot=0; break;
10854 case MF_NOMVPLOOT: map[m].flag.nomvploot=0; break;
10855 case MF_NORETURN: map[m].flag.noreturn=0; break;
10856 case MF_NOWARPTO: map[m].flag.nowarpto=0; break;
10857 case MF_NIGHTMAREDROP: map[m].flag.pvp_nightmaredrop=0; break;
10858 case MF_RESTRICTED: map[m].flag.restricted=0; break;
10859 case MF_NOCOMMAND: map[m].nocommand=0; break;
10860 case MF_JEXP: map[m].jexp=100; break;
10861 case MF_BEXP: map[m].bexp=100; break;
10862 case MF_NOVENDING: map[m].flag.novending=0; break;
10863 case MF_LOADEVENT: map[m].flag.loadevent=0; break;
10864 case MF_NOCHAT: map[m].flag.nochat=0; break;
10865 case MF_PARTYLOCK: map[m].flag.partylock=0; break;
10866 case MF_GUILDLOCK: map[m].flag.guildlock=0; break;
10867 case MF_TOWN: map[m].flag.town=0; break;
10868 case MF_AUTOTRADE: map[m].flag.autotrade=0; break;
10869 case MF_ALLOWKS: map[m].flag.allowks=0; break;
10870 case MF_MONSTER_NOTELEPORT: map[m].flag.monster_noteleport=0; break;
10871 case MF_PVP_NOCALCRANK: map[m].flag.pvp_nocalcrank=0; break;
10872 case MF_BATTLEGROUND: map[m].flag.battleground=0; break;
10873 case MF_RESET: map[m].flag.reset=0; break;
10874 case MF_NOPVPMODE: map[m].flag.nopvpmode=0; break;
10875 case MF_WOE_SET: map[m].flag.woe_set=0; break;
10876 case MF_BLOCKED: map[m].flag.blocked=0; break;
10877 case MF_NOSTORAGE: map[m].flag.nostorage=0; break;
10878 case MF_NOGUILDSTORAGE: map[m].flag.noguildstorage=0; break;
10879 }
10880 }
10881
10882 return 0;
10883}
10884
10885BUILDIN_FUNC(pvpon)
10886{
10887 int m;
10888 const char *str;
10889 TBL_PC* sd = NULL;
10890 struct s_mapiterator* iter;
10891
10892 str = script_getstr(st,2);
10893 m = map_mapname2mapid(str);
10894 if( m < 0 || map[m].flag.pvp )
10895 return 0; // nothing to do
10896
10897 map[m].flag.pvp = 1;
10898 clif_map_property_mapall(m, MAPPROPERTY_FREEPVPZONE);
10899
10900 if(battle_config.pk_mode) // disable ranking functions if pk_mode is on [Valaris]
10901 return 0;
10902
10903 iter = mapit_getallusers();
10904 for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter) )
10905 {
10906 if( sd->bl.m != m || sd->pvp_timer != INVALID_TIMER )
10907 continue; // not applicable
10908
10909 if( sd->state.pvpmode )
10910 pc_pvpmodeoff(sd, 1, 1);
10911
10912 sd->pvp_timer = add_timer(gettick()+200,pc_calc_pvprank_timer,sd->bl.id,0);
10913 sd->pvp_rank = 0;
10914 sd->pvp_lastusers = 0;
10915 sd->pvp_point = 5;
10916 sd->pvp_won = 0;
10917 sd->pvp_lost = 0;
10918 }
10919 mapit_free(iter);
10920
10921 return 0;
10922}
10923
10924static int buildin_pvpoff_sub(struct block_list *bl,va_list ap)
10925{
10926 TBL_PC* sd = (TBL_PC*)bl;
10927 clif_pvpset(sd, 0, 0, 2);
10928 if (sd->pvp_timer != INVALID_TIMER) {
10929 delete_timer(sd->pvp_timer, pc_calc_pvprank_timer);
10930 sd->pvp_timer = INVALID_TIMER;
10931 }
10932 return 0;
10933}
10934
10935BUILDIN_FUNC(pvpoff)
10936{
10937 int m;
10938 const char *str;
10939
10940 str=script_getstr(st,2);
10941 m = map_mapname2mapid(str);
10942 if(m < 0 || !map[m].flag.pvp)
10943 return 0; //fixed Lupus
10944
10945 map[m].flag.pvp = 0;
10946 clif_map_property_mapall(m, MAPPROPERTY_NOTHING);
10947
10948 if(battle_config.pk_mode) // disable ranking options if pk_mode is on [Valaris]
10949 return 0;
10950
10951 map_foreachinmap(buildin_pvpoff_sub, m, BL_PC);
10952 return 0;
10953}
10954
10955BUILDIN_FUNC(gvgon)
10956{
10957 int m;
10958 const char *str;
10959
10960 str=script_getstr(st,2);
10961 m = map_mapname2mapid(str);
10962 if(m >= 0 && !map[m].flag.gvg) {
10963 map[m].flag.gvg = 1;
10964 clif_map_property_mapall(m, MAPPROPERTY_AGITZONE);
10965 }
10966
10967 return 0;
10968}
10969BUILDIN_FUNC(gvgoff)
10970{
10971 int m;
10972 const char *str;
10973
10974 str=script_getstr(st,2);
10975 m = map_mapname2mapid(str);
10976 if(m >= 0 && map[m].flag.gvg) {
10977 map[m].flag.gvg = 0;
10978 clif_map_property_mapall(m, MAPPROPERTY_NOTHING);
10979 }
10980
10981 return 0;
10982}
10983/*==========================================
10984 * Shows an emoticon on top of the player/npc
10985 * emotion emotion#, <target: 0 - NPC, 1 - PC>, <NPC/PC name>
10986 *------------------------------------------*/
10987//Optional second parameter added by [Skotlex]
10988BUILDIN_FUNC(emotion)
10989{
10990 int type;
10991 int player=0;
10992
10993 type=script_getnum(st,2);
10994 if(type < 0 || type > 100)
10995 return 0;
10996
10997 if( script_hasdata(st,3) )
10998 player=script_getnum(st,3);
10999
11000 if (player) {
11001 TBL_PC *sd = NULL;
11002 if( script_hasdata(st,4) )
11003 sd = map_nick2sd(script_getstr(st,4));
11004 else
11005 sd = script_rid2sd(st);
11006 if (sd)
11007 clif_emotion(&sd->bl,type);
11008 } else
11009 if( script_hasdata(st,4) )
11010 {
11011 TBL_NPC *nd = npc_name2id(script_getstr(st,4));
11012 if(nd)
11013 clif_emotion(&nd->bl,type);
11014 }
11015 else
11016 clif_emotion(map_id2bl(st->oid),type);
11017 return 0;
11018}
11019
11020static int buildin_maprespawnguildid_sub_pc(struct map_session_data* sd, va_list ap)
11021{
11022 int m=va_arg(ap,int);
11023 int g_id=va_arg(ap,int);
11024 int flag=va_arg(ap,int);
11025
11026 if(!sd || sd->bl.m != m)
11027 return 0;
11028
11029 while( 1 )
11030 {
11031 if( sd->status.guild_id == 0 )
11032 break; // Warp out players not in guild
11033 if( sd->status.guild_id == g_id && flag&1 )
11034 break; // Warp out owners
11035 if( map[m].flag.ancient && !pc_class2ancientwoe(sd->status.class_) )
11036 break; // Not ancient woe users
11037 if( map_blocked_woe(m) )
11038 break; // Blocked map on this WoE
11039 if( g_id && (flag&4) && guild_isallied(g_id, sd->status.guild_id) )
11040 return 0; // Do not kick allies
11041 if( sd->status.guild_id != g_id && flag&2 )
11042 break; // Warp out outsiders except for allied on Super WoE
11043 return 0;
11044 }
11045
11046 pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
11047 return 1;
11048}
11049
11050static int buildin_maprespawnguildid_sub_mob(struct block_list *bl,va_list ap)
11051{
11052 struct mob_data *md=(struct mob_data *)bl;
11053
11054 if(!md->guardian_data && md->class_ != MOBID_EMPERIUM)
11055 status_kill(bl);
11056
11057 return 0;
11058}
11059
11060BUILDIN_FUNC(maprespawnguildid)
11061{
11062 const char *mapname=script_getstr(st,2);
11063 int g_id=script_getnum(st,3);
11064 int flag=script_getnum(st,4);
11065
11066 int m=map_mapname2mapid(mapname);
11067
11068 if(m == -1)
11069 return 0;
11070
11071 //Catch ALL players (in case some are 'between maps' on execution time)
11072 map_foreachpc(buildin_maprespawnguildid_sub_pc,m,g_id,flag);
11073 if (flag&4) //Remove script mobs.
11074 map_foreachinmap(buildin_maprespawnguildid_sub_mob,m,BL_MOB);
11075 return 0;
11076}
11077
11078BUILDIN_FUNC(agitstart)
11079{
11080 if(agit_flag==1) return 0; // Agit already Start.
11081 agit_flag=1;
11082 if( script_hasdata(st,2) )
11083 {
11084 int i = script_getnum(st,2);
11085 if( i > 0 ) woe_set = i;
11086 }
11087
11088 guild_agit_start();
11089 return 0;
11090}
11091
11092BUILDIN_FUNC(agitend)
11093{
11094 if(agit_flag==0) return 0; // Agit already End.
11095 guild_agit_end();
11096 agit_flag = 0;
11097 woe_set = 0;
11098 return 0;
11099}
11100
11101BUILDIN_FUNC(agitstart2)
11102{
11103 if(agit2_flag==1) return 0; // Agit2 already Start.
11104 agit2_flag=1;
11105 if( script_hasdata(st,2) )
11106 {
11107 int i = script_getnum(st,2);
11108 if( i > 0 ) woe_set = i;
11109 }
11110
11111 guild_agit2_start();
11112 return 0;
11113}
11114
11115BUILDIN_FUNC(agitend2)
11116{
11117 if(agit2_flag==0) return 0; // Agit2 already End.
11118 guild_agit2_end();
11119 agit2_flag=0;
11120 woe_set = 0;
11121 return 0;
11122}
11123
11124/*==========================================
11125 * Returns whether woe is on or off. // choice script
11126 *------------------------------------------*/
11127BUILDIN_FUNC(agitcheck)
11128{
11129 script_pushint(st,agit_flag);
11130 return 0;
11131}
11132
11133/*==========================================
11134 * Returns whether woese is on or off. // choice script
11135 *------------------------------------------*/
11136BUILDIN_FUNC(agitcheck2)
11137{
11138 script_pushint(st,agit2_flag);
11139 return 0;
11140}
11141
11142/// Sets the guild_id of this npc.
11143///
11144/// flagemblem <guild_id>;
11145BUILDIN_FUNC(flagemblem)
11146{
11147 TBL_NPC* nd;
11148 int g_id=script_getnum(st,2);
11149
11150 if( script_hasdata(st,3) )
11151 nd = npc_name2id(script_getstr(st,3));
11152 else
11153 nd = map_id2nd(st->oid);
11154
11155 if(g_id < 0) return 0;
11156
11157 if( nd == NULL )
11158 {
11159 ShowError("script:flagemblem: npc %d not found\n", st->oid);
11160 }
11161 else if( nd->subtype != SCRIPT )
11162 {
11163 ShowError("script:flagemblem: unexpected subtype %d for npc %d '%s'\n", nd->subtype, st->oid, nd->exname);
11164 }
11165 else
11166 {
11167 if( !map[nd->bl.m].flag.battleground )
11168 nd->u.scr.guild_id = g_id;
11169 else
11170 nd->u.scr.bg_id = g_id;
11171
11172 clif_guild_emblem_area(&nd->bl);
11173 }
11174 return 0;
11175}
11176
11177BUILDIN_FUNC(getcastlename)
11178{
11179 const char* mapname = mapindex_getmapname(script_getstr(st,2),NULL);
11180 struct guild_castle* gc = guild_mapname2gc(mapname);
11181 const char* name = (gc) ? gc->castle_name : "";
11182 script_pushstrcopy(st,name);
11183 return 0;
11184}
11185
11186BUILDIN_FUNC(getcastledata)
11187{
11188 const char* mapname = mapindex_getmapname(script_getstr(st,2),NULL);
11189 int index = script_getnum(st,3);
11190
11191 struct guild_castle* gc = guild_mapname2gc(mapname);
11192
11193 if(script_hasdata(st,4) && index==0 && gc) {
11194 const char* event = script_getstr(st,4);
11195 check_event(st, event);
11196 guild_addcastleinfoevent(gc->castle_id,17,event);
11197 }
11198
11199 if(gc){
11200 switch(index){
11201 case 0: {
11202 int i;
11203 for(i=1;i<18;i++) // Initialize[AgitInit]
11204 guild_castledataload(gc->castle_id,i);
11205 } break;
11206 case 1:
11207 script_pushint(st,gc->guild_id); break;
11208 case 2:
11209 script_pushint(st,gc->economy); break;
11210 case 3:
11211 script_pushint(st,gc->defense); break;
11212 case 4:
11213 script_pushint(st,gc->triggerE); break;
11214 case 5:
11215 script_pushint(st,gc->triggerD); break;
11216 case 6:
11217 script_pushint(st,gc->nextTime); break;
11218 case 7:
11219 script_pushint(st,gc->payTime); break;
11220 case 8:
11221 script_pushint(st,gc->createTime); break;
11222 case 9:
11223 script_pushint(st,gc->visibleC); break;
11224 case 10:
11225 case 11:
11226 case 12:
11227 case 13:
11228 case 14:
11229 case 15:
11230 case 16:
11231 case 17:
11232 script_pushint(st,gc->guardian[index-10].visible); break;
11233 default:
11234 script_pushint(st,0); break;
11235 }
11236 return 0;
11237 }
11238 script_pushint(st,0);
11239 return 0;
11240}
11241
11242BUILDIN_FUNC(setcastledata)
11243{
11244 const char* mapname = mapindex_getmapname(script_getstr(st,2),NULL);
11245 int index = script_getnum(st,3);
11246 int value = script_getnum(st,4);
11247
11248 struct guild_castle* gc = guild_mapname2gc(mapname);
11249
11250 if(gc) {
11251 // Save Data byself First
11252 switch(index){
11253 case 1:
11254 {
11255 struct guild *g;
11256 int m = map_mapindex2mapid(gc->mapindex);
11257 if( map_allowed_woe(m) && gc->guild_id && (g = guild_search(gc->guild_id)) != NULL )
11258 { // Current WoE
11259 int i = gc->castle_id,
11260 addtime = DIFF_TICK(last_tick, gc->capture_tick),
11261 score = (addtime / 300) * (1 + (gc->economy / 25));
11262
11263 g->castle[i].posesion_time += addtime;
11264 g->castle[i].defensive_score += score;
11265 g->castle[i].changed = true;
11266 }
11267
11268 gc->capture_tick = last_tick;
11269 gc->guild_id = value;
11270 }
11271 break;
11272 case 2:
11273 {
11274 struct guild *g = gc->guild_id ? guild_search(gc->guild_id) : NULL;
11275 if( g && gc->economy < value )
11276 {
11277 int eco = value - gc->economy;
11278 add2limit(g->castle[gc->castle_id].invest_eco, eco, USHRT_MAX);
11279 if( g->castle[gc->castle_id].top_eco < value )
11280 g->castle[gc->castle_id].top_eco = value;
11281 g->castle[gc->castle_id].changed = true;
11282 if( !agit_flag )
11283 {
11284 intif_guild_save_score(g->guild_id, gc->castle_id, &g->castle[gc->castle_id]);
11285 g->castle[gc->castle_id].changed = false;
11286 }
11287 }
11288
11289 gc->economy = value;
11290 }
11291 break;
11292 case 3:
11293 {
11294 struct guild *g = gc->guild_id ? guild_search(gc->guild_id) : NULL;
11295 if( g && gc->defense < value )
11296 {
11297 int def = value - gc->defense;
11298 add2limit(g->castle[gc->castle_id].invest_def, def, USHRT_MAX);
11299 if( g->castle[gc->castle_id].top_def < value )
11300 g->castle[gc->castle_id].top_def = value;
11301 g->castle[gc->castle_id].changed = true;
11302 if( !agit_flag )
11303 {
11304 intif_guild_save_score(g->guild_id, gc->castle_id, &g->castle[gc->castle_id]);
11305 g->castle[gc->castle_id].changed = false;
11306 }
11307 }
11308
11309 gc->defense = value;
11310 }
11311 break;
11312 case 4:
11313 gc->triggerE = value; break;
11314 case 5:
11315 gc->triggerD = value; break;
11316 case 6:
11317 gc->nextTime = value; break;
11318 case 7:
11319 gc->payTime = value; break;
11320 case 8:
11321 gc->createTime = value; break;
11322 case 9:
11323 gc->visibleC = value; break;
11324 case 10:
11325 case 11:
11326 case 12:
11327 case 13:
11328 case 14:
11329 case 15:
11330 case 16:
11331 case 17:
11332 gc->guardian[index-10].visible = value; break;
11333 default:
11334 return 0;
11335 }
11336 guild_castledatasave(gc->castle_id,index,value);
11337 }
11338 return 0;
11339}
11340
11341/* =====================================================================
11342 * ã‚®ãƒ«ãƒ‰æƒ…å ±ã‚’è¦æ±‚ã™ã‚‹
11343 * ---------------------------------------------------------------------*/
11344BUILDIN_FUNC(requestguildinfo)
11345{
11346 int guild_id=script_getnum(st,2);
11347 const char *event=NULL;
11348
11349 if( script_hasdata(st,3) ){
11350 event=script_getstr(st,3);
11351 check_event(st, event);
11352 }
11353
11354 if(guild_id>0)
11355 guild_npc_request_info(guild_id,event);
11356 return 0;
11357}
11358
11359/// Returns the number of cards that have been compounded onto the specified equipped item.
11360/// getequipcardcnt(<equipment slot>);
11361BUILDIN_FUNC(getequipcardcnt)
11362{
11363 int i=-1,j,num;
11364 TBL_PC *sd;
11365 int count;
11366
11367 num=script_getnum(st,2);
11368 sd=script_rid2sd(st);
11369 if (num > 0 && num <= ARRAYLENGTH(equip))
11370 i=pc_checkequip(sd,equip[num-1]);
11371
11372 if (i < 0 || !sd->inventory_data[i]) {
11373 script_pushint(st,0);
11374 return 0;
11375 }
11376
11377 if(itemdb_isspecial(sd->status.inventory[i].card[0]))
11378 {
11379 script_pushint(st,0);
11380 return 0;
11381 }
11382
11383 count = 0;
11384 for( j = 0; j < sd->inventory_data[i]->slot; j++ )
11385 if( sd->status.inventory[i].card[j] && itemdb_type(sd->status.inventory[i].card[j]) == IT_CARD )
11386 count++;
11387
11388 script_pushint(st,count);
11389 return 0;
11390}
11391
11392/// Removes all cards from the item found in the specified equipment slot of the invoking character,
11393/// and give them to the character. If any cards were removed in this manner, it will also show a success effect.
11394/// successremovecards <slot>;
11395BUILDIN_FUNC(successremovecards)
11396{
11397 int i=-1,j,c,cardflag=0;
11398
11399 TBL_PC* sd = script_rid2sd(st);
11400 int num = script_getnum(st,2);
11401
11402 if (num > 0 && num <= ARRAYLENGTH(equip))
11403 i=pc_checkequip(sd,equip[num-1]);
11404
11405 if (i < 0 || !sd->inventory_data[i]) {
11406 return 0;
11407 }
11408
11409 if(itemdb_isspecial(sd->status.inventory[i].card[0]))
11410 return 0;
11411
11412 for( c = sd->inventory_data[i]->slot - 1; c >= 0; --c )
11413 {
11414 if( sd->status.inventory[i].card[c] && itemdb_type(sd->status.inventory[i].card[c]) == IT_CARD )
11415 {// extract this card from the item
11416 int flag;
11417 struct item item_tmp;
11418 cardflag = 1;
11419
11420 memset(&item_tmp,0,sizeof(item_tmp));
11421 item_tmp.nameid=sd->status.inventory[i].card[c];
11422 item_tmp.identify=1;
11423
11424 if((flag=pc_additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))){ // æŒã¦ãªã„ãªã‚‰ãƒ‰ãƒãƒƒãƒ—
11425 clif_additem(sd,0,0,flag);
11426 map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0);
11427 }
11428 }
11429 }
11430
11431 if(cardflag == 1)
11432 { // カードをå–り除ã„ãŸã‚¢ã‚¤ãƒ†ãƒ 所得
11433 int flag;
11434 struct item item_tmp;
11435 item_tmp.id=0,item_tmp.nameid=sd->status.inventory[i].nameid;
11436 item_tmp.equip=0,item_tmp.identify=1,item_tmp.refine=sd->status.inventory[i].refine;
11437 item_tmp.attribute=sd->status.inventory[i].attribute,item_tmp.expire_time=sd->status.inventory[i].expire_time;
11438 item_tmp.serial = sd->status.inventory[i].serial,item_tmp.bound = sd->status.inventory[i].bound;
11439 item_tmp.favorite = sd->status.inventory[i].favorite;
11440 for (j = 0; j < sd->inventory_data[i]->slot; j++)
11441 item_tmp.card[j]=0;
11442 for (j = sd->inventory_data[i]->slot; j < MAX_SLOTS; j++)
11443 item_tmp.card[j]=sd->status.inventory[i].card[j];
11444
11445 pc_delitem(sd,i,1,0,3,LOG_TYPE_SCRIPT);
11446
11447 if((flag=pc_additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))){ // ã‚‚ã¦ãªã„ãªã‚‰ãƒ‰ãƒãƒƒãƒ—
11448 clif_additem(sd,0,0,flag);
11449 map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0);
11450 }
11451
11452 clif_misceffect(&sd->bl,3);
11453 }
11454 return 0;
11455}
11456
11457/// Removes all cards from the item found in the specified equipment slot of the invoking character.
11458/// failedremovecards <slot>, <type>;
11459/// <type>=0 : will destroy both the item and the cards.
11460/// <type>=1 : will keep the item, but destroy the cards.
11461/// <type>=2 : will keep the cards, but destroy the item.
11462/// <type>=? : will just display the failure effect.
11463BUILDIN_FUNC(failedremovecards)
11464{
11465 int i=-1,j,c,cardflag=0;
11466
11467 TBL_PC* sd = script_rid2sd(st);
11468 int num = script_getnum(st,2);
11469 int typefail = script_getnum(st,3);
11470
11471 if (num > 0 && num <= ARRAYLENGTH(equip))
11472 i=pc_checkequip(sd,equip[num-1]);
11473
11474 if (i < 0 || !sd->inventory_data[i])
11475 return 0;
11476
11477 if(itemdb_isspecial(sd->status.inventory[i].card[0]))
11478 return 0;
11479
11480 for( c = sd->inventory_data[i]->slot - 1; c >= 0; --c )
11481 {
11482 if( sd->status.inventory[i].card[c] && itemdb_type(sd->status.inventory[i].card[c]) == IT_CARD )
11483 {
11484 cardflag = 1;
11485
11486 if(typefail == 2)
11487 {// add cards to inventory, clear
11488 int flag;
11489 struct item item_tmp;
11490
11491 memset(&item_tmp,0,sizeof(item_tmp));
11492 item_tmp.nameid=sd->status.inventory[i].card[c];
11493 item_tmp.identify=1;
11494
11495 if((flag=pc_additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))){
11496 clif_additem(sd,0,0,flag);
11497 map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0);
11498 }
11499 }
11500 }
11501 }
11502
11503 if(cardflag == 1)
11504 {
11505 if(typefail == 0 || typefail == 2)
11506 pc_delitem(sd,i,1,0,2,LOG_TYPE_SCRIPT);
11507 if(typefail == 1){ // カードã®ã¿æå¤±ï¼ˆæ¦å…·ã‚’è¿”ã™ï¼‰
11508 int flag;
11509 struct item item_tmp;
11510 item_tmp.id=0,item_tmp.nameid=sd->status.inventory[i].nameid;
11511 item_tmp.equip=0,item_tmp.identify=1,item_tmp.refine=sd->status.inventory[i].refine;
11512 item_tmp.attribute=sd->status.inventory[i].attribute,item_tmp.expire_time=sd->status.inventory[i].expire_time;
11513 item_tmp.serial = sd->status.inventory[i].serial;
11514 item_tmp.bound = sd->status.inventory[i].bound;
11515 item_tmp.favorite = sd->status.inventory[i].favorite;
11516
11517 for (j = 0; j < sd->inventory_data[i]->slot; j++)
11518 item_tmp.card[j]=0;
11519 for (j = sd->inventory_data[i]->slot; j < MAX_SLOTS; j++)
11520 item_tmp.card[j]=sd->status.inventory[i].card[j];
11521 pc_delitem(sd,i,1,0,2,LOG_TYPE_SCRIPT);
11522
11523 if((flag=pc_additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))){
11524 clif_additem(sd,0,0,flag);
11525 map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0);
11526 }
11527 }
11528 clif_misceffect(&sd->bl,2);
11529 }
11530
11531 return 0;
11532}
11533
11534/* ================================================================
11535 * mapwarp "<from map>","<to map>",<x>,<y>,<type>,<ID for Type>;
11536 * type: 0=everyone, 1=guild, 2=party; [Reddozen]
11537 * improved by [Lance]
11538 * ================================================================*/
11539BUILDIN_FUNC(mapwarp) // Added by RoVeRT
11540{
11541 int x,y,m,check_val=0,check_ID=0,i=0;
11542 struct guild *g = NULL;
11543 struct party_data *p = NULL;
11544 const char *str;
11545 const char *mapname;
11546 unsigned int index;
11547 mapname=script_getstr(st,2);
11548 str=script_getstr(st,3);
11549 x=script_getnum(st,4);
11550 y=script_getnum(st,5);
11551 if(script_hasdata(st,7)){
11552 check_val=script_getnum(st,6);
11553 check_ID=script_getnum(st,7);
11554 }
11555
11556 if((m=map_mapname2mapid(mapname))< 0)
11557 return 0;
11558
11559 if(!(index=mapindex_name2id(str)))
11560 return 0;
11561
11562 switch(check_val){
11563 case 1:
11564 g = guild_search(check_ID);
11565 if (g){
11566 for( i=0; i < g->max_member; i++)
11567 {
11568 if(g->member[i].sd && g->member[i].sd->bl.m==m){
11569 pc_setpos(g->member[i].sd,index,x,y,CLR_TELEPORT);
11570 }
11571 }
11572 }
11573 break;
11574 case 2:
11575 p = party_search(check_ID);
11576 if(p){
11577 for(i=0;i<MAX_PARTY; i++){
11578 if(p->data[i].sd && p->data[i].sd->bl.m == m){
11579 pc_setpos(p->data[i].sd,index,x,y,CLR_TELEPORT);
11580 }
11581 }
11582 }
11583 break;
11584 default:
11585 map_foreachinmap(buildin_areawarp_sub,m,BL_PC,index,x,y,0,0);
11586 break;
11587 }
11588
11589 return 0;
11590}
11591
11592static int buildin_mobcount_sub(struct block_list *bl,va_list ap) // Added by RoVeRT
11593{
11594 char *event=va_arg(ap,char *);
11595 struct mob_data *md = ((struct mob_data *)bl);
11596 if(strcmp(event,md->npc_event)==0 && md->status.hp > 0)
11597 return 1;
11598 return 0;
11599}
11600
11601BUILDIN_FUNC(mobcount) // Added by RoVeRT
11602{
11603 const char *mapname,*event;
11604 int m;
11605 mapname=script_getstr(st,2);
11606 event=script_getstr(st,3);
11607 check_event(st, event);
11608
11609 if( (m = map_mapname2mapid(mapname)) < 0 ) {
11610 script_pushint(st,-1);
11611 return 0;
11612 }
11613
11614 if( map[m].flag.src4instance && map[m].instance_id == 0 && st->instance_id && (m = instance_mapid2imapid(m, st->instance_id)) < 0 )
11615 {
11616 script_pushint(st,-1);
11617 return 0;
11618 }
11619
11620 script_pushint(st,map_foreachinmap(buildin_mobcount_sub, m, BL_MOB, event));
11621
11622 return 0;
11623}
11624BUILDIN_FUNC(marriage)
11625{
11626 const char *partner=script_getstr(st,2);
11627 TBL_PC *sd=script_rid2sd(st);
11628 TBL_PC *p_sd=map_nick2sd(partner);
11629
11630 if(sd==NULL || p_sd==NULL || pc_marriage(sd,p_sd) < 0){
11631 script_pushint(st,0);
11632 return 0;
11633 }
11634 script_pushint(st,1);
11635 return 0;
11636}
11637BUILDIN_FUNC(wedding_effect)
11638{
11639 TBL_PC *sd=script_rid2sd(st);
11640 struct block_list *bl;
11641
11642 if(sd==NULL) {
11643 bl=map_id2bl(st->oid);
11644 } else
11645 bl=&sd->bl;
11646 clif_wedding_effect(bl);
11647 return 0;
11648}
11649BUILDIN_FUNC(divorce)
11650{
11651 TBL_PC *sd=script_rid2sd(st);
11652 if(sd==NULL || pc_divorce(sd) < 0){
11653 script_pushint(st,0);
11654 return 0;
11655 }
11656 script_pushint(st,1);
11657 return 0;
11658}
11659
11660BUILDIN_FUNC(ispartneron)
11661{
11662 TBL_PC *sd=script_rid2sd(st);
11663
11664 if(sd==NULL || !pc_ismarried(sd) ||
11665 map_charid2sd(sd->status.partner_id) == NULL) {
11666 script_pushint(st,0);
11667 return 0;
11668 }
11669
11670 script_pushint(st,1);
11671 return 0;
11672}
11673
11674BUILDIN_FUNC(getpartnerid)
11675{
11676 TBL_PC *sd=script_rid2sd(st);
11677 if (sd == NULL) {
11678 script_pushint(st,0);
11679 return 0;
11680 }
11681
11682 script_pushint(st,sd->status.partner_id);
11683 return 0;
11684}
11685
11686BUILDIN_FUNC(getchildid)
11687{
11688 TBL_PC *sd=script_rid2sd(st);
11689 if (sd == NULL) {
11690 script_pushint(st,0);
11691 return 0;
11692 }
11693
11694 script_pushint(st,sd->status.child);
11695 return 0;
11696}
11697
11698BUILDIN_FUNC(getmotherid)
11699{
11700 TBL_PC *sd=script_rid2sd(st);
11701 if (sd == NULL) {
11702 script_pushint(st,0);
11703 return 0;
11704 }
11705
11706 script_pushint(st,sd->status.mother);
11707 return 0;
11708}
11709
11710BUILDIN_FUNC(getfatherid)
11711{
11712 TBL_PC *sd=script_rid2sd(st);
11713 if (sd == NULL) {
11714 script_pushint(st,0);
11715 return 0;
11716 }
11717
11718 script_pushint(st,sd->status.father);
11719 return 0;
11720}
11721
11722BUILDIN_FUNC(warppartner)
11723{
11724 int x,y;
11725 unsigned short mapindex;
11726 const char *str;
11727 TBL_PC *sd=script_rid2sd(st);
11728 TBL_PC *p_sd=NULL;
11729
11730 if(sd==NULL || !pc_ismarried(sd) ||
11731 (p_sd=map_charid2sd(sd->status.partner_id)) == NULL) {
11732 script_pushint(st,0);
11733 return 0;
11734 }
11735
11736 str=script_getstr(st,2);
11737 x=script_getnum(st,3);
11738 y=script_getnum(st,4);
11739
11740 mapindex = mapindex_name2id(str);
11741 if (mapindex) {
11742 pc_setpos(p_sd,mapindex,x,y,CLR_OUTSIGHT);
11743 script_pushint(st,1);
11744 } else
11745 script_pushint(st,0);
11746 return 0;
11747}
11748
11749/*================================================
11750 * Script for Displaying MOB Information [Valaris]
11751 *------------------------------------------------*/
11752BUILDIN_FUNC(strmobinfo)
11753{
11754
11755 int num=script_getnum(st,2);
11756 int class_=script_getnum(st,3);
11757
11758 if(!mobdb_checkid(class_))
11759 {
11760 script_pushint(st,0);
11761 return 0;
11762 }
11763
11764 switch (num) {
11765 case 1: script_pushstrcopy(st,mob_db(class_)->name); break;
11766 case 2: script_pushstrcopy(st,mob_db(class_)->jname); break;
11767 case 3: script_pushint(st,mob_db(class_)->lv); break;
11768 case 4: script_pushint(st,mob_db(class_)->status.max_hp); break;
11769 case 5: script_pushint(st,mob_db(class_)->status.max_sp); break;
11770 case 6: script_pushint(st,mob_db(class_)->base_exp); break;
11771 case 7: script_pushint(st,mob_db(class_)->job_exp); break;
11772 default:
11773 script_pushint(st,0);
11774 break;
11775 }
11776 return 0;
11777}
11778
11779/*==========================================
11780 * Summon guardians [Valaris]
11781 * guardian("<map name>",<x>,<y>,"<name to show>",<mob id>{,"<event label>"}{,<guardian index>}) -> <id>
11782 *------------------------------------------*/
11783BUILDIN_FUNC(guardian)
11784{
11785 int class_=0,x=0,y=0,guardian=0;
11786 const char *str,*map,*evt="";
11787 struct script_data *data;
11788 bool has_index = false;
11789
11790 map =script_getstr(st,2);
11791 x =script_getnum(st,3);
11792 y =script_getnum(st,4);
11793 str =script_getstr(st,5);
11794 class_=script_getnum(st,6);
11795
11796 if( script_hasdata(st,8) )
11797 {// "<event label>",<guardian index>
11798 evt=script_getstr(st,7);
11799 guardian=script_getnum(st,8);
11800 has_index = true;
11801 } else if( script_hasdata(st,7) ){
11802 data=script_getdata(st,7);
11803 get_val(st,data);
11804 if( data_isstring(data) )
11805 {// "<event label>"
11806 evt=script_getstr(st,7);
11807 } else if( data_isint(data) )
11808 {// <guardian index>
11809 guardian=script_getnum(st,7);
11810 has_index = true;
11811 } else {
11812 ShowError("script:guardian: invalid data type for argument #6 (from 1)\n");
11813 script_reportdata(data);
11814 return 1;
11815 }
11816 }
11817
11818 check_event(st, evt);
11819 script_pushint(st, mob_spawn_guardian(map,x,y,str,class_,evt,guardian,has_index));
11820
11821 return 0;
11822}
11823/*==========================================
11824 * Invisible Walls [Zephyrus]
11825 *------------------------------------------*/
11826BUILDIN_FUNC(setwall)
11827{
11828 const char *map, *name;
11829 int x, y, m, size, dir;
11830 bool shootable;
11831
11832 map = script_getstr(st,2);
11833 x = script_getnum(st,3);
11834 y = script_getnum(st,4);
11835 size = script_getnum(st,5);
11836 dir = script_getnum(st,6);
11837 shootable = script_getnum(st,7);
11838 name = script_getstr(st,8);
11839
11840 if( (m = map_mapname2mapid(map)) < 0 )
11841 return 0; // Invalid Map
11842
11843 map_iwall_set(m, x, y, size, dir, shootable, name);
11844 return 0;
11845}
11846BUILDIN_FUNC(delwall)
11847{
11848 const char *name = script_getstr(st,2);
11849 map_iwall_remove(name);
11850
11851 return 0;
11852}
11853
11854/// Retrieves various information about the specified guardian.
11855///
11856/// guardianinfo("<map_name>", <index>, <type>) -> <value>
11857/// type: 0 - whether it is deployed or not
11858/// 1 - maximum hp
11859/// 2 - current hp
11860///
11861BUILDIN_FUNC(guardianinfo)
11862{
11863 const char* mapname = mapindex_getmapname(script_getstr(st,2),NULL);
11864 int id = script_getnum(st,3);
11865 int type = script_getnum(st,4);
11866
11867 struct guild_castle* gc = guild_mapname2gc(mapname);
11868 struct mob_data* gd;
11869
11870 if( gc == NULL || id < 0 || id >= MAX_GUARDIANS )
11871 {
11872 script_pushint(st,-1);
11873 return 0;
11874 }
11875
11876 if( type == 0 )
11877 script_pushint(st, gc->guardian[id].visible);
11878 else
11879 if( !gc->guardian[id].visible )
11880 script_pushint(st,-1);
11881 else
11882 if( (gd = map_id2md(gc->guardian[id].id)) == NULL )
11883 script_pushint(st,-1);
11884 else
11885 {
11886 if ( type == 1 ) script_pushint(st,gd->status.max_hp);
11887 else if( type == 2 ) script_pushint(st,gd->status.hp);
11888 else
11889 script_pushint(st,-1);
11890 }
11891
11892 return 0;
11893}
11894
11895/*==========================================
11896 * IDã‹ã‚‰Itemå
11897 *------------------------------------------*/
11898BUILDIN_FUNC(getitemname)
11899{
11900 int item_id=0;
11901 struct item_data *i_data;
11902 char *item_name;
11903 struct script_data *data;
11904
11905 data=script_getdata(st,2);
11906 get_val(st,data);
11907
11908 if( data_isstring(data) ){
11909 const char *name=conv_str(st,data);
11910 struct item_data *item_data = itemdb_searchname(name);
11911 if( item_data )
11912 item_id=item_data->nameid;
11913 }else
11914 item_id=conv_num(st,data);
11915
11916 i_data = itemdb_exists(item_id);
11917 if (i_data == NULL)
11918 {
11919 script_pushconststr(st,"null");
11920 return 0;
11921 }
11922 item_name=(char *)aMallocA(ITEM_NAME_LENGTH*sizeof(char));
11923
11924 memcpy(item_name, i_data->jname, ITEM_NAME_LENGTH);
11925 script_pushstr(st,item_name);
11926 return 0;
11927}
11928/*==========================================
11929 * Returns number of slots an item has. [Skotlex]
11930 *------------------------------------------*/
11931BUILDIN_FUNC(getitemslots)
11932{
11933 int item_id;
11934 struct item_data *i_data;
11935
11936 item_id=script_getnum(st,2);
11937
11938 i_data = itemdb_exists(item_id);
11939
11940 if (i_data)
11941 script_pushint(st,i_data->slot);
11942 else
11943 script_pushint(st,-1);
11944 return 0;
11945}
11946
11947/*==========================================
11948 * Returns some values of an item [Lupus]
11949 * Price, Weight, etc...
11950 getiteminfo(itemID,n), where n
11951 0 value_buy;
11952 1 value_sell;
11953 2 type;
11954 3 maxchance = Max drop chance of this item e.g. 1 = 0.01% , etc..
11955 if = 0, then monsters don't drop it at all (rare or a quest item)
11956 if = -1, then this item is sold in NPC shops only
11957 4 sex;
11958 5 equip;
11959 6 weight;
11960 7 atk;
11961 8 def;
11962 9 range;
11963 10 slot;
11964 11 look;
11965 12 elv;
11966 13 wlv;
11967 14 view id
11968 *------------------------------------------*/
11969BUILDIN_FUNC(getiteminfo)
11970{
11971 int item_id,n;
11972 int *item_arr;
11973 struct item_data *i_data;
11974
11975 item_id = script_getnum(st,2);
11976 n = script_getnum(st,3);
11977 i_data = itemdb_exists(item_id);
11978
11979 if (i_data && n>=0 && n<=14) {
11980 item_arr = (int*)&i_data->value_buy;
11981 script_pushint(st,item_arr[n]);
11982 } else
11983 script_pushint(st,-1);
11984 return 0;
11985}
11986
11987BUILDIN_FUNC(getitemisrefinable)
11988{
11989 int item_id;
11990 struct item_data *i_data;
11991
11992 item_id = script_getnum(st,2);
11993 i_data = itemdb_exists(item_id);
11994
11995 if( i_data != NULL && !i_data->flag.no_refine )
11996 script_pushint(st,1);
11997 else
11998 script_pushint(st,0);
11999 return 0;
12000}
12001
12002BUILDIN_FUNC(getitemisequipable)
12003{
12004 struct map_session_data *sd;
12005 int item_id = script_getnum(st,2);
12006 sd = script_rid2sd(st);
12007
12008 script_pushint(st,pc_isequip2(sd, item_id));
12009 return 0;
12010}
12011
12012/*==========================================
12013 * Set some values of an item [Lupus]
12014 * Price, Weight, etc...
12015 setiteminfo(itemID,n,Value), where n
12016 0 value_buy;
12017 1 value_sell;
12018 2 type;
12019 3 maxchance = Max drop chance of this item e.g. 1 = 0.01% , etc..
12020 if = 0, then monsters don't drop it at all (rare or a quest item)
12021 if = -1, then this item is sold in NPC shops only
12022 4 sex;
12023 5 equip;
12024 6 weight;
12025 7 atk;
12026 8 def;
12027 9 range;
12028 10 slot;
12029 11 look;
12030 12 elv;
12031 13 wlv;
12032 14 view id
12033 * Returns Value or -1 if the wrong field's been set
12034 *------------------------------------------*/
12035BUILDIN_FUNC(setiteminfo)
12036{
12037 int item_id,n,value;
12038 int *item_arr;
12039 struct item_data *i_data;
12040
12041 item_id = script_getnum(st,2);
12042 n = script_getnum(st,3);
12043 value = script_getnum(st,4);
12044 i_data = itemdb_exists(item_id);
12045
12046 if (i_data && n>=0 && n<=14) {
12047 item_arr = (int*)&i_data->value_buy;
12048 item_arr[n] = value;
12049 script_pushint(st,value);
12050 } else
12051 script_pushint(st,-1);
12052 return 0;
12053}
12054
12055/*==========================================
12056 * Returns value from equipped item slot n [Lupus]
12057 getequipcardid(num,slot)
12058 where
12059 num = eqip position slot
12060 slot = 0,1,2,3 (Card Slot N)
12061
12062 This func returns CARD ID, 255,254,-255 (for card 0, if the item is produced)
12063 it's useful when you want to check item cards or if it's signed
12064 Useful for such quests as "Sign this refined item with players name" etc
12065 Hat[0] +4 -> Player's Hat[0] +4
12066 *------------------------------------------*/
12067BUILDIN_FUNC(getequipcardid)
12068{
12069 int i=-1,num,slot;
12070 TBL_PC *sd;
12071
12072 num=script_getnum(st,2);
12073 slot=script_getnum(st,3);
12074 sd=script_rid2sd(st);
12075 if (num > 0 && num <= ARRAYLENGTH(equip))
12076 i=pc_checkequip(sd,equip[num-1]);
12077 if(i >= 0 && slot>=0 && slot<4)
12078 script_pushint(st,sd->status.inventory[i].card[slot]);
12079 else
12080 script_pushint(st,0);
12081
12082 return 0;
12083}
12084
12085/*==========================================
12086 * petskillbonus [Valaris] //Rewritten by [Skotlex]
12087 *------------------------------------------*/
12088BUILDIN_FUNC(petskillbonus)
12089{
12090 struct pet_data *pd;
12091
12092 TBL_PC *sd=script_rid2sd(st);
12093
12094 if(sd==NULL || sd->pd==NULL)
12095 return 0;
12096
12097 pd=sd->pd;
12098 if (pd->bonus)
12099 { //Clear previous bonus
12100 if (pd->bonus->timer != INVALID_TIMER)
12101 delete_timer(pd->bonus->timer, pet_skill_bonus_timer);
12102 } else //init
12103 pd->bonus = (struct pet_bonus *) aMalloc(sizeof(struct pet_bonus));
12104
12105 pd->bonus->type=script_getnum(st,2);
12106 pd->bonus->val=script_getnum(st,3);
12107 pd->bonus->duration=script_getnum(st,4);
12108 pd->bonus->delay=script_getnum(st,5);
12109
12110 if (pd->state.skillbonus == 1)
12111 pd->state.skillbonus=0; // waiting state
12112
12113 // wait for timer to start
12114 if (battle_config.pet_equip_required && pd->pet.equip == 0)
12115 pd->bonus->timer = INVALID_TIMER;
12116 else
12117 pd->bonus->timer = add_timer(gettick()+pd->bonus->delay*1000, pet_skill_bonus_timer, sd->bl.id, 0);
12118
12119 return 0;
12120}
12121
12122/*==========================================
12123 * pet looting [Valaris] //Rewritten by [Skotlex]
12124 *------------------------------------------*/
12125BUILDIN_FUNC(petloot)
12126{
12127 int max;
12128 struct pet_data *pd;
12129 TBL_PC *sd=script_rid2sd(st);
12130
12131 if(sd==NULL || sd->pd==NULL)
12132 return 0;
12133
12134 max=script_getnum(st,2);
12135
12136 if(max < 1)
12137 max = 1; //Let'em loot at least 1 item.
12138 else if (max > MAX_PETLOOT_SIZE)
12139 max = MAX_PETLOOT_SIZE;
12140
12141 pd = sd->pd;
12142 if (pd->loot != NULL)
12143 { //Release whatever was there already and reallocate memory
12144 pet_lootitem_drop(pd, pd->msd);
12145 aFree(pd->loot->item);
12146 }
12147 else
12148 pd->loot = (struct pet_loot *)aMalloc(sizeof(struct pet_loot));
12149
12150 pd->loot->item = (struct item *)aCalloc(max,sizeof(struct item));
12151
12152 pd->loot->max=max;
12153 pd->loot->count = 0;
12154 pd->loot->weight = 0;
12155
12156 return 0;
12157}
12158/*==========================================
12159 * PCã®æ‰€æŒå“æƒ…å ±èªã¿å–り
12160 *------------------------------------------*/
12161BUILDIN_FUNC(getinventorylist)
12162{
12163 TBL_PC *sd=script_rid2sd(st);
12164 char card_var[NAME_LENGTH];
12165
12166 int i,j=0,k;
12167 if(!sd) return 0;
12168 for(i=0;i<MAX_INVENTORY;i++){
12169 if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount > 0){
12170 pc_setreg(sd,reference_uid(add_str("@inventorylist_id"), j),sd->status.inventory[i].nameid);
12171 pc_setreg(sd,reference_uid(add_str("@inventorylist_amount"), j),sd->status.inventory[i].amount);
12172 pc_setreg(sd,reference_uid(add_str("@inventorylist_equip"), j),sd->status.inventory[i].equip);
12173 pc_setreg(sd,reference_uid(add_str("@inventorylist_refine"), j),sd->status.inventory[i].refine);
12174 pc_setreg(sd,reference_uid(add_str("@inventorylist_identify"), j),sd->status.inventory[i].identify);
12175 pc_setreg(sd,reference_uid(add_str("@inventorylist_attribute"), j),sd->status.inventory[i].attribute);
12176 for (k = 0; k < MAX_SLOTS; k++)
12177 {
12178 sprintf(card_var, "@inventorylist_card%d",k+1);
12179 pc_setreg(sd,reference_uid(add_str(card_var), j),sd->status.inventory[i].card[k]);
12180 }
12181 pc_setreg(sd,reference_uid(add_str("@inventorylist_expire"), j),sd->status.inventory[i].expire_time);
12182 j++;
12183 }
12184 }
12185 pc_setreg(sd,add_str("@inventorylist_count"),j);
12186 return 0;
12187}
12188
12189BUILDIN_FUNC(getskilllist)
12190{
12191 TBL_PC *sd=script_rid2sd(st);
12192 int i,j=0;
12193 if(!sd) return 0;
12194 for(i=0;i<MAX_SKILL;i++){
12195 if(sd->status.skill[i].id > 0 && sd->status.skill[i].lv > 0){
12196 pc_setreg(sd,reference_uid(add_str("@skilllist_id"), j),sd->status.skill[i].id);
12197 pc_setreg(sd,reference_uid(add_str("@skilllist_lv"), j),sd->status.skill[i].lv);
12198 pc_setreg(sd,reference_uid(add_str("@skilllist_flag"), j),sd->status.skill[i].flag);
12199 j++;
12200 }
12201 }
12202 pc_setreg(sd,add_str("@skilllist_count"),j);
12203 return 0;
12204}
12205
12206BUILDIN_FUNC(clearitem)
12207{
12208 TBL_PC *sd=script_rid2sd(st);
12209 int i;
12210 if(sd==NULL) return 0;
12211 for (i=0; i<MAX_INVENTORY; i++) {
12212 if (sd->status.inventory[i].amount)
12213 pc_delitem(sd, i, sd->status.inventory[i].amount, 0, 0, LOG_TYPE_SCRIPT);
12214 }
12215 return 0;
12216}
12217
12218/*==========================================
12219 * Disguise Player (returns Mob/NPC ID if success, 0 on fail)
12220 *------------------------------------------*/
12221BUILDIN_FUNC(disguise)
12222{
12223 int id;
12224 TBL_PC* sd = script_rid2sd(st);
12225 if (sd == NULL) return 0;
12226
12227 id = script_getnum(st,2);
12228
12229 if (mobdb_checkid(id) || npcdb_checkid(id)) {
12230 pc_disguise(sd, id);
12231 script_pushint(st,id);
12232 } else
12233 script_pushint(st,0);
12234
12235 return 0;
12236}
12237
12238/*==========================================
12239 * Undisguise Player (returns 1 if success, 0 on fail)
12240 *------------------------------------------*/
12241BUILDIN_FUNC(undisguise)
12242{
12243 TBL_PC* sd = script_rid2sd(st);
12244 if (sd == NULL) return 0;
12245
12246 if (sd->disguise) {
12247 pc_disguise(sd, 0);
12248 script_pushint(st,0);
12249 } else {
12250 script_pushint(st,1);
12251 }
12252 return 0;
12253}
12254
12255BUILDIN_FUNC(isdisguised)
12256{
12257 TBL_PC* sd = script_rid2sd(st);
12258 if (sd == NULL) return 0;
12259
12260 script_pushint(st,sd->disguise);
12261
12262 return 0;
12263}
12264
12265/*==========================================
12266 * NPCクラスãƒã‚§ãƒ³ã‚¸
12267 * classã¯å¤‰ã‚りãŸã„class
12268 * typeã¯é€šå¸¸0ãªã®ã‹ãªï¼Ÿ
12269 *------------------------------------------*/
12270BUILDIN_FUNC(classchange)
12271{
12272 int _class,type;
12273 struct block_list *bl=map_id2bl(st->oid);
12274
12275 if(bl==NULL) return 0;
12276
12277 _class=script_getnum(st,2);
12278 type=script_getnum(st,3);
12279 clif_class_change(bl,_class,type);
12280 return 0;
12281}
12282
12283/*==========================================
12284 * NPCã‹ã‚‰ç™ºç”Ÿã™ã‚‹ã‚¨ãƒ•ェクト
12285 *------------------------------------------*/
12286BUILDIN_FUNC(misceffect)
12287{
12288 int type;
12289
12290 type=script_getnum(st,2);
12291 if(st->oid && st->oid != fake_nd->bl.id) {
12292 struct block_list *bl = map_id2bl(st->oid);
12293 if (bl)
12294 clif_specialeffect(bl,type,AREA);
12295 } else{
12296 TBL_PC *sd=script_rid2sd(st);
12297 if(sd)
12298 clif_specialeffect(&sd->bl,type,AREA);
12299 }
12300 return 0;
12301}
12302/*==========================================
12303 * Play a BGM on a single client [Rikter/Yommy]
12304 *------------------------------------------*/
12305BUILDIN_FUNC(playBGM)
12306{
12307 const char* name;
12308 struct map_session_data* sd;
12309
12310 if( ( sd = script_rid2sd(st) ) != NULL )
12311 {
12312 name = script_getstr(st,2);
12313
12314 clif_playBGM(sd, name);
12315 }
12316
12317 return 0;
12318}
12319
12320static int playBGM_sub(struct block_list* bl,va_list ap)
12321{
12322 const char* name = va_arg(ap,const char*);
12323
12324 clif_playBGM(BL_CAST(BL_PC, bl), name);
12325
12326 return 0;
12327}
12328
12329static int playBGM_foreachpc_sub(struct map_session_data* sd, va_list args)
12330{
12331 const char* name = va_arg(args, const char*);
12332
12333 clif_playBGM(sd, name);
12334 return 0;
12335}
12336
12337/*==========================================
12338 * Play a BGM on multiple client [Rikter/Yommy]
12339 *------------------------------------------*/
12340BUILDIN_FUNC(playBGMall)
12341{
12342 const char* name;
12343
12344 name = script_getstr(st,2);
12345
12346 if( script_hasdata(st,7) )
12347 {// specified part of map
12348 const char* map = script_getstr(st,3);
12349 int x0 = script_getnum(st,4);
12350 int y0 = script_getnum(st,5);
12351 int x1 = script_getnum(st,6);
12352 int y1 = script_getnum(st,7);
12353
12354 map_foreachinarea(playBGM_sub, map_mapname2mapid(map), x0, y0, x1, y1, BL_PC, name);
12355 }
12356 else if( script_hasdata(st,3) )
12357 {// entire map
12358 const char* map = script_getstr(st,3);
12359
12360 map_foreachinmap(playBGM_sub, map_mapname2mapid(map), BL_PC, name);
12361 }
12362 else
12363 {// entire server
12364 map_foreachpc(&playBGM_foreachpc_sub, name);
12365 }
12366
12367 return 0;
12368}
12369
12370/*==========================================
12371 * サウンドエフェクト
12372 *------------------------------------------*/
12373BUILDIN_FUNC(soundeffect)
12374{
12375 TBL_PC* sd = script_rid2sd(st);
12376 const char* name = script_getstr(st,2);
12377 int type = script_getnum(st,3);
12378
12379 if(sd)
12380 {
12381 clif_soundeffect(sd,&sd->bl,name,type);
12382 }
12383 return 0;
12384}
12385
12386int soundeffect_sub(struct block_list* bl,va_list ap)
12387{
12388 char* name = va_arg(ap,char*);
12389 int type = va_arg(ap,int);
12390
12391 clif_soundeffect((TBL_PC *)bl, bl, name, type);
12392
12393 return 0;
12394}
12395
12396/*==========================================
12397 * Play a sound effect (.wav) on multiple clients
12398 * soundeffectall "<filepath>",<type>{,"<map name>"}{,<x0>,<y0>,<x1>,<y1>};
12399 *------------------------------------------*/
12400BUILDIN_FUNC(soundeffectall)
12401{
12402 struct block_list* bl;
12403 const char* name;
12404 int type;
12405
12406 bl = (st->rid) ? &(script_rid2sd(st)->bl) : map_id2bl(st->oid);
12407 if (!bl)
12408 return 0;
12409
12410 name = script_getstr(st,2);
12411 type = script_getnum(st,3);
12412
12413 //FIXME: enumerating map squares (map_foreach) is slower than enumerating the list of online players (map_foreachpc?) [ultramage]
12414
12415 if(!script_hasdata(st,4))
12416 { // area around
12417 clif_soundeffectall(bl, name, type, AREA);
12418 }
12419 else
12420 if(!script_hasdata(st,5))
12421 { // entire map
12422 const char* map = script_getstr(st,4);
12423 map_foreachinmap(soundeffect_sub, map_mapname2mapid(map), BL_PC, name, type);
12424 }
12425 else
12426 if(script_hasdata(st,8))
12427 { // specified part of map
12428 const char* map = script_getstr(st,4);
12429 int x0 = script_getnum(st,5);
12430 int y0 = script_getnum(st,6);
12431 int x1 = script_getnum(st,7);
12432 int y1 = script_getnum(st,8);
12433 map_foreachinarea(soundeffect_sub, map_mapname2mapid(map), x0, y0, x1, y1, BL_PC, name, type);
12434 }
12435 else
12436 {
12437 ShowError("buildin_soundeffectall: insufficient arguments for specific area broadcast.\n");
12438 }
12439
12440 return 0;
12441}
12442/*==========================================
12443 * pet status recovery [Valaris] / Rewritten by [Skotlex]
12444 *------------------------------------------*/
12445BUILDIN_FUNC(petrecovery)
12446{
12447 struct pet_data *pd;
12448 TBL_PC *sd=script_rid2sd(st);
12449
12450 if(sd==NULL || sd->pd==NULL)
12451 return 0;
12452
12453 pd=sd->pd;
12454
12455 if (pd->recovery)
12456 { //Halt previous bonus
12457 if (pd->recovery->timer != INVALID_TIMER)
12458 delete_timer(pd->recovery->timer, pet_recovery_timer);
12459 } else //Init
12460 pd->recovery = (struct pet_recovery *)aMalloc(sizeof(struct pet_recovery));
12461
12462 pd->recovery->type = (sc_type)script_getnum(st,2);
12463 pd->recovery->delay = script_getnum(st,3);
12464 pd->recovery->timer = INVALID_TIMER;
12465
12466 return 0;
12467}
12468
12469/*==========================================
12470 * pet healing [Valaris] //Rewritten by [Skotlex]
12471 *------------------------------------------*/
12472BUILDIN_FUNC(petheal)
12473{
12474 struct pet_data *pd;
12475 TBL_PC *sd=script_rid2sd(st);
12476
12477 if(sd==NULL || sd->pd==NULL)
12478 return 0;
12479
12480 pd=sd->pd;
12481 if (pd->s_skill)
12482 { //Clear previous skill
12483 if (pd->s_skill->timer != INVALID_TIMER)
12484 {
12485 if (pd->s_skill->id)
12486 delete_timer(pd->s_skill->timer, pet_skill_support_timer);
12487 else
12488 delete_timer(pd->s_skill->timer, pet_heal_timer);
12489 }
12490 } else //init memory
12491 pd->s_skill = (struct pet_skill_support *) aMalloc(sizeof(struct pet_skill_support));
12492
12493 pd->s_skill->id=0; //This id identifies that it IS petheal rather than pet_skillsupport
12494 //Use the lv as the amount to heal
12495 pd->s_skill->lv=script_getnum(st,2);
12496 pd->s_skill->delay=script_getnum(st,3);
12497 pd->s_skill->hp=script_getnum(st,4);
12498 pd->s_skill->sp=script_getnum(st,5);
12499
12500 //Use delay as initial offset to avoid skill/heal exploits
12501 if (battle_config.pet_equip_required && pd->pet.equip == 0)
12502 pd->s_skill->timer = INVALID_TIMER;
12503 else
12504 pd->s_skill->timer = add_timer(gettick()+pd->s_skill->delay*1000,pet_heal_timer,sd->bl.id,0);
12505
12506 return 0;
12507}
12508
12509/*==========================================
12510 * pet attack skills [Valaris] //Rewritten by [Skotlex]
12511 *------------------------------------------*/
12512/// petskillattack <skill id>,<level>,<rate>,<bonusrate>
12513/// petskillattack "<skill name>",<level>,<rate>,<bonusrate>
12514BUILDIN_FUNC(petskillattack)
12515{
12516 struct pet_data *pd;
12517 TBL_PC *sd=script_rid2sd(st);
12518
12519 if(sd==NULL || sd->pd==NULL)
12520 return 0;
12521
12522 pd=sd->pd;
12523 if (pd->a_skill == NULL)
12524 pd->a_skill = (struct pet_skill_attack *)aMalloc(sizeof(struct pet_skill_attack));
12525
12526 pd->a_skill->id=( script_isstring(st,2) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
12527 pd->a_skill->lv=script_getnum(st,3);
12528 pd->a_skill->div_ = 0;
12529 pd->a_skill->rate=script_getnum(st,4);
12530 pd->a_skill->bonusrate=script_getnum(st,5);
12531
12532 return 0;
12533}
12534
12535/*==========================================
12536 * pet attack skills [Valaris]
12537 *------------------------------------------*/
12538/// petskillattack2 <skill id>,<level>,<div>,<rate>,<bonusrate>
12539/// petskillattack2 "<skill name>",<level>,<div>,<rate>,<bonusrate>
12540BUILDIN_FUNC(petskillattack2)
12541{
12542 struct pet_data *pd;
12543 TBL_PC *sd=script_rid2sd(st);
12544
12545 if(sd==NULL || sd->pd==NULL)
12546 return 0;
12547
12548 pd=sd->pd;
12549 if (pd->a_skill == NULL)
12550 pd->a_skill = (struct pet_skill_attack *)aMalloc(sizeof(struct pet_skill_attack));
12551
12552 pd->a_skill->id=( script_isstring(st,2) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
12553 pd->a_skill->lv=script_getnum(st,3);
12554 pd->a_skill->div_ = script_getnum(st,4);
12555 pd->a_skill->rate=script_getnum(st,5);
12556 pd->a_skill->bonusrate=script_getnum(st,6);
12557
12558 return 0;
12559}
12560
12561/*==========================================
12562 * pet support skills [Skotlex]
12563 *------------------------------------------*/
12564/// petskillsupport <skill id>,<level>,<delay>,<hp>,<sp>
12565/// petskillsupport "<skill name>",<level>,<delay>,<hp>,<sp>
12566BUILDIN_FUNC(petskillsupport)
12567{
12568 struct pet_data *pd;
12569 TBL_PC *sd=script_rid2sd(st);
12570
12571 if(sd==NULL || sd->pd==NULL)
12572 return 0;
12573
12574 pd=sd->pd;
12575 if (pd->s_skill)
12576 { //Clear previous skill
12577 if (pd->s_skill->timer != INVALID_TIMER)
12578 {
12579 if (pd->s_skill->id)
12580 delete_timer(pd->s_skill->timer, pet_skill_support_timer);
12581 else
12582 delete_timer(pd->s_skill->timer, pet_heal_timer);
12583 }
12584 } else //init memory
12585 pd->s_skill = (struct pet_skill_support *) aMalloc(sizeof(struct pet_skill_support));
12586
12587 pd->s_skill->id=( script_isstring(st,2) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
12588 pd->s_skill->lv=script_getnum(st,3);
12589 pd->s_skill->delay=script_getnum(st,4);
12590 pd->s_skill->hp=script_getnum(st,5);
12591 pd->s_skill->sp=script_getnum(st,6);
12592
12593 //Use delay as initial offset to avoid skill/heal exploits
12594 if (battle_config.pet_equip_required && pd->pet.equip == 0)
12595 pd->s_skill->timer = INVALID_TIMER;
12596 else
12597 pd->s_skill->timer = add_timer(gettick()+pd->s_skill->delay*1000,pet_skill_support_timer,sd->bl.id,0);
12598
12599 return 0;
12600}
12601
12602/*==========================================
12603 * Scripted skill effects [Celest]
12604 *------------------------------------------*/
12605/// skilleffect <skill id>,<level>
12606/// skilleffect "<skill name>",<level>
12607BUILDIN_FUNC(skilleffect)
12608{
12609 TBL_PC *sd;
12610
12611 int skillid=( script_isstring(st,2) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
12612 int skilllv=script_getnum(st,3);
12613 sd=script_rid2sd(st);
12614
12615 clif_skill_nodamage(&sd->bl,&sd->bl,skillid,skilllv,1);
12616
12617 return 0;
12618}
12619
12620/*==========================================
12621 * NPC skill effects [Valaris]
12622 *------------------------------------------*/
12623/// npcskilleffect <skill id>,<level>,<x>,<y>
12624/// npcskilleffect "<skill name>",<level>,<x>,<y>
12625BUILDIN_FUNC(npcskilleffect)
12626{
12627 struct block_list *bl= map_id2bl(st->oid);
12628
12629 int skillid=( script_isstring(st,2) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
12630 int skilllv=script_getnum(st,3);
12631 int x=script_getnum(st,4);
12632 int y=script_getnum(st,5);
12633
12634 if (bl)
12635 clif_skill_poseffect(bl,skillid,skilllv,x,y,gettick());
12636
12637 return 0;
12638}
12639
12640/*==========================================
12641 * Special effects [Valaris]
12642 *------------------------------------------*/
12643BUILDIN_FUNC(specialeffect)
12644{
12645 struct block_list *bl=map_id2bl(st->oid);
12646 int type = script_getnum(st,2);
12647 enum send_target target = script_hasdata(st,3) ? (send_target)script_getnum(st,3) : AREA;
12648
12649 if(bl==NULL)
12650 return 0;
12651
12652 if( script_hasdata(st,4) )
12653 {
12654 TBL_NPC *nd = npc_name2id(script_getstr(st,4));
12655 if(nd)
12656 clif_specialeffect(&nd->bl, type, target);
12657 }
12658 else
12659 {
12660 if (target == SELF) {
12661 TBL_PC *sd=script_rid2sd(st);
12662 if (sd)
12663 clif_specialeffect_single(bl,type,sd->fd);
12664 } else {
12665 clif_specialeffect(bl, type, target);
12666 }
12667 }
12668
12669 return 0;
12670}
12671
12672BUILDIN_FUNC(specialeffect2)
12673{
12674 TBL_PC *sd=script_rid2sd(st);
12675 int type = script_getnum(st,2);
12676 enum send_target target = script_hasdata(st,3) ? (send_target)script_getnum(st,3) : AREA;
12677
12678 if( script_hasdata(st,4) )
12679 sd = map_nick2sd(script_getstr(st,4));
12680
12681 if (sd)
12682 clif_specialeffect(&sd->bl, type, target);
12683
12684 return 0;
12685}
12686
12687/*==========================================
12688 * Nude [Valaris]
12689 *------------------------------------------*/
12690BUILDIN_FUNC(nude)
12691{
12692 TBL_PC *sd=script_rid2sd(st);
12693 int i,calcflag=0;
12694
12695 if(sd==NULL)
12696 return 0;
12697
12698 for(i=0;i<11;i++)
12699 if(sd->equip_index[i] >= 0) {
12700 if(!calcflag)
12701 calcflag=1;
12702 pc_unequipitem(sd,sd->equip_index[i],2);
12703 }
12704
12705 if(calcflag)
12706 status_calc_pc(sd,0);
12707
12708 return 0;
12709}
12710
12711/*==========================================
12712 * gmcommand [MouseJstr]
12713 *
12714 * suggested on the forums...
12715 * splitted into atcommand & charcommand by [Skotlex]
12716 *------------------------------------------*/
12717BUILDIN_FUNC(atcommand)
12718{
12719 TBL_PC dummy_sd;
12720 TBL_PC* sd;
12721 int fd;
12722 const char* cmd;
12723
12724 cmd = script_getstr(st,2);
12725
12726 if (st->rid) {
12727 sd = script_rid2sd(st);
12728 fd = sd->fd;
12729 } else { //Use a dummy character.
12730 sd = &dummy_sd;
12731 fd = 0;
12732
12733 memset(&dummy_sd, 0, sizeof(TBL_PC));
12734 if (st->oid)
12735 {
12736 struct block_list* bl = map_id2bl(st->oid);
12737 memcpy(&dummy_sd.bl, bl, sizeof(struct block_list));
12738 if (bl->type == BL_NPC)
12739 safestrncpy(dummy_sd.status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH);
12740 }
12741 }
12742
12743 // compatibility with previous implementation (deprecated!)
12744 if(cmd[0] != atcommand_symbol)
12745 {
12746 cmd += strlen(sd->status.name);
12747 while(*cmd != atcommand_symbol && *cmd != 0)
12748 cmd++;
12749 }
12750
12751 is_atcommand(fd, sd, cmd, 0);
12752 return 0;
12753}
12754
12755BUILDIN_FUNC(charcommand)
12756{
12757 TBL_PC dummy_sd;
12758 TBL_PC* sd;
12759 int fd;
12760 const char* cmd;
12761
12762 cmd = script_getstr(st,2);
12763
12764 if (st->rid) {
12765 sd = script_rid2sd(st);
12766 fd = sd->fd;
12767 } else { //Use a dummy character.
12768 sd = &dummy_sd;
12769 fd = 0;
12770
12771 memset(&dummy_sd, 0, sizeof(TBL_PC));
12772 if (st->oid)
12773 {
12774 struct block_list* bl = map_id2bl(st->oid);
12775 memcpy(&dummy_sd.bl, bl, sizeof(struct block_list));
12776 if (bl->type == BL_NPC)
12777 safestrncpy(dummy_sd.status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH);
12778 }
12779 }
12780
12781 if (*cmd != charcommand_symbol) {
12782 ShowWarning("script: buildin_charcommand: No '#' symbol!\n");
12783 script_reportsrc(st);
12784 return 1;
12785 }
12786
12787 is_atcommand(fd, sd, cmd, 0);
12788 return 0;
12789}
12790
12791/*==========================================
12792 * Displays a message for the player only (like system messages like "you got an apple" )
12793 *------------------------------------------*/
12794BUILDIN_FUNC(dispbottom)
12795{
12796 TBL_PC *sd=script_rid2sd(st);
12797 const char *message;
12798 message=script_getstr(st,2);
12799 if(sd)
12800 clif_disp_onlyself(sd,message,(int)strlen(message));
12801 return 0;
12802}
12803
12804/*==========================================
12805 * All The Players Full Recovery
12806 * (HP/SP full restore and resurrect if need)
12807 *------------------------------------------*/
12808BUILDIN_FUNC(recovery)
12809{
12810 TBL_PC* sd;
12811 struct s_mapiterator* iter;
12812
12813 iter = mapit_getallusers();
12814 for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter) )
12815 {
12816 if(pc_isdead(sd))
12817 status_revive(&sd->bl, 100, 100);
12818 else
12819 status_percent_heal(&sd->bl, 100, 100);
12820 clif_displaymessage(sd->fd,"You have been recovered!");
12821 }
12822 mapit_free(iter);
12823 return 0;
12824}
12825/*==========================================
12826 * Get your pet info: getpetinfo(n)
12827 * n -> 0:pet_id 1:pet_class 2:pet_name
12828 * 3:friendly 4:hungry, 5: rename flag.
12829 *------------------------------------------*/
12830BUILDIN_FUNC(getpetinfo)
12831{
12832 TBL_PC *sd=script_rid2sd(st);
12833 TBL_PET *pd;
12834 int type=script_getnum(st,2);
12835
12836 if(!sd || !sd->pd) {
12837 if (type == 2)
12838 script_pushconststr(st,"null");
12839 else
12840 script_pushint(st,0);
12841 return 0;
12842 }
12843 pd = sd->pd;
12844 switch(type){
12845 case 0: script_pushint(st,pd->pet.pet_id); break;
12846 case 1: script_pushint(st,pd->pet.class_); break;
12847 case 2: script_pushstrcopy(st,pd->pet.name); break;
12848 case 3: script_pushint(st,pd->pet.intimate); break;
12849 case 4: script_pushint(st,pd->pet.hungry); break;
12850 case 5: script_pushint(st,pd->pet.rename_flag); break;
12851 default:
12852 script_pushint(st,0);
12853 break;
12854 }
12855 return 0;
12856}
12857
12858/*==========================================
12859 * Get your homunculus info: gethominfo(n)
12860 * n -> 0:hom_id 1:class 2:name
12861 * 3:friendly 4:hungry, 5: rename flag.
12862 * 6: level
12863 *------------------------------------------*/
12864BUILDIN_FUNC(gethominfo)
12865{
12866 TBL_PC *sd=script_rid2sd(st);
12867 TBL_HOM *hd;
12868 int type=script_getnum(st,2);
12869
12870 hd = sd?sd->hd:NULL;
12871 if(!merc_is_hom_active(hd))
12872 {
12873 if (type == 2)
12874 script_pushconststr(st,"null");
12875 else
12876 script_pushint(st,0);
12877 return 0;
12878 }
12879
12880 switch(type){
12881 case 0: script_pushint(st,hd->homunculus.hom_id); break;
12882 case 1: script_pushint(st,hd->homunculus.class_); break;
12883 case 2: script_pushstrcopy(st,hd->homunculus.name); break;
12884 case 3: script_pushint(st,hd->homunculus.intimacy); break;
12885 case 4: script_pushint(st,hd->homunculus.hunger); break;
12886 case 5: script_pushint(st,hd->homunculus.rename_flag); break;
12887 case 6: script_pushint(st,hd->homunculus.level); break;
12888 default:
12889 script_pushint(st,0);
12890 break;
12891 }
12892 return 0;
12893}
12894
12895/// Retrieves information about character's mercenary
12896/// getmercinfo <type>[,<char id>];
12897BUILDIN_FUNC(getmercinfo)
12898{
12899 int type, char_id;
12900 struct map_session_data* sd;
12901 struct mercenary_data* md;
12902
12903 type = script_getnum(st,2);
12904
12905 if( script_hasdata(st,3) )
12906 {
12907 char_id = script_getnum(st,3);
12908
12909 if( ( sd = map_charid2sd(char_id) ) == NULL )
12910 {
12911 ShowError("buildin_getmercinfo: No such character (char_id=%d).\n", char_id);
12912 script_pushnil(st);
12913 return 1;
12914 }
12915 }
12916 else
12917 {
12918 if( ( sd = script_rid2sd(st) ) == NULL )
12919 {
12920 script_pushnil(st);
12921 return 0;
12922 }
12923 }
12924
12925 md = ( sd->status.mer_id && sd->md ) ? sd->md : NULL;
12926
12927 switch( type )
12928 {
12929 case 0: script_pushint(st,md ? md->mercenary.mercenary_id : 0); break;
12930 case 1: script_pushint(st,md ? md->mercenary.class_ : 0); break;
12931 case 2:
12932 if( md )
12933 script_pushstrcopy(st,md->db->name);
12934 else
12935 script_pushconststr(st,"");
12936 break;
12937 case 3: script_pushint(st,md ? mercenary_get_faith(md) : 0); break;
12938 case 4: script_pushint(st,md ? mercenary_get_calls(md) : 0); break;
12939 case 5: script_pushint(st,md ? md->mercenary.kill_count : 0); break;
12940 case 6: script_pushint(st,md ? mercenary_get_lifetime(md) : 0); break;
12941 case 7: script_pushint(st,md ? md->db->lv : 0); break;
12942 default:
12943 ShowError("buildin_getmercinfo: Invalid type %d (char_id=%d).\n", type, sd->status.char_id);
12944 script_pushnil(st);
12945 return 1;
12946 }
12947
12948 return 0;
12949}
12950
12951/*==========================================
12952 * Shows wether your inventory(and equips) contain
12953 selected card or not.
12954 checkequipedcard(4001);
12955 *------------------------------------------*/
12956BUILDIN_FUNC(checkequipedcard)
12957{
12958 TBL_PC *sd=script_rid2sd(st);
12959 int n,i,c=0;
12960 c=script_getnum(st,2);
12961
12962 if(sd){
12963 for(i=0;i<MAX_INVENTORY;i++){
12964 if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount && sd->inventory_data[i]){
12965 if (itemdb_isspecial(sd->status.inventory[i].card[0]))
12966 continue;
12967 for(n=0;n<sd->inventory_data[i]->slot;n++){
12968 if(sd->status.inventory[i].card[n]==c){
12969 script_pushint(st,1);
12970 return 0;
12971 }
12972 }
12973 }
12974 }
12975 }
12976 script_pushint(st,0);
12977 return 0;
12978}
12979
12980BUILDIN_FUNC(jump_zero)
12981{
12982 int sel;
12983 sel=script_getnum(st,2);
12984 if(!sel) {
12985 int pos;
12986 if( !data_islabel(script_getdata(st,3)) ){
12987 ShowError("script: jump_zero: not label !\n");
12988 st->state=END;
12989 return 1;
12990 }
12991
12992 pos=script_getnum(st,3);
12993 st->pos=pos;
12994 st->state=GOTO;
12995 }
12996 return 0;
12997}
12998
12999/*==========================================
13000 * GetMapMobs
13001 returns mob counts on a set map:
13002 e.g. GetMapMobs("prontera")
13003 use "this" - for player's map
13004 *------------------------------------------*/
13005BUILDIN_FUNC(getmapmobs)
13006{
13007 const char *str=NULL;
13008 int m=-1,bx,by;
13009 int count=0;
13010 struct block_list *bl;
13011
13012 str=script_getstr(st,2);
13013
13014 if(strcmp(str,"this")==0){
13015 TBL_PC *sd=script_rid2sd(st);
13016 if(sd)
13017 m=sd->bl.m;
13018 else{
13019 script_pushint(st,-1);
13020 return 0;
13021 }
13022 }else
13023 m=map_mapname2mapid(str);
13024
13025 if(m < 0){
13026 script_pushint(st,-1);
13027 return 0;
13028 }
13029
13030 for(by=0;by<=(map[m].ys-1)/BLOCK_SIZE;by++)
13031 for(bx=0;bx<=(map[m].xs-1)/BLOCK_SIZE;bx++)
13032 for( bl = map[m].block_mob[bx+by*map[m].bxs] ; bl != NULL ; bl = bl->next )
13033 if(bl->x>=0 && bl->x<=map[m].xs-1 && bl->y>=0 && bl->y<=map[m].ys-1)
13034 count++;
13035
13036 script_pushint(st,count);
13037 return 0;
13038}
13039
13040/*==========================================
13041 * movenpc [MouseJstr]
13042 *------------------------------------------*/
13043BUILDIN_FUNC(movenpc)
13044{
13045 TBL_NPC *nd = NULL;
13046 const char *npc;
13047 int x,y;
13048
13049 npc = script_getstr(st,2);
13050 x = script_getnum(st,3);
13051 y = script_getnum(st,4);
13052
13053 if ((nd = npc_name2id(npc)) == NULL)
13054 return -1;
13055
13056 if (script_hasdata(st,5))
13057 nd->ud.dir = script_getnum(st,5) % 8;
13058 npc_movenpc(nd, x, y);
13059 return 0;
13060}
13061
13062/*==========================================
13063 * message [MouseJstr]
13064 *------------------------------------------*/
13065BUILDIN_FUNC(message)
13066{
13067 const char *msg,*player;
13068 TBL_PC *pl_sd = NULL;
13069
13070 player = script_getstr(st,2);
13071 msg = script_getstr(st,3);
13072
13073 if((pl_sd=map_nick2sd((char *) player)) == NULL)
13074 return 0;
13075 clif_displaymessage(pl_sd->fd, msg);
13076
13077 return 0;
13078}
13079
13080/*==========================================
13081 * npctalk (sends message to surrounding area)
13082 *------------------------------------------*/
13083BUILDIN_FUNC(npctalk)
13084{
13085 const char* str;
13086 char name[NAME_LENGTH], message[256];
13087
13088 struct npc_data* nd = (struct npc_data *)map_id2bl(st->oid);
13089 str = script_getstr(st,2);
13090
13091 if(nd)
13092 {
13093 safestrncpy(name, nd->name, sizeof(name));
13094 strtok(name, "#"); // discard extra name identifier if present
13095 safesnprintf(message, sizeof(message), "%s : %s", name, str);
13096 clif_message(&nd->bl, message);
13097 }
13098
13099 return 0;
13100}
13101
13102// change npc walkspeed [Valaris]
13103BUILDIN_FUNC(npcspeed)
13104{
13105 struct npc_data* nd;
13106 int speed;
13107
13108 speed = script_getnum(st,2);
13109 nd =(struct npc_data *)map_id2bl(st->oid);
13110
13111 if( nd )
13112 {
13113 nd->speed = speed;
13114 nd->ud.state.speed_changed = 1;
13115 }
13116
13117 return 0;
13118}
13119// make an npc walk to a position [Valaris]
13120BUILDIN_FUNC(npcwalkto)
13121{
13122 struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid);
13123 int x=0,y=0;
13124
13125 x=script_getnum(st,2);
13126 y=script_getnum(st,3);
13127
13128 if(nd) {
13129 unit_walktoxy(&nd->bl,x,y,0);
13130 }
13131
13132 return 0;
13133}
13134// stop an npc's movement [Valaris]
13135BUILDIN_FUNC(npcstop)
13136{
13137 struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid);
13138
13139 if(nd) {
13140 unit_stop_walking(&nd->bl,1|4);
13141 }
13142
13143 return 0;
13144}
13145
13146
13147/*==========================================
13148 * getlook char info. getlook(arg)
13149 *------------------------------------------*/
13150BUILDIN_FUNC(getlook)
13151{
13152 int type,val;
13153 TBL_PC *sd;
13154 sd=script_rid2sd(st);
13155
13156 type=script_getnum(st,2);
13157 val=-1;
13158 switch(type) {
13159 case LOOK_HAIR: val=sd->status.hair; break; //1
13160 case LOOK_WEAPON: val=sd->status.weapon; break; //2
13161 case LOOK_HEAD_BOTTOM: val=sd->status.head_bottom; break; //3
13162 case LOOK_HEAD_TOP: val=sd->status.head_top; break; //4
13163 case LOOK_HEAD_MID: val=sd->status.head_mid; break; //5
13164 case LOOK_HAIR_COLOR: val=sd->status.hair_color; break; //6
13165 case LOOK_CLOTHES_COLOR: val=sd->status.clothes_color; break; //7
13166 case LOOK_SHIELD: val=sd->status.shield; break; //8
13167 case LOOK_SHOES: break; //9
13168 }
13169
13170 script_pushint(st,val);
13171 return 0;
13172}
13173
13174/*==========================================
13175 * get char save point. argument: 0- map name, 1- x, 2- y
13176 *------------------------------------------*/
13177BUILDIN_FUNC(getsavepoint)
13178{
13179 TBL_PC* sd;
13180 int type;
13181
13182 sd = script_rid2sd(st);
13183 if (sd == NULL) {
13184 script_pushint(st,0);
13185 return 0;
13186 }
13187
13188 type = script_getnum(st,2);
13189
13190 switch(type) {
13191 case 0: script_pushstrcopy(st,mapindex_id2name(sd->status.save_point.map)); break;
13192 case 1: script_pushint(st,sd->status.save_point.x); break;
13193 case 2: script_pushint(st,sd->status.save_point.y); break;
13194 default:
13195 script_pushint(st,0);
13196 break;
13197 }
13198 return 0;
13199}
13200
13201/*==========================================
13202 * Get position for char/npc/pet/mob objects. Added by Lorky
13203 *
13204 * int getMapXY(MapName$,MapX,MapY,type,[CharName$]);
13205 * where type:
13206 * MapName$ - String variable for output map name
13207 * MapX - Integer variable for output coord X
13208 * MapY - Integer variable for output coord Y
13209 * type - type of object
13210 * 0 - Character coord
13211 * 1 - NPC coord
13212 * 2 - Pet coord
13213 * 3 - Mob coord (not released)
13214 * 4 - Homun coord
13215 * CharName$ - Name object. If miss or "this" the current object
13216 *
13217 * Return:
13218 * 0 - success
13219 * -1 - some error, MapName$,MapX,MapY contains unknown value.
13220 *------------------------------------------*/
13221BUILDIN_FUNC(getmapxy)
13222{
13223 struct block_list *bl = NULL;
13224 TBL_PC *sd=NULL;
13225
13226 int num;
13227 const char *name;
13228 char prefix;
13229
13230 int x,y,type;
13231 char mapname[MAP_NAME_LENGTH];
13232
13233 if( !data_isreference(script_getdata(st,2)) ){
13234 ShowWarning("script: buildin_getmapxy: not mapname variable\n");
13235 script_pushint(st,-1);
13236 return 1;
13237 }
13238 if( !data_isreference(script_getdata(st,3)) ){
13239 ShowWarning("script: buildin_getmapxy: not mapx variable\n");
13240 script_pushint(st,-1);
13241 return 1;
13242 }
13243 if( !data_isreference(script_getdata(st,4)) ){
13244 ShowWarning("script: buildin_getmapxy: not mapy variable\n");
13245 script_pushint(st,-1);
13246 return 1;
13247 }
13248
13249 // Possible needly check function parameters on C_STR,C_INT,C_INT
13250 type=script_getnum(st,5);
13251
13252 switch (type){
13253 case 0: //Get Character Position
13254 if( script_hasdata(st,6) )
13255 sd=map_nick2sd(script_getstr(st,6));
13256 else
13257 sd=script_rid2sd(st);
13258
13259 if (sd)
13260 bl = &sd->bl;
13261 break;
13262 case 1: //Get NPC Position
13263 if( script_hasdata(st,6) )
13264 {
13265 struct npc_data *nd;
13266 nd=npc_name2id(script_getstr(st,6));
13267 if (nd)
13268 bl = &nd->bl;
13269 } else //In case the origin is not an npc?
13270 bl=map_id2bl(st->oid);
13271 break;
13272 case 2: //Get Pet Position
13273 if(script_hasdata(st,6))
13274 sd=map_nick2sd(script_getstr(st,6));
13275 else
13276 sd=script_rid2sd(st);
13277
13278 if (sd && sd->pd)
13279 bl = &sd->pd->bl;
13280 break;
13281 case 3: //Get Mob Position
13282 break; //Not supported?
13283 case 4: //Get Homun Position
13284 if(script_hasdata(st,6))
13285 sd=map_nick2sd(script_getstr(st,6));
13286 else
13287 sd=script_rid2sd(st);
13288
13289 if (sd && sd->hd)
13290 bl = &sd->hd->bl;
13291 break;
13292 default:
13293 ShowWarning("script: buildin_getmapxy: Invalid type %d\n", type);
13294 script_pushint(st,-1);
13295 return 1;
13296 }
13297 if (!bl) { //No object found.
13298 script_pushint(st,-1);
13299 return 0;
13300 }
13301
13302 x= bl->x;
13303 y= bl->y;
13304 safestrncpy(mapname, map[bl->m].name, MAP_NAME_LENGTH);
13305
13306 //Set MapName$
13307 num=st->stack->stack_data[st->start+2].u.num;
13308 name=get_str(num&0x00ffffff);
13309 prefix=*name;
13310
13311 if(not_server_variable(prefix))
13312 sd=script_rid2sd(st);
13313 else
13314 sd=NULL;
13315 set_reg(st,sd,num,name,(void*)mapname,script_getref(st,2));
13316
13317 //Set MapX
13318 num=st->stack->stack_data[st->start+3].u.num;
13319 name=get_str(num&0x00ffffff);
13320 prefix=*name;
13321
13322 if(not_server_variable(prefix))
13323 sd=script_rid2sd(st);
13324 else
13325 sd=NULL;
13326 set_reg(st,sd,num,name,(void*)x,script_getref(st,3));
13327
13328 //Set MapY
13329 num=st->stack->stack_data[st->start+4].u.num;
13330 name=get_str(num&0x00ffffff);
13331 prefix=*name;
13332
13333 if(not_server_variable(prefix))
13334 sd=script_rid2sd(st);
13335 else
13336 sd=NULL;
13337 set_reg(st,sd,num,name,(void*)y,script_getref(st,4));
13338
13339 //Return Success value
13340 script_pushint(st,0);
13341 return 0;
13342}
13343
13344/*==========================================
13345 * Allows player to write NPC logs (i.e. Bank NPC, etc) [Lupus]
13346 *------------------------------------------*/
13347BUILDIN_FUNC(logmes)
13348{
13349 const char *str;
13350 TBL_PC* sd;
13351
13352 sd = script_rid2sd(st);
13353 if( sd == NULL )
13354 return 1;
13355
13356 str = script_getstr(st,2);
13357 log_npc(sd,str);
13358 return 0;
13359}
13360
13361BUILDIN_FUNC(summongroup)
13362{
13363 int _class, timeout=0;
13364 int mostrarhp = 0, i;
13365 TBL_PC *sd;
13366 struct mob_data *md;
13367 int tick = gettick();
13368
13369 sd=script_rid2sd(st);
13370 if (!sd) return 0;
13371
13372 timeout = script_getnum(st,2);
13373 mostrarhp = script_getnum(st,3);
13374 // Correccion a lmites
13375 timeout = cap_value(timeout, 5000, 600000);
13376 mostrarhp = cap_value(mostrarhp, 0, 3);
13377
13378 clif_skill_poseffect(&sd->bl,AM_CALLHOMUN,1,sd->bl.x,sd->bl.y,tick);
13379
13380 for (i = st->start + 4; i < st->end; i++) {
13381 _class = script_getnum(st,i);
13382 md = mob_once_spawn_sub(&sd->bl, sd->bl.m, sd->bl.x, sd->bl.y, "--ja--", _class, "");
13383 if (md) {
13384 md->option.is_event = true;
13385 md->option.hp_show = mostrarhp;
13386 md->master_id = sd->bl.id;
13387 // Opciones para Slave
13388 md->special_state.ai = 1;
13389 md->deletetimer = add_timer(tick+timeout,mob_timer_delete,md->bl.id,0); // El tiempo de vida del mob
13390 mob_spawn (md); // Listo para mostrar el mob
13391 clif_misceffect(&md->bl,344);
13392 sc_start4(&md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, timeout);
13393 }
13394 }
13395 return 0;
13396}
13397
13398BUILDIN_FUNC(summonspecial)
13399{
13400 int _class, timeout=0, hpmas=0, mostrarhp=0;
13401 const char *str,*event="";
13402 TBL_PC *sd;
13403 struct mob_data *md;
13404 int tick = gettick();
13405
13406 sd=script_rid2sd(st);
13407 if (sd == NULL) return 0; // La sesion del Player al que va a pertenecer el mob
13408
13409 str = script_getstr(st,2); // el Nombre del Mob Custom
13410 _class = script_getnum(st,3); // La clase del Mob a Summonear
13411 hpmas = script_getnum(st,4); // El aumento o disminucin de HP
13412 hpmas = cap_value(hpmas, -5000000, 10000000);
13413 timeout = script_getnum(st,5); // El tiempo de Vida del Mob en Milisegundos
13414 timeout = cap_value(timeout, 5000, 600000);
13415 mostrarhp = script_getnum(st,6); // Variable para mostrar el HP del mob o no
13416 mostrarhp = cap_value(mostrarhp, 0, 3);
13417
13418 if( script_hasdata(st,7) )
13419 { // El evento de cuando el Summon Muera
13420 event=script_getstr(st,7);
13421 check_event(st, event);
13422 }
13423
13424 md = mob_once_spawn_sub(&sd->bl, sd->bl.m, sd->bl.x, sd->bl.y, str, _class, event);
13425 if (md) {
13426 md->master_id = sd->bl.id;
13427 md->special_state.ai = 1;
13428 md->deletetimer = add_timer(tick+timeout,mob_timer_delete,md->bl.id,0);
13429
13430 md->option.is_event = true;
13431 md->option.no_expdrop = true;
13432 md->status.hp += hpmas;
13433 md->status.max_hp += hpmas; // Aumenta el Lmite del Maximo de HP [Zephyrus]
13434 if (md->status.hp <= 0) md->status.hp = 10; // No permite mob con HP 0 o negativo
13435 md->option.hp_show = mostrarhp;
13436 // *******************
13437 mob_spawn (md); //Now it is ready for spawning.
13438 clif_misceffect(&md->bl,344);
13439 sc_start4(&md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, timeout);
13440 }
13441 return 0;
13442}
13443
13444BUILDIN_FUNC(summon)
13445{
13446 int _class, timeout=0;
13447 const char *str,*event="";
13448 TBL_PC *sd;
13449 struct mob_data *md;
13450 int tick = gettick();
13451
13452 sd=script_rid2sd(st);
13453 if (!sd) return 0;
13454
13455 str =script_getstr(st,2);
13456 _class=script_getnum(st,3);
13457 if( script_hasdata(st,4) )
13458 timeout=script_getnum(st,4);
13459 if( script_hasdata(st,5) ){
13460 event=script_getstr(st,5);
13461 check_event(st, event);
13462 }
13463
13464 clif_skill_poseffect(&sd->bl,AM_CALLHOMUN,1,sd->bl.x,sd->bl.y,tick);
13465
13466 md = mob_once_spawn_sub(&sd->bl, sd->bl.m, sd->bl.x, sd->bl.y, str, _class, event);
13467 if (md) {
13468 md->master_id=sd->bl.id;
13469 md->special_state.ai=1;
13470 if( md->deletetimer != INVALID_TIMER )
13471 delete_timer(md->deletetimer, mob_timer_delete);
13472 md->deletetimer = add_timer(tick+(timeout>0?timeout*1000:60000),mob_timer_delete,md->bl.id,0);
13473 mob_spawn (md); //Now it is ready for spawning.
13474 clif_specialeffect(&md->bl,344,AREA);
13475 sc_start4(&md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, 60000);
13476 }
13477 return 0;
13478}
13479
13480/*==========================================
13481 * Checks whether it is daytime/nighttime
13482 *------------------------------------------*/
13483BUILDIN_FUNC(isnight)
13484{
13485 script_pushint(st,(night_flag == 1));
13486 return 0;
13487}
13488
13489BUILDIN_FUNC(isday)
13490{
13491 script_pushint(st,(night_flag == 0));
13492 return 0;
13493}
13494
13495/*================================================
13496 * Check how many items/cards in the list are
13497 * equipped - used for 2/15's cards patch [celest]
13498 *------------------------------------------------*/
13499BUILDIN_FUNC(isequippedcnt)
13500{
13501 TBL_PC *sd;
13502 int i, j, k, id = 1;
13503 int ret = 0;
13504
13505 sd = script_rid2sd(st);
13506 if (!sd) { //If the player is not attached it is a script error anyway... but better prevent the map server from crashing...
13507 script_pushint(st,0);
13508 return 0;
13509 }
13510
13511 for (i=0; id!=0; i++) {
13512 FETCH (i+2, id) else id = 0;
13513 if (id <= 0)
13514 continue;
13515
13516 for (j=0; j<EQI_MAX; j++) {
13517 int index;
13518 index = sd->equip_index[j];
13519 if(index < 0) continue;
13520 if(j == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == index) continue;
13521 if(j == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == index) continue;
13522 if(j == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == index || sd->equip_index[EQI_HEAD_LOW] == index)) continue;
13523
13524 if(!sd->inventory_data[index])
13525 continue;
13526
13527 if (itemdb_type(id) != IT_CARD) { //No card. Count amount in inventory.
13528 if (sd->inventory_data[index]->nameid == id)
13529 ret+= sd->status.inventory[index].amount;
13530 } else { //Count cards.
13531 if (itemdb_isspecial(sd->status.inventory[index].card[0]))
13532 continue; //No cards
13533 for(k=0; k<sd->inventory_data[index]->slot; k++) {
13534 if (sd->status.inventory[index].card[k] == id)
13535 ret++; //[Lupus]
13536 }
13537 }
13538 }
13539 }
13540
13541 script_pushint(st,ret);
13542 return 0;
13543}
13544
13545/*================================================
13546 * Check whether another card has been
13547 * equipped - used for 2/15's cards patch [celest]
13548 * -- Items checked cannot be reused in another
13549 * card set to prevent exploits
13550 *------------------------------------------------*/
13551BUILDIN_FUNC(isequipped)
13552{
13553 TBL_PC *sd;
13554 int i, j, k, id = 1;
13555 int index, flag;
13556 int ret = -1;
13557 //Original hash to reverse it when full check fails.
13558 unsigned int setitem_hash = 0, setitem_hash2 = 0;
13559
13560 sd = script_rid2sd(st);
13561
13562 if (!sd) { //If the player is not attached it is a script error anyway... but better prevent the map server from crashing...
13563 script_pushint(st,0);
13564 return 0;
13565 }
13566
13567 setitem_hash = sd->setitem_hash;
13568 setitem_hash2 = sd->setitem_hash2;
13569 for (i=0; id!=0; i++)
13570 {
13571 FETCH (i+2, id) else id = 0;
13572 if (id <= 0)
13573 continue;
13574 flag = 0;
13575 for (j=0; j<EQI_MAX; j++)
13576 {
13577 index = sd->equip_index[j];
13578 if(index < 0) continue;
13579 if(j == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == index) continue;
13580 if(j == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == index) continue;
13581 if(j == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == index || sd->equip_index[EQI_HEAD_LOW] == index)) continue;
13582
13583 if(!sd->inventory_data[index])
13584 continue;
13585
13586 if (itemdb_type(id) != IT_CARD) {
13587 if (sd->inventory_data[index]->nameid != id)
13588 continue;
13589 flag = 1;
13590 break;
13591 } else { //Cards
13592 if (sd->inventory_data[index]->slot == 0 ||
13593 itemdb_isspecial(sd->status.inventory[index].card[0]))
13594 continue;
13595
13596 for (k = 0; k < sd->inventory_data[index]->slot; k++)
13597 { //New hash system which should support up to 4 slots on any equipment. [Skotlex]
13598 unsigned int hash = 0;
13599 if (sd->status.inventory[index].card[k] != id)
13600 continue;
13601
13602 hash = 1<<((j<5?j:j-5)*4 + k);
13603 // check if card is already used by another set
13604 if ((j<5?sd->setitem_hash:sd->setitem_hash2) & hash)
13605 continue;
13606
13607 // We have found a match
13608 flag = 1;
13609 // Set hash so this card cannot be used by another
13610 if (j<5)
13611 sd->setitem_hash |= hash;
13612 else
13613 sd->setitem_hash2 |= hash;
13614 break;
13615 }
13616 }
13617 if (flag) break; //Card found
13618 }
13619 if (ret == -1)
13620 ret = flag;
13621 else
13622 ret &= flag;
13623 if (!ret) break;
13624 }
13625 if (!ret)
13626 { //When check fails, restore original hash values. [Skotlex]
13627 sd->setitem_hash = setitem_hash;
13628 sd->setitem_hash2 = setitem_hash2;
13629 }
13630 script_pushint(st,ret);
13631 return 0;
13632}
13633
13634/*================================================
13635 * Check how many given inserted cards in the CURRENT
13636 * weapon - used for 2/15's cards patch [Lupus]
13637 *------------------------------------------------*/
13638BUILDIN_FUNC(cardscnt)
13639{
13640 TBL_PC *sd;
13641 int i, k, id = 1;
13642 int ret = 0;
13643 int index;
13644
13645 sd = script_rid2sd(st);
13646
13647 for (i=0; id!=0; i++) {
13648 FETCH (i+2, id) else id = 0;
13649 if (id <= 0)
13650 continue;
13651
13652 index = current_equip_item_index; //we get CURRENT WEAPON inventory index from status.c [Lupus]
13653 if(index < 0) continue;
13654
13655 if(!sd->inventory_data[index])
13656 continue;
13657
13658 if(itemdb_type(id) != IT_CARD) {
13659 if (sd->inventory_data[index]->nameid == id)
13660 ret+= sd->status.inventory[index].amount;
13661 } else {
13662 if (itemdb_isspecial(sd->status.inventory[index].card[0]))
13663 continue;
13664 for(k=0; k<sd->inventory_data[index]->slot; k++) {
13665 if (sd->status.inventory[index].card[k] == id)
13666 ret++;
13667 }
13668 }
13669 }
13670 script_pushint(st,ret);
13671// script_pushint(st,current_equip_item_index);
13672 return 0;
13673}
13674
13675/*=======================================================
13676 * Returns the refined number of the current item, or an
13677 * item with inventory index specified
13678 *-------------------------------------------------------*/
13679BUILDIN_FUNC(getrefine)
13680{
13681 TBL_PC *sd;
13682 if ((sd = script_rid2sd(st))!= NULL)
13683 script_pushint(st,sd->status.inventory[current_equip_item_index].refine);
13684 else
13685 script_pushint(st,0);
13686 return 0;
13687}
13688
13689/*=======================================================
13690 * Day/Night controls
13691 *-------------------------------------------------------*/
13692BUILDIN_FUNC(night)
13693{
13694 if (night_flag != 1) map_night_timer(night_timer_tid, 0, 0, 1);
13695 return 0;
13696}
13697BUILDIN_FUNC(day)
13698{
13699 if (night_flag != 0) map_day_timer(day_timer_tid, 0, 0, 1);
13700 return 0;
13701}
13702
13703//=======================================================
13704// Unequip [Spectre]
13705//-------------------------------------------------------
13706BUILDIN_FUNC(unequip)
13707{
13708 int i;
13709 size_t num;
13710 TBL_PC *sd;
13711
13712 num = script_getnum(st,2);
13713 sd = script_rid2sd(st);
13714 if( sd != NULL && num >= 1 && num <= ARRAYLENGTH(equip) )
13715 {
13716 i = pc_checkequip(sd,equip[num-1]);
13717 if (i >= 0)
13718 pc_unequipitem(sd,i,1|2);
13719 }
13720 return 0;
13721}
13722
13723BUILDIN_FUNC(equip)
13724{
13725 int nameid=0,i;
13726 TBL_PC *sd;
13727 struct item_data *item_data;
13728
13729 sd = script_rid2sd(st);
13730
13731 nameid=script_getnum(st,2);
13732 if((item_data = itemdb_exists(nameid)) == NULL)
13733 {
13734 ShowError("wrong item ID : equipitem(%i)\n",nameid);
13735 return 1;
13736 }
13737 ARR_FIND( 0, MAX_INVENTORY, i, sd->status.inventory[i].nameid == nameid );
13738 if( i < MAX_INVENTORY )
13739 pc_equipitem(sd,i,item_data->equip);
13740
13741 return 0;
13742}
13743
13744BUILDIN_FUNC(setbattleflag)
13745{
13746 const char *flag, *value;
13747
13748 flag = script_getstr(st,2);
13749 value = script_getstr(st,3); // HACK: Retrieve number as string (auto-converted) for battle_set_value
13750
13751 if (battle_set_value(flag, value) == 0)
13752 ShowWarning("buildin_setbattleflag: unknown battle_config flag '%s'\n",flag);
13753 else
13754 ShowInfo("buildin_setbattleflag: battle_config flag '%s' is now set to '%s'.\n",flag,value);
13755
13756 return 0;
13757}
13758
13759BUILDIN_FUNC(getbattleflag)
13760{
13761 const char *flag;
13762 flag = script_getstr(st,2);
13763 script_pushint(st,battle_get_value(flag));
13764 return 0;
13765}
13766
13767//=======================================================
13768// strlen [Valaris]
13769//-------------------------------------------------------
13770BUILDIN_FUNC(getstrlen)
13771{
13772
13773 const char *str = script_getstr(st,2);
13774 int len = (int)strlen(str);
13775
13776 script_pushint(st,len);
13777 return 0;
13778}
13779
13780//=======================================================
13781// isalpha [Valaris]
13782//-------------------------------------------------------
13783BUILDIN_FUNC(charisalpha)
13784{
13785 const char *str=script_getstr(st,2);
13786 int pos=script_getnum(st,3);
13787
13788 int val = ( pos >= 0 && (unsigned int)pos < strlen(str) && ISALPHA(str[pos]) )? 1: 0;
13789
13790 script_pushint(st,val);
13791 return 0;
13792}
13793
13794//=======================================================
13795// charisupper <str>, <index>
13796//-------------------------------------------------------
13797BUILDIN_FUNC(charisupper)
13798{
13799 const char *str = script_getstr(st,2);
13800 int pos = script_getnum(st,3);
13801
13802 int val = ( pos >= 0 && (unsigned int)pos < strlen(str) && ISUPPER(str[pos]) )? 1: 0;
13803
13804 script_pushint(st,val);
13805 return 0;
13806}
13807
13808//=======================================================
13809// charislower <str>, <index>
13810//-------------------------------------------------------
13811BUILDIN_FUNC(charislower)
13812{
13813 const char *str = script_getstr(st,2);
13814 int pos = script_getnum(st,3);
13815
13816 int val = ( pos >= 0 && (unsigned int)pos < strlen(str) && ISLOWER(str[pos]) )? 1: 0;
13817
13818 script_pushint(st,val);
13819 return 0;
13820}
13821//=======================================================
13822// charat <str>, <index>
13823//-------------------------------------------------------
13824BUILDIN_FUNC(charat)
13825{
13826 const char *str = script_getstr(st,2);
13827 int pos = script_getnum(st,3);
13828
13829 if( pos >= 0 && (unsigned int)pos < strlen(str) )
13830 {
13831 char output[2];
13832 output[0] = str[pos];
13833 output[1] = '\0';
13834 script_pushstrcopy(st, output);
13835 }
13836 else
13837 {
13838 script_pushconststr(st, "");
13839 }
13840
13841 return 0;
13842}
13843
13844//=======================================================
13845// setchar <string>, <char>, <index>
13846//-------------------------------------------------------
13847BUILDIN_FUNC(setchar)
13848{
13849 const char *str = script_getstr(st,2);
13850 const char *c = script_getstr(st,3);
13851 int index = script_getnum(st,4);
13852 char *output = aStrdup(str);
13853
13854 if( index >= 0 && (unsigned int)index < strlen(output) )
13855 output[index] = *c;
13856
13857 script_pushstr(st, output);
13858 return 0;
13859}
13860
13861//=======================================================
13862// insertchar <string>, <char>, <index>
13863//-------------------------------------------------------
13864BUILDIN_FUNC(insertchar)
13865{
13866 const char *str = script_getstr(st,2);
13867 const char *c = script_getstr(st,3);
13868 int index = script_getnum(st,4);
13869 char *output;
13870 size_t len = strlen(str);
13871
13872 if(index < 0)
13873 index = 0;
13874 else if(index > len)
13875 index = len;
13876
13877 output = (char*)aMalloc(len + 2);
13878
13879 memcpy(output, str, index);
13880 output[index] = c[0];
13881 memcpy(&output[index+1], &str[index], len - index);
13882 output[len+1] = '\0';
13883
13884 script_pushstr(st, output);
13885 return 0;
13886}
13887
13888//=======================================================
13889// delchar <string>, <index>
13890//-------------------------------------------------------
13891BUILDIN_FUNC(delchar)
13892{
13893 const char *str = script_getstr(st,2);
13894 int index = script_getnum(st,3);
13895 char *output;
13896 size_t len = strlen(str);
13897
13898 if( index < 0 || index >= len )
13899 { // no change
13900 script_pushstrcopy(st, str);
13901 return 0;
13902 }
13903
13904 output = (char*)aMalloc(len);
13905
13906 memcpy(output, str, index);
13907 memcpy(&output[index], &str[index+1], len - index);
13908
13909 script_pushstr(st, output);
13910 return 0;
13911}
13912
13913//=======================================================
13914// strtoupper <str>
13915//-------------------------------------------------------
13916BUILDIN_FUNC(strtoupper)
13917{
13918 const char *str = script_getstr(st,2);
13919 char *output = aStrdup(str);
13920 char *cursor = output;
13921
13922 while (*cursor != '\0') {
13923 *cursor = TOUPPER(*cursor);
13924 cursor++;
13925 }
13926
13927 script_pushstr(st, output);
13928 return 0;
13929}
13930
13931//=======================================================
13932// strtolower <str>
13933//-------------------------------------------------------
13934BUILDIN_FUNC(strtolower)
13935{
13936 const char *str = script_getstr(st,2);
13937 char *output = aStrdup(str);
13938 char *cursor = output;
13939
13940 while (*cursor != '\0') {
13941 *cursor = TOLOWER(*cursor);
13942 cursor++;
13943 }
13944
13945 script_pushstr(st, output);
13946 return 0;
13947}
13948//=======================================================
13949// substr <str>, <start>, <end>
13950//-------------------------------------------------------
13951BUILDIN_FUNC(substr)
13952{
13953 const char *str = script_getstr(st,2);
13954 int start = script_getnum(st,3);
13955 int end = script_getnum(st,4);
13956
13957 if( start >= 0 && start <= end && (unsigned int)end < strlen(str) )
13958 {
13959 int len = end + 1 - start;
13960 char* output = (char*)aMalloc(len + 1);
13961 memcpy(output, &str[start], len);
13962 output[len] = '\0';
13963 script_pushstr(st, output);
13964 }
13965 else
13966 {
13967 script_pushconststr(st, "");
13968 }
13969
13970 return 0;
13971}
13972
13973//=======================================================
13974// explode <dest_string_array>, <str>, <delimiter>
13975// Note: delimiter is limited to 1 char
13976//-------------------------------------------------------
13977BUILDIN_FUNC(explode)
13978{
13979 struct script_data* data = script_getdata(st, 2);
13980 const char *str = script_getstr(st,3);
13981 const char delimiter = script_getstr(st, 4)[0];
13982 int32 id;
13983 size_t len = strlen(str);
13984 int i = 0, j = 0;
13985 int index;
13986
13987 char *temp;
13988 const char* name;
13989
13990 TBL_PC* sd = NULL;
13991
13992 if( !data_isreference(data) )
13993 {
13994 ShowError("script:explode: not a variable\n");
13995 script_reportdata(data);
13996 st->state = END;
13997 return 1;// not a variable
13998 }
13999
14000 id = reference_getid(data);
14001 index = reference_getindex(data);
14002 name = reference_getname(data);
14003
14004 if( not_array_variable(*name) )
14005 {
14006 ShowError("script:explode: illegal scope\n");
14007 script_reportdata(data);
14008 st->state = END;
14009 return 1;// not supported
14010 }
14011
14012 if( !is_string_variable(name) )
14013 {
14014 ShowError("script:explode: not string array\n");
14015 script_reportdata(data);
14016 st->state = END;
14017 return 1;// data type mismatch
14018 }
14019
14020 if( not_server_variable(*name) )
14021 {
14022 sd = script_rid2sd(st);
14023 if( sd == NULL )
14024 return 0;// no player attached
14025 }
14026
14027 temp = (char*)aMalloc(len + 1);
14028
14029 for( i = 0, j = 0; i < len; ++i )
14030 {
14031 if( index < SCRIPT_MAX_ARRAYSIZE-1 && str[i] == delimiter )
14032 { // break string at delimiter while there is space in the array
14033 temp[j] = '\0';
14034 set_reg(st, sd, reference_uid(id, index), name, (void*)temp, reference_getref(data));
14035 ++index;
14036 j = 0;
14037 }
14038 else
14039 {
14040 temp[j] = str[i];
14041 ++j;
14042 }
14043 }
14044 //set last string
14045 temp[j] = '\0';
14046 set_reg(st, sd, reference_uid(id, index), name, (void*)temp, reference_getref(data));
14047
14048 aFree(temp);
14049 return 0;
14050}
14051//=======================================================
14052// implode <string_array>
14053// implode <string_array>, <glue>
14054//-------------------------------------------------------
14055BUILDIN_FUNC(implode)
14056{
14057 struct script_data* data = script_getdata(st, 2);
14058 const char* name;
14059 int32 array_size, id;
14060
14061 TBL_PC* sd = NULL;
14062
14063 if( !data_isreference(data) )
14064 {
14065 ShowError("script:implode: not a variable\n");
14066 script_reportdata(data);
14067 st->state = END;
14068 return 1;// not a variable
14069 }
14070
14071 id = reference_getid(data);
14072 name = reference_getname(data);
14073
14074 if( not_array_variable(*name) )
14075 {
14076 ShowError("script:implode: illegal scope\n");
14077 script_reportdata(data);
14078 st->state = END;
14079 return 1;// not supported
14080 }
14081
14082 if( !is_string_variable(name) )
14083 {
14084 ShowError("script:implode: not string array\n");
14085 script_reportdata(data);
14086 st->state = END;
14087 return 1;// data type mismatch
14088 }
14089
14090 if( not_server_variable(*name) )
14091 {
14092 sd = script_rid2sd(st);
14093 if( sd == NULL )
14094 return 0;// no player attached
14095 }
14096
14097 //count chars
14098 array_size = getarraysize(st, id, reference_getindex(data), is_string_variable(name), reference_getref(data));
14099
14100 if( array_size < 0 || array_size >= SCRIPT_MAX_ARRAYSIZE )
14101 {
14102 ShowError("script:implode: invalid array length = %d\n", array_size);
14103 script_reportdata(data);
14104 st->state = END;
14105 return -1;
14106 }
14107
14108 if( array_size == 0 ) //empty array check (AmsTaff)
14109 {
14110 ShowWarning("script:implode: array length = 0\n");
14111 script_reportdata(data);
14112 script_reportsrc(st);
14113 script_pushconststr(st, "NULL"); // XXX why return "NULL" for an empty array? [flaviojs]
14114 }
14115 else
14116 {
14117 const char* str[SCRIPT_MAX_ARRAYSIZE];
14118 size_t len[SCRIPT_MAX_ARRAYSIZE];
14119 size_t total_len = 0;
14120 const char* glue = "";
14121 size_t glue_len = 0;
14122 char *output;
14123 int i, k;
14124
14125 // parse data
14126 for( i = 0; i < array_size; ++i )
14127 {
14128 str[i] = (const char*)get_val2(st, reference_uid(id, i), reference_getref(data)); // leave string data in the stack
14129 len[i] = strlen(str[i]);
14130 total_len += len[i];
14131 }
14132
14133 if( script_hasdata(st,3) )
14134 {
14135 glue = script_getstr(st,3);
14136 glue_len = strlen(glue);
14137 total_len += glue_len * (array_size - 1);
14138 }
14139
14140 //build output
14141 output = (char*)aMalloc(total_len + 1);
14142 for( i = 0, k = 0; i < array_size; ++i )
14143 {
14144 memcpy(&output[k], str[i], len[i]);
14145 k += len[i];
14146 if( glue_len > 0 && i < array_size - 1 )
14147 {
14148 memcpy(&output[k], glue, glue_len);
14149 k += glue_len;
14150 }
14151 }
14152 output[k] = '\0';
14153 script_removetop(st, -array_size, 0); // clear string data in the stack
14154
14155 script_pushstr(st, output);
14156 }
14157
14158 return 0;
14159}
14160
14161//=======================================================
14162// sprintf(<format>, ...);
14163// Implements C sprintf, except format %n. The resulting string is
14164// returned, instead of being saved in variable by reference.
14165//-------------------------------------------------------
14166BUILDIN_FUNC(sprintf)
14167{
14168 unsigned int len, argc = 0, arg = 0, buf2_len = 0;
14169 const char* format;
14170 char* p;
14171 char* q;
14172 char* buf = NULL;
14173 char* buf2 = NULL;
14174 struct script_data* data;
14175 StringBuf final_buf;
14176
14177 // Fetch init data
14178 format = script_getstr(st, 2);
14179 argc = script_lastdata(st)-2;
14180 len = strlen(format);
14181
14182 // Skip parsing, where no parsing is required.
14183 if(len==0){
14184 script_pushconststr(st,"");
14185 return 0;
14186 }
14187
14188 // Pessimistic alloc
14189 CREATE(buf, char, len+1);
14190
14191 // Need not be parsed, just solve stuff like %%.
14192 if(argc==0){
14193 sprintf(buf, format);
14194 script_pushstrcopy(st, buf);
14195 aFree(buf);
14196 return 0;
14197 }
14198
14199 safestrncpy(buf, format, len+1);
14200
14201 // Issue sprintf for each parameter
14202 StringBuf_Init(&final_buf);
14203 q = buf;
14204 while((p = strchr(q, '%'))!=NULL){
14205 if(p!=q){
14206 len = p-q+1;
14207 if(buf2_len<len){
14208 RECREATE(buf2, char, len);
14209 buf2_len = len;
14210 }
14211 safestrncpy(buf2, q, len);
14212 StringBuf_AppendStr(&final_buf, buf2);
14213 q = p;
14214 }
14215 p = q+1;
14216 if(*p=='%'){ // %%
14217 StringBuf_AppendStr(&final_buf, "%");
14218 q+=2;
14219 continue;
14220 }
14221 if(*p=='n'){ // %n
14222 ShowWarning("buildin_sprintf: Format %%n not supported! Skipping...\n");
14223 script_reportsrc(st);
14224 q+=2;
14225 continue;
14226 }
14227 if(arg>=argc){
14228 ShowError("buildin_sprintf: Not enough arguments passed!\n");
14229 if(buf) aFree(buf);
14230 if(buf2) aFree(buf2);
14231 StringBuf_Destroy(&final_buf);
14232 script_pushconststr(st,"");
14233 return 1;
14234 }
14235 if((p = strchr(q+1, '%'))==NULL){
14236 p = strchr(q, 0); // EOS
14237 }
14238 len = p-q+1;
14239 if(buf2_len<len){
14240 RECREATE(buf2, char, len);
14241 buf2_len = len;
14242 }
14243 safestrncpy(buf2, q, len);
14244 q = p;
14245
14246 // Note: This assumes the passed value being the correct
14247 // type to the current format specifier. If not, the server
14248 // probably crashes or returns anything else, than expected,
14249 // but it would behave in normal code the same way so it's
14250 // the scripter's responsibility.
14251 data = script_getdata(st, arg+3);
14252 if(data_isstring(data)){ // String
14253 StringBuf_Printf(&final_buf, buf2, script_getstr(st, arg+3));
14254 }else if(data_isint(data)){ // Number
14255 StringBuf_Printf(&final_buf, buf2, script_getnum(st, arg+3));
14256 }else if(data_isreference(data)){ // Variable
14257 char* name = reference_getname(data);
14258 if(name[strlen(name)-1]=='$'){ // var Str
14259 StringBuf_Printf(&final_buf, buf2, script_getstr(st, arg+3));
14260 }else{ // var Int
14261 StringBuf_Printf(&final_buf, buf2, script_getnum(st, arg+3));
14262 }
14263 }else{ // Unsupported type
14264 ShowError("buildin_sprintf: Unknown argument type!\n");
14265 if(buf) aFree(buf);
14266 if(buf2) aFree(buf2);
14267 StringBuf_Destroy(&final_buf);
14268 script_pushconststr(st,"");
14269 return 1;
14270 }
14271 arg++;
14272 }
14273
14274 // Append anything left
14275 if(*q){
14276 StringBuf_AppendStr(&final_buf, q);
14277 }
14278
14279 // Passed more, than needed
14280 if(arg<argc){
14281 ShowWarning("buildin_sprintf: Unused arguments passed.\n");
14282 script_reportsrc(st);
14283 }
14284
14285 script_pushstrcopy(st, StringBuf_Value(&final_buf));
14286
14287 if(buf) aFree(buf);
14288 if(buf2) aFree(buf2);
14289 StringBuf_Destroy(&final_buf);
14290
14291 return 0;
14292}
14293
14294//=======================================================
14295// sscanf(<str>, <format>, ...);
14296// Implements C sscanf.
14297//-------------------------------------------------------
14298BUILDIN_FUNC(sscanf){
14299 unsigned int argc, arg = 0, len;
14300 struct script_data* data;
14301 struct map_session_data* sd = NULL;
14302 const char* str;
14303 const char* format;
14304 const char* p;
14305 const char* q;
14306 char* buf = NULL;
14307 char* buf_p;
14308 char* ref_str = NULL;
14309 int ref_int;
14310
14311 // Get data
14312 str = script_getstr(st, 2);
14313 format = script_getstr(st, 3);
14314 argc = script_lastdata(st)-3;
14315
14316 len = strlen(format);
14317 CREATE(buf, char, len*2+1);
14318
14319 // Issue sscanf for each parameter
14320 *buf = 0;
14321 q = format;
14322 while(p = strchr(q, '%')){
14323 if(p!=q){
14324 strncat(buf, q, (size_t)(p-q));
14325 q = p;
14326 }
14327 p = q+1;
14328 if(*p=='*' || *p=='%'){ // Skip
14329 strncat(buf, q, 2);
14330 q+=2;
14331 continue;
14332 }
14333 if(arg>=argc){
14334 ShowError("buildin_sscanf: Not enough arguments passed!\n");
14335 script_pushint(st, -1);
14336 if(buf) aFree(buf);
14337 if(ref_str) aFree(ref_str);
14338 return 1;
14339 }
14340 if((p = strchr(q+1, '%'))==NULL){
14341 p = strchr(q, 0); // EOS
14342 }
14343 len = p-q;
14344 strncat(buf, q, len);
14345 q = p;
14346
14347 // Validate output
14348 data = script_getdata(st, arg+4);
14349 if(!data_isreference(data) || !reference_tovariable(data)){
14350 ShowError("buildin_sscanf: Target argument is not a variable!\n");
14351 script_pushint(st, -1);
14352 if(buf) aFree(buf);
14353 if(ref_str) aFree(ref_str);
14354 return 1;
14355 }
14356 buf_p = reference_getname(data);
14357 if(not_server_variable(*buf_p) && (sd = script_rid2sd(st))==NULL){
14358 script_pushint(st, -1);
14359 if(buf) aFree(buf);
14360 if(ref_str) aFree(ref_str);
14361 return 0;
14362 }
14363
14364 // Save value if any
14365 if(buf_p[strlen(buf_p)-1]=='$'){ // String
14366 if(ref_str==NULL){
14367 CREATE(ref_str, char, strlen(str)+1);
14368 }
14369 if(sscanf(str, buf, ref_str)==0){
14370 break;
14371 }
14372 set_reg(st, sd, add_str(buf_p), buf_p, (void *)(ref_str), reference_getref(data));
14373 }else{ // Number
14374 if(sscanf(str, buf, &ref_int)==0){
14375 break;
14376 }
14377 set_reg(st, sd, add_str(buf_p), buf_p, (void *)(ref_int), reference_getref(data));
14378 }
14379 arg++;
14380
14381 // Disable used format (%... -> %*...)
14382 buf_p = strchr(buf, 0);
14383 memmove(buf_p-len+2, buf_p-len+1, len);
14384 *(buf_p-len+1) = '*';
14385 }
14386
14387 // Passed more, than needed
14388 if(arg<argc){
14389 ShowWarning("buildin_sscanf: Unused arguments passed.\n");
14390 script_reportsrc(st);
14391 }
14392
14393 script_pushint(st, arg);
14394 if(buf) aFree(buf);
14395 if(ref_str) aFree(ref_str);
14396
14397 return 0;
14398}
14399
14400//=======================================================
14401// strpos(<haystack>, <needle>)
14402// strpos(<haystack>, <needle>, <offset>)
14403//
14404// Implements PHP style strpos. Adapted from code from
14405// http://www.daniweb.com/code/snippet313.html, Dave Sinkula
14406//-------------------------------------------------------
14407BUILDIN_FUNC(strpos) {
14408 const char *haystack = script_getstr(st,2);
14409 const char *needle = script_getstr(st,3);
14410 int i;
14411 size_t len;
14412
14413 if( script_hasdata(st,4) )
14414 i = script_getnum(st,4);
14415 else
14416 i = 0;
14417
14418 if ( strlen(needle) == 0 ) {
14419 script_pushint(st, -1);
14420 return 0;
14421 }
14422
14423 len = strlen(haystack);
14424 for ( ; i < len; ++i ) {
14425 if ( haystack[i] == *needle ) {
14426 // matched starting char -- loop through remaining chars
14427 const char *h, *n;
14428 for ( h = &haystack[i], n = needle; *h && *n; ++h, ++n ) {
14429 if ( *h != *n ) {
14430 break;
14431 }
14432 }
14433 if ( !*n ) { // matched all of 'needle' to null termination
14434 script_pushint(st, i);
14435 return 0;
14436 }
14437 }
14438 }
14439 script_pushint(st, -1);
14440 return 0;
14441}
14442
14443//===============================================================
14444// replacestr <input>, <search>, <replace>{, <usecase>{, <count>}}
14445//
14446// Note: Finds all instances of <search> in <input> and replaces
14447// with <replace>. If specified will only replace as many
14448// instances as specified in <count>. By default will be case
14449// sensitive.
14450//---------------------------------------------------------------
14451BUILDIN_FUNC(replacestr)
14452{
14453 const char *input = script_getstr(st, 2);
14454 const char *find = script_getstr(st, 3);
14455 const char *replace = script_getstr(st, 4);
14456 size_t inputlen = strlen(input);
14457 size_t findlen = strlen(find);
14458 struct StringBuf output;
14459 bool usecase = true;
14460
14461 int count = 0;
14462 int numFinds = 0;
14463 int i = 0, f = 0;
14464
14465 if(findlen == 0) {
14466 ShowError("script:replacestr: Invalid search length.\n");
14467 st->state = END;
14468 return 1;
14469 }
14470
14471 if(script_hasdata(st, 5)) {
14472 if(script_isint(st,5))
14473 usecase = script_getnum(st, 5) != 0;
14474 else {
14475 ShowError("script:replacestr: Invalid usecase value. Expected int got string\n");
14476 st->state = END;
14477 return 1;
14478 }
14479 }
14480
14481 if(script_hasdata(st, 6)) {
14482 if(script_isint(st,6))
14483 count = script_getnum(st, 6);
14484 else {
14485 ShowError("script:replacestr: Invalid count value. Expected int got string\n");
14486 st->state = END;
14487 return 1;
14488 }
14489 }
14490
14491 StringBuf_Init(&output);
14492
14493 for(; i < inputlen; i++) {
14494 if(count && count == numFinds) { //found enough, stop looking
14495 break;
14496 }
14497
14498 for(f = 0; f <= findlen; f++) {
14499 if(f == findlen) { //complete match
14500 numFinds++;
14501 StringBuf_AppendStr(&output, replace);
14502
14503 i += findlen - 1;
14504 break;
14505 } else {
14506 if(usecase) {
14507 if((i + f) > inputlen || input[i + f] != find[f]) {
14508 StringBuf_Printf(&output, "%c", input[i]);
14509 break;
14510 }
14511 } else {
14512 if((i + f) > inputlen || input[i + f] != find[f] && TOUPPER(input[i+f]) != TOUPPER(find[f])) {
14513 StringBuf_Printf(&output, "%c", input[i]);
14514 break;
14515 }
14516 }
14517 }
14518 }
14519 }
14520
14521 //append excess after enough found
14522 if(i < inputlen)
14523 StringBuf_AppendStr(&output, &(input[i]));
14524
14525 script_pushstrcopy(st, StringBuf_Value(&output));
14526 StringBuf_Destroy(&output);
14527 return 0;
14528}
14529
14530//========================================================
14531// countstr <input>, <search>{, <usecase>}
14532//
14533// Note: Counts the number of times <search> occurs in
14534// <input>. By default will be case sensitive.
14535//--------------------------------------------------------
14536BUILDIN_FUNC(countstr)
14537{
14538 const char *input = script_getstr(st, 2);
14539 const char *find = script_getstr(st, 3);
14540 size_t inputlen = strlen(input);
14541 size_t findlen = strlen(find);
14542 bool usecase = true;
14543
14544 int numFinds = 0;
14545 int i = 0, f = 0;
14546
14547 if(findlen == 0) {
14548 ShowError("script:countstr: Invalid search length.\n");
14549 st->state = END;
14550 return 1;
14551 }
14552
14553 if(script_hasdata(st, 4)) {
14554 if(script_isint(st,4))
14555 usecase = script_getnum(st, 4) != 0;
14556 else {
14557 ShowError("script:countstr: Invalid usecase value. Expected int got string\n");
14558 st->state = END;
14559 return 1;
14560 }
14561 }
14562
14563 for(; i < inputlen; i++) {
14564 for(f = 0; f <= findlen; f++) {
14565 if(f == findlen) { //complete match
14566 numFinds++;
14567 i += findlen - 1;
14568 break;
14569 } else {
14570 if(usecase) {
14571 if((i + f) > inputlen || input[i + f] != find[f]) {
14572 break;
14573 }
14574 } else {
14575 if((i + f) > inputlen || input[i + f] != find[f] && TOUPPER(input[i+f]) != TOUPPER(find[f])) {
14576 break;
14577 }
14578 }
14579 }
14580 }
14581 }
14582 script_pushint(st, numFinds);
14583 return 0;
14584}
14585
14586/// Changes the display name and/or display class of the npc.
14587/// Returns 0 is successful, 1 if the npc does not exist.
14588///
14589/// setnpcdisplay("<npc name>", "<new display name>", <new class id>, <new size>) -> <int>
14590/// setnpcdisplay("<npc name>", "<new display name>", <new class id>) -> <int>
14591/// setnpcdisplay("<npc name>", "<new display name>") -> <int>
14592/// setnpcdisplay("<npc name>", <new class id>) -> <int>
14593BUILDIN_FUNC(setnpcdisplay)
14594{
14595 const char* name;
14596 const char* newname = NULL;
14597 int class_ = -1, size = -1;
14598 struct script_data* data;
14599 struct npc_data* nd;
14600
14601 name = script_getstr(st,2);
14602 data = script_getdata(st,3);
14603
14604 if( script_hasdata(st,4) )
14605 class_ = script_getnum(st,4);
14606 if( script_hasdata(st,5) )
14607 size = script_getnum(st,5);
14608
14609 get_val(st, data);
14610 if( data_isstring(data) )
14611 newname = conv_str(st,data);
14612 else if( data_isint(data) )
14613 class_ = conv_num(st,data);
14614 else
14615 {
14616 ShowError("script:setnpcdisplay: expected a string or number\n");
14617 script_reportdata(data);
14618 return 1;
14619 }
14620
14621 nd = npc_name2id(name);
14622 if( nd == NULL )
14623 {// not found
14624 script_pushint(st,1);
14625 return 0;
14626 }
14627
14628 // update npc
14629 if( newname )
14630 npc_setdisplayname(nd, newname);
14631
14632 if( size != -1 && size != (int)nd->size )
14633 nd->size = size;
14634 else
14635 size = -1;
14636
14637 if( class_ != -1 && nd->class_ != class_ )
14638 npc_setclass(nd, class_);
14639 else if( size != -1 )
14640 { // Required to update the visual size
14641 clif_clearunit_area(&nd->bl, CLR_OUTSIGHT);
14642 clif_spawn(&nd->bl);
14643 }
14644
14645 script_pushint(st,0);
14646 return 0;
14647}
14648
14649BUILDIN_FUNC(atoi)
14650{
14651 const char *value;
14652 value = script_getstr(st,2);
14653 script_pushint(st,atoi(value));
14654 return 0;
14655}
14656
14657// case-insensitive substring search [lordalfa]
14658BUILDIN_FUNC(compare)
14659{
14660 const char *message;
14661 const char *cmpstring;
14662 message = script_getstr(st,2);
14663 cmpstring = script_getstr(st,3);
14664 script_pushint(st,(stristr(message,cmpstring) != NULL));
14665 return 0;
14666}
14667
14668// [zBuffer] List of mathematics commands --->
14669BUILDIN_FUNC(sqrt)
14670{
14671 double i, a;
14672 i = script_getnum(st,2);
14673 a = sqrt(i);
14674 script_pushint(st,(int)a);
14675 return 0;
14676}
14677
14678BUILDIN_FUNC(pow)
14679{
14680 double i, a, b;
14681 a = script_getnum(st,2);
14682 b = script_getnum(st,3);
14683 i = pow(a,b);
14684 script_pushint(st,(int)i);
14685 return 0;
14686}
14687
14688BUILDIN_FUNC(distance)
14689{
14690 int x0, y0, x1, y1;
14691
14692 x0 = script_getnum(st,2);
14693 y0 = script_getnum(st,3);
14694 x1 = script_getnum(st,4);
14695 y1 = script_getnum(st,5);
14696
14697 script_pushint(st,distance_xy(x0,y0,x1,y1));
14698 return 0;
14699}
14700
14701// <--- [zBuffer] List of mathematics commands
14702
14703BUILDIN_FUNC(md5)
14704{
14705 const char *tmpstr;
14706 char *md5str;
14707
14708 tmpstr = script_getstr(st,2);
14709 md5str = (char *)aMallocA((32+1)*sizeof(char));
14710 MD5_String(tmpstr, md5str);
14711 script_pushstr(st, md5str);
14712 return 0;
14713}
14714
14715// [zBuffer] List of dynamic var commands --->
14716
14717BUILDIN_FUNC(setd)
14718{
14719 TBL_PC *sd=NULL;
14720 char varname[100];
14721 const char *buffer;
14722 int elem;
14723 buffer = script_getstr(st, 2);
14724
14725 if(sscanf(buffer, "%99[^[][%d]", varname, &elem) < 2)
14726 elem = 0;
14727
14728 if( not_server_variable(*varname) )
14729 {
14730 sd = script_rid2sd(st);
14731 if( sd == NULL )
14732 {
14733 ShowError("script:setd: no player attached for player variable '%s'\n", buffer);
14734 return 0;
14735 }
14736 }
14737
14738 if( is_string_variable(varname) ) {
14739 setd_sub(st, sd, varname, elem, (void *)script_getstr(st, 3), NULL);
14740 } else {
14741 setd_sub(st, sd, varname, elem, (void *)script_getnum(st, 3), NULL);
14742 }
14743
14744 return 0;
14745}
14746
14747#ifndef TXT_ONLY
14748int buildin_query_sql_sub(struct script_state* st, Sql* handle)
14749{
14750 int i, j;
14751 TBL_PC* sd = NULL;
14752 const char* query;
14753 struct script_data* data;
14754 const char* name;
14755 int max_rows = SCRIPT_MAX_ARRAYSIZE;// maximum number of rows
14756 int num_vars;
14757 int num_cols;
14758
14759 // check target variables
14760 for( i = 3; script_hasdata(st,i); ++i )
14761 {
14762 data = script_getdata(st, i);
14763 if( data_isreference(data) && reference_tovariable(data) )
14764 {// it's a variable
14765 name = reference_getname(data);
14766 if( not_server_variable(*name) && sd == NULL )
14767 {// requires a player
14768 sd = script_rid2sd(st);
14769 if( sd == NULL )
14770 {// no player attached
14771 script_reportdata(data);
14772 st->state = END;
14773 return 1;
14774 }
14775 }
14776 if( not_array_variable(*name) )
14777 max_rows = 1;// not an array, limit to one row
14778 }
14779 else
14780 {
14781 ShowError("script:query_sql: not a variable\n");
14782 script_reportdata(data);
14783 st->state = END;
14784 return 1;
14785 }
14786 }
14787 num_vars = i - 3;
14788
14789 // Execute the query
14790 query = script_getstr(st,2);
14791 if( SQL_ERROR == Sql_QueryStr(handle, query) )
14792 {
14793 Sql_ShowDebug(handle);
14794 script_pushint(st, 0);
14795 return 1;
14796 }
14797
14798 if( Sql_NumRows(handle) == 0 )
14799 {// No data received
14800 Sql_FreeResult(handle);
14801 script_pushint(st, 0);
14802 return 0;
14803 }
14804
14805 // Count the number of columns to store
14806 num_cols = Sql_NumColumns(handle);
14807 if( num_vars < num_cols )
14808 {
14809 ShowWarning("script:query_sql: Too many columns, discarding last %u columns.\n", (unsigned int)(num_cols-num_vars));
14810 script_reportsrc(st);
14811 }
14812 else if( num_vars > num_cols )
14813 {
14814 ShowWarning("script:query_sql: Too many variables (%u extra).\n", (unsigned int)(num_vars-num_cols));
14815 script_reportsrc(st);
14816 }
14817
14818 // Store data
14819 for( i = 0; i < max_rows && SQL_SUCCESS == Sql_NextRow(handle); ++i )
14820 {
14821 for( j = 0; j < num_vars; ++j )
14822 {
14823 char* str = NULL;
14824
14825 if( j < num_cols )
14826 Sql_GetData(handle, j, &str, NULL);
14827
14828 data = script_getdata(st, j+3);
14829 name = reference_getname(data);
14830 if( is_string_variable(name) )
14831 setd_sub(st, sd, name, i, (void *)(str?str:""), reference_getref(data));
14832 else
14833 setd_sub(st, sd, name, i, (void *)(str?atoi(str):0), reference_getref(data));
14834 }
14835 }
14836 if( i == max_rows && max_rows < Sql_NumRows(handle) )
14837 {
14838 ShowWarning("script:query_sql: Only %d/%u rows have been stored.\n", max_rows, (unsigned int)Sql_NumRows(handle));
14839 script_reportsrc(st);
14840 }
14841
14842 // Free data
14843 Sql_FreeResult(handle);
14844 script_pushint(st, i);
14845 return 0;
14846}
14847#endif
14848
14849BUILDIN_FUNC(query_sql)
14850{
14851#ifndef TXT_ONLY
14852 return buildin_query_sql_sub(st, mmysql_handle);
14853#else
14854 //for TXT version, we always return -1
14855 script_pushint(st,-1);
14856 return 0;
14857#endif
14858}
14859
14860BUILDIN_FUNC(query_logsql)
14861{
14862#ifndef TXT_ONLY
14863 if( !log_config.sql_logs )
14864 {// logmysql_handle == NULL
14865 ShowWarning("buildin_query_logsql: SQL logs are disabled, query '%s' will not be executed.\n", script_getstr(st,2));
14866 script_pushint(st,-1);
14867 return 1;
14868 }
14869
14870 return buildin_query_sql_sub(st, logmysql_handle);
14871#else
14872 //for TXT version, we always return -1
14873 script_pushint(st,-1);
14874 return 0;
14875#endif
14876}
14877
14878//Allows escaping of a given string.
14879BUILDIN_FUNC(escape_sql)
14880{
14881 const char *str;
14882 char *esc_str;
14883 size_t len;
14884
14885 str = script_getstr(st,2);
14886 len = strlen(str);
14887 esc_str = (char*)aMallocA(len*2+1);
14888#if defined(TXT_ONLY)
14889 jstrescapecpy(esc_str, str);
14890#else
14891 Sql_EscapeStringLen(mmysql_handle, esc_str, str, len);
14892#endif
14893 script_pushstr(st, esc_str);
14894 return 0;
14895}
14896
14897BUILDIN_FUNC(getd)
14898{
14899 const char* p;
14900 const char* name;
14901 int namelen;
14902 bool isarray;
14903 long idx;
14904 struct script_data* data;
14905
14906 p = script_getstr(st, 2);
14907 p = skip_space(p);
14908
14909 // parse name
14910 name = p; // not NUL terminated (not needed)
14911 namelen = skip_word(p) - p;
14912 p += namelen;
14913 p = skip_space(p);
14914 // parse index (optional)
14915 isarray = false;
14916 idx = 0;
14917 if( p[0] == '[' )
14918 {
14919 char* end = NULL;
14920 const char* p2 = skip_space(p + 1);
14921 idx = strtol(p2, &end, 0);
14922 if( p2 != NULL && p2 != end )
14923 { // has a numeric index
14924 p2 = skip_space(end);
14925 if( p2[0] == ']' )
14926 {
14927 p = skip_space(p2 + 1);
14928 isarray = true;
14929 }
14930 }
14931 }
14932
14933 // validate
14934 if( p[0] != '\0' )
14935 {
14936 ShowError("script:getd: failed to parse '%s'\n", p);
14937 script_reportdata(script_getdata(st, 2));
14938 st->state = END;
14939 return 1;
14940 }
14941 if( namelen == 0 )
14942 {
14943 ShowError("script:getd: variable name is empty\n");
14944 script_reportdata(script_getdata(st, 2));
14945 st->state = END;
14946 return 1;
14947 }
14948 if( isarray && not_array_variable(name[0]) )
14949 {
14950 ShowError("script:getd: not an array variable\n");
14951 script_reportdata(script_getdata(st, 2));
14952 st->state = END;
14953 return 1;
14954 }
14955 if( idx < 0 || idx >= SCRIPT_MAX_ARRAYSIZE )
14956 {
14957 ShowError("script:getd: index=%ld is invalid, must be a number from 0 to %d\n", idx, SCRIPT_MAX_ARRAYSIZE - 1);
14958 script_reportdata(script_getdata(st, 2));
14959 st->state = END;
14960 return 1;
14961 }
14962
14963 // generate reference
14964 data = push_val(st->stack, C_NAME, reference_uid(add_word(name), idx));
14965 if( reference_tonil(data) )
14966 str_data[reference_getid(data)].type = C_NAME; // unused name, make it a reference to variable
14967 //XXX references can point to other types of data, not just variables
14968
14969 return 0;
14970}
14971
14972// <--- [zBuffer] List of dynamic var commands
14973// Pet stat [Lance]
14974BUILDIN_FUNC(petstat)
14975{
14976 TBL_PC *sd = NULL;
14977 struct pet_data *pd;
14978 int flag = script_getnum(st,2);
14979 sd = script_rid2sd(st);
14980 if(!sd || !sd->status.pet_id || !sd->pd){
14981 if(flag == 2)
14982 script_pushconststr(st, "");
14983 else
14984 script_pushint(st,0);
14985 return 0;
14986 }
14987 pd = sd->pd;
14988 switch(flag){
14989 case 1: script_pushint(st,(int)pd->pet.class_); break;
14990 case 2: script_pushstrcopy(st, pd->pet.name); break;
14991 case 3: script_pushint(st,(int)pd->pet.level); break;
14992 case 4: script_pushint(st,(int)pd->pet.hungry); break;
14993 case 5: script_pushint(st,(int)pd->pet.intimate); break;
14994 default:
14995 script_pushint(st,0);
14996 break;
14997 }
14998 return 0;
14999}
15000
15001BUILDIN_FUNC(callshop)
15002{
15003 TBL_PC *sd = NULL;
15004 struct npc_data *nd;
15005 const char *shopname;
15006 int flag = 0;
15007 sd = script_rid2sd(st);
15008 if (!sd) {
15009 script_pushint(st,0);
15010 return 0;
15011 }
15012 shopname = script_getstr(st, 2);
15013 if( script_hasdata(st,3) )
15014 flag = script_getnum(st,3);
15015 nd = npc_name2id(shopname);
15016 if( !nd || nd->bl.type != BL_NPC || (nd->subtype != SHOP && nd->subtype != CASHSHOP && nd->subtype != SPSHOP) )
15017 {
15018 ShowError("buildin_callshop: Shop [%s] not found (or NPC is not shop type)\n", shopname);
15019 script_pushint(st,0);
15020 return 1;
15021 }
15022
15023 if( nd->subtype == SHOP )
15024 {
15025 switch( flag )
15026 {
15027 case 1: npc_buysellsel(sd,nd->bl.id,0); break; //Buy window
15028 case 2: npc_buysellsel(sd,nd->bl.id,1); break; //Sell window
15029 default: clif_npcbuysell(sd,nd->bl.id); break; //Show menu
15030 }
15031 }
15032 else
15033 clif_cashshop_show(sd, nd);
15034
15035 sd->npc_shopid = nd->bl.id;
15036 script_pushint(st,1);
15037 return 0;
15038}
15039
15040BUILDIN_FUNC(npcshopitem)
15041{
15042 const char* npcname = script_getstr(st, 2);
15043 struct npc_data* nd = npc_name2id(npcname);
15044 int n, i;
15045 int amount;
15046
15047 if( !nd || ( nd->subtype != SHOP && nd->subtype != CASHSHOP ) )
15048 { //Not found.
15049 script_pushint(st,0);
15050 return 0;
15051 }
15052
15053 // get the count of new entries
15054 amount = (script_lastdata(st)-2)/2;
15055
15056 // generate new shop item list
15057 RECREATE(nd->u.shop.shop_item, struct npc_item_list, amount);
15058 for( n = 0, i = 3; n < amount; n++, i+=2 )
15059 {
15060 nd->u.shop.shop_item[n].nameid = script_getnum(st,i);
15061 nd->u.shop.shop_item[n].value = script_getnum(st,i+1);
15062 }
15063 nd->u.shop.count = n;
15064
15065 script_pushint(st,1);
15066 return 0;
15067}
15068
15069BUILDIN_FUNC(npcshopadditem)
15070{
15071 const char* npcname = script_getstr(st,2);
15072 struct npc_data* nd = npc_name2id(npcname);
15073 int n, i;
15074 int amount;
15075
15076 if( !nd || ( nd->subtype != SHOP && nd->subtype != CASHSHOP ) )
15077 { //Not found.
15078 script_pushint(st,0);
15079 return 0;
15080 }
15081
15082 // get the count of new entries
15083 amount = (script_lastdata(st)-2)/2;
15084
15085 // append new items to existing shop item list
15086 RECREATE(nd->u.shop.shop_item, struct npc_item_list, nd->u.shop.count+amount);
15087 for( n = nd->u.shop.count, i = 3; n < nd->u.shop.count+amount; n++, i+=2 )
15088 {
15089 nd->u.shop.shop_item[n].nameid = script_getnum(st,i);
15090 nd->u.shop.shop_item[n].value = script_getnum(st,i+1);
15091 }
15092 nd->u.shop.count = n;
15093
15094 script_pushint(st,1);
15095 return 0;
15096}
15097
15098BUILDIN_FUNC(npcshopdelitem)
15099{
15100 const char* npcname = script_getstr(st,2);
15101 struct npc_data* nd = npc_name2id(npcname);
15102 unsigned int nameid;
15103 int n, i;
15104 int amount;
15105 int size;
15106
15107 if( !nd || ( nd->subtype != SHOP && nd->subtype != CASHSHOP ) )
15108 { //Not found.
15109 script_pushint(st,0);
15110 return 0;
15111 }
15112
15113 amount = script_lastdata(st)-2;
15114 size = nd->u.shop.count;
15115
15116 // remove specified items from the shop item list
15117 for( i = 3; i < 3 + amount; i++ )
15118 {
15119 nameid = script_getnum(st,i);
15120
15121 ARR_FIND( 0, size, n, nd->u.shop.shop_item[n].nameid == nameid );
15122 if( n < size )
15123 {
15124 memmove(&nd->u.shop.shop_item[n], &nd->u.shop.shop_item[n+1], sizeof(nd->u.shop.shop_item[0])*(size-n));
15125 size--;
15126 }
15127 }
15128
15129 RECREATE(nd->u.shop.shop_item, struct npc_item_list, size);
15130 nd->u.shop.count = size;
15131
15132 script_pushint(st,1);
15133 return 0;
15134}
15135
15136//Sets a script to attach to a shop npc.
15137BUILDIN_FUNC(npcshopattach)
15138{
15139 const char* npcname = script_getstr(st,2);
15140 struct npc_data* nd = npc_name2id(npcname);
15141 int flag = 1;
15142
15143 if( script_hasdata(st,3) )
15144 flag = script_getnum(st,3);
15145
15146 if( !nd || (nd->subtype != SHOP && nd->subtype != CASHSHOP) )
15147 { //Not found.
15148 script_pushint(st,0);
15149 return 0;
15150 }
15151
15152 if (flag)
15153 nd->master_nd = ((struct npc_data *)map_id2bl(st->oid));
15154 else
15155 nd->master_nd = NULL;
15156
15157 script_pushint(st,1);
15158 return 0;
15159}
15160
15161/*==========================================
15162 * Returns some values of an item [Lupus]
15163 * Price, Weight, etc...
15164 setitemscript(itemID,"{new item bonus script}",[n]);
15165 Where n:
15166 0 - script
15167 1 - Equip script
15168 2 - Unequip script
15169 *------------------------------------------*/
15170BUILDIN_FUNC(setitemscript)
15171{
15172 int item_id,n=0;
15173 const char *script;
15174 struct item_data *i_data;
15175 struct script_code **dstscript;
15176
15177 item_id = script_getnum(st,2);
15178 script = script_getstr(st,3);
15179 if( script_hasdata(st,4) )
15180 n=script_getnum(st,4);
15181 i_data = itemdb_exists(item_id);
15182
15183 if (!i_data || script==NULL || ( script[0] && script[0]!='{' )) {
15184 script_pushint(st,0);
15185 return 0;
15186 }
15187 switch (n) {
15188 case 2:
15189 dstscript = &i_data->unequip_script;
15190 break;
15191 case 1:
15192 dstscript = &i_data->equip_script;
15193 break;
15194 default:
15195 dstscript = &i_data->script;
15196 break;
15197 }
15198 if(*dstscript)
15199 script_free_code(*dstscript);
15200
15201 *dstscript = script[0] ? parse_script(script, "script_setitemscript", 0, 0) : NULL;
15202 script_pushint(st,1);
15203 return 0;
15204}
15205
15206/* Work In Progress [Lupus]
15207BUILDIN_FUNC(addmonsterdrop)
15208{
15209 int class_,item_id,chance;
15210 class_=script_getnum(st,2);
15211 item_id=script_getnum(st,3);
15212 chance=script_getnum(st,4);
15213 if(class_>1000 && item_id>500 && chance>0) {
15214 script_pushint(st,1);
15215 } else {
15216 script_pushint(st,0);
15217 }
15218}
15219
15220BUILDIN_FUNC(delmonsterdrop)
15221{
15222 int class_,item_id;
15223 class_=script_getnum(st,2);
15224 item_id=script_getnum(st,3);
15225 if(class_>1000 && item_id>500) {
15226 script_pushint(st,1);
15227 } else {
15228 script_pushint(st,0);
15229 }
15230}
15231*/
15232
15233/*==========================================
15234 * Returns some values of a monster [Lupus]
15235 * Name, Level, race, size, etc...
15236 getmonsterinfo(monsterID,queryIndex);
15237 *------------------------------------------*/
15238BUILDIN_FUNC(getmonsterinfo)
15239{
15240 struct mob_db *mob;
15241 int mob_id;
15242
15243 mob_id = script_getnum(st,2);
15244 if (!mobdb_checkid(mob_id)) {
15245 ShowError("buildin_getmonsterinfo: Wrong Monster ID: %i\n", mob_id);
15246 if ( !script_getnum(st,3) ) //requested a string
15247 script_pushconststr(st,"null");
15248 else
15249 script_pushint(st,-1);
15250 return -1;
15251 }
15252 mob = mob_db(mob_id);
15253 switch ( script_getnum(st,3) ) {
15254 case 0: script_pushstrcopy(st,mob->jname); break;
15255 case 1: script_pushint(st,mob->lv); break;
15256 case 2: script_pushint(st,mob->status.max_hp); break;
15257 case 3: script_pushint(st,mob->base_exp); break;
15258 case 4: script_pushint(st,mob->job_exp); break;
15259 case 5: script_pushint(st,mob->status.rhw.atk); break;
15260 case 6: script_pushint(st,mob->status.rhw.atk2); break;
15261 case 7: script_pushint(st,mob->status.def); break;
15262 case 8: script_pushint(st,mob->status.mdef); break;
15263 case 9: script_pushint(st,mob->status.str); break;
15264 case 10: script_pushint(st,mob->status.agi); break;
15265 case 11: script_pushint(st,mob->status.vit); break;
15266 case 12: script_pushint(st,mob->status.int_); break;
15267 case 13: script_pushint(st,mob->status.dex); break;
15268 case 14: script_pushint(st,mob->status.luk); break;
15269 case 15: script_pushint(st,mob->status.rhw.range); break;
15270 case 16: script_pushint(st,mob->range2); break;
15271 case 17: script_pushint(st,mob->range3); break;
15272 case 18: script_pushint(st,mob->status.size); break;
15273 case 19: script_pushint(st,mob->status.race); break;
15274 case 20: script_pushint(st,mob->status.def_ele); break;
15275 case 21: script_pushint(st,mob->status.mode); break;
15276 default: script_pushint(st,-1); //wrong Index
15277 }
15278 return 0;
15279}
15280
15281BUILDIN_FUNC(checkvending) // check vending [Nab4]
15282{
15283 TBL_PC *sd = NULL;
15284
15285 if(script_hasdata(st,2))
15286 sd = map_nick2sd(script_getstr(st,2));
15287 else
15288 sd = script_rid2sd(st);
15289
15290 if(sd)
15291 script_pushint(st,sd->state.vending);
15292 else
15293 script_pushint(st,0);
15294
15295 return 0;
15296}
15297
15298
15299BUILDIN_FUNC(checkchatting) // check chatting [Marka]
15300{
15301 TBL_PC *sd = NULL;
15302
15303 if(script_hasdata(st,2))
15304 sd = map_nick2sd(script_getstr(st,2));
15305 else
15306 sd = script_rid2sd(st);
15307
15308 if(sd)
15309 script_pushint(st,(sd->chatID != 0));
15310 else
15311 script_pushint(st,0);
15312
15313 return 0;
15314}
15315
15316BUILDIN_FUNC(searchitem)
15317{
15318 struct script_data* data = script_getdata(st, 2);
15319 const char *itemname = script_getstr(st,3);
15320 struct item_data *items[MAX_SEARCH];
15321 int count;
15322
15323 char* name;
15324 int32 start;
15325 int32 id;
15326 int32 i;
15327 TBL_PC* sd = NULL;
15328
15329 if ((items[0] = itemdb_exists(atoi(itemname))))
15330 count = 1;
15331 else {
15332 count = itemdb_searchname_array(items, ARRAYLENGTH(items), itemname);
15333 if (count > MAX_SEARCH) count = MAX_SEARCH;
15334 }
15335
15336 if (!count) {
15337 script_pushint(st, 0);
15338 return 0;
15339 }
15340
15341 if( !data_isreference(data) )
15342 {
15343 ShowError("script:searchitem: not a variable\n");
15344 script_reportdata(data);
15345 st->state = END;
15346 return 1;// not a variable
15347 }
15348
15349 id = reference_getid(data);
15350 start = reference_getindex(data);
15351 name = reference_getname(data);
15352 if( not_array_variable(*name) )
15353 {
15354 ShowError("script:searchitem: illegal scope\n");
15355 script_reportdata(data);
15356 st->state = END;
15357 return 1;// not supported
15358 }
15359
15360 if( not_server_variable(*name) )
15361 {
15362 sd = script_rid2sd(st);
15363 if( sd == NULL )
15364 return 0;// no player attached
15365 }
15366
15367 if( is_string_variable(name) )
15368 {// string array
15369 ShowError("script:searchitem: not an integer array reference\n");
15370 script_reportdata(data);
15371 st->state = END;
15372 return 1;// not supported
15373 }
15374
15375 for( i = 0; i < count; ++start, ++i )
15376 {// Set array
15377 void* v = (void*)items[i]->nameid;
15378 set_reg(st, sd, reference_uid(id, start), name, v, reference_getref(data));
15379 }
15380
15381 script_pushint(st, count);
15382 return 0;
15383}
15384
15385int axtoi(const char *hexStg)
15386{
15387 int n = 0; // position in string
15388 int m = 0; // position in digit[] to shift
15389 int count; // loop index
15390 int intValue = 0; // integer value of hex string
15391 int digit[11]; // hold values to convert
15392 while (n < 10) {
15393 if (hexStg[n]=='\0')
15394 break;
15395 if (hexStg[n] > 0x29 && hexStg[n] < 0x40 ) //if 0 to 9
15396 digit[n] = hexStg[n] & 0x0f; //convert to int
15397 else if (hexStg[n] >='a' && hexStg[n] <= 'f') //if a to f
15398 digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int
15399 else if (hexStg[n] >='A' && hexStg[n] <= 'F') //if A to F
15400 digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int
15401 else break;
15402 n++;
15403 }
15404 count = n;
15405 m = n - 1;
15406 n = 0;
15407 while(n < count) {
15408 // digit[n] is value of hex digit at position n
15409 // (m << 2) is the number of positions to shift
15410 // OR the bits into return value
15411 intValue = intValue | (digit[n] << (m << 2));
15412 m--; // adjust the position to set
15413 n++; // next digit to process
15414 }
15415 return (intValue);
15416}
15417
15418// [Lance] Hex string to integer converter
15419BUILDIN_FUNC(axtoi)
15420{
15421 const char *hex = script_getstr(st,2);
15422 script_pushint(st,axtoi(hex));
15423 return 0;
15424}
15425
15426// [zBuffer] List of player cont commands --->
15427BUILDIN_FUNC(rid2name)
15428{
15429 struct block_list *bl = NULL;
15430 int rid = script_getnum(st,2);
15431 if((bl = map_id2bl(rid)))
15432 {
15433 switch(bl->type) {
15434 case BL_MOB: script_pushstrcopy(st,((TBL_MOB*)bl)->name); break;
15435 case BL_PC: script_pushstrcopy(st,((TBL_PC*)bl)->status.name); break;
15436 case BL_NPC: script_pushstrcopy(st,((TBL_NPC*)bl)->exname); break;
15437 case BL_PET: script_pushstrcopy(st,((TBL_PET*)bl)->pet.name); break;
15438 case BL_HOM: script_pushstrcopy(st,((TBL_HOM*)bl)->homunculus.name); break;
15439 case BL_MER: script_pushstrcopy(st,((TBL_MER*)bl)->db->name); break;
15440 default:
15441 ShowError("buildin_rid2name: BL type unknown.\n");
15442 script_pushconststr(st,"");
15443 break;
15444 }
15445 } else {
15446 ShowError("buildin_rid2name: invalid RID\n");
15447 script_pushconststr(st,"(null)");
15448 }
15449 return 0;
15450}
15451
15452BUILDIN_FUNC(pcblock)
15453{
15454 int id = 0, flag, type;
15455 TBL_PC *sd = NULL;
15456
15457 type = script_getnum(st,2);
15458 flag = script_getnum(st,3);
15459 if( script_hasdata(st,4) )
15460 id = script_getnum(st,4);
15461
15462 if( id && (sd = map_id2sd(id)) == NULL )
15463 return 0;
15464 else
15465 sd = script_rid2sd(st);
15466
15467 if( sd == NULL )
15468 return 0;
15469
15470 switch( type )
15471 {
15472 case 0: sd->state.blockedmove = flag > 0; break;
15473 case 1: sd->state.only_walk = flag > 0; break;
15474 }
15475
15476 return 0;
15477}
15478
15479BUILDIN_FUNC(pcblockmove)
15480{
15481 int id, flag;
15482 TBL_PC *sd = NULL;
15483
15484 id = script_getnum(st,2);
15485 flag = script_getnum(st,3);
15486
15487 if(id)
15488 sd = map_id2sd(id);
15489 else
15490 sd = script_rid2sd(st);
15491
15492 if(sd)
15493 sd->state.blockedmove = flag > 0;
15494
15495 return 0;
15496}
15497
15498BUILDIN_FUNC(pcfollow)
15499{
15500 int id, targetid;
15501 TBL_PC *sd = NULL;
15502
15503
15504 id = script_getnum(st,2);
15505 targetid = script_getnum(st,3);
15506
15507 if(id)
15508 sd = map_id2sd(id);
15509 else
15510 sd = script_rid2sd(st);
15511
15512 if(sd)
15513 pc_follow(sd, targetid);
15514
15515 return 0;
15516}
15517
15518BUILDIN_FUNC(pcstopfollow)
15519{
15520 int id;
15521 TBL_PC *sd = NULL;
15522
15523
15524 id = script_getnum(st,2);
15525
15526 if(id)
15527 sd = map_id2sd(id);
15528 else
15529 sd = script_rid2sd(st);
15530
15531 if(sd)
15532 pc_stop_following(sd);
15533
15534 return 0;
15535}
15536// <--- [zBuffer] List of player cont commands
15537// [zBuffer] List of mob control commands --->
15538//## TODO always return if the request/whatever was successfull [FlavioJS]
15539
15540/// Makes the unit walk to target position or map
15541/// Returns if it was successfull
15542///
15543/// unitwalk(<unit_id>,<x>,<y>) -> <bool>
15544/// unitwalk(<unit_id>,<map_id>) -> <bool>
15545BUILDIN_FUNC(unitwalk)
15546{
15547 struct block_list* bl;
15548
15549 bl = map_id2bl(script_getnum(st,2));
15550 if( bl == NULL )
15551 {
15552 script_pushint(st, 0);
15553 }
15554 else if( script_hasdata(st,4) )
15555 {
15556 int x = script_getnum(st,3);
15557 int y = script_getnum(st,4);
15558 script_pushint(st, unit_walktoxy(bl,x,y,0));// We'll use harder calculations.
15559 }
15560 else
15561 {
15562 int map_id = script_getnum(st,3);
15563 script_pushint(st, unit_walktobl(bl,map_id2bl(map_id),65025,1));
15564 }
15565
15566 return 0;
15567}
15568
15569/// Kills the unit
15570///
15571/// unitkill <unit_id>;
15572BUILDIN_FUNC(unitkill)
15573{
15574 struct block_list* bl = map_id2bl(script_getnum(st,2));
15575 if( bl != NULL )
15576 status_kill(bl);
15577
15578 return 0;
15579}
15580
15581/// Warps the unit to the target position in the target map
15582/// Returns if it was successfull
15583///
15584/// unitwarp(<unit_id>,"<map name>",<x>,<y>) -> <bool>
15585BUILDIN_FUNC(unitwarp)
15586{
15587 int unit_id;
15588 int map;
15589 short x;
15590 short y;
15591 struct block_list* bl;
15592 const char *mapname;
15593
15594 unit_id = script_getnum(st,2);
15595 mapname = script_getstr(st, 3);
15596 x = (short)script_getnum(st,4);
15597 y = (short)script_getnum(st,5);
15598
15599 if (!unit_id) //Warp the script's runner
15600 bl = map_id2bl(st->rid);
15601 else
15602 bl = map_id2bl(unit_id);
15603
15604 if( strcmp(mapname,"this") == 0 )
15605 map = bl?bl->m:-1;
15606 else
15607 map = map_mapname2mapid(mapname);
15608
15609 if( map >= 0 && bl != NULL )
15610 script_pushint(st, unit_warp(bl,map,x,y,CLR_OUTSIGHT));
15611 else
15612 script_pushint(st, 0);
15613
15614 return 0;
15615}
15616
15617/// Makes the unit attack the target.
15618/// If the unit is a player and <action type> is not 0, it does a continuous
15619/// attack instead of a single attack.
15620/// Returns if the request was successfull.
15621///
15622/// unitattack(<unit_id>,"<target name>"{,<action type>}) -> <bool>
15623/// unitattack(<unit_id>,<target_id>{,<action type>}) -> <bool>
15624BUILDIN_FUNC(unitattack)
15625{
15626 struct block_list* unit_bl;
15627 struct block_list* target_bl = NULL;
15628 struct script_data* data;
15629 int actiontype = 0;
15630
15631 // get unit
15632 unit_bl = map_id2bl(script_getnum(st,2));
15633 if( unit_bl == NULL ) {
15634 script_pushint(st, 0);
15635 return 0;
15636 }
15637
15638 data = script_getdata(st, 3);
15639 get_val(st, data);
15640 if( data_isstring(data) )
15641 {
15642 TBL_PC* sd = map_nick2sd(conv_str(st, data));
15643 if( sd != NULL )
15644 target_bl = &sd->bl;
15645 } else
15646 target_bl = map_id2bl(conv_num(st, data));
15647 // request the attack
15648 if( target_bl == NULL )
15649 {
15650 script_pushint(st, 0);
15651 return 0;
15652 }
15653
15654 // get actiontype
15655 if( script_hasdata(st,4) )
15656 actiontype = script_getnum(st,4);
15657
15658 switch( unit_bl->type )
15659 {
15660 case BL_PC:
15661 // FIXME: Leeching off a parse function
15662 clif_parse_ActionRequest_sub(((TBL_PC *)unit_bl), actiontype > 0 ? 0x07 : 0x00, target_bl->id, gettick());
15663 script_pushint(st, 1);
15664 return 0;
15665 case BL_MOB:
15666 ((TBL_MOB *)unit_bl)->target_id = target_bl->id;
15667 break;
15668 case BL_PET:
15669 ((TBL_PET *)unit_bl)->target_id = target_bl->id;
15670 break;
15671 default:
15672 ShowError("script:unitattack: unsupported source unit type %d\n", unit_bl->type);
15673 script_pushint(st, 0);
15674 return 1;
15675 }
15676 script_pushint(st, unit_walktobl(unit_bl, target_bl, 65025, 2));
15677 return 0;
15678}
15679
15680/// Makes the unit stop attacking and moving
15681///
15682/// unitstop <unit_id>;
15683BUILDIN_FUNC(unitstop)
15684{
15685 int unit_id;
15686 struct block_list* bl;
15687
15688 unit_id = script_getnum(st,2);
15689
15690 bl = map_id2bl(unit_id);
15691 if( bl != NULL )
15692 {
15693 unit_stop_attack(bl);
15694 unit_stop_walking(bl,4);
15695 if( bl->type == BL_MOB )
15696 ((TBL_MOB*)bl)->target_id = 0;
15697 }
15698
15699 return 0;
15700}
15701
15702/// Makes the unit say the message
15703///
15704/// unittalk <unit_id>,"<message>";
15705BUILDIN_FUNC(unittalk)
15706{
15707 int unit_id;
15708 const char* message;
15709 struct block_list* bl;
15710
15711 unit_id = script_getnum(st,2);
15712 message = script_getstr(st, 3);
15713
15714 bl = map_id2bl(unit_id);
15715 if( bl != NULL )
15716 {
15717 struct StringBuf sbuf;
15718 StringBuf_Init(&sbuf);
15719 StringBuf_Printf(&sbuf, "%s : %s", status_get_name(bl), message);
15720 clif_message(bl, StringBuf_Value(&sbuf));
15721 if( bl->type == BL_PC )
15722 clif_displaymessage(((TBL_PC*)bl)->fd, StringBuf_Value(&sbuf));
15723 StringBuf_Destroy(&sbuf);
15724 }
15725
15726 return 0;
15727}
15728
15729/// Makes the unit do an emotion
15730///
15731/// unitemote <unit_id>,<emotion>;
15732///
15733/// @see e_* in const.txt
15734BUILDIN_FUNC(unitemote)
15735{
15736 int unit_id;
15737 int emotion;
15738 struct block_list* bl;
15739
15740 unit_id = script_getnum(st,2);
15741 emotion = script_getnum(st,3);
15742 bl = map_id2bl(unit_id);
15743 if( bl != NULL )
15744 clif_emotion(bl, emotion);
15745
15746 return 0;
15747}
15748
15749/// Makes the unit cast the skill on the target or self if no target is specified
15750///
15751/// unitskilluseid <unit_id>,<skill_id>,<skill_lv>{,<target_id>};
15752/// unitskilluseid <unit_id>,"<skill name>",<skill_lv>{,<target_id>};
15753BUILDIN_FUNC(unitskilluseid)
15754{
15755 int unit_id;
15756 int skill_id;
15757 int skill_lv;
15758 int target_id;
15759 struct block_list* bl;
15760
15761 unit_id = script_getnum(st,2);
15762 skill_id = ( script_isstring(st,3) ? skill_name2id(script_getstr(st,3)) : script_getnum(st,3) );
15763 skill_lv = script_getnum(st,4);
15764 target_id = ( script_hasdata(st,5) ? script_getnum(st,5) : unit_id );
15765
15766 bl = map_id2bl(unit_id);
15767 if( bl != NULL )
15768 unit_skilluse_id(bl, target_id, skill_id, skill_lv);
15769
15770 return 0;
15771}
15772
15773/// Makes the unit cast the skill on the target position.
15774///
15775/// unitskillusepos <unit_id>,<skill_id>,<skill_lv>,<target_x>,<target_y>;
15776/// unitskillusepos <unit_id>,"<skill name>",<skill_lv>,<target_x>,<target_y>;
15777BUILDIN_FUNC(unitskillusepos)
15778{
15779 int unit_id;
15780 int skill_id;
15781 int skill_lv;
15782 int skill_x;
15783 int skill_y;
15784 struct block_list* bl;
15785
15786 unit_id = script_getnum(st,2);
15787 skill_id = ( script_isstring(st,3) ? skill_name2id(script_getstr(st,3)) : script_getnum(st,3) );
15788 skill_lv = script_getnum(st,4);
15789 skill_x = script_getnum(st,5);
15790 skill_y = script_getnum(st,6);
15791
15792 bl = map_id2bl(unit_id);
15793 if( bl != NULL )
15794 unit_skilluse_pos(bl, skill_x, skill_y, skill_id, skill_lv);
15795
15796 return 0;
15797}
15798
15799// <--- [zBuffer] List of mob control commands
15800
15801/// Pauses the execution of the script, detaching the player
15802///
15803/// sleep <mili seconds>;
15804BUILDIN_FUNC(sleep)
15805{
15806 int ticks;
15807
15808 ticks = script_getnum(st,2);
15809
15810 // detach the player
15811 script_detach_rid(st);
15812
15813 if( ticks <= 0 )
15814 {// do nothing
15815 }
15816 else if( st->sleep.tick == 0 )
15817 {// sleep for the target amount of time
15818 st->state = RERUNLINE;
15819 st->sleep.tick = ticks;
15820 }
15821 else
15822 {// sleep time is over
15823 st->state = RUN;
15824 st->sleep.tick = 0;
15825 }
15826 return 0;
15827}
15828
15829/// Pauses the execution of the script, keeping the player attached
15830/// Returns if a player is still attached
15831///
15832/// sleep2(<mili secconds>) -> <bool>
15833BUILDIN_FUNC(sleep2)
15834{
15835 int ticks;
15836
15837 ticks = script_getnum(st,2);
15838
15839 if( ticks <= 0 )
15840 {// do nothing
15841 script_pushint(st, (map_id2sd(st->rid)!=NULL));
15842 }
15843 else if( !st->sleep.tick )
15844 {// sleep for the target amount of time
15845 st->state = RERUNLINE;
15846 st->sleep.tick = ticks;
15847 }
15848 else
15849 {// sleep time is over
15850 st->state = RUN;
15851 st->sleep.tick = 0;
15852 script_pushint(st, (map_id2sd(st->rid)!=NULL));
15853 }
15854 return 0;
15855}
15856
15857/// Awakes all the sleep timers of the target npc
15858///
15859/// awake "<npc name>";
15860BUILDIN_FUNC(awake)
15861{
15862 struct npc_data* nd;
15863 struct linkdb_node *node = (struct linkdb_node *)sleep_db;
15864
15865 nd = npc_name2id(script_getstr(st, 2));
15866 if( nd == NULL ) {
15867 ShowError("awake: NPC \"%s\" not found\n", script_getstr(st, 2));
15868 return 1;
15869 }
15870
15871 while( node )
15872 {
15873 if( (int)node->key == nd->bl.id )
15874 {// sleep timer for the npc
15875 struct script_state* tst = (struct script_state*)node->data;
15876 TBL_PC* sd = map_id2sd(tst->rid);
15877
15878 if( tst->sleep.timer == INVALID_TIMER )
15879 {// already awake ???
15880 node = node->next;
15881 continue;
15882 }
15883 if( (sd && sd->status.char_id != tst->sleep.charid) || (tst->rid && !sd))
15884 {// char not online anymore / another char of the same account is online - Cancel execution
15885 tst->state = END;
15886 tst->rid = 0;
15887 }
15888
15889 delete_timer(tst->sleep.timer, run_script_timer);
15890 node = script_erase_sleepdb(node);
15891 tst->sleep.timer = INVALID_TIMER;
15892 if(tst->state != RERUNLINE)
15893 tst->sleep.tick = 0;
15894 run_script_main(tst);
15895 }
15896 else
15897 {
15898 node = node->next;
15899 }
15900 }
15901 return 0;
15902}
15903
15904/// Returns a reference to a variable of the target NPC.
15905/// Returns 0 if an error occurs.
15906///
15907/// getvariableofnpc(<variable>, "<npc name>") -> <reference>
15908BUILDIN_FUNC(getvariableofnpc)
15909{
15910 struct script_data* data;
15911 const char* name;
15912 struct npc_data* nd;
15913
15914 data = script_getdata(st,2);
15915 if( !data_isreference(data) )
15916 {// Not a reference (aka varaible name)
15917 ShowError("script:getvariableofnpc: not a variable\n");
15918 script_reportdata(data);
15919 script_pushnil(st);
15920 st->state = END;
15921 return 1;
15922 }
15923
15924 name = reference_getname(data);
15925 if( *name != '.' || name[1] == '@' )
15926 {// not a npc variable
15927 ShowError("script:getvariableofnpc: invalid scope (not npc variable)\n");
15928 script_reportdata(data);
15929 script_pushnil(st);
15930 st->state = END;
15931 return 1;
15932 }
15933
15934 nd = npc_name2id(script_getstr(st,3));
15935 if( nd == NULL || nd->subtype != SCRIPT || nd->u.scr.script == NULL )
15936 {// NPC not found or has no script
15937 ShowError("script:getvariableofnpc: can't find npc %s\n", script_getstr(st,3));
15938 script_pushnil(st);
15939 st->state = END;
15940 return 1;
15941 }
15942
15943 push_val2(st->stack, C_NAME, reference_getuid(data), &nd->u.scr.script->script_vars );
15944 return 0;
15945}
15946
15947/// Opens a warp portal.
15948/// Has no "portal opening" effect/sound, it opens the portal immediately.
15949///
15950/// warpportal <source x>,<source y>,"<target map>",<target x>,<target y>;
15951///
15952/// @author blackhole89
15953BUILDIN_FUNC(warpportal)
15954{
15955 int spx;
15956 int spy;
15957 unsigned short mapindex;
15958 int tpx;
15959 int tpy;
15960 struct skill_unit_group* group;
15961 struct block_list* bl;
15962
15963 bl = map_id2bl(st->oid);
15964 if( bl == NULL )
15965 {
15966 ShowError("script:warpportal: npc is needed\n");
15967 return 1;
15968 }
15969
15970 spx = script_getnum(st,2);
15971 spy = script_getnum(st,3);
15972 mapindex = mapindex_name2id(script_getstr(st, 4));
15973 tpx = script_getnum(st,5);
15974 tpy = script_getnum(st,6);
15975
15976 if( mapindex == 0 )
15977 return 0;// map not found
15978
15979 group = skill_unitsetting(bl, AL_WARP, 4, spx, spy, 0);
15980 if( group == NULL )
15981 return 0;// failed
15982 group->val2 = (tpx<<16) | tpy;
15983 group->val3 = mapindex;
15984
15985 return 0;
15986}
15987
15988BUILDIN_FUNC(openmail)
15989{
15990 TBL_PC* sd;
15991
15992 sd = script_rid2sd(st);
15993 if( sd == NULL )
15994 return 0;
15995
15996#ifndef TXT_ONLY
15997 mail_openmail(sd);
15998#endif
15999 return 0;
16000}
16001
16002BUILDIN_FUNC(openauction)
16003{
16004 TBL_PC* sd;
16005
16006 sd = script_rid2sd(st);
16007 if( sd == NULL )
16008 return 0;
16009
16010#ifndef TXT_ONLY
16011 clif_Auction_openwindow(sd);
16012#endif
16013 return 0;
16014}
16015
16016/// Retrieves the value of the specified flag of the specified cell.
16017///
16018/// checkcell("<map name>",<x>,<y>,<type>) -> <bool>
16019///
16020/// @see cell_chk* constants in const.txt for the types
16021BUILDIN_FUNC(checkcell)
16022{
16023 int m = map_mapname2mapid(script_getstr(st,2));
16024 int x = script_getnum(st,3);
16025 int y = script_getnum(st,4);
16026 cell_chk type = (cell_chk)script_getnum(st,5);
16027
16028 script_pushint(st, map_getcell(m, x, y, type));
16029
16030 return 0;
16031}
16032
16033/// Modifies flags of cells in the specified area.
16034///
16035/// setcell "<map name>",<x1>,<y1>,<x2>,<y2>,<type>,<flag>;
16036///
16037/// @see cell_* constants in const.txt for the types
16038BUILDIN_FUNC(setcell)
16039{
16040 int m = map_mapname2mapid(script_getstr(st,2));
16041 int x1 = script_getnum(st,3);
16042 int y1 = script_getnum(st,4);
16043 int x2 = script_getnum(st,5);
16044 int y2 = script_getnum(st,6);
16045 cell_t type = (cell_t)script_getnum(st,7);
16046 bool flag = (bool)script_getnum(st,8);
16047
16048 int x,y;
16049
16050 if( x1 > x2 ) swap(x1,x2);
16051 if( y1 > y2 ) swap(y1,y2);
16052
16053 for( y = y1; y <= y2; ++y )
16054 for( x = x1; x <= x2; ++x )
16055 map_setcell(m, x, y, type, flag);
16056
16057 return 0;
16058}
16059
16060/*==========================================
16061 * Mercenary Commands
16062 *------------------------------------------*/
16063BUILDIN_FUNC(mercenary_create)
16064{
16065#ifndef TXT_ONLY
16066 struct map_session_data *sd;
16067 int class_, contract_time;
16068
16069 if( (sd = script_rid2sd(st)) == NULL || sd->md || sd->status.mer_id != 0 )
16070 return 0;
16071
16072 class_ = script_getnum(st,2);
16073
16074 if( !merc_class(class_) )
16075 return 0;
16076
16077 contract_time = script_getnum(st,3);
16078 merc_create(sd, class_, contract_time);
16079#endif
16080 return 0;
16081}
16082
16083BUILDIN_FUNC(mercenary_heal)
16084{
16085 struct map_session_data *sd = script_rid2sd(st);
16086 int hp, sp;
16087
16088 if( sd == NULL || sd->md == NULL )
16089 return 0;
16090 hp = script_getnum(st,2);
16091 sp = script_getnum(st,3);
16092
16093 status_heal(&sd->md->bl, hp, sp, 0);
16094 return 0;
16095}
16096
16097BUILDIN_FUNC(mercenary_sc_start)
16098{
16099 struct map_session_data *sd = script_rid2sd(st);
16100 enum sc_type type;
16101 int tick, val1;
16102
16103 if( sd == NULL || sd->md == NULL )
16104 return 0;
16105
16106 type = (sc_type)script_getnum(st,2);
16107 tick = script_getnum(st,3);
16108 val1 = script_getnum(st,4);
16109
16110 status_change_start(&sd->md->bl, type, 10000, val1, 0, 0, 0, tick, 2);
16111 return 0;
16112}
16113
16114BUILDIN_FUNC(mercenary_get_calls)
16115{
16116 struct map_session_data *sd = script_rid2sd(st);
16117 int guild;
16118
16119 if( sd == NULL )
16120 return 0;
16121
16122 guild = script_getnum(st,2);
16123 switch( guild )
16124 {
16125 case ARCH_MERC_GUILD:
16126 script_pushint(st,sd->status.arch_calls);
16127 break;
16128 case SPEAR_MERC_GUILD:
16129 script_pushint(st,sd->status.spear_calls);
16130 break;
16131 case SWORD_MERC_GUILD:
16132 script_pushint(st,sd->status.sword_calls);
16133 break;
16134 default:
16135 script_pushint(st,0);
16136 break;
16137 }
16138
16139 return 0;
16140}
16141
16142BUILDIN_FUNC(mercenary_set_calls)
16143{
16144 struct map_session_data *sd = script_rid2sd(st);
16145 int guild, value, *calls;
16146
16147 if( sd == NULL )
16148 return 0;
16149
16150 guild = script_getnum(st,2);
16151 value = script_getnum(st,3);
16152
16153 switch( guild )
16154 {
16155 case ARCH_MERC_GUILD:
16156 calls = &sd->status.arch_calls;
16157 break;
16158 case SPEAR_MERC_GUILD:
16159 calls = &sd->status.spear_calls;
16160 break;
16161 case SWORD_MERC_GUILD:
16162 calls = &sd->status.sword_calls;
16163 break;
16164 default:
16165 return 0; // Invalid Guild
16166 }
16167
16168 *calls += value;
16169 *calls = cap_value(*calls, 0, INT_MAX);
16170
16171 return 0;
16172}
16173
16174BUILDIN_FUNC(mercenary_get_faith)
16175{
16176 struct map_session_data *sd = script_rid2sd(st);
16177 int guild;
16178
16179 if( sd == NULL )
16180 return 0;
16181
16182 guild = script_getnum(st,2);
16183 switch( guild )
16184 {
16185 case ARCH_MERC_GUILD:
16186 script_pushint(st,sd->status.arch_faith);
16187 break;
16188 case SPEAR_MERC_GUILD:
16189 script_pushint(st,sd->status.spear_faith);
16190 break;
16191 case SWORD_MERC_GUILD:
16192 script_pushint(st,sd->status.sword_faith);
16193 break;
16194 default:
16195 script_pushint(st,0);
16196 break;
16197 }
16198
16199 return 0;
16200}
16201
16202BUILDIN_FUNC(mercenary_set_faith)
16203{
16204 struct map_session_data *sd = script_rid2sd(st);
16205 int guild, value, *calls;
16206
16207 if( sd == NULL )
16208 return 0;
16209
16210 guild = script_getnum(st,2);
16211 value = script_getnum(st,3);
16212
16213 switch( guild )
16214 {
16215 case ARCH_MERC_GUILD:
16216 calls = &sd->status.arch_faith;
16217 break;
16218 case SPEAR_MERC_GUILD:
16219 calls = &sd->status.spear_faith;
16220 break;
16221 case SWORD_MERC_GUILD:
16222 calls = &sd->status.sword_faith;
16223 break;
16224 default:
16225 return 0; // Invalid Guild
16226 }
16227
16228 *calls += value;
16229 *calls = cap_value(*calls, 0, INT_MAX);
16230 if( mercenary_get_guild(sd->md) == guild )
16231 clif_mercenary_updatestatus(sd,SP_MERCFAITH);
16232
16233 return 0;
16234}
16235
16236/*------------------------------------------
16237 * Book Reading
16238 *------------------------------------------*/
16239BUILDIN_FUNC(readbook)
16240{
16241 struct map_session_data *sd;
16242 int book_id, page;
16243
16244 if( (sd = script_rid2sd(st)) == NULL )
16245 return 0;
16246
16247 book_id = script_getnum(st,2);
16248 page = script_getnum(st,3);
16249
16250 clif_readbook(sd->fd, book_id, page);
16251 return 0;
16252}
16253
16254// Addons from Terra
16255BUILDIN_FUNC(strcmpi)
16256{
16257 const char *str1, *str2;
16258
16259 str1 = script_getstr(st,2);
16260 str2 = script_getstr(st,3);
16261
16262 script_pushint(st,strcmpi(str1, str2));
16263
16264 return 0;
16265}
16266
16267BUILDIN_FUNC(chatmessage)
16268{
16269 const char *str;
16270 int color, channel;
16271
16272 if( !battle_config.channel_system_enable )
16273 return 0;
16274
16275 str = script_getstr(st,2); // Mensaje
16276 channel = script_getnum(st,3); // Canal
16277 color = script_getnum(st,4); // Color
16278
16279 switch( channel )
16280 {
16281 case CHN_MAIN: clif_channel_message(server_channel[CHN_MAIN], str, color); break;
16282 case CHN_VENDING: clif_channel_message(server_channel[CHN_VENDING], str, color); break;
16283 case CHN_BATTLEGROUND: clif_channel_message(server_channel[CHN_BATTLEGROUND], str, color); break;
16284 }
16285 return 0;
16286}
16287
16288BUILDIN_FUNC(flooritem)
16289{
16290 struct map_session_data *sd = script_rid2sd(st);
16291 struct item_data *item_data;
16292 int nameid, amount;
16293
16294 if( sd == NULL ) return 0;
16295
16296 nameid = script_getnum(st,2);
16297 if( (item_data = itemdb_search(nameid)) == NULL )
16298 return 0;
16299
16300 amount = script_getnum(st,3);
16301 if( amount <= 0 )
16302 return 0;
16303
16304 map_addflooritem_area(&sd->bl, 0, 0, 0, nameid, amount);
16305 return 0;
16306}
16307
16308BUILDIN_FUNC(flooritem2xy)
16309{
16310 struct item_data *item_data;
16311 int nameid, amount, m, x, y;
16312 const char *mapname;
16313
16314 mapname = script_getstr(st,2);
16315 if( (m = map_mapname2mapid(mapname)) < 0 )
16316 return 0;
16317
16318 x = script_getnum(st,3);
16319 y = script_getnum(st,4);
16320 nameid = script_getnum(st,5);
16321 if( (item_data = itemdb_search(nameid)) == NULL )
16322 return 0;
16323
16324 amount = script_getnum(st,6);
16325 if( amount < 1 )
16326 return 0;
16327
16328 map_addflooritem_area(NULL, m, x, y, nameid, amount);
16329 return 0;
16330}
16331
16332/*==========================================
16333 * killslaves [Zephyrus]
16334 *------------------------------------------*/
16335int script_deleteslave_sub(struct block_list *bl, va_list ap)
16336{
16337 struct mob_data *md;
16338 int id;
16339
16340 nullpo_ret(bl);
16341 nullpo_ret(ap);
16342 nullpo_ret(md = (struct mob_data *)bl);
16343
16344 id = va_arg(ap,int);
16345 if( md->master_id > 0 && md->master_id == id )
16346 status_kill(bl);
16347
16348 return 0;
16349}
16350
16351BUILDIN_FUNC(killslaves)
16352{
16353 struct map_session_data *sd = script_rid2sd(st);
16354 if( sd == NULL ) return 0;
16355
16356 map_foreachinmap(script_deleteslave_sub, sd->bl.m, BL_MOB, sd->bl.id);
16357
16358 return 0;
16359}
16360
16361BUILDIN_FUNC(class2ancientwoe)
16362{
16363 struct map_session_data *sd;
16364
16365 sd = script_rid2sd(st);
16366
16367 if( sd && pc_class2ancientwoe(sd->status.class_) && !sd->md )
16368 script_pushint(st,1); // Cannot Access Ancient WoE with Mercenaries
16369 else
16370 script_pushint(st,0);
16371
16372 return 0;
16373}
16374
16375/*==========================================
16376 * partyitem <item id>,<amount>;
16377 *------------------------------------------*/
16378BUILDIN_FUNC(partyitem)
16379{
16380 int nameid,amount,i,flag;
16381 struct item_data *item_data;
16382 struct item item_tmp;
16383 struct map_session_data *sd = script_rid2sd(st);
16384 struct party_data *p;
16385
16386 if( sd == NULL ) return 0;
16387
16388 nameid = script_getnum(st,2);
16389 if( (item_data = itemdb_search(nameid)) == NULL )
16390 return 0;
16391
16392 amount = script_getnum(st,3);
16393 if( amount <= 0 )
16394 return 0;
16395
16396 memset(&item_tmp,0,sizeof(item_tmp));
16397 item_tmp.nameid = nameid;
16398 item_tmp.identify = 1;
16399 item_tmp.amount = 1;
16400
16401 if( (p = party_search(sd->status.party_id)) == NULL )
16402 { // No party
16403 if( (flag = pc_additem(sd,&item_tmp,amount,LOG_TYPE_SCRIPT)) )
16404 {
16405 clif_additem(sd,0,0,flag);
16406 if( pc_candrop(sd,&item_tmp) )
16407 map_addflooritem(&item_tmp,amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0);
16408 }
16409
16410 return 0;
16411 }
16412
16413 // Party Share
16414 for( i = 0; i < amount; i++ )
16415 {
16416 if( (flag = party_share_loot(p,sd,&item_tmp,sd->status.char_id)) )
16417 {
16418 clif_additem(sd,0,0,flag);
16419 if( pc_candrop(sd,&item_tmp) )
16420 map_addflooritem(&item_tmp,amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0);
16421 }
16422 }
16423
16424 return 0;
16425}
16426
16427/******************
16428Questlog script commands
16429*******************/
16430
16431BUILDIN_FUNC(setquest)
16432{
16433 TBL_PC * sd = script_rid2sd(st);
16434
16435 quest_add(sd, script_getnum(st, 2));
16436 return 0;
16437}
16438
16439BUILDIN_FUNC(erasequest)
16440{
16441 TBL_PC * sd = script_rid2sd(st);
16442
16443 quest_delete(sd, script_getnum(st, 2));
16444 return 0;
16445}
16446
16447BUILDIN_FUNC(completequest)
16448{
16449 TBL_PC * sd = script_rid2sd(st);
16450
16451 quest_update_status(sd, script_getnum(st, 2), Q_COMPLETE);
16452 return 0;
16453}
16454
16455BUILDIN_FUNC(changequest)
16456{
16457 TBL_PC * sd = script_rid2sd(st);
16458
16459 quest_change(sd, script_getnum(st, 2),script_getnum(st, 3));
16460 return 0;
16461}
16462
16463BUILDIN_FUNC(checkquest)
16464{
16465 TBL_PC * sd = script_rid2sd(st);
16466 quest_check_type type = HAVEQUEST;
16467
16468 if( script_hasdata(st, 3) )
16469 type = (quest_check_type)script_getnum(st, 3);
16470
16471 script_pushint(st, quest_check(sd, script_getnum(st, 2), type));
16472
16473 return 0;
16474}
16475
16476BUILDIN_FUNC(showevent)
16477{
16478 TBL_PC *sd = script_rid2sd(st);
16479 struct npc_data *nd = map_id2nd(st->oid);
16480 int state, color;
16481
16482 if( sd == NULL || nd == NULL )
16483 return 0;
16484 state = script_getnum(st, 2);
16485 color = script_getnum(st, 3);
16486
16487 if( color < 0 || color > 4 )
16488 color = 0; // set default color
16489
16490 clif_quest_show_event(sd, &nd->bl, state, color);
16491 return 0;
16492}
16493
16494/*==========================================
16495 * BattleGround System
16496 *------------------------------------------*/
16497BUILDIN_FUNC(map_logincount)
16498{
16499 const char *var = script_getstr(st,2);
16500 struct map_session_data *sd = script_rid2sd(st);
16501 int i = 0, m;
16502
16503 if( sd && (m = map_mapname2mapid(var)) >= 0 )
16504 {
16505 struct map_session_data* pl_sd;
16506 struct s_mapiterator* iter;
16507
16508 iter = mapit_getallusers();
16509 for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
16510 {
16511 if( pl_sd->bl.m != m )
16512 continue;
16513 if( session[sd->fd]->client_addr == session[pl_sd->fd]->client_addr )
16514 i++;
16515 }
16516 mapit_free(iter);
16517 }
16518
16519 script_pushint(st,i);
16520 return 0;
16521}
16522
16523BUILDIN_FUNC(bg_logincount)
16524{
16525 struct map_session_data *sd = script_rid2sd(st);
16526 int i = 0;
16527
16528 if( sd )
16529 i = battleground_countlogin(sd,true);
16530
16531 script_pushint(st,i);
16532 return 0;
16533}
16534
16535BUILDIN_FUNC(bg_team_create)
16536{
16537 const char *map_name, *ev = "", *dev = "";
16538 int x, y, mapindex = 0, guild_index, bg_id;
16539
16540 map_name = script_getstr(st,2);
16541 if( strcmp(map_name,"-") != 0 && (mapindex = mapindex_name2id(map_name)) == 0 )
16542 {
16543 script_pushint(st,0);
16544 return 0;
16545 }
16546
16547 x = script_getnum(st,3);
16548 y = script_getnum(st,4);
16549 guild_index = script_getnum(st,5);
16550 ev = script_getstr(st,6); // Logout Event
16551 dev = script_getstr(st,7); // Die Event
16552
16553 guild_index = cap_value(guild_index, 0, 12);
16554 bg_id = bg_create(mapindex, x, y, guild_index, ev, dev);
16555
16556 script_pushint(st,bg_id);
16557 return 0;
16558}
16559
16560// Creates a Queue
16561// bg_queue_create "Queue Name","On Join Event",min_level;
16562
16563BUILDIN_FUNC(bg_queue_create)
16564{
16565 const char *queue_name, *jev;
16566 int q_id, min_level = 0;
16567
16568 queue_name = script_getstr(st,2);
16569 jev = script_getstr(st,3);
16570 if( script_hasdata(st,4) )
16571 min_level = script_getnum(st,4);
16572
16573 q_id = queue_create(queue_name,jev,min_level);
16574 script_pushint(st,q_id);
16575 return 0;
16576}
16577
16578// Changes the Queue's Join Event.
16579// bg_queue_event queue_id,"On Join Event";
16580
16581BUILDIN_FUNC(bg_queue_event)
16582{
16583 struct queue_data *qd;
16584 const char *jev;
16585 int q_id;
16586
16587 q_id = script_getnum(st,2);
16588 if( (qd = queue_search(q_id)) == NULL )
16589 return 0;
16590
16591 jev = script_getstr(st,3);
16592 safestrncpy(qd->join_event, jev, sizeof(qd->join_event));
16593 return 0;
16594}
16595
16596// Joins a Queue
16597// bg_queue_join queue_id;
16598
16599BUILDIN_FUNC(bg_queue_join)
16600{
16601 int q_id;
16602 struct map_session_data *sd = script_rid2sd(st);
16603 if( !sd ) return 0;
16604
16605 q_id = script_getnum(st,2);
16606 queue_join(sd,q_id);
16607 return 0;
16608}
16609
16610// Party Joins a Queue
16611// bg_queue_partyjoin party_id,queue_id;
16612
16613BUILDIN_FUNC(bg_queue_partyjoin)
16614{
16615 int q_id, i, party_id;
16616 struct map_session_data *sd;
16617 struct party_data *p;
16618
16619 party_id = script_getnum(st,2);
16620 if( !party_id || (p = party_search(party_id)) == NULL ) return 0;
16621
16622 q_id = script_getnum(st,3);
16623 if( !queue_search(q_id) ) return 0;
16624
16625 for( i = 0; i < MAX_PARTY; i++ )
16626 {
16627 if( (sd = p->data[i].sd) == NULL )
16628 continue;
16629 queue_join(sd,q_id);
16630 }
16631
16632 return 0;
16633}
16634
16635// Leaves a Queue
16636// bg_queue_leave queue_id;
16637
16638BUILDIN_FUNC(bg_queue_leave)
16639{
16640 int q_id;
16641 struct map_session_data *sd = script_rid2sd(st);
16642 if( !sd ) return 0;
16643
16644 q_id = script_getnum(st,2);
16645 queue_leave(sd,q_id);
16646 return 0;
16647}
16648
16649// Request Information from a Queue
16650// bg_queue_data queue_id,type;
16651
16652BUILDIN_FUNC(bg_queue_data)
16653{
16654 struct queue_data *qd;
16655 int q_id = script_getnum(st,2),
16656 type = script_getnum(st,3);
16657
16658 if( (qd = queue_search(q_id)) == NULL )
16659 {
16660 script_pushint(st,0);
16661 return 0;
16662 }
16663
16664 switch( type )
16665 {
16666 case 0: script_pushint(st,qd->users); break;
16667 case 1: // User List
16668 {
16669 int j = 0;
16670 struct map_session_data *sd;
16671 struct queue_member *head;
16672 head = qd->first;
16673 while( head )
16674 {
16675 if( (sd = head->sd) != NULL )
16676 {
16677 mapreg_setregstr(reference_uid(add_str("$@qmembers$"),j),sd->status.name);
16678 j++;
16679 }
16680 head = head->next;
16681 }
16682 script_pushint(st,j);
16683 }
16684 break;
16685 default:
16686 ShowError("script:bg_queue_data: unknown data identifier %d\n", type);
16687 break;
16688 }
16689
16690 return 0;
16691}
16692
16693// Creates a Team from a BG Queue
16694// bg_queue2team queue_id,max2join,"mapname",x,y,guild_index,"Logout Event","Die Event";
16695
16696BUILDIN_FUNC(bg_queue2team)
16697{
16698 struct queue_data *qd;
16699 struct queue_member *qm;
16700 const char *map_name, *ev = "", *dev = "";
16701 int q_id, max, x, y, i, mapindex = 0, guild_index, bg_id;
16702
16703 q_id = script_getnum(st,2);
16704 if( (qd = queue_search(q_id)) == NULL )
16705 {
16706 script_pushint(st,0);
16707 return 0;
16708 }
16709
16710 max = script_getnum(st,3);
16711 map_name = script_getstr(st,4);
16712
16713 if( strcmp(map_name,"-") != 0 && (mapindex = mapindex_name2id(map_name)) == 0 )
16714 {
16715 script_pushint(st,0);
16716 return 0;
16717 }
16718
16719 x = script_getnum(st,5);
16720 y = script_getnum(st,6);
16721 guild_index = script_getnum(st,7);
16722 ev = script_getstr(st,8); // Logout Event
16723 dev = script_getstr(st,9); // Die Event
16724
16725 guild_index = cap_value(guild_index, 0, 12);
16726 if( (bg_id = bg_create(mapindex, x, y, guild_index, ev, dev)) == 0 )
16727 { // Creation failed
16728 script_pushint(st,0);
16729 return 0;
16730 }
16731
16732 i = 0; // Counter
16733 while( (qm = qd->first) != NULL && i < max && i < MAX_BG_MEMBERS )
16734 {
16735 if( qm->sd && bg_team_join(bg_id, qm->sd) )
16736 {
16737 mapreg_setreg(reference_uid(add_str("$@arenamembers"), i), qm->sd->bl.id);
16738 queue_member_remove(qd,qm->sd->bl.id);
16739 i++;
16740 }
16741 else break; // Failed? Should not. Anyway, to avoid a infinite loop
16742 }
16743
16744 mapreg_setreg(add_str("$@arenamembersnum"), i);
16745 script_pushint(st,bg_id);
16746 return 0;
16747}
16748
16749// Joins the first player from the queue to the given team and warp him.
16750// bg_queue2team_single queue_id,bg_id,"mapname",x,y;
16751
16752BUILDIN_FUNC(bg_queue2team_single)
16753{
16754 const char* map_name;
16755 struct queue_data *qd;
16756 struct map_session_data *sd;
16757 int x, y, mapindex, bg_id, q_id;
16758
16759 q_id = script_getnum(st,2);
16760 if( (qd = queue_search(q_id)) == NULL || !qd->first || !qd->first->sd )
16761 return 0;
16762
16763 bg_id = script_getnum(st,3);
16764 map_name = script_getstr(st,4);
16765 if( (mapindex = mapindex_name2id(map_name)) == 0 )
16766 return 0; // Invalid Map
16767 x = script_getnum(st,5);
16768 y = script_getnum(st,6);
16769 sd = qd->first->sd;
16770
16771 if( bg_team_join(bg_id,sd) )
16772 {
16773 queue_member_remove(qd,sd->bl.id);
16774 pc_setpos(sd,mapindex,x,y,CLR_TELEPORT);
16775 }
16776
16777 return 0;
16778}
16779
16780// Check if the given BG queue can start a BG in the given Mode
16781// bg_queue_checkstart queue_id,type,teams,required min players;
16782
16783BUILDIN_FUNC(bg_queue_checkstart)
16784{
16785 int q_id, result = 0;
16786 struct queue_data *qd;
16787
16788 q_id = script_getnum(st,2);
16789 if( (qd = queue_search(q_id)) != NULL )
16790 {
16791 int type, req_min, teams;
16792
16793 type = script_getnum(st,3);
16794 teams = script_getnum(st,4);
16795 req_min = script_getnum(st,5);
16796
16797 switch( type )
16798 {
16799 case 0: // Lineal, as they Join
16800 case 1: // Random
16801 case 2: // Class Balance
16802 if( qd->users >= (req_min * teams) )
16803 result = 1;
16804 break;
16805 case 3: // Faction
16806 {
16807 int count[FACTION_MAX+1], factions = 0;
16808 struct queue_member *qm = qd->first;
16809 struct map_session_data *sd;
16810
16811 memset(count,0,sizeof(count));
16812 while( qm && (sd = qm->sd) != NULL && factions < teams )
16813 { // Faction Count
16814 count[sd->status.faction_id]++;
16815 if( count[sd->status.faction_id] == req_min )
16816 factions++;
16817 qm = qm->next;
16818 }
16819
16820 if( factions >= teams ) result = 1;
16821 }
16822 break;
16823 case 4: // BG Team Selected by Script
16824 {
16825 int count[3], teamcount = 0;
16826 struct queue_member *qm = qd->first;
16827 struct map_session_data *sd;
16828
16829 memset(count,0,sizeof(count));
16830 while( qm && (sd = qm->sd) != NULL && teamcount < teams )
16831 { // Faction Count
16832 count[sd->bg_team]++;
16833 // 0 - Traitors | 1 - Guillaume | 2 - Croix
16834 if( count[sd->bg_team] == req_min )
16835 teamcount++;
16836 qm = qm->next;
16837 }
16838
16839 if( teamcount >= teams ) result = 1;
16840 }
16841 break;
16842 default:
16843 result = 0;
16844 break;
16845 }
16846 }
16847
16848 script_pushint(st,result);
16849 return 0;
16850}
16851
16852// Build BG Teams from one Queue
16853// bg_queue2teams queue_id,maxplayersperteam,type,teamID1,teamID2...;
16854
16855BUILDIN_FUNC(bg_queue2teams)
16856{ // Send Users from Queue to Teams. Requires previously created teams.
16857 struct queue_data *qd;
16858 int i, j = 0, bg_id = 0, c = 0, q_id, min, max, type, limit = 0;
16859 struct map_session_data *sd;
16860
16861 q_id = script_getnum(st,2); // Queue ID
16862 if( (qd = queue_search(q_id)) == NULL )
16863 {
16864 ShowError("script:bg_queue2teams: Non existant queue id received %d.\n", q_id);
16865 return 0;
16866 }
16867
16868 min = script_getnum(st,3); // Min Members per Team
16869 max = script_getnum(st,4); // Max Members per Team
16870 type = script_getnum(st,5); // Team Building Method
16871
16872 i = 6; // Team ID's to build
16873 while( script_hasdata(st,i) )
16874 {
16875 bg_id = script_getnum(st,i);
16876 if( bg_team_search(bg_id) == NULL )
16877 {
16878 ShowError("script:bg_queue2teams: Non existant team id received %d.\n", bg_id);
16879 return 0;
16880 }
16881 i++;
16882 }
16883 c = i - 6;
16884
16885 if( c < 2 )
16886 {
16887 ShowError("script:bg_queue2teams: Less than 2 teams received to build members.\n");
16888 return 0;
16889 }
16890
16891 if( type < 3 )
16892 {
16893 limit = min(max * c,qd->users); // How many players are we going to take from the Queue
16894 if( battle_config.bg_queue2team_balanced )
16895 {
16896 limit -= limit % c; // Remove the remaining difference to balance teams
16897 max = limit / c;
16898 }
16899 else
16900 {
16901 max = (limit - (limit % c)) / c;
16902 if( limit % c > 0 ) max++; // Extra slot per team to add the remaining members
16903 }
16904 }
16905
16906 switch( type )
16907 {
16908 case 0: // Lineal - Maybe to keep party together
16909 for( i = 0; i < limit; i++ )
16910 {
16911 if( i % max == 0 )
16912 { // Switch Team
16913 bg_id = script_getnum(st,j+6);
16914 if( ++j >= c ) j = 0;
16915 }
16916
16917 if( !qd->first || (sd = qd->first->sd) == NULL )
16918 break; // No more people to join Teams
16919
16920 bg_team_join(bg_id,sd);
16921 queue_member_remove(qd,sd->bl.id);
16922 }
16923 break;
16924 case 1: // Random
16925 {
16926 int pos;
16927 struct queue_member *qm;
16928
16929 for( i = 0; i < limit; i++ )
16930 {
16931 if( i % max == 0 )
16932 { // Switch Team
16933 bg_id = script_getnum(st,j+6);
16934 if( ++j >= c ) j = 0;
16935 }
16936
16937 pos = 1 + rand() % (limit - i);
16938 if( (qm = queue_member_get(qd,pos)) == NULL || (sd = qm->sd) == NULL )
16939 break;
16940
16941 bg_team_join(bg_id,sd);
16942 queue_member_remove(qd,sd->bl.id);
16943 }
16944 }
16945 break;
16946 case 2: // Job Balance
16947 {
16948 struct queue_member *qm, *head, *previous, *first = NULL;
16949 int s_class, t_class;
16950
16951 // Building a Temporal Sorted by Class Queue
16952 i = 0;
16953 while( i < limit && (qm = qd->first) != NULL && (sd = qm->sd) != NULL )
16954 {
16955 qd->first = qd->first->next; // Move the queue head to the next pos
16956 qd->users--; // Reduces the amount of members on queue
16957 if( qm->next == NULL ) qd->last = NULL;
16958 qm->next = NULL;
16959 sd->qd = NULL;
16960
16961 // Plug qm into the temporal Queue
16962 head = first;
16963 previous = NULL;
16964 s_class = sd->class_&MAPID_UPPERMASK; // Current Member's Upper Class
16965
16966 while( head && head->sd && (s_class > (t_class = (head->sd->class_&MAPID_UPPERMASK)) || (s_class == t_class && sd->class_ > head->sd->class_)) )
16967 { // Search for Insert Position
16968 previous = head;
16969 head = head->next;
16970 }
16971
16972 qm->next = head;
16973 if( previous )
16974 previous->next = qm;
16975 else
16976 first = qm;
16977 }
16978
16979 // Update the Queue new positions
16980 i = 0;
16981 head = qd->first;
16982 while( head )
16983 {
16984 head->position = ++i;
16985 head = head->next;
16986 }
16987
16988 // Player distribution into Teams
16989 while( (head = first) != NULL && (sd = head->sd) != NULL )
16990 {
16991 bg_id = script_getnum(st,j+6);
16992 if( ++j >= c ) j = 0;
16993 bg_team_join(bg_id,sd);
16994
16995 first = first->next;
16996 aFree(head);
16997 }
16998 }
16999 break;
17000 case 3: // Faction Mode
17001 {
17002 bool faction[FACTION_MAX+1];
17003 int count[FACTION_MAX+1], factions = 0, k;
17004 struct queue_member *qm = qd->first;
17005 struct battleground_data *bg;
17006
17007 memset(count,0,sizeof(count));
17008 memset(faction,0,sizeof(faction));
17009
17010 while( qm && (sd = qm->sd) != NULL )
17011 { // Search the First Factions to Build Teams
17012 i = sd->status.faction_id;
17013 count[i]++;
17014
17015 if( count[i] == min && !faction[i] && factions < c )
17016 {
17017 faction[i] = true; // Tag this Faction
17018 factions++;
17019 }
17020
17021 qm = qm->next;
17022 }
17023
17024 if( factions < c ) break; // Should not happen if you use first bg_queue_checkstart
17025
17026 if( battle_config.bg_queue2team_balanced )
17027 {
17028 for( i = 0; i < FACTION_MAX+1; i++ )
17029 { // Set the Max per Team to be taken from the Queue
17030 if( !faction[i] ) continue; // Ignore this Faction.
17031 max = min(count[i],max);
17032 }
17033 }
17034
17035 for( i = 0; i < FACTION_MAX+1; i++ )
17036 {
17037 if( !faction[i] ) continue; // Ignore this Faction.
17038
17039 k = 0;
17040 bg_id = script_getnum(st,j+6);
17041 if( (bg = bg_team_search(bg_id)) != NULL ) bg->pf_id = i; // Faction ID stored for Balancing
17042 j++;
17043
17044 qm = qd->first;
17045 while( qm && (sd = qm->sd) != NULL && k < max )
17046 {
17047 qm = qm->next;
17048 if( sd->status.faction_id != i ) continue; // Not from this faction
17049 queue_member_remove(qd,sd->bl.id);
17050 bg_team_join(bg_id,sd);
17051 k++;
17052 }
17053 }
17054 }
17055 break;
17056 case 4: // BG Team Mode
17057 {
17058 bool team[3];
17059 int count[3], teams = 0, k;
17060 struct queue_member *qm = qd->first;
17061 struct battleground_data *bg;
17062
17063 memset(count,0,sizeof(count));
17064 memset(team,0,sizeof(team));
17065
17066 while( qm && (sd = qm->sd) != NULL )
17067 { // Search the First Teams to Build Teams
17068 i = sd->bg_team;
17069 count[i]++;
17070
17071 if( count[i] == min && !team[i] && teams < c )
17072 {
17073 team[i] = true; // Tag this Team.
17074 teams++;
17075 }
17076
17077 qm = qm->next;
17078 }
17079
17080 if( teams < c ) break; // Should not happen if you use first bg_queue_checkstart
17081
17082 if( battle_config.bg_queue2team_balanced )
17083 {
17084 for( i = 0; i < 3; i++ )
17085 { // Set the Max per Team to be taken from the Queue
17086 if( !team[i] ) continue; // Ignore this Team.
17087 max = min(count[i],max);
17088 }
17089 }
17090
17091 for( i = 0; i < 3; i++ )
17092 {
17093 if( !team[i] ) continue; // Ignore this Team.
17094
17095 k = 0;
17096 bg_id = script_getnum(st,j+6);
17097 if( (bg = bg_team_search(bg_id)) != NULL )
17098 {
17099 bg->pf_id = i; // Team ID stored for Balancing
17100 bg->g = &bg_guild[( !i ? 2 : i-1 )];
17101 bg->color = bg_colors[( !i ? 2 : i-1 )];
17102 }
17103 j++;
17104
17105 qm = qd->first;
17106 while( qm && (sd = qm->sd) != NULL && k < max )
17107 {
17108 qm = qm->next;
17109 if( sd->bg_team != i ) continue; // Not from this Team
17110 queue_member_remove(qd,sd->bl.id);
17111 bg_team_join(bg_id,sd);
17112 k++;
17113 }
17114 }
17115 }
17116 break;
17117 }
17118
17119 return 0;
17120}
17121
17122// Fill teams with members from the given Queue
17123// bg_balance_teams queue_id,maxplayersperteam,TeamID1,TeamID2,...;
17124
17125BUILDIN_FUNC(bg_balance_teams)
17126{
17127 struct queue_data *qd;
17128 struct queue_member *head;
17129 struct battleground_data *bg, *p_bg;
17130 int i, c, q_id, bg_id, m_bg_id = 0, max, min, type, bg_count[FACTION_MAX+1];
17131 struct map_session_data *sd;
17132 bool balanced, bg_faction[FACTION_MAX+1];
17133
17134 q_id = script_getnum(st,2);
17135 if( (qd = queue_search(q_id)) == NULL || qd->users <= 0 )
17136 return 0;
17137
17138 max = script_getnum(st,3);
17139 if( max > MAX_BG_MEMBERS ) max = MAX_BG_MEMBERS;
17140 min = MAX_BG_MEMBERS + 1;
17141 type = script_getnum(st,4);
17142
17143 i = 5; // Team ID's to build
17144 memset(bg_count,0,sizeof(bg_count));
17145 memset(bg_faction,0,sizeof(bg_faction));
17146
17147 while( script_hasdata(st,i) )
17148 {
17149 bg_id = script_getnum(st,i);
17150 if( (bg = bg_team_search(bg_id)) == NULL )
17151 {
17152 ShowError("script:bg_balance_teams: Non existant team id received %d.\n", bg_id);
17153 return 0;
17154 }
17155
17156 if( bg->count < min ) min = bg->count;
17157 if( type > 2 )
17158 {
17159 bg_count[bg->pf_id] = bg->count;
17160 bg_faction[bg->pf_id] = true;
17161 }
17162 i++;
17163 }
17164
17165 c = i - 5; // Teams Found
17166 if( c < 2 || min >= max ) return 0; // No Balance Required
17167
17168 if( type < 3 )
17169 {
17170 while( (head = qd->first) != NULL && (sd = head->sd) != NULL )
17171 {
17172 p_bg = NULL;
17173 balanced = true;
17174 min = MAX_BG_MEMBERS + 1;
17175
17176 // Search the Current Minimum and Balance status
17177 for( i = 0; i < c; i++ )
17178 {
17179 bg_id = script_getnum(st,i+5);
17180 if( (bg = bg_team_search(bg_id)) == NULL )
17181 break; // Should not happen. Teams already check
17182 if( p_bg && p_bg->count != bg->count )
17183 balanced = false; // Teams still with different member count
17184 if( bg->count < min )
17185 {
17186 m_bg_id = bg_id;
17187 min = bg->count;
17188 }
17189 p_bg = bg;
17190 }
17191
17192 if( min >= max ) break; // Balance completed
17193
17194 if( battle_config.bg_queue2team_balanced && balanced && qd->users < c )
17195 break; // No required users on queue to keep balance
17196
17197 bg_team_join(m_bg_id,sd);
17198 queue_member_remove(qd,sd->bl.id);
17199 if( (bg = bg_team_search(m_bg_id)) != NULL && bg->mapindex )
17200 pc_setpos(sd,bg->mapindex,bg->x,bg->y,CLR_OUTSIGHT); // Joins and Warps
17201 }
17202 }
17203 else if( type == 3 )
17204 {
17205 int fd_count[FACTION_MAX+1], j;
17206 memset(fd_count,0,sizeof(fd_count));
17207
17208 head = qd->first;
17209 while( head && (sd = head->sd) != NULL )
17210 {
17211 fd_count[sd->status.faction_id]++;
17212 head = head->next;
17213 }
17214
17215 min = MAX_BG_MEMBERS + 1;
17216 for( i = 0; i < FACTION_MAX+1; i++ )
17217 {
17218 if( !bg_faction[i] ) continue; // Faction not present on the BG teams.
17219 if( (fd_count[i] + bg_count[i]) > max ) fd_count[i] = max - bg_count[i];
17220 if( battle_config.bg_queue2team_balanced && min < (fd_count[i] + bg_count[i]) ) min = fd_count[i] + bg_count[i];
17221 }
17222
17223 // Balancing - Limit to the minimum possible
17224 if( battle_config.bg_queue2team_balanced )
17225 {
17226 for( i = 0; i < FACTION_MAX+1; i++ )
17227 {
17228 if( !bg_faction[i] ) continue; // Faction not present on the BG teams.
17229 if( (fd_count[i] + bg_count[i]) > min ) fd_count[i] = min - bg_count[i];
17230 }
17231 }
17232
17233 // Fill Teams
17234 for( i = 0; i < c; i++ )
17235 {
17236 bg_id = script_getnum(st,i+5);
17237 if( (bg = bg_team_search(bg_id)) == NULL || fd_count[bg->pf_id] <= 0 )
17238 continue; // Nothing to Add here
17239
17240 j = 0;
17241 head = qd->first;
17242 while( head && (sd = head->sd) != NULL && j < fd_count[bg->pf_id] )
17243 {
17244 head = head->next;
17245 if( sd->status.faction_id != bg->pf_id ) continue;
17246 queue_member_remove(qd,sd->bl.id);
17247 bg_team_join(bg_id,sd);
17248 j++;
17249 }
17250 }
17251 }
17252 else if( type == 4 )
17253 {
17254 int td_count[3], j;
17255 memset(td_count,0,sizeof(td_count));
17256
17257 head = qd->first;
17258 while( head && (sd = head->sd) != NULL )
17259 {
17260 td_count[sd->bg_team]++;
17261 head = head->next;
17262 }
17263
17264 min = MAX_BG_MEMBERS + 1;
17265 for( i = 0; i < 3; i++ )
17266 {
17267 if( !bg_faction[i] ) continue; // Team not present on the BG teams.
17268 if( (td_count[i] + bg_count[i]) > max ) td_count[i] = max - bg_count[i];
17269 if( battle_config.bg_queue2team_balanced && min < (td_count[i] + bg_count[i]) ) min = td_count[i] + bg_count[i];
17270 }
17271
17272 // Balancing - Limit to the minimum possible
17273 if( battle_config.bg_queue2team_balanced )
17274 {
17275 for( i = 0; i < 3; i++ )
17276 {
17277 if( !bg_faction[i] ) continue; // Team not present on the BG teams.
17278 if( (td_count[i] + bg_count[i]) > min ) td_count[i] = min - bg_count[i];
17279 }
17280 }
17281
17282 // Fill Teams
17283 for( i = 0; i < c; i++ )
17284 {
17285 bg_id = script_getnum(st,i+5);
17286 if( (bg = bg_team_search(bg_id)) == NULL || td_count[bg->pf_id] <= 0 )
17287 continue; // Nothing to Add here
17288
17289 j = 0;
17290 head = qd->first;
17291 while( head && (sd = head->sd) != NULL && j < td_count[bg->pf_id] )
17292 {
17293 head = head->next;
17294 if( sd->bg_team != bg->pf_id ) continue;
17295 queue_member_remove(qd,sd->bl.id);
17296 bg_team_join(bg_id,sd);
17297 j++;
17298 }
17299 }
17300 }
17301
17302 return 0;
17303}
17304
17305BUILDIN_FUNC(waitingroom2bg)
17306{
17307 struct npc_data *nd;
17308 struct chat_data *cd;
17309 const char *map_name, *ev = "", *dev = "";
17310 int x, y, i, mapindex = 0, guild_index, bg_id;
17311 struct map_session_data *sd;
17312
17313 nd = (struct npc_data *)map_id2bl(st->oid);
17314 if( nd == NULL || (cd = (struct chat_data *)map_id2bl(nd->chat_id)) == NULL )
17315 {
17316 script_pushint(st,0);
17317 return 0;
17318 }
17319
17320 map_name = script_getstr(st,2);
17321 if( strcmp(map_name,"-") != 0 && (mapindex = mapindex_name2id(map_name)) == 0 )
17322 {
17323 script_pushint(st,0);
17324 return 0;
17325 }
17326
17327 x = script_getnum(st,3);
17328 y = script_getnum(st,4);
17329 guild_index = script_getnum(st,5);
17330 ev = script_getstr(st,6); // Logout Event
17331 dev = script_getstr(st,7); // Die Event
17332
17333 guild_index = cap_value(guild_index, 0, 12);
17334 if( (bg_id = bg_create(mapindex, x, y, guild_index, ev, dev)) == 0 )
17335 { // Creation failed
17336 script_pushint(st,0);
17337 return 0;
17338 }
17339
17340 for( i = 0; i < cd->users && i < MAX_BG_MEMBERS; i++ )
17341 {
17342 if( (sd = cd->usersd[i]) != NULL && bg_team_join(bg_id, sd) )
17343 mapreg_setreg(reference_uid(add_str("$@arenamembers"), i), sd->bl.id);
17344 else
17345 mapreg_setreg(reference_uid(add_str("$@arenamembers"), i), 0);
17346 }
17347
17348 mapreg_setreg(add_str("$@arenamembersnum"), i);
17349 script_pushint(st,bg_id);
17350 return 0;
17351}
17352
17353BUILDIN_FUNC(waitingroom2bg_single)
17354{
17355 const char* map_name;
17356 struct npc_data *nd;
17357 struct chat_data *cd;
17358 struct map_session_data *sd;
17359 int x, y, mapindex, bg_id;
17360
17361 bg_id = script_getnum(st,2);
17362 map_name = script_getstr(st,3);
17363 if( (mapindex = mapindex_name2id(map_name)) == 0 )
17364 return 0; // Invalid Map
17365
17366 x = script_getnum(st,4);
17367 y = script_getnum(st,5);
17368 nd = npc_name2id(script_getstr(st,6));
17369
17370 if( nd == NULL || (cd = (struct chat_data *)map_id2bl(nd->chat_id)) == NULL || cd->users <= 0 )
17371 return 0;
17372
17373 if( (sd = cd->usersd[0]) == NULL )
17374 return 0;
17375
17376 if( bg_team_join(bg_id, sd) )
17377 {
17378 pc_setpos(sd, mapindex, x, y, CLR_TELEPORT);
17379 script_pushint(st,1);
17380 }
17381 else
17382 script_pushint(st,0);
17383
17384 return 0;
17385}
17386
17387BUILDIN_FUNC(bg_team_setxy)
17388{
17389 struct battleground_data *bg;
17390 int bg_id;
17391
17392 bg_id = script_getnum(st,2);
17393 if( (bg = bg_team_search(bg_id)) == NULL )
17394 return 0;
17395
17396 bg->x = script_getnum(st,3);
17397 bg->y = script_getnum(st,4);
17398 return 0;
17399}
17400
17401BUILDIN_FUNC(bg_team_reveal)
17402{
17403 struct battleground_data *bg;
17404 int bg_id;
17405
17406 bg_id = script_getnum(st,2);
17407 if( (bg = bg_team_search(bg_id)) == NULL )
17408 return 0;
17409
17410 bg->reveal_pos = true; // Reveal Position Mode
17411 return 0;
17412}
17413
17414BUILDIN_FUNC(bg_team_setquest)
17415{
17416 struct battleground_data *bg;
17417 struct map_session_data *sd;
17418 int i, bg_id, quest;
17419
17420 bg_id = script_getnum(st,2);
17421 quest = script_getnum(st,3);
17422
17423 if( bg_id == 0 || (bg = bg_team_search(bg_id)) == NULL )
17424 return 0;
17425
17426 for( i = 0; i < MAX_BG_MEMBERS; i++ )
17427 {
17428 if( (sd = bg->members[i].sd) == NULL )
17429 continue;
17430 quest_add(sd,quest);
17431 }
17432 return 0;
17433}
17434
17435BUILDIN_FUNC(bg_warp)
17436{
17437 int x, y, mapindex, bg_id;
17438 const char* map_name;
17439
17440 bg_id = script_getnum(st,2);
17441 map_name = script_getstr(st,3);
17442 if( !strcmp(map_name,"RespawnPoint") )
17443 mapindex = 0;
17444 else if( (mapindex = mapindex_name2id(map_name)) == 0 )
17445 return 0; // Invalid Map
17446 x = script_getnum(st,4);
17447 y = script_getnum(st,5);
17448 bg_team_warp(bg_id, mapindex, x, y);
17449 return 0;
17450}
17451
17452BUILDIN_FUNC(bg_monster)
17453{
17454 int class_ = 0, x = 0, y = 0, bg_id = 0;
17455 const char *str,*map, *evt="";
17456
17457 bg_id = script_getnum(st,2);
17458 map = script_getstr(st,3);
17459 x = script_getnum(st,4);
17460 y = script_getnum(st,5);
17461 str = script_getstr(st,6);
17462 class_ = script_getnum(st,7);
17463 if( script_hasdata(st,8) ) evt = script_getstr(st,8);
17464 check_event(st, evt);
17465 script_pushint(st, mob_spawn_bg(map,x,y,str,class_,evt,bg_id));
17466 return 0;
17467}
17468
17469BUILDIN_FUNC(bg_monster_reveal)
17470{
17471 struct mob_data *md;
17472 struct block_list *mbl;
17473 int id = script_getnum(st,2),
17474 flag = script_getnum(st,3),
17475 color = script_getnum(st,4);
17476
17477 if( id == 0 || (mbl = map_id2bl(id)) == NULL || mbl->type != BL_MOB )
17478 return 0;
17479 md = (TBL_MOB *)mbl;
17480 map_foreachinmap(viewpointmap_sub,mbl->m,BL_PC,st->oid,flag,mbl->x,mbl->y,mbl->id,color);
17481 return 0;
17482}
17483
17484BUILDIN_FUNC(bg_monster_set_team)
17485{
17486 struct mob_data *md;
17487 struct block_list *mbl;
17488 int id = script_getnum(st,2),
17489 bg_id = script_getnum(st,3);
17490
17491 if( id == 0 || (mbl = map_id2bl(id)) == NULL || mbl->type != BL_MOB )
17492 return 0;
17493 md = (TBL_MOB *)mbl;
17494 md->bg_id = bg_id;
17495
17496 mob_stop_attack(md);
17497 mob_stop_walking(md, 0);
17498 md->target_id = md->attacked_id = 0;
17499 clif_mobnameack(NULL, md, 0);
17500 return 0;
17501}
17502
17503BUILDIN_FUNC(bg_monster_inmunity)
17504{
17505 struct mob_data *md;
17506 struct block_list *mbl;
17507 int id = script_getnum(st,2),
17508 flag = script_getnum(st,3);
17509
17510 if( id == 0 || (mbl = map_id2bl(id)) == NULL || mbl->type != BL_MOB )
17511 return 0;
17512
17513 md = (TBL_MOB *)mbl;
17514 md->state.inmunity = flag;
17515 return 0;
17516}
17517
17518BUILDIN_FUNC(bg_leave)
17519{
17520 struct map_session_data *sd = script_rid2sd(st);
17521 if( sd == NULL || !sd->bg_id )
17522 return 0;
17523
17524 bg_team_leave(sd,0);
17525 return 0;
17526}
17527
17528static int bg_cleanmap_sub(struct block_list *bl, va_list ap)
17529{
17530 nullpo_ret(bl);
17531 map_clearflooritem(bl->id);
17532
17533 return 0;
17534}
17535
17536BUILDIN_FUNC(bg_cleanmap)
17537{
17538 const char* map_name;
17539 int m;
17540
17541 map_name = script_getstr(st,3);
17542 m = map_mapname2mapid(map_name);
17543
17544 map_foreachinmap(bg_cleanmap_sub,m,BL_ITEM);
17545 return 0;
17546}
17547
17548BUILDIN_FUNC(bg_destroy)
17549{
17550 int bg_id = script_getnum(st,2);
17551 bg_team_clean(bg_id, true);
17552 return 0;
17553}
17554
17555BUILDIN_FUNC(bg_clean)
17556{
17557 int bg_id = script_getnum(st,2);
17558 bg_team_clean(bg_id, false);
17559 return 0;
17560}
17561
17562BUILDIN_FUNC(bg_getareausers)
17563{
17564 const char *str;
17565 int m, x0, y0, x1, y1, bg_id;
17566 int i = 0, c = 0;
17567 struct battleground_data *bg = NULL;
17568 struct map_session_data *sd;
17569
17570 bg_id = script_getnum(st,2);
17571 str = script_getstr(st,3);
17572
17573 if( (bg = bg_team_search(bg_id)) == NULL || (m = map_mapname2mapid(str)) < 0 )
17574 {
17575 script_pushint(st,0);
17576 return 0;
17577 }
17578
17579 x0 = script_getnum(st,4);
17580 y0 = script_getnum(st,5);
17581 x1 = script_getnum(st,6);
17582 y1 = script_getnum(st,7);
17583
17584 for( i = 0; i < MAX_BG_MEMBERS; i++ )
17585 {
17586 if( (sd = bg->members[i].sd) == NULL )
17587 continue;
17588 if( sd->bl.m != m || sd->bl.x < x0 || sd->bl.y < y0 || sd->bl.x > x1 || sd->bl.y > y1 )
17589 continue;
17590 c++;
17591 }
17592
17593 script_pushint(st,c);
17594 return 0;
17595}
17596
17597BUILDIN_FUNC(bg_updatescore)
17598{
17599 const char *str;
17600 int m;
17601
17602 str = script_getstr(st,2);
17603 if( (m = map_mapname2mapid(str)) < 0 )
17604 return 0;
17605
17606 map[m].bgscore_lion = script_getnum(st,3);
17607 map[m].bgscore_eagle = script_getnum(st,4);
17608
17609 clif_bg_updatescore(m);
17610 return 0;
17611}
17612
17613BUILDIN_FUNC(bg_team_updatescore)
17614{
17615 struct battleground_data *bg;
17616 int bg_id = script_getnum(st,2),
17617 score = script_getnum(st,3);
17618
17619 if( (bg = bg_team_search(bg_id)) != NULL )
17620 {
17621 bg->team_score = score;
17622 clif_bg_updatescore_team(bg);
17623 }
17624
17625 return 0;
17626}
17627
17628BUILDIN_FUNC(bg_team_guildid)
17629{
17630 struct battleground_data *bg;
17631 int bg_id = script_getnum(st,2),
17632 guild_id = 0;
17633
17634 if( (bg = bg_team_search(bg_id)) != NULL && bg->g )
17635 guild_id = bg->g->guild_id;
17636
17637 script_pushint(st,guild_id);
17638 return 0;
17639}
17640
17641BUILDIN_FUNC(bg_get_data)
17642{
17643 struct battleground_data *bg;
17644 int bg_id = script_getnum(st,2),
17645 type = script_getnum(st,3);
17646
17647 if( (bg = bg_team_search(bg_id)) == NULL )
17648 {
17649 script_pushint(st,0);
17650 return 0;
17651 }
17652
17653 switch( type )
17654 {
17655 case 0: script_pushint(st, bg->count); break;
17656 case 1: // Users and List
17657 {
17658 int i, j = 0;
17659 struct map_session_data *sd;
17660 for( i = 0; i < bg->count; i++ )
17661 {
17662 if( (sd = bg->members[i].sd) == NULL )
17663 continue;
17664 mapreg_setregstr(reference_uid(add_str("$@bgmembers$"),j),sd->status.name);
17665 j++;
17666 }
17667 script_pushint(st, j);
17668 }
17669 break;
17670 case 2:
17671 script_pushconststr(st,bg->g ? bg->g->name : "null");
17672 break;
17673 case 3:
17674 script_pushconststr(st,bg->g ? bg->g->master : "null");
17675 break;
17676 case 4:
17677 script_pushint(st,bg->color);
17678 break;
17679
17680 default:
17681 ShowError("script:bg_get_data: unknown data identifier %d\n", type);
17682 break;
17683 }
17684
17685 return 0;
17686}
17687
17688BUILDIN_FUNC(bg_rankpoints)
17689{
17690 struct map_session_data *sd;
17691 struct battleground_data *bg;
17692 const char *type;
17693 int i, add_value, flag;
17694
17695 if( script_hasdata(st,4) )
17696 sd = map_id2sd(script_getnum(st,4));
17697 else
17698 sd = script_rid2sd(st);
17699
17700 if( sd == NULL )
17701 return 0;
17702
17703 if( !sd->bg_id || (bg = bg_team_search(sd->bg_id)) == NULL )
17704 return 0;
17705 ARR_FIND(0,MAX_BG_MEMBERS,i,bg->members[i].sd == sd);
17706 if( i >= MAX_BG_MEMBERS )
17707 return 0;
17708
17709 flag = bg->members[i].ranked ? 2 : 3;
17710 type = script_getstr(st,2);
17711 add_value = script_getnum(st,3);
17712
17713 // Just +1 Fame Point
17714 if( !strcmpi(type,"fame") )
17715 pc_addfame(sd,add_value,flag);
17716 // Normal Ranking actions
17717 else if( !strcmpi(type,"skulls") )
17718 {
17719 add2limit(sd->status.bgstats.skulls,add_value,USHRT_MAX);
17720 achievement_validate_bg(sd,ATB_TI_SKULLS,add_value);
17721 pc_addfame(sd,2 * add_value,flag);
17722 }
17723 else if( !strcmpi(type,"eos_flags") )
17724 {
17725 add2limit(sd->status.bgstats.eos_flags,add_value,USHRT_MAX);
17726 achievement_validate_bg(sd,ATB_EOS_FLAGS,1);
17727 pc_addfame(sd,5,flag);
17728 }
17729 else if( !strcmpi(type,"sc_stole") )
17730 {
17731 pc_addfame(sd,1,flag);
17732 achievement_validate_bg(sd,ATB_SC_TAKE,1);
17733 add2limit(sd->status.bgstats.sc_stole,add_value,USHRT_MAX);
17734 }
17735 else if( !strcmpi(type,"sc_captured") )
17736 {
17737 add2limit(sd->status.bgstats.sc_captured,add_value,USHRT_MAX);
17738 achievement_validate_bg(sd,ATB_SC_CAPTURED,1);
17739 pc_addfame(sd,5,flag);
17740 }
17741 else if( !strcmpi(type,"sc_droped") )
17742 {
17743 add2limit(sd->status.bgstats.sc_droped,add_value,USHRT_MAX);
17744 achievement_validate_bg(sd,ATB_SC_DROP,1);
17745 }
17746 else if( !strcmpi(type,"ctf_taken") )
17747 {
17748 add2limit(sd->status.bgstats.ctf_taken,add_value,USHRT_MAX);
17749 achievement_validate_bg(sd,ATB_CTF_TAKE,1);
17750 pc_addfame(sd,1,flag);
17751 }
17752 else if( !strcmpi(type,"ctf_captured") )
17753 {
17754 add2limit(sd->status.bgstats.ctf_captured,add_value,USHRT_MAX);
17755 achievement_validate_bg(sd,ATB_CTF_CAPTURED,1);
17756 pc_addfame(sd,25,flag);
17757 }
17758 else if( !strcmpi(type,"ctf_droped") )
17759 {
17760 add2limit(sd->status.bgstats.ctf_droped,add_value,USHRT_MAX);
17761 achievement_validate_bg(sd,ATB_CTF_DROP,1);
17762 }
17763 else if( !strcmpi(type,"dom_off_kills") )
17764 {
17765 add2limit(sd->status.bgstats.dom_off_kills,add_value,USHRT_MAX);
17766 achievement_validate_bg(sd,ATB_DOM_OFFKILLS,1);
17767 }
17768 else if( !strcmpi(type,"dom_def_kills") )
17769 {
17770 add2limit(sd->status.bgstats.dom_def_kills,add_value,USHRT_MAX);
17771 achievement_validate_bg(sd,ATB_DOM_DEFKILLS,1);
17772 }
17773
17774 return 0;
17775}
17776
17777BUILDIN_FUNC(bg_rankpoints_area)
17778{
17779 const char *str, *type;
17780 int m, x0, y0, x1, y1, bg_id;
17781 int i = 0, add_value;
17782 int type_val;
17783 struct battleground_data *bg = NULL;
17784 struct map_session_data *sd;
17785
17786 bg_id = script_getnum(st,2);
17787 str = script_getstr(st,3);
17788
17789 if( (bg = bg_team_search(bg_id)) == NULL || (m = map_mapname2mapid(str)) < 0 )
17790 {
17791 script_pushint(st,0);
17792 return 0;
17793 }
17794
17795 x0 = script_getnum(st,4);
17796 y0 = script_getnum(st,5);
17797 x1 = script_getnum(st,6);
17798 y1 = script_getnum(st,7);
17799 type = script_getstr(st,8);
17800
17801 if( !strcmpi(type,"eos_bases") )
17802 type_val = 1;
17803 else if( !strcmpi(type,"dom_bases") )
17804 type_val = 2;
17805 else return 0; // Invalid Type
17806
17807 add_value = script_getnum(st,9);
17808
17809 for( i = 0; i < MAX_BG_MEMBERS; i++ )
17810 {
17811 if( (sd = bg->members[i].sd) == NULL )
17812 continue;
17813 if( sd->bl.m != m || sd->bl.x < x0 || sd->bl.y < y0 || sd->bl.x > x1 || sd->bl.y > y1 )
17814 continue;
17815
17816 switch( type_val )
17817 {
17818 case 1:
17819 add2limit(sd->status.bgstats.eos_bases,add_value,USHRT_MAX);
17820 achievement_validate_bg(sd,ATB_EOS_BASES,1);
17821 pc_addfame(sd,10,(bg->members[i].ranked ? 2 : 3));
17822 break;
17823 case 2:
17824 add2limit(sd->status.bgstats.dom_bases,add_value,USHRT_MAX);
17825 achievement_validate_bg(sd,ATB_DOM_BASES,1);
17826 pc_addfame(sd,10,(bg->members[i].ranked ? 2 : 3));
17827 break;
17828 }
17829 }
17830
17831 return 0;
17832}
17833
17834BUILDIN_FUNC(bg_getitem)
17835{
17836 int bg_id, nameid, amount;
17837
17838 bg_id = script_getnum(st,2);
17839 nameid = script_getnum(st,3);
17840 amount = script_getnum(st,4);
17841
17842 bg_team_getitem(bg_id, nameid, amount);
17843 return 0;
17844}
17845
17846BUILDIN_FUNC(bg_getkafrapoints)
17847{
17848 int bg_id, amount;
17849
17850 bg_id = script_getnum(st,2);
17851 amount = script_getnum(st,3);
17852
17853 bg_team_get_kafrapoints(bg_id, amount);
17854 return 0;
17855}
17856
17857BUILDIN_FUNC(bg_reward)
17858{
17859 int bg_id, nameid, amount, kafrapoints, quest_id, add_value, bg_arena, bg_result;
17860 const char *var;
17861
17862 bg_id = script_getnum(st,2);
17863 nameid = script_getnum(st,3);
17864 amount = script_getnum(st,4);
17865 kafrapoints = script_getnum(st,5);
17866 quest_id = script_getnum(st,6);
17867 var = script_getstr(st,7);
17868 add_value = script_getnum(st,8);
17869 bg_arena = script_getnum(st,9);
17870 bg_result = script_getnum(st,10);
17871
17872 bg_team_rewards(bg_id, nameid, amount, kafrapoints, quest_id, var, add_value, bg_arena, bg_result);
17873 return 0;
17874}
17875
17876/*==========================================
17877 * Instancing Script Commands
17878 *------------------------------------------*/
17879
17880BUILDIN_FUNC(instance_create)
17881{
17882 const char *name;
17883 int party_id, res;
17884
17885 name = script_getstr(st, 2);
17886 party_id = script_getnum(st, 3);
17887
17888 res = instance_create(party_id, name);
17889 if( res == -4 ) // Already exists
17890 {
17891 script_pushint(st, -1);
17892 return 0;
17893 }
17894 else if( res < 0 )
17895 {
17896 const char *err;
17897 switch(res)
17898 {
17899 case -3: err = "No free instances"; break;
17900 case -2: err = "Invalid party ID"; break;
17901 case -1: err = "Invalid type"; break;
17902 default: err = "Unknown"; break;
17903 }
17904 ShowError("buildin_instance_create: %s [%d].\n", err, res);
17905 script_pushint(st, -2);
17906 return 0;
17907 }
17908
17909 script_pushint(st, res);
17910 return 0;
17911}
17912
17913BUILDIN_FUNC(instance_destroy)
17914{
17915 int instance_id;
17916 struct map_session_data *sd;
17917 struct party_data *p;
17918
17919 if( script_hasdata(st, 2) )
17920 instance_id = script_getnum(st, 2);
17921 else if( st->instance_id )
17922 instance_id = st->instance_id;
17923 else if( (sd = script_rid2sd(st)) != NULL && sd->status.party_id && (p = party_search(sd->status.party_id)) != NULL && p->instance_id )
17924 instance_id = p->instance_id;
17925 else return 0;
17926
17927 if( instance_id <= 0 || instance_id >= MAX_INSTANCE )
17928 {
17929 ShowError("buildin_instance_destroy: Trying to destroy invalid instance %d.\n", instance_id);
17930 return 0;
17931 }
17932
17933 instance_destroy(instance_id);
17934 return 0;
17935}
17936
17937BUILDIN_FUNC(instance_attachmap)
17938{
17939 const char *name;
17940 int m;
17941 int instance_id;
17942 bool usebasename = false;
17943
17944 name = script_getstr(st,2);
17945 instance_id = script_getnum(st,3);
17946 if( script_hasdata(st,4) && script_getnum(st,4) > 0)
17947 usebasename = true;
17948
17949 if( (m = instance_add_map(name, instance_id, usebasename)) < 0 ) // [Saithis]
17950 {
17951 ShowError("buildin_instance_attachmap: instance creation failed (%s): %d\n", name, m);
17952 script_pushconststr(st, "");
17953 return 0;
17954 }
17955 script_pushconststr(st, map[m].name);
17956
17957 return 0;
17958}
17959
17960BUILDIN_FUNC(instance_detachmap)
17961{
17962 struct map_session_data *sd;
17963 struct party_data *p;
17964 const char *str;
17965 int m, instance_id;
17966
17967 str = script_getstr(st, 2);
17968 if( script_hasdata(st, 3) )
17969 instance_id = script_getnum(st, 3);
17970 else if( st->instance_id )
17971 instance_id = st->instance_id;
17972 else if( (sd = script_rid2sd(st)) != NULL && sd->status.party_id && (p = party_search(sd->status.party_id)) != NULL && p->instance_id )
17973 instance_id = p->instance_id;
17974 else return 0;
17975
17976 if( (m = map_mapname2mapid(str)) < 0 || (m = instance_map2imap(m,instance_id)) < 0 )
17977 {
17978 ShowError("buildin_instance_detachmap: Trying to detach invalid map %s\n", str);
17979 return 0;
17980 }
17981
17982 instance_del_map(m);
17983 return 0;
17984}
17985
17986BUILDIN_FUNC(instance_attach)
17987{
17988 int instance_id;
17989
17990 instance_id = script_getnum(st, 2);
17991 if( instance_id <= 0 || instance_id >= MAX_INSTANCE )
17992 return 0;
17993
17994 st->instance_id = instance_id;
17995 return 0;
17996}
17997
17998BUILDIN_FUNC(instance_id)
17999{
18000 int type, instance_id;
18001 struct map_session_data *sd;
18002 struct party_data *p;
18003
18004 if( script_hasdata(st, 2) )
18005 {
18006 type = script_getnum(st, 2);
18007 if( type == 0 )
18008 instance_id = st->instance_id;
18009 else if( type == 1 && (sd = script_rid2sd(st)) != NULL && sd->status.party_id && (p = party_search(sd->status.party_id)) != NULL )
18010 instance_id = p->instance_id;
18011 else
18012 instance_id = 0;
18013 }
18014 else
18015 instance_id = st->instance_id;
18016
18017 script_pushint(st, instance_id);
18018 return 0;
18019}
18020
18021BUILDIN_FUNC(instance_set_timeout)
18022{
18023 int progress_timeout, idle_timeout;
18024 int instance_id;
18025 struct map_session_data *sd;
18026 struct party_data *p;
18027
18028 progress_timeout = script_getnum(st, 2);
18029 idle_timeout = script_getnum(st, 3);
18030
18031 if( script_hasdata(st, 4) )
18032 instance_id = script_getnum(st, 4);
18033 else if( st->instance_id )
18034 instance_id = st->instance_id;
18035 else if( (sd = script_rid2sd(st)) != NULL && sd->status.party_id && (p = party_search(sd->status.party_id)) != NULL && p->instance_id )
18036 instance_id = p->instance_id;
18037 else return 0;
18038
18039 if( instance_id > 0 )
18040 instance_set_timeout(instance_id, progress_timeout, idle_timeout);
18041
18042 return 0;
18043}
18044
18045BUILDIN_FUNC(instance_init)
18046{
18047 int instance_id = script_getnum(st, 2);
18048
18049 if( instance[instance_id].state != INSTANCE_IDLE )
18050 {
18051 ShowError("instance_init: instance already initialized.\n");
18052 return 0;
18053 }
18054
18055 instance_init(instance_id);
18056 return 0;
18057}
18058
18059BUILDIN_FUNC(instance_announce)
18060{
18061 int instance_id = script_getnum(st,2);
18062 const char *mes = script_getstr(st,3);
18063 int flag = script_getnum(st,4);
18064 const char *fontColor = script_hasdata(st,5) ? script_getstr(st,5) : NULL;
18065 int fontType = script_hasdata(st,6) ? script_getnum(st,6) : 0x190; // default fontType (FW_NORMAL)
18066 int fontSize = script_hasdata(st,7) ? script_getnum(st,7) : 12; // default fontSize
18067 int fontAlign = script_hasdata(st,8) ? script_getnum(st,8) : 0; // default fontAlign
18068 int fontY = script_hasdata(st,9) ? script_getnum(st,9) : 0; // default fontY
18069
18070 int i;
18071 struct map_session_data *sd;
18072 struct party_data *p;
18073
18074 if( instance_id == 0 )
18075 {
18076 if( st->instance_id )
18077 instance_id = st->instance_id;
18078 else if( (sd = script_rid2sd(st)) != NULL && sd->status.party_id && (p = party_search(sd->status.party_id)) != NULL && p->instance_id )
18079 instance_id = p->instance_id;
18080 else return 0;
18081 }
18082
18083 if( instance_id <= 0 || instance_id >= MAX_INSTANCE )
18084 return 0;
18085
18086 for( i = 0; i < instance[instance_id].num_map; i++ )
18087 map_foreachinmap(buildin_announce_sub, instance[instance_id].map[i], BL_PC,
18088 mes, strlen(mes)+1, flag&0xf0, fontColor, fontType, fontSize, fontAlign, fontY);
18089
18090 return 0;
18091}
18092
18093BUILDIN_FUNC(instance_npcname)
18094{
18095 const char *str;
18096 int instance_id = 0;
18097
18098 struct map_session_data *sd;
18099 struct party_data *p;
18100 struct npc_data *nd;
18101
18102 str = script_getstr(st, 2);
18103 if( script_hasdata(st, 3) )
18104 instance_id = script_getnum(st, 3);
18105 else if( st->instance_id )
18106 instance_id = st->instance_id;
18107 else if( (sd = script_rid2sd(st)) != NULL && sd->status.party_id && (p = party_search(sd->status.party_id)) != NULL && p->instance_id )
18108 instance_id = p->instance_id;
18109
18110 if( instance_id && (nd = npc_name2id(str)) != NULL )
18111 {
18112 static char npcname[NAME_LENGTH];
18113 snprintf(npcname, sizeof(npcname), "dup_%d_%d", instance_id, nd->bl.id);
18114 script_pushconststr(st,npcname);
18115 }
18116 else
18117 {
18118 ShowError("script:instance_npcname: invalid instance NPC (instance_id: %d, NPC name: \"%s\".)\n", instance_id, str);
18119 st->state = END;
18120 return 1;
18121 }
18122
18123 return 0;
18124}
18125
18126BUILDIN_FUNC(has_instance)
18127{
18128 struct map_session_data *sd;
18129 struct party_data *p;
18130 const char *str;
18131 int m, instance_id = 0;
18132
18133 str = script_getstr(st, 2);
18134 if( script_hasdata(st, 3) )
18135 instance_id = script_getnum(st, 3);
18136 else if( st->instance_id )
18137 instance_id = st->instance_id;
18138 else if( (sd = script_rid2sd(st)) != NULL && sd->status.party_id && (p = party_search(sd->status.party_id)) != NULL && p->instance_id )
18139 instance_id = p->instance_id;
18140
18141 if( !instance_id || (m = map_mapname2mapid(str)) < 0 || (m = instance_map2imap(m, instance_id)) < 0 )
18142 {
18143 script_pushconststr(st, "");
18144 return 0;
18145 }
18146
18147 script_pushconststr(st, map[m].name);
18148 return 0;
18149}
18150
18151BUILDIN_FUNC(instance_warpall)
18152{
18153 struct map_session_data *pl_sd;
18154 int m, i, instance_id;
18155 const char *mapn;
18156 int x, y;
18157 unsigned short mapindex;
18158 struct party_data *p = NULL;
18159
18160 mapn = script_getstr(st,2);
18161 x = script_getnum(st,3);
18162 y = script_getnum(st,4);
18163 if( script_hasdata(st,5) )
18164 instance_id = script_getnum(st,5);
18165 else if( st->instance_id )
18166 instance_id = st->instance_id;
18167 else if( (pl_sd = script_rid2sd(st)) != NULL && pl_sd->status.party_id && (p = party_search(pl_sd->status.party_id)) != NULL && p->instance_id )
18168 instance_id = p->instance_id;
18169 else return 0;
18170
18171 if( (m = map_mapname2mapid(mapn)) < 0 || (map[m].flag.src4instance && (m = instance_mapid2imapid(m, instance_id)) < 0) )
18172 return 0;
18173
18174 if( !(p = party_search(instance[instance_id].party_id)) )
18175 return 0;
18176
18177 mapindex = map_id2index(m);
18178 for( i = 0; i < MAX_PARTY; i++ )
18179 if( (pl_sd = p->data[i].sd) && map[pl_sd->bl.m].instance_id == st->instance_id ) pc_setpos(pl_sd,mapindex,x,y,CLR_TELEPORT);
18180
18181 return 0;
18182}
18183
18184/*==========================================
18185 * PlayTime
18186 *------------------------------------------*/
18187BUILDIN_FUNC(get_playtime)
18188{
18189 struct map_session_data *sd = script_rid2sd(st);
18190 if( sd == NULL )
18191 return 0;
18192
18193 pc_calc_playtime(sd);
18194 script_pushint(st,sd->status.playtime);
18195 return 0;
18196}
18197/*==========================================
18198 * Premium account check
18199 *------------------------------------------*/
18200BUILDIN_FUNC(isPremium)
18201{
18202 struct map_session_data *sd = script_rid2sd(st);
18203 if( sd == NULL || !pc_isPremium(sd) )
18204 script_pushint(st,0);
18205 else
18206 script_pushint(st,1);
18207 return 0;
18208}
18209/*==========================================
18210 * Hunting Missions [Zephyrus]
18211 *------------------------------------------*/
18212BUILDIN_FUNC(mission_sethunting)
18213{
18214 struct map_session_data *sd = script_rid2sd(st);
18215 int index, i;
18216 char varname[32];
18217
18218 if( sd == NULL )
18219 return 0;
18220
18221 index = script_getnum(st,2);
18222 if( index < 1 || index > 5 )
18223 return 0; // Invalid Index
18224
18225 i = index - 1;
18226
18227 sprintf(varname, "Mission_ID%d", index);
18228 sd->hunting[i].mob_id = script_getnum(st,3);
18229 pc_setglobalreg(sd, varname, sd->hunting[i].mob_id);
18230
18231 sprintf(varname, "Mission_Count%d", index);
18232 sd->hunting[i].count = script_getnum(st,4);
18233 pc_setglobalreg(sd, varname, sd->hunting[i].count);
18234
18235 return 0;
18236}
18237
18238BUILDIN_FUNC(mission_settime)
18239{
18240 struct map_session_data *sd = script_rid2sd(st);
18241
18242 if( sd == NULL )
18243 return 0;
18244
18245 sd->hunting_time = script_getnum(st,2);
18246 pc_setglobalreg(sd, "Mission_Tick", sd->hunting_time);
18247
18248 return 0;
18249}
18250
18251/*==========================================
18252 * Custom Fonts
18253 *------------------------------------------*/
18254BUILDIN_FUNC(setfont)
18255{
18256 struct map_session_data *sd = script_rid2sd(st);
18257 int font = script_getnum(st,2);
18258 if( sd == NULL )
18259 return 0;
18260
18261 if( sd->user_font != font )
18262 sd->user_font = font;
18263 else
18264 sd->user_font = 0;
18265
18266 clif_font(sd);
18267 return 0;
18268}
18269
18270static int buildin_mobuseskill_sub(struct block_list *bl,va_list ap)
18271{
18272 TBL_MOB* md = (TBL_MOB*)bl;
18273 struct block_list *tbl;
18274 int mobid = va_arg(ap,int);
18275 int skillid = va_arg(ap,int);
18276 int skilllv = va_arg(ap,int);
18277 int casttime = va_arg(ap,int);
18278 int cancel = va_arg(ap,int);
18279 int emotion = va_arg(ap,int);
18280 int target = va_arg(ap,int);
18281
18282 if( md->class_ != mobid )
18283 return 0;
18284
18285 // 0:self, 1:target, 2:master, default:random
18286 switch( target )
18287 {
18288 case 0: tbl = map_id2bl(md->bl.id); break;
18289 case 1: tbl = map_id2bl(md->target_id); break;
18290 case 2: tbl = map_id2bl(md->master_id); break;
18291 default:tbl = battle_getenemy(&md->bl, DEFAULT_ENEMY_TYPE(md),skill_get_range2(&md->bl, skillid, skilllv)); break;
18292 }
18293
18294 if( !tbl )
18295 return 0;
18296
18297 if( md->ud.skilltimer != INVALID_TIMER ) // Cancel the casting skill.
18298 unit_skillcastcancel(bl,0);
18299
18300 if( skill_get_casttype(skillid) == CAST_GROUND )
18301 unit_skilluse_pos2(&md->bl, tbl->x, tbl->y, skillid, skilllv, casttime, cancel);
18302 else
18303 unit_skilluse_id2(&md->bl, tbl->id, skillid, skilllv, casttime, cancel);
18304
18305 clif_emotion(&md->bl, emotion);
18306
18307 return 0;
18308}
18309/*==========================================
18310 * areamobuseskill "Map Name",<x>,<y>,<range>,<Mob ID>,"Skill Name"/<Skill ID>,<Skill Lv>,<Cast Time>,<Cancelable>,<Emotion>,<Target Type>;
18311 *------------------------------------------*/
18312BUILDIN_FUNC(areamobuseskill)
18313{
18314 struct block_list center;
18315 int m,range,mobid,skillid,skilllv,casttime,emotion,target,cancel;
18316
18317 if( (m = map_mapname2mapid(script_getstr(st,2))) < 0 )
18318 {
18319 ShowError("areamobuseskill: invalid map name.\n");
18320 return 0;
18321 }
18322
18323 if( map[m].flag.src4instance && st->instance_id && (m = instance_mapid2imapid(m, st->instance_id)) < 0 )
18324 return 0;
18325
18326 center.m = m;
18327 center.x = script_getnum(st,3);
18328 center.y = script_getnum(st,4);
18329 range = script_getnum(st,5);
18330 mobid = script_getnum(st,6);
18331 skillid = ( script_isstring(st,7) ? skill_name2id(script_getstr(st,7)) : script_getnum(st,7) );
18332 if( (skilllv = script_getnum(st,8)) > battle_config.mob_max_skilllvl )
18333 skilllv = battle_config.mob_max_skilllvl;
18334
18335 casttime = script_getnum(st,9);
18336 cancel = script_getnum(st,10);
18337 emotion = script_getnum(st,11);
18338 target = script_getnum(st,12);
18339
18340 map_foreachinrange(buildin_mobuseskill_sub, ¢er, range, BL_MOB, mobid, skillid, skilllv, casttime, cancel, emotion, target);
18341 return 0;
18342}
18343
18344
18345BUILDIN_FUNC(progressbar)
18346{
18347#if PACKETVER >= 20080318
18348 struct map_session_data * sd = script_rid2sd(st);
18349 const char * color;
18350 unsigned int second;
18351
18352 if( !st || !sd )
18353 return 0;
18354
18355 st->state = STOP;
18356
18357 color = script_getstr(st,2);
18358 second = script_getnum(st,3);
18359
18360 sd->progressbar.npc_id = st->oid;
18361 sd->progressbar.timeout = gettick() + second*1000;
18362
18363 clif_progressbar(sd, strtol(color, (char **)NULL, 0), second);
18364#endif
18365 return 0;
18366}
18367
18368BUILDIN_FUNC(pushpc)
18369{
18370 int direction, cells, dx, dy;
18371 struct map_session_data* sd;
18372
18373 if((sd = script_rid2sd(st))==NULL)
18374 {
18375 return 0;
18376 }
18377
18378 direction = script_getnum(st,2);
18379 cells = script_getnum(st,3);
18380
18381 if(direction<0 || direction>7)
18382 {
18383 ShowWarning("buildin_pushpc: Invalid direction %d specified.\n", direction);
18384 script_reportsrc(st);
18385
18386 direction%= 8; // trim spin-over
18387 }
18388
18389 if(!cells)
18390 {// zero distance
18391 return 0;
18392 }
18393 else if(cells<0)
18394 {// pushing backwards
18395 direction = (direction+4)%8; // turn around
18396 cells = -cells;
18397 }
18398
18399 dx = dirx[direction];
18400 dy = diry[direction];
18401
18402 unit_blown(&sd->bl, dx, dy, cells, 0);
18403 return 0;
18404}
18405
18406
18407/// Invokes buying store preparation window
18408/// buyingstore <slots>;
18409BUILDIN_FUNC(buyingstore)
18410{
18411 struct map_session_data* sd;
18412
18413 if( ( sd = script_rid2sd(st) ) == NULL )
18414 {
18415 return 0;
18416 }
18417
18418 buyingstore_setup(sd, script_getnum(st,2));
18419 return 0;
18420}
18421
18422
18423/// Invokes search store info window
18424/// searchstores <uses>,<effect>;
18425BUILDIN_FUNC(searchstores)
18426{
18427 unsigned short effect;
18428 unsigned int uses;
18429 struct map_session_data* sd;
18430
18431 if( ( sd = script_rid2sd(st) ) == NULL )
18432 {
18433 return 0;
18434 }
18435
18436 uses = script_getnum(st,2);
18437 effect = script_getnum(st,3);
18438
18439 if( !uses )
18440 {
18441 ShowError("buildin_searchstores: Amount of uses cannot be zero.\n");
18442 return 1;
18443 }
18444
18445 if( effect > 1 )
18446 {
18447 ShowError("buildin_searchstores: Invalid effect id %hu, specified.\n", effect);
18448 return 1;
18449 }
18450
18451 searchstore_open(sd, uses, effect);
18452 return 0;
18453}
18454
18455
18456/// Displays a number as large digital clock.
18457/// showdigit <value>[,<type>];
18458BUILDIN_FUNC(showdigit)
18459{
18460 unsigned int type = 0;
18461 int value;
18462 struct map_session_data* sd;
18463
18464 if( ( sd = script_rid2sd(st) ) == NULL )
18465 {
18466 return 0;
18467 }
18468
18469 value = script_getnum(st,2);
18470
18471 if( script_hasdata(st,3) )
18472 {
18473 type = script_getnum(st,3);
18474
18475 if( type > 3 )
18476 {
18477 ShowError("buildin_showdigit: Invalid type %u.\n", type);
18478 return 1;
18479 }
18480 }
18481
18482 clif_showdigit(sd, (unsigned char)type, value);
18483 return 0;
18484}
18485/// [CreativeSD]: bindclock "<hour>:<minute>", "<npc_event::label>";
18486BUILDIN_FUNC(bindclock)
18487{
18488 char strtimer[5];
18489 const char* timer = script_getstr(st,2);
18490 const char* ev = script_getstr(st,3);
18491 int hour, minute, i = 0;
18492
18493 sscanf(timer, "%d:%d", &hour, &minute);
18494
18495 if( hour < 0 || hour > 23 )
18496 {
18497 ShowError("script_bind_clock: Time '%d' incorrect. The time should be between 00~24.\n", hour);
18498 script_pushint(st,0);
18499 return 0;
18500 }
18501
18502 if( minute < 0 || minute> 59 )
18503 {
18504 ShowError("script_bind_clock: Minute '%d' incorrect. The minute should be between 00~59.\n", minute);
18505 script_pushint(st,0);
18506 return 0;
18507 }
18508
18509 check_event(st, ev);
18510 sprintf(strtimer, "%02d%02d", hour, minute);
18511
18512 ARR_FIND(0, MAX_BIND_CLOCK, i, strcmp(npc_bind_clock[i].clock,strtimer) == 0 && strcmp(npc_bind_clock[i].event,ev) == 0);
18513 if(i < MAX_BIND_CLOCK)
18514 script_pushint(st,0); // It is already in use.
18515 else {
18516 ARR_FIND(0, MAX_BIND_CLOCK, i, npc_bind_clock[i].clock[0] == '\0');
18517 if(i < MAX_BIND_CLOCK) {
18518 safestrncpy(npc_bind_clock[i].clock, strtimer, 5);
18519 safestrncpy(npc_bind_clock[i].event, ev, EVENT_NAME_LENGTH);
18520 }
18521 script_pushint(st,1);
18522 }
18523 return 0;
18524}
18525
18526/// [CreativeSD]: unbindclock "<hour>:<minute>", "<npc_event::label>";
18527BUILDIN_FUNC(unbindclock)
18528{
18529 char strtimer[5];
18530 const char* timer = script_getstr(st,2);
18531 const char* ev = script_getstr(st,3);
18532 int hour, minute, i = 0;
18533
18534 sscanf(timer, "%d:%d", &hour, &minute);
18535
18536 if( hour < 0 || hour > 23 )
18537 {
18538 ShowError("script_unbind_clock: Time '%d' incorrect. The time should be between 00~24.\n", hour);
18539 script_pushint(st,0);
18540 return 0;
18541 }
18542
18543 if( minute < 0 || minute> 59 )
18544 {
18545 ShowError("script_unbind_clock: Minute '%d' incorrect. The minute should be between 00~59.\n", minute);
18546 script_pushint(st,0);
18547 return 0;
18548 }
18549
18550 sprintf(strtimer, "%02d%02d", hour, minute);
18551
18552 ARR_FIND(0, MAX_BIND_CLOCK, i, strcmp(npc_bind_clock[i].clock,strtimer) == 0 && strcmp(npc_bind_clock[i].event,ev) == 0);
18553 if(i < MAX_BIND_CLOCK)
18554 {
18555 safestrncpy(npc_bind_clock[i].clock, "", 5);
18556 safestrncpy(npc_bind_clock[i].event, "", EVENT_NAME_LENGTH);
18557 script_pushint(st,1);
18558 }
18559 else
18560 script_pushint(st, 0);
18561 return 0;
18562}
18563
18564BUILDIN_FUNC(checkbindclock)
18565{
18566 char strtimer[5];
18567 const char* timer = script_getstr(st,2);
18568 const char* ev = script_getstr(st,3);
18569 int hour, minute, i = 0;
18570
18571 sscanf(timer, "%d:%d", &hour, &minute);
18572
18573 if( hour < 0 || hour > 23 )
18574 {
18575 ShowError("script_unbind_clock: Time '%d' incorrect. The time should be between 00~24.\n", hour);
18576 script_pushint(st,0);
18577 return 0;
18578 }
18579
18580 if( minute < 0 || minute> 59 )
18581 {
18582 ShowError("script_unbind_clock: Minute '%d' incorrect. The minute should be between 00~59.\n", minute);
18583 script_pushint(st,0);
18584 return 0;
18585 }
18586
18587 sprintf(strtimer, "%02d%02d", hour, minute);
18588
18589 ARR_FIND(0, MAX_BIND_CLOCK, i, strcmp(npc_bind_clock[i].clock,strtimer) == 0 && strcmp(npc_bind_clock[i].event,ev));
18590
18591 if(i < MAX_BIND_CLOCK)
18592 script_pushint(st,1);
18593 else
18594 script_pushint(st,0);
18595
18596 return 0;
18597}
18598
18599BUILDIN_FUNC(addrestock)
18600{
18601 Sql* handle = mmysql_handle;
18602 struct map_session_data *sd = script_rid2sd(st);
18603 struct script_data *data;
18604 struct item_data* id = NULL;
18605 int i = 0, amount;
18606 int flag = 0;
18607 unsigned short item_id;
18608
18609 if (sd == NULL)
18610 {
18611 script_pushint(st, 0);
18612 return 1;
18613 }
18614
18615 data = script_getdata(st, 2);
18616 get_val(st,data);
18617
18618 if (data_isstring(data))
18619 {
18620 const char *name = conv_str(st, data);
18621 id = itemdb_searchname(name);
18622 if (id == NULL){
18623 ShowError("buildin_addrestock: Invalid item '%s'.\n", name);
18624 return 1;
18625 }
18626 item_id = id->nameid;
18627 }
18628 else if (data_isint(data))
18629 {
18630 item_id = conv_num(st,data);
18631 if (!(id = itemdb_exists(item_id))) {
18632 ShowError("buildin_addrestock: Invalid item '%d'.\n", id);
18633 return 1; //No item created.
18634 }
18635 }
18636 else {
18637 ShowError("buildin_addrestock: invalid data type for argument #1 (%d).", data->type);
18638 return 1;
18639 }
18640
18641 amount = script_getnum(st, 3);
18642 for (i = 0; i < MAX_RESTOCK; i++)
18643 {
18644 if (sd->status.restock[i].nameid == item_id)
18645 {
18646 flag = 1;
18647 break;
18648 }
18649 }
18650
18651 if (flag)
18652 {
18653 // Update Restock Item.
18654 if (SQL_ERROR == Sql_Query(handle, "UPDATE `restock` SET `amount`='%d' WHERE `char_id`='%d' AND `nameid`='%d'", amount, sd->status.char_id, item_id))
18655 {
18656 Sql_ShowDebug(handle);
18657 script_pushint(st, 0);
18658 return 1;
18659 }
18660
18661 sd->status.restock[i].amount = amount;
18662 }
18663 else {
18664 // New Restock Item.
18665 if (SQL_ERROR == Sql_Query(handle, "INSERT INTO `restock` (`char_id`, `nameid`, `amount`) VALUES (%d, %d, %d)", sd->status.char_id, item_id, amount))
18666 {
18667 Sql_ShowDebug(handle);
18668 script_pushint(st, 0);
18669 return 1;
18670 }
18671
18672 ARR_FIND(0, MAX_RESTOCK, i, sd->status.restock[i].nameid == 0);
18673 if (i >= MAX_RESTOCK)
18674 {
18675 script_pushint(st, 0);
18676 return 0;
18677 }
18678
18679 sd->status.restock[i].nameid = item_id;
18680 sd->status.restock[i].amount = amount;
18681 }
18682
18683 Sql_FreeResult(handle);
18684 script_pushint(st, 1);
18685 return 0;
18686}
18687
18688BUILDIN_FUNC(delrestock)
18689{
18690 Sql* handle = mmysql_handle;
18691 struct map_session_data *sd = script_rid2sd(st);
18692 struct script_data *data;
18693 struct item_data* id = NULL;
18694 int i = 0, flag = 0;
18695 unsigned short item_id;
18696
18697 if (sd == NULL)
18698 {
18699 script_pushint(st, 0);
18700 return 1;
18701 }
18702
18703 data = script_getdata(st, 2);
18704 get_val(st, data);
18705 if (data_isstring(data))
18706 {
18707 const char *name = conv_str(st, data);
18708 id = itemdb_searchname(name);
18709 if (id == NULL){
18710 ShowError("buildin_delrestock: Invalid item '%s'.\n", name);
18711 return 1;
18712 }
18713 item_id = id->nameid;
18714 }
18715 else if (data_isint(data))
18716 {
18717 item_id = conv_num(st, data);
18718 if (!(id = itemdb_exists(item_id))) {
18719 ShowError("buildin_delrestock: Invalid item '%d'.\n", id);
18720 return 1; //No item created.
18721 }
18722 }
18723 else {
18724 ShowError("buildin_delrestock: invalid data type for argument #1 (%d).", data->type);
18725 return 1;
18726 }
18727
18728 for (i = 0; i < MAX_RESTOCK; i++)
18729 {
18730 if (sd->status.restock[i].nameid == item_id)
18731 {
18732 // Update Restock Item.
18733 if (SQL_ERROR == Sql_Query(handle, "DELETE FROM `restock` WHERE `char_id`='%d' AND `nameid`='%d'", sd->status.char_id, item_id))
18734 {
18735 Sql_ShowDebug(handle);
18736 script_pushint(st, 0);
18737 return 1;
18738 }
18739
18740 memset(&sd->status.restock[i], 0, sizeof(sd->status.restock[0]));
18741 flag = true;
18742 break;
18743 }
18744 }
18745 Sql_FreeResult(handle);
18746 script_pushint(st, flag);
18747 return 0;
18748}
18749/*==========================================
18750 * PvP Event Start/Stop Scripts
18751 *------------------------------------------*/
18752BUILDIN_FUNC(pvpeventstart)
18753{
18754 struct map_session_data *pl_sd;
18755 struct s_mapiterator* iter;
18756
18757 iter = mapit_getallusers();
18758 for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
18759 pl_sd->pvpevent_fame = 0;
18760
18761 mapit_free(iter);
18762
18763 memset(pvpevent_fame_list, 0, sizeof(pvpevent_fame_list));
18764 pvpevent_flag = 1;
18765 return 0;
18766}
18767
18768BUILDIN_FUNC(pvpeventstop)
18769{
18770 memset(pvpevent_fame_list, 0, sizeof(pvpevent_fame_list));
18771 pvpevent_flag = 0;
18772 return 0;
18773}
18774
18775BUILDIN_FUNC(pvpeventcheck)
18776{
18777 script_pushint(st,pvpevent_flag);
18778 return 0;
18779}
18780
18781BUILDIN_FUNC(pvpevent_addpoints)
18782{
18783 struct map_session_data *sd = script_rid2sd(st);
18784 int value = script_getnum(st,2);
18785 if( sd == NULL ) return 0;
18786
18787 sd->pvpevent_fame += value;
18788 pc_pvpevent_addfame(sd, true);
18789
18790 return 0;
18791}
18792/*==========================================
18793 * Ranking Reset
18794 *------------------------------------------*/
18795BUILDIN_FUNC(rankreset)
18796{
18797 int type = script_getnum(st,2);
18798 if( type >= 0 && type <= 2 )
18799 pc_ranking_reset(type,true);
18800
18801 return 0;
18802}
18803/*==========================================
18804 * Item Destroy
18805 *------------------------------------------*/
18806BUILDIN_FUNC(item_remove4all)
18807{
18808 int nameid = script_getnum(st,2);
18809 pc_item_remove4all(nameid,true);
18810
18811 return 0;
18812}
18813/*==========================================
18814 * Guild Ranking - Zeny Investments
18815 *------------------------------------------*/
18816BUILDIN_FUNC(guild_addzenyeco)
18817{
18818 struct map_session_data *sd = script_rid2sd(st);
18819 struct guild_castle *gc;
18820 struct guild *g;
18821
18822 int value = script_getnum(st,2);
18823 if( sd == NULL || sd->status.guild_id == 0 || (g = guild_search(sd->status.guild_id)) == NULL || (gc = guild_mapindex2gc(map[sd->bl.m].index)) == NULL )
18824 return 0;
18825
18826 add2limit(g->castle[gc->castle_id].zeny_eco, value, UINT_MAX);
18827 g->castle[gc->castle_id].changed = true;
18828 if( !agit_flag )
18829 {
18830 intif_guild_save_score(g->guild_id, gc->castle_id, &g->castle[gc->castle_id]);
18831 g->castle[gc->castle_id].changed = false;
18832 }
18833 return 0;
18834}
18835
18836BUILDIN_FUNC(guild_addzenydef)
18837{
18838 struct map_session_data *sd = script_rid2sd(st);
18839 struct guild_castle *gc;
18840 struct guild *g;
18841
18842 int value = script_getnum(st,2);
18843 if( sd == NULL || sd->status.guild_id == 0 || (g = guild_search(sd->status.guild_id)) == NULL || (gc = guild_mapindex2gc(map[sd->bl.m].index)) == NULL )
18844 return 0;
18845
18846 add2limit(g->castle[gc->castle_id].zeny_def, value, UINT_MAX);
18847 g->castle[gc->castle_id].changed = true;
18848 if( !agit_flag )
18849 {
18850 intif_guild_save_score(g->guild_id, gc->castle_id, &g->castle[gc->castle_id]);
18851 g->castle[gc->castle_id].changed = false;
18852 }
18853 return 0;
18854}
18855
18856/*==========================================
18857 * Character PvP Mode
18858 *------------------------------------------*/
18859BUILDIN_FUNC(getpvpmode)
18860{
18861 int result = 0;
18862 struct map_session_data *sd = script_rid2sd(st);
18863 if( sd && sd->state.pvpmode )
18864 result = 1;
18865
18866 script_pushint(st,result);
18867 return 0;
18868}
18869
18870/*==========================================
18871 * Item Security System
18872 *------------------------------------------*/
18873BUILDIN_FUNC(setsecurity)
18874{
18875 struct map_session_data *sd = script_rid2sd(st);
18876 int value = script_getnum(st,2);
18877 if( sd == NULL )
18878 return 0;
18879
18880 sd->state.secure_items = (value)?1:0;
18881 return 0;
18882}
18883
18884BUILDIN_FUNC(getsecurity)
18885{
18886 struct map_session_data *sd = script_rid2sd(st);
18887 if( sd == NULL )
18888 return 0;
18889
18890 script_pushint(st,sd->state.secure_items);
18891 return 0;
18892}
18893
18894BUILDIN_FUNC(bindatcmd)
18895{
18896 const char* atcmd;
18897 const char* eventName;
18898 int i = 0, level = 0, level2 = 0;
18899
18900 atcmd = script_getstr(st,2);
18901 eventName = script_getstr(st,3);
18902
18903 if( script_hasdata(st,4) ) level = script_getnum(st,4);
18904 if( script_hasdata(st,5) ) level2 = script_getnum(st,5);
18905
18906 // check if event is already binded
18907 ARR_FIND(0, MAX_ATCMD_BINDINGS, i, strcmp(atcmd_binding[i].command,atcmd) == 0);
18908 if( i < MAX_ATCMD_BINDINGS )
18909 {
18910 safestrncpy(atcmd_binding[i].npc_event, eventName, 50);
18911 atcmd_binding[i].level = level;
18912 atcmd_binding[i].level2 = level2;
18913 }
18914 else
18915 { // make new binding
18916 ARR_FIND(0, MAX_ATCMD_BINDINGS, i, atcmd_binding[i].command[0] == '\0');
18917 if( i < MAX_ATCMD_BINDINGS )
18918 {
18919 safestrncpy(atcmd_binding[i].command, atcmd, 50);
18920 safestrncpy(atcmd_binding[i].npc_event, eventName, 50);
18921 atcmd_binding[i].level = level;
18922 atcmd_binding[i].level2 = level2;
18923 }
18924 }
18925
18926 return 0;
18927}
18928
18929BUILDIN_FUNC(unbindatcmd)
18930{
18931 const char* atcmd;
18932 int i = 0;
18933
18934 atcmd = script_getstr(st, 2);
18935
18936 ARR_FIND(0, MAX_ATCMD_BINDINGS, i, strcmp(atcmd_binding[i].command, atcmd) == 0);
18937 if( i < MAX_ATCMD_BINDINGS )
18938 memset(&atcmd_binding[i],0,sizeof(atcmd_binding[0]));
18939
18940 return 0;
18941}
18942
18943BUILDIN_FUNC(useatcmd)
18944{
18945 TBL_PC dummy_sd;
18946 TBL_PC* sd;
18947 int fd;
18948 const char* cmd;
18949
18950 cmd = script_getstr(st,2);
18951
18952 if( st->rid )
18953 {
18954 sd = script_rid2sd(st);
18955 fd = sd->fd;
18956 }
18957 else
18958 { // Use a dummy character.
18959 sd = &dummy_sd;
18960 fd = 0;
18961
18962 memset(&dummy_sd, 0, sizeof(TBL_PC));
18963 if( st->oid )
18964 {
18965 struct block_list* bl = map_id2bl(st->oid);
18966 memcpy(&dummy_sd.bl, bl, sizeof(struct block_list));
18967 if( bl->type == BL_NPC )
18968 safestrncpy(dummy_sd.status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH);
18969 }
18970 }
18971
18972 // compatibility with previous implementation (deprecated!)
18973 if( cmd[0] != atcommand_symbol )
18974 {
18975 cmd += strlen(sd->status.name);
18976 while( *cmd != atcommand_symbol && *cmd != 0 )
18977 cmd++;
18978 }
18979
18980 is_atcommand(fd, sd, cmd, 2);
18981 return 0;
18982}
18983
18984// Graveyard System
18985BUILDIN_FUNC(graveyard_info)
18986{
18987 struct tm *datetime;
18988 char buf[128], *output = NULL;
18989
18990 struct npc_data* nd = map_id2nd(st->oid);
18991 int type = script_getnum(st,2);
18992
18993 if( !nd ) return 0;
18994
18995 switch( type )
18996 {
18997 case 1: // Killer Name
18998 output = aStrdup(nd->graveyard.killed_by);
18999 break;
19000 case 2: // Killed Time
19001 datetime = localtime(&nd->graveyard.killed_time);
19002 strftime(buf, sizeof(buf)-1, "%A, %B %d %Y %X.", datetime);
19003 output = aStrdup(buf);
19004 break;
19005 default: // Victim Name
19006 output = aStrdup(nd->graveyard.name);
19007 break;
19008 }
19009
19010 if( output )
19011 script_pushstr(st,output);
19012 else
19013 script_pushconststr(st,"");
19014
19015 return 0;
19016}
19017
19018// Achievement System
19019BUILDIN_FUNC(achieve)
19020{
19021 struct map_session_data* sd = script_rid2sd(st);
19022 int id = script_getnum(st,2);
19023 struct achievement_data *ad;
19024
19025 if( (ad = achievement_search(id)) != NULL )
19026 achievement_complete(sd,ad);
19027
19028 return 0;
19029}
19030
19031BUILDIN_FUNC(achievement_info)
19032{
19033 struct achievement_data *ad;
19034 int id, flag;
19035
19036 id = script_getnum(st,2);
19037 flag = script_getnum(st,3);
19038
19039 if( (ad = achievement_search(id)) == NULL )
19040 {
19041 ShowError("buildin:achievement_info: No achievement found with id %d.\n",id);
19042 return 0;
19043 }
19044
19045 switch( flag )
19046 {
19047 case 0: // Status
19048 {
19049 struct map_session_data* sd = script_rid2sd(st);
19050 int index;
19051 if( !sd )
19052 {
19053 ShowError("buildin:achievement_info: No player attached.\n");
19054 return 0;
19055 }
19056 index = achievement_index(sd,id);
19057 script_pushint(st,(index >= 0 && sd->achievement[index].completed) ? 1 : 0);
19058 }
19059 break;
19060 case 1: // Type
19061 script_pushint(st,ad->type);
19062 break;
19063 case 2: // Name
19064 script_pushconststr(st,ad->name);
19065 break;
19066 case 3: // Cut-in
19067 script_pushconststr(st,ad->cutin);
19068 break;
19069 case 4: // Reward Base Exp
19070 script_pushint(st,ad->bexp);
19071 break;
19072 case 5: // Reward Base Exp
19073 script_pushint(st,ad->jexp);
19074 break;
19075 case 6: // Reward Item ID
19076 script_pushint(st,ad->nameid);
19077 break;
19078 case 7: // Reward Amount
19079 script_pushint(st,ad->amount);
19080 break;
19081 case 8: // Attached Script
19082 script_pushconststr(st,ad->achieve_event);
19083 break;
19084 case 9: // Objetive Count
19085 script_pushint(st,ad->objectives);
19086 break;
19087 }
19088
19089 return 0;
19090}
19091
19092BUILDIN_FUNC(achieve_progress)
19093{
19094 struct map_session_data* sd = script_rid2sd(st);
19095 int i, id = script_getnum(st,2);
19096 struct achievement_data *ad;
19097 struct s_achievement *sad;
19098
19099 if( !sd )
19100 {
19101 ShowError("buildin:achieve_progress: Non attached character to script.\n");
19102 return 0;
19103 }
19104
19105 if( (ad = achievement_search(id)) == NULL )
19106 {
19107 ShowError("buildin:achieve_progress: No achievement found with id %d.\n",id);
19108 return 0;
19109 }
19110
19111 i = achievement_index(sd,id);
19112 sad = (i >= 0 ? &sd->achievement[i] : NULL );
19113
19114 for( i = 0; i < ad->objectives; i++ )
19115 {
19116 pc_setreg(sd,reference_uid(add_str("@obj_value"), i),ad->ao[i].value);
19117 pc_setreg(sd,reference_uid(add_str("@obj_count"), i),ad->ao[i].count);
19118 pc_setreg(sd,reference_uid(add_str("@obj_progress"), i),( sad ? sad->count[i] : 0 ));
19119 }
19120
19121 script_pushint(st,ad->objectives);
19122 return 0;
19123}
19124
19125// Faction and Language System
19126BUILDIN_FUNC(setfaction)
19127{
19128 struct faction_data* fd;
19129 struct map_session_data* sd = script_rid2sd(st);
19130 int id = script_getnum(st,2);
19131
19132 if( sd && (fd = faction_search(id)) != NULL )
19133 {
19134 char output[256];
19135 sd->status.faction_id = id;
19136 snprintf(output,sizeof(output),"- You have joined the faction [ %s ] -",fd->name);
19137 clif_broadcast2(&sd->bl,output,strlen(output) + 1,0xFFA500,0x190,20,0,0,SELF);
19138 status_calc_pc(sd,0);
19139 sd->lang_id = fd->lang_id;
19140 }
19141
19142 return 0;
19143}
19144
19145BUILDIN_FUNC(language)
19146{
19147 struct lang_data* ld;
19148 struct map_session_data* sd = script_rid2sd(st);
19149 int id = script_getnum(st,2);
19150
19151 if( sd && (ld = lang_search(id)) != NULL )
19152 {
19153 char output[256];
19154 sd->lang_id = id;
19155 snprintf(output,sizeof(output),"- Now you will speak and understand [ %s ] -",ld->name);
19156 clif_broadcast2(&sd->bl,output,strlen(output) + 1,0xFFA500,0x190,20,0,0,SELF);
19157 }
19158
19159 return 0;
19160}
19161
19162BUILDIN_FUNC(learnlang)
19163{
19164 struct lang_data* ld;
19165 struct map_session_data* sd = script_rid2sd(st);
19166 int id = script_getnum(st,2);
19167
19168 if( sd && (ld = lang_search(id)) != NULL && !(sd->lang_mastery&lang_pow[id-1]) )
19169 {
19170 char output[256];
19171 sd->lang_mastery |= lang_pow[id-1];
19172 pc_setglobalreg(sd,"eAmod_Languages",sd->lang_mastery);
19173 snprintf(output,sizeof(output),"- You learn to speak and understand [ %s ] -",ld->name);
19174 clif_broadcast2(&sd->bl,output,strlen(output) + 1,0x00FF00,0x190,20,0,0,SELF);
19175 }
19176
19177 return 0;
19178}
19179
19180BUILDIN_FUNC(unlearnlang)
19181{
19182 struct lang_data* ld;
19183 struct map_session_data* sd = script_rid2sd(st);
19184 int id = script_getnum(st,2);
19185
19186 if( sd && (ld = lang_search(id)) != NULL && (sd->lang_mastery&lang_pow[id-1]) )
19187 {
19188 char output[256];
19189 sd->lang_mastery &= ~lang_pow[id-1];
19190 pc_setglobalreg(sd,"eAmod_Languages",sd->lang_mastery);
19191 snprintf(output,sizeof(output),"- You can't speak and understand [ %s ] anymore -",ld->name);
19192 clif_broadcast2(&sd->bl,output,strlen(output) + 1,0xC0C0C0,0x190,20,0,0,SELF);
19193 }
19194
19195 return 0;
19196}
19197
19198
19199
19200// declarations that were supposed to be exported from npc_chat.c
19201#ifdef PCRE_SUPPORT
19202BUILDIN_FUNC(defpattern);
19203BUILDIN_FUNC(activatepset);
19204BUILDIN_FUNC(deactivatepset);
19205BUILDIN_FUNC(deletepset);
19206#endif
19207
19208/// script command definitions
19209/// for an explanation on args, see add_buildin_func
19210struct script_function buildin_func[] = {
19211 // NPC interaction
19212 BUILDIN_DEF(mes,"s"),
19213 BUILDIN_DEF(next,""),
19214 BUILDIN_DEF(close,""),
19215 BUILDIN_DEF(close2,""),
19216 BUILDIN_DEF(menu,"sl*"),
19217 BUILDIN_DEF(select,"s*"), //for future jA script compatibility
19218 BUILDIN_DEF(prompt,"s*"),
19219 //
19220 BUILDIN_DEF(goto,"l"),
19221 BUILDIN_DEF(callsub,"l*"),
19222 BUILDIN_DEF(callfunc,"s*"),
19223 BUILDIN_DEF(return,"?"),
19224 BUILDIN_DEF(getarg,"i?"),
19225 BUILDIN_DEF(jobchange,"i?"),
19226 BUILDIN_DEF(jobname,"i"),
19227 BUILDIN_DEF(input,"r??"),
19228 BUILDIN_DEF(warp,"sii"),
19229 BUILDIN_DEF(areawarp,"siiiisii??"),
19230 BUILDIN_DEF(warpchar,"siii"), // [LuzZza]
19231 BUILDIN_DEF(warpparty,"siii?"), // [Fredzilla] [Paradox924X]
19232 BUILDIN_DEF(warpguild,"siii"), // [Fredzilla]
19233 BUILDIN_DEF(setlook,"ii"),
19234 BUILDIN_DEF(changelook,"ii"), // Simulates but don't Store it
19235 BUILDIN_DEF(set,"rv"),
19236 BUILDIN_DEF(setarray,"rv*"),
19237 BUILDIN_DEF(cleararray,"rvi"),
19238 BUILDIN_DEF(copyarray,"rri"),
19239 BUILDIN_DEF(getarraysize,"r"),
19240 BUILDIN_DEF(deletearray,"r?"),
19241 BUILDIN_DEF(getelementofarray,"ri"),
19242 BUILDIN_DEF(getitem,"vi?"),
19243 BUILDIN_DEF(storeitem,"vi?"),
19244 BUILDIN_DEF(rentitem,"vi"),
19245 BUILDIN_DEF(itembound,"vi?"),
19246 BUILDIN_DEF(getitem2,"viiiiiiii?"),
19247 BUILDIN_DEF(storeitem2,"viiiiiiii?"),
19248 BUILDIN_DEF(checkspace,"viiiiiiii"),
19249 BUILDIN_DEF(rentitem2,"viiiiiiii"),
19250 BUILDIN_DEF(itembound2,"viiiiiiii?"),
19251 BUILDIN_DEF(getnameditem,"vv"),
19252 BUILDIN_DEF2(grouprandomitem,"groupranditem","i"),
19253 BUILDIN_DEF(makeitem,"visii"),
19254 BUILDIN_DEF(delitem,"vi?"),
19255 BUILDIN_DEF(delitem2,"viiiiiiii?"),
19256 BUILDIN_DEF2(enableitemuse,"enable_items",""),
19257 BUILDIN_DEF2(disableitemuse,"disable_items",""),
19258 BUILDIN_DEF(cutin,"si"),
19259 BUILDIN_DEF(viewpoint,"iiiii"),
19260 BUILDIN_DEF(viewpointmap,"siiiii"),
19261 BUILDIN_DEF(heal,"ii"),
19262 BUILDIN_DEF(itemheal,"ii"),
19263 BUILDIN_DEF(percentheal,"ii"),
19264 BUILDIN_DEF(rand,"i?"),
19265 BUILDIN_DEF(countitem,"v"),
19266 BUILDIN_DEF(countitem2,"viiiiiii"),
19267 BUILDIN_DEF(checkweight,"vi"),
19268 BUILDIN_DEF(readparam,"i?"),
19269 BUILDIN_DEF(getcharid,"i?"),
19270 BUILDIN_DEF(getnpcid,"i?"),
19271 BUILDIN_DEF(getpartyname,"i"),
19272 BUILDIN_DEF(getpartymember,"i?"),
19273 BUILDIN_DEF(getpartyleader,"i?"),
19274 BUILDIN_DEF(getguildname,"i"),
19275 BUILDIN_DEF(getguildmaster,"i"),
19276 BUILDIN_DEF(getguildmasterid,"i"),
19277 BUILDIN_DEF(strcharinfo,"i"),
19278 BUILDIN_DEF(strnpcinfo,"i"),
19279 BUILDIN_DEF(getequipid,"i"),
19280 BUILDIN_DEF(getequipname,"i"),
19281 BUILDIN_DEF(getbrokenid,"i"), // [Valaris]
19282 BUILDIN_DEF(repair,"i"), // [Valaris]
19283 BUILDIN_DEF(repairall,""),
19284 BUILDIN_DEF(getequipisequiped,"i"),
19285 BUILDIN_DEF(getequipisenableref,"i"),
19286 BUILDIN_DEF(getequipisidentify,"i"),
19287 BUILDIN_DEF(getequiprefinerycnt,"i"),
19288 BUILDIN_DEF(getequipweaponlv,"i"),
19289 BUILDIN_DEF(getequippercentrefinery,"i"),
19290 BUILDIN_DEF(getequipisrental,"i"),
19291 BUILDIN_DEF(getequipisbounded,"i"),
19292 BUILDIN_DEF(successrefitem,"i"),
19293 BUILDIN_DEF(failedrefitem,"i"),
19294 BUILDIN_DEF(failedrefitemR,"ii"),
19295 BUILDIN_DEF(statusup,"i"),
19296 BUILDIN_DEF(statusup2,"ii"),
19297 BUILDIN_DEF(bonus,"iv"),
19298 BUILDIN_DEF2(bonus,"bonus2","ivi"),
19299 BUILDIN_DEF2(bonus,"bonus3","ivii"),
19300 BUILDIN_DEF2(bonus,"bonus4","ivvii"),
19301 BUILDIN_DEF2(bonus,"bonus5","ivviii"),
19302 BUILDIN_DEF(autobonus,"sii??"),
19303 BUILDIN_DEF(autobonus2,"sii??"),
19304 BUILDIN_DEF(autobonus3,"siiv?"),
19305 BUILDIN_DEF(skill,"vi?"),
19306 BUILDIN_DEF(addtoskill,"vi?"), // [Valaris]
19307 BUILDIN_DEF(guildskill,"vi"),
19308 BUILDIN_DEF(getskilllv,"v"),
19309 BUILDIN_DEF(getgdskilllv,"iv"),
19310 BUILDIN_DEF(basicskillcheck,""),
19311 BUILDIN_DEF(getgmlevel,""),
19312 BUILDIN_DEF(end,""),
19313 BUILDIN_DEF(checkoption,"i"),
19314 BUILDIN_DEF(setoption,"i?"),
19315 BUILDIN_DEF(setcart,"?"),
19316 BUILDIN_DEF(checkcart,""),
19317 BUILDIN_DEF(setfalcon,"?"),
19318 BUILDIN_DEF(checkfalcon,""),
19319 BUILDIN_DEF(setriding,"?"),
19320 BUILDIN_DEF(checkriding,""),
19321 BUILDIN_DEF2(savepoint,"save","sii"),
19322 BUILDIN_DEF(savepoint,"sii"),
19323 BUILDIN_DEF(gettimetick,"i"),
19324 BUILDIN_DEF(gettime,"i"),
19325 BUILDIN_DEF(gettimestr,"si"),
19326 BUILDIN_DEF(openstorage,""),
19327 BUILDIN_DEF(guildopenstorage,""),
19328 BUILDIN_DEF(restock,"ii"), // [ by Emistry ]
19329 BUILDIN_DEF(openrentstorage,""),
19330 BUILDIN_DEF(itemskill,"vi"),
19331 BUILDIN_DEF(produce,"i"),
19332 BUILDIN_DEF(cooking,"i"),
19333 BUILDIN_DEF(monster,"siisii?"),
19334 BUILDIN_DEF(mobdemolition,"siiiiii"),
19335 BUILDIN_DEF2(mobevent,"mobevent","siisiiiiiiiiiiiiii?"),
19336 BUILDIN_DEF(getmobrandid,"ii"),
19337 BUILDIN_DEF(getmobdrops,"i"),
19338 BUILDIN_DEF(invocar,"ii"),
19339 BUILDIN_DEF(areamonster,"siiiisii?"),
19340 BUILDIN_DEF(killmonster,"ss?"),
19341 BUILDIN_DEF(killmonsterall,"s?"),
19342 BUILDIN_DEF(clone,"siisi????"),
19343 BUILDIN_DEF(doevent,"s"),
19344 BUILDIN_DEF(donpcevent,"s"),
19345 BUILDIN_DEF(cmdothernpc,"ss"),
19346 BUILDIN_DEF(addtimer,"is"),
19347 BUILDIN_DEF(deltimer,"s"),
19348 BUILDIN_DEF(addtimercount,"si"),
19349 BUILDIN_DEF(initnpctimer,"??"),
19350 BUILDIN_DEF(stopnpctimer,"??"),
19351 BUILDIN_DEF(startnpctimer,"??"),
19352 BUILDIN_DEF(setnpctimer,"i?"),
19353 BUILDIN_DEF(getnpctimer,"i?"),
19354 BUILDIN_DEF(attachnpctimer,"?"), // attached the player id to the npc timer [Celest]
19355 BUILDIN_DEF(detachnpctimer,"?"), // detached the player id from the npc timer [Celest]
19356 BUILDIN_DEF(playerattached,""), // returns id of the current attached player. [Skotlex]
19357 BUILDIN_DEF(announce,"si?????"),
19358 BUILDIN_DEF(mapannounce,"ssi?????"),
19359 BUILDIN_DEF(areaannounce,"siiiisi?????"),
19360 BUILDIN_DEF(getusers,"i"),
19361 BUILDIN_DEF(getmapguildusers,"si"),
19362 BUILDIN_DEF(getmapusers,"s"),
19363 BUILDIN_DEF(getareausers,"siiii"),
19364 BUILDIN_DEF(getareadropitem,"siiiiv"),
19365 BUILDIN_DEF(enablenpc,"s"),
19366 BUILDIN_DEF(disablenpc,"s"),
19367 BUILDIN_DEF(hideoffnpc,"s"),
19368 BUILDIN_DEF(hideonnpc,"s"),
19369 BUILDIN_DEF(sc_start,"iii?"),
19370 BUILDIN_DEF(sc_start2,"iiii?"),
19371 BUILDIN_DEF(sc_start4,"iiiiii?"),
19372 BUILDIN_DEF(sc_end,"i?"),
19373 BUILDIN_DEF(getscrate,"ii?"),
19374 BUILDIN_DEF(debugmes,"s"),
19375 BUILDIN_DEF2(catchpet,"pet","i"),
19376 BUILDIN_DEF2(birthpet,"bpet",""),
19377 BUILDIN_DEF(resetlvl,"i"),
19378 BUILDIN_DEF(resetstatus,""),
19379 BUILDIN_DEF(resetskill,""),
19380 BUILDIN_DEF(skillpointcount,""),
19381 BUILDIN_DEF(changebase,"i?"),
19382 BUILDIN_DEF(changesex,""),
19383 BUILDIN_DEF(waitingroom,"si?????"),
19384 BUILDIN_DEF(delwaitingroom,"?"),
19385 BUILDIN_DEF2(waitingroomkickall,"kickwaitingroomall","?"),
19386 BUILDIN_DEF(enablewaitingroomevent,"?"),
19387 BUILDIN_DEF(disablewaitingroomevent,"?"),
19388 BUILDIN_DEF2(enablewaitingroomevent,"enablearena",""), // Added by RoVeRT
19389 BUILDIN_DEF2(disablewaitingroomevent,"disablearena",""), // Added by RoVeRT
19390 BUILDIN_DEF(getwaitingroomstate,"i?"),
19391 BUILDIN_DEF(warpwaitingpc,"sii?"),
19392 BUILDIN_DEF(attachrid,"i"),
19393 BUILDIN_DEF(detachrid,""),
19394 BUILDIN_DEF(isloggedin,"i?"),
19395 BUILDIN_DEF(setmapflagnosave,"ssii"),
19396 BUILDIN_DEF(getmapflag,"si"),
19397 BUILDIN_DEF(setmapflag,"si?"),
19398 BUILDIN_DEF(removemapflag,"si"),
19399 BUILDIN_DEF(pvpon,"s"),
19400 BUILDIN_DEF(pvpoff,"s"),
19401 BUILDIN_DEF(gvgon,"s"),
19402 BUILDIN_DEF(gvgoff,"s"),
19403 BUILDIN_DEF(emotion,"i??"),
19404 BUILDIN_DEF(maprespawnguildid,"sii"),
19405 BUILDIN_DEF(agitstart,"?"), // <Agit>
19406 BUILDIN_DEF(agitend,""),
19407 BUILDIN_DEF(agitcheck,""), // <Agitcheck>
19408 BUILDIN_DEF(flagemblem,"i?"), // Flag Emblem
19409 BUILDIN_DEF(getcastlename,"s"),
19410 BUILDIN_DEF(getcastledata,"si?"),
19411 BUILDIN_DEF(setcastledata,"sii"),
19412 BUILDIN_DEF(requestguildinfo,"i?"),
19413 BUILDIN_DEF(getequipcardcnt,"i"),
19414 BUILDIN_DEF(successremovecards,"i"),
19415 BUILDIN_DEF(failedremovecards,"ii"),
19416 BUILDIN_DEF(marriage,"s"),
19417 BUILDIN_DEF2(wedding_effect,"wedding",""),
19418 BUILDIN_DEF(divorce,""),
19419 BUILDIN_DEF(ispartneron,""),
19420 BUILDIN_DEF(getpartnerid,""),
19421 BUILDIN_DEF(getchildid,""),
19422 BUILDIN_DEF(getmotherid,""),
19423 BUILDIN_DEF(getfatherid,""),
19424 BUILDIN_DEF(warppartner,"sii"),
19425 BUILDIN_DEF(getitemname,"v"),
19426 BUILDIN_DEF(getitemslots,"i"),
19427 BUILDIN_DEF(makepet,"i"),
19428 BUILDIN_DEF(getexp,"ii?"), // [Zephyrus] Added Custom Exp Rates
19429 BUILDIN_DEF(getinventorylist,""),
19430 BUILDIN_DEF(getskilllist,""),
19431 BUILDIN_DEF(clearitem,""),
19432 BUILDIN_DEF(classchange,"ii"),
19433 BUILDIN_DEF(misceffect,"i"),
19434 BUILDIN_DEF(playBGM,"s"),
19435 BUILDIN_DEF(playBGMall,"s?????"),
19436 BUILDIN_DEF(soundeffect,"si"),
19437 BUILDIN_DEF(soundeffectall,"si?????"), // SoundEffectAll [Codemaster]
19438 BUILDIN_DEF(strmobinfo,"ii"), // display mob data [Valaris]
19439 BUILDIN_DEF(guardian,"siisi??"), // summon guardians
19440 BUILDIN_DEF(guardianinfo,"sii"), // display guardian data [Valaris]
19441 BUILDIN_DEF(petskillbonus,"iiii"), // [Valaris]
19442 BUILDIN_DEF(petrecovery,"ii"), // [Valaris]
19443 BUILDIN_DEF(petloot,"i"), // [Valaris]
19444 BUILDIN_DEF(petheal,"iiii"), // [Valaris]
19445 BUILDIN_DEF(petskillattack,"viii"), // [Skotlex]
19446 BUILDIN_DEF(petskillattack2,"viiii"), // [Valaris]
19447 BUILDIN_DEF(petskillsupport,"viiii"), // [Skotlex]
19448 BUILDIN_DEF(skilleffect,"vi"), // skill effect [Celest]
19449 BUILDIN_DEF(npcskilleffect,"viii"), // npc skill effect [Valaris]
19450 BUILDIN_DEF(specialeffect,"i??"), // npc skill effect [Valaris]
19451 BUILDIN_DEF(specialeffect2,"i??"), // skill effect on players[Valaris]
19452 BUILDIN_DEF(nude,""), // nude command [Valaris]
19453 BUILDIN_DEF(mapwarp,"ssii??"), // Added by RoVeRT
19454 BUILDIN_DEF(atcommand,"s"), // [MouseJstr]
19455 BUILDIN_DEF(charcommand,"s"), // [MouseJstr]
19456 BUILDIN_DEF(movenpc,"sii"), // [MouseJstr]
19457 BUILDIN_DEF(message,"ss"), // [MouseJstr]
19458 BUILDIN_DEF(npctalk,"s"), // [Valaris]
19459 BUILDIN_DEF(mobcount,"ss"),
19460 BUILDIN_DEF(getlook,"i"),
19461 BUILDIN_DEF(getsavepoint,"i"),
19462 BUILDIN_DEF(npcspeed,"i"), // [Valaris]
19463 BUILDIN_DEF(npcwalkto,"ii"), // [Valaris]
19464 BUILDIN_DEF(npcstop,""), // [Valaris]
19465 BUILDIN_DEF(getmapxy,"rrri?"), //by Lorky [Lupus]
19466 BUILDIN_DEF(checkoption1,"i"),
19467 BUILDIN_DEF(checkoption2,"i"),
19468 BUILDIN_DEF(guildgetexp,"i"),
19469 BUILDIN_DEF(guildchangegm,"is"),
19470 BUILDIN_DEF(logmes,"s"), //this command actls as MES but rints info into LOG file either SQL/TXT [Lupus]
19471 BUILDIN_DEF(summon,"si??"), // summons a slave monster [Celest]
19472 BUILDIN_DEF(summonspecial,"siiii?"), // Un Slave Monster del tipo evento [Zephyrus] - (nombre del mob, class, hp+, tiempo del mob, mostrarhp, evento)
19473 BUILDIN_DEF(summongroup,"ii*"), // El anterior pero en grupos
19474 BUILDIN_DEF(isnight,""), // check whether it is night time [Celest]
19475 BUILDIN_DEF(isday,""), // check whether it is day time [Celest]
19476 BUILDIN_DEF(isequipped,"i*"), // check whether another item/card has been equipped [Celest]
19477 BUILDIN_DEF(isequippedcnt,"i*"), // check how many items/cards are being equipped [Celest]
19478 BUILDIN_DEF(cardscnt,"i*"), // check how many items/cards are being equipped in the same arm [Lupus]
19479 BUILDIN_DEF(getrefine,""), // returns the refined number of the current item, or an item with index specified [celest]
19480 BUILDIN_DEF(night,""), // sets the server to night time
19481 BUILDIN_DEF(day,""), // sets the server to day time
19482#ifdef PCRE_SUPPORT
19483 BUILDIN_DEF(defpattern,"iss"), // Define pattern to listen for [MouseJstr]
19484 BUILDIN_DEF(activatepset,"i"), // Activate a pattern set [MouseJstr]
19485 BUILDIN_DEF(deactivatepset,"i"), // Deactive a pattern set [MouseJstr]
19486 BUILDIN_DEF(deletepset,"i"), // Delete a pattern set [MouseJstr]
19487#endif
19488 BUILDIN_DEF(dispbottom,"s"), //added from jA [Lupus]
19489 BUILDIN_DEF(getusersname,""),
19490 BUILDIN_DEF(recovery,""),
19491 BUILDIN_DEF(getpetinfo,"i"),
19492 BUILDIN_DEF(gethominfo,"i"),
19493 BUILDIN_DEF(getmercinfo,"i?"),
19494 BUILDIN_DEF(checkequipedcard,"i"),
19495 BUILDIN_DEF(jump_zero,"il"), //for future jA script compatibility
19496 BUILDIN_DEF(globalmes,"s?"),
19497 BUILDIN_DEF(getmapmobs,"s"), //end jA addition
19498 BUILDIN_DEF(unequip,"i"), // unequip command [Spectre]
19499 BUILDIN_DEF(getstrlen,"s"), //strlen [Valaris]
19500 BUILDIN_DEF(charisalpha,"si"), //isalpha [Valaris]
19501 BUILDIN_DEF(charat,"si"),
19502 BUILDIN_DEF(setchar,"ssi"),
19503 BUILDIN_DEF(insertchar,"ssi"),
19504 BUILDIN_DEF(delchar,"si"),
19505 BUILDIN_DEF(strtoupper,"s"),
19506 BUILDIN_DEF(strtolower,"s"),
19507 BUILDIN_DEF(charisupper, "si"),
19508 BUILDIN_DEF(charislower, "si"),
19509 BUILDIN_DEF(substr,"sii"),
19510 BUILDIN_DEF(explode, "rss"),
19511 BUILDIN_DEF(implode, "r?"),
19512 BUILDIN_DEF(sprintf,"s*"), // [Mirei]
19513 BUILDIN_DEF(sscanf,"ss*"), // [Mirei]
19514 BUILDIN_DEF(strpos,"ss?"),
19515 BUILDIN_DEF(replacestr,"sss??"),
19516 BUILDIN_DEF(countstr,"ss?"),
19517 BUILDIN_DEF(setnpcdisplay,"sv??"),
19518 BUILDIN_DEF(compare,"ss"), // Lordalfa - To bring strstr to scripting Engine.
19519 BUILDIN_DEF(getiteminfo,"ii"), //[Lupus] returns Items Buy / sell Price, etc info
19520 BUILDIN_DEF(getitemisrefinable,"i"), // [Zephyrus] Report if the item is refinable
19521 BUILDIN_DEF(getitemisequipable,"i"), // [Zephyrus] Reports if the item is equipable by sd
19522 BUILDIN_DEF(setiteminfo,"iii"), //[Lupus] set Items Buy / sell Price, etc info
19523 BUILDIN_DEF(getequipcardid,"ii"), //[Lupus] returns CARD ID or other info from CARD slot N of equipped item
19524 // [zBuffer] List of mathematics commands --->
19525 BUILDIN_DEF(sqrt,"i"),
19526 BUILDIN_DEF(pow,"ii"),
19527 BUILDIN_DEF(distance,"iiii"),
19528 // <--- [zBuffer] List of mathematics commands
19529 BUILDIN_DEF(md5,"s"),
19530 // [zBuffer] List of dynamic var commands --->
19531 BUILDIN_DEF(getd,"s"),
19532 BUILDIN_DEF(setd,"sv"),
19533 // <--- [zBuffer] List of dynamic var commands
19534 BUILDIN_DEF(petstat,"i"),
19535 BUILDIN_DEF(callshop,"s?"), // [Skotlex]
19536 BUILDIN_DEF(npcshopitem,"sii*"), // [Lance]
19537 BUILDIN_DEF(npcshopadditem,"sii*"),
19538 BUILDIN_DEF(npcshopdelitem,"si*"),
19539 BUILDIN_DEF(npcshopattach,"s?"),
19540 BUILDIN_DEF(equip,"i"),
19541 BUILDIN_DEF(setbattleflag,"si"),
19542 BUILDIN_DEF(getbattleflag,"s"),
19543 BUILDIN_DEF(setitemscript,"is?"), //Set NEW item bonus script. Lupus
19544 BUILDIN_DEF(disguise,"i"), //disguise player. Lupus
19545 BUILDIN_DEF(undisguise,""), //undisguise player. Lupus
19546 BUILDIN_DEF(isdisguised,""), // [Zephyrus]
19547 BUILDIN_DEF(getmonsterinfo,"ii"), //Lupus
19548 BUILDIN_DEF(axtoi,"s"),
19549 BUILDIN_DEF(query_sql,"s*"),
19550 BUILDIN_DEF(query_logsql,"s*"),
19551 BUILDIN_DEF(escape_sql,"v"),
19552 BUILDIN_DEF(atoi,"s"),
19553 // [zBuffer] List of player cont commands --->
19554 BUILDIN_DEF(rid2name,"i"),
19555 BUILDIN_DEF(pcfollow,"ii"),
19556 BUILDIN_DEF(pcstopfollow,"i"),
19557 BUILDIN_DEF(pcblock,"ii?"),
19558 BUILDIN_DEF(pcblockmove,"ii"),
19559 // <--- [zBuffer] List of player cont commands
19560 // [zBuffer] List of mob control commands --->
19561 BUILDIN_DEF(unitwalk,"ii?"),
19562 BUILDIN_DEF(unitkill,"i"),
19563 BUILDIN_DEF(unitwarp,"isii"),
19564 BUILDIN_DEF(unitattack,"iv?"),
19565 BUILDIN_DEF(unitstop,"i"),
19566 BUILDIN_DEF(unittalk,"is"),
19567 BUILDIN_DEF(unitemote,"ii"),
19568 BUILDIN_DEF(unitskilluseid,"ivi?"), // originally by Qamera [Celest]
19569 BUILDIN_DEF(unitskillusepos,"iviii"), // [Celest]
19570// <--- [zBuffer] List of mob control commands
19571 BUILDIN_DEF(sleep,"i"),
19572 BUILDIN_DEF(sleep2,"i"),
19573 BUILDIN_DEF(awake,"s"),
19574 BUILDIN_DEF(getvariableofnpc,"rs"),
19575 BUILDIN_DEF(warpportal,"iisii"),
19576 BUILDIN_DEF2(homunculus_evolution,"homevolution",""), //[orn]
19577 BUILDIN_DEF2(homunculus_shuffle,"homshuffle",""), //[Zephyrus]
19578 BUILDIN_DEF(eaclass,"?"), //[Skotlex]
19579 BUILDIN_DEF(roclass,"i?"), //[Skotlex]
19580 BUILDIN_DEF(checkvending,"?"),
19581 BUILDIN_DEF(checkchatting,"?"),
19582 BUILDIN_DEF(openmail,""),
19583 BUILDIN_DEF(openauction,""),
19584 BUILDIN_DEF(checkcell,"siii"),
19585 BUILDIN_DEF(setcell,"siiiiii"),
19586 BUILDIN_DEF(chatmessage,"sii"),
19587 BUILDIN_DEF(strcmpi,"ss"),
19588 BUILDIN_DEF(flooritem,"ii"),
19589 BUILDIN_DEF(flooritem2xy,"siiii"),
19590 BUILDIN_DEF(partyitem,"ii"),
19591 BUILDIN_DEF(mission_sethunting,"iii"),
19592 BUILDIN_DEF(mission_settime,"i"),
19593 BUILDIN_DEF(killslaves,""),
19594 BUILDIN_DEF(class2ancientwoe,""),
19595 BUILDIN_DEF(pvpeventstart,""),
19596 BUILDIN_DEF(pvpeventstop,""),
19597 BUILDIN_DEF(pvpeventcheck,""),
19598 BUILDIN_DEF(pvpevent_addpoints,"i"),
19599 BUILDIN_DEF(setwall,"siiiiis"),
19600 BUILDIN_DEF(delwall,"s"),
19601 BUILDIN_DEF(searchitem,"rs"),
19602 BUILDIN_DEF(mercenary_create,"ii"),
19603 BUILDIN_DEF(mercenary_heal,"ii"),
19604 BUILDIN_DEF(mercenary_sc_start,"iii"),
19605 BUILDIN_DEF(mercenary_get_calls,"i"),
19606 BUILDIN_DEF(mercenary_get_faith,"i"),
19607 BUILDIN_DEF(mercenary_set_calls,"ii"),
19608 BUILDIN_DEF(mercenary_set_faith,"ii"),
19609 BUILDIN_DEF(readbook,"ii"),
19610 BUILDIN_DEF(setfont,"i"),
19611 BUILDIN_DEF(areamobuseskill,"siiiiviiiii"),
19612 BUILDIN_DEF(progressbar,"si"),
19613 BUILDIN_DEF(pushpc,"ii"),
19614 BUILDIN_DEF(buyingstore,"i"),
19615 BUILDIN_DEF(searchstores,"ii"),
19616 BUILDIN_DEF(showdigit,"i?"),
19617 // WoE SE
19618 BUILDIN_DEF(agitstart2,"?"),
19619 BUILDIN_DEF(agitend2,""),
19620 BUILDIN_DEF(agitcheck2,""),
19621 // BattleGround
19622 BUILDIN_DEF(bg_logincount,""),
19623 BUILDIN_DEF(map_logincount,"s"),
19624 BUILDIN_DEF(bg_team_create,"siiiss"),
19625
19626 BUILDIN_DEF(bg_queue_create,"ss?"),
19627 BUILDIN_DEF(bg_queue_event,"is"),
19628 BUILDIN_DEF(bg_queue_join,"i"),
19629 BUILDIN_DEF(bg_queue_partyjoin,"ii"),
19630 BUILDIN_DEF(bg_queue_leave,"i"),
19631 BUILDIN_DEF(bg_queue_data,"ii"),
19632 BUILDIN_DEF(bg_queue2team,"iisiiiss"),
19633 BUILDIN_DEF(bg_queue2team_single,"iisii"),
19634 BUILDIN_DEF(bg_queue2teams,"iiiiii*"),
19635 BUILDIN_DEF(bg_queue_checkstart,"iiii"),
19636 BUILDIN_DEF(bg_balance_teams,"iiiii*"),
19637
19638 BUILDIN_DEF(waitingroom2bg,"siiiss"),
19639 BUILDIN_DEF(waitingroom2bg_single,"isiis"),
19640 BUILDIN_DEF(bg_team_setxy,"iii"),
19641 BUILDIN_DEF(bg_team_reveal,"i"),
19642 BUILDIN_DEF(bg_team_setquest,"ii"),
19643 BUILDIN_DEF(bg_warp,"isii"),
19644 BUILDIN_DEF(bg_monster,"isiisi?"),
19645 BUILDIN_DEF(bg_monster_reveal,"iii"),
19646 BUILDIN_DEF(bg_monster_set_team,"ii"),
19647 BUILDIN_DEF(bg_monster_inmunity,"ii"),
19648 BUILDIN_DEF(bg_leave,""),
19649 BUILDIN_DEF(bg_cleanmap,"s"),
19650 BUILDIN_DEF(bg_destroy,"i"),
19651 BUILDIN_DEF(bg_clean,"i"),
19652 BUILDIN_DEF(areapercentheal,"siiiiii"),
19653 BUILDIN_DEF(bg_get_data,"ii"),
19654 BUILDIN_DEF(bg_getareausers,"isiiii"),
19655 BUILDIN_DEF(bg_rankpoints,"si?"),
19656 BUILDIN_DEF(bg_rankpoints_area,"isiiiisi"),
19657 BUILDIN_DEF(bg_updatescore,"sii"),
19658 BUILDIN_DEF(bg_team_updatescore,"ii"),
19659 BUILDIN_DEF(bg_team_guildid,"i"),
19660 BUILDIN_DEF(bg_getitem,"iii"),
19661 BUILDIN_DEF(bg_getkafrapoints,"ii"),
19662 BUILDIN_DEF(bg_reward,"iiiiisiii"),
19663 BUILDIN_DEF(bgannounce,"s?????"),
19664
19665 // Instancing
19666 BUILDIN_DEF(instance_create,"si"),
19667 BUILDIN_DEF(instance_destroy,"?"),
19668 BUILDIN_DEF(instance_attachmap,"si?"),
19669 BUILDIN_DEF(instance_detachmap,"s?"),
19670 BUILDIN_DEF(instance_attach,"i"),
19671 BUILDIN_DEF(instance_id,"?"),
19672 BUILDIN_DEF(instance_set_timeout,"ii?"),
19673 BUILDIN_DEF(instance_init,"i"),
19674 BUILDIN_DEF(instance_announce,"isi?????"),
19675 BUILDIN_DEF(instance_npcname,"s?"),
19676 BUILDIN_DEF(has_instance,"s?"),
19677 BUILDIN_DEF(instance_warpall,"sii?"),
19678
19679 //Quest Log System [Inkfish]
19680 BUILDIN_DEF(setquest, "i"),
19681 BUILDIN_DEF(erasequest, "i"),
19682 BUILDIN_DEF(completequest, "i"),
19683 BUILDIN_DEF(checkquest, "i?"),
19684 BUILDIN_DEF(changequest, "ii"),
19685 BUILDIN_DEF(showevent, "ii"),
19686
19687 //Bind Clock [CreativeSD]
19688 BUILDIN_DEF(bindclock, "ss"),
19689 BUILDIN_DEF(unbindclock, "ss"),
19690 BUILDIN_DEF(checkbindclock, "ss"),
19691
19692 BUILDIN_DEF(addrestock,"vi"),
19693 BUILDIN_DEF(delrestock,"v"),
19694 // Enchanting - Costume
19695 BUILDIN_DEF(costume,"i"),
19696 BUILDIN_DEF(successenchant,"ii"),
19697 BUILDIN_DEF(failedenchant,"i"),
19698
19699 BUILDIN_DEF(get_playtime,""),
19700 BUILDIN_DEF(isPremium,""),
19701 BUILDIN_DEF(rankreset,"i"),
19702 BUILDIN_DEF(item_remove4all,"i"),
19703 BUILDIN_DEF(guild_addzenyeco,"i"),
19704 BUILDIN_DEF(guild_addzenydef,"i"),
19705 BUILDIN_DEF(getpvpmode,""),
19706 BUILDIN_DEF(setsecurity,"i"),
19707 BUILDIN_DEF(getsecurity,""),
19708
19709 // At Command Events [ToastOfDoom]
19710 BUILDIN_DEF(bindatcmd, "ss??"),
19711 BUILDIN_DEF(unbindatcmd, "s"),
19712 BUILDIN_DEF(useatcmd, "s"),
19713
19714 BUILDIN_DEF(graveyard_info,"i"),
19715 BUILDIN_DEF(achieve,"i"),
19716 BUILDIN_DEF(achievement_info,"ii"),
19717 BUILDIN_DEF(achieve_progress,"i"),
19718 BUILDIN_DEF(setfaction,"i"),
19719 BUILDIN_DEF(language,"i"),
19720 BUILDIN_DEF(learnlang,"i"),
19721 BUILDIN_DEF(unlearnlang,"i"),
19722
19723 {NULL,NULL,NULL},
19724};