· 9 years ago · Dec 12, 2016, 02:24 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#include "../common/malloc.h"
12#include "../common/md5calc.h"
13#include "../common/lock.h"
14#include "../common/nullpo.h"
15#include "../common/showmsg.h"
16#include "../common/strlib.h"
17#include "../common/timer.h"
18#include "../common/utils.h"
19
20#include "map.h"
21#include "path.h"
22#include "clif.h"
23#include "chrif.h"
24#include "itemdb.h"
25#include "pc.h"
26#include "status.h"
27#include "storage.h"
28#include "mob.h"
29#include "npc.h"
30#include "pet.h"
31#include "mapreg.h"
32#include "homunculus.h"
33#include "instance.h"
34#include "mercenary.h"
35#include "intif.h"
36#include "skill.h"
37#include "status.h"
38#include "chat.h"
39#include "battle.h"
40#include "battleground.h"
41#include "party.h"
42#include "guild.h"
43#include "atcommand.h"
44#include "log.h"
45#include "unit.h"
46#include "pet.h"
47#include "mail.h"
48#include "script.h"
49#include "quest.h"
50
51#include <stdio.h>
52#include <stdlib.h>
53#include <string.h>
54#include <math.h>
55#ifndef WIN32
56 #include <sys/time.h>
57#endif
58#include <time.h>
59#include <setjmp.h>
60#include <errno.h>
61
62
63///////////////////////////////////////////////////////////////////////////////
64//## TODO possible enhancements: [FlavioJS]
65// - 'callfunc' supporting labels in the current npc "::LabelName"
66// - 'callfunc' supporting labels in other npcs "NpcName::LabelName"
67// - 'function FuncName;' function declarations reverting to global functions
68// if local label isn't found
69// - join callfunc and callsub's functionality
70// - remove dynamic allocation in add_word()
71// - remove GETVALUE / SETVALUE
72// - clean up the set_reg / set_val / setd_sub mess
73// - detect invalid label references at parse-time
74
75//
76// struct script_state* st;
77//
78
79/// Returns the script_data at the target index
80#define script_getdata(st,i) ( &((st)->stack->stack_data[(st)->start + (i)]) )
81/// Returns if the stack contains data at the target index
82#define script_hasdata(st,i) ( (st)->end > (st)->start + (i) )
83/// Returns the index of the last data in the stack
84#define script_lastdata(st) ( (st)->end - (st)->start - 1 )
85/// Pushes an int into the stack
86#define script_pushint(st,val) push_val((st)->stack, C_INT, (val))
87/// Pushes a string into the stack (script engine frees it automatically)
88#define script_pushstr(st,val) push_str((st)->stack, C_STR, (val))
89/// Pushes a copy of a string into the stack
90#define script_pushstrcopy(st,val) push_str((st)->stack, C_STR, aStrdup(val))
91/// Pushes a constant string into the stack (must never change or be freed)
92#define script_pushconststr(st,val) push_str((st)->stack, C_CONSTSTR, (val))
93/// Pushes a nil into the stack
94#define script_pushnil(st) push_val((st)->stack, C_NOP, 0)
95/// Pushes a copy of the data in the target index
96#define script_pushcopy(st,i) push_copy((st)->stack, (st)->start + (i))
97
98#define script_isstring(st,i) data_isstring(script_getdata(st,i))
99#define script_isint(st,i) data_isint(script_getdata(st,i))
100
101#define script_getnum(st,val) conv_num(st, script_getdata(st,val))
102#define script_getstr(st,val) conv_str(st, script_getdata(st,val))
103#define script_getref(st,val) ( script_getdata(st,val)->ref )
104
105// Note: "top" functions/defines use indexes relative to the top of the stack
106// -1 is the index of the data at the top
107
108/// Returns the script_data at the target index relative to the top of the stack
109#define script_getdatatop(st,i) ( &((st)->stack->stack_data[(st)->stack->sp + (i)]) )
110/// Pushes a copy of the data in the target index relative to the top of the stack
111#define script_pushcopytop(st,i) push_copy((st)->stack, (st)->stack->sp + (i))
112/// Removes the range of values [start,end[ relative to the top of the stack
113#define script_removetop(st,start,end) ( pop_stack((st), ((st)->stack->sp + (start)), (st)->stack->sp + (end)) )
114
115//
116// struct script_data* data;
117//
118
119/// Returns if the script data is a string
120#define data_isstring(data) ( (data)->type == C_STR || (data)->type == C_CONSTSTR )
121/// Returns if the script data is an int
122#define data_isint(data) ( (data)->type == C_INT )
123/// Returns if the script data is a reference
124#define data_isreference(data) ( (data)->type == C_NAME )
125/// Returns if the script data is a label
126#define data_islabel(data) ( (data)->type == C_POS )
127/// Returns if the script data is an internal script function label
128#define data_isfunclabel(data) ( (data)->type == C_USERFUNC_POS )
129
130/// Returns if this is a reference to a constant
131#define reference_toconstant(data) ( str_data[reference_getid(data)].type == C_INT )
132/// Returns if this a reference to a param
133#define reference_toparam(data) ( str_data[reference_getid(data)].type == C_PARAM )
134/// Returns if this a reference to a variable
135//##TODO confirm it's C_NAME [FlavioJS]
136#define reference_tovariable(data) ( str_data[reference_getid(data)].type == C_NAME )
137/// Returns if this a reference to nil (unused name, is probably supposed to be a variable)
138#define reference_tonil(data) ( str_data[reference_getid(data)].type == C_NOP )
139/// Returns the unique id of the reference (id and index)
140#define reference_getuid(data) ( (data)->u.num )
141/// Returns the id of the reference
142#define reference_getid(data) ( (int32)(reference_getuid(data) & 0x00ffffff) )
143/// Returns the array index of the reference
144#define reference_getindex(data) ( (int32)(((uint32)(reference_getuid(data) & 0xff000000)) >> 24) )
145/// Returns the name of the reference
146#define reference_getname(data) ( str_buf + str_data[reference_getid(data)].str )
147/// Returns the linked list of uid-value pairs of the reference (can be NULL)
148#define reference_getref(data) ( (data)->ref )
149/// Returns the value of the constant
150#define reference_getconstant(data) ( str_data[reference_getid(data)].val )
151/// Returns the type of param
152#define reference_getparamtype(data) ( str_data[reference_getid(data)].val )
153
154/// Composes the uid of a reference from the id and the index
155#define reference_uid(id,idx) ( (int32)((((uint32)(id)) & 0x00ffffff) | (((uint32)(idx)) << 24)) )
156
157#define not_server_variable(prefix) ( (prefix) != '$' && (prefix) != '.' && (prefix) != '\'')
158#define not_array_variable(prefix) ( (prefix) != '$' && (prefix) != '@' && (prefix) != '.' && (prefix) != '\'' )
159#define is_string_variable(name) ( (name)[strlen(name) - 1] == '$' )
160
161#define FETCH(n, t) \
162 if( script_hasdata(st,n) ) \
163 (t)=script_getnum(st,n);
164
165/// Maximum amount of elements in script arrays
166#define SCRIPT_MAX_ARRAYSIZE 128
167
168#define SCRIPT_BLOCK_SIZE 512
169enum { LABEL_NEXTLINE=1,LABEL_START };
170
171/// temporary buffer for passing around compiled bytecode
172/// @see add_scriptb, set_label, parse_script
173static unsigned char* script_buf = NULL;
174static int script_pos = 0, script_size = 0;
175
176static inline int GETVALUE(const unsigned char* buf, int i)
177{
178 return (int)MakeDWord(MakeWord(buf[i], buf[i+1]), MakeWord(buf[i+2], 0));
179}
180static inline void SETVALUE(unsigned char* buf, int i, int n)
181{
182 buf[i] = GetByte(n, 0);
183 buf[i+1] = GetByte(n, 1);
184 buf[i+2] = GetByte(n, 2);
185}
186
187// String buffer structures.
188// str_data stores string information
189static struct str_data_struct {
190 enum c_op type;
191 int str;
192 int backpatch;
193 int label;
194 int (*func)(struct script_state *st);
195 int val;
196 int next;
197} *str_data = NULL;
198static int str_data_size = 0; // size of the data
199static int str_num = LABEL_START; // next id to be assigned
200
201// str_buf holds the strings themselves
202static char *str_buf;
203static int str_size = 0; // size of the buffer
204static int str_pos = 0; // next position to be assigned
205
206
207// Using a prime number for SCRIPT_HASH_SIZE should give better distributions
208#define SCRIPT_HASH_SIZE 1021
209int str_hash[SCRIPT_HASH_SIZE];
210// Specifies which string hashing method to use
211//#define SCRIPT_HASH_DJB2
212//#define SCRIPT_HASH_SDBM
213#define SCRIPT_HASH_ELF
214
215static DBMap* scriptlabel_db=NULL; // const char* label_name -> int script_pos
216static DBMap* userfunc_db=NULL; // const char* func_name -> struct script_code*
217static int parse_options=0;
218DBMap* script_get_label_db(){ return scriptlabel_db; }
219DBMap* script_get_userfunc_db(){ return userfunc_db; }
220
221// Caches compiled autoscript item code.
222// Note: This is not cleared when reloading itemdb.
223static DBMap* autobonus_db=NULL; // char* script -> char* bytecode
224
225struct Script_Config script_config = {
226 1, // warn_func_mismatch_argtypes
227 1, 65535, 2048, //warn_func_mismatch_paramnum/check_cmdcount/check_gotocount
228 0, INT_MAX, // input_min_value/input_max_value
229 "OnPCDieEvent", //die_event_name
230 "OnPCKillEvent", //kill_pc_event_name
231 "OnNPCKillEvent", //kill_mob_event_name
232 "OnPCLoginEvent", //login_event_name
233 "OnPCLogoutEvent", //logout_event_name
234 "OnPCLoadMapEvent", //loadmap_event_name
235 "OnPCBaseLvUpEvent", //baselvup_event_name
236 "OnPCJobLvUpEvent", //joblvup_event_name
237 "OnTouch_", //ontouch_name (runs on first visible char to enter area, picks another char if the first char leaves)
238 "OnTouch", //ontouch2_name (run whenever a char walks into the OnTouch area)
239};
240
241static jmp_buf error_jump;
242static char* error_msg;
243static const char* error_pos;
244static int error_report; // if the error should produce output
245
246// for advanced scripting support ( nested if, switch, while, for, do-while, function, etc )
247// [Eoe / jA 1080, 1081, 1094, 1164]
248enum curly_type {
249 TYPE_NULL = 0,
250 TYPE_IF,
251 TYPE_SWITCH,
252 TYPE_WHILE,
253 TYPE_FOR,
254 TYPE_DO,
255 TYPE_USERFUNC,
256 TYPE_ARGLIST // function argument list
257};
258
259enum e_arglist
260{
261 ARGLIST_UNDEFINED = 0,
262 ARGLIST_NO_PAREN = 1,
263 ARGLIST_PAREN = 2,
264};
265
266static struct {
267 struct {
268 enum curly_type type;
269 int index;
270 int count;
271 int flag;
272 struct linkdb_node *case_label;
273 } curly[256]; // ‰EÆ’JÆ’bÆ’R‚ÌÂî•ñ
274 int curly_count; // ‰EÆ’JÆ’bÆ’R‚ÌÂâ€
275 int index; // Æ’XÆ’NÆ’Å Æ’vÆ’g“à ‚ÅŽg—p‚µ‚½Â\•¶‚ÌÂâ€
276} syntax;
277
278const char* parse_curly_close(const char* p);
279const char* parse_syntax_close(const char* p);
280const char* parse_syntax_close_sub(const char* p,int* flag);
281const char* parse_syntax(const char* p);
282static int parse_syntax_for_flag = 0;
283
284extern int current_equip_item_index; //for New CARDS Scripts. It contains Inventory Index of the EQUIP_SCRIPT caller item. [Lupus]
285int potion_flag=0; //For use on Alchemist improved potions/Potion Pitcher. [Skotlex]
286int potion_hp=0, potion_per_hp=0, potion_sp=0, potion_per_sp=0;
287int potion_target=0;
288
289
290c_op get_com(unsigned char *script,int *pos);
291int get_num(unsigned char *script,int *pos);
292
293typedef struct script_function {
294 int (*func)(struct script_state *st);
295 const char *name;
296 const char *arg;
297} script_function;
298
299extern script_function buildin_func[];
300
301static struct linkdb_node* sleep_db;// int oid -> struct script_state*
302
303/*==========================================
304 * Æ’ÂÂ[Æ’Jƒ‹ƒvÆ’ÂÆ’gÆ’^Æ’CÆ’vÂ錾 (•K—v‚È•¨‚Ì‚Ã)
305 *------------------------------------------*/
306const char* parse_subexpr(const char* p,int limit);
307int run_func(struct script_state *st);
308
309enum {
310 MF_NOMEMO, //0
311 MF_NOTELEPORT,
312 MF_NOSAVE,
313 MF_NOBRANCH,
314 MF_NOPENALTY,
315 MF_NOZENYPENALTY,
316 MF_PVP,
317 MF_PVP_NOPARTY,
318 MF_PVP_NOGUILD,
319 MF_GVG,
320 MF_GVG_NOPARTY, //10
321 MF_NOTRADE,
322 MF_NOSKILL,
323 MF_NOWARP,
324 MF_PARTYLOCK,
325 MF_NOICEWALL,
326 MF_SNOW,
327 MF_FOG,
328 MF_SAKURA,
329 MF_LEAVES,
330 MF_RAIN, //20
331 // 21 free
332 MF_NOGO = 22,
333 MF_CLOUDS,
334 MF_CLOUDS2,
335 MF_FIREWORKS,
336 MF_GVG_CASTLE,
337 MF_GVG_DUNGEON,
338 MF_NIGHTENABLED,
339 MF_NOBASEEXP,
340 MF_NOJOBEXP, //30
341 MF_NOMOBLOOT,
342 MF_NOMVPLOOT,
343 MF_NORETURN,
344 MF_NOWARPTO,
345 MF_NIGHTMAREDROP,
346 MF_RESTRICTED,
347 MF_NOCOMMAND,
348 MF_NODROP,
349 MF_JEXP,
350 MF_BEXP, //40
351 MF_NOVENDING,
352 MF_LOADEVENT,
353 MF_NOCHAT,
354 MF_NOEXPPENALTY,
355 MF_GUILDLOCK,
356 MF_TOWN,
357 MF_AUTOTRADE,
358 MF_ALLOWKS,
359 MF_MONSTER_NOTELEPORT,
360 MF_PVP_NOCALCRANK, //50
361 MF_BATTLEGROUND,
362 MF_RESET
363};
364
365const char* script_op2name(int op)
366{
367#define RETURN_OP_NAME(type) case type: return #type
368 switch( op )
369 {
370 RETURN_OP_NAME(C_NOP);
371 RETURN_OP_NAME(C_POS);
372 RETURN_OP_NAME(C_INT);
373 RETURN_OP_NAME(C_PARAM);
374 RETURN_OP_NAME(C_FUNC);
375 RETURN_OP_NAME(C_STR);
376 RETURN_OP_NAME(C_CONSTSTR);
377 RETURN_OP_NAME(C_ARG);
378 RETURN_OP_NAME(C_NAME);
379 RETURN_OP_NAME(C_EOL);
380 RETURN_OP_NAME(C_RETINFO);
381 RETURN_OP_NAME(C_USERFUNC);
382 RETURN_OP_NAME(C_USERFUNC_POS);
383
384 // operators
385 RETURN_OP_NAME(C_OP3);
386 RETURN_OP_NAME(C_LOR);
387 RETURN_OP_NAME(C_LAND);
388 RETURN_OP_NAME(C_LE);
389 RETURN_OP_NAME(C_LT);
390 RETURN_OP_NAME(C_GE);
391 RETURN_OP_NAME(C_GT);
392 RETURN_OP_NAME(C_EQ);
393 RETURN_OP_NAME(C_NE);
394 RETURN_OP_NAME(C_XOR);
395 RETURN_OP_NAME(C_OR);
396 RETURN_OP_NAME(C_AND);
397 RETURN_OP_NAME(C_ADD);
398 RETURN_OP_NAME(C_SUB);
399 RETURN_OP_NAME(C_MUL);
400 RETURN_OP_NAME(C_DIV);
401 RETURN_OP_NAME(C_MOD);
402 RETURN_OP_NAME(C_NEG);
403 RETURN_OP_NAME(C_LNOT);
404 RETURN_OP_NAME(C_NOT);
405 RETURN_OP_NAME(C_R_SHIFT);
406 RETURN_OP_NAME(C_L_SHIFT);
407
408 default:
409 ShowDebug("script_op2name: unexpected op=%d\n", op);
410 return "???";
411 }
412#undef RETURN_OP_NAME
413}
414
415#ifdef DEBUG_DUMP_STACK
416static void script_dump_stack(struct script_state* st)
417{
418 int i;
419 ShowMessage("\tstart = %d\n", st->start);
420 ShowMessage("\tend = %d\n", st->end);
421 ShowMessage("\tdefsp = %d\n", st->stack->defsp);
422 ShowMessage("\tsp = %d\n", st->stack->sp);
423 for( i = 0; i < st->stack->sp; ++i )
424 {
425 struct script_data* data = &st->stack->stack_data[i];
426 ShowMessage("\t[%d] %s", i, script_op2name(data->type));
427 switch( data->type )
428 {
429 case C_INT:
430 case C_POS:
431 ShowMessage(" %d\n", data->u.num);
432 break;
433
434 case C_STR:
435 case C_CONSTSTR:
436 ShowMessage(" \"%s\"\n", data->u.str);
437 break;
438
439 case C_NAME:
440 ShowMessage(" \"%s\" (id=%d ref=%p subtype=%s)\n", reference_getname(data), data->u.num, data->ref, script_op2name(str_data[data->u.num].type));
441 break;
442
443 case C_RETINFO:
444 {
445 struct script_retinfo* ri = data->u.ri;
446 ShowMessage(" %p {var_function=%p, script=%p, pos=%d, nargs=%d, defsp=%d}\n", ri, ri->var_function, ri->script, ri->pos, ri->nargs, ri->defsp);
447 }
448 break;
449 default:
450 ShowMessage("\n");
451 break;
452 }
453 }
454}
455#endif
456
457/// Reports on the console the src of a script error.
458static void script_reportsrc(struct script_state *st)
459{
460 struct block_list* bl;
461
462 if( st->oid == 0 )
463 return; //Can't report source.
464
465 bl = map_id2bl(st->oid);
466 if( bl == NULL )
467 return;
468
469 switch( bl->type )
470 {
471 case BL_NPC:
472 if( bl->m >= 0 )
473 ShowDebug("Source (NPC): %s at %s (%d,%d)\n", ((struct npc_data *)bl)->name, map[bl->m].name, bl->x, bl->y);
474 else
475 ShowDebug("Source (NPC): %s (invisible/not on a map)\n", ((struct npc_data *)bl)->name);
476 break;
477 default:
478 if( bl->m >= 0 )
479 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);
480 else
481 ShowDebug("Source (Non-NPC type %d): name %s (invisible/not on a map)\n", bl->type, status_get_name(bl));
482 break;
483 }
484}
485
486/// Reports on the console information about the script data.
487static void script_reportdata(struct script_data* data)
488{
489 if( data == NULL )
490 return;
491 switch( data->type )
492 {
493 case C_NOP:// no value
494 ShowDebug("Data: nothing (nil)\n");
495 break;
496 case C_INT:// number
497 ShowDebug("Data: number value=%d\n", data->u.num);
498 break;
499 case C_STR:
500 case C_CONSTSTR:// string
501 if( data->u.str )
502 {
503 ShowDebug("Data: string value=\"%s\"\n", data->u.str);
504 }
505 else
506 {
507 ShowDebug("Data: string value=NULL\n");
508 }
509 break;
510 case C_NAME:// reference
511 if( reference_tovariable(data) )
512 {// variable
513 const char* name = reference_getname(data);
514 if( not_array_variable(*name) )
515 ShowDebug("Data: variable name='%s'\n", name);
516 else
517 ShowDebug("Data: variable name='%s' index=%d\n", name, reference_getindex(data));
518 }
519 else if( reference_toconstant(data) )
520 {// constant
521 ShowDebug("Data: constant name='%s' value=%d\n", reference_getname(data), reference_getconstant(data));
522 }
523 else if( reference_toparam(data) )
524 {// param
525 ShowDebug("Data: param name='%s' type=%d\n", reference_getname(data), reference_getparamtype(data));
526 }
527 else
528 {// ???
529 ShowDebug("Data: reference name='%s' type=%s\n", reference_getname(data), script_op2name(data->type));
530 ShowDebug("Please report this!!! - str_data.type=%s\n", script_op2name(str_data[reference_getid(data)].type));
531 }
532 break;
533 case C_POS:// label
534 ShowDebug("Data: label pos=%d\n", data->u.num);
535 break;
536 default:
537 ShowDebug("Data: %s\n", script_op2name(data->type));
538 break;
539 }
540}
541
542
543/// Reports on the console information about the current built-in function.
544static void script_reportfunc(struct script_state* st)
545{
546 int i, params, id;
547 struct script_data* data;
548
549 if( !script_hasdata(st,0) )
550 {// no stack
551 return;
552 }
553
554 data = script_getdata(st,0);
555
556 if( !data_isreference(data) || str_data[reference_getid(data)].type != C_FUNC )
557 {// script currently not executing a built-in function or corrupt stack
558 return;
559 }
560
561 id = reference_getid(data);
562 params = script_lastdata(st)-1;
563
564 if( params > 0 )
565 {
566 ShowDebug("Function: %s (%d parameter%s):\n", get_str(id), params, ( params == 1 ) ? "" : "s");
567
568 for( i = 2; i <= script_lastdata(st); i++ )
569 {
570 script_reportdata(script_getdata(st,i));
571 }
572 }
573 else
574 {
575 ShowDebug("Function: %s (no parameters)\n", get_str(id));
576 }
577}
578
579
580/*==========================================
581 * Æ’Gƒ‰Â[Æ’ÂÆ’bÆ’ZÂ[Æ’WÂo—Ã
582 *------------------------------------------*/
583static void disp_error_message2(const char *mes,const char *pos,int report)
584{
585 error_msg = aStrdup(mes);
586 error_pos = pos;
587 error_report = report;
588 longjmp( error_jump, 1 );
589}
590#define disp_error_message(mes,pos) disp_error_message2(mes,pos,1)
591
592/// Checks event parameter validity
593static void check_event(struct script_state *st, const char *evt)
594{
595 if( evt && evt[0] && !stristr(evt, "::On") )
596 {
597 if( npc_event_isspecial(evt) )
598 {
599 ; // portable small/large monsters or other attributes
600 }
601 else
602 {
603 ShowWarning("NPC event parameter deprecated! Please use 'NPCNAME::OnEVENT' instead of '%s'.\n", evt);
604 script_reportsrc(st);
605 }
606 }
607}
608
609/*==========================================
610 * Hashes the input string
611 *------------------------------------------*/
612static unsigned int calc_hash(const char* p)
613{
614 unsigned int h;
615
616#if defined(SCRIPT_HASH_DJB2)
617 h = 5381;
618 while( *p ) // hash*33 + c
619 h = ( h << 5 ) + h + ((unsigned char)TOLOWER(*p++));
620#elif defined(SCRIPT_HASH_SDBM)
621 h = 0;
622 while( *p ) // hash*65599 + c
623 h = ( h << 6 ) + ( h << 16 ) - h + ((unsigned char)TOLOWER(*p++));
624#elif defined(SCRIPT_HASH_ELF) // UNIX ELF hash
625 h = 0;
626 while( *p ){
627 unsigned int g;
628 h = ( h << 4 ) + ((unsigned char)TOLOWER(*p++));
629 g = h & 0xF0000000;
630 if( g )
631 {
632 h ^= g >> 24;
633 h &= ~g;
634 }
635 }
636#else // athena hash
637 h = 0;
638 while( *p )
639 h = ( h << 1 ) + ( h >> 3 ) + ( h >> 5 ) + ( h >> 8 ) + (unsigned char)TOLOWER(*p++);
640#endif
641
642 return h % SCRIPT_HASH_SIZE;
643}
644
645
646/*==========================================
647 * str_data manipulation functions
648 *------------------------------------------*/
649
650/// Looks up string using the provided id.
651const char* get_str(int id)
652{
653 Assert( id >= LABEL_START && id < str_size );
654 return str_buf+str_data[id].str;
655}
656
657/// Returns the uid of the string, or -1.
658static int search_str(const char* p)
659{
660 int i;
661
662 for( i = str_hash[calc_hash(p)]; i != 0; i = str_data[i].next )
663 if( strcasecmp(get_str(i),p) == 0 )
664 return i;
665
666 return -1;
667}
668
669/// Stores a copy of the string and returns its id.
670/// If an identical string is already present, returns its id instead.
671int add_str(const char* p)
672{
673 int i, h;
674 int len;
675
676 h = calc_hash(p);
677
678 if( str_hash[h] == 0 )
679 {// empty bucket, add new node here
680 str_hash[h] = str_num;
681 }
682 else
683 {// scan for end of list, or occurence of identical string
684 for( i = str_hash[h]; ; i = str_data[i].next )
685 {
686 if( strcasecmp(get_str(i),p) == 0 )
687 return i; // string already in list
688 if( str_data[i].next == 0 )
689 break; // reached the end
690 }
691
692 // append node to end of list
693 str_data[i].next = str_num;
694 }
695
696 // grow list if neccessary
697 if( str_num >= str_data_size )
698 {
699 str_data_size += 128;
700 RECREATE(str_data,struct str_data_struct,str_data_size);
701 memset(str_data + (str_data_size - 128), '\0', 128);
702 }
703
704 len=(int)strlen(p);
705
706 // grow string buffer if neccessary
707 while( str_pos+len+1 >= str_size )
708 {
709 str_size += 256;
710 RECREATE(str_buf,char,str_size);
711 memset(str_buf + (str_size - 256), '\0', 256);
712 }
713
714 safestrncpy(str_buf+str_pos, p, len+1);
715 str_data[str_num].type = C_NOP;
716 str_data[str_num].str = str_pos;
717 str_data[str_num].next = 0;
718 str_data[str_num].func = NULL;
719 str_data[str_num].backpatch = -1;
720 str_data[str_num].label = -1;
721 str_pos += len+1;
722
723 return str_num++;
724}
725
726
727/// Appends 1 byte to the script buffer.
728static void add_scriptb(int a)
729{
730 if( script_pos+1 >= script_size )
731 {
732 script_size += SCRIPT_BLOCK_SIZE;
733 RECREATE(script_buf,unsigned char,script_size);
734 }
735 script_buf[script_pos++] = (uint8)(a);
736}
737
738/// Appends a c_op value to the script buffer.
739/// The value is variable-length encoded into 8-bit blocks.
740/// The encoding scheme is ( 01?????? )* 00??????, LSB first.
741/// All blocks but the last hold 7 bits of data, topmost bit is always 1 (carries).
742static void add_scriptc(int a)
743{
744 while( a >= 0x40 )
745 {
746 add_scriptb((a&0x3f)|0x40);
747 a = (a - 0x40) >> 6;
748 }
749
750 add_scriptb(a);
751}
752
753/// Appends an integer value to the script buffer.
754/// The value is variable-length encoded into 8-bit blocks.
755/// The encoding scheme is ( 11?????? )* 10??????, LSB first.
756/// All blocks but the last hold 7 bits of data, topmost bit is always 1 (carries).
757static void add_scripti(int a)
758{
759 while( a >= 0x40 )
760 {
761 add_scriptb((a&0x3f)|0xc0);
762 a = (a - 0x40) >> 6;
763 }
764 add_scriptb(a|0x80);
765}
766
767/// Appends a str_data object (label/function/variable/integer) to the script buffer.
768
769///
770/// @param l The id of the str_data entry
771// ÂÅ‘å16M‚Ü‚Å
772static void add_scriptl(int l)
773{
774 int backpatch = str_data[l].backpatch;
775
776 switch(str_data[l].type){
777 case C_POS:
778 case C_USERFUNC_POS:
779 add_scriptc(C_POS);
780 add_scriptb(str_data[l].label);
781 add_scriptb(str_data[l].label>>8);
782 add_scriptb(str_data[l].label>>16);
783 break;
784 case C_NOP:
785 case C_USERFUNC:
786 // ƒ‰ƒxƒ‹‚̉Ââ€\«‚ª‚ ‚é‚Ì‚Åbackpatch—pÆ’fÂ[Æ’^–„‚ßž‚Ã
787 add_scriptc(C_NAME);
788 str_data[l].backpatch = script_pos;
789 add_scriptb(backpatch);
790 add_scriptb(backpatch>>8);
791 add_scriptb(backpatch>>16);
792 break;
793 case C_INT:
794 add_scripti(abs(str_data[l].val));
795 if( str_data[l].val < 0 ) //Notice that this is negative, from jA (Rayce)
796 add_scriptc(C_NEG);
797 break;
798 default: // assume C_NAME
799 add_scriptc(C_NAME);
800 add_scriptb(l);
801 add_scriptb(l>>8);
802 add_scriptb(l>>16);
803 break;
804 }
805}
806
807/*==========================================
808 * ƒ‰ƒxƒ‹‚ð‰ðŒˆ‚·‚é
809 *------------------------------------------*/
810void set_label(int l,int pos, const char* script_pos)
811{
812 int i,next;
813
814 if(str_data[l].type==C_INT || str_data[l].type==C_PARAM || str_data[l].type==C_FUNC)
815 { //Prevent overwriting constants values, parameters and built-in functions [Skotlex]
816 disp_error_message("set_label: invalid label name",script_pos);
817 return;
818 }
819 if(str_data[l].label!=-1){
820 disp_error_message("set_label: dup label ",script_pos);
821 return;
822 }
823 str_data[l].type=(str_data[l].type == C_USERFUNC ? C_USERFUNC_POS : C_POS);
824 str_data[l].label=pos;
825 for(i=str_data[l].backpatch;i>=0 && i!=0x00ffffff;){
826 next=GETVALUE(script_buf,i);
827 script_buf[i-1]=(str_data[l].type == C_USERFUNC ? C_USERFUNC_POS : C_POS);
828 SETVALUE(script_buf,i,pos);
829 i=next;
830 }
831}
832
833/// Skips spaces and/or comments.
834const char* skip_space(const char* p)
835{
836 if( p == NULL )
837 return NULL;
838 for(;;)
839 {
840 while( ISSPACE(*p) )
841 ++p;
842 if( *p == '/' && p[1] == '/' )
843 {// line comment
844 while(*p && *p!='\n')
845 ++p;
846 }
847 else if( *p == '/' && p[1] == '*' )
848 {// block comment
849 p += 2;
850 for(;;)
851 {
852 if( *p == '\0' )
853 return p;//disp_error_message("script:skip_space: end of file while parsing block comment. expected "CL_BOLD"*/"CL_NORM, p);
854 if( *p == '*' && p[1] == '/' )
855 {// end of block comment
856 p += 2;
857 break;
858 }
859 ++p;
860 }
861 }
862 else
863 break;
864 }
865 return p;
866}
867
868/// Skips a word.
869/// A word consists of undercores and/or alfanumeric characters,
870/// and valid variable prefixes/postfixes.
871static
872const char* skip_word(const char* p)
873{
874 // prefix
875 switch( *p )
876 {
877 case '@':// temporary char variable
878 ++p; break;
879 case '#':// account variable
880 p += ( p[1] == '#' ? 2 : 1 ); break;
881 case '\'':// instance variable
882 ++p; break;
883 case '.':// npc variable
884 p += ( p[1] == '@' ? 2 : 1 ); break;
885 case '$':// global variable
886 p += ( p[1] == '@' ? 2 : 1 ); break;
887 }
888
889 while( ISALNUM(*p) || *p == '_' )
890 ++p;
891
892 // postfix
893 if( *p == '$' )// string
894 p++;
895
896 return p;
897}
898
899/// Adds a word to str_data.
900/// @see skip_word
901/// @see add_str
902static
903int add_word(const char* p)
904{
905 char* word;
906 int len;
907 int i;
908
909 // Check for a word
910 len = skip_word(p) - p;
911 if( len == 0 )
912 disp_error_message("script:add_word: invalid word. A word consists of undercores and/or alfanumeric characters, and valid variable prefixes/postfixes.", p);
913
914 // Duplicate the word
915 word = (char*)aMalloc(len+1);
916 memcpy(word, p, len);
917 word[len] = 0;
918
919 // add the word
920 i = add_str(word);
921 aFree(word);
922 return i;
923}
924
925/// Parses a function call.
926/// The argument list can have parenthesis or not.
927/// The number of arguments is checked.
928static
929const char* parse_callfunc(const char* p, int require_paren)
930{
931 const char* p2;
932 const char* arg=NULL;
933 int func;
934
935 func = add_word(p);
936 if( str_data[func].type == C_FUNC ){
937 // buildin function
938 add_scriptl(func);
939 add_scriptc(C_ARG);
940 arg = buildin_func[str_data[func].val].arg;
941 } else if( str_data[func].type == C_USERFUNC || str_data[func].type == C_USERFUNC_POS ){
942 // script defined function
943 int callsub = search_str("callsub");
944 add_scriptl(callsub);
945 add_scriptc(C_ARG);
946 add_scriptl(func);
947 arg = buildin_func[str_data[callsub].val].arg;
948 if( *arg == 0 )
949 disp_error_message("parse_callfunc: callsub has no arguments, please review it's definition",p);
950 if( *arg != '*' )
951 ++arg; // count func as argument
952 } else
953 disp_error_message("parse_line: expect command, missing function name or calling undeclared function",p);
954
955 p = skip_word(p);
956 p = skip_space(p);
957 syntax.curly[syntax.curly_count].type = TYPE_ARGLIST;
958 syntax.curly[syntax.curly_count].count = 0;
959 if( *p == ';' )
960 {// <func name> ';'
961 syntax.curly[syntax.curly_count].flag = ARGLIST_NO_PAREN;
962 } else if( *p == '(' && *(p2=skip_space(p+1)) == ')' )
963 {// <func name> '(' ')'
964 syntax.curly[syntax.curly_count].flag = ARGLIST_PAREN;
965 p = p2;
966 /*
967 } else if( 0 && require_paren && *p != '(' )
968 {// <func name>
969 syntax.curly[syntax.curly_count].flag = ARGLIST_NO_PAREN;
970 */
971 } else
972 {// <func name> <arg list>
973 if( require_paren ){
974 if( *p != '(' )
975 disp_error_message("need '('",p);
976 ++p; // skip '('
977 syntax.curly[syntax.curly_count].flag = ARGLIST_PAREN;
978 } else if( *p == '(' ){
979 syntax.curly[syntax.curly_count].flag = ARGLIST_UNDEFINED;
980 } else {
981 syntax.curly[syntax.curly_count].flag = ARGLIST_NO_PAREN;
982 }
983 ++syntax.curly_count;
984 while( *arg ) {
985 p2=parse_subexpr(p,-1);
986 if( p == p2 )
987 break; // not an argument
988 if( *arg != '*' )
989 ++arg; // next argument
990
991 p=skip_space(p2);
992 if( *arg == 0 || *p != ',' )
993 break; // no more arguments
994 ++p; // skip comma
995 }
996 --syntax.curly_count;
997 }
998 if( *arg && *arg != '?' && *arg != '*' )
999 disp_error_message2("parse_callfunc: not enough arguments, expected ','", p, script_config.warn_func_mismatch_paramnum);
1000 if( syntax.curly[syntax.curly_count].type != TYPE_ARGLIST )
1001 disp_error_message("parse_callfunc: DEBUG last curly is not an argument list",p);
1002 if( syntax.curly[syntax.curly_count].flag == ARGLIST_PAREN ){
1003 if( *p != ')' )
1004 disp_error_message("parse_callfunc: expected ')' to close argument list",p);
1005 ++p;
1006 }
1007 add_scriptc(C_FUNC);
1008 return p;
1009}
1010
1011/// Processes end of logical script line.
1012/// @param first When true, only fix up scheduling data is initialized
1013/// @param p Script position for error reporting in set_label
1014static void parse_nextline(bool first, const char* p)
1015{
1016 if( !first )
1017 {
1018 add_scriptc(C_EOL); // mark end of line for stack cleanup
1019 set_label(LABEL_NEXTLINE, script_pos, p); // fix up '-' labels
1020 }
1021
1022 // initialize data for new '-' label fix up scheduling
1023 str_data[LABEL_NEXTLINE].type = C_NOP;
1024 str_data[LABEL_NEXTLINE].backpatch = -1;
1025 str_data[LABEL_NEXTLINE].label = -1;
1026}
1027
1028/*==========================================
1029 * €‚̉ðÂÃ
1030 *------------------------------------------*/
1031const char* parse_simpleexpr(const char *p)
1032{
1033 int i;
1034 p=skip_space(p);
1035
1036 if(*p==';' || *p==',')
1037 disp_error_message("parse_simpleexpr: unexpected expr end",p);
1038 if(*p=='('){
1039 if( (i=syntax.curly_count-1) >= 0 && syntax.curly[i].type == TYPE_ARGLIST )
1040 ++syntax.curly[i].count;
1041 p=parse_subexpr(p+1,-1);
1042 p=skip_space(p);
1043 if( (i=syntax.curly_count-1) >= 0 && syntax.curly[i].type == TYPE_ARGLIST &&
1044 syntax.curly[i].flag == ARGLIST_UNDEFINED && --syntax.curly[i].count == 0
1045 ){
1046 if( *p == ',' ){
1047 syntax.curly[i].flag = ARGLIST_PAREN;
1048 return p;
1049 } else
1050 syntax.curly[i].flag = ARGLIST_NO_PAREN;
1051 }
1052 if( *p != ')' )
1053 disp_error_message("parse_simpleexpr: unmatch ')'",p);
1054 ++p;
1055 } else if(ISDIGIT(*p) || ((*p=='-' || *p=='+') && ISDIGIT(p[1]))){
1056 char *np;
1057 i=strtoul(p,&np,0);
1058 add_scripti(i);
1059 p=np;
1060 } else if(*p=='"'){
1061 add_scriptc(C_STR);
1062 p++;
1063 while( *p && *p != '"' ){
1064 if( (unsigned char)p[-1] <= 0x7e && *p == '\\' )
1065 {
1066 char buf[8];
1067 size_t len = skip_escaped_c(p) - p;
1068 size_t n = sv_unescape_c(buf, p, len);
1069 if( n != 1 )
1070 ShowDebug("parse_simpleexpr: unexpected length %d after unescape (\"%.*s\" -> %.*s)\n", (int)n, (int)len, p, (int)n, buf);
1071 p += len;
1072 add_scriptb(*buf);
1073 continue;
1074 }
1075 else if( *p == '\n' )
1076 disp_error_message("parse_simpleexpr: unexpected newline @ string",p);
1077 add_scriptb(*p++);
1078 }
1079 if(!*p)
1080 disp_error_message("parse_simpleexpr: unexpected eof @ string",p);
1081 add_scriptb(0);
1082 p++; //'"'
1083 } else {
1084 int l;
1085 // label , register , function etc
1086 if(skip_word(p)==p)
1087 disp_error_message("parse_simpleexpr: unexpected character",p);
1088
1089 l=add_word(p);
1090 if( str_data[l].type == C_FUNC || str_data[l].type == C_USERFUNC || str_data[l].type == C_USERFUNC_POS)
1091 return parse_callfunc(p,1);
1092
1093 p=skip_word(p);
1094 if( *p == '[' ){
1095 // array(name[i] => getelementofarray(name,i) )
1096 add_scriptl(search_str("getelementofarray"));
1097 add_scriptc(C_ARG);
1098 add_scriptl(l);
1099
1100 p=parse_subexpr(p+1,-1);
1101 p=skip_space(p);
1102 if( *p != ']' )
1103 disp_error_message("parse_simpleexpr: unmatch ']'",p);
1104 ++p;
1105 add_scriptc(C_FUNC);
1106 }else
1107 add_scriptl(l);
1108
1109 }
1110
1111 return p;
1112}
1113
1114/*==========================================
1115 * Ž®‚̉ðÂÃ
1116 *------------------------------------------*/
1117const char* parse_subexpr(const char* p,int limit)
1118{
1119 int op,opl,len;
1120 const char* tmpp;
1121
1122 p=skip_space(p);
1123
1124 if(*p=='-'){
1125 tmpp=skip_space(p+1);
1126 if(*tmpp==';' || *tmpp==','){
1127 add_scriptl(LABEL_NEXTLINE);
1128 p++;
1129 return p;
1130 }
1131 }
1132 tmpp=p;
1133 if((op=C_NEG,*p=='-') || (op=C_LNOT,*p=='!') || (op=C_NOT,*p=='~')){
1134 p=parse_subexpr(p+1,10);
1135 add_scriptc(op);
1136 } else
1137 p=parse_simpleexpr(p);
1138 p=skip_space(p);
1139 while((
1140 (op=C_OP3,opl=0,len=1,*p=='?') ||
1141 (op=C_ADD,opl=8,len=1,*p=='+') ||
1142 (op=C_SUB,opl=8,len=1,*p=='-') ||
1143 (op=C_MUL,opl=9,len=1,*p=='*') ||
1144 (op=C_DIV,opl=9,len=1,*p=='/') ||
1145 (op=C_MOD,opl=9,len=1,*p=='%') ||
1146 (op=C_LAND,opl=2,len=2,*p=='&' && p[1]=='&') ||
1147 (op=C_AND,opl=6,len=1,*p=='&') ||
1148 (op=C_LOR,opl=1,len=2,*p=='|' && p[1]=='|') ||
1149 (op=C_OR,opl=5,len=1,*p=='|') ||
1150 (op=C_XOR,opl=4,len=1,*p=='^') ||
1151 (op=C_EQ,opl=3,len=2,*p=='=' && p[1]=='=') ||
1152 (op=C_NE,opl=3,len=2,*p=='!' && p[1]=='=') ||
1153 (op=C_R_SHIFT,opl=7,len=2,*p=='>' && p[1]=='>') ||
1154 (op=C_GE,opl=3,len=2,*p=='>' && p[1]=='=') ||
1155 (op=C_GT,opl=3,len=1,*p=='>') ||
1156 (op=C_L_SHIFT,opl=7,len=2,*p=='<' && p[1]=='<') ||
1157 (op=C_LE,opl=3,len=2,*p=='<' && p[1]=='=') ||
1158 (op=C_LT,opl=3,len=1,*p=='<')) && opl>limit){
1159 p+=len;
1160 if(op == C_OP3) {
1161 p=parse_subexpr(p,-1);
1162 p=skip_space(p);
1163 if( *(p++) != ':')
1164 disp_error_message("parse_subexpr: need ':'", p-1);
1165 p=parse_subexpr(p,-1);
1166 } else {
1167 p=parse_subexpr(p,opl);
1168 }
1169 add_scriptc(op);
1170 p=skip_space(p);
1171 }
1172
1173 return p; /* return first untreated operator */
1174}
1175
1176/*==========================================
1177 * Ž®‚Ì•]‰¿
1178 *------------------------------------------*/
1179const char* parse_expr(const char *p)
1180{
1181 switch(*p){
1182 case ')': case ';': case ':': case '[': case ']':
1183 case '}':
1184 disp_error_message("parse_expr: unexpected char",p);
1185 }
1186 p=parse_subexpr(p,-1);
1187 return p;
1188}
1189
1190/*==========================================
1191 * Âs‚̉ðÂÃ
1192 *------------------------------------------*/
1193const char* parse_line(const char* p)
1194{
1195 const char* p2;
1196
1197 p=skip_space(p);
1198 if(*p==';') {
1199 // if(); for(); while(); ‚Ì‚½‚߂ɕ‚¶â€Â»â€™Ã¨
1200 p = parse_syntax_close(p + 1);
1201 return p;
1202 }
1203 if(*p==')' && parse_syntax_for_flag)
1204 return p+1;
1205
1206 p = skip_space(p);
1207 if(p[0] == '{') {
1208 syntax.curly[syntax.curly_count].type = TYPE_NULL;
1209 syntax.curly[syntax.curly_count].count = -1;
1210 syntax.curly[syntax.curly_count].index = -1;
1211 syntax.curly_count++;
1212 return p + 1;
1213 } else if(p[0] == '}') {
1214 return parse_curly_close(p);
1215 }
1216
1217 // Â\•¶ŠÖ˜A‚̈—Â
1218 p2 = parse_syntax(p);
1219 if(p2 != NULL)
1220 return p2;
1221
1222 p = parse_callfunc(p,0);
1223 p = skip_space(p);
1224
1225 if(parse_syntax_for_flag) {
1226 if( *p != ')' )
1227 disp_error_message("parse_line: need ')'",p);
1228 } else {
1229 if( *p != ';' )
1230 disp_error_message("parse_line: need ';'",p);
1231 }
1232
1233 // if, for , while ‚̕‚¶â€Â»â€™Ã¨
1234 p = parse_syntax_close(p+1);
1235
1236 return p;
1237}
1238
1239// { ... } ‚̕‚¶Âˆ—Â
1240const char* parse_curly_close(const char* p)
1241{
1242 if(syntax.curly_count <= 0) {
1243 disp_error_message("parse_curly_close: unexpected string",p);
1244 return p + 1;
1245 } else if(syntax.curly[syntax.curly_count-1].type == TYPE_NULL) {
1246 syntax.curly_count--;
1247 // if, for , while ‚̕‚¶â€Â»â€™Ã¨
1248 p = parse_syntax_close(p + 1);
1249 return p;
1250 } else if(syntax.curly[syntax.curly_count-1].type == TYPE_SWITCH) {
1251 // switch() •‚¶â€Â»â€™Ã¨
1252 int pos = syntax.curly_count-1;
1253 char label[256];
1254 int l;
1255 // ˆêŽž•ÃÂâ€â€šÃ°Â·
1256 sprintf(label,"set $@__SW%x_VAL,0;",syntax.curly[pos].index);
1257 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1258 parse_line(label);
1259 syntax.curly_count--;
1260
1261 // –³ÂðŒÂ‚ÅÂI—¹ƒ|Æ’Cƒ“ƒ^‚Ɉړ®
1262 sprintf(label,"goto __SW%x_FIN;",syntax.curly[pos].index);
1263 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1264 parse_line(label);
1265 syntax.curly_count--;
1266
1267 // Œ»ÂÃ’n‚̃‰ƒxƒ‹‚ð•t‚¯‚é
1268 sprintf(label,"__SW%x_%x",syntax.curly[pos].index,syntax.curly[pos].count);
1269 l=add_str(label);
1270 set_label(l,script_pos, p);
1271
1272 if(syntax.curly[pos].flag) {
1273 // default ‚ª‘¶Â·‚é
1274 sprintf(label,"goto __SW%x_DEF;",syntax.curly[pos].index);
1275 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1276 parse_line(label);
1277 syntax.curly_count--;
1278 }
1279
1280 // ÂI—¹ƒ‰ƒxƒ‹‚ð•t‚¯‚é
1281 sprintf(label,"__SW%x_FIN",syntax.curly[pos].index);
1282 l=add_str(label);
1283 set_label(l,script_pos, p);
1284 linkdb_final(&syntax.curly[pos].case_label); // free the list of case label
1285 syntax.curly_count--;
1286 // if, for , while ‚̕‚¶â€Â»â€™Ã¨
1287 p = parse_syntax_close(p + 1);
1288 return p;
1289 } else {
1290 disp_error_message("parse_curly_close: unexpected string",p);
1291 return p + 1;
1292 }
1293}
1294
1295// Â\•¶ŠÖ˜A‚̈—Â
1296// break, case, continue, default, do, for, function,
1297// if, switch, while ‚ð‚±‚Ì“à •â€â€šÃ…ˆ—‚µ‚Ü‚·ÂB
1298const char* parse_syntax(const char* p)
1299{
1300 const char *p2 = skip_word(p);
1301
1302 switch(*p) {
1303 case 'B':
1304 case 'b':
1305 if(p2 - p == 5 && !strncasecmp(p,"break",5)) {
1306 // break ‚̈—Â
1307 char label[256];
1308 int pos = syntax.curly_count - 1;
1309 while(pos >= 0) {
1310 if(syntax.curly[pos].type == TYPE_DO) {
1311 sprintf(label,"goto __DO%x_FIN;",syntax.curly[pos].index);
1312 break;
1313 } else if(syntax.curly[pos].type == TYPE_FOR) {
1314 sprintf(label,"goto __FR%x_FIN;",syntax.curly[pos].index);
1315 break;
1316 } else if(syntax.curly[pos].type == TYPE_WHILE) {
1317 sprintf(label,"goto __WL%x_FIN;",syntax.curly[pos].index);
1318 break;
1319 } else if(syntax.curly[pos].type == TYPE_SWITCH) {
1320 sprintf(label,"goto __SW%x_FIN;",syntax.curly[pos].index);
1321 break;
1322 }
1323 pos--;
1324 }
1325 if(pos < 0) {
1326 disp_error_message("parse_syntax: unexpected 'break'",p);
1327 } else {
1328 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1329 parse_line(label);
1330 syntax.curly_count--;
1331 }
1332 p = skip_space(p2);
1333 if(*p != ';')
1334 disp_error_message("parse_syntax: need ';'",p);
1335 // if, for , while ‚̕‚¶â€Â»â€™Ã¨
1336 p = parse_syntax_close(p + 1);
1337 return p;
1338 }
1339 break;
1340 case 'c':
1341 case 'C':
1342 if(p2 - p == 4 && !strncasecmp(p,"case",4)) {
1343 // case ‚̈—Â
1344 int pos = syntax.curly_count-1;
1345 if(pos < 0 || syntax.curly[pos].type != TYPE_SWITCH) {
1346 disp_error_message("parse_syntax: unexpected 'case' ",p);
1347 return p+1;
1348 } else {
1349 char label[256];
1350 int l,v;
1351 char *np;
1352 if(syntax.curly[pos].count != 1) {
1353 // FALLTHRU —p‚̃Wƒƒƒ“ƒv
1354 sprintf(label,"goto __SW%x_%xJ;",syntax.curly[pos].index,syntax.curly[pos].count);
1355 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1356 parse_line(label);
1357 syntax.curly_count--;
1358
1359 // Œ»ÂÃ’n‚̃‰ƒxƒ‹‚ð•t‚¯‚é
1360 sprintf(label,"__SW%x_%x",syntax.curly[pos].index,syntax.curly[pos].count);
1361 l=add_str(label);
1362 set_label(l,script_pos, p);
1363 }
1364 // switch â€Â»â€™Ã¨â€¢Â¶
1365 p = skip_space(p2);
1366 if(p == p2) {
1367 disp_error_message("parse_syntax: expect space ' '",p);
1368 }
1369 // check whether case label is integer or not
1370 v = strtol(p,&np,0);
1371 if(np == p) { //Check for constants
1372 p2 = skip_word(p);
1373 v = p2-p; // length of word at p2
1374 memcpy(label,p,v);
1375 label[v]='\0';
1376 if( !script_get_constant(label, &v) )
1377 disp_error_message("parse_syntax: 'case' label not integer",p);
1378 p = skip_word(p);
1379 } else { //Numeric value
1380 if((*p == '-' || *p == '+') && ISDIGIT(p[1])) // pre-skip because '-' can not skip_word
1381 p++;
1382 p = skip_word(p);
1383 if(np != p)
1384 disp_error_message("parse_syntax: 'case' label not integer",np);
1385 }
1386 p = skip_space(p);
1387 if(*p != ':')
1388 disp_error_message("parse_syntax: expect ':'",p);
1389 sprintf(label,"if(%d != $@__SW%x_VAL) goto __SW%x_%x;",
1390 v,syntax.curly[pos].index,syntax.curly[pos].index,syntax.curly[pos].count+1);
1391 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1392 // ‚Q‰ñparse ‚µ‚È‚¢‚ƃ_Æ’Â
1393 p2 = parse_line(label);
1394 parse_line(p2);
1395 syntax.curly_count--;
1396 if(syntax.curly[pos].count != 1) {
1397 // FALLTHRU ÂI—¹Œã‚̃‰ƒxƒ‹
1398 sprintf(label,"__SW%x_%xJ",syntax.curly[pos].index,syntax.curly[pos].count);
1399 l=add_str(label);
1400 set_label(l,script_pos,p);
1401 }
1402 // check duplication of case label [Rayce]
1403 if(linkdb_search(&syntax.curly[pos].case_label, (void*)v) != NULL)
1404 disp_error_message("parse_syntax: dup 'case'",p);
1405 linkdb_insert(&syntax.curly[pos].case_label, (void*)v, (void*)1);
1406
1407 sprintf(label,"set $@__SW%x_VAL,0;",syntax.curly[pos].index);
1408 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1409
1410 parse_line(label);
1411 syntax.curly_count--;
1412 syntax.curly[pos].count++;
1413 }
1414 return p + 1;
1415 } else if(p2 - p == 8 && !strncasecmp(p,"continue",8)) {
1416 // continue ‚̈—Â
1417 char label[256];
1418 int pos = syntax.curly_count - 1;
1419 while(pos >= 0) {
1420 if(syntax.curly[pos].type == TYPE_DO) {
1421 sprintf(label,"goto __DO%x_NXT;",syntax.curly[pos].index);
1422 syntax.curly[pos].flag = 1; // continue —p‚ÌƒŠƒ“ƒN’£‚éƒtƒ‰ƒO
1423 break;
1424 } else if(syntax.curly[pos].type == TYPE_FOR) {
1425 sprintf(label,"goto __FR%x_NXT;",syntax.curly[pos].index);
1426 break;
1427 } else if(syntax.curly[pos].type == TYPE_WHILE) {
1428 sprintf(label,"goto __WL%x_NXT;",syntax.curly[pos].index);
1429 break;
1430 }
1431 pos--;
1432 }
1433 if(pos < 0) {
1434 disp_error_message("parse_syntax: unexpected 'continue'",p);
1435 } else {
1436 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1437 parse_line(label);
1438 syntax.curly_count--;
1439 }
1440 p = skip_space(p2);
1441 if(*p != ';')
1442 disp_error_message("parse_syntax: need ';'",p);
1443 // if, for , while ‚̕‚¶â€Â»â€™Ã¨
1444 p = parse_syntax_close(p + 1);
1445 return p;
1446 }
1447 break;
1448 case 'd':
1449 case 'D':
1450 if(p2 - p == 7 && !strncasecmp(p,"default",7)) {
1451 // switch - default ‚̈—Â
1452 int pos = syntax.curly_count-1;
1453 if(pos < 0 || syntax.curly[pos].type != TYPE_SWITCH) {
1454 disp_error_message("parse_syntax: unexpected 'default'",p);
1455 } else if(syntax.curly[pos].flag) {
1456 disp_error_message("parse_syntax: dup 'default'",p);
1457 } else {
1458 char label[256];
1459 int l;
1460 // Œ»ÂÃ’n‚̃‰ƒxƒ‹‚ð•t‚¯‚é
1461 p = skip_space(p2);
1462 if(*p != ':') {
1463 disp_error_message("parse_syntax: need ':'",p);
1464 }
1465 sprintf(label,"__SW%x_%x",syntax.curly[pos].index,syntax.curly[pos].count);
1466 l=add_str(label);
1467 set_label(l,script_pos,p);
1468
1469 // –³ÂðŒÂ‚ÅŽŸ‚ÌƒŠƒ“ƒN‚Éâ€Ã²â€šÃŽâ€šÂ·
1470 sprintf(label,"goto __SW%x_%x;",syntax.curly[pos].index,syntax.curly[pos].count+1);
1471 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1472 parse_line(label);
1473 syntax.curly_count--;
1474
1475 // default ‚̃‰ƒxƒ‹‚ð•t‚¯‚é
1476 sprintf(label,"__SW%x_DEF",syntax.curly[pos].index);
1477 l=add_str(label);
1478 set_label(l,script_pos,p);
1479
1480 syntax.curly[syntax.curly_count - 1].flag = 1;
1481 syntax.curly[pos].count++;
1482 }
1483 return p + 1;
1484 } else if(p2 - p == 2 && !strncasecmp(p,"do",2)) {
1485 int l;
1486 char label[256];
1487 p=skip_space(p2);
1488
1489 syntax.curly[syntax.curly_count].type = TYPE_DO;
1490 syntax.curly[syntax.curly_count].count = 1;
1491 syntax.curly[syntax.curly_count].index = syntax.index++;
1492 syntax.curly[syntax.curly_count].flag = 0;
1493 // Œ»ÂÃ’n‚̃‰ƒxƒ‹Œ`¬‚·‚é
1494 sprintf(label,"__DO%x_BGN",syntax.curly[syntax.curly_count].index);
1495 l=add_str(label);
1496 set_label(l,script_pos,p);
1497 syntax.curly_count++;
1498 return p;
1499 }
1500 break;
1501 case 'f':
1502 case 'F':
1503 if(p2 - p == 3 && !strncasecmp(p,"for",3)) {
1504 int l;
1505 char label[256];
1506 int pos = syntax.curly_count;
1507 syntax.curly[syntax.curly_count].type = TYPE_FOR;
1508 syntax.curly[syntax.curly_count].count = 1;
1509 syntax.curly[syntax.curly_count].index = syntax.index++;
1510 syntax.curly[syntax.curly_count].flag = 0;
1511 syntax.curly_count++;
1512
1513 p=skip_space(p2);
1514
1515 if(*p != '(')
1516 disp_error_message("parse_syntax: need '('",p);
1517 p++;
1518
1519 // ‰Šú‰»•¶‚ðŽÀÂs‚·‚é
1520 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1521 p=parse_line(p);
1522 syntax.curly_count--;
1523
1524 // ÂðŒÂâ€Â»â€™fÅ JŽn‚̃‰ƒxƒ‹Œ`¬‚·‚é
1525 sprintf(label,"__FR%x_J",syntax.curly[pos].index);
1526 l=add_str(label);
1527 set_label(l,script_pos,p);
1528
1529 p=skip_space(p);
1530 if(*p == ';') {
1531 // for(;;) ‚̃pÆ’^Â[ƒ“‚Ȃ̂ŕK‚¸Â^
1532 ;
1533 } else {
1534 // ÂðŒÂ‚ª‹U‚È‚çÂI—¹’n“_‚Éâ€Ã²â€šÃŽâ€šÂ·
1535 sprintf(label,"__FR%x_FIN",syntax.curly[pos].index);
1536 add_scriptl(add_str("jump_zero"));
1537 add_scriptc(C_ARG);
1538 p=parse_expr(p);
1539 p=skip_space(p);
1540 add_scriptl(add_str(label));
1541 add_scriptc(C_FUNC);
1542 }
1543 if(*p != ';')
1544 disp_error_message("parse_syntax: need ';'",p);
1545 p++;
1546
1547 // ƒ‹Â[Æ’vÅ JŽn‚Éâ€Ã²â€šÃŽâ€šÂ·
1548 sprintf(label,"goto __FR%x_BGN;",syntax.curly[pos].index);
1549 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1550 parse_line(label);
1551 syntax.curly_count--;
1552
1553 // ŽŸ‚̃‹Â[Æ’v‚ւ̃‰ƒxƒ‹Œ`¬‚·‚é
1554 sprintf(label,"__FR%x_NXT",syntax.curly[pos].index);
1555 l=add_str(label);
1556 set_label(l,script_pos,p);
1557
1558 // ŽŸ‚̃‹Â[Æ’v‚É“ü‚鎞‚̈—Â
1559 // for ÂÅŒã‚Ì ')' ‚ð ';' ‚Æ‚µ‚Ĉµ‚¤ƒtƒ‰ƒO
1560 parse_syntax_for_flag = 1;
1561 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1562 p=parse_line(p);
1563 syntax.curly_count--;
1564 parse_syntax_for_flag = 0;
1565
1566 // ÂðŒÂâ€Â»â€™Ã¨Âˆ—‚Éâ€Ã²â€šÃŽâ€šÂ·
1567 sprintf(label,"goto __FR%x_J;",syntax.curly[pos].index);
1568 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1569 parse_line(label);
1570 syntax.curly_count--;
1571
1572 // ƒ‹Â[Æ’vÅ JŽn‚̃‰ƒxƒ‹•t‚¯
1573 sprintf(label,"__FR%x_BGN",syntax.curly[pos].index);
1574 l=add_str(label);
1575 set_label(l,script_pos,p);
1576 return p;
1577 }
1578 else if( p2 - p == 8 && strncasecmp(p,"function",8) == 0 )
1579 {// internal script function
1580 const char *func_name;
1581
1582 func_name = skip_space(p2);
1583 p = skip_word(func_name);
1584 if( p == func_name )
1585 disp_error_message("parse_syntax:function: function name is missing or invalid", p);
1586 p2 = skip_space(p);
1587 if( *p2 == ';' )
1588 {// function <name> ;
1589 // function declaration - just register the name
1590 int l;
1591 l = add_word(func_name);
1592 if( str_data[l].type == C_NOP )// register only, if the name was not used by something else
1593 str_data[l].type = C_USERFUNC;
1594 else if( str_data[l].type == C_USERFUNC )
1595 ; // already registered
1596 else
1597 disp_error_message("parse_syntax:function: function name is invalid", func_name);
1598
1599 // if, for , while ‚̕‚¶â€Â»â€™Ã¨
1600 p = parse_syntax_close(p2 + 1);
1601 return p;
1602 }
1603 else if(*p2 == '{')
1604 {// function <name> <line/block of code>
1605 char label[256];
1606 int l;
1607
1608 syntax.curly[syntax.curly_count].type = TYPE_USERFUNC;
1609 syntax.curly[syntax.curly_count].count = 1;
1610 syntax.curly[syntax.curly_count].index = syntax.index++;
1611 syntax.curly[syntax.curly_count].flag = 0;
1612 ++syntax.curly_count;
1613
1614 // Jump over the function code
1615 sprintf(label, "goto __FN%x_FIN;", syntax.curly[syntax.curly_count-1].index);
1616 syntax.curly[syntax.curly_count].type = TYPE_NULL;
1617 ++syntax.curly_count;
1618 parse_line(label);
1619 --syntax.curly_count;
1620
1621 // Set the position of the function (label)
1622 l=add_word(func_name);
1623 if( str_data[l].type == C_NOP || str_data[l].type == C_USERFUNC )// register only, if the name was not used by something else
1624 {
1625 str_data[l].type = C_USERFUNC;
1626 set_label(l, script_pos, p);
1627 if( parse_options&SCRIPT_USE_LABEL_DB )
1628 strdb_put(scriptlabel_db, get_str(l), (void*)script_pos);
1629 }
1630 else
1631 disp_error_message("parse_syntax:function: function name is invalid", func_name);
1632
1633 return skip_space(p);
1634 }
1635 else
1636 {
1637 disp_error_message("expect ';' or '{' at function syntax",p);
1638 }
1639 }
1640 break;
1641 case 'i':
1642 case 'I':
1643 if(p2 - p == 2 && !strncasecmp(p,"if",2)) {
1644 // if() ‚̈—Â
1645 char label[256];
1646 p=skip_space(p2);
1647 if(*p != '(') { //Prevent if this {} non-c syntax. from Rayce (jA)
1648 disp_error_message("need '('",p);
1649 }
1650 syntax.curly[syntax.curly_count].type = TYPE_IF;
1651 syntax.curly[syntax.curly_count].count = 1;
1652 syntax.curly[syntax.curly_count].index = syntax.index++;
1653 syntax.curly[syntax.curly_count].flag = 0;
1654 sprintf(label,"__IF%x_%x",syntax.curly[syntax.curly_count].index,syntax.curly[syntax.curly_count].count);
1655 syntax.curly_count++;
1656 add_scriptl(add_str("jump_zero"));
1657 add_scriptc(C_ARG);
1658 p=parse_expr(p);
1659 p=skip_space(p);
1660 add_scriptl(add_str(label));
1661 add_scriptc(C_FUNC);
1662 return p;
1663 }
1664 break;
1665 case 's':
1666 case 'S':
1667 if(p2 - p == 6 && !strncasecmp(p,"switch",6)) {
1668 // switch() ‚̈—Â
1669 char label[256];
1670 p=skip_space(p2);
1671 if(*p != '(') {
1672 disp_error_message("need '('",p);
1673 }
1674 syntax.curly[syntax.curly_count].type = TYPE_SWITCH;
1675 syntax.curly[syntax.curly_count].count = 1;
1676 syntax.curly[syntax.curly_count].index = syntax.index++;
1677 syntax.curly[syntax.curly_count].flag = 0;
1678 sprintf(label,"$@__SW%x_VAL",syntax.curly[syntax.curly_count].index);
1679 syntax.curly_count++;
1680 add_scriptl(add_str("set"));
1681 add_scriptc(C_ARG);
1682 add_scriptl(add_str(label));
1683 p=parse_expr(p);
1684 p=skip_space(p);
1685 if(*p != '{') {
1686 disp_error_message("parse_syntax: need '{'",p);
1687 }
1688 add_scriptc(C_FUNC);
1689 return p + 1;
1690 }
1691 break;
1692 case 'w':
1693 case 'W':
1694 if(p2 - p == 5 && !strncasecmp(p,"while",5)) {
1695 int l;
1696 char label[256];
1697 p=skip_space(p2);
1698 if(*p != '(') {
1699 disp_error_message("need '('",p);
1700 }
1701 syntax.curly[syntax.curly_count].type = TYPE_WHILE;
1702 syntax.curly[syntax.curly_count].count = 1;
1703 syntax.curly[syntax.curly_count].index = syntax.index++;
1704 syntax.curly[syntax.curly_count].flag = 0;
1705 // ÂðŒÂâ€Â»â€™fÅ JŽn‚̃‰ƒxƒ‹Œ`¬‚·‚é
1706 sprintf(label,"__WL%x_NXT",syntax.curly[syntax.curly_count].index);
1707 l=add_str(label);
1708 set_label(l,script_pos,p);
1709
1710 // ÂðŒÂ‚ª‹U‚È‚çÂI—¹’n“_‚Éâ€Ã²â€šÃŽâ€šÂ·
1711 sprintf(label,"__WL%x_FIN",syntax.curly[syntax.curly_count].index);
1712 syntax.curly_count++;
1713 add_scriptl(add_str("jump_zero"));
1714 add_scriptc(C_ARG);
1715 p=parse_expr(p);
1716 p=skip_space(p);
1717 add_scriptl(add_str(label));
1718 add_scriptc(C_FUNC);
1719 return p;
1720 }
1721 break;
1722 }
1723 return NULL;
1724}
1725
1726const char* parse_syntax_close(const char *p) {
1727 // if(...) for(...) hoge(); ‚̂悤‚ÉÂA‚P“x•‚¶‚ç‚ꂽ‚çÂÄ“x•‚¶‚ç‚ê‚é‚©Šmâ€F‚·‚é
1728 int flag;
1729
1730 do {
1731 p = parse_syntax_close_sub(p,&flag);
1732 } while(flag);
1733 return p;
1734}
1735
1736// if, for , while , do ‚̕‚¶â€Â»â€™Ã¨
1737// flag == 1 : •‚¶‚ç‚ꂽ
1738// flag == 0 : •‚¶‚ç‚ê‚È‚¢
1739const char* parse_syntax_close_sub(const char* p,int* flag)
1740{
1741 char label[256];
1742 int pos = syntax.curly_count - 1;
1743 int l;
1744 *flag = 1;
1745
1746 if(syntax.curly_count <= 0) {
1747 *flag = 0;
1748 return p;
1749 } else if(syntax.curly[pos].type == TYPE_IF) {
1750 const char *bp = p;
1751 const char *p2;
1752
1753 // if-block and else-block end is a new line
1754 parse_nextline(false, p);
1755
1756 // if ÂÃ…ÂIÂꊂÖâ€Ã²â€šÃŽâ€šÂ·
1757 sprintf(label,"goto __IF%x_FIN;",syntax.curly[pos].index);
1758 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1759 parse_line(label);
1760 syntax.curly_count--;
1761
1762 // Œ»ÂÃ’n‚̃‰ƒxƒ‹‚ð•t‚¯‚é
1763 sprintf(label,"__IF%x_%x",syntax.curly[pos].index,syntax.curly[pos].count);
1764 l=add_str(label);
1765 set_label(l,script_pos,p);
1766
1767 syntax.curly[pos].count++;
1768 p = skip_space(p);
1769 p2 = skip_word(p);
1770 if(!syntax.curly[pos].flag && p2 - p == 4 && !strncasecmp(p,"else",4)) {
1771 // else or else - if
1772 p = skip_space(p2);
1773 p2 = skip_word(p);
1774 if(p2 - p == 2 && !strncasecmp(p,"if",2)) {
1775 // else - if
1776 p=skip_space(p2);
1777 if(*p != '(') {
1778 disp_error_message("need '('",p);
1779 }
1780 sprintf(label,"__IF%x_%x",syntax.curly[pos].index,syntax.curly[pos].count);
1781 add_scriptl(add_str("jump_zero"));
1782 add_scriptc(C_ARG);
1783 p=parse_expr(p);
1784 p=skip_space(p);
1785 add_scriptl(add_str(label));
1786 add_scriptc(C_FUNC);
1787 *flag = 0;
1788 return p;
1789 } else {
1790 // else
1791 if(!syntax.curly[pos].flag) {
1792 syntax.curly[pos].flag = 1;
1793 *flag = 0;
1794 return p;
1795 }
1796 }
1797 }
1798 // if •‚¶
1799 syntax.curly_count--;
1800 // ÂÃ…ÂI’n‚̃‰ƒxƒ‹‚ð•t‚¯‚é
1801 sprintf(label,"__IF%x_FIN",syntax.curly[pos].index);
1802 l=add_str(label);
1803 set_label(l,script_pos,p);
1804 if(syntax.curly[pos].flag == 1) {
1805 // ‚±‚Ìif‚ɑ΂·‚éelse‚¶‚á‚È‚¢‚̂Ń|Æ’Cƒ“ƒ^‚̈ʒu‚Ó¯‚¶
1806 return bp;
1807 }
1808 return p;
1809 } else if(syntax.curly[pos].type == TYPE_DO) {
1810 int l;
1811 char label[256];
1812 const char *p2;
1813
1814 if(syntax.curly[pos].flag) {
1815 // Œ»ÂÃ’n‚̃‰ƒxƒ‹Œ`¬‚·‚é(continue ‚Å‚±‚±‚É—ˆ‚é)
1816 sprintf(label,"__DO%x_NXT",syntax.curly[pos].index);
1817 l=add_str(label);
1818 set_label(l,script_pos,p);
1819 }
1820
1821 // ÂðŒÂ‚ª‹U‚È‚çÂI—¹’n“_‚Éâ€Ã²â€šÃŽâ€šÂ·
1822 p = skip_space(p);
1823 p2 = skip_word(p);
1824 if(p2 - p != 5 || strncasecmp(p,"while",5))
1825 disp_error_message("parse_syntax: need 'while'",p);
1826
1827 p = skip_space(p2);
1828 if(*p != '(') {
1829 disp_error_message("need '('",p);
1830 }
1831
1832 // do-block end is a new line
1833 parse_nextline(false, p);
1834
1835 sprintf(label,"__DO%x_FIN",syntax.curly[pos].index);
1836 add_scriptl(add_str("jump_zero"));
1837 add_scriptc(C_ARG);
1838 p=parse_expr(p);
1839 p=skip_space(p);
1840 add_scriptl(add_str(label));
1841 add_scriptc(C_FUNC);
1842
1843 // Å JŽn’n“_‚Éâ€Ã²â€šÃŽâ€šÂ·
1844 sprintf(label,"goto __DO%x_BGN;",syntax.curly[pos].index);
1845 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1846 parse_line(label);
1847 syntax.curly_count--;
1848
1849 // ÂðŒÂÂI—¹’n“_‚̃‰ƒxƒ‹Œ`¬‚·‚é
1850 sprintf(label,"__DO%x_FIN",syntax.curly[pos].index);
1851 l=add_str(label);
1852 set_label(l,script_pos,p);
1853 p = skip_space(p);
1854 if(*p != ';') {
1855 disp_error_message("parse_syntax: need ';'",p);
1856 return p+1;
1857 }
1858 p++;
1859 syntax.curly_count--;
1860 return p;
1861 } else if(syntax.curly[pos].type == TYPE_FOR) {
1862 // for-block end is a new line
1863 parse_nextline(false, p);
1864
1865 // ŽŸ‚̃‹Â[Æ’v‚Éâ€Ã²â€šÃŽâ€šÂ·
1866 sprintf(label,"goto __FR%x_NXT;",syntax.curly[pos].index);
1867 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1868 parse_line(label);
1869 syntax.curly_count--;
1870
1871 // for ÂI—¹‚̃‰ƒxƒ‹•t‚¯
1872 sprintf(label,"__FR%x_FIN",syntax.curly[pos].index);
1873 l=add_str(label);
1874 set_label(l,script_pos,p);
1875 syntax.curly_count--;
1876 return p;
1877 } else if(syntax.curly[pos].type == TYPE_WHILE) {
1878 // while-block end is a new line
1879 parse_nextline(false, p);
1880
1881 // while ÂðŒÂâ€Â»â€™f‚Öâ€Ã²â€šÃŽâ€šÂ·
1882 sprintf(label,"goto __WL%x_NXT;",syntax.curly[pos].index);
1883 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1884 parse_line(label);
1885 syntax.curly_count--;
1886
1887 // while ÂI—¹‚̃‰ƒxƒ‹•t‚¯
1888 sprintf(label,"__WL%x_FIN",syntax.curly[pos].index);
1889 l=add_str(label);
1890 set_label(l,script_pos,p);
1891 syntax.curly_count--;
1892 return p;
1893 } else if(syntax.curly[syntax.curly_count-1].type == TYPE_USERFUNC) {
1894 int pos = syntax.curly_count-1;
1895 char label[256];
1896 int l;
1897 // –ß‚·
1898 sprintf(label,"return;");
1899 syntax.curly[syntax.curly_count++].type = TYPE_NULL;
1900 parse_line(label);
1901 syntax.curly_count--;
1902
1903 // Œ»ÂÃ’n‚̃‰ƒxƒ‹‚ð•t‚¯‚é
1904 sprintf(label,"__FN%x_FIN",syntax.curly[pos].index);
1905 l=add_str(label);
1906 set_label(l,script_pos,p);
1907 syntax.curly_count--;
1908 return p;
1909 } else {
1910 *flag = 0;
1911 return p;
1912 }
1913}
1914
1915/*==========================================
1916 * ‘g‚Þ‚ÊÖÂâ€â€šÃŒâ€™Ã‡â€°Ã
1917 *------------------------------------------*/
1918static void add_buildin_func(void)
1919{
1920 int i,n;
1921 const char* p;
1922 for( i = 0; buildin_func[i].func; i++ )
1923 {
1924 // arg must follow the pattern: (v|s|i|r|l)*\?*\*?
1925 // 'v' - value (either string or int or reference)
1926 // 's' - string
1927 // 'i' - int
1928 // 'r' - reference (of a variable)
1929 // 'l' - label
1930 // '?' - one optional parameter
1931 // '*' - unknown number of optional parameters
1932 p = buildin_func[i].arg;
1933 while( *p == 'v' || *p == 's' || *p == 'i' || *p == 'r' || *p == 'l' ) ++p;
1934 while( *p == '?' ) ++p;
1935 if( *p == '*' ) ++p;
1936 if( *p != 0){
1937 ShowWarning("add_buildin_func: ignoring function \"%s\" with invalid arg \"%s\".\n", buildin_func[i].name, buildin_func[i].arg);
1938 } else if( *skip_word(buildin_func[i].name) != 0 ){
1939 ShowWarning("add_buildin_func: ignoring function with invalid name \"%s\" (must be a word).\n", buildin_func[i].name);
1940 } else {
1941 n = add_str(buildin_func[i].name);
1942 str_data[n].type = C_FUNC;
1943 str_data[n].val = i;
1944 str_data[n].func = buildin_func[i].func;
1945 }
1946 }
1947}
1948
1949/// Retrieves the value of a constant.
1950bool script_get_constant(const char* name, int* value)
1951{
1952 int n = search_str(name);
1953
1954 if( n == -1 || str_data[n].type != C_INT )
1955 {// not found or not a constant
1956 return false;
1957 }
1958 value[0] = str_data[n].val;
1959
1960 return true;
1961}
1962
1963/// Creates new constant or parameter with given value.
1964void script_set_constant(const char* name, int value, bool isparameter)
1965{
1966 int n = add_str(name);
1967
1968 if( str_data[n].type == C_NOP )
1969 {// new
1970 str_data[n].type = isparameter ? C_PARAM : C_INT;
1971 str_data[n].val = value;
1972 }
1973 else if( str_data[n].type == C_PARAM || str_data[n].type == C_INT )
1974 {// existing parameter or constant
1975 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);
1976 }
1977 else
1978 {// existing name
1979 ShowError("script_set_constant: Invalid name for %s '%s' (already defined as %s).\n", isparameter ? "parameter" : "constant", name, script_op2name(str_data[n].type));
1980 }
1981}
1982
1983/*==========================================
1984 * ’èÂâ€Æ’fÂ[Æ’^Æ’xÂ[Æ’X‚̓ǂÞ‚Ã
1985 *------------------------------------------*/
1986static void read_constdb(void)
1987{
1988 FILE *fp;
1989 char line[1024],name[1024],val[1024];
1990 int type;
1991
1992 sprintf(line, "%s/const.txt", db_path);
1993 fp=fopen(line, "r");
1994 if(fp==NULL){
1995 ShowError("can't read %s\n", line);
1996 return ;
1997 }
1998 while(fgets(line, sizeof(line), fp))
1999 {
2000 if(line[0]=='/' && line[1]=='/')
2001 continue;
2002 type=0;
2003 if(sscanf(line,"%[A-Za-z0-9_],%[-0-9xXA-Fa-f],%d",name,val,&type)>=2 ||
2004 sscanf(line,"%[A-Za-z0-9_] %[-0-9xXA-Fa-f] %d",name,val,&type)>=2){
2005 script_set_constant(name, (int)strtol(val, NULL, 0), (bool)type);
2006 }
2007 }
2008 fclose(fp);
2009}
2010
2011/*==========================================
2012 * Æ’Gƒ‰Â[•\ަ
2013 *------------------------------------------*/
2014static const char* script_print_line(StringBuf* buf, const char* p, const char* mark, int line)
2015{
2016 int i;
2017 if( p == NULL || !p[0] ) return NULL;
2018 if( line < 0 )
2019 StringBuf_Printf(buf, "*% 5d : ", -line);
2020 else
2021 StringBuf_Printf(buf, " % 5d : ", line);
2022 for(i=0;p[i] && p[i] != '\n';i++){
2023 if(p + i != mark)
2024 StringBuf_Printf(buf, "%c", p[i]);
2025 else
2026 StringBuf_Printf(buf, "\'%c\'", p[i]);
2027 }
2028 StringBuf_AppendStr(buf, "\n");
2029 return p+i+(p[i] == '\n' ? 1 : 0);
2030}
2031
2032void script_error(const char* src, const char* file, int start_line, const char* error_msg, const char* error_pos)
2033{
2034 // Æ’Gƒ‰Â[‚ªâ€Â¶‚µ‚½Âs‚ð‹Â‚ß‚é
2035 int j;
2036 int line = start_line;
2037 const char *p;
2038 const char *linestart[5] = { NULL, NULL, NULL, NULL, NULL };
2039 StringBuf buf;
2040
2041 for(p=src;p && *p;line++){
2042 const char *lineend=strchr(p,'\n');
2043 if(lineend==NULL || error_pos<lineend){
2044 break;
2045 }
2046 for( j = 0; j < 4; j++ ) {
2047 linestart[j] = linestart[j+1];
2048 }
2049 linestart[4] = p;
2050 p=lineend+1;
2051 }
2052
2053 StringBuf_Init(&buf);
2054 StringBuf_AppendStr(&buf, "\a\n");
2055 StringBuf_Printf(&buf, "script error on %s line %d\n", file, line);
2056 StringBuf_Printf(&buf, " %s\n", error_msg);
2057 for(j = 0; j < 5; j++ ) {
2058 script_print_line(&buf, linestart[j], NULL, line + j - 5);
2059 }
2060 p = script_print_line(&buf, p, error_pos, -line);
2061 for(j = 0; j < 5; j++) {
2062 p = script_print_line(&buf, p, NULL, line + j + 1 );
2063 }
2064 ShowError("%s", StringBuf_Value(&buf));
2065 StringBuf_Destroy(&buf);
2066}
2067
2068/*==========================================
2069 * Æ’XÆ’NÆ’Å Æ’vÆ’g‚̉ðÂÃ
2070 *------------------------------------------*/
2071struct script_code* parse_script(const char *src,const char *file,int line,int options)
2072{
2073 const char *p,*tmpp;
2074 int i;
2075 struct script_code* code = NULL;
2076 static int first=1;
2077 char end;
2078 bool unresolved_names = false;
2079
2080 if( src == NULL )
2081 return NULL;// empty script
2082
2083 memset(&syntax,0,sizeof(syntax));
2084 if(first){
2085 add_buildin_func();
2086 read_constdb();
2087 first=0;
2088 }
2089
2090 script_buf=(unsigned char *)aMalloc(SCRIPT_BLOCK_SIZE*sizeof(unsigned char));
2091 script_pos=0;
2092 script_size=SCRIPT_BLOCK_SIZE;
2093 parse_nextline(true, NULL);
2094
2095 // who called parse_script is responsible for clearing the database after using it, but just in case... lets clear it here
2096 if( options&SCRIPT_USE_LABEL_DB )
2097 scriptlabel_db->clear(scriptlabel_db, NULL);
2098 parse_options = options;
2099
2100 if( setjmp( error_jump ) != 0 ) {
2101 //Restore program state when script has problems. [from jA]
2102 int i;
2103 const int size = ARRAYLENGTH(syntax.curly);
2104 if( error_report )
2105 script_error(src,file,line,error_msg,error_pos);
2106 aFree( error_msg );
2107 aFree( script_buf );
2108 script_pos = 0;
2109 script_size = 0;
2110 script_buf = NULL;
2111 for(i=LABEL_START;i<str_num;i++)
2112 if(str_data[i].type == C_NOP) str_data[i].type = C_NAME;
2113 for(i=0; i<size; i++)
2114 linkdb_final(&syntax.curly[i].case_label);
2115 return NULL;
2116 }
2117
2118 parse_syntax_for_flag=0;
2119 p=src;
2120 p=skip_space(p);
2121 if( options&SCRIPT_IGNORE_EXTERNAL_BRACKETS )
2122 {// does not require brackets around the script
2123 if( *p == '\0' && !(options&SCRIPT_RETURN_EMPTY_SCRIPT) )
2124 {// empty script and can return NULL
2125 aFree( script_buf );
2126 script_pos = 0;
2127 script_size = 0;
2128 script_buf = NULL;
2129 return NULL;
2130 }
2131 end = '\0';
2132 }
2133 else
2134 {// requires brackets around the script
2135 if( *p != '{' )
2136 disp_error_message("not found '{'",p);
2137 p = skip_space(p+1);
2138 if( *p == '}' && !(options&SCRIPT_RETURN_EMPTY_SCRIPT) )
2139 {// empty script and can return NULL
2140 aFree( script_buf );
2141 script_pos = 0;
2142 script_size = 0;
2143 script_buf = NULL;
2144 return NULL;
2145 }
2146 end = '}';
2147 }
2148
2149 // clear references of labels, variables and internal functions
2150 for(i=LABEL_START;i<str_num;i++){
2151 if(
2152 str_data[i].type==C_POS || str_data[i].type==C_NAME ||
2153 str_data[i].type==C_USERFUNC || str_data[i].type == C_USERFUNC_POS
2154 ){
2155 str_data[i].type=C_NOP;
2156 str_data[i].backpatch=-1;
2157 str_data[i].label=-1;
2158 }
2159 }
2160
2161 while( syntax.curly_count != 0 || *p != end )
2162 {
2163 if( *p == '\0' )
2164 disp_error_message("unexpected end of script",p);
2165 // label‚¾‚¯“ÎꈗÂ
2166 tmpp=skip_space(skip_word(p));
2167 if(*tmpp==':' && !(!strncasecmp(p,"default:",8) && p + 7 == tmpp)){
2168 i=add_word(p);
2169 set_label(i,script_pos,p);
2170 if( parse_options&SCRIPT_USE_LABEL_DB )
2171 strdb_put(scriptlabel_db, get_str(i), (void*)script_pos);
2172 p=tmpp+1;
2173 p=skip_space(p);
2174 continue;
2175 }
2176
2177 // ‘¼‚ÑS•â€Ë†ÃªÂ‚‚½
2178 p=parse_line(p);
2179 p=skip_space(p);
2180
2181 parse_nextline(false, p);
2182 }
2183
2184 add_scriptc(C_NOP);
2185
2186 // trim code to size
2187 script_size = script_pos;
2188 RECREATE(script_buf,unsigned char,script_pos);
2189
2190 // default unknown references to variables
2191 for(i=LABEL_START;i<str_num;i++){
2192 if(str_data[i].type==C_NOP){
2193 int j,next;
2194 str_data[i].type=C_NAME;
2195 str_data[i].label=i;
2196 for(j=str_data[i].backpatch;j>=0 && j!=0x00ffffff;){
2197 next=GETVALUE(script_buf,j);
2198 SETVALUE(script_buf,j,i);
2199 j=next;
2200 }
2201 }
2202 else if( str_data[i].type == C_USERFUNC )
2203 {// 'function name;' without follow-up code
2204 ShowError("parse_script: function '%s' declared but not defined.\n", str_buf+str_data[i].str);
2205 unresolved_names = true;
2206 }
2207 }
2208
2209 if( unresolved_names )
2210 {
2211 disp_error_message("parse_script: unresolved function references", p);
2212 }
2213
2214#ifdef DEBUG_DISP
2215 for(i=0;i<script_pos;i++){
2216 if((i&15)==0) ShowMessage("%04x : ",i);
2217 ShowMessage("%02x ",script_buf[i]);
2218 if((i&15)==15) ShowMessage("\n");
2219 }
2220 ShowMessage("\n");
2221#endif
2222#ifdef DEBUG_DISASM
2223 {
2224 int i = 0,j;
2225 while(i < script_pos) {
2226 c_op op = get_com(script_buf,&i);
2227
2228 ShowMessage("%06x %s", i, script_op2name(op));
2229 j = i;
2230 switch(op) {
2231 case C_INT:
2232 ShowMessage(" %d", get_num(script_buf,&i));
2233 break;
2234 case C_POS:
2235 ShowMessage(" 0x%06x", *(int*)(script_buf+i)&0xffffff);
2236 i += 3;
2237 break;
2238 case C_NAME:
2239 j = (*(int*)(script_buf+i)&0xffffff);
2240 ShowMessage(" %s", ( j == 0xffffff ) ? "?? unknown ??" : get_str(j));
2241 i += 3;
2242 break;
2243 case C_STR:
2244 j = strlen(script_buf + i);
2245 ShowMessage(" %s", script_buf + i);
2246 i += j+1;
2247 break;
2248 }
2249 ShowMessage(CL_CLL"\n");
2250 }
2251 }
2252#endif
2253
2254 CREATE(code,struct script_code,1);
2255 code->script_buf = script_buf;
2256 code->script_size = script_size;
2257 code->script_vars = NULL;
2258 return code;
2259}
2260
2261/// Returns the player attached to this script, identified by the rid.
2262/// If there is no player attached, the script is terminated.
2263TBL_PC *script_rid2sd(struct script_state *st)
2264{
2265 TBL_PC *sd=map_id2sd(st->rid);
2266 if(!sd){
2267 ShowError("script_rid2sd: fatal error ! player not attached!\n");
2268 script_reportfunc(st);
2269 script_reportsrc(st);
2270 st->state = END;
2271 }
2272 return sd;
2273}
2274
2275/// Dereferences a variable/constant, replacing it with a copy of the value.
2276///
2277/// @param st Script state
2278/// @param data Variable/constant
2279void get_val(struct script_state* st, struct script_data* data)
2280{
2281 const char* name;
2282 char prefix;
2283 char postfix;
2284 TBL_PC* sd = NULL;
2285
2286 if( !data_isreference(data) )
2287 return;// not a variable/constant
2288
2289 name = reference_getname(data);
2290 prefix = name[0];
2291 postfix = name[strlen(name) - 1];
2292
2293 //##TODO use reference_tovariable(data) when it's confirmed that it works [FlavioJS]
2294 if( !reference_toconstant(data) && not_server_variable(prefix) )
2295 {
2296 sd = script_rid2sd(st);
2297 if( sd == NULL )
2298 {// needs player attached
2299 if( postfix == '$' )
2300 {// string variable
2301 ShowWarning("script:get_val: cannot access player variable '%s', defaulting to \"\"\n", name);
2302 data->type = C_CONSTSTR;
2303 data->u.str = "";
2304 }
2305 else
2306 {// integer variable
2307 ShowWarning("script:get_val: cannot access player variable '%s', defaulting to 0\n", name);
2308 data->type = C_INT;
2309 data->u.num = 0;
2310 }
2311 return;
2312 }
2313 }
2314
2315 if( postfix == '$' )
2316 {// string variable
2317
2318 switch( prefix )
2319 {
2320 case '@':
2321 data->u.str = pc_readregstr(sd, data->u.num);
2322 break;
2323 case '$':
2324 data->u.str = mapreg_readregstr(data->u.num);
2325 break;
2326 case '#':
2327 if( name[1] == '#' )
2328 data->u.str = pc_readaccountreg2str(sd, name);// global
2329 else
2330 data->u.str = pc_readaccountregstr(sd, name);// local
2331 break;
2332 case '.':
2333 {
2334 struct linkdb_node** n =
2335 data->ref ? data->ref:
2336 name[1] == '@' ? st->stack->var_function:// instance/scope variable
2337 &st->script->script_vars;// npc variable
2338 data->u.str = (char*)linkdb_search(n, (void*)reference_getuid(data));
2339 }
2340 break;
2341 case '\'':
2342 {
2343 struct linkdb_node** n = NULL;
2344 if( st->instance_id )
2345 n = &instance[st->instance_id].svar;
2346 data->u.str = (char*)linkdb_search(n, (void*)reference_getuid(data));
2347 }
2348 break;
2349 default:
2350 data->u.str = pc_readglobalreg_str(sd, name);
2351 break;
2352 }
2353
2354 if( data->u.str == NULL || data->u.str[0] == '\0' )
2355 {// empty string
2356 data->type = C_CONSTSTR;
2357 data->u.str = "";
2358 }
2359 else
2360 {// duplicate string
2361 data->type = C_STR;
2362 data->u.str = aStrdup(data->u.str);
2363 }
2364
2365 }
2366 else
2367 {// integer variable
2368
2369 data->type = C_INT;
2370
2371 if( reference_toconstant(data) )
2372 {
2373 data->u.num = reference_getconstant(data);
2374 }
2375 else if( reference_toparam(data) )
2376 {
2377 data->u.num = pc_readparam(sd, reference_getparamtype(data));
2378 }
2379 else
2380 switch( prefix )
2381 {
2382 case '@':
2383 data->u.num = pc_readreg(sd, data->u.num);
2384 break;
2385 case '$':
2386 data->u.num = mapreg_readreg(data->u.num);
2387 break;
2388 case '#':
2389 if( name[1] == '#' )
2390 data->u.num = pc_readaccountreg2(sd, name);// global
2391 else
2392 data->u.num = pc_readaccountreg(sd, name);// local
2393 break;
2394 case '.':
2395 {
2396 struct linkdb_node** n =
2397 data->ref ? data->ref:
2398 name[1] == '@' ? st->stack->var_function:// instance/scope variable
2399 &st->script->script_vars;// npc variable
2400 data->u.num = (int)linkdb_search(n, (void*)reference_getuid(data));
2401 }
2402 break;
2403 case '\'':
2404 {
2405 struct linkdb_node** n = NULL;
2406 if( st->instance_id )
2407 n = &instance[st->instance_id].ivar;
2408 data->u.num = (int)linkdb_search(n, (void*)reference_getuid(data));
2409 }
2410 break;
2411 default:
2412 data->u.num = pc_readglobalreg(sd, name);
2413 break;
2414 }
2415
2416 }
2417
2418 return;
2419}
2420
2421struct script_data* push_val2(struct script_stack* stack, enum c_op type, int val, struct linkdb_node** ref);
2422
2423/// Retrieves the value of a reference identified by uid (variable, constant, param)
2424/// The value is left in the top of the stack and needs to be removed manually.
2425void* get_val2(struct script_state* st, int uid, struct linkdb_node** ref)
2426{
2427 struct script_data* data;
2428 push_val2(st->stack, C_NAME, uid, ref);
2429 data = script_getdatatop(st, -1);
2430 get_val(st, data);
2431 return (data->type == C_INT ? (void*)data->u.num : (void*)data->u.str);
2432}
2433
2434/*==========================================
2435 * Stores the value of a script variable
2436 * Return value is 0 on fail, 1 on success.
2437 *------------------------------------------*/
2438static int set_reg(struct script_state* st, TBL_PC* sd, int num, const char* name, const void* value, struct linkdb_node** ref)
2439{
2440 char prefix = name[0];
2441
2442 if( is_string_variable(name) )
2443 {// string variable
2444 const char* str = (const char*)value;
2445 switch (prefix) {
2446 case '@':
2447 return pc_setregstr(sd, num, str);
2448 case '$':
2449 return mapreg_setregstr(num, str);
2450 case '#':
2451 return (name[1] == '#') ?
2452 pc_setaccountreg2str(sd, name, str) :
2453 pc_setaccountregstr(sd, name, str);
2454 case '.': {
2455 char* p;
2456 struct linkdb_node** n;
2457 n = (ref) ? ref : (name[1] == '@') ? st->stack->var_function : &st->script->script_vars;
2458 p = (char*)linkdb_erase(n, (void*)num);
2459 if (p) aFree(p);
2460 if (str[0]) linkdb_insert(n, (void*)num, aStrdup(str));
2461 }
2462 return 1;
2463 case '\'': {
2464 char *p;
2465 struct linkdb_node** n = NULL;
2466 if( st->instance_id )
2467 n = &instance[st->instance_id].svar;
2468
2469 p = (char*)linkdb_erase(n, (void*)num);
2470 if (p) aFree(p);
2471 if( str[0] ) linkdb_insert(n, (void*)num, aStrdup(str));
2472 }
2473 return 1;
2474 default:
2475 return pc_setglobalreg_str(sd, name, str);
2476 }
2477 }
2478 else
2479 {// integer variable
2480 int val = (int)value;
2481 if(str_data[num&0x00ffffff].type == C_PARAM)
2482 {
2483 if( pc_setparam(sd, str_data[num&0x00ffffff].val, val) == 0 )
2484 {
2485 if( st != NULL )
2486 {
2487 ShowError("script:set_reg: failed to set param '%s' to %d.\n", name, val);
2488 script_reportsrc(st);
2489 st->state = END;
2490 }
2491 return 0;
2492 }
2493 return 1;
2494 }
2495
2496 switch (prefix) {
2497 case '@':
2498 return pc_setreg(sd, num, val);
2499 case '$':
2500 return mapreg_setreg(num, val);
2501 case '#':
2502 return (name[1] == '#') ?
2503 pc_setaccountreg2(sd, name, val) :
2504 pc_setaccountreg(sd, name, val);
2505 case '.': {
2506 struct linkdb_node** n;
2507 n = (ref) ? ref : (name[1] == '@') ? st->stack->var_function : &st->script->script_vars;
2508 if (val == 0)
2509 linkdb_erase(n, (void*)num);
2510 else
2511 linkdb_replace(n, (void*)num, (void*)val);
2512 }
2513 return 1;
2514 case '\'':
2515 {
2516 struct linkdb_node** n = NULL;
2517 if( st->instance_id )
2518 n = &instance[st->instance_id].ivar;
2519
2520 if( val == 0 )
2521 linkdb_erase(n, (void*)num);
2522 else
2523 linkdb_replace(n, (void*)num, (void*)val);
2524 return 1;
2525 }
2526 default:
2527 return pc_setglobalreg(sd, name, val);
2528 }
2529 }
2530}
2531
2532int set_var(TBL_PC* sd, char* name, void* val)
2533{
2534 return set_reg(NULL, sd, reference_uid(add_str(name),0), name, val, NULL);
2535}
2536
2537void setd_sub(struct script_state *st, TBL_PC *sd, const char *varname, int elem, void *value, struct linkdb_node **ref)
2538{
2539 set_reg(st, sd, reference_uid(add_str(varname),elem), varname, value, ref);
2540}
2541
2542/// Converts the data to a string
2543const char* conv_str(struct script_state* st, struct script_data* data)
2544{
2545 char* p;
2546
2547 get_val(st, data);
2548 if( data_isstring(data) )
2549 {// nothing to convert
2550 }
2551 else if( data_isint(data) )
2552 {// int -> string
2553 CREATE(p, char, ITEM_NAME_LENGTH);
2554 snprintf(p, ITEM_NAME_LENGTH, "%d", data->u.num);
2555 p[ITEM_NAME_LENGTH-1] = '\0';
2556 data->type = C_STR;
2557 data->u.str = p;
2558 }
2559 else if( data_isreference(data) )
2560 {// reference -> string
2561 //##TODO when does this happen (check get_val) [FlavioJS]
2562 data->type = C_CONSTSTR;
2563 data->u.str = reference_getname(data);
2564 }
2565 else
2566 {// unsupported data type
2567 ShowError("script:conv_str: cannot convert to string, defaulting to \"\"\n");
2568 script_reportdata(data);
2569 script_reportsrc(st);
2570 data->type = C_CONSTSTR;
2571 data->u.str = "";
2572 }
2573 return data->u.str;
2574}
2575
2576/// Converts the data to an int
2577int conv_num(struct script_state* st, struct script_data* data)
2578{
2579 char* p;
2580 long num;
2581
2582 get_val(st, data);
2583 if( data_isint(data) )
2584 {// nothing to convert
2585 }
2586 else if( data_isstring(data) )
2587 {// string -> int
2588 // the result does not overflow or underflow, it is capped instead
2589 // ex: 999999999999 is capped to INT_MAX (2147483647)
2590 p = data->u.str;
2591 errno = 0;
2592 num = strtol(data->u.str, NULL, 10);// change radix to 0 to support octal numbers "o377" and hex numbers "0xFF"
2593 if( errno == ERANGE
2594#if LONG_MAX > INT_MAX
2595 || num < INT_MIN || num > INT_MAX
2596#endif
2597 )
2598 {
2599 if( num <= INT_MIN )
2600 {
2601 num = INT_MIN;
2602 ShowError("script:conv_num: underflow detected, capping to %ld\n", num);
2603 }
2604 else//if( num >= INT_MAX )
2605 {
2606 num = INT_MAX;
2607 ShowError("script:conv_num: overflow detected, capping to %ld\n", num);
2608 }
2609 script_reportdata(data);
2610 script_reportsrc(st);
2611 }
2612 if( data->type == C_STR )
2613 aFree(p);
2614 data->type = C_INT;
2615 data->u.num = (int)num;
2616 }
2617#if 0
2618 // FIXME this function is being used to retrieve the position of labels and
2619 // probably other stuff [FlavioJS]
2620 else
2621 {// unsupported data type
2622 ShowError("script:conv_num: cannot convert to number, defaulting to 0\n");
2623 script_reportdata(data);
2624 script_reportsrc(st);
2625 data->type = C_INT;
2626 data->u.num = 0;
2627 }
2628#endif
2629 return data->u.num;
2630}
2631
2632//
2633// Stack operations
2634//
2635
2636/// Increases the size of the stack
2637void stack_expand(struct script_stack* stack)
2638{
2639 stack->sp_max += 64;
2640 stack->stack_data = (struct script_data*)aRealloc(stack->stack_data,
2641 stack->sp_max * sizeof(stack->stack_data[0]) );
2642 memset(stack->stack_data + (stack->sp_max - 64), 0,
2643 64 * sizeof(stack->stack_data[0]) );
2644}
2645
2646/// Pushes a value into the stack
2647#define push_val(stack,type,val) push_val2(stack, type, val, NULL)
2648
2649/// Pushes a value into the stack (with reference)
2650struct script_data* push_val2(struct script_stack* stack, enum c_op type, int val, struct linkdb_node** ref)
2651{
2652 if( stack->sp >= stack->sp_max )
2653 stack_expand(stack);
2654 stack->stack_data[stack->sp].type = type;
2655 stack->stack_data[stack->sp].u.num = val;
2656 stack->stack_data[stack->sp].ref = ref;
2657 stack->sp++;
2658 return &stack->stack_data[stack->sp-1];
2659}
2660
2661/// Pushes a string into the stack
2662struct script_data* push_str(struct script_stack* stack, enum c_op type, char* str)
2663{
2664 if( stack->sp >= stack->sp_max )
2665 stack_expand(stack);
2666 stack->stack_data[stack->sp].type = type;
2667 stack->stack_data[stack->sp].u.str = str;
2668 stack->stack_data[stack->sp].ref = NULL;
2669 stack->sp++;
2670 return &stack->stack_data[stack->sp-1];
2671}
2672
2673/// Pushes a retinfo into the stack
2674struct script_data* push_retinfo(struct script_stack* stack, struct script_retinfo* ri)
2675{
2676 if( stack->sp >= stack->sp_max )
2677 stack_expand(stack);
2678 stack->stack_data[stack->sp].type = C_RETINFO;
2679 stack->stack_data[stack->sp].u.ri = ri;
2680 stack->stack_data[stack->sp].ref = NULL;
2681 stack->sp++;
2682 return &stack->stack_data[stack->sp-1];
2683}
2684
2685/// Pushes a copy of the target position into the stack
2686struct script_data* push_copy(struct script_stack* stack, int pos)
2687{
2688 switch( stack->stack_data[pos].type )
2689 {
2690 case C_CONSTSTR:
2691 return push_str(stack, C_CONSTSTR, stack->stack_data[pos].u.str);
2692 break;
2693 case C_STR:
2694 return push_str(stack, C_STR, aStrdup(stack->stack_data[pos].u.str));
2695 break;
2696 case C_RETINFO:
2697 ShowFatalError("script:push_copy: can't create copies of C_RETINFO. Exiting...\n");
2698 exit(1);
2699 break;
2700 default:
2701 return push_val2(
2702 stack,stack->stack_data[pos].type,
2703 stack->stack_data[pos].u.num,
2704 stack->stack_data[pos].ref
2705 );
2706 break;
2707 }
2708}
2709
2710/// Removes the values in indexes [start,end[ from the stack.
2711/// Adjusts all stack pointers.
2712void pop_stack(struct script_state* st, int start, int end)
2713{
2714 struct script_stack* stack = st->stack;
2715 struct script_data* data;
2716 int i;
2717
2718 if( start < 0 )
2719 start = 0;
2720 if( end > stack->sp )
2721 end = stack->sp;
2722 if( start >= end )
2723 return;// nothing to pop
2724
2725 // free stack elements
2726 for( i = start; i < end; i++ )
2727 {
2728 data = &stack->stack_data[i];
2729 if( data->type == C_STR )
2730 aFree(data->u.str);
2731 if( data->type == C_RETINFO )
2732 {
2733 struct script_retinfo* ri = data->u.ri;
2734 if( ri->var_function )
2735 {
2736 script_free_vars(ri->var_function);
2737 aFree(ri->var_function);
2738 }
2739 aFree(ri);
2740 }
2741 data->type = C_NOP;
2742 }
2743 // move the rest of the elements
2744 if( stack->sp > end )
2745 {
2746 memmove(&stack->stack_data[start], &stack->stack_data[end], sizeof(stack->stack_data[0])*(stack->sp - end));
2747 for( i = start + stack->sp - end; i < stack->sp; ++i )
2748 stack->stack_data[i].type = C_NOP;
2749 }
2750 // adjust stack pointers
2751 if( st->start > end ) st->start -= end - start;
2752 else if( st->start > start ) st->start = start;
2753 if( st->end > end ) st->end -= end - start;
2754 else if( st->end > start ) st->end = start;
2755 if( stack->defsp > end ) stack->defsp -= end - start;
2756 else if( stack->defsp > start ) stack->defsp = start;
2757 stack->sp -= end - start;
2758}
2759
2760///
2761///
2762///
2763
2764/*==========================================
2765 * Æ’XÆ’NÆ’Å Æ’vÆ’gˆË‘¶•ÃÂâ€ÂAŠÖÂâ€Ë†Ã‹â€˜Â¶â€¢ÃÂâ€â€šÃŒâ€°Ã°â€¢Ãº
2766 *------------------------------------------*/
2767void script_free_vars(struct linkdb_node **node)
2768{
2769 struct linkdb_node* n = *node;
2770 while( n != NULL)
2771 {
2772 const char* name = get_str((int)(n->key)&0x00ffffff);
2773 if( is_string_variable(name) )
2774 aFree(n->data); // •¶ŽšŒ^•ÃÂâ€â€šÃˆâ€šÃŒâ€šÃ…ÂAÆ’fÂ[Æ’^ÂÃÂÅ“
2775 n = n->next;
2776 }
2777 linkdb_final( node );
2778}
2779
2780void script_free_code(struct script_code* code)
2781{
2782 script_free_vars( &code->script_vars );
2783 aFree( code->script_buf );
2784 aFree( code );
2785}
2786
2787/// Creates a new script state.
2788///
2789/// @param script Script code
2790/// @param pos Position in the code
2791/// @param rid Who is running the script (attached player)
2792/// @param oid Where the code is being run (npc 'object')
2793/// @return Script state
2794struct script_state* script_alloc_state(struct script_code* script, int pos, int rid, int oid)
2795{
2796 struct script_state* st;
2797 CREATE(st, struct script_state, 1);
2798 st->stack = (struct script_stack*)aMalloc(sizeof(struct script_stack));
2799 st->stack->sp = 0;
2800 st->stack->sp_max = 64;
2801 CREATE(st->stack->stack_data, struct script_data, st->stack->sp_max);
2802 st->stack->defsp = st->stack->sp;
2803 CREATE(st->stack->var_function, struct linkdb_node*, 1);
2804 st->state = RUN;
2805 st->script = script;
2806 //st->scriptroot = script;
2807 st->pos = pos;
2808 st->rid = rid;
2809 st->oid = oid;
2810 st->sleep.timer = INVALID_TIMER;
2811 return st;
2812}
2813
2814/// Frees a script state.
2815///
2816/// @param st Script state
2817void script_free_state(struct script_state* st)
2818{
2819 if(st->bk_st)
2820 {// backup was not restored
2821 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);
2822 }
2823 if( st->sleep.timer != INVALID_TIMER )
2824 delete_timer(st->sleep.timer, run_script_timer);
2825 script_free_vars(st->stack->var_function);
2826 aFree(st->stack->var_function);
2827 pop_stack(st, 0, st->stack->sp);
2828 aFree(st->stack->stack_data);
2829 aFree(st->stack);
2830 st->pos = -1;
2831 aFree(st);
2832}
2833
2834//
2835// ŽÀÂs•â€main
2836//
2837/*==========================================
2838 * Æ’RÆ’}ƒ“ƒh‚̓ǂÃŽæ‚è
2839 *------------------------------------------*/
2840c_op get_com(unsigned char *script,int *pos)
2841{
2842 int i = 0, j = 0;
2843
2844 if(script[*pos]>=0x80){
2845 return C_INT;
2846 }
2847 while(script[*pos]>=0x40){
2848 i=script[(*pos)++]<<j;
2849 j+=6;
2850 }
2851 return (c_op)(i+(script[(*pos)++]<<j));
2852}
2853
2854/*==========================================
2855 * Ââ€â€™l‚ÌŠ“¾
2856 *------------------------------------------*/
2857int get_num(unsigned char *script,int *pos)
2858{
2859 int i,j;
2860 i=0; j=0;
2861 while(script[*pos]>=0xc0){
2862 i+=(script[(*pos)++]&0x7f)<<j;
2863 j+=6;
2864 }
2865 return i+((script[(*pos)++]&0x7f)<<j);
2866}
2867
2868/*==========================================
2869 * Æ’XÆ’^Æ’bÆ’N‚©‚ç’l‚ðŽæ‚èÂo‚·
2870 *------------------------------------------*/
2871int pop_val(struct script_state* st)
2872{
2873 if(st->stack->sp<=0)
2874 return 0;
2875 st->stack->sp--;
2876 get_val(st,&(st->stack->stack_data[st->stack->sp]));
2877 if(st->stack->stack_data[st->stack->sp].type==C_INT)
2878 return st->stack->stack_data[st->stack->sp].u.num;
2879 return 0;
2880}
2881
2882/// Ternary operators
2883/// test ? if_true : if_false
2884void op_3(struct script_state* st, int op)
2885{
2886 struct script_data* data;
2887 int flag = 0;
2888
2889 data = script_getdatatop(st, -3);
2890 get_val(st, data);
2891
2892 if( data_isstring(data) )
2893 flag = data->u.str[0];// "" -> false
2894 else if( data_isint(data) )
2895 flag = data->u.num;// 0 -> false
2896 else
2897 {
2898 ShowError("script:op_3: invalid data for the ternary operator test\n");
2899 script_reportdata(data);
2900 script_reportsrc(st);
2901 script_removetop(st, -3, 0);
2902 script_pushnil(st);
2903 return;
2904 }
2905 if( flag )
2906 script_pushcopytop(st, -2);
2907 else
2908 script_pushcopytop(st, -1);
2909 script_removetop(st, -4, -1);
2910}
2911
2912/// Binary string operators
2913/// s1 EQ s2 -> i
2914/// s1 NE s2 -> i
2915/// s1 GT s2 -> i
2916/// s1 GE s2 -> i
2917/// s1 LT s2 -> i
2918/// s1 LE s2 -> i
2919/// s1 ADD s2 -> s
2920void op_2str(struct script_state* st, int op, const char* s1, const char* s2)
2921{
2922 int a = 0;
2923
2924 switch(op){
2925 case C_EQ: a = (strcmp(s1,s2) == 0); break;
2926 case C_NE: a = (strcmp(s1,s2) != 0); break;
2927 case C_GT: a = (strcmp(s1,s2) > 0); break;
2928 case C_GE: a = (strcmp(s1,s2) >= 0); break;
2929 case C_LT: a = (strcmp(s1,s2) < 0); break;
2930 case C_LE: a = (strcmp(s1,s2) <= 0); break;
2931 case C_ADD:
2932 {
2933 char* buf = (char *)aMallocA((strlen(s1)+strlen(s2)+1)*sizeof(char));
2934 strcpy(buf, s1);
2935 strcat(buf, s2);
2936 script_pushstr(st, buf);
2937 return;
2938 }
2939 default:
2940 ShowError("script:op2_str: unexpected string operator %s\n", script_op2name(op));
2941 script_reportsrc(st);
2942 script_pushnil(st);
2943 st->state = END;
2944 return;
2945 }
2946
2947 script_pushint(st,a);
2948}
2949
2950/// Binary number operators
2951/// i OP i -> i
2952void op_2num(struct script_state* st, int op, int i1, int i2)
2953{
2954 int ret;
2955 double ret_double;
2956
2957 switch( op )
2958 {
2959 case C_AND: ret = i1 & i2; break;
2960 case C_OR: ret = i1 | i2; break;
2961 case C_XOR: ret = i1 ^ i2; break;
2962 case C_LAND: ret = (i1 && i2); break;
2963 case C_LOR: ret = (i1 || i2); break;
2964 case C_EQ: ret = (i1 == i2); break;
2965 case C_NE: ret = (i1 != i2); break;
2966 case C_GT: ret = (i1 > i2); break;
2967 case C_GE: ret = (i1 >= i2); break;
2968 case C_LT: ret = (i1 < i2); break;
2969 case C_LE: ret = (i1 <= i2); break;
2970 case C_R_SHIFT: ret = i1>>i2; break;
2971 case C_L_SHIFT: ret = i1<<i2; break;
2972 case C_DIV:
2973 case C_MOD:
2974 if( i2 == 0 )
2975 {
2976 ShowError("script:op_2num: division by zero detected op=%s i1=%d i2=%d\n", script_op2name(op), i1, i2);
2977 script_reportsrc(st);
2978 script_pushnil(st);
2979 st->state = END;
2980 return;
2981 }
2982 else if( op == C_DIV )
2983 ret = i1 / i2;
2984 else//if( op == C_MOD )
2985 ret = i1 % i2;
2986 break;
2987 default:
2988 switch( op )
2989 {// operators that can overflow/underflow
2990 case C_ADD: ret = i1 + i2; ret_double = (double)i1 + (double)i2; break;
2991 case C_SUB: ret = i1 - i2; ret_double = (double)i1 - (double)i2; break;
2992 case C_MUL: ret = i1 * i2; ret_double = (double)i1 * (double)i2; break;
2993 default:
2994 ShowError("script:op_2num: unexpected number operator %s i1=%d i2=%d\n", script_op2name(op), i1, i2);
2995 script_reportsrc(st);
2996 script_pushnil(st);
2997 return;
2998 }
2999 if( ret_double < (double)INT_MIN )
3000 {
3001 ShowWarning("script:op_2num: underflow detected op=%s i1=%d i2=%d\n", script_op2name(op), i1, i2);
3002 script_reportsrc(st);
3003 ret = INT_MIN;
3004 }
3005 else if( ret_double > (double)INT_MAX )
3006 {
3007 ShowWarning("script:op_2num: overflow detected op=%s i1=%d i2=%d\n", script_op2name(op), i1, i2);
3008 script_reportsrc(st);
3009 ret = INT_MAX;
3010 }
3011 }
3012 script_pushint(st, ret);
3013}
3014
3015/// Binary operators
3016void op_2(struct script_state *st, int op)
3017{
3018 struct script_data* left;
3019 struct script_data* right;
3020
3021 left = script_getdatatop(st, -2);
3022 right = script_getdatatop(st, -1);
3023
3024 get_val(st, left);
3025 get_val(st, right);
3026
3027 // automatic conversions
3028 switch( op )
3029 {
3030 case C_ADD:
3031 if( data_isint(left) && data_isstring(right) )
3032 {// convert int-string to string-string
3033 conv_str(st, left);
3034 }
3035 else if( data_isstring(left) && data_isint(right) )
3036 {// convert string-int to string-string
3037 conv_str(st, right);
3038 }
3039 break;
3040 }
3041
3042 if( data_isstring(left) && data_isstring(right) )
3043 {// ss => op_2str
3044 op_2str(st, op, left->u.str, right->u.str);
3045 script_removetop(st, -3, -1);// pop the two values before the top one
3046 }
3047 else if( data_isint(left) && data_isint(right) )
3048 {// ii => op_2num
3049 int i1 = left->u.num;
3050 int i2 = right->u.num;
3051 script_removetop(st, -2, 0);
3052 op_2num(st, op, i1, i2);
3053 }
3054 else
3055 {// invalid argument
3056 ShowError("script:op_2: invalid data for operator %s\n", script_op2name(op));
3057 script_reportdata(left);
3058 script_reportdata(right);
3059 script_reportsrc(st);
3060 script_removetop(st, -2, 0);
3061 script_pushnil(st);
3062 st->state = END;
3063 }
3064}
3065
3066/// Unary operators
3067/// NEG i -> i
3068/// NOT i -> i
3069/// LNOT i -> i
3070void op_1(struct script_state* st, int op)
3071{
3072 struct script_data* data;
3073 int i1;
3074
3075 data = script_getdatatop(st, -1);
3076 get_val(st, data);
3077
3078 if( !data_isint(data) )
3079 {// not a number
3080 ShowError("script:op_1: argument is not a number (op=%s)\n", script_op2name(op));
3081 script_reportdata(data);
3082 script_reportsrc(st);
3083 script_pushnil(st);
3084 st->state = END;
3085 return;
3086 }
3087
3088 i1 = data->u.num;
3089 script_removetop(st, -1, 0);
3090 switch( op )
3091 {
3092 case C_NEG: i1 = -i1; break;
3093 case C_NOT: i1 = ~i1; break;
3094 case C_LNOT: i1 = !i1; break;
3095 default:
3096 ShowError("script:op_1: unexpected operator %s i1=%d\n", script_op2name(op), i1);
3097 script_reportsrc(st);
3098 script_pushnil(st);
3099 st->state = END;
3100 return;
3101 }
3102 script_pushint(st, i1);
3103}
3104
3105
3106/// Checks the type of all arguments passed to a built-in function.
3107///
3108/// @param st Script state whose stack arguments should be inspected.
3109/// @param func Built-in function for which the arguments are intended.
3110static void script_check_buildin_argtype(struct script_state* st, int func)
3111{
3112 char type;
3113 int idx, invalid = 0;
3114 script_function* sf = &buildin_func[str_data[func].val];
3115
3116 for( idx = 2; script_hasdata(st, idx); idx++ )
3117 {
3118 struct script_data* data = script_getdata(st, idx);
3119
3120 type = sf->arg[idx-2];
3121
3122 if( type == '?' || type == '*' )
3123 {// optional argument or unknown number of optional parameters ( no types are after this )
3124 break;
3125 }
3126 else if( type == 0 )
3127 {// more arguments than necessary ( should not happen, as it is checked before )
3128 ShowWarning("Found more arguments than necessary.\n");
3129 invalid++;
3130 break;
3131 }
3132 else
3133 {
3134 const char* name = NULL;
3135
3136 if( data_isreference(data) )
3137 {// get name for variables to determine the type they refer to
3138 name = reference_getname(data);
3139 }
3140
3141 switch( type )
3142 {
3143 case 'v':
3144 if( !data_isstring(data) && !data_isint(data) && !data_isreference(data) )
3145 {// variant
3146 ShowWarning("Unexpected type for argument %d. Expected string, number or variable.\n", idx-1);
3147 script_reportdata(data);
3148 invalid++;
3149 }
3150 break;
3151 case 's':
3152 if( !data_isstring(data) && !( data_isreference(data) && is_string_variable(name) ) )
3153 {// string
3154 ShowWarning("Unexpected type for argument %d. Expected string.\n", idx-1);
3155 script_reportdata(data);
3156 invalid++;
3157 }
3158 break;
3159 case 'i':
3160 if( !data_isint(data) && !( data_isreference(data) && ( reference_toparam(data) || reference_toconstant(data) || !is_string_variable(name) ) ) )
3161 {// int ( params and constants are always int )
3162 ShowWarning("Unexpected type for argument %d. Expected number.\n", idx-1);
3163 script_reportdata(data);
3164 invalid++;
3165 }
3166 break;
3167 case 'r':
3168 if( !data_isreference(data) )
3169 {// variables
3170 ShowWarning("Unexpected type for argument %d. Expected variable.\n", idx-1);
3171 script_reportdata(data);
3172 invalid++;
3173 }
3174 break;
3175 case 'l':
3176 if( !data_islabel(data) && !data_isfunclabel(data) )
3177 {// label
3178 ShowWarning("Unexpected type for argument %d. Expected label.\n", idx-1);
3179 script_reportdata(data);
3180 invalid++;
3181 }
3182 break;
3183 }
3184 }
3185 }
3186
3187 if(invalid)
3188 {
3189 ShowDebug("Function: %s\n", get_str(func));
3190 script_reportsrc(st);
3191 }
3192}
3193
3194
3195/// Executes a buildin command.
3196/// Stack: C_NAME(<command>) C_ARG <arg0> <arg1> ... <argN>
3197int run_func(struct script_state *st)
3198{
3199 struct script_data* data;
3200 int i,start_sp,end_sp,func;
3201
3202 end_sp = st->stack->sp;// position after the last argument
3203 for( i = end_sp-1; i > 0 ; --i )
3204 if( st->stack->stack_data[i].type == C_ARG )
3205 break;
3206 if( i == 0 )
3207 {
3208 ShowError("script:run_func: C_ARG not found. please report this!!!\n");
3209 st->state = END;
3210 script_reportsrc(st);
3211 return 1;
3212 }
3213 start_sp = i-1;// C_NAME of the command
3214 st->start = start_sp;
3215 st->end = end_sp;
3216
3217 data = &st->stack->stack_data[st->start];
3218 if( data->type == C_NAME && str_data[data->u.num].type == C_FUNC )
3219 func = data->u.num;
3220 else
3221 {
3222 ShowError("script:run_func: not a buildin command.\n");
3223 script_reportdata(data);
3224 script_reportsrc(st);
3225 st->state = END;
3226 return 1;
3227 }
3228
3229 if( script_config.warn_func_mismatch_argtypes )
3230 {
3231 script_check_buildin_argtype(st, func);
3232 }
3233
3234 if(str_data[func].func){
3235 if (str_data[func].func(st)) //Report error
3236 script_reportsrc(st);
3237 } else {
3238 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));
3239 script_reportsrc(st);
3240 st->state = END;
3241 }
3242
3243 // Stack's datum are used when re-running functions [Eoe]
3244 if( st->state == RERUNLINE )
3245 return 0;
3246
3247 pop_stack(st, st->start, st->end);
3248 if( st->state == RETFUNC )
3249 {// return from a user-defined function
3250 struct script_retinfo* ri;
3251 int olddefsp = st->stack->defsp;
3252 int nargs;
3253
3254 pop_stack(st, st->stack->defsp, st->start);// pop distractions from the stack
3255 if( st->stack->defsp < 1 || st->stack->stack_data[st->stack->defsp-1].type != C_RETINFO )
3256 {
3257 ShowWarning("script:run_func: return without callfunc or callsub!\n");
3258 script_reportsrc(st);
3259 st->state = END;
3260 return 1;
3261 }
3262 script_free_vars( st->stack->var_function );
3263 aFree(st->stack->var_function);
3264
3265 ri = st->stack->stack_data[st->stack->defsp-1].u.ri;
3266 nargs = ri->nargs;
3267 st->pos = ri->pos;
3268 st->script = ri->script;
3269 st->stack->var_function = ri->var_function;
3270 st->stack->defsp = ri->defsp;
3271 memset(ri, 0, sizeof(struct script_retinfo));
3272
3273 pop_stack(st, olddefsp-nargs-1, olddefsp);// pop arguments and retinfo
3274
3275 st->state = GOTO;
3276 }
3277
3278 return 0;
3279}
3280
3281/*==========================================
3282 * script execution
3283 *------------------------------------------*/
3284void run_script(struct script_code *rootscript,int pos,int rid,int oid)
3285{
3286 struct script_state *st;
3287
3288 if( rootscript == NULL || pos < 0 )
3289 return;
3290
3291 // TODO In jAthena, this function can take over the pending script in the player. [FlavioJS]
3292 // It is unclear how that can be triggered, so it needs the be traced/checked in more detail.
3293 // NOTE At the time of this change, this function wasn't capable of taking over the script state because st->scriptroot was never set.
3294 st = script_alloc_state(rootscript, pos, rid, oid);
3295 run_script_main(st);
3296}
3297
3298void script_stop_sleeptimers(int id)
3299{
3300 struct script_state* st;
3301 for(;;)
3302 {
3303 st = (struct script_state*)linkdb_erase(&sleep_db,(void*)id);
3304 if( st == NULL )
3305 break; // no more sleep timers
3306 script_free_state(st);
3307 }
3308}
3309
3310/*==========================================
3311 * Žw’èƒmÂ[Æ’h‚ðsleep_db‚©‚çÂÃÂÅ“
3312 *------------------------------------------*/
3313struct linkdb_node* script_erase_sleepdb(struct linkdb_node *n)
3314{
3315 struct linkdb_node *retnode;
3316
3317 if( n == NULL)
3318 return NULL;
3319 if( n->prev == NULL )
3320 sleep_db = n->next;
3321 else
3322 n->prev->next = n->next;
3323 if( n->next )
3324 n->next->prev = n->prev;
3325 retnode = n->next;
3326 aFree( n );
3327 return retnode; // ŽŸ‚̃mÂ[Æ’h‚ð•Ô‚·
3328}
3329
3330/*==========================================
3331 * sleep—pÆ’^Æ’CÆ’}Â[ŠÖÂâ€
3332 *------------------------------------------*/
3333int run_script_timer(int tid, unsigned int tick, int id, intptr_t data)
3334{
3335 struct script_state *st = (struct script_state *)data;
3336 struct linkdb_node *node = (struct linkdb_node *)sleep_db;
3337 TBL_PC *sd = map_id2sd(st->rid);
3338
3339 if((sd && sd->status.char_id != id) || (st->rid && !sd))
3340 { //Character mismatch. Cancel execution.
3341 st->rid = 0;
3342 st->state = END;
3343 }
3344 while( node && st->sleep.timer != INVALID_TIMER ) {
3345 if( (int)node->key == st->oid && ((struct script_state *)node->data)->sleep.timer == st->sleep.timer ) {
3346 script_erase_sleepdb(node);
3347 st->sleep.timer = INVALID_TIMER;
3348 break;
3349 }
3350 node = node->next;
3351 }
3352 if(st->state != RERUNLINE)
3353 st->sleep.tick = 0;
3354 run_script_main(st);
3355 return 0;
3356}
3357
3358/// Detaches script state from possibly attached character and restores it's previous script if any.
3359///
3360/// @param st Script state to detach.
3361/// @param dequeue_event Whether to schedule any queued events, when there was no previous script.
3362static void script_detach_state(struct script_state* st, bool dequeue_event)
3363{
3364 struct map_session_data* sd;
3365
3366 if(st->rid && (sd = map_id2sd(st->rid))!=NULL)
3367 {
3368 sd->st = st->bk_st;
3369 sd->npc_id = st->bk_npcid;
3370
3371 if(st->bk_st)
3372 {
3373 //Remove tag for removal.
3374 st->bk_st = NULL;
3375 st->bk_npcid = 0;
3376 }
3377 else if(dequeue_event)
3378 {
3379 npc_event_dequeue(sd);
3380 }
3381 }
3382 else if(st->bk_st)
3383 {// rid was set to 0, before detaching the script state
3384 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);
3385 script_reportsrc(st->bk_st);
3386
3387 script_free_state(st->bk_st);
3388 st->bk_st = NULL;
3389 }
3390}
3391
3392/// Attaches script state to possibly attached character and backups it's previous script, if any.
3393///
3394/// @param st Script state to attach.
3395static void script_attach_state(struct script_state* st)
3396{
3397 struct map_session_data* sd;
3398
3399 if(st->rid && (sd = map_id2sd(st->rid))!=NULL)
3400 {
3401 if(st!=sd->st)
3402 {
3403 if(st->bk_st)
3404 {// there is already a backup
3405 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);
3406 }
3407 st->bk_st = sd->st;
3408 st->bk_npcid = sd->npc_id;
3409 }
3410 sd->st = st;
3411 sd->npc_id = st->oid;
3412 }
3413}
3414
3415/*==========================================
3416 * Æ’XÆ’NÆ’Å Æ’vÆ’g‚ÌŽÀÂsÆ’ÂÆ’Cƒ“•â€â€¢Âª
3417 *------------------------------------------*/
3418void run_script_main(struct script_state *st)
3419{
3420 int cmdcount=script_config.check_cmdcount;
3421 int gotocount=script_config.check_gotocount;
3422 TBL_PC *sd;
3423 struct script_stack *stack=st->stack;
3424 struct npc_data *nd;
3425
3426 script_attach_state(st);
3427
3428 nd = map_id2nd(st->oid);
3429 if( nd && map[nd->bl.m].instance_id > 0 )
3430 st->instance_id = map[nd->bl.m].instance_id;
3431
3432 if(st->state == RERUNLINE) {
3433 run_func(st);
3434 if(st->state == GOTO)
3435 st->state = RUN;
3436 } else if(st->state != END)
3437 st->state = RUN;
3438
3439 while(st->state == RUN)
3440 {
3441 enum c_op c = get_com(st->script->script_buf,&st->pos);
3442 switch(c){
3443 case C_EOL:
3444 if( stack->defsp > stack->sp )
3445 ShowError("script:run_script_main: unexpected stack position (defsp=%d sp=%d). please report this!!!\n", stack->defsp, stack->sp);
3446 else
3447 pop_stack(st, stack->defsp, stack->sp);// pop unused stack data. (unused return value)
3448 break;
3449 case C_INT:
3450 push_val(stack,C_INT,get_num(st->script->script_buf,&st->pos));
3451 break;
3452 case C_POS:
3453 case C_NAME:
3454 push_val(stack,c,GETVALUE(st->script->script_buf,st->pos));
3455 st->pos+=3;
3456 break;
3457 case C_ARG:
3458 push_val(stack,c,0);
3459 break;
3460 case C_STR:
3461 push_str(stack,C_CONSTSTR,(char*)(st->script->script_buf+st->pos));
3462 while(st->script->script_buf[st->pos++]);
3463 break;
3464 case C_FUNC:
3465 run_func(st);
3466 if(st->state==GOTO){
3467 st->state = RUN;
3468 if( gotocount>0 && (--gotocount)<=0 ){
3469 ShowError("run_script: infinity loop !\n");
3470 script_reportsrc(st);
3471 st->state=END;
3472 }
3473 }
3474 break;
3475
3476 case C_NEG:
3477 case C_NOT:
3478 case C_LNOT:
3479 op_1(st ,c);
3480 break;
3481
3482 case C_ADD:
3483 case C_SUB:
3484 case C_MUL:
3485 case C_DIV:
3486 case C_MOD:
3487 case C_EQ:
3488 case C_NE:
3489 case C_GT:
3490 case C_GE:
3491 case C_LT:
3492 case C_LE:
3493 case C_AND:
3494 case C_OR:
3495 case C_XOR:
3496 case C_LAND:
3497 case C_LOR:
3498 case C_R_SHIFT:
3499 case C_L_SHIFT:
3500 op_2(st, c);
3501 break;
3502
3503 case C_OP3:
3504 op_3(st, c);
3505 break;
3506
3507 case C_NOP:
3508 st->state=END;
3509 break;
3510
3511 default:
3512 ShowError("unknown command : %d @ %d\n",c,st->pos);
3513 st->state=END;
3514 break;
3515 }
3516 if( cmdcount>0 && (--cmdcount)<=0 ){
3517 ShowError("run_script: infinity loop !\n");
3518 script_reportsrc(st);
3519 st->state=END;
3520 }
3521 }
3522
3523 if(st->sleep.tick > 0) {
3524 //Restore previous script
3525 script_detach_state(st, false);
3526 //Delay execution
3527 sd = map_id2sd(st->rid); // Get sd since script might have attached someone while running. [Inkfish]
3528 st->sleep.charid = sd?sd->status.char_id:0;
3529 st->sleep.timer = add_timer(gettick()+st->sleep.tick,
3530 run_script_timer, st->sleep.charid, (intptr_t)st);
3531 linkdb_insert(&sleep_db, (void*)st->oid, st);
3532 }
3533 else if(st->state != END && st->rid){
3534 //Resume later (st is already attached to player).
3535 if(st->bk_st) {
3536 ShowWarning("Unable to restore stack! Double continuation!\n");
3537 //Report BOTH scripts to see if that can help somehow.
3538 ShowDebug("Previous script (lost):\n");
3539 script_reportsrc(st->bk_st);
3540 ShowDebug("Current script:\n");
3541 script_reportsrc(st);
3542
3543 script_free_state(st->bk_st);
3544 st->bk_st = NULL;
3545 }
3546 } else {
3547 //Dispose of script.
3548 if ((sd = map_id2sd(st->rid))!=NULL)
3549 { //Restore previous stack and save char.
3550 if(sd->state.using_fake_npc){
3551 clif_clearunit_single(sd->npc_id, CLR_OUTSIGHT, sd->fd);
3552 sd->state.using_fake_npc = 0;
3553 }
3554 //Restore previous script if any.
3555 script_detach_state(st, true);
3556 if (sd->state.reg_dirty&2)
3557 intif_saveregistry(sd,2);
3558 if (sd->state.reg_dirty&1)
3559 intif_saveregistry(sd,1);
3560 }
3561 script_free_state(st);
3562 st = NULL;
3563 }
3564}
3565
3566int script_config_read(char *cfgName)
3567{
3568 int i;
3569 char line[1024],w1[1024],w2[1024];
3570 FILE *fp;
3571
3572
3573 fp=fopen(cfgName,"r");
3574 if(fp==NULL){
3575 ShowError("file not found: [%s]\n", cfgName);
3576 return 1;
3577 }
3578 while(fgets(line, sizeof(line), fp))
3579 {
3580 if(line[0] == '/' && line[1] == '/')
3581 continue;
3582 i=sscanf(line,"%[^:]: %[^\r\n]",w1,w2);
3583 if(i!=2)
3584 continue;
3585
3586 if(strcmpi(w1,"warn_func_mismatch_paramnum")==0) {
3587 script_config.warn_func_mismatch_paramnum = config_switch(w2);
3588 }
3589 else if(strcmpi(w1,"check_cmdcount")==0) {
3590 script_config.check_cmdcount = config_switch(w2);
3591 }
3592 else if(strcmpi(w1,"check_gotocount")==0) {
3593 script_config.check_gotocount = config_switch(w2);
3594 }
3595 else if(strcmpi(w1,"input_min_value")==0) {
3596 script_config.input_min_value = config_switch(w2);
3597 }
3598 else if(strcmpi(w1,"input_max_value")==0) {
3599 script_config.input_max_value = config_switch(w2);
3600 }
3601 else if(strcmpi(w1,"warn_func_mismatch_argtypes")==0) {
3602 script_config.warn_func_mismatch_argtypes = config_switch(w2);
3603 }
3604 else if(strcmpi(w1,"import")==0){
3605 script_config_read(w2);
3606 }
3607 }
3608 fclose(fp);
3609
3610 return 0;
3611}
3612
3613static int do_final_userfunc_sub (DBKey key,void *data,va_list ap)
3614{
3615 struct script_code *code = (struct script_code *)data;
3616 if(code){
3617 script_free_vars( &code->script_vars );
3618 aFree( code->script_buf );
3619 aFree( code );
3620 }
3621 return 0;
3622}
3623
3624static int do_final_autobonus_sub (DBKey key,void *data,va_list ap)
3625{
3626 struct script_code *script = (struct script_code *)data;
3627
3628 if( script )
3629 script_free_code(script);
3630
3631 return 0;
3632}
3633
3634void script_run_autobonus(const char *autobonus, int id, int pos)
3635{
3636 struct script_code *script = (struct script_code *)strdb_get(autobonus_db, autobonus);
3637
3638 if( script )
3639 {
3640 current_equip_item_index = pos;
3641 run_script(script,0,id,0);
3642 }
3643}
3644
3645void script_add_autobonus(const char *autobonus)
3646{
3647 if( strdb_get(autobonus_db, autobonus) == NULL )
3648 {
3649 struct script_code *script = parse_script(autobonus, "autobonus", 0, 0);
3650
3651 if( script )
3652 strdb_put(autobonus_db, autobonus, script);
3653 }
3654}
3655
3656
3657/// resets a temporary character array variable to given value
3658void script_cleararray_pc(struct map_session_data* sd, const char* varname, void* value)
3659{
3660 int key;
3661 uint8 idx;
3662
3663 if( not_array_variable(varname[0]) || !not_server_variable(varname[0]) )
3664 {
3665 ShowError("script_cleararray_pc: Variable '%s' has invalid scope (char_id=%d).\n", varname, sd->status.char_id);
3666 return;
3667 }
3668
3669 key = add_str(varname);
3670
3671 if( is_string_variable(varname) )
3672 {
3673 for( idx = 0; idx < SCRIPT_MAX_ARRAYSIZE; idx++ )
3674 {
3675 pc_setregstr(sd, reference_uid(key, idx), (const char*)value);
3676 }
3677 }
3678 else
3679 {
3680 for( idx = 0; idx < SCRIPT_MAX_ARRAYSIZE; idx++ )
3681 {
3682 pc_setreg(sd, reference_uid(key, idx), (int)value);
3683 }
3684 }
3685}
3686
3687
3688/// sets a temporary character array variable element idx to given value
3689/// @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.
3690void script_setarray_pc(struct map_session_data* sd, const char* varname, uint8 idx, void* value, int* refcache)
3691{
3692 int key;
3693
3694 if( not_array_variable(varname[0]) || !not_server_variable(varname[0]) )
3695 {
3696 ShowError("script_setarray_pc: Variable '%s' has invalid scope (char_id=%d).\n", varname, sd->status.char_id);
3697 return;
3698 }
3699
3700 if( idx >= SCRIPT_MAX_ARRAYSIZE )
3701 {
3702 ShowError("script_setarray_pc: Variable '%s' has invalid index '%d' (char_id=%d).\n", varname, (int)idx, sd->status.char_id);
3703 return;
3704 }
3705
3706 key = ( refcache && refcache[0] ) ? refcache[0] : add_str(varname);
3707
3708 if( is_string_variable(varname) )
3709 {
3710 pc_setregstr(sd, reference_uid(key, idx), (const char*)value);
3711 }
3712 else
3713 {
3714 pc_setreg(sd, reference_uid(key, idx), (int)value);
3715 }
3716
3717 if( refcache )
3718 {// save to avoid repeated add_str calls
3719 refcache[0] = key;
3720 }
3721}
3722
3723
3724/*==========================================
3725 * ÂI—¹
3726 *------------------------------------------*/
3727int do_final_script()
3728{
3729#ifdef DEBUG_HASH
3730 if (battle_config.etc_log)
3731 {
3732 FILE *fp = fopen("hash_dump.txt","wt");
3733 if(fp) {
3734 int i,count[SCRIPT_HASH_SIZE];
3735 int count2[SCRIPT_HASH_SIZE]; // number of buckets with a certain number of items
3736 int n=0;
3737 int min=INT_MAX,max=0,zero=0;
3738 double mean=0.0f;
3739 double median=0.0f;
3740
3741 ShowNotice("Dumping script str hash information to hash_dump.txt\n");
3742 memset(count, 0, sizeof(count));
3743 fprintf(fp,"num : hash : data_name\n");
3744 fprintf(fp,"---------------------------------------------------------------\n");
3745 for(i=LABEL_START; i<str_num; i++) {
3746 unsigned int h = calc_hash(get_str(i));
3747 fprintf(fp,"%04d : %4u : %s\n",i,h, get_str(i));
3748 ++count[h];
3749 }
3750 fprintf(fp,"--------------------\n\n");
3751 memset(count2, 0, sizeof(count2));
3752 for(i=0; i<SCRIPT_HASH_SIZE; i++) {
3753 fprintf(fp," hash %3d = %d\n",i,count[i]);
3754 if(min > count[i])
3755 min = count[i]; // minimun count of collision
3756 if(max < count[i])
3757 max = count[i]; // maximun count of collision
3758 if(count[i] == 0)
3759 zero++;
3760 ++count2[count[i]];
3761 }
3762 fprintf(fp,"\n--------------------\n items : buckets\n--------------------\n");
3763 for( i=min; i <= max; ++i ){
3764 fprintf(fp," %5d : %7d\n",i,count2[i]);
3765 mean += 1.0f*i*count2[i]/SCRIPT_HASH_SIZE; // Note: this will always result in <nr labels>/<nr buckets>
3766 }
3767 for( i=min; i <= max; ++i ){
3768 n += count2[i];
3769 if( n*2 >= SCRIPT_HASH_SIZE )
3770 {
3771 if( SCRIPT_HASH_SIZE%2 == 0 && SCRIPT_HASH_SIZE/2 == n )
3772 median = (i+i+1)/2.0f;
3773 else
3774 median = i;
3775 break;
3776 }
3777 }
3778 fprintf(fp,"--------------------\n min = %d, max = %d, zero = %d\n mean = %lf, median = %lf\n",min,max,zero,mean,median);
3779 fclose(fp);
3780 }
3781 }
3782#endif
3783
3784 mapreg_final();
3785
3786 scriptlabel_db->destroy(scriptlabel_db,NULL);
3787 userfunc_db->destroy(userfunc_db,do_final_userfunc_sub);
3788 autobonus_db->destroy(autobonus_db, do_final_autobonus_sub);
3789 if(sleep_db) {
3790 struct linkdb_node *n = (struct linkdb_node *)sleep_db;
3791 while(n) {
3792 struct script_state *st = (struct script_state *)n->data;
3793 script_free_state(st);
3794 n = n->next;
3795 }
3796 linkdb_final(&sleep_db);
3797 }
3798
3799 if (str_data)
3800 aFree(str_data);
3801 if (str_buf)
3802 aFree(str_buf);
3803
3804 return 0;
3805}
3806/*==========================================
3807 * ‰Šú‰»
3808 *------------------------------------------*/
3809int do_init_script()
3810{
3811 userfunc_db=strdb_alloc(DB_OPT_DUP_KEY,0);
3812 scriptlabel_db=strdb_alloc((DBOptions)(DB_OPT_DUP_KEY|DB_OPT_ALLOW_NULL_DATA),50);
3813 autobonus_db = strdb_alloc(DB_OPT_DUP_KEY,0);
3814
3815 mapreg_init();
3816
3817 return 0;
3818}
3819
3820int script_reload()
3821{
3822 userfunc_db->clear(userfunc_db,do_final_userfunc_sub);
3823 scriptlabel_db->clear(scriptlabel_db, NULL);
3824
3825 if(sleep_db) {
3826 struct linkdb_node *n = (struct linkdb_node *)sleep_db;
3827 while(n) {
3828 struct script_state *st = (struct script_state *)n->data;
3829 script_free_state(st);
3830 n = n->next;
3831 }
3832 linkdb_final(&sleep_db);
3833 }
3834
3835 mapreg_reload();
3836 return 0;
3837}
3838
3839//-----------------------------------------------------------------------------
3840// buildin functions
3841//
3842
3843#define BUILDIN_DEF(x,args) { buildin_ ## x , #x , args }
3844#define BUILDIN_DEF2(x,x2,args) { buildin_ ## x , x2 , args }
3845#define BUILDIN_FUNC(x) int buildin_ ## x (struct script_state* st)
3846
3847/////////////////////////////////////////////////////////////////////
3848// NPC interaction
3849//
3850
3851/// Appends a message to the npc dialog.
3852/// If a dialog doesn't exist yet, one is created.
3853///
3854/// mes "<message>";
3855BUILDIN_FUNC(mes)
3856{
3857 TBL_PC* sd = script_rid2sd(st);
3858 if( sd == NULL )
3859 return 0;
3860
3861 clif_scriptmes(sd, st->oid, script_getstr(st, 2));
3862 return 0;
3863}
3864
3865/// Displays the button 'next' in the npc dialog.
3866/// The dialog text is cleared and the script continues when the button is pressed.
3867///
3868/// next;
3869BUILDIN_FUNC(next)
3870{
3871 TBL_PC* sd;
3872
3873 sd = script_rid2sd(st);
3874 if( sd == NULL )
3875 return 0;
3876
3877 st->state = STOP;
3878 clif_scriptnext(sd, st->oid);
3879 return 0;
3880}
3881
3882/// Ends the script and displays the button 'close' on the npc dialog.
3883/// The dialog is closed when the button is pressed.
3884///
3885/// close;
3886BUILDIN_FUNC(close)
3887{
3888 TBL_PC* sd;
3889
3890 sd = script_rid2sd(st);
3891 if( sd == NULL )
3892 return 0;
3893
3894 st->state = END;
3895 clif_scriptclose(sd, st->oid);
3896 return 0;
3897}
3898
3899/// Displays the button 'close' on the npc dialog.
3900/// The dialog is closed and the script continues when the button is pressed.
3901///
3902/// close2;
3903BUILDIN_FUNC(close2)
3904{
3905 TBL_PC* sd;
3906
3907 sd = script_rid2sd(st);
3908 if( sd == NULL )
3909 return 0;
3910
3911 st->state = STOP;
3912 clif_scriptclose(sd, st->oid);
3913 return 0;
3914}
3915
3916/// Counts the number of valid and total number of options in 'str'
3917/// If max_count > 0 the counting stops when that valid option is reached
3918/// total is incremented for each option (NULL is supported)
3919static int menu_countoptions(const char* str, int max_count, int* total)
3920{
3921 int count = 0;
3922 int bogus_total;
3923
3924 if( total == NULL )
3925 total = &bogus_total;
3926 ++(*total);
3927
3928 // initial empty options
3929 while( *str == ':' )
3930 {
3931 ++str;
3932 ++(*total);
3933 }
3934 // count menu options
3935 while( *str != '\0' )
3936 {
3937 ++count;
3938 --max_count;
3939 if( max_count == 0 )
3940 break;
3941 while( *str != ':' && *str != '\0' )
3942 ++str;
3943 while( *str == ':' )
3944 {
3945 ++str;
3946 ++(*total);
3947 }
3948 }
3949 return count;
3950}
3951
3952/// Displays a menu with options and goes to the target label.
3953/// The script is stopped if cancel is pressed.
3954/// Options with no text are not displayed in the client.
3955///
3956/// Options can be grouped together, separated by the character ':' in the text:
3957/// ex: menu "A:B:C",L_target;
3958/// All these options go to the specified target label.
3959///
3960/// The index of the selected option is put in the variable @menu.
3961/// Indexes start with 1 and are consistent with grouped and empty options.
3962/// ex: menu "A::B",-,"",L_Impossible,"C",-;
3963/// // displays "A", "B" and "C", corresponding to indexes 1, 3 and 5
3964///
3965/// NOTE: the client closes the npc dialog when cancel is pressed
3966///
3967/// menu "<option_text>",<target_label>{,"<option_text>",<target_label>,...};
3968BUILDIN_FUNC(menu)
3969{
3970 int i;
3971 const char* text;
3972 TBL_PC* sd;
3973
3974 sd = script_rid2sd(st);
3975 if( sd == NULL )
3976 return 0;
3977
3978 // TODO detect multiple scripts waiting for input at the same time, and what to do when that happens
3979 if( sd->state.menu_or_input == 0 )
3980 {
3981 struct StringBuf buf;
3982 struct script_data* data;
3983
3984 if( script_lastdata(st) % 2 == 0 )
3985 {// argument count is not even (1st argument is at index 2)
3986 ShowError("script:menu: illegal number of arguments (%d).\n", (script_lastdata(st) - 1));
3987 st->state = END;
3988 return 1;
3989 }
3990
3991 StringBuf_Init(&buf);
3992 sd->npc_menu = 0;
3993 for( i = 2; i < script_lastdata(st); i += 2 )
3994 {
3995 // menu options
3996 text = script_getstr(st, i);
3997
3998 // target label
3999 data = script_getdata(st, i+1);
4000 if( !data_islabel(data) )
4001 {// not a label
4002 StringBuf_Destroy(&buf);
4003 ShowError("script:menu: argument #%d (from 1) is not a label or label not found.\n", i);
4004 script_reportdata(data);
4005 st->state = END;
4006 return 1;
4007 }
4008
4009 // append option(s)
4010 if( text[0] == '\0' )
4011 continue;// empty string, ignore
4012 if( sd->npc_menu > 0 )
4013 StringBuf_AppendStr(&buf, ":");
4014 StringBuf_AppendStr(&buf, text);
4015 sd->npc_menu += menu_countoptions(text, 0, NULL);
4016 }
4017 st->state = RERUNLINE;
4018 sd->state.menu_or_input = 1;
4019 clif_scriptmenu(sd, st->oid, StringBuf_Value(&buf));
4020 StringBuf_Destroy(&buf);
4021
4022 if( sd->npc_menu >= 0xff )
4023 {// 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
4024 ShowWarning("buildin_menu: Too many options specified (current=%d, max=254).\n", sd->npc_menu);
4025 script_reportsrc(st);
4026 }
4027 }
4028 else if( sd->npc_menu == 0xff )
4029 {// Cancel was pressed
4030 sd->state.menu_or_input = 0;
4031 st->state = END;
4032 }
4033 else
4034 {// goto target label
4035 int menu = 0;
4036
4037 sd->state.menu_or_input = 0;
4038 if( sd->npc_menu <= 0 )
4039 {
4040 ShowDebug("script:menu: unexpected selection (%d)\n", sd->npc_menu);
4041 st->state = END;
4042 return 1;
4043 }
4044
4045 // get target label
4046 for( i = 2; i < script_lastdata(st); i += 2 )
4047 {
4048 text = script_getstr(st, i);
4049 sd->npc_menu -= menu_countoptions(text, sd->npc_menu, &menu);
4050 if( sd->npc_menu <= 0 )
4051 break;// entry found
4052 }
4053 if( sd->npc_menu > 0 )
4054 {// Invalid selection
4055 ShowDebug("script:menu: selection is out of range (%d pairs are missing?) - please report this\n", sd->npc_menu);
4056 st->state = END;
4057 return 1;
4058 }
4059 if( !data_islabel(script_getdata(st, i + 1)) )
4060 {// TODO remove this temporary crash-prevention code (fallback for multiple scripts requesting user input)
4061 ShowError("script:menu: unexpected data in label argument\n");
4062 script_reportdata(script_getdata(st, i + 1));
4063 st->state = END;
4064 return 1;
4065 }
4066 pc_setreg(sd, add_str("@menu"), menu);
4067 st->pos = script_getnum(st, i + 1);
4068 st->state = GOTO;
4069 }
4070 return 0;
4071}
4072
4073/// Displays a menu with options and returns the selected option.
4074/// Behaves like 'menu' without the target labels.
4075///
4076/// select(<option_text>{,<option_text>,...}) -> <selected_option>
4077///
4078/// @see menu
4079BUILDIN_FUNC(select)
4080{
4081 int i;
4082 const char* text;
4083 TBL_PC* sd;
4084
4085 sd = script_rid2sd(st);
4086 if( sd == NULL )
4087 return 0;
4088
4089 if( sd->state.menu_or_input == 0 )
4090 {
4091 struct StringBuf buf;
4092
4093 StringBuf_Init(&buf);
4094 sd->npc_menu = 0;
4095 for( i = 2; i <= script_lastdata(st); ++i )
4096 {
4097 text = script_getstr(st, i);
4098 if( sd->npc_menu > 0 )
4099 StringBuf_AppendStr(&buf, ":");
4100 StringBuf_AppendStr(&buf, text);
4101 sd->npc_menu += menu_countoptions(text, 0, NULL);
4102 }
4103
4104 st->state = RERUNLINE;
4105 sd->state.menu_or_input = 1;
4106 clif_scriptmenu(sd, st->oid, StringBuf_Value(&buf));
4107 StringBuf_Destroy(&buf);
4108
4109 if( sd->npc_menu >= 0xff )
4110 {
4111 ShowWarning("buildin_select: Too many options specified (current=%d, max=254).\n", sd->npc_menu);
4112 script_reportsrc(st);
4113 }
4114 }
4115 else if( sd->npc_menu == 0xff )
4116 {// Cancel was pressed
4117 sd->state.menu_or_input = 0;
4118 st->state = END;
4119 }
4120 else
4121 {// return selected option
4122 int menu = 0;
4123
4124 sd->state.menu_or_input = 0;
4125 for( i = 2; i <= script_lastdata(st); ++i )
4126 {
4127 text = script_getstr(st, i);
4128 sd->npc_menu -= menu_countoptions(text, sd->npc_menu, &menu);
4129 if( sd->npc_menu <= 0 )
4130 break;// entry found
4131 }
4132 pc_setreg(sd, add_str("@menu"), menu);
4133 script_pushint(st, menu);
4134 st->state = RUN;
4135 }
4136 return 0;
4137}
4138
4139/// Displays a menu with options and returns the selected option.
4140/// Behaves like 'menu' without the target labels, except when cancel is
4141/// pressed.
4142/// When cancel is pressed, the script continues and 255 is returned.
4143///
4144/// prompt(<option_text>{,<option_text>,...}) -> <selected_option>
4145///
4146/// @see menu
4147BUILDIN_FUNC(prompt)
4148{
4149 int i;
4150 const char *text;
4151 TBL_PC* sd;
4152
4153 sd = script_rid2sd(st);
4154 if( sd == NULL )
4155 return 0;
4156
4157 if( sd->state.menu_or_input == 0 )
4158 {
4159 struct StringBuf buf;
4160
4161 StringBuf_Init(&buf);
4162 sd->npc_menu = 0;
4163 for( i = 2; i <= script_lastdata(st); ++i )
4164 {
4165 text = script_getstr(st, i);
4166 if( sd->npc_menu > 0 )
4167 StringBuf_AppendStr(&buf, ":");
4168 StringBuf_AppendStr(&buf, text);
4169 sd->npc_menu += menu_countoptions(text, 0, NULL);
4170 }
4171
4172 st->state = RERUNLINE;
4173 sd->state.menu_or_input = 1;
4174 clif_scriptmenu(sd, st->oid, StringBuf_Value(&buf));
4175 StringBuf_Destroy(&buf);
4176
4177 if( sd->npc_menu >= 0xff )
4178 {
4179 ShowWarning("buildin_prompt: Too many options specified (current=%d, max=254).\n", sd->npc_menu);
4180 script_reportsrc(st);
4181 }
4182 }
4183 else if( sd->npc_menu == 0xff )
4184 {// Cancel was pressed
4185 sd->state.menu_or_input = 0;
4186 pc_setreg(sd, add_str("@menu"), 0xff);
4187 script_pushint(st, 0xff);
4188 st->state = RUN;
4189 }
4190 else
4191 {// return selected option
4192 int menu = 0;
4193
4194 sd->state.menu_or_input = 0;
4195 for( i = 2; i <= script_lastdata(st); ++i )
4196 {
4197 text = script_getstr(st, i);
4198 sd->npc_menu -= menu_countoptions(text, sd->npc_menu, &menu);
4199 if( sd->npc_menu <= 0 )
4200 break;// entry found
4201 }
4202 pc_setreg(sd, add_str("@menu"), menu);
4203 script_pushint(st, menu);
4204 st->state = RUN;
4205 }
4206 return 0;
4207}
4208
4209/////////////////////////////////////////////////////////////////////
4210// ...
4211//
4212
4213/// Jumps to the target script label.
4214///
4215/// goto <label>;
4216BUILDIN_FUNC(goto)
4217{
4218 if( !data_islabel(script_getdata(st,2)) )
4219 {
4220 ShowError("script:goto: not a label\n");
4221 script_reportdata(script_getdata(st,2));
4222 st->state = END;
4223 return 1;
4224 }
4225
4226 st->pos = script_getnum(st,2);
4227 st->state = GOTO;
4228 return 0;
4229}
4230
4231/*==========================================
4232 * user-defined function call
4233 *------------------------------------------*/
4234BUILDIN_FUNC(callfunc)
4235{
4236 int i, j;
4237 struct script_retinfo* ri;
4238 struct script_code* scr;
4239 const char* str = script_getstr(st,2);
4240
4241 scr = (struct script_code*)strdb_get(userfunc_db, str);
4242 if( !scr )
4243 {
4244 ShowError("script:callfunc: function not found! [%s]\n", str);
4245 st->state = END;
4246 return 1;
4247 }
4248
4249 for( i = st->start+3, j = 0; i < st->end; i++, j++ )
4250 {
4251 struct script_data* data = push_copy(st->stack,i);
4252 if( data_isreference(data) && !data->ref )
4253 {
4254 const char* name = reference_getname(data);
4255 if( name[0] == '.' && name[1] == '@' )
4256 data->ref = st->stack->var_function;
4257 else if( name[0] == '.' )
4258 data->ref = &st->script->script_vars;
4259 }
4260 }
4261
4262 CREATE(ri, struct script_retinfo, 1);
4263 ri->script = st->script;// script code
4264 ri->var_function = st->stack->var_function;// scope variables
4265 ri->pos = st->pos;// script location
4266 ri->nargs = j;// argument count
4267 ri->defsp = st->stack->defsp;// default stack pointer
4268 push_retinfo(st->stack, ri);
4269
4270 st->pos = 0;
4271 st->script = scr;
4272 st->stack->defsp = st->stack->sp;
4273 st->state = GOTO;
4274 st->stack->var_function = (struct linkdb_node**)aCalloc(1, sizeof(struct linkdb_node*));
4275
4276 return 0;
4277}
4278/*==========================================
4279 * subroutine call
4280 *------------------------------------------*/
4281BUILDIN_FUNC(callsub)
4282{
4283 int i,j;
4284 struct script_retinfo* ri;
4285 int pos = script_getnum(st,2);
4286
4287 if( !data_islabel(script_getdata(st,2)) && !data_isfunclabel(script_getdata(st,2)) )
4288 {
4289 ShowError("script:callsub: argument is not a label\n");
4290 script_reportdata(script_getdata(st,2));
4291 st->state = END;
4292 return 1;
4293 }
4294
4295 for( i = st->start+3, j = 0; i < st->end; i++, j++ )
4296 {
4297 struct script_data* data = push_copy(st->stack,i);
4298 if( data_isreference(data) && !data->ref )
4299 {
4300 const char* name = reference_getname(data);
4301 if( name[0] == '.' && name[1] == '@' )
4302 data->ref = st->stack->var_function;
4303 }
4304 }
4305
4306 CREATE(ri, struct script_retinfo, 1);
4307 ri->script = st->script;// script code
4308 ri->var_function = st->stack->var_function;// scope variables
4309 ri->pos = st->pos;// script location
4310 ri->nargs = j;// argument count
4311 ri->defsp = st->stack->defsp;// default stack pointer
4312 push_retinfo(st->stack, ri);
4313
4314 st->pos = pos;
4315 st->stack->defsp = st->stack->sp;
4316 st->state = GOTO;
4317 st->stack->var_function = (struct linkdb_node**)aCalloc(1, sizeof(struct linkdb_node*));
4318
4319 return 0;
4320}
4321
4322/// Retrieves an argument provided to callfunc/callsub.
4323/// If the argument doesn't exist
4324///
4325/// getarg(<index>{,<default_value>}) -> <value>
4326BUILDIN_FUNC(getarg)
4327{
4328 struct script_retinfo* ri;
4329 int idx;
4330
4331 if( st->stack->defsp < 1 || st->stack->stack_data[st->stack->defsp - 1].type != C_RETINFO )
4332 {
4333 ShowError("script:getarg: no callfunc or callsub!\n");
4334 st->state = END;
4335 return 1;
4336 }
4337 ri = st->stack->stack_data[st->stack->defsp - 1].u.ri;
4338
4339 idx = script_getnum(st,2);
4340
4341 if( idx >= 0 && idx < ri->nargs )
4342 push_copy(st->stack, st->stack->defsp - 1 - ri->nargs + idx);
4343 else if( script_hasdata(st,3) )
4344 script_pushcopy(st, 3);
4345 else
4346 {
4347 ShowError("script:getarg: index (idx=%d) out of range (nargs=%d) and no default value found\n", idx, ri->nargs);
4348 st->state = END;
4349 return 1;
4350 }
4351
4352 return 0;
4353}
4354
4355/// Returns from the current function, optionaly returning a value from the functions.
4356/// Don't use outside script functions.
4357///
4358/// return;
4359/// return <value>;
4360BUILDIN_FUNC(return)
4361{
4362 if( script_hasdata(st,2) )
4363 {// return value
4364 struct script_data* data;
4365 script_pushcopy(st, 2);
4366 data = script_getdatatop(st, -1);
4367 if( data_isreference(data) )
4368 {
4369 const char* name = reference_getname(data);
4370 if( name[0] == '.' && name[1] == '@' )
4371 {// scope variable
4372 if( !data->ref || data->ref == st->stack->var_function )
4373 get_val(st, data);// current scope, convert to value
4374 }
4375 else if( name[0] == '.' && !data->ref )
4376 {// script variable, link to current script
4377 data->ref = &st->script->script_vars;
4378 }
4379 }
4380 }
4381 else
4382 {// no return value
4383 script_pushnil(st);
4384 }
4385 st->state = RETFUNC;
4386 return 0;
4387}
4388
4389/// Returns a random number from 0 to <range>-1.
4390/// Or returns a random number from <min> to <max>.
4391/// If <min> is greater than <max>, their numbers are switched.
4392/// rand(<range>) -> <int>
4393/// rand(<min>,<max>) -> <int>
4394BUILDIN_FUNC(rand)
4395{
4396 int range;
4397 int min;
4398 int max;
4399
4400 if( script_hasdata(st,3) )
4401 {// min,max
4402 min = script_getnum(st,2);
4403 max = script_getnum(st,3);
4404 if( max < min )
4405 swap(min, max);
4406 range = max - min + 1;
4407 }
4408 else
4409 {// range
4410 min = 0;
4411 range = script_getnum(st,2);
4412 }
4413 if( range <= 1 )
4414 script_pushint(st, min);
4415 else
4416 script_pushint(st, rand()%range + min);
4417
4418 return 0;
4419}
4420
4421/*==========================================
4422 *
4423 *------------------------------------------*/
4424BUILDIN_FUNC(warp)
4425{
4426 int ret;
4427 int x,y;
4428 const char* str;
4429 TBL_PC* sd;
4430
4431 sd = script_rid2sd(st);
4432 if( sd == NULL )
4433 return 0;
4434
4435 str = script_getstr(st,2);
4436 x = script_getnum(st,3);
4437 y = script_getnum(st,4);
4438
4439 if(strcmp(str,"Random")==0)
4440 ret = pc_randomwarp(sd,CLR_TELEPORT);
4441 else if(strcmp(str,"SavePoint")==0 || strcmp(str,"Save")==0)
4442 ret = pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
4443 else
4444 ret = pc_setpos(sd,mapindex_name2id(str),x,y,CLR_OUTSIGHT);
4445
4446 if( ret ) {
4447 ShowError("buildin_warp: moving player '%s' to \"%s\",%d,%d failed.\n", sd->status.name, str, x, y);
4448 script_reportsrc(st);
4449 }
4450
4451 return 0;
4452}
4453/*==========================================
4454 * Æ’GÆ’Å Æ’AŽw’èƒÂÂ[Æ’v
4455 *------------------------------------------*/
4456static int buildin_areawarp_sub(struct block_list *bl,va_list ap)
4457{
4458 int x,y;
4459 unsigned int map;
4460 map=va_arg(ap, unsigned int);
4461 x=va_arg(ap,int);
4462 y=va_arg(ap,int);
4463 if(map == 0)
4464 pc_randomwarp((TBL_PC *)bl,CLR_TELEPORT);
4465 else
4466 pc_setpos((TBL_PC *)bl,map,x,y,CLR_OUTSIGHT);
4467 return 0;
4468}
4469BUILDIN_FUNC(areawarp)
4470{
4471 int x,y,m;
4472 unsigned int index;
4473 const char *str;
4474 const char *mapname;
4475 int x0,y0,x1,y1;
4476
4477 mapname=script_getstr(st,2);
4478 x0=script_getnum(st,3);
4479 y0=script_getnum(st,4);
4480 x1=script_getnum(st,5);
4481 y1=script_getnum(st,6);
4482 str=script_getstr(st,7);
4483 x=script_getnum(st,8);
4484 y=script_getnum(st,9);
4485
4486 if( (m=map_mapname2mapid(mapname))< 0)
4487 return 0;
4488
4489 if(strcmp(str,"Random")==0)
4490 index = 0;
4491 else if(!(index=mapindex_name2id(str)))
4492 return 0;
4493
4494 map_foreachinarea(buildin_areawarp_sub, m,x0,y0,x1,y1,BL_PC, index,x,y);
4495 return 0;
4496}
4497
4498/*==========================================
4499 * areapercentheal <map>,<x1>,<y1>,<x2>,<y2>,<hp>,<sp>
4500 *------------------------------------------*/
4501static int buildin_areapercentheal_sub(struct block_list *bl,va_list ap)
4502{
4503 int hp, sp;
4504 hp = va_arg(ap, int);
4505 sp = va_arg(ap, int);
4506 pc_percentheal((TBL_PC *)bl,hp,sp);
4507 return 0;
4508}
4509BUILDIN_FUNC(areapercentheal)
4510{
4511 int hp,sp,m;
4512 const char *mapname;
4513 int x0,y0,x1,y1;
4514
4515 mapname=script_getstr(st,2);
4516 x0=script_getnum(st,3);
4517 y0=script_getnum(st,4);
4518 x1=script_getnum(st,5);
4519 y1=script_getnum(st,6);
4520 hp=script_getnum(st,7);
4521 sp=script_getnum(st,8);
4522
4523 if( (m=map_mapname2mapid(mapname))< 0)
4524 return 0;
4525
4526 map_foreachinarea(buildin_areapercentheal_sub,m,x0,y0,x1,y1,BL_PC,hp,sp);
4527 return 0;
4528}
4529
4530/*==========================================
4531 * warpchar [LuzZza]
4532 * Useful for warp one player from
4533 * another player npc-session.
4534 * Using: warpchar "mapname",x,y,Char_ID;
4535 *------------------------------------------*/
4536BUILDIN_FUNC(warpchar)
4537{
4538 int x,y,a;
4539 const char *str;
4540 TBL_PC *sd;
4541
4542 str=script_getstr(st,2);
4543 x=script_getnum(st,3);
4544 y=script_getnum(st,4);
4545 a=script_getnum(st,5);
4546
4547 sd = map_charid2sd(a);
4548 if( sd == NULL )
4549 return 0;
4550
4551 if(strcmp(str, "Random") == 0)
4552 pc_randomwarp(sd, CLR_TELEPORT);
4553 else
4554 if(strcmp(str, "SavePoint") == 0)
4555 pc_setpos(sd, sd->status.save_point.map,sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT);
4556 else
4557 pc_setpos(sd, mapindex_name2id(str), x, y, CLR_TELEPORT);
4558
4559 return 0;
4560}
4561/*==========================================
4562 * Warpparty - [Fredzilla] [Paradox924X]
4563 * Syntax: warpparty "to_mapname",x,y,Party_ID,{"from_mapname"};
4564 * If 'from_mapname' is specified, only the party members on that map will be warped
4565 *------------------------------------------*/
4566BUILDIN_FUNC(warpparty)
4567{
4568 TBL_PC *sd = NULL;
4569 TBL_PC *pl_sd;
4570 struct party_data* p;
4571 int type;
4572 int mapindex;
4573 int i;
4574
4575 const char* str = script_getstr(st,2);
4576 int x = script_getnum(st,3);
4577 int y = script_getnum(st,4);
4578 int p_id = script_getnum(st,5);
4579 const char* str2 = NULL;
4580 if ( script_hasdata(st,6) )
4581 str2 = script_getstr(st,6);
4582
4583 p = party_search(p_id);
4584 if(!p)
4585 return 0;
4586
4587 type = ( strcmp(str,"Random")==0 ) ? 0
4588 : ( strcmp(str,"SavePointAll")==0 ) ? 1
4589 : ( strcmp(str,"SavePoint")==0 ) ? 2
4590 : ( strcmp(str,"Leader")==0 ) ? 3
4591 : 4;
4592
4593 switch (type)
4594 {
4595 case 3:
4596 for(i = 0; i < MAX_PARTY && !p->party.member[i].leader; i++);
4597 if (i == MAX_PARTY || !p->data[i].sd) //Leader not found / not online
4598 return 0;
4599 pl_sd = p->data[i].sd;
4600 mapindex = pl_sd->mapindex;
4601 x = pl_sd->bl.x;
4602 y = pl_sd->bl.y;
4603 break;
4604 case 4:
4605 mapindex = mapindex_name2id(str);
4606 break;
4607 case 2:
4608 //"SavePoint" uses save point of the currently attached player
4609 if (( sd = script_rid2sd(st) ) == NULL )
4610 return 0;
4611 default:
4612 mapindex = 0;
4613 break;
4614 }
4615
4616 for (i = 0; i < MAX_PARTY; i++)
4617 {
4618 if( !(pl_sd = p->data[i].sd) || pl_sd->status.party_id != p_id )
4619 continue;
4620
4621 if( str2 && strcmp(str2, map[pl_sd->bl.m].name) != 0 )
4622 continue;
4623
4624 if( pc_isdead(pl_sd) )
4625 continue;
4626
4627 switch( type )
4628 {
4629 case 0: // Random
4630 if(!map[pl_sd->bl.m].flag.nowarp)
4631 pc_randomwarp(pl_sd,CLR_TELEPORT);
4632 break;
4633 case 1: // SavePointAll
4634 if(!map[pl_sd->bl.m].flag.noreturn)
4635 pc_setpos(pl_sd,pl_sd->status.save_point.map,pl_sd->status.save_point.x,pl_sd->status.save_point.y,CLR_TELEPORT);
4636 break;
4637 case 2: // SavePoint
4638 if(!map[pl_sd->bl.m].flag.noreturn)
4639 pc_setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
4640 break;
4641 case 3: // Leader
4642 case 4: // m,x,y
4643 if(!map[pl_sd->bl.m].flag.noreturn && !map[pl_sd->bl.m].flag.nowarp)
4644 pc_setpos(pl_sd,mapindex,x,y,CLR_TELEPORT);
4645 break;
4646 }
4647 }
4648
4649 return 0;
4650}
4651/*==========================================
4652 * Warpguild - [Fredzilla]
4653 * Syntax: warpguild "mapname",x,y,Guild_ID;
4654 *------------------------------------------*/
4655BUILDIN_FUNC(warpguild)
4656{
4657 TBL_PC *sd = NULL;
4658 TBL_PC *pl_sd;
4659 struct guild* g;
4660 struct s_mapiterator* iter;
4661 int type;
4662
4663 const char* str = script_getstr(st,2);
4664 int x = script_getnum(st,3);
4665 int y = script_getnum(st,4);
4666 int gid = script_getnum(st,5);
4667
4668 g = guild_search(gid);
4669 if( g == NULL )
4670 return 0;
4671
4672 type = ( strcmp(str,"Random")==0 ) ? 0
4673 : ( strcmp(str,"SavePointAll")==0 ) ? 1
4674 : ( strcmp(str,"SavePoint")==0 ) ? 2
4675 : 3;
4676
4677 if( type == 2 && ( sd = script_rid2sd(st) ) == NULL )
4678 {// "SavePoint" uses save point of the currently attached player
4679 return 0;
4680 }
4681
4682 iter = mapit_getallusers();
4683 for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
4684 {
4685 if( pl_sd->status.guild_id != gid )
4686 continue;
4687
4688 switch( type )
4689 {
4690 case 0: // Random
4691 if(!map[pl_sd->bl.m].flag.nowarp)
4692 pc_randomwarp(pl_sd,CLR_TELEPORT);
4693 break;
4694 case 1: // SavePointAll
4695 if(!map[pl_sd->bl.m].flag.noreturn)
4696 pc_setpos(pl_sd,pl_sd->status.save_point.map,pl_sd->status.save_point.x,pl_sd->status.save_point.y,CLR_TELEPORT);
4697 break;
4698 case 2: // SavePoint
4699 if(!map[pl_sd->bl.m].flag.noreturn)
4700 pc_setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
4701 break;
4702 case 3: // m,x,y
4703 if(!map[pl_sd->bl.m].flag.noreturn && !map[pl_sd->bl.m].flag.nowarp)
4704 pc_setpos(pl_sd,mapindex_name2id(str),x,y,CLR_TELEPORT);
4705 break;
4706 }
4707 }
4708 mapit_free(iter);
4709
4710 return 0;
4711}
4712/*==========================================
4713 *
4714 *------------------------------------------*/
4715BUILDIN_FUNC(heal)
4716{
4717 TBL_PC *sd;
4718 int hp,sp;
4719
4720 sd = script_rid2sd(st);
4721 if (!sd) return 0;
4722
4723 hp=script_getnum(st,2);
4724 sp=script_getnum(st,3);
4725 status_heal(&sd->bl, hp, sp, 1);
4726 return 0;
4727}
4728/*==========================================
4729 *
4730 *------------------------------------------*/
4731BUILDIN_FUNC(itemheal)
4732{
4733 TBL_PC *sd;
4734 int hp,sp;
4735
4736 hp=script_getnum(st,2);
4737 sp=script_getnum(st,3);
4738
4739 if(potion_flag==1) {
4740 potion_hp = hp;
4741 potion_sp = sp;
4742 return 0;
4743 }
4744
4745 sd = script_rid2sd(st);
4746 if (!sd) return 0;
4747 pc_itemheal(sd,sd->itemid,hp,sp);
4748 return 0;
4749}
4750/*==========================================
4751 *
4752 *------------------------------------------*/
4753BUILDIN_FUNC(percentheal)
4754{
4755 int hp,sp;
4756 TBL_PC* sd;
4757
4758 hp=script_getnum(st,2);
4759 sp=script_getnum(st,3);
4760
4761 if(potion_flag==1) {
4762 potion_per_hp = hp;
4763 potion_per_sp = sp;
4764 return 0;
4765 }
4766
4767 sd = script_rid2sd(st);
4768 if( sd == NULL )
4769 return 0;
4770
4771 pc_percentheal(sd,hp,sp);
4772 return 0;
4773}
4774
4775/*==========================================
4776 *
4777 *------------------------------------------*/
4778BUILDIN_FUNC(jobchange)
4779{
4780 int job, upper=-1;
4781
4782 job=script_getnum(st,2);
4783 if( script_hasdata(st,3) )
4784 upper=script_getnum(st,3);
4785
4786 if (pcdb_checkid(job))
4787 {
4788 TBL_PC* sd;
4789
4790 sd = script_rid2sd(st);
4791 if( sd == NULL )
4792 return 0;
4793
4794 pc_jobchange(sd, job, upper);
4795 }
4796
4797 return 0;
4798}
4799
4800/*==========================================
4801 *
4802 *------------------------------------------*/
4803BUILDIN_FUNC(jobname)
4804{
4805 int class_=script_getnum(st,2);
4806 script_pushconststr(st, (char*)job_name(class_));
4807 return 0;
4808}
4809
4810/// Get input from the player.
4811/// For numeric inputs the value is capped to the range [min,max]. Returns 1 if
4812/// the value was higher than 'max', -1 if lower than 'min' and 0 otherwise.
4813/// For string inputs it returns 1 if the string was longer than 'max', -1 is
4814/// shorter than 'min' and 0 otherwise.
4815///
4816/// input(<var>{,<min>{,<max>}}) -> <int>
4817BUILDIN_FUNC(input)
4818{
4819 TBL_PC* sd;
4820 struct script_data* data;
4821 int uid;
4822 const char* name;
4823 int min;
4824 int max;
4825
4826 sd = script_rid2sd(st);
4827 if( sd == NULL )
4828 return 0;
4829
4830 data = script_getdata(st,2);
4831 if( !data_isreference(data) ){
4832 ShowError("script:input: not a variable\n");
4833 script_reportdata(data);
4834 st->state = END;
4835 return 1;
4836 }
4837 uid = reference_getuid(data);
4838 name = reference_getname(data);
4839 min = (script_hasdata(st,3) ? script_getnum(st,3) : script_config.input_min_value);
4840 max = (script_hasdata(st,4) ? script_getnum(st,4) : script_config.input_max_value);
4841
4842 if( !sd->state.menu_or_input )
4843 { // first invocation, display npc input box
4844 sd->state.menu_or_input = 1;
4845 st->state = RERUNLINE;
4846 if( is_string_variable(name) )
4847 clif_scriptinputstr(sd,st->oid);
4848 else
4849 clif_scriptinput(sd,st->oid);
4850 }
4851 else
4852 { // take received text/value and store it in the designated variable
4853 sd->state.menu_or_input = 0;
4854 if( is_string_variable(name) )
4855 {
4856 int len = (int)strlen(sd->npc_str);
4857 set_reg(st, sd, uid, name, (void*)sd->npc_str, script_getref(st,2));
4858 script_pushint(st, (len > max ? 1 : len < min ? -1 : 0));
4859 }
4860 else
4861 {
4862 int amount = sd->npc_amount;
4863 set_reg(st, sd, uid, name, (void*)cap_value(amount,min,max), script_getref(st,2));
4864 script_pushint(st, (amount > max ? 1 : amount < min ? -1 : 0));
4865 }
4866 st->state = RUN;
4867 }
4868 return 0;
4869}
4870
4871/// Sets the value of a variable.
4872/// The value is converted to the type of the variable.
4873///
4874/// set(<variable>,<value>) -> <variable>
4875BUILDIN_FUNC(set)
4876{
4877 TBL_PC* sd = NULL;
4878 struct script_data* data;
4879 int num;
4880 const char* name;
4881 char prefix;
4882
4883 data = script_getdata(st,2);
4884 if( !data_isreference(data) )
4885 {
4886 ShowError("script:set: not a variable\n");
4887 script_reportdata(script_getdata(st,2));
4888 st->state = END;
4889 return 1;
4890 }
4891
4892 num = reference_getuid(data);
4893 name = reference_getname(data);
4894 prefix = *name;
4895
4896 if( not_server_variable(prefix) )
4897 {
4898 sd = script_rid2sd(st);
4899 if( sd == NULL )
4900 {
4901 ShowError("script:set: no player attached for player variable '%s'\n", name);
4902 return 0;
4903 }
4904 }
4905
4906 if( is_string_variable(name) )
4907 set_reg(st,sd,num,name,(void*)script_getstr(st,3),script_getref(st,2));
4908 else
4909 set_reg(st,sd,num,name,(void*)script_getnum(st,3),script_getref(st,2));
4910
4911 // return a copy of the variable reference
4912 script_pushcopy(st,2);
4913
4914 return 0;
4915}
4916
4917/////////////////////////////////////////////////////////////////////
4918/// Array variables
4919///
4920
4921/// Returns the size of the specified array
4922static int32 getarraysize(struct script_state* st, int32 id, int32 idx, int isstring, struct linkdb_node** ref)
4923{
4924 int32 ret = idx;
4925
4926 if( isstring )
4927 {
4928 for( ; idx < SCRIPT_MAX_ARRAYSIZE; ++idx )
4929 {
4930 char* str = (char*)get_val2(st, reference_uid(id, idx), ref);
4931 if( str && *str )
4932 ret = idx + 1;
4933 script_removetop(st, -1, 0);
4934 }
4935 }
4936 else
4937 {
4938 for( ; idx < SCRIPT_MAX_ARRAYSIZE; ++idx )
4939 {
4940 int32 num = (int32)get_val2(st, reference_uid(id, idx), ref);
4941 if( num )
4942 ret = idx + 1;
4943 script_removetop(st, -1, 0);
4944 }
4945 }
4946 return ret;
4947}
4948
4949/// Sets values of an array, from the starting index.
4950/// ex: setarray arr[1],1,2,3;
4951///
4952/// setarray <array variable>,<value1>{,<value2>...};
4953BUILDIN_FUNC(setarray)
4954{
4955 struct script_data* data;
4956 const char* name;
4957 int32 start;
4958 int32 end;
4959 int32 id;
4960 int32 i;
4961 TBL_PC* sd = NULL;
4962
4963 data = script_getdata(st, 2);
4964 if( !data_isreference(data) )
4965 {
4966 ShowError("script:setarray: not a variable\n");
4967 script_reportdata(data);
4968 st->state = END;
4969 return 1;// not a variable
4970 }
4971
4972 id = reference_getid(data);
4973 start = reference_getindex(data);
4974 name = reference_getname(data);
4975 if( not_array_variable(*name) )
4976 {
4977 ShowError("script:setarray: illegal scope\n");
4978 script_reportdata(data);
4979 st->state = END;
4980 return 1;// not supported
4981 }
4982
4983 if( not_server_variable(*name) )
4984 {
4985 sd = script_rid2sd(st);
4986 if( sd == NULL )
4987 return 0;// no player attached
4988 }
4989
4990 end = start + script_lastdata(st) - 2;
4991 if( end > SCRIPT_MAX_ARRAYSIZE )
4992 end = SCRIPT_MAX_ARRAYSIZE;
4993
4994 if( is_string_variable(name) )
4995 {// string array
4996 for( i = 3; start < end; ++start, ++i )
4997 set_reg(st, sd, reference_uid(id, start), name, (void*)script_getstr(st,i), reference_getref(data));
4998 }
4999 else
5000 {// int array
5001 for( i = 3; start < end; ++start, ++i )
5002 set_reg(st, sd, reference_uid(id, start), name, (void*)script_getnum(st,i), reference_getref(data));
5003 }
5004 return 0;
5005}
5006
5007/// Sets count values of an array, from the starting index.
5008/// ex: cleararray arr[0],0,1;
5009///
5010/// cleararray <array variable>,<value>,<count>;
5011BUILDIN_FUNC(cleararray)
5012{
5013 struct script_data* data;
5014 const char* name;
5015 int32 start;
5016 int32 end;
5017 int32 id;
5018 void* v;
5019 TBL_PC* sd = NULL;
5020
5021 data = script_getdata(st, 2);
5022 if( !data_isreference(data) )
5023 {
5024 ShowError("script:cleararray: not a variable\n");
5025 script_reportdata(data);
5026 st->state = END;
5027 return 1;// not a variable
5028 }
5029
5030 id = reference_getid(data);
5031 start = reference_getindex(data);
5032 name = reference_getname(data);
5033 if( not_array_variable(*name) )
5034 {
5035 ShowError("script:cleararray: illegal scope\n");
5036 script_reportdata(data);
5037 st->state = END;
5038 return 1;// not supported
5039 }
5040
5041 if( not_server_variable(*name) )
5042 {
5043 sd = script_rid2sd(st);
5044 if( sd == NULL )
5045 return 0;// no player attached
5046 }
5047
5048 if( is_string_variable(name) )
5049 v = (void*)script_getstr(st, 3);
5050 else
5051 v = (void*)script_getnum(st, 3);
5052
5053 end = start + script_getnum(st, 4);
5054 if( end > SCRIPT_MAX_ARRAYSIZE )
5055 end = SCRIPT_MAX_ARRAYSIZE;
5056
5057 for( ; start < end; ++start )
5058 set_reg(st, sd, reference_uid(id, start), name, v, script_getref(st,2));
5059 return 0;
5060}
5061
5062/// Copies data from one array to another.
5063/// ex: copyarray arr[0],arr[2],2;
5064///
5065/// copyarray <destination array variable>,<source array variable>,<count>;
5066BUILDIN_FUNC(copyarray)
5067{
5068 struct script_data* data1;
5069 struct script_data* data2;
5070 const char* name1;
5071 const char* name2;
5072 int32 idx1;
5073 int32 idx2;
5074 int32 id1;
5075 int32 id2;
5076 void* v;
5077 int32 i;
5078 int32 count;
5079 TBL_PC* sd = NULL;
5080
5081 data1 = script_getdata(st, 2);
5082 data2 = script_getdata(st, 3);
5083 if( !data_isreference(data1) || !data_isreference(data2) )
5084 {
5085 ShowError("script:copyarray: not a variable\n");
5086 script_reportdata(data1);
5087 script_reportdata(data2);
5088 st->state = END;
5089 return 1;// not a variable
5090 }
5091
5092 id1 = reference_getid(data1);
5093 id2 = reference_getid(data2);
5094 idx1 = reference_getindex(data1);
5095 idx2 = reference_getindex(data2);
5096 name1 = reference_getname(data1);
5097 name2 = reference_getname(data2);
5098 if( not_array_variable(*name1) || not_array_variable(*name2) )
5099 {
5100 ShowError("script:copyarray: illegal scope\n");
5101 script_reportdata(data1);
5102 script_reportdata(data2);
5103 st->state = END;
5104 return 1;// not supported
5105 }
5106
5107 if( is_string_variable(name1) != is_string_variable(name2) )
5108 {
5109 ShowError("script:copyarray: type mismatch\n");
5110 script_reportdata(data1);
5111 script_reportdata(data2);
5112 st->state = END;
5113 return 1;// data type mismatch
5114 }
5115
5116 if( not_server_variable(*name1) || not_server_variable(*name2) )
5117 {
5118 sd = script_rid2sd(st);
5119 if( sd == NULL )
5120 return 0;// no player attached
5121 }
5122
5123 count = script_getnum(st, 4);
5124 if( count > SCRIPT_MAX_ARRAYSIZE - idx1 )
5125 count = SCRIPT_MAX_ARRAYSIZE - idx1;
5126 if( count <= 0 || (id1 == id2 && idx1 == idx2) )
5127 return 0;// nothing to copy
5128
5129 if( id1 == id2 && idx1 > idx2 )
5130 {// destination might be overlapping the source - copy in reverse order
5131 for( i = count - 1; i >= 0; --i )
5132 {
5133 v = get_val2(st, reference_uid(id2, idx2 + i), reference_getref(data2));
5134 set_reg(st, sd, reference_uid(id1, idx1 + i), name1, v, reference_getref(data1));
5135 script_removetop(st, -1, 0);
5136 }
5137 }
5138 else
5139 {// normal copy
5140 for( i = 0; i < count; ++i )
5141 {
5142 if( idx2 + i < SCRIPT_MAX_ARRAYSIZE )
5143 {
5144 v = get_val2(st, reference_uid(id2, idx2 + i), reference_getref(data2));
5145 set_reg(st, sd, reference_uid(id1, idx1 + i), name1, v, reference_getref(data1));
5146 script_removetop(st, -1, 0);
5147 }
5148 else// out of range - assume ""/0
5149 set_reg(st, sd, reference_uid(id1, idx1 + i), name1, (is_string_variable(name1)?(void*)"":(void*)0), reference_getref(data1));
5150 }
5151 }
5152 return 0;
5153}
5154
5155/// Returns the size of the array.
5156/// Assumes that everything before the starting index exists.
5157/// ex: getarraysize(arr[3])
5158///
5159/// getarraysize(<array variable>) -> <int>
5160BUILDIN_FUNC(getarraysize)
5161{
5162 struct script_data* data;
5163 const char* name;
5164
5165 data = script_getdata(st, 2);
5166 if( !data_isreference(data) )
5167 {
5168 ShowError("script:getarraysize: not a variable\n");
5169 script_reportdata(data);
5170 script_pushnil(st);
5171 st->state = END;
5172 return 1;// not a variable
5173 }
5174
5175 name = reference_getname(data);
5176 if( not_array_variable(*name) )
5177 {
5178 ShowError("script:getarraysize: illegal scope\n");
5179 script_reportdata(data);
5180 script_pushnil(st);
5181 st->state = END;
5182 return 1;// not supported
5183 }
5184
5185 script_pushint(st, getarraysize(st, reference_getid(data), reference_getindex(data), is_string_variable(name), reference_getref(data)));
5186 return 0;
5187}
5188
5189/// Deletes count or all the elements in an array, from the starting index.
5190/// ex: deletearray arr[4],2;
5191///
5192/// deletearray <array variable>;
5193/// deletearray <array variable>,<count>;
5194BUILDIN_FUNC(deletearray)
5195{
5196 struct script_data* data;
5197 const char* name;
5198 int start;
5199 int end;
5200 int id;
5201 TBL_PC *sd = NULL;
5202
5203 data = script_getdata(st, 2);
5204 if( !data_isreference(data) )
5205 {
5206 ShowError("script:deletearray: not a variable\n");
5207 script_reportdata(data);
5208 st->state = END;
5209 return 1;// not a variable
5210 }
5211
5212 id = reference_getid(data);
5213 start = reference_getindex(data);
5214 name = reference_getname(data);
5215 if( not_array_variable(*name) )
5216 {
5217 ShowError("script:deletearray: illegal scope\n");
5218 script_reportdata(data);
5219 st->state = END;
5220 return 1;// not supported
5221 }
5222
5223 if( not_server_variable(*name) )
5224 {
5225 sd = script_rid2sd(st);
5226 if( sd == NULL )
5227 return 0;// no player attached
5228 }
5229
5230 end = SCRIPT_MAX_ARRAYSIZE;
5231
5232 if( start >= end )
5233 return 0;// nothing to free
5234
5235 if( script_hasdata(st,3) )
5236 {
5237 int count = script_getnum(st, 3);
5238 if( count > end - start )
5239 count = end - start;
5240 if( count <= 0 )
5241 return 0;// nothing to free
5242
5243 // move rest of the elements backward
5244 for( ; start + count < end; ++start )
5245 {
5246 void* v = get_val2(st, reference_uid(id, start + count), reference_getref(data));
5247 set_reg(st, sd, reference_uid(id, start), name, v, reference_getref(data));
5248 script_removetop(st, -1, 0);
5249 }
5250 }
5251
5252 // clear the rest of the array
5253 if( is_string_variable(name) )
5254 {
5255 for( ; start < end; ++start )
5256 set_reg(st, sd, reference_uid(id, start), name, (void *)"", reference_getref(data));
5257 }
5258 else
5259 {
5260 for( ; start < end; ++start )
5261 set_reg(st, sd, reference_uid(id, start), name, (void*)0, reference_getref(data));
5262 }
5263 return 0;
5264}
5265
5266/// Returns a reference to the target index of the array variable.
5267/// Equivalent to var[index].
5268///
5269/// getelementofarray(<array variable>,<index>) -> <variable reference>
5270BUILDIN_FUNC(getelementofarray)
5271{
5272 struct script_data* data;
5273 const char* name;
5274 int32 id;
5275 int i;
5276
5277 data = script_getdata(st, 2);
5278 if( !data_isreference(data) )
5279 {
5280 ShowError("script:getelementofarray: not a variable\n");
5281 script_reportdata(data);
5282 script_pushnil(st);
5283 st->state = END;
5284 return 1;// not a variable
5285 }
5286
5287 id = reference_getid(data);
5288 name = reference_getname(data);
5289 if( not_array_variable(*name) )
5290 {
5291 ShowError("script:getelementofarray: illegal scope\n");
5292 script_reportdata(data);
5293 script_pushnil(st);
5294 st->state = END;
5295 return 1;// not supported
5296 }
5297
5298 i = script_getnum(st, 3);
5299 if( i < 0 || i >= SCRIPT_MAX_ARRAYSIZE )
5300 {
5301 ShowWarning("script:getelementofarray: index out of range (%d)\n", i);
5302 script_reportdata(data);
5303 script_pushnil(st);
5304 st->state = END;
5305 return 1;// out of range
5306 }
5307
5308 push_val2(st->stack, C_NAME, reference_uid(id, i), reference_getref(data));
5309 return 0;
5310}
5311
5312/////////////////////////////////////////////////////////////////////
5313/// ...
5314///
5315
5316/*==========================================
5317 *
5318 *------------------------------------------*/
5319BUILDIN_FUNC(setlook)
5320{
5321 int type,val;
5322 TBL_PC* sd;
5323
5324 type=script_getnum(st,2);
5325 val=script_getnum(st,3);
5326
5327 sd = script_rid2sd(st);
5328 if( sd == NULL )
5329 return 0;
5330
5331 pc_changelook(sd,type,val);
5332
5333 return 0;
5334}
5335
5336BUILDIN_FUNC(changelook)
5337{ // As setlook but only client side
5338 int type,val;
5339 TBL_PC* sd;
5340
5341 type=script_getnum(st,2);
5342 val=script_getnum(st,3);
5343
5344 sd = script_rid2sd(st);
5345 if( sd == NULL )
5346 return 0;
5347
5348 clif_changelook(&sd->bl,type,val);
5349
5350 return 0;
5351}
5352
5353/*==========================================
5354 *
5355 *------------------------------------------*/
5356BUILDIN_FUNC(cutin)
5357{
5358 TBL_PC* sd;
5359
5360 sd = script_rid2sd(st);
5361 if( sd == NULL )
5362 return 0;
5363
5364 clif_cutin(sd,script_getstr(st,2),script_getnum(st,3));
5365 return 0;
5366}
5367
5368/*==========================================
5369 *
5370 *------------------------------------------*/
5371BUILDIN_FUNC(viewpoint)
5372{
5373 int type,x,y,id,color;
5374 TBL_PC* sd;
5375
5376 type=script_getnum(st,2);
5377 x=script_getnum(st,3);
5378 y=script_getnum(st,4);
5379 id=script_getnum(st,5);
5380 color=script_getnum(st,6);
5381
5382 sd = script_rid2sd(st);
5383 if( sd == NULL )
5384 return 0;
5385
5386 clif_viewpoint(sd,st->oid,type,x,y,id,color);
5387
5388 return 0;
5389}
5390
5391/*==========================================
5392 *
5393 *------------------------------------------*/
5394BUILDIN_FUNC(countitem)
5395{
5396 int nameid, i;
5397 int count = 0;
5398 struct item_data* id = NULL;
5399 struct script_data* data;
5400
5401 TBL_PC* sd = script_rid2sd(st);
5402 if (!sd) {
5403 script_pushint(st,0);
5404 return 0;
5405 }
5406
5407 data = script_getdata(st,2);
5408 get_val(st, data); // convert into value in case of a variable
5409
5410 if( data_isstring(data) )
5411 {// item name
5412 id = itemdb_searchname(conv_str(st, data));
5413 }
5414 else
5415 {// item id
5416 id = itemdb_exists(conv_num(st, data));
5417 }
5418
5419 if( id == NULL )
5420 {
5421 ShowError("buildin_countitem: Invalid item '%s'.\n", script_getstr(st,2)); // returns string, regardless of what it was
5422 script_pushint(st,0);
5423 return 1;
5424 }
5425
5426 nameid = id->nameid;
5427
5428 for(i = 0; i < MAX_INVENTORY; i++)
5429 if(sd->status.inventory[i].nameid == nameid)
5430 count += sd->status.inventory[i].amount;
5431
5432 script_pushint(st,count);
5433 return 0;
5434}
5435
5436/*==========================================
5437 * countitem2(nameID,Identified,Refine,Attribute,Card0,Card1,Card2,Card3) [Lupus]
5438 * returns number of items that meet the conditions
5439 *------------------------------------------*/
5440BUILDIN_FUNC(countitem2)
5441{
5442 int nameid, iden, ref, attr, c1, c2, c3, c4;
5443 int count = 0;
5444 int i;
5445 struct item_data* id = NULL;
5446 struct script_data* data;
5447
5448 TBL_PC* sd = script_rid2sd(st);
5449 if (!sd) {
5450 script_pushint(st,0);
5451 return 0;
5452 }
5453
5454 data = script_getdata(st,2);
5455 get_val(st, data); // convert into value in case of a variable
5456
5457 if( data_isstring(data) )
5458 {// item name
5459 id = itemdb_searchname(conv_str(st, data));
5460 }
5461 else
5462 {// item id
5463 id = itemdb_exists(conv_num(st, data));
5464 }
5465
5466 if( id == NULL )
5467 {
5468 ShowError("buildin_countitem2: Invalid item '%s'.\n", script_getstr(st,2)); // returns string, regardless of what it was
5469 script_pushint(st,0);
5470 return 1;
5471 }
5472
5473 nameid = id->nameid;
5474 iden = script_getnum(st,3);
5475 ref = script_getnum(st,4);
5476 attr = script_getnum(st,5);
5477 c1 = (short)script_getnum(st,6);
5478 c2 = (short)script_getnum(st,7);
5479 c3 = (short)script_getnum(st,8);
5480 c4 = (short)script_getnum(st,9);
5481
5482 for(i = 0; i < MAX_INVENTORY; i++)
5483 if (sd->status.inventory[i].nameid > 0 && sd->inventory_data[i] != NULL &&
5484 sd->status.inventory[i].amount > 0 && sd->status.inventory[i].nameid == nameid &&
5485 sd->status.inventory[i].identify == iden && sd->status.inventory[i].refine == ref &&
5486 sd->status.inventory[i].attribute == attr && sd->status.inventory[i].card[0] == c1 &&
5487 sd->status.inventory[i].card[1] == c2 && sd->status.inventory[i].card[2] == c3 &&
5488 sd->status.inventory[i].card[3] == c4
5489 )
5490 count += sd->status.inventory[i].amount;
5491
5492 script_pushint(st,count);
5493 return 0;
5494}
5495
5496/*==========================================
5497 * Âd—ʃ`Æ’FÆ’bÆ’N
5498 *------------------------------------------*/
5499BUILDIN_FUNC(checkweight)
5500{
5501 int nameid, amount, slots;
5502 unsigned int weight;
5503 struct item_data* id = NULL;
5504 struct map_session_data* sd;
5505 struct script_data* data;
5506
5507 if( ( sd = script_rid2sd(st) ) == NULL )
5508 {
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_checkweight: 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 amount = script_getnum(st,3);
5533
5534 if( amount < 1 )
5535 {
5536 ShowError("buildin_checkweight: Invalid amount '%d'.\n", amount);
5537 script_pushint(st,0);
5538 return 1;
5539 }
5540
5541 weight = itemdb_weight(nameid)*amount;
5542
5543 if( weight + sd->weight > sd->max_weight )
5544 {// too heavy
5545 script_pushint(st,0);
5546 return 0;
5547 }
5548
5549 switch( pc_checkadditem(sd, nameid, amount) )
5550 {
5551 case ADDITEM_EXIST:
5552 // item is already in inventory, but there is still space for the requested amount
5553 break;
5554 case ADDITEM_NEW:
5555 slots = pc_inventoryblank(sd);
5556
5557 if( itemdb_isstackable(nameid) )
5558 {// stackable
5559 if( slots < 1 )
5560 {
5561 script_pushint(st,0);
5562 return 0;
5563 }
5564 }
5565 else
5566 {// non-stackable
5567 if( slots < amount )
5568 {
5569 script_pushint(st,0);
5570 return 0;
5571 }
5572 }
5573 break;
5574 case ADDITEM_OVERAMOUNT:
5575 script_pushint(st,0);
5576 return 0;
5577 }
5578
5579 script_pushint(st,1);
5580 return 0;
5581}
5582
5583/*==========================================
5584 * getitem <item id>,<amount>{,<account ID>};
5585 * getitem "<item name>",<amount>{,<account ID>};
5586 *------------------------------------------*/
5587BUILDIN_FUNC(getitem)
5588{
5589 int nameid,amount,get_count,i,flag = 0;
5590 struct item it;
5591 TBL_PC *sd;
5592 struct script_data *data;
5593
5594 data=script_getdata(st,2);
5595 get_val(st,data);
5596 if( data_isstring(data) )
5597 {// "<item name>"
5598 const char *name=conv_str(st,data);
5599 struct item_data *item_data = itemdb_searchname(name);
5600 if( item_data == NULL ){
5601 ShowError("buildin_getitem: Nonexistant item %s requested.\n", name);
5602 return 1; //No item created.
5603 }
5604 nameid=item_data->nameid;
5605 } else if( data_isint(data) )
5606 {// <item id>
5607 nameid=conv_num(st,data);
5608 //Violet Box, Blue Box, etc - random item pick
5609 if( nameid < 0 ) {
5610 nameid=itemdb_searchrandomid(-nameid);
5611 flag = 1;
5612 }
5613 if( nameid <= 0 || !itemdb_exists(nameid) ){
5614 ShowError("buildin_getitem: Nonexistant item %d requested.\n", nameid);
5615 return 1; //No item created.
5616 }
5617 } else {
5618 ShowError("buildin_getitem: invalid data type for argument #1 (%d).", data->type);
5619 return 1;
5620 }
5621
5622 // <amount>
5623 if( (amount=script_getnum(st,3)) <= 0)
5624 return 0; //return if amount <=0, skip the useles iteration
5625
5626 memset(&it,0,sizeof(it));
5627 it.nameid=nameid;
5628 if(!flag)
5629 it.identify=1;
5630 else
5631 it.identify=itemdb_isidentified(nameid);
5632
5633 if( script_hasdata(st,4) )
5634 sd=map_id2sd(script_getnum(st,4)); // <Account ID>
5635 else
5636 sd=script_rid2sd(st); // Attached player
5637
5638 if( sd == NULL ) // no target
5639 return 0;
5640
5641 //Check if it's stackable.
5642 if (!itemdb_isstackable(nameid))
5643 get_count = 1;
5644 else
5645 get_count = amount;
5646
5647 for (i = 0; i < amount; i += get_count)
5648 {
5649 // if not pet egg
5650 if (!pet_create_egg(sd, nameid))
5651 {
5652 if ((flag = pc_additem(sd, &it, get_count)))
5653 {
5654 clif_additem(sd, 0, 0, flag);
5655 if( pc_candrop(sd,&it) )
5656 map_addflooritem(&it,get_count,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0);
5657 }
5658 }
5659 }
5660
5661 //Logs items, got from (N)PC scripts [Lupus]
5662 log_pick(&sd->bl, LOG_TYPE_SCRIPT, nameid, amount, NULL);
5663
5664 return 0;
5665}
5666
5667/*==========================================
5668 *
5669 *------------------------------------------*/
5670BUILDIN_FUNC(getitem2)
5671{
5672 int nameid,amount,get_count,i,flag = 0;
5673 int iden,ref,attr,c1,c2,c3,c4;
5674 struct item_data *item_data;
5675 struct item item_tmp;
5676 TBL_PC *sd;
5677 struct script_data *data;
5678
5679 if( script_hasdata(st,11) )
5680 sd=map_id2sd(script_getnum(st,11)); // <Account ID>
5681 else
5682 sd=script_rid2sd(st); // Attached player
5683
5684 if( sd == NULL ) // no target
5685 return 0;
5686
5687 data=script_getdata(st,2);
5688 get_val(st,data);
5689 if( data_isstring(data) ){
5690 const char *name=conv_str(st,data);
5691 struct item_data *item_data = itemdb_searchname(name);
5692 if( item_data )
5693 nameid=item_data->nameid;
5694 else
5695 nameid=UNKNOWN_ITEM_ID;
5696 }else
5697 nameid=conv_num(st,data);
5698
5699 amount=script_getnum(st,3);
5700 iden=script_getnum(st,4);
5701 ref=script_getnum(st,5);
5702 attr=script_getnum(st,6);
5703 c1=(short)script_getnum(st,7);
5704 c2=(short)script_getnum(st,8);
5705 c3=(short)script_getnum(st,9);
5706 c4=(short)script_getnum(st,10);
5707
5708 if(nameid<0) { // ƒ‰ƒ“ƒ_ƒ€
5709 nameid=itemdb_searchrandomid(-nameid);
5710 flag = 1;
5711 }
5712
5713 if(nameid > 0) {
5714 memset(&item_tmp,0,sizeof(item_tmp));
5715 item_data=itemdb_exists(nameid);
5716 if (item_data == NULL)
5717 return -1;
5718 if(item_data->type==IT_WEAPON || item_data->type==IT_ARMOR){
5719 if(ref > MAX_REFINE) ref = MAX_REFINE;
5720 }
5721 else if(item_data->type==IT_PETEGG) {
5722 iden = 1;
5723 ref = 0;
5724 }
5725 else {
5726 iden = 1;
5727 ref = attr = 0;
5728 }
5729
5730 item_tmp.nameid=nameid;
5731 if(!flag)
5732 item_tmp.identify=iden;
5733 else if(item_data->type==IT_WEAPON || item_data->type==IT_ARMOR)
5734 item_tmp.identify=0;
5735 item_tmp.refine=ref;
5736 item_tmp.attribute=attr;
5737 item_tmp.card[0]=(short)c1;
5738 item_tmp.card[1]=(short)c2;
5739 item_tmp.card[2]=(short)c3;
5740 item_tmp.card[3]=(short)c4;
5741
5742 //Check if it's stackable.
5743 if (!itemdb_isstackable(nameid))
5744 get_count = 1;
5745 else
5746 get_count = amount;
5747
5748 for (i = 0; i < amount; i += get_count)
5749 {
5750 // if not pet egg
5751 if (!pet_create_egg(sd, nameid))
5752 {
5753 if ((flag = pc_additem(sd, &item_tmp, get_count)))
5754 {
5755 clif_additem(sd, 0, 0, flag);
5756 if( pc_candrop(sd,&item_tmp) )
5757 map_addflooritem(&item_tmp,get_count,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0);
5758 }
5759 }
5760 }
5761
5762 //Logs items, got from (N)PC scripts [Lupus]
5763 log_pick(&sd->bl, LOG_TYPE_SCRIPT, nameid, amount, &item_tmp);
5764 }
5765
5766 return 0;
5767}
5768
5769/*==========================================
5770 * rentitem <item id>,<seconds>
5771 * rentitem "<item name>",<seconds>
5772 *------------------------------------------*/
5773BUILDIN_FUNC(rentitem)
5774{
5775 struct map_session_data *sd;
5776 struct script_data *data;
5777 struct item it;
5778 int seconds;
5779 int nameid = 0, flag;
5780
5781 data = script_getdata(st,2);
5782 get_val(st,data);
5783
5784 if( (sd = script_rid2sd(st)) == NULL )
5785 return 0;
5786
5787 if( data_isstring(data) )
5788 {
5789 const char *name = conv_str(st,data);
5790 struct item_data *itd = itemdb_searchname(name);
5791 if( itd == NULL )
5792 {
5793 ShowError("buildin_rentitem: Nonexistant item %s requested.\n", name);
5794 return 1;
5795 }
5796 nameid = itd->nameid;
5797 }
5798 else if( data_isint(data) )
5799 {
5800 nameid = conv_num(st,data);
5801 if( nameid <= 0 || !itemdb_exists(nameid) )
5802 {
5803 ShowError("buildin_rentitem: Nonexistant item %d requested.\n", nameid);
5804 return 1;
5805 }
5806 }
5807 else
5808 {
5809 ShowError("buildin_rentitem: invalid data type for argument #1 (%d).\n", data->type);
5810 return 1;
5811 }
5812
5813 seconds = script_getnum(st,3);
5814 memset(&it, 0, sizeof(it));
5815 it.nameid = nameid;
5816 it.identify = 1;
5817 it.expire_time = (unsigned int)(time(NULL) + seconds);
5818
5819 if( (flag = pc_additem(sd, &it, 1)) )
5820 {
5821 clif_additem(sd, 0, 0, flag);
5822 return 1;
5823 }
5824
5825 clif_rental_time(sd->fd, nameid, seconds);
5826 pc_inventory_rental_add(sd, seconds);
5827
5828 log_pick(&sd->bl, LOG_TYPE_SCRIPT, nameid, 1, NULL);
5829
5830 return 0;
5831}
5832
5833/*==========================================
5834 * gets an item with someone's name inscribed [Skotlex]
5835 * getinscribeditem item_num, character_name
5836 * Returned Qty is always 1, only works on equip-able
5837 * equipment
5838 *------------------------------------------*/
5839BUILDIN_FUNC(getnameditem)
5840{
5841 int nameid;
5842 struct item item_tmp;
5843 TBL_PC *sd, *tsd;
5844 struct script_data *data;
5845
5846 sd = script_rid2sd(st);
5847 if (sd == NULL)
5848 { //Player not attached!
5849 script_pushint(st,0);
5850 return 0;
5851 }
5852
5853 data=script_getdata(st,2);
5854 get_val(st,data);
5855 if( data_isstring(data) ){
5856 const char *name=conv_str(st,data);
5857 struct item_data *item_data = itemdb_searchname(name);
5858 if( item_data == NULL)
5859 { //Failed
5860 script_pushint(st,0);
5861 return 0;
5862 }
5863 nameid = item_data->nameid;
5864 }else
5865 nameid = conv_num(st,data);
5866
5867 if(!itemdb_exists(nameid)/* || itemdb_isstackable(nameid)*/)
5868 { //Even though named stackable items "could" be risky, they are required for certain quests.
5869 script_pushint(st,0);
5870 return 0;
5871 }
5872
5873 data=script_getdata(st,3);
5874 get_val(st,data);
5875 if( data_isstring(data) ) //Char Name
5876 tsd=map_nick2sd(conv_str(st,data));
5877 else //Char Id was given
5878 tsd=map_charid2sd(conv_num(st,data));
5879
5880 if( tsd == NULL )
5881 { //Failed
5882 script_pushint(st,0);
5883 return 0;
5884 }
5885
5886 memset(&item_tmp,0,sizeof(item_tmp));
5887 item_tmp.nameid=nameid;
5888 item_tmp.amount=1;
5889 item_tmp.identify=1;
5890 item_tmp.card[0]=CARD0_CREATE; //we don't use 255! because for example SIGNED WEAPON shouldn't get TOP10 BS Fame bonus [Lupus]
5891 item_tmp.card[2]=tsd->status.char_id;
5892 item_tmp.card[3]=tsd->status.char_id >> 16;
5893 if(pc_additem(sd,&item_tmp,1)) {
5894 script_pushint(st,0);
5895 return 0; //Failed to add item, we will not drop if they don't fit
5896 }
5897
5898 //Logs items, got from (N)PC scripts [Lupus]
5899 log_pick(&sd->bl, LOG_TYPE_SCRIPT, item_tmp.nameid, item_tmp.amount, &item_tmp);
5900
5901 script_pushint(st,1);
5902 return 0;
5903}
5904
5905/*==========================================
5906 * gets a random item ID from an item group [Skotlex]
5907 * groupranditem group_num
5908 *------------------------------------------*/
5909BUILDIN_FUNC(grouprandomitem)
5910{
5911 int group;
5912
5913 group = script_getnum(st,2);
5914 script_pushint(st,itemdb_searchrandomid(group));
5915 return 0;
5916}
5917
5918/*==========================================
5919 *
5920 *------------------------------------------*/
5921BUILDIN_FUNC(makeitem)
5922{
5923 int nameid,amount,flag = 0;
5924 int x,y,m;
5925 const char *mapname;
5926 struct item item_tmp;
5927 struct script_data *data;
5928
5929 data=script_getdata(st,2);
5930 get_val(st,data);
5931 if( data_isstring(data) ){
5932 const char *name=conv_str(st,data);
5933 struct item_data *item_data = itemdb_searchname(name);
5934 if( item_data )
5935 nameid=item_data->nameid;
5936 else
5937 nameid=UNKNOWN_ITEM_ID;
5938 }else
5939 nameid=conv_num(st,data);
5940
5941 amount=script_getnum(st,3);
5942 mapname =script_getstr(st,4);
5943 x =script_getnum(st,5);
5944 y =script_getnum(st,6);
5945
5946 if(strcmp(mapname,"this")==0)
5947 {
5948 TBL_PC *sd;
5949 sd = script_rid2sd(st);
5950 if (!sd) return 0; //Failed...
5951 m=sd->bl.m;
5952 } else
5953 m=map_mapname2mapid(mapname);
5954
5955 if(nameid<0) { // ƒ‰ƒ“ƒ_ƒ€
5956 nameid=itemdb_searchrandomid(-nameid);
5957 flag = 1;
5958 }
5959
5960 if(nameid > 0) {
5961 memset(&item_tmp,0,sizeof(item_tmp));
5962 item_tmp.nameid=nameid;
5963 if(!flag)
5964 item_tmp.identify=1;
5965 else
5966 item_tmp.identify=itemdb_isidentified(nameid);
5967
5968 map_addflooritem(&item_tmp,amount,m,x,y,0,0,0,0);
5969 }
5970
5971 return 0;
5972}
5973
5974
5975/// Counts / deletes the current item given by idx.
5976/// Used by buildin_delitem_search
5977/// Relies on all input data being already fully valid.
5978static void buildin_delitem_delete(struct map_session_data* sd, int idx, int* amount, bool delete_items)
5979{
5980 int delamount;
5981 struct item* inv = &sd->status.inventory[idx];
5982
5983 delamount = ( amount[0] < inv->amount ) ? amount[0] : inv->amount;
5984
5985 if( delete_items )
5986 {
5987 if( sd->inventory_data[idx]->type == IT_PETEGG && inv->card[0] == CARD0_PET )
5988 {// delete associated pet
5989 intif_delete_petdata(MakeDWord(inv->card[1], inv->card[2]));
5990 }
5991
5992 //Logs items, got from (N)PC scripts [Lupus]
5993 log_pick(&sd->bl, LOG_TYPE_SCRIPT, inv->nameid, -delamount, inv);
5994 //Logs
5995
5996 pc_delitem(sd, idx, delamount, 0, 0);
5997 }
5998
5999 amount[0]-= delamount;
6000}
6001
6002
6003/// Searches for item(s) and checks, if there is enough of them.
6004/// Used by delitem and delitem2
6005/// Relies on all input data being already fully valid.
6006/// @param exact_match will also match item attributes and cards, not just name id
6007/// @return true when all items could be deleted, false when there were not enough items to delete
6008static bool buildin_delitem_search(struct map_session_data* sd, struct item* it, bool exact_match)
6009{
6010 bool delete_items = false;
6011 int i, amount, important;
6012 struct item* inv;
6013
6014 // prefer always non-equipped items
6015 it->equip = 0;
6016
6017 // when searching for nameid only, prefer additionally
6018 if( !exact_match )
6019 {
6020 // non-refined items
6021 it->refine = 0;
6022 // card-less items
6023 memset(it->card, 0, sizeof(it->card));
6024 }
6025
6026 for(;;)
6027 {
6028 amount = it->amount;
6029 important = 0;
6030
6031 // 1st pass -- less important items / exact match
6032 for( i = 0; amount && i < ARRAYLENGTH(sd->status.inventory); i++ )
6033 {
6034 inv = &sd->status.inventory[i];
6035
6036 if( !inv->nameid || !sd->inventory_data[i] || inv->nameid != it->nameid )
6037 {// wrong/invalid item
6038 continue;
6039 }
6040
6041 if( inv->equip != it->equip || inv->refine != it->refine )
6042 {// not matching attributes
6043 important++;
6044 continue;
6045 }
6046
6047 if( exact_match )
6048 {
6049 if( inv->identify != it->identify || inv->attribute != it->attribute || memcmp(inv->card, it->card, sizeof(inv->card)) )
6050 {// not matching exact attributes
6051 continue;
6052 }
6053 }
6054 else
6055 {
6056 if( sd->inventory_data[i]->type == IT_PETEGG )
6057 {
6058 if( inv->card[0] == CARD0_PET && CheckForCharServer() )
6059 {// pet which cannot be deleted
6060 continue;
6061 }
6062 }
6063 else if( memcmp(inv->card, it->card, sizeof(inv->card)) )
6064 {// named/carded item
6065 important++;
6066 continue;
6067 }
6068 }
6069
6070 // count / delete item
6071 buildin_delitem_delete(sd, i, &amount, delete_items);
6072 }
6073
6074 // 2nd pass -- any matching item
6075 if( amount == 0 || important == 0 )
6076 {// either everything was already consumed or no items were skipped
6077 ;
6078 }
6079 else for( i = 0; amount && i < ARRAYLENGTH(sd->status.inventory); i++ )
6080 {
6081 inv = &sd->status.inventory[i];
6082
6083 if( !inv->nameid || !sd->inventory_data[i] || inv->nameid != it->nameid )
6084 {// wrong/invalid item
6085 continue;
6086 }
6087
6088 if( sd->inventory_data[i]->type == IT_PETEGG && inv->card[0] == CARD0_PET && CheckForCharServer() )
6089 {// pet which cannot be deleted
6090 continue;
6091 }
6092
6093 if( exact_match )
6094 {
6095 if( inv->refine != it->refine || inv->identify != it->identify || inv->attribute != it->attribute || memcmp(inv->card, it->card, sizeof(inv->card)) )
6096 {// not matching attributes
6097 continue;
6098 }
6099 }
6100
6101 // count / delete item
6102 buildin_delitem_delete(sd, i, &amount, delete_items);
6103 }
6104
6105 if( amount )
6106 {// not enough items
6107 return false;
6108 }
6109 else if( delete_items )
6110 {// we are done with the work
6111 return true;
6112 }
6113 else
6114 {// get rid of the items now
6115 delete_items = true;
6116 }
6117 }
6118}
6119
6120
6121/// Deletes items from the target/attached player.
6122/// Prioritizes ordinary items.
6123///
6124/// delitem <item id>,<amount>{,<account id>}
6125/// delitem "<item name>",<amount>{,<account id>}
6126BUILDIN_FUNC(delitem)
6127{
6128 TBL_PC *sd;
6129 struct item it;
6130 struct script_data *data;
6131
6132 if( script_hasdata(st,4) )
6133 {
6134 int account_id = script_getnum(st,4);
6135 sd = map_id2sd(account_id); // <account id>
6136 if( sd == NULL )
6137 {
6138 ShowError("script:delitem: player not found (AID=%d).\n", account_id);
6139 st->state = END;
6140 return 1;
6141 }
6142 }
6143 else
6144 {
6145 sd = script_rid2sd(st);// attached player
6146 if( sd == NULL )
6147 return 0;
6148 }
6149
6150 data = script_getdata(st,2);
6151 get_val(st,data);
6152 if( data_isstring(data) )
6153 {
6154 const char* item_name = conv_str(st,data);
6155 struct item_data* id = itemdb_searchname(item_name);
6156 if( id == NULL )
6157 {
6158 ShowError("script:delitem: unknown item \"%s\".\n", item_name);
6159 st->state = END;
6160 return 1;
6161 }
6162 it.nameid = id->nameid;// "<item name>"
6163 }
6164 else
6165 {
6166 it.nameid = conv_num(st,data);// <item id>
6167 if( !itemdb_exists( it.nameid ) )
6168 {
6169 ShowError("script:delitem: unknown item \"%d\".\n", it.nameid);
6170 st->state = END;
6171 return 1;
6172 }
6173 }
6174
6175 it.amount=script_getnum(st,3);
6176
6177 if( it.amount <= 0 )
6178 return 0;// nothing to do
6179
6180 if( buildin_delitem_search(sd, &it, false) )
6181 {// success
6182 return 0;
6183 }
6184
6185 ShowError("script:delitem: failed to delete %d items (AID=%d item_id=%d).\n", it.amount, sd->status.account_id, it.nameid);
6186 st->state = END;
6187 clif_scriptclose(sd, st->oid);
6188 return 1;
6189}
6190
6191/// Deletes items from the target/attached player.
6192///
6193/// delitem2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
6194/// delitem2 "<Item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
6195BUILDIN_FUNC(delitem2)
6196{
6197 TBL_PC *sd;
6198 struct item it;
6199 struct script_data *data;
6200
6201 if( script_hasdata(st,11) )
6202 {
6203 int account_id = script_getnum(st,11);
6204 sd = map_id2sd(account_id); // <account id>
6205 if( sd == NULL )
6206 {
6207 ShowError("script:delitem2: player not found (AID=%d).\n", account_id);
6208 st->state = END;
6209 return 1;
6210 }
6211 }
6212 else
6213 {
6214 sd = script_rid2sd(st);// attached player
6215 if( sd == NULL )
6216 return 0;
6217 }
6218
6219 data = script_getdata(st,2);
6220 get_val(st,data);
6221 if( data_isstring(data) )
6222 {
6223 const char* item_name = conv_str(st,data);
6224 struct item_data* id = itemdb_searchname(item_name);
6225 if( id == NULL )
6226 {
6227 ShowError("script:delitem2: unknown item \"%s\".\n", item_name);
6228 st->state = END;
6229 return 1;
6230 }
6231 it.nameid = id->nameid;// "<item name>"
6232 }
6233 else
6234 {
6235 it.nameid = conv_num(st,data);// <item id>
6236 if( !itemdb_exists( it.nameid ) )
6237 {
6238 ShowError("script:delitem: unknown item \"%d\".\n", it.nameid);
6239 st->state = END;
6240 return 1;
6241 }
6242 }
6243
6244 it.amount=script_getnum(st,3);
6245 it.identify=script_getnum(st,4);
6246 it.refine=script_getnum(st,5);
6247 it.attribute=script_getnum(st,6);
6248 it.card[0]=(short)script_getnum(st,7);
6249 it.card[1]=(short)script_getnum(st,8);
6250 it.card[2]=(short)script_getnum(st,9);
6251 it.card[3]=(short)script_getnum(st,10);
6252
6253 if( it.amount <= 0 )
6254 return 0;// nothing to do
6255
6256 if( buildin_delitem_search(sd, &it, true) )
6257 {// success
6258 return 0;
6259 }
6260
6261 ShowError("script:delitem2: failed to delete %d items (AID=%d item_id=%d).\n", it.amount, sd->status.account_id, it.nameid);
6262 st->state = END;
6263 clif_scriptclose(sd, st->oid);
6264 return 1;
6265}
6266
6267/*==========================================
6268 * Enables/Disables use of items while in an NPC [Skotlex]
6269 *------------------------------------------*/
6270BUILDIN_FUNC(enableitemuse)
6271{
6272 TBL_PC *sd;
6273 sd=script_rid2sd(st);
6274 if (sd)
6275 sd->npc_item_flag = st->oid;
6276 return 0;
6277}
6278
6279BUILDIN_FUNC(disableitemuse)
6280{
6281 TBL_PC *sd;
6282 sd=script_rid2sd(st);
6283 if (sd)
6284 sd->npc_item_flag = 0;
6285 return 0;
6286}
6287
6288/*==========================================
6289 *Æ’Lƒƒƒ‰ŠÖŒW‚̃pƒ‰ƒÂÂ[Æ’^Žæ“¾
6290 *------------------------------------------*/
6291BUILDIN_FUNC(readparam)
6292{
6293 int type;
6294 TBL_PC *sd;
6295
6296 type=script_getnum(st,2);
6297 if( script_hasdata(st,3) )
6298 sd=map_nick2sd(script_getstr(st,3));
6299 else
6300 sd=script_rid2sd(st);
6301
6302 if(sd==NULL){
6303 script_pushint(st,-1);
6304 return 0;
6305 }
6306
6307 script_pushint(st,pc_readparam(sd,type));
6308
6309 return 0;
6310}
6311/*==========================================
6312 *ƒLƒƒƒ‰ŠÖŒW‚ÌIDŽæ“¾
6313 *------------------------------------------*/
6314BUILDIN_FUNC(getcharid)
6315{
6316 int num;
6317 TBL_PC *sd;
6318
6319 num = script_getnum(st,2);
6320 if( script_hasdata(st,3) )
6321 sd=map_nick2sd(script_getstr(st,3));
6322 else
6323 sd=script_rid2sd(st);
6324
6325 if(sd==NULL){
6326 script_pushint(st,0); //return 0, according docs
6327 return 0;
6328 }
6329
6330 switch( num ) {
6331 case 0: script_pushint(st,sd->status.char_id); break;
6332 case 1: script_pushint(st,sd->status.party_id); break;
6333 case 2: script_pushint(st,sd->status.guild_id); break;
6334 case 3: script_pushint(st,sd->status.account_id); break;
6335 case 4: script_pushint(st,sd->bg_id); break;
6336 default:
6337 ShowError("buildin_getcharid: invalid parameter (%d).\n", num);
6338 script_pushint(st,0);
6339 break;
6340 }
6341
6342 return 0;
6343}
6344/*==========================================
6345 * [Paradox924X]
6346 *------------------------------------------*/
6347BUILDIN_FUNC(getnpcid)
6348{
6349 int num = script_getnum(st,2);
6350 struct npc_data* nd = NULL;
6351
6352 if( script_hasdata(st,3) )
6353 {// unique npc name
6354 if( ( nd = npc_name2id(script_getstr(st,3)) ) == NULL )
6355 {
6356 ShowError("buildin_getnpcid: No such NPC '%s'.\n", script_getstr(st,3));
6357 script_pushint(st,0);
6358 return 1;
6359 }
6360 }
6361
6362 switch (num) {
6363 case 0:
6364 script_pushint(st,nd ? nd->bl.id : st->oid);
6365 break;
6366 default:
6367 ShowError("buildin_getnpcid: invalid parameter (%d).\n", num);
6368 script_pushint(st,0);
6369 return 1;
6370 }
6371
6372 return 0;
6373}
6374/*==========================================
6375 *Žw’èID‚ÌPT–¼Žæ“¾
6376 *------------------------------------------*/
6377BUILDIN_FUNC(getpartyname)
6378{
6379 int party_id;
6380 struct party_data* p;
6381
6382 party_id = script_getnum(st,2);
6383
6384 if( ( p = party_search(party_id) ) != NULL )
6385 {
6386 script_pushstrcopy(st,p->party.name);
6387 }
6388 else
6389 {
6390 script_pushconststr(st,"null");
6391 }
6392 return 0;
6393}
6394/*==========================================
6395 *Žw’èID‚ÌPTÂlÂâ€â€šÃ†Æ’ÂÆ’“ƒoÂ[IDŽæ“¾
6396 *------------------------------------------*/
6397BUILDIN_FUNC(getpartymember)
6398{
6399 struct party_data *p;
6400 int i,j=0,type=0;
6401
6402 p=party_search(script_getnum(st,2));
6403
6404 if( script_hasdata(st,3) )
6405 type=script_getnum(st,3);
6406
6407 if(p!=NULL){
6408 for(i=0;i<MAX_PARTY;i++){
6409 if(p->party.member[i].account_id){
6410 switch (type) {
6411 case 2:
6412 mapreg_setreg(reference_uid(add_str("$@partymemberaid"), j),p->party.member[i].account_id);
6413 break;
6414 case 1:
6415 mapreg_setreg(reference_uid(add_str("$@partymembercid"), j),p->party.member[i].char_id);
6416 break;
6417 default:
6418 mapreg_setregstr(reference_uid(add_str("$@partymembername$"), j),p->party.member[i].name);
6419 }
6420 j++;
6421 }
6422 }
6423 }
6424 mapreg_setreg(add_str("$@partymembercount"),j);
6425
6426 return 0;
6427}
6428
6429/*==========================================
6430 * Retrieves party leader. if flag is specified,
6431 * return some of the leader data. Otherwise, return name.
6432 *------------------------------------------*/
6433BUILDIN_FUNC(getpartyleader)
6434{
6435 int party_id, type = 0, i=0;
6436 struct party_data *p;
6437
6438 party_id=script_getnum(st,2);
6439 if( script_hasdata(st,3) )
6440 type=script_getnum(st,3);
6441
6442 p=party_search(party_id);
6443
6444 if (p) //Search leader
6445 for(i = 0; i < MAX_PARTY && !p->party.member[i].leader; i++);
6446
6447 if (!p || i == MAX_PARTY) { //leader not found
6448 if (type)
6449 script_pushint(st,-1);
6450 else
6451 script_pushconststr(st,"null");
6452 return 0;
6453 }
6454
6455 switch (type) {
6456 case 1: script_pushint(st,p->party.member[i].account_id); break;
6457 case 2: script_pushint(st,p->party.member[i].char_id); break;
6458 case 3: script_pushint(st,p->party.member[i].class_); break;
6459 case 4: script_pushstrcopy(st,mapindex_id2name(p->party.member[i].map)); break;
6460 case 5: script_pushint(st,p->party.member[i].lv); break;
6461 default: script_pushstrcopy(st,p->party.member[i].name); break;
6462 }
6463 return 0;
6464}
6465
6466/*==========================================
6467 *Žw’èID‚̃Mƒ‹ƒh–¼Žæ“¾
6468 *------------------------------------------*/
6469BUILDIN_FUNC(getguildname)
6470{
6471 int guild_id;
6472 struct guild* g;
6473
6474 guild_id = script_getnum(st,2);
6475
6476 if( ( g = guild_search(guild_id) ) != NULL )
6477 {
6478 script_pushstrcopy(st,g->name);
6479 }
6480 else
6481 {
6482 script_pushconststr(st,"null");
6483 }
6484 return 0;
6485}
6486
6487/*==========================================
6488 *Žw’èID‚ÌGuildMaster–¼Žæ“¾
6489 *------------------------------------------*/
6490BUILDIN_FUNC(getguildmaster)
6491{
6492 int guild_id;
6493 struct guild* g;
6494
6495 guild_id = script_getnum(st,2);
6496
6497 if( ( g = guild_search(guild_id) ) != NULL )
6498 {
6499 script_pushstrcopy(st,g->member[0].name);
6500 }
6501 else
6502 {
6503 script_pushconststr(st,"null");
6504 }
6505 return 0;
6506}
6507
6508BUILDIN_FUNC(getguildmasterid)
6509{
6510 int guild_id;
6511 struct guild* g;
6512
6513 guild_id = script_getnum(st,2);
6514
6515 if( ( g = guild_search(guild_id) ) != NULL )
6516 {
6517 script_pushint(st,g->member[0].char_id);
6518 }
6519 else
6520 {
6521 script_pushint(st,0);
6522 }
6523 return 0;
6524}
6525
6526/*==========================================
6527 * ƒLƒƒƒ‰ƒNƒ^‚Ì–¼‘O
6528 *------------------------------------------*/
6529BUILDIN_FUNC(strcharinfo)
6530{
6531 TBL_PC *sd;
6532 int num;
6533 struct guild* g;
6534 struct party_data* p;
6535
6536 sd=script_rid2sd(st);
6537 if (!sd) { //Avoid crashing....
6538 script_pushconststr(st,"");
6539 return 0;
6540 }
6541 num=script_getnum(st,2);
6542 switch(num){
6543 case 0:
6544 script_pushstrcopy(st,sd->status.name);
6545 break;
6546 case 1:
6547 if( ( p = party_search(sd->status.party_id) ) != NULL )
6548 {
6549 script_pushstrcopy(st,p->party.name);
6550 }
6551 else
6552 {
6553 script_pushconststr(st,"");
6554 }
6555 break;
6556 case 2:
6557 if( ( g = guild_search(sd->status.guild_id) ) != NULL )
6558 {
6559 script_pushstrcopy(st,g->name);
6560 }
6561 else
6562 {
6563 script_pushconststr(st,"");
6564 }
6565 break;
6566 case 3:
6567 script_pushconststr(st,map[sd->bl.m].name);
6568 break;
6569 default:
6570 ShowWarning("buildin_strcharinfo: unknown parameter.\n");
6571 script_pushconststr(st,"");
6572 break;
6573 }
6574
6575 return 0;
6576}
6577
6578/*==========================================
6579 * ŒÄ‚ÑÂo‚µŒ³‚ÌNPCÂî•ñ‚ðŽæ“¾‚·‚é
6580 *------------------------------------------*/
6581BUILDIN_FUNC(strnpcinfo)
6582{
6583 TBL_NPC* nd;
6584 int num;
6585 char *buf,*name=NULL;
6586
6587 nd = map_id2nd(st->oid);
6588 if (!nd) {
6589 script_pushconststr(st, "");
6590 return 0;
6591 }
6592
6593 num = script_getnum(st,2);
6594 switch(num){
6595 case 0: // display name
6596 name = aStrdup(nd->name);
6597 break;
6598 case 1: // visible part of display name
6599 if((buf = strchr(nd->name,'#')) != NULL)
6600 {
6601 name = aStrdup(nd->name);
6602 name[buf - nd->name] = 0;
6603 } else // Return the name, there is no '#' present
6604 name = aStrdup(nd->name);
6605 break;
6606 case 2: // # fragment
6607 if((buf = strchr(nd->name,'#')) != NULL)
6608 name = aStrdup(buf+1);
6609 break;
6610 case 3: // unique name
6611 name = aStrdup(nd->exname);
6612 break;
6613 case 4: // map name
6614 name = aStrdup(map[nd->bl.m].name);
6615 break;
6616 }
6617
6618 if(name)
6619 script_pushstr(st, name);
6620 else
6621 script_pushconststr(st, "");
6622
6623 return 0;
6624}
6625
6626
6627// aegis->athena slot position conversion table
6628static 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};
6629
6630/*==========================================
6631 * GetEquipID(Pos); Pos: 1-10
6632 *------------------------------------------*/
6633BUILDIN_FUNC(getequipid)
6634{
6635 int i, num;
6636 TBL_PC* sd;
6637 struct item_data* item;
6638
6639 sd = script_rid2sd(st);
6640 if( sd == NULL )
6641 return 0;
6642
6643 num = script_getnum(st,2) - 1;
6644 if( num < 0 || num >= ARRAYLENGTH(equip) )
6645 {
6646 script_pushint(st,-1);
6647 return 0;
6648 }
6649
6650 // get inventory position of item
6651 i = pc_checkequip(sd,equip[num]);
6652 if( i < 0 )
6653 {
6654 script_pushint(st,-1);
6655 return 0;
6656 }
6657
6658 item = sd->inventory_data[i];
6659 if( item != 0 )
6660 script_pushint(st,item->nameid);
6661 else
6662 script_pushint(st,0);
6663
6664 return 0;
6665}
6666
6667/*==========================================
6668 * ‘•â€Ãµâ€“¼•¶Žš—ñÂi¸˜BÆ’ÂÆ’jƒ…Â[—pÂj
6669 *------------------------------------------*/
6670BUILDIN_FUNC(getequipname)
6671{
6672 int i, num;
6673 TBL_PC* sd;
6674 struct item_data* item;
6675
6676 sd = script_rid2sd(st);
6677 if( sd == NULL )
6678 return 0;
6679
6680 num = script_getnum(st,2) - 1;
6681 if( num < 0 || num >= ARRAYLENGTH(equip) )
6682 {
6683 script_pushconststr(st,"");
6684 return 0;
6685 }
6686
6687 // get inventory position of item
6688 i = pc_checkequip(sd,equip[num]);
6689 if( i < 0 )
6690 {
6691 script_pushint(st,-1);
6692 return 0;
6693 }
6694
6695 item = sd->inventory_data[i];
6696 if( item != 0 )
6697 script_pushstrcopy(st,item->jname);
6698 else
6699 script_pushconststr(st,"");
6700
6701 return 0;
6702}
6703
6704/*==========================================
6705 * getbrokenid [Valaris]
6706 *------------------------------------------*/
6707BUILDIN_FUNC(getbrokenid)
6708{
6709 int i,num,id=0,brokencounter=0;
6710 TBL_PC *sd;
6711
6712 sd = script_rid2sd(st);
6713 if( sd == NULL )
6714 return 0;
6715
6716 num=script_getnum(st,2);
6717 for(i=0; i<MAX_INVENTORY; i++) {
6718 if(sd->status.inventory[i].attribute){
6719 brokencounter++;
6720 if(num==brokencounter){
6721 id=sd->status.inventory[i].nameid;
6722 break;
6723 }
6724 }
6725 }
6726
6727 script_pushint(st,id);
6728
6729 return 0;
6730}
6731
6732/*==========================================
6733 * repair [Valaris]
6734 *------------------------------------------*/
6735BUILDIN_FUNC(repair)
6736{
6737 int i,num;
6738 int repaircounter=0;
6739 TBL_PC *sd;
6740
6741 sd = script_rid2sd(st);
6742 if( sd == NULL )
6743 return 0;
6744
6745 num=script_getnum(st,2);
6746 for(i=0; i<MAX_INVENTORY; i++) {
6747 if(sd->status.inventory[i].attribute){
6748 repaircounter++;
6749 if(num==repaircounter){
6750 sd->status.inventory[i].attribute=0;
6751 clif_equiplist(sd);
6752 clif_produceeffect(sd, 0, sd->status.inventory[i].nameid);
6753 clif_misceffect(&sd->bl, 3);
6754 break;
6755 }
6756 }
6757 }
6758
6759 return 0;
6760}
6761
6762/*==========================================
6763 * ‘•â€ÃµÆ’`Æ’FÆ’bÆ’N
6764 *------------------------------------------*/
6765BUILDIN_FUNC(getequipisequiped)
6766{
6767 int i=-1,num;
6768 TBL_PC *sd;
6769
6770 num=script_getnum(st,2);
6771 sd = script_rid2sd(st);
6772 if( sd == NULL )
6773 return 0;
6774
6775 if (num > 0 && num <= ARRAYLENGTH(equip))
6776 i=pc_checkequip(sd,equip[num-1]);
6777
6778 if(i >= 0)
6779 script_pushint(st,1);
6780 else
6781 script_pushint(st,0);
6782 return 0;
6783}
6784
6785/*==========================================
6786 * ‘•â€Ãµâ€¢i¸˜B‰Ââ€\Æ’`Æ’FÆ’bÆ’N
6787 *------------------------------------------*/
6788BUILDIN_FUNC(getequipisenableref)
6789{
6790 int i=-1,num;
6791 TBL_PC *sd;
6792
6793 num=script_getnum(st,2);
6794 sd = script_rid2sd(st);
6795 if( sd == NULL )
6796 return 0;
6797
6798 if( num > 0 && num <= ARRAYLENGTH(equip) )
6799 i = pc_checkequip(sd,equip[num-1]);
6800 if( i >= 0 && sd->inventory_data[i] && !sd->inventory_data[i]->flag.no_refine && !sd->status.inventory[i].expire_time )
6801 script_pushint(st,1);
6802 else
6803 script_pushint(st,0);
6804
6805 return 0;
6806}
6807
6808/*==========================================
6809 * ‘•â€Ãµâ€¢iŠÓ’èƒ`Æ’FÆ’bÆ’N
6810 *------------------------------------------*/
6811BUILDIN_FUNC(getequipisidentify)
6812{
6813 int i=-1,num;
6814 TBL_PC *sd;
6815
6816 num=script_getnum(st,2);
6817 sd = script_rid2sd(st);
6818 if( sd == NULL )
6819 return 0;
6820
6821 if (num > 0 && num <= ARRAYLENGTH(equip))
6822 i=pc_checkequip(sd,equip[num-1]);
6823 if(i >= 0)
6824 script_pushint(st,sd->status.inventory[i].identify);
6825 else
6826 script_pushint(st,0);
6827
6828 return 0;
6829}
6830
6831/*==========================================
6832 * ‘•â€Ãµâ€¢i¸˜B“x
6833 *------------------------------------------*/
6834BUILDIN_FUNC(getequiprefinerycnt)
6835{
6836 int i=-1,num;
6837 TBL_PC *sd;
6838
6839 num=script_getnum(st,2);
6840 sd = script_rid2sd(st);
6841 if( sd == NULL )
6842 return 0;
6843
6844 if (num > 0 && num <= ARRAYLENGTH(equip))
6845 i=pc_checkequip(sd,equip[num-1]);
6846 if(i >= 0)
6847 script_pushint(st,sd->status.inventory[i].refine);
6848 else
6849 script_pushint(st,0);
6850
6851 return 0;
6852}
6853
6854/*==========================================
6855 * ‘•â€Ãµâ€¢i•ÂÅ ÃLV
6856 *------------------------------------------*/
6857BUILDIN_FUNC(getequipweaponlv)
6858{
6859 int i=-1,num;
6860 TBL_PC *sd;
6861
6862 num=script_getnum(st,2);
6863 sd = script_rid2sd(st);
6864 if( sd == NULL )
6865 return 0;
6866
6867 if (num > 0 && num <= ARRAYLENGTH(equip))
6868 i=pc_checkequip(sd,equip[num-1]);
6869 if(i >= 0 && sd->inventory_data[i])
6870 script_pushint(st,sd->inventory_data[i]->wlv);
6871 else
6872 script_pushint(st,0);
6873
6874 return 0;
6875}
6876
6877/*==========================================
6878 * ‘•â€Ãµâ€¢i¸˜B¬Œ÷—¦
6879 *------------------------------------------*/
6880BUILDIN_FUNC(getequippercentrefinery)
6881{
6882 int i=-1,num;
6883 TBL_PC *sd;
6884
6885 num=script_getnum(st,2);
6886 sd = script_rid2sd(st);
6887 if( sd == NULL )
6888 return 0;
6889
6890 if (num > 0 && num <= ARRAYLENGTH(equip))
6891 i=pc_checkequip(sd,equip[num-1]);
6892 if(i >= 0 && sd->status.inventory[i].nameid && sd->status.inventory[i].refine < MAX_REFINE)
6893 script_pushint(st,percentrefinery[itemdb_wlv(sd->status.inventory[i].nameid)][(int)sd->status.inventory[i].refine]);
6894 else
6895 script_pushint(st,0);
6896
6897 return 0;
6898}
6899
6900/*==========================================
6901 * ¸˜B¬Œ÷
6902 *------------------------------------------*/
6903BUILDIN_FUNC(successrefitem)
6904{
6905 int i=-1,num,ep;
6906 TBL_PC *sd;
6907
6908 num=script_getnum(st,2);
6909 sd = script_rid2sd(st);
6910 if( sd == NULL )
6911 return 0;
6912
6913 if (num > 0 && num <= ARRAYLENGTH(equip))
6914 i=pc_checkequip(sd,equip[num-1]);
6915 if(i >= 0) {
6916 ep=sd->status.inventory[i].equip;
6917
6918 //Logs items, got from (N)PC scripts [Lupus]
6919 log_pick(&sd->bl, LOG_TYPE_SCRIPT, sd->status.inventory[i].nameid, -1, &sd->status.inventory[i]);
6920
6921 sd->status.inventory[i].refine++;
6922 pc_unequipitem(sd,i,2); // status calc will happen in pc_equipitem() below
6923
6924 clif_refine(sd->fd,0,i,sd->status.inventory[i].refine);
6925 clif_delitem(sd,i,1,3);
6926
6927 //Logs items, got from (N)PC scripts [Lupus]
6928 log_pick(&sd->bl, LOG_TYPE_SCRIPT, sd->status.inventory[i].nameid, 1, &sd->status.inventory[i]);
6929
6930 clif_additem(sd,i,1,0);
6931 pc_equipitem(sd,i,ep);
6932 clif_misceffect(&sd->bl,3);
6933 if(sd->status.inventory[i].refine == MAX_REFINE &&
6934 sd->status.inventory[i].card[0] == CARD0_FORGE &&
6935 sd->status.char_id == (int)MakeDWord(sd->status.inventory[i].card[2],sd->status.inventory[i].card[3])
6936 ){ // Fame point system [DracoRPG]
6937 switch (sd->inventory_data[i]->wlv){
6938 case 1:
6939 pc_addfame(sd,1); // Success to refine to +10 a lv1 weapon you forged = +1 fame point
6940 break;
6941 case 2:
6942 pc_addfame(sd,25); // Success to refine to +10 a lv2 weapon you forged = +25 fame point
6943 break;
6944 case 3:
6945 pc_addfame(sd,1000); // Success to refine to +10 a lv3 weapon you forged = +1000 fame point
6946 break;
6947 }
6948 }
6949 }
6950
6951 return 0;
6952}
6953
6954/*==========================================
6955 * ¸˜Bޏâ€s
6956 *------------------------------------------*/
6957BUILDIN_FUNC(failedrefitem)
6958{
6959 int i=-1,num;
6960 TBL_PC *sd;
6961
6962 num=script_getnum(st,2);
6963 sd = script_rid2sd(st);
6964 if( sd == NULL )
6965 return 0;
6966
6967 if (num > 0 && num <= ARRAYLENGTH(equip))
6968 i=pc_checkequip(sd,equip[num-1]);
6969 if(i >= 0) {
6970 //Logs items, got from (N)PC scripts [Lupus]
6971 log_pick(&sd->bl, LOG_TYPE_SCRIPT, sd->status.inventory[i].nameid, -1, &sd->status.inventory[i]);
6972
6973 sd->status.inventory[i].refine = 0;
6974 pc_unequipitem(sd,i,3);
6975 // ¸˜Bޏâ€sÆ’GÆ’tÆ’FÆ’NÆ’g‚̃pÆ’PÆ’bÆ’g
6976 clif_refine(sd->fd,1,i,sd->status.inventory[i].refine);
6977
6978 pc_delitem(sd,i,1,0,2);
6979 // ‘¼‚ÌÂl‚É‚à Ž¸â€s‚ð’Ê’m
6980 clif_misceffect(&sd->bl,2);
6981 }
6982
6983 return 0;
6984}
6985
6986/*==========================================
6987 *
6988 *------------------------------------------*/
6989BUILDIN_FUNC(statusup)
6990{
6991 int type;
6992 TBL_PC *sd;
6993
6994 type=script_getnum(st,2);
6995 sd = script_rid2sd(st);
6996 if( sd == NULL )
6997 return 0;
6998
6999 pc_statusup(sd,type);
7000
7001 return 0;
7002}
7003/*==========================================
7004 *
7005 *------------------------------------------*/
7006BUILDIN_FUNC(statusup2)
7007{
7008 int type,val;
7009 TBL_PC *sd;
7010
7011 type=script_getnum(st,2);
7012 val=script_getnum(st,3);
7013 sd = script_rid2sd(st);
7014 if( sd == NULL )
7015 return 0;
7016
7017 pc_statusup2(sd,type,val);
7018
7019 return 0;
7020}
7021
7022/// See 'doc/item_bonus.txt'
7023///
7024/// bonus <bonus type>,<val1>;
7025/// bonus2 <bonus type>,<val1>,<val2>;
7026/// bonus3 <bonus type>,<val1>,<val2>,<val3>;
7027/// bonus4 <bonus type>,<val1>,<val2>,<val3>,<val4>;
7028/// bonus5 <bonus type>,<val1>,<val2>,<val3>,<val4>,<val5>;
7029BUILDIN_FUNC(bonus)
7030{
7031 int type;
7032 int val1;
7033 int val2 = 0;
7034 int val3 = 0;
7035 int val4 = 0;
7036 int val5 = 0;
7037 TBL_PC* sd;
7038
7039 sd = script_rid2sd(st);
7040 if( sd == NULL )
7041 return 0; // no player attached
7042
7043 type = script_getnum(st,2);
7044 switch( type )
7045 {
7046 case SP_AUTOSPELL:
7047 case SP_AUTOSPELL_WHENHIT:
7048 case SP_AUTOSPELL_ONSKILL:
7049 case SP_SKILL_ATK:
7050 case SP_SKILL_HEAL:
7051 case SP_SKILL_HEAL2:
7052 case SP_ADD_SKILL_BLOW:
7053 case SP_CASTRATE:
7054 case SP_ADDEFF_ONSKILL:
7055 // these bonuses support skill names
7056 val1 = ( script_isstring(st,3) ? skill_name2id(script_getstr(st,3)) : script_getnum(st,3) );
7057 break;
7058 default:
7059 val1 = script_getnum(st,3);
7060 break;
7061 }
7062
7063 switch( script_lastdata(st)-2 )
7064 {
7065 case 1:
7066 pc_bonus(sd, type, val1);
7067 break;
7068 case 2:
7069 val2 = script_getnum(st,4);
7070 pc_bonus2(sd, type, val1, val2);
7071 break;
7072 case 3:
7073 val2 = script_getnum(st,4);
7074 val3 = script_getnum(st,5);
7075 pc_bonus3(sd, type, val1, val2, val3);
7076 break;
7077 case 4:
7078 if( type == SP_AUTOSPELL_ONSKILL && script_isstring(st,4) )
7079 val2 = skill_name2id(script_getstr(st,4)); // 2nd value can be skill name
7080 else
7081 val2 = script_getnum(st,4);
7082
7083 val3 = script_getnum(st,5);
7084 val4 = script_getnum(st,6);
7085 pc_bonus4(sd, type, val1, val2, val3, val4);
7086 break;
7087 case 5:
7088 if( type == SP_AUTOSPELL_ONSKILL && script_isstring(st,4) )
7089 val2 = skill_name2id(script_getstr(st,4)); // 2nd value can be skill name
7090 else
7091 val2 = script_getnum(st,4);
7092
7093 val3 = script_getnum(st,5);
7094 val4 = script_getnum(st,6);
7095 val5 = script_getnum(st,7);
7096 pc_bonus5(sd, type, val1, val2, val3, val4, val5);
7097 break;
7098 default:
7099 ShowDebug("buildin_bonus: unexpected number of arguments (%d)\n", (script_lastdata(st) - 1));
7100 break;
7101 }
7102
7103 return 0;
7104}
7105
7106BUILDIN_FUNC(autobonus)
7107{
7108 unsigned int dur;
7109 short rate;
7110 short atk_type = 0;
7111 TBL_PC* sd;
7112 const char *bonus_script, *other_script = NULL;
7113
7114 sd = script_rid2sd(st);
7115 if( sd == NULL )
7116 return 0; // no player attached
7117
7118 if( sd->state.autobonus&sd->status.inventory[current_equip_item_index].equip )
7119 return 0;
7120
7121 rate = script_getnum(st,3);
7122 dur = script_getnum(st,4);
7123 bonus_script = script_getstr(st,2);
7124 if( !rate || !dur || !bonus_script )
7125 return 0;
7126
7127 if( script_hasdata(st,5) )
7128 atk_type = script_getnum(st,5);
7129 if( script_hasdata(st,6) )
7130 other_script = script_getstr(st,6);
7131
7132 if( pc_addautobonus(sd->autobonus,ARRAYLENGTH(sd->autobonus),
7133 bonus_script,rate,dur,atk_type,other_script,sd->status.inventory[current_equip_item_index].equip,false) )
7134 {
7135 script_add_autobonus(bonus_script);
7136 if( other_script )
7137 script_add_autobonus(other_script);
7138 }
7139
7140 return 0;
7141}
7142
7143BUILDIN_FUNC(autobonus2)
7144{
7145 unsigned int dur;
7146 short rate;
7147 short atk_type = 0;
7148 TBL_PC* sd;
7149 const char *bonus_script, *other_script = NULL;
7150
7151 sd = script_rid2sd(st);
7152 if( sd == NULL )
7153 return 0; // no player attached
7154
7155 if( sd->state.autobonus&sd->status.inventory[current_equip_item_index].equip )
7156 return 0;
7157
7158 rate = script_getnum(st,3);
7159 dur = script_getnum(st,4);
7160 bonus_script = script_getstr(st,2);
7161 if( !rate || !dur || !bonus_script )
7162 return 0;
7163
7164 if( script_hasdata(st,5) )
7165 atk_type = script_getnum(st,5);
7166 if( script_hasdata(st,6) )
7167 other_script = script_getstr(st,6);
7168
7169 if( pc_addautobonus(sd->autobonus2,ARRAYLENGTH(sd->autobonus2),
7170 bonus_script,rate,dur,atk_type,other_script,sd->status.inventory[current_equip_item_index].equip,false) )
7171 {
7172 script_add_autobonus(bonus_script);
7173 if( other_script )
7174 script_add_autobonus(other_script);
7175 }
7176
7177 return 0;
7178}
7179
7180BUILDIN_FUNC(autobonus3)
7181{
7182 unsigned int dur;
7183 short rate,atk_type;
7184 TBL_PC* sd;
7185 const char *bonus_script, *other_script = NULL;
7186
7187 sd = script_rid2sd(st);
7188 if( sd == NULL )
7189 return 0; // no player attached
7190
7191 if( sd->state.autobonus&sd->status.inventory[current_equip_item_index].equip )
7192 return 0;
7193
7194 rate = script_getnum(st,3);
7195 dur = script_getnum(st,4);
7196 atk_type = ( script_isstring(st,5) ? skill_name2id(script_getstr(st,5)) : script_getnum(st,5) );
7197 bonus_script = script_getstr(st,2);
7198 if( !rate || !dur || !atk_type || !bonus_script )
7199 return 0;
7200
7201 if( script_hasdata(st,6) )
7202 other_script = script_getstr(st,6);
7203
7204 if( pc_addautobonus(sd->autobonus3,ARRAYLENGTH(sd->autobonus3),
7205 bonus_script,rate,dur,atk_type,other_script,sd->status.inventory[current_equip_item_index].equip,true) )
7206 {
7207 script_add_autobonus(bonus_script);
7208 if( other_script )
7209 script_add_autobonus(other_script);
7210 }
7211
7212 return 0;
7213}
7214
7215/// Changes the level of a player skill.
7216/// <flag> defaults to 1
7217/// <flag>=0 : set the level of the skill
7218/// <flag>=1 : set the temporary level of the skill
7219/// <flag>=2 : add to the level of the skill
7220///
7221/// skill <skill id>,<level>,<flag>
7222/// skill <skill id>,<level>
7223/// skill "<skill name>",<level>,<flag>
7224/// skill "<skill name>",<level>
7225BUILDIN_FUNC(skill)
7226{
7227 int id;
7228 int level;
7229 int flag = 1;
7230 TBL_PC* sd;
7231
7232 sd = script_rid2sd(st);
7233 if( sd == NULL )
7234 return 0;// no player attached, report source
7235
7236 id = ( script_isstring(st,2) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
7237 level = script_getnum(st,3);
7238 if( script_hasdata(st,4) )
7239 flag = script_getnum(st,4);
7240 pc_skill(sd, id, level, flag);
7241
7242 return 0;
7243}
7244
7245/// Changes the level of a player skill.
7246/// like skill, but <flag> defaults to 2
7247///
7248/// addtoskill <skill id>,<amount>,<flag>
7249/// addtoskill <skill id>,<amount>
7250/// addtoskill "<skill name>",<amount>,<flag>
7251/// addtoskill "<skill name>",<amount>
7252///
7253/// @see skill
7254BUILDIN_FUNC(addtoskill)
7255{
7256 int id;
7257 int level;
7258 int flag = 2;
7259 TBL_PC* sd;
7260
7261 sd = script_rid2sd(st);
7262 if( sd == NULL )
7263 return 0;// no player attached, report source
7264
7265 id = ( script_isstring(st,2) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
7266 level = script_getnum(st,3);
7267 if( script_hasdata(st,4) )
7268 flag = script_getnum(st,4);
7269 pc_skill(sd, id, level, flag);
7270
7271 return 0;
7272}
7273
7274/// Increases the level of a guild skill.
7275///
7276/// guildskill <skill id>,<amount>;
7277/// guildskill "<skill name>",<amount>;
7278BUILDIN_FUNC(guildskill)
7279{
7280 int id;
7281 int level;
7282 TBL_PC* sd;
7283 int i;
7284
7285 sd = script_rid2sd(st);
7286 if( sd == NULL )
7287 return 0;// no player attached, report source
7288
7289 id = ( script_isstring(st,2) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
7290 level = script_getnum(st,3);
7291 for( i=0; i < level; i++ )
7292 guild_skillup(sd, id);
7293
7294 return 0;
7295}
7296
7297/// Returns the level of the player skill.
7298///
7299/// getskilllv(<skill id>) -> <level>
7300/// getskilllv("<skill name>") -> <level>
7301BUILDIN_FUNC(getskilllv)
7302{
7303 int id;
7304 TBL_PC* sd;
7305
7306 sd = script_rid2sd(st);
7307 if( sd == NULL )
7308 return 0;// no player attached, report source
7309
7310 id = ( script_isstring(st,2) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
7311 script_pushint(st, pc_checkskill(sd,id));
7312
7313 return 0;
7314}
7315
7316/// Returns the level of the guild skill.
7317///
7318/// getgdskilllv(<guild id>,<skill id>) -> <level>
7319/// getgdskilllv(<guild id>,"<skill name>") -> <level>
7320BUILDIN_FUNC(getgdskilllv)
7321{
7322 int guild_id;
7323 int skill_id;
7324 struct guild* g;
7325
7326 guild_id = script_getnum(st,2);
7327 skill_id = ( script_isstring(st,3) ? skill_name2id(script_getstr(st,3)) : script_getnum(st,3) );
7328 g = guild_search(guild_id);
7329 if( g == NULL )
7330 script_pushint(st, -1);
7331 else
7332 script_pushint(st, guild_checkskill(g,skill_id));
7333
7334 return 0;
7335}
7336
7337/// Returns the 'basic_skill_check' setting.
7338/// This config determines if the server checks the skill level of NV_BASIC
7339/// before allowing the basic actions.
7340///
7341/// basicskillcheck() -> <bool>
7342BUILDIN_FUNC(basicskillcheck)
7343{
7344 script_pushint(st, battle_config.basic_skill_check);
7345 return 0;
7346}
7347
7348/// Returns the GM level of the player.
7349///
7350/// getgmlevel() -> <level>
7351BUILDIN_FUNC(getgmlevel)
7352{
7353 TBL_PC* sd;
7354
7355 sd = script_rid2sd(st);
7356 if( sd == NULL )
7357 return 0;// no player attached, report source
7358
7359 script_pushint(st, pc_isGM(sd));
7360
7361 return 0;
7362}
7363
7364/// Terminates the execution of this script instance.
7365///
7366/// end
7367BUILDIN_FUNC(end)
7368{
7369 st->state = END;
7370 return 0;
7371}
7372
7373/// Checks if the player has that effect state (option).
7374///
7375/// checkoption(<option>) -> <bool>
7376BUILDIN_FUNC(checkoption)
7377{
7378 int option;
7379 TBL_PC* sd;
7380
7381 sd = script_rid2sd(st);
7382 if( sd == NULL )
7383 return 0;// no player attached, report source
7384
7385 option = script_getnum(st,2);
7386 if( sd->sc.option&option )
7387 script_pushint(st, 1);
7388 else
7389 script_pushint(st, 0);
7390
7391 return 0;
7392}
7393
7394/// Checks if the player is in that body state (opt1).
7395///
7396/// checkoption1(<opt1>) -> <bool>
7397BUILDIN_FUNC(checkoption1)
7398{
7399 int opt1;
7400 TBL_PC* sd;
7401
7402 sd = script_rid2sd(st);
7403 if( sd == NULL )
7404 return 0;// no player attached, report source
7405
7406 opt1 = script_getnum(st,2);
7407 if( sd->sc.opt1 == opt1 )
7408 script_pushint(st, 1);
7409 else
7410 script_pushint(st, 0);
7411
7412 return 0;
7413}
7414
7415/// Checks if the player has that health state (opt2).
7416///
7417/// checkoption2(<opt2>) -> <bool>
7418BUILDIN_FUNC(checkoption2)
7419{
7420 int opt2;
7421 TBL_PC* sd;
7422
7423 sd = script_rid2sd(st);
7424 if( sd == NULL )
7425 return 0;// no player attached, report source
7426
7427 opt2 = script_getnum(st,2);
7428 if( sd->sc.opt2&opt2 )
7429 script_pushint(st, 1);
7430 else
7431 script_pushint(st, 0);
7432
7433 return 0;
7434}
7435
7436/// Changes the effect state (option) of the player.
7437/// <flag> defaults to 1
7438/// <flag>=0 : removes the option
7439/// <flag>=other : adds the option
7440///
7441/// setoption <option>,<flag>;
7442/// setoption <option>;
7443BUILDIN_FUNC(setoption)
7444{
7445 int option;
7446 int flag = 1;
7447 TBL_PC* sd;
7448
7449 sd = script_rid2sd(st);
7450 if( sd == NULL )
7451 return 0;// no player attached, report source
7452
7453 option = script_getnum(st,2);
7454 if( script_hasdata(st,3) )
7455 flag = script_getnum(st,3);
7456 else if( !option ){// Request to remove everything.
7457 flag = 0;
7458 option = OPTION_CART|OPTION_FALCON|OPTION_RIDING;
7459 }
7460 if( flag ){// Add option
7461 if( option&OPTION_WEDDING && !battle_config.wedding_modifydisplay )
7462 option &= ~OPTION_WEDDING;// Do not show the wedding sprites
7463 pc_setoption(sd, sd->sc.option|option);
7464 } else// Remove option
7465 pc_setoption(sd, sd->sc.option&~option);
7466
7467 return 0;
7468}
7469
7470/// Returns if the player has a cart.
7471///
7472/// checkcart() -> <bool>
7473///
7474/// @author Valaris
7475BUILDIN_FUNC(checkcart)
7476{
7477 TBL_PC* sd;
7478
7479 sd = script_rid2sd(st);
7480 if( sd == NULL )
7481 return 0;// no player attached, report source
7482
7483 if( pc_iscarton(sd) )
7484 script_pushint(st, 1);
7485 else
7486 script_pushint(st, 0);
7487
7488 return 0;
7489}
7490
7491/// Sets the cart of the player.
7492/// <type> defaults to 1
7493/// <type>=0 : removes the cart
7494/// <type>=1 : Normal cart
7495/// <type>=2 : Wooden cart
7496/// <type>=3 : Covered cart with flowers and ferns
7497/// <type>=4 : Wooden cart with a Panda doll on the back
7498/// <type>=5 : Normal cart with bigger wheels, a roof and a banner on the back
7499///
7500/// setcart <type>;
7501/// setcart;
7502BUILDIN_FUNC(setcart)
7503{
7504 int type = 1;
7505 TBL_PC* sd;
7506
7507 sd = script_rid2sd(st);
7508 if( sd == NULL )
7509 return 0;// no player attached, report source
7510
7511 if( script_hasdata(st,2) )
7512 type = script_getnum(st,2);
7513 pc_setcart(sd, type);
7514
7515 return 0;
7516}
7517
7518/// Returns if the player has a falcon.
7519///
7520/// checkfalcon() -> <bool>
7521///
7522/// @author Valaris
7523BUILDIN_FUNC(checkfalcon)
7524{
7525 TBL_PC* sd;
7526
7527 sd = script_rid2sd(st);
7528 if( sd == NULL )
7529 return 0;// no player attached, report source
7530
7531 if( pc_isfalcon(sd) )
7532 script_pushint(st, 1);
7533 else
7534 script_pushint(st, 0);
7535
7536 return 0;
7537}
7538
7539/// Sets if the player has a falcon or not.
7540/// <flag> defaults to 1
7541///
7542/// setfalcon <flag>;
7543/// setfalcon;
7544BUILDIN_FUNC(setfalcon)
7545{
7546 int flag = 1;
7547 TBL_PC* sd;
7548
7549 sd = script_rid2sd(st);
7550 if( sd == NULL )
7551 return 0;// no player attached, report source
7552
7553 if( script_hasdata(st,2) )
7554 flag = script_getnum(st,2);
7555
7556 pc_setfalcon(sd, flag);
7557
7558 return 0;
7559}
7560
7561/// Returns if the player is riding.
7562///
7563/// checkriding() -> <bool>
7564///
7565/// @author Valaris
7566BUILDIN_FUNC(checkriding)
7567{
7568 TBL_PC* sd;
7569
7570 sd = script_rid2sd(st);
7571 if( sd == NULL )
7572 return 0;// no player attached, report source
7573
7574 if( pc_isriding(sd) )
7575 script_pushint(st, 1);
7576 else
7577 script_pushint(st, 0);
7578
7579 return 0;
7580}
7581
7582/// Sets if the player is riding.
7583/// <flag> defaults to 1
7584///
7585/// setriding <flag>;
7586/// setriding;
7587BUILDIN_FUNC(setriding)
7588{
7589 int flag = 1;
7590 TBL_PC* sd;
7591
7592 sd = script_rid2sd(st);
7593 if( sd == NULL )
7594 return 0;// no player attached, report source
7595
7596 if( script_hasdata(st,2) )
7597 flag = script_getnum(st,2);
7598 pc_setriding(sd, flag);
7599
7600 return 0;
7601}
7602
7603/// Sets the save point of the player.
7604///
7605/// save "<map name>",<x>,<y>
7606/// savepoint "<map name>",<x>,<y>
7607BUILDIN_FUNC(savepoint)
7608{
7609 int x;
7610 int y;
7611 short map;
7612 const char* str;
7613 TBL_PC* sd;
7614
7615 sd = script_rid2sd(st);
7616 if( sd == NULL )
7617 return 0;// no player attached, report source
7618
7619 str = script_getstr(st, 2);
7620 x = script_getnum(st,3);
7621 y = script_getnum(st,4);
7622 map = mapindex_name2id(str);
7623 if( map )
7624 pc_setsavepoint(sd, map, x, y);
7625
7626 return 0;
7627}
7628
7629/*==========================================
7630 * GetTimeTick(0: System Tick, 1: Time Second Tick)
7631 *------------------------------------------*/
7632BUILDIN_FUNC(gettimetick) /* Asgard Version */
7633{
7634 int type;
7635 time_t timer;
7636 struct tm *t;
7637
7638 type=script_getnum(st,2);
7639
7640 switch(type){
7641 case 2:
7642 //type 2:(Get the number of seconds elapsed since 00:00 hours, Jan 1, 1970 UTC
7643 // from the system clock.)
7644 script_pushint(st,(int)time(NULL));
7645 break;
7646 case 1:
7647 //type 1:(Second Ticks: 0-86399, 00:00:00-23:59:59)
7648 time(&timer);
7649 t=localtime(&timer);
7650 script_pushint(st,((t->tm_hour)*3600+(t->tm_min)*60+t->tm_sec));
7651 break;
7652 case 0:
7653 default:
7654 //type 0:(System Ticks)
7655 script_pushint(st,gettick());
7656 break;
7657 }
7658 return 0;
7659}
7660
7661/*==========================================
7662 * GetTime(Type);
7663 * 1: Sec 2: Min 3: Hour
7664 * 4: WeekDay 5: MonthDay 6: Month
7665 * 7: Year
7666 *------------------------------------------*/
7667BUILDIN_FUNC(gettime) /* Asgard Version */
7668{
7669 int type;
7670 time_t timer;
7671 struct tm *t;
7672
7673 type=script_getnum(st,2);
7674
7675 time(&timer);
7676 t=localtime(&timer);
7677
7678 switch(type){
7679 case 1://Sec(0~59)
7680 script_pushint(st,t->tm_sec);
7681 break;
7682 case 2://Min(0~59)
7683 script_pushint(st,t->tm_min);
7684 break;
7685 case 3://Hour(0~23)
7686 script_pushint(st,t->tm_hour);
7687 break;
7688 case 4://WeekDay(0~6)
7689 script_pushint(st,t->tm_wday);
7690 break;
7691 case 5://MonthDay(01~31)
7692 script_pushint(st,t->tm_mday);
7693 break;
7694 case 6://Month(01~12)
7695 script_pushint(st,t->tm_mon+1);
7696 break;
7697 case 7://Year(20xx)
7698 script_pushint(st,t->tm_year+1900);
7699 break;
7700 case 8://Year Day(01~366)
7701 script_pushint(st,t->tm_yday+1);
7702 break;
7703 default://(format error)
7704 script_pushint(st,-1);
7705 break;
7706 }
7707 return 0;
7708}
7709
7710/*==========================================
7711 * GetTimeStr("TimeFMT", Length);
7712 *------------------------------------------*/
7713BUILDIN_FUNC(gettimestr)
7714{
7715 char *tmpstr;
7716 const char *fmtstr;
7717 int maxlen;
7718 time_t now = time(NULL);
7719
7720 fmtstr=script_getstr(st,2);
7721 maxlen=script_getnum(st,3);
7722
7723 tmpstr=(char *)aMallocA((maxlen+1)*sizeof(char));
7724 strftime(tmpstr,maxlen,fmtstr,localtime(&now));
7725 tmpstr[maxlen]='\0';
7726
7727 script_pushstr(st,tmpstr);
7728 return 0;
7729}
7730
7731/*==========================================
7732 * Æ’JÆ’vƒ‰‘qŒÉ‚ðŠJ‚Â
7733 *------------------------------------------*/
7734BUILDIN_FUNC(openstorage)
7735{
7736 TBL_PC* sd;
7737
7738 sd = script_rid2sd(st);
7739 if( sd == NULL )
7740 return 0;
7741
7742 storage_storageopen(sd);
7743 return 0;
7744}
7745
7746BUILDIN_FUNC(guildopenstorage)
7747{
7748 TBL_PC* sd;
7749 int ret;
7750
7751 sd = script_rid2sd(st);
7752 if( sd == NULL )
7753 return 0;
7754
7755 ret = storage_guild_storageopen(sd);
7756 script_pushint(st,ret);
7757 return 0;
7758}
7759
7760/*==========================================
7761 * Æ’AÆ’CÆ’eƒ€‚É‚æ‚éƒXÆ’Lƒ‹â€Â“®
7762 *------------------------------------------*/
7763/// itemskill <skill id>,<level>
7764/// itemskill "<skill name>",<level>
7765BUILDIN_FUNC(itemskill)
7766{
7767 int id;
7768 int lv;
7769 TBL_PC* sd;
7770
7771 sd = script_rid2sd(st);
7772 if( sd == NULL || sd->ud.skilltimer != INVALID_TIMER )
7773 return 0;
7774
7775 id = ( script_isstring(st,2) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
7776 lv = script_getnum(st,3);
7777
7778 sd->skillitem=id;
7779 sd->skillitemlv=lv;
7780 clif_item_skill(sd,id,lv);
7781 return 0;
7782}
7783/*==========================================
7784 * Æ’AÆ’CÆ’eƒ€Âì¬
7785 *------------------------------------------*/
7786BUILDIN_FUNC(produce)
7787{
7788 int trigger;
7789 TBL_PC* sd;
7790
7791 sd = script_rid2sd(st);
7792 if( sd == NULL )
7793 return 0;
7794
7795 trigger=script_getnum(st,2);
7796 clif_skill_produce_mix_list(sd, trigger);
7797 return 0;
7798}
7799/*==========================================
7800 *
7801 *------------------------------------------*/
7802BUILDIN_FUNC(cooking)
7803{
7804 int trigger;
7805 TBL_PC* sd;
7806
7807 sd = script_rid2sd(st);
7808 if( sd == NULL )
7809 return 0;
7810
7811 trigger=script_getnum(st,2);
7812 clif_cooking_list(sd, trigger);
7813 return 0;
7814}
7815/*==========================================
7816 * NPC‚ŃyÆ’bÆ’gÂì‚é
7817 *------------------------------------------*/
7818BUILDIN_FUNC(makepet)
7819{
7820 TBL_PC* sd;
7821 int id,pet_id;
7822
7823 id=script_getnum(st,2);
7824 sd = script_rid2sd(st);
7825 if( sd == NULL )
7826 return 0;
7827
7828 pet_id = search_petDB_index(id, PET_CLASS);
7829
7830 if (pet_id < 0)
7831 pet_id = search_petDB_index(id, PET_EGG);
7832 if (pet_id >= 0 && sd) {
7833 sd->catch_target_class = pet_db[pet_id].class_;
7834 intif_create_pet(
7835 sd->status.account_id, sd->status.char_id,
7836 (short)pet_db[pet_id].class_, (short)mob_db(pet_db[pet_id].class_)->lv,
7837 (short)pet_db[pet_id].EggID, 0, (short)pet_db[pet_id].intimate,
7838 100, 0, 1, pet_db[pet_id].jname);
7839 }
7840
7841 return 0;
7842}
7843/*==========================================
7844 * NPC‚ÅŒoŒ±’lÂã‚°‚é
7845 *------------------------------------------*/
7846BUILDIN_FUNC(getexp)
7847{
7848 TBL_PC* sd;
7849 int base=0,job=0;
7850 double bonus;
7851
7852 sd = script_rid2sd(st);
7853 if( sd == NULL )
7854 return 0;
7855
7856 base=script_getnum(st,2);
7857 job =script_getnum(st,3);
7858 if(base<0 || job<0)
7859 return 0;
7860
7861 // bonus for npc-given exp
7862 bonus = battle_config.quest_exp_rate / 100.;
7863 base = (int) cap_value(base * bonus, 0, INT_MAX);
7864 job = (int) cap_value(job * bonus, 0, INT_MAX);
7865
7866 pc_gainexp(sd, NULL, base, job, true);
7867
7868 return 0;
7869}
7870
7871/*==========================================
7872 * Gain guild exp [Celest]
7873 *------------------------------------------*/
7874BUILDIN_FUNC(guildgetexp)
7875{
7876 TBL_PC* sd;
7877 int exp;
7878
7879 sd = script_rid2sd(st);
7880 if( sd == NULL )
7881 return 0;
7882
7883 exp = script_getnum(st,2);
7884 if(exp < 0)
7885 return 0;
7886 if(sd && sd->status.guild_id > 0)
7887 guild_getexp (sd, exp);
7888
7889 return 0;
7890}
7891
7892/*==========================================
7893 * Changes the guild master of a guild [Skotlex]
7894 *------------------------------------------*/
7895BUILDIN_FUNC(guildchangegm)
7896{
7897 TBL_PC *sd;
7898 int guild_id;
7899 const char *name;
7900
7901 guild_id = script_getnum(st,2);
7902 name = script_getstr(st,3);
7903 sd=map_nick2sd(name);
7904
7905 if (!sd)
7906 script_pushint(st,0);
7907 else
7908 script_pushint(st,guild_gm_change(guild_id, sd));
7909
7910 return 0;
7911}
7912
7913/*==========================================
7914 * ƒ‚ƒ“ƒXÆ’^Â[â€Â¶
7915 *------------------------------------------*/
7916BUILDIN_FUNC(monster)
7917{
7918 const char* mapn = script_getstr(st,2);
7919 int x = script_getnum(st,3);
7920 int y = script_getnum(st,4);
7921 const char* str = script_getstr(st,5);
7922 int class_ = script_getnum(st,6);
7923 int amount = script_getnum(st,7);
7924 const char* event = "";
7925
7926 struct map_session_data* sd;
7927 int m;
7928
7929 if( script_hasdata(st,8) )
7930 {
7931 event = script_getstr(st,8);
7932 check_event(st, event);
7933 }
7934
7935 if (class_ >= 0 && !mobdb_checkid(class_)) {
7936 ShowWarning("buildin_monster: Attempted to spawn non-existing monster class %d\n", class_);
7937 return 1;
7938 }
7939
7940 sd = map_id2sd(st->rid);
7941
7942 if( sd && strcmp(mapn,"this") == 0 )
7943 m = sd->bl.m;
7944 else
7945 {
7946 m = map_mapname2mapid(mapn);
7947 if( map[m].flag.src4instance && st->instance_id )
7948 { // Try to redirect to the instance map, not the src map
7949 if( (m = instance_mapid2imapid(m, st->instance_id)) < 0 )
7950 {
7951 ShowError("buildin_monster: Trying to spawn monster (%d) on instance map (%s) without instance attached.\n", class_, mapn);
7952 return 1;
7953 }
7954 }
7955 }
7956
7957 mob_once_spawn(sd,m,x,y,str,class_,amount,event);
7958 return 0;
7959}
7960/*==========================================
7961 * Request List of Monster Drops
7962 *------------------------------------------*/
7963BUILDIN_FUNC(getmobdrops)
7964{
7965 int class_ = script_getnum(st,2);
7966 int i, j = 0;
7967 struct mob_db *mob;
7968
7969 if( !mobdb_checkid(class_) )
7970 {
7971 script_pushint(st, 0);
7972 return 0;
7973 }
7974
7975 mob = mob_db(class_);
7976
7977 for( i = 0; i < MAX_MOB_DROP; i++ )
7978 {
7979 if( mob->dropitem[i].nameid < 1 )
7980 continue;
7981 if( itemdb_exists(mob->dropitem[i].nameid) == NULL )
7982 continue;
7983
7984 mapreg_setreg(reference_uid(add_str("$@MobDrop_item"), j), mob->dropitem[i].nameid);
7985 mapreg_setreg(reference_uid(add_str("$@MobDrop_rate"), j), mob->dropitem[i].p);
7986
7987 j++;
7988 }
7989
7990 mapreg_setreg(add_str("$@MobDrop_count"), j);
7991 script_pushint(st, 1);
7992
7993 return 0;
7994}
7995/*==========================================
7996 * ƒ‚ƒ“ƒXÆ’^Â[â€Â¶
7997 *------------------------------------------*/
7998BUILDIN_FUNC(areamonster)
7999{
8000 const char* mapn = script_getstr(st,2);
8001 int x0 = script_getnum(st,3);
8002 int y0 = script_getnum(st,4);
8003 int x1 = script_getnum(st,5);
8004 int y1 = script_getnum(st,6);
8005 const char* str = script_getstr(st,7);
8006 int class_ = script_getnum(st,8);
8007 int amount = script_getnum(st,9);
8008 const char* event = "";
8009
8010 struct map_session_data* sd;
8011 int m;
8012
8013 if( script_hasdata(st,10) )
8014 {
8015 event = script_getstr(st,10);
8016 check_event(st, event);
8017 }
8018
8019 sd = map_id2sd(st->rid);
8020
8021 if( sd && strcmp(mapn,"this") == 0 )
8022 m = sd->bl.m;
8023 else
8024 {
8025 m = map_mapname2mapid(mapn);
8026 if( map[m].flag.src4instance && st->instance_id )
8027 { // Try to redirect to the instance map, not the src map
8028 if( (m = instance_mapid2imapid(m, st->instance_id)) < 0 )
8029 {
8030 ShowError("buildin_areamonster: Trying to spawn monster (%d) on instance map (%s) without instance attached.\n", class_, mapn);
8031 return 1;
8032 }
8033 }
8034 }
8035
8036 mob_once_spawn_area(sd,m,x0,y0,x1,y1,str,class_,amount,event);
8037 return 0;
8038}
8039/*==========================================
8040 * ƒ‚ƒ“ƒXÆ’^Â[ÂÃÂÅ“
8041 *------------------------------------------*/
8042 static int buildin_killmonster_sub_strip(struct block_list *bl,va_list ap)
8043{ //same fix but with killmonster instead - stripping events from mobs.
8044 TBL_MOB* md = (TBL_MOB*)bl;
8045 char *event=va_arg(ap,char *);
8046 int allflag=va_arg(ap,int);
8047
8048 md->state.npc_killmonster = 1;
8049
8050 if(!allflag){
8051 if(strcmp(event,md->npc_event)==0)
8052 status_kill(bl);
8053 }else{
8054 if(!md->spawn)
8055 status_kill(bl);
8056 }
8057 md->state.npc_killmonster = 0;
8058 return 0;
8059}
8060static int buildin_killmonster_sub(struct block_list *bl,va_list ap)
8061{
8062 TBL_MOB* md = (TBL_MOB*)bl;
8063 char *event=va_arg(ap,char *);
8064 int allflag=va_arg(ap,int);
8065
8066 if(!allflag){
8067 if(strcmp(event,md->npc_event)==0)
8068 status_kill(bl);
8069 }else{
8070 if(!md->spawn)
8071 status_kill(bl);
8072 }
8073 return 0;
8074}
8075BUILDIN_FUNC(killmonster)
8076{
8077 const char *mapname,*event;
8078 int m,allflag=0;
8079 mapname=script_getstr(st,2);
8080 event=script_getstr(st,3);
8081 if(strcmp(event,"All")==0)
8082 allflag = 1;
8083 else
8084 check_event(st, event);
8085
8086 if( (m=map_mapname2mapid(mapname))<0 )
8087 return 0;
8088
8089 if( map[m].flag.src4instance && st->instance_id && (m = instance_mapid2imapid(m, st->instance_id)) < 0 )
8090 return 0;
8091
8092 if( script_hasdata(st,4) ) {
8093 if ( script_getnum(st,4) == 1 ) {
8094 map_foreachinmap(buildin_killmonster_sub, m, BL_MOB, event ,allflag);
8095 return 0;
8096 }
8097 }
8098
8099 map_freeblock_lock();
8100 map_foreachinmap(buildin_killmonster_sub_strip, m, BL_MOB, event ,allflag);
8101 map_freeblock_unlock();
8102 return 0;
8103}
8104
8105static int buildin_killmonsterall_sub_strip(struct block_list *bl,va_list ap)
8106{ //Strips the event from the mob if it's killed the old method.
8107 struct mob_data *md;
8108
8109 md = BL_CAST(BL_MOB, bl);
8110 if (md->npc_event[0])
8111 md->npc_event[0] = 0;
8112
8113 status_kill(bl);
8114 return 0;
8115}
8116static int buildin_killmonsterall_sub(struct block_list *bl,va_list ap)
8117{
8118 status_kill(bl);
8119 return 0;
8120}
8121BUILDIN_FUNC(killmonsterall)
8122{
8123 const char *mapname;
8124 int m;
8125 mapname=script_getstr(st,2);
8126
8127 if( (m = map_mapname2mapid(mapname))<0 )
8128 return 0;
8129
8130 if( map[m].flag.src4instance && st->instance_id && (m = instance_mapid2imapid(m, st->instance_id)) < 0 )
8131 return 0;
8132
8133 if( script_hasdata(st,3) ) {
8134 if ( script_getnum(st,3) == 1 ) {
8135 map_foreachinmap(buildin_killmonsterall_sub,m,BL_MOB);
8136 return 0;
8137 }
8138 }
8139
8140 map_foreachinmap(buildin_killmonsterall_sub_strip,m,BL_MOB);
8141 return 0;
8142}
8143
8144/*==========================================
8145 * Creates a clone of a player.
8146 * clone map, x, y, event, char_id, master_id, mode, flag, duration
8147 *------------------------------------------*/
8148BUILDIN_FUNC(clone)
8149{
8150 TBL_PC *sd, *msd=NULL;
8151 int char_id,master_id=0,x,y, mode = 0, flag = 0, m;
8152 unsigned int duration = 0;
8153 const char *map,*event="";
8154
8155 map=script_getstr(st,2);
8156 x=script_getnum(st,3);
8157 y=script_getnum(st,4);
8158 event=script_getstr(st,5);
8159 char_id=script_getnum(st,6);
8160
8161 if( script_hasdata(st,7) )
8162 master_id=script_getnum(st,7);
8163
8164 if( script_hasdata(st,8) )
8165 mode=script_getnum(st,8);
8166
8167 if( script_hasdata(st,9) )
8168 flag=script_getnum(st,9);
8169
8170 if( script_hasdata(st,10) )
8171 duration=script_getnum(st,10);
8172
8173 check_event(st, event);
8174
8175 m = map_mapname2mapid(map);
8176 if (m < 0) return 0;
8177
8178 sd = map_charid2sd(char_id);
8179
8180 if (master_id) {
8181 msd = map_charid2sd(master_id);
8182 if (msd)
8183 master_id = msd->bl.id;
8184 else
8185 master_id = 0;
8186 }
8187 if (sd) //Return ID of newly crafted clone.
8188 script_pushint(st,mob_clone_spawn(sd, m, x, y, event, master_id, mode, flag, 1000*duration));
8189 else //Failed to create clone.
8190 script_pushint(st,0);
8191
8192 return 0;
8193}
8194/*==========================================
8195 * Æ’CÆ’xƒ“ƒgŽÀÂs
8196 *------------------------------------------*/
8197BUILDIN_FUNC(doevent)
8198{
8199 const char* event = script_getstr(st,2);
8200 struct map_session_data* sd;
8201
8202 if( ( sd = script_rid2sd(st) ) == NULL )
8203 {
8204 return 0;
8205 }
8206
8207 check_event(st, event);
8208 npc_event(sd, event, 0);
8209 return 0;
8210}
8211/*==========================================
8212 * NPCŽå‘̃CÆ’xƒ“ƒgŽÀÂs
8213 *------------------------------------------*/
8214BUILDIN_FUNC(donpcevent)
8215{
8216 const char* event = script_getstr(st,2);
8217 check_event(st, event);
8218 npc_event_do(event);
8219 return 0;
8220}
8221
8222/// for Aegis compatibility
8223/// basically a specialized 'donpcevent', with the event specified as two arguments instead of one
8224BUILDIN_FUNC(cmdothernpc) // Added by RoVeRT
8225{
8226 const char* npc = script_getstr(st,2);
8227 const char* command = script_getstr(st,3);
8228 char event[EVENT_NAME_LENGTH];
8229 snprintf(event, sizeof(event), "%s::OnCommand%s", npc, command);
8230 check_event(st, event);
8231 npc_event_do(event);
8232 return 0;
8233}
8234
8235/*==========================================
8236 * Æ’CÆ’xƒ“ƒgÆ’^Æ’CÆ’}Â[’ljÃ
8237 *------------------------------------------*/
8238BUILDIN_FUNC(addtimer)
8239{
8240 int tick = script_getnum(st,2);
8241 const char* event = script_getstr(st, 3);
8242 TBL_PC* sd;
8243
8244 check_event(st, event);
8245 sd = script_rid2sd(st);
8246 if( sd == NULL )
8247 return 0;
8248
8249 pc_addeventtimer(sd,tick,event);
8250 return 0;
8251}
8252/*==========================================
8253 * Æ’CÆ’xƒ“ƒgÆ’^Æ’CÆ’}Â[ÂÃÂÅ“
8254 *------------------------------------------*/
8255BUILDIN_FUNC(deltimer)
8256{
8257 const char *event;
8258 TBL_PC* sd;
8259
8260 event=script_getstr(st, 2);
8261 sd = script_rid2sd(st);
8262 if( sd == NULL )
8263 return 0;
8264
8265 check_event(st, event);
8266 pc_deleventtimer(sd,event);
8267 return 0;
8268}
8269/*==========================================
8270 * Æ’CÆ’xƒ“ƒgÆ’^Æ’CÆ’}Â[‚̃JÆ’Eƒ“ƒg’l’ljÃ
8271 *------------------------------------------*/
8272BUILDIN_FUNC(addtimercount)
8273{
8274 const char *event;
8275 int tick;
8276 TBL_PC* sd;
8277
8278 event=script_getstr(st, 2);
8279 tick=script_getnum(st,3);
8280 sd = script_rid2sd(st);
8281 if( sd == NULL )
8282 return 0;
8283
8284 check_event(st, event);
8285 pc_addeventtimercount(sd,event,tick);
8286 return 0;
8287}
8288
8289/*==========================================
8290 * NPCÆ’^Æ’CÆ’}Â[‰Šú‰»
8291 *------------------------------------------*/
8292BUILDIN_FUNC(initnpctimer)
8293{
8294 struct npc_data *nd;
8295 int flag = 0;
8296
8297 if( script_hasdata(st,3) )
8298 { //Two arguments: NPC name and attach flag.
8299 nd = npc_name2id(script_getstr(st, 2));
8300 flag = script_getnum(st,3);
8301 }
8302 else if( script_hasdata(st,2) )
8303 { //Check if argument is numeric (flag) or string (npc name)
8304 struct script_data *data;
8305 data = script_getdata(st,2);
8306 get_val(st,data);
8307 if( data_isstring(data) ) //NPC name
8308 nd = npc_name2id(conv_str(st, data));
8309 else if( data_isint(data) ) //Flag
8310 {
8311 nd = (struct npc_data *)map_id2bl(st->oid);
8312 flag = conv_num(st,data);
8313 }
8314 else
8315 {
8316 ShowError("initnpctimer: invalid argument type #1 (needs be int or string)).\n");
8317 return 1;
8318 }
8319 }
8320 else
8321 nd = (struct npc_data *)map_id2bl(st->oid);
8322
8323 if( !nd )
8324 return 0;
8325 if( flag ) //Attach
8326 {
8327 TBL_PC* sd = script_rid2sd(st);
8328 if( sd == NULL )
8329 return 0;
8330 nd->u.scr.rid = sd->bl.id;
8331 }
8332
8333 npc_settimerevent_tick(nd,0);
8334 npc_timerevent_start(nd, st->rid);
8335 return 0;
8336}
8337/*==========================================
8338 * NPCÆ’^Æ’CÆ’}Â[Å JŽn
8339 *------------------------------------------*/
8340BUILDIN_FUNC(startnpctimer)
8341{
8342 struct npc_data *nd;
8343 int flag = 0;
8344
8345 if( script_hasdata(st,3) )
8346 { //Two arguments: NPC name and attach flag.
8347 nd = npc_name2id(script_getstr(st, 2));
8348 flag = script_getnum(st,3);
8349 }
8350 else if( script_hasdata(st,2) )
8351 { //Check if argument is numeric (flag) or string (npc name)
8352 struct script_data *data;
8353 data = script_getdata(st,2);
8354 get_val(st,data);
8355 if( data_isstring(data) ) //NPC name
8356 nd = npc_name2id(conv_str(st, data));
8357 else if( data_isint(data) ) //Flag
8358 {
8359 nd = (struct npc_data *)map_id2bl(st->oid);
8360 flag = conv_num(st,data);
8361 }
8362 else
8363 {
8364 ShowError("initnpctimer: invalid argument type #1 (needs be int or string)).\n");
8365 return 1;
8366 }
8367 }
8368 else
8369 nd=(struct npc_data *)map_id2bl(st->oid);
8370
8371 if( !nd )
8372 return 0;
8373 if( flag ) //Attach
8374 {
8375 TBL_PC* sd = script_rid2sd(st);
8376 if( sd == NULL )
8377 return 0;
8378 nd->u.scr.rid = sd->bl.id;
8379 }
8380
8381 npc_timerevent_start(nd, st->rid);
8382 return 0;
8383}
8384/*==========================================
8385 * NPCÆ’^Æ’CÆ’}Â[’âŽ~
8386 *------------------------------------------*/
8387BUILDIN_FUNC(stopnpctimer)
8388{
8389 struct npc_data *nd;
8390 int flag = 0;
8391
8392 if( script_hasdata(st,3) )
8393 { //Two arguments: NPC name and attach flag.
8394 nd = npc_name2id(script_getstr(st, 2));
8395 flag = script_getnum(st,3);
8396 }
8397 else if( script_hasdata(st,2) )
8398 { //Check if argument is numeric (flag) or string (npc name)
8399 struct script_data *data;
8400 data = script_getdata(st,2);
8401 get_val(st,data);
8402 if( data_isstring(data) ) //NPC name
8403 nd = npc_name2id(conv_str(st, data));
8404 else if( data_isint(data) ) //Flag
8405 {
8406 nd = (struct npc_data *)map_id2bl(st->oid);
8407 flag = conv_num(st,data);
8408 }
8409 else
8410 {
8411 ShowError("initnpctimer: invalid argument type #1 (needs be int or string)).\n");
8412 return 1;
8413 }
8414 }
8415 else
8416 nd=(struct npc_data *)map_id2bl(st->oid);
8417
8418 if( !nd )
8419 return 0;
8420 if( flag ) //Detach
8421 nd->u.scr.rid = 0;
8422
8423 npc_timerevent_stop(nd);
8424 return 0;
8425}
8426/*==========================================
8427 * NPCÆ’^Æ’CÆ’}Â[Âî•ñŠ“¾
8428 *------------------------------------------*/
8429BUILDIN_FUNC(getnpctimer)
8430{
8431 struct npc_data *nd;
8432 TBL_PC *sd;
8433 int type = script_getnum(st,2);
8434 int val = 0;
8435
8436 if( script_hasdata(st,3) )
8437 nd = npc_name2id(script_getstr(st,3));
8438 else
8439 nd = (struct npc_data *)map_id2bl(st->oid);
8440
8441 if( !nd || nd->bl.type != BL_NPC )
8442 {
8443 script_pushint(st,0);
8444 ShowError("getnpctimer: Invalid NPC.\n");
8445 return 1;
8446 }
8447
8448 switch( type )
8449 {
8450 case 0: val = npc_gettimerevent_tick(nd); break;
8451 case 1:
8452 if( nd->u.scr.rid )
8453 {
8454 sd = map_id2sd(nd->u.scr.rid);
8455 if( !sd )
8456 {
8457 ShowError("buildin_getnpctimer: Attached player not found!\n");
8458 break;
8459 }
8460 val = (sd->npc_timer_id != INVALID_TIMER);
8461 }
8462 else
8463 val = (nd->u.scr.timerid != INVALID_TIMER);
8464 break;
8465 case 2: val = nd->u.scr.timeramount; break;
8466 }
8467
8468 script_pushint(st,val);
8469 return 0;
8470}
8471/*==========================================
8472 * NPCÆ’^Æ’CÆ’}Â[’lÂÃ’è
8473 *------------------------------------------*/
8474BUILDIN_FUNC(setnpctimer)
8475{
8476 int tick;
8477 struct npc_data *nd;
8478
8479 tick = script_getnum(st,2);
8480 if( script_hasdata(st,3) )
8481 nd = npc_name2id(script_getstr(st,3));
8482 else
8483 nd = (struct npc_data *)map_id2bl(st->oid);
8484
8485 if( !nd || nd->bl.type != BL_NPC )
8486 {
8487 script_pushint(st,1);
8488 ShowError("setnpctimer: Invalid NPC.\n");
8489 return 1;
8490 }
8491
8492 npc_settimerevent_tick(nd,tick);
8493 script_pushint(st,0);
8494 return 0;
8495}
8496
8497/*==========================================
8498 * attaches the player rid to the timer [Celest]
8499 *------------------------------------------*/
8500BUILDIN_FUNC(attachnpctimer)
8501{
8502 TBL_PC *sd;
8503 struct npc_data *nd = (struct npc_data *)map_id2bl(st->oid);
8504
8505 if( !nd || nd->bl.type != BL_NPC )
8506 {
8507 script_pushint(st,1);
8508 ShowError("setnpctimer: Invalid NPC.\n");
8509 return 1;
8510 }
8511
8512 if( script_hasdata(st,2) )
8513 sd = map_nick2sd(script_getstr(st,2));
8514 else
8515 sd = script_rid2sd(st);
8516
8517 if( !sd )
8518 {
8519 script_pushint(st,1);
8520 ShowWarning("attachnpctimer: Invalid player.\n");
8521 return 1;
8522 }
8523
8524 nd->u.scr.rid = sd->bl.id;
8525 script_pushint(st,0);
8526 return 0;
8527}
8528
8529/*==========================================
8530 * detaches a player rid from the timer [Celest]
8531 *------------------------------------------*/
8532BUILDIN_FUNC(detachnpctimer)
8533{
8534 struct npc_data *nd;
8535
8536 if( script_hasdata(st,2) )
8537 nd = npc_name2id(script_getstr(st,2));
8538 else
8539 nd = (struct npc_data *)map_id2bl(st->oid);
8540
8541 if( !nd || nd->bl.type != BL_NPC )
8542 {
8543 script_pushint(st,1);
8544 ShowError("detachnpctimer: Invalid NPC.\n");
8545 return 1;
8546 }
8547
8548 nd->u.scr.rid = 0;
8549 script_pushint(st,0);
8550 return 0;
8551}
8552
8553/*==========================================
8554 * To avoid "player not attached" script errors, this function is provided,
8555 * it checks if there is a player attached to the current script. [Skotlex]
8556 * If no, returns 0, if yes, returns the account_id of the attached player.
8557 *------------------------------------------*/
8558BUILDIN_FUNC(playerattached)
8559{
8560 if(st->rid == 0 || map_id2sd(st->rid) == NULL)
8561 script_pushint(st,0);
8562 else
8563 script_pushint(st,st->rid);
8564 return 0;
8565}
8566
8567/*==========================================
8568 * “V‚̺ƒAÆ’iÆ’Eƒ“ƒX
8569 *------------------------------------------*/
8570BUILDIN_FUNC(announce)
8571{
8572 const char *mes = script_getstr(st,2);
8573 int flag = script_getnum(st,3);
8574 const char *fontColor = script_hasdata(st,4) ? script_getstr(st,4) : NULL;
8575 int fontType = script_hasdata(st,5) ? script_getnum(st,5) : 0x190; // default fontType (FW_NORMAL)
8576 int fontSize = script_hasdata(st,6) ? script_getnum(st,6) : 12; // default fontSize
8577 int fontAlign = script_hasdata(st,7) ? script_getnum(st,7) : 0; // default fontAlign
8578 int fontY = script_hasdata(st,8) ? script_getnum(st,8) : 0; // default fontY
8579
8580 if (flag&0x0f) // Broadcast source or broadcast region defined
8581 {
8582 send_target target;
8583 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
8584 if (bl == NULL)
8585 return 0;
8586
8587 flag &= 0x07;
8588 target = (flag == 1) ? ALL_SAMEMAP :
8589 (flag == 2) ? AREA :
8590 (flag == 3) ? SELF :
8591 ALL_CLIENT;
8592 if (fontColor)
8593 clif_broadcast2(bl, mes, (int)strlen(mes)+1, strtol(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY, target);
8594 else
8595 clif_broadcast(bl, mes, (int)strlen(mes)+1, flag&0xf0, target);
8596 }
8597 else
8598 {
8599 if (fontColor)
8600 intif_broadcast2(mes, (int)strlen(mes)+1, strtol(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY);
8601 else
8602 intif_broadcast(mes, (int)strlen(mes)+1, flag&0xf0);
8603 }
8604 return 0;
8605}
8606/*==========================================
8607 * “V‚̺ƒAÆ’iÆ’Eƒ“ƒXÂi“Ã’èƒ}Æ’bÆ’vÂj
8608 *------------------------------------------*/
8609static int buildin_announce_sub(struct block_list *bl, va_list ap)
8610{
8611 char *mes = va_arg(ap, char *);
8612 int len = va_arg(ap, int);
8613 int type = va_arg(ap, int);
8614 char *fontColor = va_arg(ap, char *);
8615 short fontType = (short)va_arg(ap, int);
8616 short fontSize = (short)va_arg(ap, int);
8617 short fontAlign = (short)va_arg(ap, int);
8618 short fontY = (short)va_arg(ap, int);
8619 if (fontColor)
8620 clif_broadcast2(bl, mes, len, strtol(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY, SELF);
8621 else
8622 clif_broadcast(bl, mes, len, type, SELF);
8623 return 0;
8624}
8625
8626BUILDIN_FUNC(mapannounce)
8627{
8628 const char *mapname = script_getstr(st,2);
8629 const char *mes = script_getstr(st,3);
8630 int flag = script_getnum(st,4);
8631 const char *fontColor = script_hasdata(st,5) ? script_getstr(st,5) : NULL;
8632 int fontType = script_hasdata(st,6) ? script_getnum(st,6) : 0x190; // default fontType (FW_NORMAL)
8633 int fontSize = script_hasdata(st,7) ? script_getnum(st,7) : 12; // default fontSize
8634 int fontAlign = script_hasdata(st,8) ? script_getnum(st,8) : 0; // default fontAlign
8635 int fontY = script_hasdata(st,9) ? script_getnum(st,9) : 0; // default fontY
8636 int m;
8637
8638 if ((m = map_mapname2mapid(mapname)) < 0)
8639 return 0;
8640
8641 map_foreachinmap(buildin_announce_sub, m, BL_PC,
8642 mes, strlen(mes)+1, flag&0xf0, fontColor, fontType, fontSize, fontAlign, fontY);
8643 return 0;
8644}
8645/*==========================================
8646 * “V‚̺ƒAÆ’iÆ’Eƒ“ƒXÂi“Ã’èƒGÆ’Å Æ’AÂj
8647 *------------------------------------------*/
8648BUILDIN_FUNC(areaannounce)
8649{
8650 const char *mapname = script_getstr(st,2);
8651 int x0 = script_getnum(st,3);
8652 int y0 = script_getnum(st,4);
8653 int x1 = script_getnum(st,5);
8654 int y1 = script_getnum(st,6);
8655 const char *mes = script_getstr(st,7);
8656 int flag = script_getnum(st,8);
8657 const char *fontColor = script_hasdata(st,9) ? script_getstr(st,9) : NULL;
8658 int fontType = script_hasdata(st,10) ? script_getnum(st,10) : 0x190; // default fontType (FW_NORMAL)
8659 int fontSize = script_hasdata(st,11) ? script_getnum(st,11) : 12; // default fontSize
8660 int fontAlign = script_hasdata(st,12) ? script_getnum(st,12) : 0; // default fontAlign
8661 int fontY = script_hasdata(st,13) ? script_getnum(st,13) : 0; // default fontY
8662 int m;
8663
8664 if ((m = map_mapname2mapid(mapname)) < 0)
8665 return 0;
8666
8667 map_foreachinarea(buildin_announce_sub, m, x0, y0, x1, y1, BL_PC,
8668 mes, strlen(mes)+1, flag&0xf0, fontColor, fontType, fontSize, fontAlign, fontY);
8669 return 0;
8670}
8671
8672/*==========================================
8673 * ĠÂ[Æ’UÂ[Ââ€ÂŠ“¾
8674 *------------------------------------------*/
8675BUILDIN_FUNC(getusers)
8676{
8677 int flag, val = 0;
8678 struct map_session_data* sd;
8679 struct block_list* bl = NULL;
8680
8681 flag = script_getnum(st,2);
8682
8683 switch(flag&0x07)
8684 {
8685 case 0:
8686 if(flag&0x8)
8687 {// npc
8688 bl = map_id2bl(st->oid);
8689 }
8690 else if((sd = script_rid2sd(st))!=NULL)
8691 {// pc
8692 bl = &sd->bl;
8693 }
8694
8695 if(bl)
8696 {
8697 val = map[bl->m].users;
8698 }
8699 break;
8700 case 1:
8701 val = map_getusers();
8702 break;
8703 default:
8704 ShowWarning("buildin_getusers: Unknown type %d.\n", flag);
8705 script_pushint(st,0);
8706 return 1;
8707 }
8708
8709 script_pushint(st,val);
8710 return 0;
8711}
8712/*==========================================
8713 * Works like @WHO - displays all online users names in window
8714 *------------------------------------------*/
8715BUILDIN_FUNC(getusersname)
8716{
8717 TBL_PC *sd, *pl_sd;
8718 int disp_num=1;
8719 struct s_mapiterator* iter;
8720
8721 sd = script_rid2sd(st);
8722 if (!sd) return 0;
8723
8724 iter = mapit_getallusers();
8725 for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
8726 {
8727 if( battle_config.hide_GM_session && pc_isGM(pl_sd) )
8728 continue; // skip hidden GMs
8729
8730 if((disp_num++)%10==0)
8731 clif_scriptnext(sd,st->oid);
8732 clif_scriptmes(sd,st->oid,pl_sd->status.name);
8733 }
8734 mapit_free(iter);
8735
8736 return 0;
8737}
8738/*==========================================
8739 * getmapguildusers("mapname",guild ID) Returns the number guild members present on a map [Reddozen]
8740 *------------------------------------------*/
8741BUILDIN_FUNC(getmapguildusers)
8742{
8743 const char *str;
8744 int m, gid;
8745 int i=0,c=0;
8746 struct guild *g = NULL;
8747 str=script_getstr(st,2);
8748 gid=script_getnum(st,3);
8749 if ((m = map_mapname2mapid(str)) < 0) { // map id on this server (m == -1 if not in actual map-server)
8750 script_pushint(st,-1);
8751 return 0;
8752 }
8753 g = guild_search(gid);
8754
8755 if (g){
8756 for(i = 0; i < g->max_member; i++)
8757 {
8758 if (g->member[i].sd && g->member[i].sd->bl.m == m)
8759 c++;
8760 }
8761 }
8762
8763 script_pushint(st,c);
8764 return 0;
8765}
8766/*==========================================
8767 * Æ’}Æ’bÆ’vŽwՏĠÂ[Æ’UÂ[Ââ€ÂŠ“¾
8768 *------------------------------------------*/
8769BUILDIN_FUNC(getmapusers)
8770{
8771 const char *str;
8772 int m;
8773 str=script_getstr(st,2);
8774 if( (m=map_mapname2mapid(str))< 0){
8775 script_pushint(st,-1);
8776 return 0;
8777 }
8778 script_pushint(st,map[m].users);
8779 return 0;
8780}
8781/*==========================================
8782 * Æ’GÆ’Å Æ’AŽwՏĠÂ[Æ’UÂ[Ââ€ÂŠ“¾
8783 *------------------------------------------*/
8784static int buildin_getareausers_sub(struct block_list *bl,va_list ap)
8785{
8786 int *users=va_arg(ap,int *);
8787 (*users)++;
8788 return 0;
8789}
8790BUILDIN_FUNC(getareausers)
8791{
8792 const char *str;
8793 int m,x0,y0,x1,y1,users=0;
8794 str=script_getstr(st,2);
8795 x0=script_getnum(st,3);
8796 y0=script_getnum(st,4);
8797 x1=script_getnum(st,5);
8798 y1=script_getnum(st,6);
8799 if( (m=map_mapname2mapid(str))< 0){
8800 script_pushint(st,-1);
8801 return 0;
8802 }
8803 map_foreachinarea(buildin_getareausers_sub,
8804 m,x0,y0,x1,y1,BL_PC,&users);
8805 script_pushint(st,users);
8806 return 0;
8807}
8808
8809/*==========================================
8810 * Æ’GÆ’Å Æ’AŽw’èƒhÆ’ÂÆ’bÆ’vÆ’AÆ’CÆ’eƒ€Ââ€ÂŠ“¾
8811 *------------------------------------------*/
8812static int buildin_getareadropitem_sub(struct block_list *bl,va_list ap)
8813{
8814 int item=va_arg(ap,int);
8815 int *amount=va_arg(ap,int *);
8816 struct flooritem_data *drop=(struct flooritem_data *)bl;
8817
8818 if(drop->item_data.nameid==item)
8819 (*amount)+=drop->item_data.amount;
8820
8821 return 0;
8822}
8823BUILDIN_FUNC(getareadropitem)
8824{
8825 const char *str;
8826 int m,x0,y0,x1,y1,item,amount=0;
8827 struct script_data *data;
8828
8829 str=script_getstr(st,2);
8830 x0=script_getnum(st,3);
8831 y0=script_getnum(st,4);
8832 x1=script_getnum(st,5);
8833 y1=script_getnum(st,6);
8834
8835 data=script_getdata(st,7);
8836 get_val(st,data);
8837 if( data_isstring(data) ){
8838 const char *name=conv_str(st,data);
8839 struct item_data *item_data = itemdb_searchname(name);
8840 item=UNKNOWN_ITEM_ID;
8841 if( item_data )
8842 item=item_data->nameid;
8843 }else
8844 item=conv_num(st,data);
8845
8846 if( (m=map_mapname2mapid(str))< 0){
8847 script_pushint(st,-1);
8848 return 0;
8849 }
8850 map_foreachinarea(buildin_getareadropitem_sub,
8851 m,x0,y0,x1,y1,BL_ITEM,item,&amount);
8852 script_pushint(st,amount);
8853 return 0;
8854}
8855/*==========================================
8856 * NPC‚Ì—LŒø‰»
8857 *------------------------------------------*/
8858BUILDIN_FUNC(enablenpc)
8859{
8860 const char *str;
8861 str=script_getstr(st,2);
8862 npc_enable(str,1);
8863 return 0;
8864}
8865/*==========================================
8866 * NPC‚Ì–³Œø‰»
8867 *------------------------------------------*/
8868BUILDIN_FUNC(disablenpc)
8869{
8870 const char *str;
8871 str=script_getstr(st,2);
8872 npc_enable(str,0);
8873 return 0;
8874}
8875
8876/*==========================================
8877 * ‰B‚ê‚Ä‚¢‚éNPC‚Ì•\ަ
8878 *------------------------------------------*/
8879BUILDIN_FUNC(hideoffnpc)
8880{
8881 const char *str;
8882 str=script_getstr(st,2);
8883 npc_enable(str,2);
8884 return 0;
8885}
8886/*==========================================
8887 * NPC‚ðƒnƒCƒfƒBƒ“ƒO
8888 *------------------------------------------*/
8889BUILDIN_FUNC(hideonnpc)
8890{
8891 const char *str;
8892 str=script_getstr(st,2);
8893 npc_enable(str,4);
8894 return 0;
8895}
8896
8897/// Starts a status effect on the target unit or on the attached player.
8898///
8899/// sc_start <effect_id>,<duration>,<val1>{,<unit_id>};
8900BUILDIN_FUNC(sc_start)
8901{
8902 struct block_list* bl;
8903 enum sc_type type;
8904 int tick;
8905 int val1;
8906 int val4 = 0;
8907
8908 type = (sc_type)script_getnum(st,2);
8909 tick = script_getnum(st,3);
8910 val1 = script_getnum(st,4);
8911 if( script_hasdata(st,5) )
8912 bl = map_id2bl(script_getnum(st,5));
8913 else
8914 bl = map_id2bl(st->rid);
8915
8916 if( tick == 0 && val1 > 0 && type > SC_NONE && type < SC_MAX && status_sc2skill(type) != 0 )
8917 {// When there isn't a duration specified, try to get it from the skill_db
8918 tick = skill_get_time(status_sc2skill(type), val1);
8919 }
8920
8921 if( potion_flag == 1 && potion_target )
8922 { //skill.c set the flags before running the script, this must be a potion-pitched effect.
8923 bl = map_id2bl(potion_target);
8924 tick /= 2;// Thrown potions only last half.
8925 val4 = 1;// Mark that this was a thrown sc_effect
8926 }
8927
8928 if( bl )
8929 status_change_start(bl, type, 10000, val1, 0, 0, val4, tick, 2);
8930
8931 return 0;
8932}
8933
8934/// Starts a status effect on the target unit or on the attached player.
8935///
8936/// sc_start2 <effect_id>,<duration>,<val1>,<percent chance>{,<unit_id>};
8937BUILDIN_FUNC(sc_start2)
8938{
8939 struct block_list* bl;
8940 enum sc_type type;
8941 int tick;
8942 int val1;
8943 int val4 = 0;
8944 int rate;
8945
8946 type = (sc_type)script_getnum(st,2);
8947 tick = script_getnum(st,3);
8948 val1 = script_getnum(st,4);
8949 rate = script_getnum(st,5);
8950 if( script_hasdata(st,6) )
8951 bl = map_id2bl(script_getnum(st,6));
8952 else
8953 bl = map_id2bl(st->rid);
8954
8955 if( tick == 0 && val1 > 0 && type > SC_NONE && type < SC_MAX && status_sc2skill(type) != 0 )
8956 {// When there isn't a duration specified, try to get it from the skill_db
8957 tick = skill_get_time(status_sc2skill(type), val1);
8958 }
8959
8960 if( potion_flag == 1 && potion_target )
8961 { //skill.c set the flags before running the script, this must be a potion-pitched effect.
8962 bl = map_id2bl(potion_target);
8963 tick /= 2;// Thrown potions only last half.
8964 val4 = 1;// Mark that this was a thrown sc_effect
8965 }
8966
8967 if( bl )
8968 status_change_start(bl, type, rate, val1, 0, 0, val4, tick, 2);
8969
8970 return 0;
8971}
8972
8973/// Starts a status effect on the target unit or on the attached player.
8974///
8975/// sc_start4 <effect_id>,<duration>,<val1>,<val2>,<val3>,<val4>{,<unit_id>};
8976BUILDIN_FUNC(sc_start4)
8977{
8978 struct block_list* bl;
8979 enum sc_type type;
8980 int tick;
8981 int val1;
8982 int val2;
8983 int val3;
8984 int val4;
8985
8986 type = (sc_type)script_getnum(st,2);
8987 tick = script_getnum(st,3);
8988 val1 = script_getnum(st,4);
8989 val2 = script_getnum(st,5);
8990 val3 = script_getnum(st,6);
8991 val4 = script_getnum(st,7);
8992 if( script_hasdata(st,8) )
8993 bl = map_id2bl(script_getnum(st,8));
8994 else
8995 bl = map_id2bl(st->rid);
8996
8997 if( tick == 0 && val1 > 0 && type > SC_NONE && type < SC_MAX && status_sc2skill(type) != 0 )
8998 {// When there isn't a duration specified, try to get it from the skill_db
8999 tick = skill_get_time(status_sc2skill(type), val1);
9000 }
9001
9002 if( potion_flag == 1 && potion_target )
9003 { //skill.c set the flags before running the script, this must be a potion-pitched effect.
9004 bl = map_id2bl(potion_target);
9005 tick /= 2;// Thrown potions only last half.
9006 }
9007
9008 if( bl )
9009 status_change_start(bl, type, 10000, val1, val2, val3, val4, tick, 2);
9010
9011 return 0;
9012}
9013
9014/// Ends one or all status effects on the target unit or on the attached player.
9015///
9016/// sc_end <effect_id>{,<unit_id>};
9017BUILDIN_FUNC(sc_end)
9018{
9019 struct block_list* bl;
9020 int type;
9021
9022 type = script_getnum(st,2);
9023 if( script_hasdata(st,3) )
9024 bl = map_id2bl(script_getnum(st,3));
9025 else
9026 bl = map_id2bl(st->rid);
9027
9028 if( potion_flag==1 && potion_target )
9029 {//##TODO how does this work [FlavioJS]
9030 bl = map_id2bl(potion_target);
9031 }
9032
9033 if( !bl ) return 0;
9034
9035 if( type >= 0 && type < SC_MAX )
9036 {
9037 struct status_change *sc = status_get_sc(bl);
9038 struct status_change_entry *sce = sc?sc->data[type]:NULL;
9039 if (!sce) return 0;
9040 //This should help status_change_end force disabling the SC in case it has no limit.
9041 sce->val1 = sce->val2 = sce->val3 = sce->val4 = 0;
9042 status_change_end(bl, (sc_type)type, INVALID_TIMER);
9043 } else
9044 status_change_clear(bl, 2);// remove all effects
9045 return 0;
9046}
9047
9048/*==========================================
9049 * Âó‘ÔˆÙÂÑë‚ðŒvŽZ‚µ‚½Šm—¦‚ð•Ô‚·
9050 *------------------------------------------*/
9051BUILDIN_FUNC(getscrate)
9052{
9053 struct block_list *bl;
9054 int type,rate;
9055
9056 type=script_getnum(st,2);
9057 rate=script_getnum(st,3);
9058 if( script_hasdata(st,4) ) //Žw’肵‚½ƒLƒƒƒ‰‚̑ë‚ðŒvŽZ‚·‚é
9059 bl = map_id2bl(script_getnum(st,4));
9060 else
9061 bl = map_id2bl(st->rid);
9062
9063 if (bl)
9064 rate = status_get_sc_def(bl, (sc_type)type, 10000, 10000, 0);
9065
9066 script_pushint(st,rate);
9067 return 0;
9068}
9069
9070/*==========================================
9071 *
9072 *------------------------------------------*/
9073BUILDIN_FUNC(debugmes)
9074{
9075 const char *str;
9076 str=script_getstr(st,2);
9077 ShowDebug("script debug : %d %d : %s\n",st->rid,st->oid,str);
9078 return 0;
9079}
9080
9081/*==========================================
9082 *•ߊlƒAƒCƒeƒ€Žg—p
9083 *------------------------------------------*/
9084BUILDIN_FUNC(catchpet)
9085{
9086 int pet_id;
9087 TBL_PC *sd;
9088
9089 pet_id= script_getnum(st,2);
9090 sd=script_rid2sd(st);
9091 if( sd == NULL )
9092 return 0;
9093
9094 pet_catch_process1(sd,pet_id);
9095 return 0;
9096}
9097
9098/*==========================================
9099 * [orn]
9100 *------------------------------------------*/
9101BUILDIN_FUNC(homunculus_evolution)
9102{
9103 TBL_PC *sd;
9104
9105 sd=script_rid2sd(st);
9106 if( sd == NULL )
9107 return 0;
9108
9109 if(merc_is_hom_active(sd->hd))
9110 {
9111 if (sd->hd->homunculus.intimacy > 91000)
9112 merc_hom_evolution(sd->hd);
9113 else
9114 clif_emotion(&sd->hd->bl, E_SWT);
9115 }
9116 return 0;
9117}
9118
9119// [Zephyrus]
9120BUILDIN_FUNC(homunculus_shuffle)
9121{
9122 TBL_PC *sd;
9123
9124 sd=script_rid2sd(st);
9125 if( sd == NULL )
9126 return 0;
9127
9128 if(merc_is_hom_active(sd->hd))
9129 merc_hom_shuffle(sd->hd);
9130
9131 return 0;
9132}
9133
9134//These two functions bring the eA MAPID_* class functionality to scripts.
9135BUILDIN_FUNC(eaclass)
9136{
9137 int class_;
9138 if( script_hasdata(st,2) )
9139 class_ = script_getnum(st,2);
9140 else {
9141 TBL_PC *sd;
9142 sd=script_rid2sd(st);
9143 if (!sd) {
9144 script_pushint(st,-1);
9145 return 0;
9146 }
9147 class_ = sd->status.class_;
9148 }
9149 script_pushint(st,pc_jobid2mapid(class_));
9150 return 0;
9151}
9152
9153BUILDIN_FUNC(roclass)
9154{
9155 int class_ =script_getnum(st,2);
9156 int sex;
9157 if( script_hasdata(st,3) )
9158 sex = script_getnum(st,3);
9159 else {
9160 TBL_PC *sd;
9161 if (st->rid && (sd=script_rid2sd(st)))
9162 sex = sd->status.sex;
9163 else
9164 sex = 1; //Just use male when not found.
9165 }
9166 script_pushint(st,pc_mapid2jobid(class_, sex));
9167 return 0;
9168}
9169
9170/*==========================================
9171 *Œg‘Ñ—‘›z‰»‹@Žg—p
9172 *------------------------------------------*/
9173BUILDIN_FUNC(birthpet)
9174{
9175 TBL_PC *sd;
9176 sd=script_rid2sd(st);
9177 if( sd == NULL )
9178 return 0;
9179
9180 if( sd->status.pet_id )
9181 {// do not send egg list, when you already have a pet
9182 return 0;
9183 }
9184
9185 clif_sendegg(sd);
9186 return 0;
9187}
9188
9189/*==========================================
9190 * Added - AppleGirl For Advanced Classes, (Updated for Cleaner Script Purposes)
9191 *------------------------------------------*/
9192BUILDIN_FUNC(resetlvl)
9193{
9194 TBL_PC *sd;
9195
9196 int type=script_getnum(st,2);
9197
9198 sd=script_rid2sd(st);
9199 if( sd == NULL )
9200 return 0;
9201
9202 pc_resetlvl(sd,type);
9203 return 0;
9204}
9205/*==========================================
9206 * Æ’XÆ’eÂ[Æ’^Æ’XÆ’Å Æ’ZÆ’bÆ’g
9207 *------------------------------------------*/
9208BUILDIN_FUNC(resetstatus)
9209{
9210 TBL_PC *sd;
9211 sd=script_rid2sd(st);
9212 pc_resetstate(sd);
9213 return 0;
9214}
9215
9216/*==========================================
9217 * script command resetskill
9218 *------------------------------------------*/
9219BUILDIN_FUNC(resetskill)
9220{
9221 TBL_PC *sd;
9222 sd=script_rid2sd(st);
9223 pc_resetskill(sd,1);
9224 return 0;
9225}
9226
9227/*==========================================
9228 * Counts total amount of skill points.
9229 *------------------------------------------*/
9230BUILDIN_FUNC(skillpointcount)
9231{
9232 TBL_PC *sd;
9233 sd=script_rid2sd(st);
9234 script_pushint(st,sd->status.skill_point + pc_resetskill(sd,2));
9235 return 0;
9236}
9237
9238/*==========================================
9239 *
9240 *------------------------------------------*/
9241BUILDIN_FUNC(changebase)
9242{
9243 TBL_PC *sd=NULL;
9244 int vclass;
9245
9246 if( script_hasdata(st,3) )
9247 sd=map_id2sd(script_getnum(st,3));
9248 else
9249 sd=script_rid2sd(st);
9250
9251 if(sd == NULL)
9252 return 0;
9253
9254 vclass = script_getnum(st,2);
9255 if(vclass == JOB_WEDDING)
9256 {
9257 if (!battle_config.wedding_modifydisplay || //Do not show the wedding sprites
9258 sd->class_&JOBL_BABY //Baby classes screw up when showing wedding sprites. [Skotlex] They don't seem to anymore.
9259 )
9260 return 0;
9261 }
9262
9263 if(!sd->disguise && vclass != sd->vd.class_) {
9264 status_set_viewdata(&sd->bl, vclass);
9265 //Updated client view. Base, Weapon and Cloth Colors.
9266 clif_changelook(&sd->bl,LOOK_BASE,sd->vd.class_);
9267 clif_changelook(&sd->bl,LOOK_WEAPON,sd->status.weapon);
9268 if (sd->vd.cloth_color)
9269 clif_changelook(&sd->bl,LOOK_CLOTHES_COLOR,sd->vd.cloth_color);
9270 clif_skillinfoblock(sd);
9271 }
9272
9273 return 0;
9274}
9275
9276/*==========================================
9277 * «•ʕÊ·
9278 *------------------------------------------*/
9279BUILDIN_FUNC(changesex)
9280{
9281 TBL_PC *sd = NULL;
9282 sd = script_rid2sd(st);
9283
9284 chrif_changesex(sd);
9285 return 0;
9286}
9287
9288/*==========================================
9289 * Works like 'announce' but outputs in the common chat window
9290 *------------------------------------------*/
9291BUILDIN_FUNC(globalmes)
9292{
9293 struct block_list *bl = map_id2bl(st->oid);
9294 struct npc_data *nd = (struct npc_data *)bl;
9295 const char *name=NULL,*mes;
9296
9297 mes=script_getstr(st,2); // Æ’ÂÆ’bÆ’ZÂ[Æ’W‚̎擾
9298 if(mes==NULL) return 0;
9299
9300 if(script_hasdata(st,3)){ // NPC–¼‚̎擾(123#456)
9301 name=script_getstr(st,3);
9302 } else {
9303 name=nd->name;
9304 }
9305
9306 npc_globalmessage(name,mes); // Æ’OÆ’ÂÂ[Æ’oÆ’â€¹Æ’ÂÆ’bÆ’ZÂ[Æ’W‘—ÂM
9307
9308 return 0;
9309}
9310
9311/////////////////////////////////////////////////////////////////////
9312// NPC waiting room (chat room)
9313//
9314
9315/// Creates a waiting room (chat room) for this npc.
9316///
9317/// waitingroom "<title>",<limit>{,"<event>"{,<trigger>{,<zeny>{,<minlvl>{,<maxlvl>}}}}};
9318BUILDIN_FUNC(waitingroom)
9319{
9320 struct npc_data* nd;
9321 int pub = 1;
9322 const char* title = script_getstr(st, 2);
9323 int limit = script_getnum(st, 3);
9324 const char* ev = script_hasdata(st,4) ? script_getstr(st,4) : "";
9325 int trigger = script_hasdata(st,5) ? script_getnum(st,5) : limit;
9326 int zeny = script_hasdata(st,6) ? script_getnum(st,6) : 0;
9327 int minLvl = script_hasdata(st,7) ? script_getnum(st,7) : 1;
9328 int maxLvl = script_hasdata(st,8) ? script_getnum(st,8) : MAX_LEVEL;
9329
9330 nd = (struct npc_data *)map_id2bl(st->oid);
9331 if( nd != NULL )
9332 chat_createnpcchat(nd, title, limit, pub, trigger, ev, zeny, minLvl, maxLvl);
9333
9334 return 0;
9335}
9336
9337/// Removes the waiting room of the current or target npc.
9338///
9339/// delwaitingroom "<npc_name>";
9340/// delwaitingroom;
9341BUILDIN_FUNC(delwaitingroom)
9342{
9343 struct npc_data* nd;
9344 if( script_hasdata(st,2) )
9345 nd = npc_name2id(script_getstr(st, 2));
9346 else
9347 nd = (struct npc_data *)map_id2bl(st->oid);
9348 if( nd != NULL )
9349 chat_deletenpcchat(nd);
9350 return 0;
9351}
9352
9353/// Kicks all the players from the waiting room of the current or target npc.
9354///
9355/// kickwaitingroomall "<npc_name>";
9356/// kickwaitingroomall;
9357BUILDIN_FUNC(waitingroomkickall)
9358{
9359 struct npc_data* nd;
9360 struct chat_data* cd;
9361
9362 if( script_hasdata(st,2) )
9363 nd = npc_name2id(script_getstr(st,2));
9364 else
9365 nd = (struct npc_data *)map_id2bl(st->oid);
9366
9367 if( nd != NULL && (cd=(struct chat_data *)map_id2bl(nd->chat_id)) != NULL )
9368 chat_npckickall(cd);
9369 return 0;
9370}
9371
9372/// Enables the waiting room event of the current or target npc.
9373///
9374/// enablewaitingroomevent "<npc_name>";
9375/// enablewaitingroomevent;
9376BUILDIN_FUNC(enablewaitingroomevent)
9377{
9378 struct npc_data* nd;
9379 struct chat_data* cd;
9380
9381 if( script_hasdata(st,2) )
9382 nd = npc_name2id(script_getstr(st, 2));
9383 else
9384 nd = (struct npc_data *)map_id2bl(st->oid);
9385
9386 if( nd != NULL && (cd=(struct chat_data *)map_id2bl(nd->chat_id)) != NULL )
9387 chat_enableevent(cd);
9388 return 0;
9389}
9390
9391/// Disables the waiting room event of the current or target npc.
9392///
9393/// disablewaitingroomevent "<npc_name>";
9394/// disablewaitingroomevent;
9395BUILDIN_FUNC(disablewaitingroomevent)
9396{
9397 struct npc_data *nd;
9398 struct chat_data *cd;
9399
9400 if( script_hasdata(st,2) )
9401 nd = npc_name2id(script_getstr(st, 2));
9402 else
9403 nd = (struct npc_data *)map_id2bl(st->oid);
9404
9405 if( nd != NULL && (cd=(struct chat_data *)map_id2bl(nd->chat_id)) != NULL )
9406 chat_disableevent(cd);
9407 return 0;
9408}
9409
9410/// Returns info on the waiting room of the current or target npc.
9411/// Returns -1 if the type unknown
9412/// <type>=0 : current number of users
9413/// <type>=1 : maximum number of users allowed
9414/// <type>=2 : the number of users that trigger the event
9415/// <type>=3 : if the trigger is disabled
9416/// <type>=4 : the title of the waiting room
9417/// <type>=5 : the password of the waiting room
9418/// <type>=16 : the name of the waiting room event
9419/// <type>=32 : if the waiting room is full
9420/// <type>=33 : if there are enough users to trigger the event
9421///
9422/// getwaitingroomstate(<type>,"<npc_name>") -> <info>
9423/// getwaitingroomstate(<type>) -> <info>
9424BUILDIN_FUNC(getwaitingroomstate)
9425{
9426 struct npc_data *nd;
9427 struct chat_data *cd;
9428 int type;
9429
9430 type = script_getnum(st,2);
9431 if( script_hasdata(st,3) )
9432 nd = npc_name2id(script_getstr(st, 3));
9433 else
9434 nd = (struct npc_data *)map_id2bl(st->oid);
9435
9436 if( nd == NULL || (cd=(struct chat_data *)map_id2bl(nd->chat_id)) == NULL )
9437 {
9438 script_pushint(st, -1);
9439 return 0;
9440 }
9441
9442 switch(type)
9443 {
9444 case 0: script_pushint(st, cd->users); break;
9445 case 1: script_pushint(st, cd->limit); break;
9446 case 2: script_pushint(st, cd->trigger&0x7f); break;
9447 case 3: script_pushint(st, ((cd->trigger&0x80)!=0)); break;
9448 case 4: script_pushstrcopy(st, cd->title); break;
9449 case 5: script_pushstrcopy(st, cd->pass); break;
9450 case 16: script_pushstrcopy(st, cd->npc_event);break;
9451 case 32: script_pushint(st, (cd->users >= cd->limit)); break;
9452 case 33: script_pushint(st, (cd->users >= cd->trigger)); break;
9453 default: script_pushint(st, -1); break;
9454 }
9455 return 0;
9456}
9457
9458/// Warps the trigger or target amount of players to the target map and position.
9459/// Players are automatically removed from the waiting room.
9460/// Those waiting the longest will get warped first.
9461/// The target map can be "Random" for a random position in the current map,
9462/// and "SavePoint" for the savepoint map+position.
9463/// The map flag noteleport of the current map is only considered when teleporting to the savepoint.
9464///
9465/// The id's of the teleported players are put into the array $@warpwaitingpc[]
9466/// The total number of teleported players is put into $@warpwaitingpcnum
9467///
9468/// warpwaitingpc "<map name>",<x>,<y>,<number of players>;
9469/// warpwaitingpc "<map name>",<x>,<y>;
9470BUILDIN_FUNC(warpwaitingpc)
9471{
9472 int x;
9473 int y;
9474 int i;
9475 int n;
9476 const char* map_name;
9477 struct npc_data* nd;
9478 struct chat_data* cd;
9479 TBL_PC* sd;
9480
9481 nd = (struct npc_data *)map_id2bl(st->oid);
9482 if( nd == NULL || (cd=(struct chat_data *)map_id2bl(nd->chat_id)) == NULL )
9483 return 0;
9484
9485 map_name = script_getstr(st,2);
9486 x = script_getnum(st,3);
9487 y = script_getnum(st,4);
9488 n = cd->trigger&0x7f;
9489
9490 if( script_hasdata(st,5) )
9491 n = script_getnum(st,5);
9492
9493 for( i = 0; i < n && cd->users > 0; i++ )
9494 {
9495 sd = cd->usersd[0];
9496
9497 if( strcmp(map_name,"SavePoint") == 0 && map[sd->bl.m].flag.noteleport )
9498 {// can't teleport on this map
9499 break;
9500 }
9501
9502 if( cd->zeny )
9503 {// fee set
9504 if( (uint32)sd->status.zeny < cd->zeny )
9505 {// no zeny to cover set fee
9506 break;
9507 }
9508 pc_payzeny(sd, cd->zeny);
9509 }
9510
9511 mapreg_setreg(reference_uid(add_str("$@warpwaitingpc"), i), sd->bl.id);
9512
9513 if( strcmp(map_name,"Random") == 0 )
9514 pc_randomwarp(sd,CLR_TELEPORT);
9515 else if( strcmp(map_name,"SavePoint") == 0 )
9516 pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT);
9517 else
9518 pc_setpos(sd, mapindex_name2id(map_name), x, y, CLR_OUTSIGHT);
9519 }
9520 mapreg_setreg(add_str("$@warpwaitingpcnum"), i);
9521 return 0;
9522}
9523
9524/////////////////////////////////////////////////////////////////////
9525// ...
9526//
9527
9528/// Detaches a character from a script.
9529///
9530/// @param st Script state to detach the character from.
9531static void script_detach_rid(struct script_state* st)
9532{
9533 if(st->rid)
9534 {
9535 script_detach_state(st, false);
9536 st->rid = 0;
9537 }
9538}
9539
9540/*==========================================
9541 * RID‚̃Aƒ^ƒbƒ`
9542 *------------------------------------------*/
9543BUILDIN_FUNC(attachrid)
9544{
9545 int rid = script_getnum(st,2);
9546 struct map_session_data* sd;
9547
9548 if ((sd = map_id2sd(rid))!=NULL) {
9549 script_detach_rid(st);
9550
9551 st->rid = rid;
9552 script_attach_state(st);
9553 script_pushint(st,1);
9554 } else
9555 script_pushint(st,0);
9556 return 0;
9557}
9558/*==========================================
9559 * RID‚̃fƒ^ƒbƒ`
9560 *------------------------------------------*/
9561BUILDIN_FUNC(detachrid)
9562{
9563 script_detach_rid(st);
9564 return 0;
9565}
9566/*==========================================
9567 * ‘¶ÂÃÆ’`Æ’FÆ’bÆ’N
9568 *------------------------------------------*/
9569BUILDIN_FUNC(isloggedin)
9570{
9571 TBL_PC* sd = map_id2sd(script_getnum(st,2));
9572 if (script_hasdata(st,3) && sd &&
9573 sd->status.char_id != script_getnum(st,3))
9574 sd = NULL;
9575 push_val(st->stack,C_INT,sd!=NULL);
9576 return 0;
9577}
9578
9579
9580/*==========================================
9581 *
9582 *------------------------------------------*/
9583BUILDIN_FUNC(setmapflagnosave)
9584{
9585 int m,x,y;
9586 unsigned short mapindex;
9587 const char *str,*str2;
9588
9589 str=script_getstr(st,2);
9590 str2=script_getstr(st,3);
9591 x=script_getnum(st,4);
9592 y=script_getnum(st,5);
9593 m = map_mapname2mapid(str);
9594 mapindex = mapindex_name2id(str2);
9595
9596 if(m >= 0 && mapindex) {
9597 map[m].flag.nosave=1;
9598 map[m].save.map=mapindex;
9599 map[m].save.x=x;
9600 map[m].save.y=y;
9601 }
9602
9603 return 0;
9604}
9605
9606BUILDIN_FUNC(getmapflag)
9607{
9608 int m,i;
9609 const char *str;
9610
9611 str=script_getstr(st,2);
9612 i=script_getnum(st,3);
9613
9614 m = map_mapname2mapid(str);
9615 if(m >= 0) {
9616 switch(i) {
9617 case MF_NOMEMO: script_pushint(st,map[m].flag.nomemo); break;
9618 case MF_NOTELEPORT: script_pushint(st,map[m].flag.noteleport); break;
9619 case MF_NOBRANCH: script_pushint(st,map[m].flag.nobranch); break;
9620 case MF_NOPENALTY: script_pushint(st,map[m].flag.noexppenalty); break;
9621 case MF_NOZENYPENALTY: script_pushint(st,map[m].flag.nozenypenalty); break;
9622 case MF_PVP: script_pushint(st,map[m].flag.pvp); break;
9623 case MF_PVP_NOPARTY: script_pushint(st,map[m].flag.pvp_noparty); break;
9624 case MF_PVP_NOGUILD: script_pushint(st,map[m].flag.pvp_noguild); break;
9625 case MF_GVG: script_pushint(st,map[m].flag.gvg); break;
9626 case MF_GVG_NOPARTY: script_pushint(st,map[m].flag.gvg_noparty); break;
9627 case MF_GVG_DUNGEON: script_pushint(st,map[m].flag.gvg_dungeon); break;
9628 case MF_GVG_CASTLE: script_pushint(st,map[m].flag.gvg_castle); break;
9629 case MF_NOTRADE: script_pushint(st,map[m].flag.notrade); break;
9630 case MF_NODROP: script_pushint(st,map[m].flag.nodrop); break;
9631 case MF_NOSKILL: script_pushint(st,map[m].flag.noskill); break;
9632 case MF_NOWARP: script_pushint(st,map[m].flag.nowarp); break;
9633 case MF_NOICEWALL: script_pushint(st,map[m].flag.noicewall); break;
9634 case MF_SNOW: script_pushint(st,map[m].flag.snow); break;
9635 case MF_CLOUDS: script_pushint(st,map[m].flag.clouds); break;
9636 case MF_CLOUDS2: script_pushint(st,map[m].flag.clouds2); break;
9637 case MF_FOG: script_pushint(st,map[m].flag.fog); break;
9638 case MF_FIREWORKS: script_pushint(st,map[m].flag.fireworks); break;
9639 case MF_SAKURA: script_pushint(st,map[m].flag.sakura); break;
9640 case MF_LEAVES: script_pushint(st,map[m].flag.leaves); break;
9641 case MF_RAIN: script_pushint(st,map[m].flag.rain); break;
9642 case MF_NIGHTENABLED: script_pushint(st,map[m].flag.nightenabled); break;
9643 case MF_NOGO: script_pushint(st,map[m].flag.nogo); break;
9644 case MF_NOBASEEXP: script_pushint(st,map[m].flag.nobaseexp); break;
9645 case MF_NOJOBEXP: script_pushint(st,map[m].flag.nojobexp); break;
9646 case MF_NOMOBLOOT: script_pushint(st,map[m].flag.nomobloot); break;
9647 case MF_NOMVPLOOT: script_pushint(st,map[m].flag.nomvploot); break;
9648 case MF_NORETURN: script_pushint(st,map[m].flag.noreturn); break;
9649 case MF_NOWARPTO: script_pushint(st,map[m].flag.nowarpto); break;
9650 case MF_NIGHTMAREDROP: script_pushint(st,map[m].flag.pvp_nightmaredrop); break;
9651 case MF_RESTRICTED: script_pushint(st,map[m].flag.restricted); break;
9652 case MF_NOCOMMAND: script_pushint(st,map[m].nocommand); break;
9653 case MF_JEXP: script_pushint(st,map[m].jexp); break;
9654 case MF_BEXP: script_pushint(st,map[m].bexp); break;
9655 case MF_NOVENDING: script_pushint(st,map[m].flag.novending); break;
9656 case MF_LOADEVENT: script_pushint(st,map[m].flag.loadevent); break;
9657 case MF_NOCHAT: script_pushint(st,map[m].flag.nochat); break;
9658 case MF_PARTYLOCK: script_pushint(st,map[m].flag.partylock); break;
9659 case MF_GUILDLOCK: script_pushint(st,map[m].flag.guildlock); break;
9660 case MF_TOWN: script_pushint(st,map[m].flag.town); break;
9661 case MF_AUTOTRADE: script_pushint(st,map[m].flag.autotrade); break;
9662 case MF_ALLOWKS: script_pushint(st,map[m].flag.allowks); break;
9663 case MF_MONSTER_NOTELEPORT: script_pushint(st,map[m].flag.monster_noteleport); break;
9664 case MF_PVP_NOCALCRANK: script_pushint(st,map[m].flag.pvp_nocalcrank); break;
9665 case MF_BATTLEGROUND: script_pushint(st,map[m].flag.battleground); break;
9666 case MF_RESET: script_pushint(st,map[m].flag.reset); break;
9667 }
9668 }
9669
9670 return 0;
9671}
9672
9673BUILDIN_FUNC(setmapflag)
9674{
9675 int m,i;
9676 const char *str;
9677 const char *val=NULL;
9678
9679 str=script_getstr(st,2);
9680 i=script_getnum(st,3);
9681 if(script_hasdata(st,4)){
9682 val=script_getstr(st,4);
9683 }
9684 m = map_mapname2mapid(str);
9685 if(m >= 0) {
9686 switch(i) {
9687 case MF_NOMEMO: map[m].flag.nomemo=1; break;
9688 case MF_NOTELEPORT: map[m].flag.noteleport=1; break;
9689 case MF_NOBRANCH: map[m].flag.nobranch=1; break;
9690 case MF_NOPENALTY: map[m].flag.noexppenalty=1; map[m].flag.nozenypenalty=1; break;
9691 case MF_NOZENYPENALTY: map[m].flag.nozenypenalty=1; break;
9692 case MF_PVP: map[m].flag.pvp=1; break;
9693 case MF_PVP_NOPARTY: map[m].flag.pvp_noparty=1; break;
9694 case MF_PVP_NOGUILD: map[m].flag.pvp_noguild=1; break;
9695 case MF_GVG: map[m].flag.gvg=1; break;
9696 case MF_GVG_NOPARTY: map[m].flag.gvg_noparty=1; break;
9697 case MF_GVG_DUNGEON: map[m].flag.gvg_dungeon=1; break;
9698 case MF_GVG_CASTLE: map[m].flag.gvg_castle=1; break;
9699 case MF_NOTRADE: map[m].flag.notrade=1; break;
9700 case MF_NODROP: map[m].flag.nodrop=1; break;
9701 case MF_NOSKILL: map[m].flag.noskill=1; break;
9702 case MF_NOWARP: map[m].flag.nowarp=1; break;
9703 case MF_NOICEWALL: map[m].flag.noicewall=1; break;
9704 case MF_SNOW: map[m].flag.snow=1; break;
9705 case MF_CLOUDS: map[m].flag.clouds=1; break;
9706 case MF_CLOUDS2: map[m].flag.clouds2=1; break;
9707 case MF_FOG: map[m].flag.fog=1; break;
9708 case MF_FIREWORKS: map[m].flag.fireworks=1; break;
9709 case MF_SAKURA: map[m].flag.sakura=1; break;
9710 case MF_LEAVES: map[m].flag.leaves=1; break;
9711 case MF_RAIN: map[m].flag.rain=1; break;
9712 case MF_NIGHTENABLED: map[m].flag.nightenabled=1; break;
9713 case MF_NOGO: map[m].flag.nogo=1; break;
9714 case MF_NOBASEEXP: map[m].flag.nobaseexp=1; break;
9715 case MF_NOJOBEXP: map[m].flag.nojobexp=1; break;
9716 case MF_NOMOBLOOT: map[m].flag.nomobloot=1; break;
9717 case MF_NOMVPLOOT: map[m].flag.nomvploot=1; break;
9718 case MF_NORETURN: map[m].flag.noreturn=1; break;
9719 case MF_NOWARPTO: map[m].flag.nowarpto=1; break;
9720 case MF_NIGHTMAREDROP: map[m].flag.pvp_nightmaredrop=1; break;
9721 case MF_RESTRICTED: map[m].flag.restricted=1; break;
9722 case MF_NOCOMMAND: map[m].nocommand = (!val || atoi(val) <= 0) ? 100 : atoi(val); break;
9723 case MF_JEXP: map[m].jexp = (!val || atoi(val) < 0) ? 100 : atoi(val); break;
9724 case MF_BEXP: map[m].bexp = (!val || atoi(val) < 0) ? 100 : atoi(val); break;
9725 case MF_NOVENDING: map[m].flag.novending=1; break;
9726 case MF_LOADEVENT: map[m].flag.loadevent=1; break;
9727 case MF_NOCHAT: map[m].flag.nochat=1; break;
9728 case MF_PARTYLOCK: map[m].flag.partylock=1; break;
9729 case MF_GUILDLOCK: map[m].flag.guildlock=1; break;
9730 case MF_TOWN: map[m].flag.town=1; break;
9731 case MF_AUTOTRADE: map[m].flag.autotrade=1; break;
9732 case MF_ALLOWKS: map[m].flag.allowks=1; break;
9733 case MF_MONSTER_NOTELEPORT: map[m].flag.monster_noteleport=1; break;
9734 case MF_PVP_NOCALCRANK: map[m].flag.pvp_nocalcrank=1; break;
9735 case MF_BATTLEGROUND: map[m].flag.battleground = (!val || atoi(val) < 0 || atoi(val) > 2) ? 1 : atoi(val); break;
9736 case MF_RESET: map[m].flag.reset=1; break;
9737 }
9738 }
9739
9740 return 0;
9741}
9742
9743BUILDIN_FUNC(removemapflag)
9744{
9745 int m,i;
9746 const char *str;
9747
9748 str=script_getstr(st,2);
9749 i=script_getnum(st,3);
9750 m = map_mapname2mapid(str);
9751 if(m >= 0) {
9752 switch(i) {
9753 case MF_NOMEMO: map[m].flag.nomemo=0; break;
9754 case MF_NOTELEPORT: map[m].flag.noteleport=0; break;
9755 case MF_NOSAVE: map[m].flag.nosave=0; break;
9756 case MF_NOBRANCH: map[m].flag.nobranch=0; break;
9757 case MF_NOPENALTY: map[m].flag.noexppenalty=0; map[m].flag.nozenypenalty=0; break;
9758 case MF_PVP: map[m].flag.pvp=0; break;
9759 case MF_PVP_NOPARTY: map[m].flag.pvp_noparty=0; break;
9760 case MF_PVP_NOGUILD: map[m].flag.pvp_noguild=0; break;
9761 case MF_GVG: map[m].flag.gvg=0; break;
9762 case MF_GVG_NOPARTY: map[m].flag.gvg_noparty=0; break;
9763 case MF_GVG_DUNGEON: map[m].flag.gvg_dungeon=0; break;
9764 case MF_GVG_CASTLE: map[m].flag.gvg_castle=0; break;
9765 case MF_NOZENYPENALTY: map[m].flag.nozenypenalty=0; break;
9766 case MF_NOTRADE: map[m].flag.notrade=0; break;
9767 case MF_NODROP: map[m].flag.nodrop=0; break;
9768 case MF_NOSKILL: map[m].flag.noskill=0; break;
9769 case MF_NOWARP: map[m].flag.nowarp=0; break;
9770 case MF_NOICEWALL: map[m].flag.noicewall=0; break;
9771 case MF_SNOW: map[m].flag.snow=0; break;
9772 case MF_CLOUDS: map[m].flag.clouds=0; break;
9773 case MF_CLOUDS2: map[m].flag.clouds2=0; break;
9774 case MF_FOG: map[m].flag.fog=0; break;
9775 case MF_FIREWORKS: map[m].flag.fireworks=0; break;
9776 case MF_SAKURA: map[m].flag.sakura=0; break;
9777 case MF_LEAVES: map[m].flag.leaves=0; break;
9778 case MF_RAIN: map[m].flag.rain=0; break;
9779 case MF_NIGHTENABLED: map[m].flag.nightenabled=0; break;
9780 case MF_NOGO: map[m].flag.nogo=0; break;
9781 case MF_NOBASEEXP: map[m].flag.nobaseexp=0; break;
9782 case MF_NOJOBEXP: map[m].flag.nojobexp=0; break;
9783 case MF_NOMOBLOOT: map[m].flag.nomobloot=0; break;
9784 case MF_NOMVPLOOT: map[m].flag.nomvploot=0; break;
9785 case MF_NORETURN: map[m].flag.noreturn=0; break;
9786 case MF_NOWARPTO: map[m].flag.nowarpto=0; break;
9787 case MF_NIGHTMAREDROP: map[m].flag.pvp_nightmaredrop=0; break;
9788 case MF_RESTRICTED: map[m].flag.restricted=0; break;
9789 case MF_NOCOMMAND: map[m].nocommand=0; break;
9790 case MF_JEXP: map[m].jexp=100; break;
9791 case MF_BEXP: map[m].bexp=100; break;
9792 case MF_NOVENDING: map[m].flag.novending=0; break;
9793 case MF_LOADEVENT: map[m].flag.loadevent=0; break;
9794 case MF_NOCHAT: map[m].flag.nochat=0; break;
9795 case MF_PARTYLOCK: map[m].flag.partylock=0; break;
9796 case MF_GUILDLOCK: map[m].flag.guildlock=0; break;
9797 case MF_TOWN: map[m].flag.town=0; break;
9798 case MF_AUTOTRADE: map[m].flag.autotrade=0; break;
9799 case MF_ALLOWKS: map[m].flag.allowks=0; break;
9800 case MF_MONSTER_NOTELEPORT: map[m].flag.monster_noteleport=0; break;
9801 case MF_PVP_NOCALCRANK: map[m].flag.pvp_nocalcrank=0; break;
9802 case MF_BATTLEGROUND: map[m].flag.battleground=0; break;
9803 case MF_RESET: map[m].flag.reset=0; break;
9804 }
9805 }
9806
9807 return 0;
9808}
9809
9810BUILDIN_FUNC(pvpon)
9811{
9812 int m;
9813 const char *str;
9814 TBL_PC* sd = NULL;
9815 struct s_mapiterator* iter;
9816
9817 str = script_getstr(st,2);
9818 m = map_mapname2mapid(str);
9819 if( m < 0 || map[m].flag.pvp )
9820 return 0; // nothing to do
9821
9822 map[m].flag.pvp = 1;
9823 clif_map_property_mapall(m, MAPPROPERTY_FREEPVPZONE);
9824
9825 if(battle_config.pk_mode) // disable ranking functions if pk_mode is on [Valaris]
9826 return 0;
9827
9828 iter = mapit_getallusers();
9829 for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter) )
9830 {
9831 if( sd->bl.m != m || sd->pvp_timer != INVALID_TIMER )
9832 continue; // not applicable
9833
9834 sd->pvp_timer = add_timer(gettick()+200,pc_calc_pvprank_timer,sd->bl.id,0);
9835 sd->pvp_rank = 0;
9836 sd->pvp_lastusers = 0;
9837 sd->pvp_point = 5;
9838 sd->pvp_won = 0;
9839 sd->pvp_lost = 0;
9840 }
9841 mapit_free(iter);
9842
9843 return 0;
9844}
9845
9846static int buildin_pvpoff_sub(struct block_list *bl,va_list ap)
9847{
9848 TBL_PC* sd = (TBL_PC*)bl;
9849 clif_pvpset(sd, 0, 0, 2);
9850 if (sd->pvp_timer != INVALID_TIMER) {
9851 delete_timer(sd->pvp_timer, pc_calc_pvprank_timer);
9852 sd->pvp_timer = INVALID_TIMER;
9853 }
9854 return 0;
9855}
9856
9857BUILDIN_FUNC(pvpoff)
9858{
9859 int m;
9860 const char *str;
9861
9862 str=script_getstr(st,2);
9863 m = map_mapname2mapid(str);
9864 if(m < 0 || !map[m].flag.pvp)
9865 return 0; //fixed Lupus
9866
9867 map[m].flag.pvp = 0;
9868 clif_map_property_mapall(m, MAPPROPERTY_NOTHING);
9869
9870 if(battle_config.pk_mode) // disable ranking options if pk_mode is on [Valaris]
9871 return 0;
9872
9873 map_foreachinmap(buildin_pvpoff_sub, m, BL_PC);
9874 return 0;
9875}
9876
9877BUILDIN_FUNC(gvgon)
9878{
9879 int m;
9880 const char *str;
9881
9882 str=script_getstr(st,2);
9883 m = map_mapname2mapid(str);
9884 if(m >= 0 && !map[m].flag.gvg) {
9885 map[m].flag.gvg = 1;
9886 clif_map_property_mapall(m, MAPPROPERTY_AGITZONE);
9887 }
9888
9889 return 0;
9890}
9891BUILDIN_FUNC(gvgoff)
9892{
9893 int m;
9894 const char *str;
9895
9896 str=script_getstr(st,2);
9897 m = map_mapname2mapid(str);
9898 if(m >= 0 && map[m].flag.gvg) {
9899 map[m].flag.gvg = 0;
9900 clif_map_property_mapall(m, MAPPROPERTY_NOTHING);
9901 }
9902
9903 return 0;
9904}
9905/*==========================================
9906 * Shows an emoticon on top of the player/npc
9907 * emotion emotion#, <target: 0 - NPC, 1 - PC>, <NPC/PC name>
9908 *------------------------------------------*/
9909//Optional second parameter added by [Skotlex]
9910BUILDIN_FUNC(emotion)
9911{
9912 int type;
9913 int player=0;
9914
9915 type=script_getnum(st,2);
9916 if(type < 0 || type > 100)
9917 return 0;
9918
9919 if( script_hasdata(st,3) )
9920 player=script_getnum(st,3);
9921
9922 if (player) {
9923 TBL_PC *sd = NULL;
9924 if( script_hasdata(st,4) )
9925 sd = map_nick2sd(script_getstr(st,4));
9926 else
9927 sd = script_rid2sd(st);
9928 if (sd)
9929 clif_emotion(&sd->bl,type);
9930 } else
9931 if( script_hasdata(st,4) )
9932 {
9933 TBL_NPC *nd = npc_name2id(script_getstr(st,4));
9934 if(nd)
9935 clif_emotion(&nd->bl,type);
9936 }
9937 else
9938 clif_emotion(map_id2bl(st->oid),type);
9939 return 0;
9940}
9941
9942static int buildin_maprespawnguildid_sub_pc(struct map_session_data* sd, va_list ap)
9943{
9944 int m=va_arg(ap,int);
9945 int g_id=va_arg(ap,int);
9946 int flag=va_arg(ap,int);
9947
9948 if(!sd || sd->bl.m != m)
9949 return 0;
9950 if(
9951 (sd->status.guild_id == g_id && flag&1) || //Warp out owners
9952 (sd->status.guild_id != g_id && flag&2) || //Warp out outsiders
9953 (sd->status.guild_id == 0) // Warp out players not in guild [Valaris]
9954 )
9955 pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
9956 return 1;
9957}
9958
9959static int buildin_maprespawnguildid_sub_mob(struct block_list *bl,va_list ap)
9960{
9961 struct mob_data *md=(struct mob_data *)bl;
9962
9963 if(!md->guardian_data && md->class_ != MOBID_EMPERIUM)
9964 status_kill(bl);
9965
9966 return 0;
9967}
9968
9969BUILDIN_FUNC(maprespawnguildid)
9970{
9971 const char *mapname=script_getstr(st,2);
9972 int g_id=script_getnum(st,3);
9973 int flag=script_getnum(st,4);
9974
9975 int m=map_mapname2mapid(mapname);
9976
9977 if(m == -1)
9978 return 0;
9979
9980 //Catch ALL players (in case some are 'between maps' on execution time)
9981 map_foreachpc(buildin_maprespawnguildid_sub_pc,m,g_id,flag);
9982 if (flag&4) //Remove script mobs.
9983 map_foreachinmap(buildin_maprespawnguildid_sub_mob,m,BL_MOB);
9984 return 0;
9985}
9986
9987BUILDIN_FUNC(agitstart)
9988{
9989 if(agit_flag==1) return 0; // Agit already Start.
9990 agit_flag=1;
9991 guild_agit_start();
9992 return 0;
9993}
9994
9995BUILDIN_FUNC(agitend)
9996{
9997 if(agit_flag==0) return 0; // Agit already End.
9998 agit_flag=0;
9999 guild_agit_end();
10000 return 0;
10001}
10002
10003BUILDIN_FUNC(agitstart2)
10004{
10005 if(agit2_flag==1) return 0; // Agit2 already Start.
10006 agit2_flag=1;
10007 guild_agit2_start();
10008 return 0;
10009}
10010
10011BUILDIN_FUNC(agitend2)
10012{
10013 if(agit2_flag==0) return 0; // Agit2 already End.
10014 agit2_flag=0;
10015 guild_agit2_end();
10016 return 0;
10017}
10018
10019/*==========================================
10020 * Returns whether woe is on or off. // choice script
10021 *------------------------------------------*/
10022BUILDIN_FUNC(agitcheck)
10023{
10024 script_pushint(st,agit_flag);
10025 return 0;
10026}
10027
10028/*==========================================
10029 * Returns whether woese is on or off. // choice script
10030 *------------------------------------------*/
10031BUILDIN_FUNC(agitcheck2)
10032{
10033 script_pushint(st,agit2_flag);
10034 return 0;
10035}
10036
10037/// Sets the guild_id of this npc.
10038///
10039/// flagemblem <guild_id>;
10040BUILDIN_FUNC(flagemblem)
10041{
10042 TBL_NPC* nd;
10043 int g_id=script_getnum(st,2);
10044
10045 if(g_id < 0) return 0;
10046
10047 nd = (TBL_NPC*)map_id2nd(st->oid);
10048 if( nd == NULL )
10049 {
10050 ShowError("script:flagemblem: npc %d not found\n", st->oid);
10051 }
10052 else if( nd->subtype != SCRIPT )
10053 {
10054 ShowError("script:flagemblem: unexpected subtype %d for npc %d '%s'\n", nd->subtype, st->oid, nd->exname);
10055 }
10056 else
10057 {
10058 nd->u.scr.guild_id = g_id;
10059 clif_guild_emblem_area(&nd->bl);
10060 }
10061 return 0;
10062}
10063
10064BUILDIN_FUNC(getcastlename)
10065{
10066 const char* mapname = mapindex_getmapname(script_getstr(st,2),NULL);
10067 struct guild_castle* gc = guild_mapname2gc(mapname);
10068 const char* name = (gc) ? gc->castle_name : "";
10069 script_pushstrcopy(st,name);
10070 return 0;
10071}
10072
10073BUILDIN_FUNC(getcastledata)
10074{
10075 const char* mapname = mapindex_getmapname(script_getstr(st,2),NULL);
10076 int index = script_getnum(st,3);
10077
10078 struct guild_castle* gc = guild_mapname2gc(mapname);
10079
10080 if(script_hasdata(st,4) && index==0 && gc) {
10081 const char* event = script_getstr(st,4);
10082 check_event(st, event);
10083 guild_addcastleinfoevent(gc->castle_id,17,event);
10084 }
10085
10086 if(gc){
10087 switch(index){
10088 case 0: {
10089 int i;
10090 for(i=1;i<18;i++) // Initialize[AgitInit]
10091 guild_castledataload(gc->castle_id,i);
10092 } break;
10093 case 1:
10094 script_pushint(st,gc->guild_id); break;
10095 case 2:
10096 script_pushint(st,gc->economy); break;
10097 case 3:
10098 script_pushint(st,gc->defense); break;
10099 case 4:
10100 script_pushint(st,gc->triggerE); break;
10101 case 5:
10102 script_pushint(st,gc->triggerD); break;
10103 case 6:
10104 script_pushint(st,gc->nextTime); break;
10105 case 7:
10106 script_pushint(st,gc->payTime); break;
10107 case 8:
10108 script_pushint(st,gc->createTime); break;
10109 case 9:
10110 script_pushint(st,gc->visibleC); break;
10111 case 10:
10112 case 11:
10113 case 12:
10114 case 13:
10115 case 14:
10116 case 15:
10117 case 16:
10118 case 17:
10119 script_pushint(st,gc->guardian[index-10].visible); break;
10120 default:
10121 script_pushint(st,0); break;
10122 }
10123 return 0;
10124 }
10125 script_pushint(st,0);
10126 return 0;
10127}
10128
10129BUILDIN_FUNC(setcastledata)
10130{
10131 const char* mapname = mapindex_getmapname(script_getstr(st,2),NULL);
10132 int index = script_getnum(st,3);
10133 int value = script_getnum(st,4);
10134
10135 struct guild_castle* gc = guild_mapname2gc(mapname);
10136
10137 if(gc) {
10138 // Save Data byself First
10139 switch(index){
10140 case 1:
10141 gc->guild_id = value; break;
10142 case 2:
10143 gc->economy = value; break;
10144 case 3:
10145 gc->defense = value; break;
10146 case 4:
10147 gc->triggerE = value; break;
10148 case 5:
10149 gc->triggerD = value; break;
10150 case 6:
10151 gc->nextTime = value; break;
10152 case 7:
10153 gc->payTime = value; break;
10154 case 8:
10155 gc->createTime = value; break;
10156 case 9:
10157 gc->visibleC = value; break;
10158 case 10:
10159 case 11:
10160 case 12:
10161 case 13:
10162 case 14:
10163 case 15:
10164 case 16:
10165 case 17:
10166 gc->guardian[index-10].visible = value; break;
10167 default:
10168 return 0;
10169 }
10170 guild_castledatasave(gc->castle_id,index,value);
10171 }
10172 return 0;
10173}
10174
10175/* =====================================================================
10176 * Æ’Mƒ‹ƒhÂî•ñ‚ð—v‹Â‚·‚é
10177 * ---------------------------------------------------------------------*/
10178BUILDIN_FUNC(requestguildinfo)
10179{
10180 int guild_id=script_getnum(st,2);
10181 const char *event=NULL;
10182
10183 if( script_hasdata(st,3) ){
10184 event=script_getstr(st,3);
10185 check_event(st, event);
10186 }
10187
10188 if(guild_id>0)
10189 guild_npc_request_info(guild_id,event);
10190 return 0;
10191}
10192
10193/// Returns the number of cards that have been compounded onto the specified equipped item.
10194/// getequipcardcnt(<equipment slot>);
10195BUILDIN_FUNC(getequipcardcnt)
10196{
10197 int i=-1,j,num;
10198 TBL_PC *sd;
10199 int count;
10200
10201 num=script_getnum(st,2);
10202 sd=script_rid2sd(st);
10203 if (num > 0 && num <= ARRAYLENGTH(equip))
10204 i=pc_checkequip(sd,equip[num-1]);
10205
10206 if (i < 0 || !sd->inventory_data[i]) {
10207 script_pushint(st,0);
10208 return 0;
10209 }
10210
10211 if(itemdb_isspecial(sd->status.inventory[i].card[0]))
10212 {
10213 script_pushint(st,0);
10214 return 0;
10215 }
10216
10217 count = 0;
10218 for( j = 0; j < sd->inventory_data[i]->slot; j++ )
10219 if( sd->status.inventory[i].card[j] && itemdb_type(sd->status.inventory[i].card[j]) == IT_CARD )
10220 count++;
10221
10222 script_pushint(st,count);
10223 return 0;
10224}
10225
10226/// Removes all cards from the item found in the specified equipment slot of the invoking character,
10227/// and give them to the character. If any cards were removed in this manner, it will also show a success effect.
10228/// successremovecards <slot>;
10229BUILDIN_FUNC(successremovecards)
10230{
10231 int i=-1,j,c,cardflag=0;
10232
10233 TBL_PC* sd = script_rid2sd(st);
10234 int num = script_getnum(st,2);
10235
10236 if (num > 0 && num <= ARRAYLENGTH(equip))
10237 i=pc_checkequip(sd,equip[num-1]);
10238
10239 if (i < 0 || !sd->inventory_data[i]) {
10240 return 0;
10241 }
10242
10243 if(itemdb_isspecial(sd->status.inventory[i].card[0]))
10244 return 0;
10245
10246 for( c = sd->inventory_data[i]->slot - 1; c >= 0; --c )
10247 {
10248 if( sd->status.inventory[i].card[c] && itemdb_type(sd->status.inventory[i].card[c]) == IT_CARD )
10249 {// extract this card from the item
10250 int flag;
10251 struct item item_tmp;
10252 cardflag = 1;
10253 item_tmp.id=0,item_tmp.nameid=sd->status.inventory[i].card[c];
10254 item_tmp.equip=0,item_tmp.identify=1,item_tmp.refine=0;
10255 item_tmp.attribute=0,item_tmp.expire_time=0;
10256 for (j = 0; j < MAX_SLOTS; j++)
10257 item_tmp.card[j]=0;
10258
10259 //Logs items, got from (N)PC scripts [Lupus]
10260 log_pick(&sd->bl, LOG_TYPE_SCRIPT, item_tmp.nameid, 1, NULL);
10261
10262 if((flag=pc_additem(sd,&item_tmp,1))){ // ŽÂ‚ĂȂ¢‚È‚çƒhÆ’ÂÆ’bÆ’v
10263 clif_additem(sd,0,0,flag);
10264 map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0);
10265 }
10266 }
10267 }
10268
10269 if(cardflag == 1)
10270 { // Æ’JÂ[Æ’h‚ðŽæ‚èœ‚¢‚½ƒAÆ’CÆ’eƒ€ÂŠ“¾
10271 int flag;
10272 struct item item_tmp;
10273 item_tmp.id=0,item_tmp.nameid=sd->status.inventory[i].nameid;
10274 item_tmp.equip=0,item_tmp.identify=1,item_tmp.refine=sd->status.inventory[i].refine;
10275 item_tmp.attribute=sd->status.inventory[i].attribute,item_tmp.expire_time=sd->status.inventory[i].expire_time;
10276 for (j = 0; j < sd->inventory_data[i]->slot; j++)
10277 item_tmp.card[j]=0;
10278 for (j = sd->inventory_data[i]->slot; j < MAX_SLOTS; j++)
10279 item_tmp.card[j]=sd->status.inventory[i].card[j];
10280
10281 //Logs items, got from (N)PC scripts [Lupus]
10282 log_pick(&sd->bl, LOG_TYPE_SCRIPT, sd->status.inventory[i].nameid, -1, &sd->status.inventory[i]);
10283
10284 pc_delitem(sd,i,1,0,3);
10285
10286 //Logs items, got from (N)PC scripts [Lupus]
10287 log_pick(&sd->bl, LOG_TYPE_SCRIPT, item_tmp.nameid, 1, &item_tmp);
10288
10289 if((flag=pc_additem(sd,&item_tmp,1))){ // ‚à ‚Ä‚È‚¢‚È‚çƒhÆ’ÂÆ’bÆ’v
10290 clif_additem(sd,0,0,flag);
10291 map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0);
10292 }
10293
10294 clif_misceffect(&sd->bl,3);
10295 }
10296 return 0;
10297}
10298
10299/// Removes all cards from the item found in the specified equipment slot of the invoking character.
10300/// failedremovecards <slot>, <type>;
10301/// <type>=0 : will destroy both the item and the cards.
10302/// <type>=1 : will keep the item, but destroy the cards.
10303/// <type>=2 : will keep the cards, but destroy the item.
10304/// <type>=? : will just display the failure effect.
10305BUILDIN_FUNC(failedremovecards)
10306{
10307 int i=-1,j,c,cardflag=0;
10308
10309 TBL_PC* sd = script_rid2sd(st);
10310 int num = script_getnum(st,2);
10311 int typefail = script_getnum(st,3);
10312
10313 if (num > 0 && num <= ARRAYLENGTH(equip))
10314 i=pc_checkequip(sd,equip[num-1]);
10315
10316 if (i < 0 || !sd->inventory_data[i])
10317 return 0;
10318
10319 if(itemdb_isspecial(sd->status.inventory[i].card[0]))
10320 return 0;
10321
10322 for( c = sd->inventory_data[i]->slot - 1; c >= 0; --c )
10323 {
10324 if( sd->status.inventory[i].card[c] && itemdb_type(sd->status.inventory[i].card[c]) == IT_CARD )
10325 {
10326 cardflag = 1;
10327
10328 if(typefail == 2)
10329 {// add cards to inventory, clear
10330 int flag;
10331 struct item item_tmp;
10332 item_tmp.id=0,item_tmp.nameid=sd->status.inventory[i].card[c];
10333 item_tmp.equip=0,item_tmp.identify=1,item_tmp.refine=0;
10334 item_tmp.attribute=0,item_tmp.expire_time=0;
10335 for (j = 0; j < MAX_SLOTS; j++)
10336 item_tmp.card[j]=0;
10337
10338 //Logs items, got from (N)PC scripts [Lupus]
10339 log_pick(&sd->bl, LOG_TYPE_SCRIPT, item_tmp.nameid, 1, NULL);
10340
10341 if((flag=pc_additem(sd,&item_tmp,1))){
10342 clif_additem(sd,0,0,flag);
10343 map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0);
10344 }
10345 }
10346 }
10347 }
10348
10349 if(cardflag == 1)
10350 {
10351 if(typefail == 0 || typefail == 2){ // •Â‹ï‘¹Ž¸
10352 //Logs items, got from (N)PC scripts [Lupus]
10353 log_pick(&sd->bl, LOG_TYPE_SCRIPT, sd->status.inventory[i].nameid, -1, &sd->status.inventory[i]);
10354
10355 pc_delitem(sd,i,1,0,2);
10356 }
10357 if(typefail == 1){ // Æ’JÂ[Æ’h‚̂Ñ¹Ž¸Âi•‹ï‚ð•Ô‚·Âj
10358 int flag;
10359 struct item item_tmp;
10360 item_tmp.id=0,item_tmp.nameid=sd->status.inventory[i].nameid;
10361 item_tmp.equip=0,item_tmp.identify=1,item_tmp.refine=sd->status.inventory[i].refine;
10362 item_tmp.attribute=sd->status.inventory[i].attribute,item_tmp.expire_time=sd->status.inventory[i].expire_time;
10363
10364 //Logs items, got from (N)PC scripts [Lupus]
10365 log_pick(&sd->bl, LOG_TYPE_SCRIPT, sd->status.inventory[i].nameid, -1, &sd->status.inventory[i]);
10366
10367 for (j = 0; j < sd->inventory_data[i]->slot; j++)
10368 item_tmp.card[j]=0;
10369 for (j = sd->inventory_data[i]->slot; j < MAX_SLOTS; j++)
10370 item_tmp.card[j]=sd->status.inventory[i].card[j];
10371 pc_delitem(sd,i,1,0,2);
10372
10373 //Logs items, got from (N)PC scripts [Lupus]
10374 log_pick(&sd->bl, LOG_TYPE_SCRIPT, item_tmp.nameid, 1, &item_tmp);
10375
10376 if((flag=pc_additem(sd,&item_tmp,1))){
10377 clif_additem(sd,0,0,flag);
10378 map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0);
10379 }
10380 }
10381 clif_misceffect(&sd->bl,2);
10382 }
10383
10384 return 0;
10385}
10386
10387/* ================================================================
10388 * mapwarp "<from map>","<to map>",<x>,<y>,<type>,<ID for Type>;
10389 * type: 0=everyone, 1=guild, 2=party; [Reddozen]
10390 * improved by [Lance]
10391 * ================================================================*/
10392BUILDIN_FUNC(mapwarp) // Added by RoVeRT
10393{
10394 int x,y,m,check_val=0,check_ID=0,i=0;
10395 struct guild *g = NULL;
10396 struct party_data *p = NULL;
10397 const char *str;
10398 const char *mapname;
10399 unsigned int index;
10400 mapname=script_getstr(st,2);
10401 str=script_getstr(st,3);
10402 x=script_getnum(st,4);
10403 y=script_getnum(st,5);
10404 if(script_hasdata(st,7)){
10405 check_val=script_getnum(st,6);
10406 check_ID=script_getnum(st,7);
10407 }
10408
10409 if((m=map_mapname2mapid(mapname))< 0)
10410 return 0;
10411
10412 if(!(index=mapindex_name2id(str)))
10413 return 0;
10414
10415 switch(check_val){
10416 case 1:
10417 g = guild_search(check_ID);
10418 if (g){
10419 for( i=0; i < g->max_member; i++)
10420 {
10421 if(g->member[i].sd && g->member[i].sd->bl.m==m){
10422 pc_setpos(g->member[i].sd,index,x,y,CLR_TELEPORT);
10423 }
10424 }
10425 }
10426 break;
10427 case 2:
10428 p = party_search(check_ID);
10429 if(p){
10430 for(i=0;i<MAX_PARTY; i++){
10431 if(p->data[i].sd && p->data[i].sd->bl.m == m){
10432 pc_setpos(p->data[i].sd,index,x,y,CLR_TELEPORT);
10433 }
10434 }
10435 }
10436 break;
10437 default:
10438 map_foreachinmap(buildin_areawarp_sub,m,BL_PC,index,x,y);
10439 break;
10440 }
10441
10442 return 0;
10443}
10444
10445static int buildin_mobcount_sub(struct block_list *bl,va_list ap) // Added by RoVeRT
10446{
10447 char *event=va_arg(ap,char *);
10448 struct mob_data *md = ((struct mob_data *)bl);
10449 if(strcmp(event,md->npc_event)==0 && md->status.hp > 0)
10450 return 1;
10451 return 0;
10452}
10453
10454BUILDIN_FUNC(mobcount) // Added by RoVeRT
10455{
10456 const char *mapname,*event;
10457 int m;
10458 mapname=script_getstr(st,2);
10459 event=script_getstr(st,3);
10460 check_event(st, event);
10461
10462 if( (m = map_mapname2mapid(mapname)) < 0 ) {
10463 script_pushint(st,-1);
10464 return 0;
10465 }
10466
10467 if( map[m].flag.src4instance && map[m].instance_id == 0 && st->instance_id && (m = instance_mapid2imapid(m, st->instance_id)) < 0 )
10468 {
10469 script_pushint(st,-1);
10470 return 0;
10471 }
10472
10473 script_pushint(st,map_foreachinmap(buildin_mobcount_sub, m, BL_MOB, event));
10474
10475 return 0;
10476}
10477BUILDIN_FUNC(marriage)
10478{
10479 const char *partner=script_getstr(st,2);
10480 TBL_PC *sd=script_rid2sd(st);
10481 TBL_PC *p_sd=map_nick2sd(partner);
10482
10483 if(sd==NULL || p_sd==NULL || pc_marriage(sd,p_sd) < 0){
10484 script_pushint(st,0);
10485 return 0;
10486 }
10487 script_pushint(st,1);
10488 return 0;
10489}
10490BUILDIN_FUNC(wedding_effect)
10491{
10492 TBL_PC *sd=script_rid2sd(st);
10493 struct block_list *bl;
10494
10495 if(sd==NULL) {
10496 bl=map_id2bl(st->oid);
10497 } else
10498 bl=&sd->bl;
10499 clif_wedding_effect(bl);
10500 return 0;
10501}
10502BUILDIN_FUNC(divorce)
10503{
10504 TBL_PC *sd=script_rid2sd(st);
10505 if(sd==NULL || pc_divorce(sd) < 0){
10506 script_pushint(st,0);
10507 return 0;
10508 }
10509 script_pushint(st,1);
10510 return 0;
10511}
10512
10513BUILDIN_FUNC(ispartneron)
10514{
10515 TBL_PC *sd=script_rid2sd(st);
10516
10517 if(sd==NULL || !pc_ismarried(sd) ||
10518 map_charid2sd(sd->status.partner_id) == NULL) {
10519 script_pushint(st,0);
10520 return 0;
10521 }
10522
10523 script_pushint(st,1);
10524 return 0;
10525}
10526
10527BUILDIN_FUNC(getpartnerid)
10528{
10529 TBL_PC *sd=script_rid2sd(st);
10530 if (sd == NULL) {
10531 script_pushint(st,0);
10532 return 0;
10533 }
10534
10535 script_pushint(st,sd->status.partner_id);
10536 return 0;
10537}
10538
10539BUILDIN_FUNC(getchildid)
10540{
10541 TBL_PC *sd=script_rid2sd(st);
10542 if (sd == NULL) {
10543 script_pushint(st,0);
10544 return 0;
10545 }
10546
10547 script_pushint(st,sd->status.child);
10548 return 0;
10549}
10550
10551BUILDIN_FUNC(getmotherid)
10552{
10553 TBL_PC *sd=script_rid2sd(st);
10554 if (sd == NULL) {
10555 script_pushint(st,0);
10556 return 0;
10557 }
10558
10559 script_pushint(st,sd->status.mother);
10560 return 0;
10561}
10562
10563BUILDIN_FUNC(getfatherid)
10564{
10565 TBL_PC *sd=script_rid2sd(st);
10566 if (sd == NULL) {
10567 script_pushint(st,0);
10568 return 0;
10569 }
10570
10571 script_pushint(st,sd->status.father);
10572 return 0;
10573}
10574
10575BUILDIN_FUNC(warppartner)
10576{
10577 int x,y;
10578 unsigned short mapindex;
10579 const char *str;
10580 TBL_PC *sd=script_rid2sd(st);
10581 TBL_PC *p_sd=NULL;
10582
10583 if(sd==NULL || !pc_ismarried(sd) ||
10584 (p_sd=map_charid2sd(sd->status.partner_id)) == NULL) {
10585 script_pushint(st,0);
10586 return 0;
10587 }
10588
10589 str=script_getstr(st,2);
10590 x=script_getnum(st,3);
10591 y=script_getnum(st,4);
10592
10593 mapindex = mapindex_name2id(str);
10594 if (mapindex) {
10595 pc_setpos(p_sd,mapindex,x,y,CLR_OUTSIGHT);
10596 script_pushint(st,1);
10597 } else
10598 script_pushint(st,0);
10599 return 0;
10600}
10601
10602/*================================================
10603 * Script for Displaying MOB Information [Valaris]
10604 *------------------------------------------------*/
10605BUILDIN_FUNC(strmobinfo)
10606{
10607
10608 int num=script_getnum(st,2);
10609 int class_=script_getnum(st,3);
10610
10611 if(!mobdb_checkid(class_))
10612 {
10613 script_pushint(st,0);
10614 return 0;
10615 }
10616
10617 switch (num) {
10618 case 1: script_pushstrcopy(st,mob_db(class_)->name); break;
10619 case 2: script_pushstrcopy(st,mob_db(class_)->jname); break;
10620 case 3: script_pushint(st,mob_db(class_)->lv); break;
10621 case 4: script_pushint(st,mob_db(class_)->status.max_hp); break;
10622 case 5: script_pushint(st,mob_db(class_)->status.max_sp); break;
10623 case 6: script_pushint(st,mob_db(class_)->base_exp); break;
10624 case 7: script_pushint(st,mob_db(class_)->job_exp); break;
10625 default:
10626 script_pushint(st,0);
10627 break;
10628 }
10629 return 0;
10630}
10631
10632/*==========================================
10633 * Summon guardians [Valaris]
10634 * guardian("<map name>",<x>,<y>,"<name to show>",<mob id>{,"<event label>"}{,<guardian index>}) -> <id>
10635 *------------------------------------------*/
10636BUILDIN_FUNC(guardian)
10637{
10638 int class_=0,x=0,y=0,guardian=0;
10639 const char *str,*map,*evt="";
10640 struct script_data *data;
10641 bool has_index = false;
10642
10643 map =script_getstr(st,2);
10644 x =script_getnum(st,3);
10645 y =script_getnum(st,4);
10646 str =script_getstr(st,5);
10647 class_=script_getnum(st,6);
10648
10649 if( script_hasdata(st,8) )
10650 {// "<event label>",<guardian index>
10651 evt=script_getstr(st,7);
10652 guardian=script_getnum(st,8);
10653 has_index = true;
10654 } else if( script_hasdata(st,7) ){
10655 data=script_getdata(st,7);
10656 get_val(st,data);
10657 if( data_isstring(data) )
10658 {// "<event label>"
10659 evt=script_getstr(st,7);
10660 } else if( data_isint(data) )
10661 {// <guardian index>
10662 guardian=script_getnum(st,7);
10663 has_index = true;
10664 } else {
10665 ShowError("script:guardian: invalid data type for argument #6 (from 1)\n");
10666 script_reportdata(data);
10667 return 1;
10668 }
10669 }
10670
10671 check_event(st, evt);
10672 script_pushint(st, mob_spawn_guardian(map,x,y,str,class_,evt,guardian,has_index));
10673
10674 return 0;
10675}
10676/*==========================================
10677 * Invisible Walls [Zephyrus]
10678 *------------------------------------------*/
10679BUILDIN_FUNC(setwall)
10680{
10681 const char *map, *name;
10682 int x, y, m, size, dir;
10683 bool shootable;
10684
10685 map = script_getstr(st,2);
10686 x = script_getnum(st,3);
10687 y = script_getnum(st,4);
10688 size = script_getnum(st,5);
10689 dir = script_getnum(st,6);
10690 shootable = script_getnum(st,7);
10691 name = script_getstr(st,8);
10692
10693 if( (m = map_mapname2mapid(map)) < 0 )
10694 return 0; // Invalid Map
10695
10696 map_iwall_set(m, x, y, size, dir, shootable, name);
10697 return 0;
10698}
10699BUILDIN_FUNC(delwall)
10700{
10701 const char *name = script_getstr(st,2);
10702 map_iwall_remove(name);
10703
10704 return 0;
10705}
10706
10707/// Retrieves various information about the specified guardian.
10708///
10709/// guardianinfo("<map_name>", <index>, <type>) -> <value>
10710/// type: 0 - whether it is deployed or not
10711/// 1 - maximum hp
10712/// 2 - current hp
10713///
10714BUILDIN_FUNC(guardianinfo)
10715{
10716 const char* mapname = mapindex_getmapname(script_getstr(st,2),NULL);
10717 int id = script_getnum(st,3);
10718 int type = script_getnum(st,4);
10719
10720 struct guild_castle* gc = guild_mapname2gc(mapname);
10721 struct mob_data* gd;
10722
10723 if( gc == NULL || id < 0 || id >= MAX_GUARDIANS )
10724 {
10725 script_pushint(st,-1);
10726 return 0;
10727 }
10728
10729 if( type == 0 )
10730 script_pushint(st, gc->guardian[id].visible);
10731 else
10732 if( !gc->guardian[id].visible )
10733 script_pushint(st,-1);
10734 else
10735 if( (gd = map_id2md(gc->guardian[id].id)) == NULL )
10736 script_pushint(st,-1);
10737 else
10738 {
10739 if ( type == 1 ) script_pushint(st,gd->status.max_hp);
10740 else if( type == 2 ) script_pushint(st,gd->status.hp);
10741 else
10742 script_pushint(st,-1);
10743 }
10744
10745 return 0;
10746}
10747
10748/*==========================================
10749 * ID‚©‚çItem–¼
10750 *------------------------------------------*/
10751BUILDIN_FUNC(getitemname)
10752{
10753 int item_id=0;
10754 struct item_data *i_data;
10755 char *item_name;
10756 struct script_data *data;
10757
10758 data=script_getdata(st,2);
10759 get_val(st,data);
10760
10761 if( data_isstring(data) ){
10762 const char *name=conv_str(st,data);
10763 struct item_data *item_data = itemdb_searchname(name);
10764 if( item_data )
10765 item_id=item_data->nameid;
10766 }else
10767 item_id=conv_num(st,data);
10768
10769 i_data = itemdb_exists(item_id);
10770 if (i_data == NULL)
10771 {
10772 script_pushconststr(st,"null");
10773 return 0;
10774 }
10775 item_name=(char *)aMallocA(ITEM_NAME_LENGTH*sizeof(char));
10776
10777 memcpy(item_name, i_data->jname, ITEM_NAME_LENGTH);
10778 script_pushstr(st,item_name);
10779 return 0;
10780}
10781/*==========================================
10782 * Returns number of slots an item has. [Skotlex]
10783 *------------------------------------------*/
10784BUILDIN_FUNC(getitemslots)
10785{
10786 int item_id;
10787 struct item_data *i_data;
10788
10789 item_id=script_getnum(st,2);
10790
10791 i_data = itemdb_exists(item_id);
10792
10793 if (i_data)
10794 script_pushint(st,i_data->slot);
10795 else
10796 script_pushint(st,-1);
10797 return 0;
10798}
10799
10800/*==========================================
10801 * Returns some values of an item [Lupus]
10802 * Price, Weight, etc...
10803 getiteminfo(itemID,n), where n
10804 0 value_buy;
10805 1 value_sell;
10806 2 type;
10807 3 maxchance = Max drop chance of this item e.g. 1 = 0.01% , etc..
10808 if = 0, then monsters don't drop it at all (rare or a quest item)
10809 if = -1, then this item is sold in NPC shops only
10810 4 sex;
10811 5 equip;
10812 6 weight;
10813 7 atk;
10814 8 def;
10815 9 range;
10816 10 slot;
10817 11 look;
10818 12 elv;
10819 13 wlv;
10820 14 view id
10821 *------------------------------------------*/
10822BUILDIN_FUNC(getiteminfo)
10823{
10824 int item_id,n;
10825 int *item_arr;
10826 struct item_data *i_data;
10827
10828 item_id = script_getnum(st,2);
10829 n = script_getnum(st,3);
10830 i_data = itemdb_exists(item_id);
10831
10832 if (i_data && n>=0 && n<=14) {
10833 item_arr = (int*)&i_data->value_buy;
10834 script_pushint(st,item_arr[n]);
10835 } else
10836 script_pushint(st,-1);
10837 return 0;
10838}
10839
10840/*==========================================
10841 * Set some values of an item [Lupus]
10842 * Price, Weight, etc...
10843 setiteminfo(itemID,n,Value), where n
10844 0 value_buy;
10845 1 value_sell;
10846 2 type;
10847 3 maxchance = Max drop chance of this item e.g. 1 = 0.01% , etc..
10848 if = 0, then monsters don't drop it at all (rare or a quest item)
10849 if = -1, then this item is sold in NPC shops only
10850 4 sex;
10851 5 equip;
10852 6 weight;
10853 7 atk;
10854 8 def;
10855 9 range;
10856 10 slot;
10857 11 look;
10858 12 elv;
10859 13 wlv;
10860 14 view id
10861 * Returns Value or -1 if the wrong field's been set
10862 *------------------------------------------*/
10863BUILDIN_FUNC(setiteminfo)
10864{
10865 int item_id,n,value;
10866 int *item_arr;
10867 struct item_data *i_data;
10868
10869 item_id = script_getnum(st,2);
10870 n = script_getnum(st,3);
10871 value = script_getnum(st,4);
10872 i_data = itemdb_exists(item_id);
10873
10874 if (i_data && n>=0 && n<=14) {
10875 item_arr = (int*)&i_data->value_buy;
10876 item_arr[n] = value;
10877 script_pushint(st,value);
10878 } else
10879 script_pushint(st,-1);
10880 return 0;
10881}
10882
10883/*==========================================
10884 * Returns value from equipped item slot n [Lupus]
10885 getequipcardid(num,slot)
10886 where
10887 num = eqip position slot
10888 slot = 0,1,2,3 (Card Slot N)
10889
10890 This func returns CARD ID, 255,254,-255 (for card 0, if the item is produced)
10891 it's useful when you want to check item cards or if it's signed
10892 Useful for such quests as "Sign this refined item with players name" etc
10893 Hat[0] +4 -> Player's Hat[0] +4
10894 *------------------------------------------*/
10895BUILDIN_FUNC(getequipcardid)
10896{
10897 int i=-1,num,slot;
10898 TBL_PC *sd;
10899
10900 num=script_getnum(st,2);
10901 slot=script_getnum(st,3);
10902 sd=script_rid2sd(st);
10903 if (num > 0 && num <= ARRAYLENGTH(equip))
10904 i=pc_checkequip(sd,equip[num-1]);
10905 if(i >= 0 && slot>=0 && slot<4)
10906 script_pushint(st,sd->status.inventory[i].card[slot]);
10907 else
10908 script_pushint(st,0);
10909
10910 return 0;
10911}
10912
10913/*==========================================
10914 * petskillbonus [Valaris] //Rewritten by [Skotlex]
10915 *------------------------------------------*/
10916BUILDIN_FUNC(petskillbonus)
10917{
10918 struct pet_data *pd;
10919
10920 TBL_PC *sd=script_rid2sd(st);
10921
10922 if(sd==NULL || sd->pd==NULL)
10923 return 0;
10924
10925 pd=sd->pd;
10926 if (pd->bonus)
10927 { //Clear previous bonus
10928 if (pd->bonus->timer != INVALID_TIMER)
10929 delete_timer(pd->bonus->timer, pet_skill_bonus_timer);
10930 } else //init
10931 pd->bonus = (struct pet_bonus *) aMalloc(sizeof(struct pet_bonus));
10932
10933 pd->bonus->type=script_getnum(st,2);
10934 pd->bonus->val=script_getnum(st,3);
10935 pd->bonus->duration=script_getnum(st,4);
10936 pd->bonus->delay=script_getnum(st,5);
10937
10938 if (pd->state.skillbonus == 1)
10939 pd->state.skillbonus=0; // waiting state
10940
10941 // wait for timer to start
10942 if (battle_config.pet_equip_required && pd->pet.equip == 0)
10943 pd->bonus->timer = INVALID_TIMER;
10944 else
10945 pd->bonus->timer = add_timer(gettick()+pd->bonus->delay*1000, pet_skill_bonus_timer, sd->bl.id, 0);
10946
10947 return 0;
10948}
10949
10950/*==========================================
10951 * pet looting [Valaris] //Rewritten by [Skotlex]
10952 *------------------------------------------*/
10953BUILDIN_FUNC(petloot)
10954{
10955 int max;
10956 struct pet_data *pd;
10957 TBL_PC *sd=script_rid2sd(st);
10958
10959 if(sd==NULL || sd->pd==NULL)
10960 return 0;
10961
10962 max=script_getnum(st,2);
10963
10964 if(max < 1)
10965 max = 1; //Let'em loot at least 1 item.
10966 else if (max > MAX_PETLOOT_SIZE)
10967 max = MAX_PETLOOT_SIZE;
10968
10969 pd = sd->pd;
10970 if (pd->loot != NULL)
10971 { //Release whatever was there already and reallocate memory
10972 pet_lootitem_drop(pd, pd->msd);
10973 aFree(pd->loot->item);
10974 }
10975 else
10976 pd->loot = (struct pet_loot *)aMalloc(sizeof(struct pet_loot));
10977
10978 pd->loot->item = (struct item *)aCalloc(max,sizeof(struct item));
10979
10980 pd->loot->max=max;
10981 pd->loot->count = 0;
10982 pd->loot->weight = 0;
10983
10984 return 0;
10985}
10986/*==========================================
10987 * PC‚ÌŠŽÂ•iÂî•ñ“ǂÎæ‚è
10988 *------------------------------------------*/
10989BUILDIN_FUNC(getinventorylist)
10990{
10991 TBL_PC *sd=script_rid2sd(st);
10992 char card_var[NAME_LENGTH];
10993
10994 int i,j=0,k;
10995 if(!sd) return 0;
10996 for(i=0;i<MAX_INVENTORY;i++){
10997 if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount > 0){
10998 pc_setreg(sd,reference_uid(add_str("@inventorylist_id"), j),sd->status.inventory[i].nameid);
10999 pc_setreg(sd,reference_uid(add_str("@inventorylist_amount"), j),sd->status.inventory[i].amount);
11000 pc_setreg(sd,reference_uid(add_str("@inventorylist_equip"), j),sd->status.inventory[i].equip);
11001 pc_setreg(sd,reference_uid(add_str("@inventorylist_refine"), j),sd->status.inventory[i].refine);
11002 pc_setreg(sd,reference_uid(add_str("@inventorylist_identify"), j),sd->status.inventory[i].identify);
11003 pc_setreg(sd,reference_uid(add_str("@inventorylist_attribute"), j),sd->status.inventory[i].attribute);
11004 for (k = 0; k < MAX_SLOTS; k++)
11005 {
11006 sprintf(card_var, "@inventorylist_card%d",k+1);
11007 pc_setreg(sd,reference_uid(add_str(card_var), j),sd->status.inventory[i].card[k]);
11008 }
11009 pc_setreg(sd,reference_uid(add_str("@inventorylist_expire"), j),sd->status.inventory[i].expire_time);
11010 j++;
11011 }
11012 }
11013 pc_setreg(sd,add_str("@inventorylist_count"),j);
11014 return 0;
11015}
11016
11017BUILDIN_FUNC(getskilllist)
11018{
11019 TBL_PC *sd=script_rid2sd(st);
11020 int i,j=0;
11021 if(!sd) return 0;
11022 for(i=0;i<MAX_SKILL;i++){
11023 if(sd->status.skill[i].id > 0 && sd->status.skill[i].lv > 0){
11024 pc_setreg(sd,reference_uid(add_str("@skilllist_id"), j),sd->status.skill[i].id);
11025 pc_setreg(sd,reference_uid(add_str("@skilllist_lv"), j),sd->status.skill[i].lv);
11026 pc_setreg(sd,reference_uid(add_str("@skilllist_flag"), j),sd->status.skill[i].flag);
11027 j++;
11028 }
11029 }
11030 pc_setreg(sd,add_str("@skilllist_count"),j);
11031 return 0;
11032}
11033
11034BUILDIN_FUNC(clearitem)
11035{
11036 TBL_PC *sd=script_rid2sd(st);
11037 int i;
11038 if(sd==NULL) return 0;
11039 for (i=0; i<MAX_INVENTORY; i++) {
11040 if (sd->status.inventory[i].amount) {
11041
11042 //Logs items, got from (N)PC scripts [Lupus]
11043 log_pick(&sd->bl, LOG_TYPE_SCRIPT, sd->status.inventory[i].nameid, -sd->status.inventory[i].amount, &sd->status.inventory[i]);
11044
11045 pc_delitem(sd, i, sd->status.inventory[i].amount, 0, 0);
11046 }
11047 }
11048 return 0;
11049}
11050
11051/*==========================================
11052 * Disguise Player (returns Mob/NPC ID if success, 0 on fail)
11053 *------------------------------------------*/
11054BUILDIN_FUNC(disguise)
11055{
11056 int id;
11057 TBL_PC* sd = script_rid2sd(st);
11058 if (sd == NULL) return 0;
11059
11060 id = script_getnum(st,2);
11061
11062 if (mobdb_checkid(id) || npcdb_checkid(id)) {
11063 pc_disguise(sd, id);
11064 script_pushint(st,id);
11065 } else
11066 script_pushint(st,0);
11067
11068 return 0;
11069}
11070
11071/*==========================================
11072 * Undisguise Player (returns 1 if success, 0 on fail)
11073 *------------------------------------------*/
11074BUILDIN_FUNC(undisguise)
11075{
11076 TBL_PC* sd = script_rid2sd(st);
11077 if (sd == NULL) return 0;
11078
11079 if (sd->disguise) {
11080 pc_disguise(sd, 0);
11081 script_pushint(st,0);
11082 } else {
11083 script_pushint(st,1);
11084 }
11085 return 0;
11086}
11087
11088/*==========================================
11089 * NPCƒNƒ‰ƒXƒ`ƒFƒ“ƒW
11090 * class‚ÕÂÂ肽‚¢class
11091 * type‚Ã’ÊÂÃ0‚Ȃ̂©‚ÈÂH
11092 *------------------------------------------*/
11093BUILDIN_FUNC(classchange)
11094{
11095 int _class,type;
11096 struct block_list *bl=map_id2bl(st->oid);
11097
11098 if(bl==NULL) return 0;
11099
11100 _class=script_getnum(st,2);
11101 type=script_getnum(st,3);
11102 clif_class_change(bl,_class,type);
11103 return 0;
11104}
11105
11106/*==========================================
11107 * NPC‚©‚çâ€Â¶‚·‚éƒGÆ’tÆ’FÆ’NÆ’g
11108 *------------------------------------------*/
11109BUILDIN_FUNC(misceffect)
11110{
11111 int type;
11112
11113 type=script_getnum(st,2);
11114 if(st->oid && st->oid != fake_nd->bl.id) {
11115 struct block_list *bl = map_id2bl(st->oid);
11116 if (bl)
11117 clif_specialeffect(bl,type,AREA);
11118 } else{
11119 TBL_PC *sd=script_rid2sd(st);
11120 if(sd)
11121 clif_specialeffect(&sd->bl,type,AREA);
11122 }
11123 return 0;
11124}
11125/*==========================================
11126 * Play a BGM on a single client [Rikter/Yommy]
11127 *------------------------------------------*/
11128BUILDIN_FUNC(playBGM)
11129{
11130 const char* name;
11131 struct map_session_data* sd;
11132
11133 if( ( sd = script_rid2sd(st) ) != NULL )
11134 {
11135 name = script_getstr(st,2);
11136
11137 clif_playBGM(sd, name);
11138 }
11139
11140 return 0;
11141}
11142
11143static int playBGM_sub(struct block_list* bl,va_list ap)
11144{
11145 const char* name = va_arg(ap,const char*);
11146
11147 clif_playBGM(BL_CAST(BL_PC, bl), name);
11148
11149 return 0;
11150}
11151
11152static int playBGM_foreachpc_sub(struct map_session_data* sd, va_list args)
11153{
11154 const char* name = va_arg(args, const char*);
11155
11156 clif_playBGM(sd, name);
11157 return 0;
11158}
11159
11160/*==========================================
11161 * Play a BGM on multiple client [Rikter/Yommy]
11162 *------------------------------------------*/
11163BUILDIN_FUNC(playBGMall)
11164{
11165 const char* name;
11166
11167 name = script_getstr(st,2);
11168
11169 if( script_hasdata(st,7) )
11170 {// specified part of map
11171 const char* map = script_getstr(st,3);
11172 int x0 = script_getnum(st,4);
11173 int y0 = script_getnum(st,5);
11174 int x1 = script_getnum(st,6);
11175 int y1 = script_getnum(st,7);
11176
11177 map_foreachinarea(playBGM_sub, map_mapname2mapid(map), x0, y0, x1, y1, BL_PC, name);
11178 }
11179 else if( script_hasdata(st,3) )
11180 {// entire map
11181 const char* map = script_getstr(st,3);
11182
11183 map_foreachinmap(playBGM_sub, map_mapname2mapid(map), BL_PC, name);
11184 }
11185 else
11186 {// entire server
11187 map_foreachpc(&playBGM_foreachpc_sub, name);
11188 }
11189
11190 return 0;
11191}
11192
11193/*==========================================
11194 * ƒTƒEƒ“ƒhƒGƒtƒFƒNƒg
11195 *------------------------------------------*/
11196BUILDIN_FUNC(soundeffect)
11197{
11198 TBL_PC* sd = script_rid2sd(st);
11199 const char* name = script_getstr(st,2);
11200 int type = script_getnum(st,3);
11201
11202 if(sd)
11203 {
11204 clif_soundeffect(sd,&sd->bl,name,type);
11205 }
11206 return 0;
11207}
11208
11209int soundeffect_sub(struct block_list* bl,va_list ap)
11210{
11211 char* name = va_arg(ap,char*);
11212 int type = va_arg(ap,int);
11213
11214 clif_soundeffect((TBL_PC *)bl, bl, name, type);
11215
11216 return 0;
11217}
11218
11219/*==========================================
11220 * Play a sound effect (.wav) on multiple clients
11221 * soundeffectall "<filepath>",<type>{,"<map name>"}{,<x0>,<y0>,<x1>,<y1>};
11222 *------------------------------------------*/
11223BUILDIN_FUNC(soundeffectall)
11224{
11225 struct block_list* bl;
11226 const char* name;
11227 int type;
11228
11229 bl = (st->rid) ? &(script_rid2sd(st)->bl) : map_id2bl(st->oid);
11230 if (!bl)
11231 return 0;
11232
11233 name = script_getstr(st,2);
11234 type = script_getnum(st,3);
11235
11236 //FIXME: enumerating map squares (map_foreach) is slower than enumerating the list of online players (map_foreachpc?) [ultramage]
11237
11238 if(!script_hasdata(st,4))
11239 { // area around
11240 clif_soundeffectall(bl, name, type, AREA);
11241 }
11242 else
11243 if(!script_hasdata(st,5))
11244 { // entire map
11245 const char* map = script_getstr(st,4);
11246 map_foreachinmap(soundeffect_sub, map_mapname2mapid(map), BL_PC, name, type);
11247 }
11248 else
11249 if(script_hasdata(st,8))
11250 { // specified part of map
11251 const char* map = script_getstr(st,4);
11252 int x0 = script_getnum(st,5);
11253 int y0 = script_getnum(st,6);
11254 int x1 = script_getnum(st,7);
11255 int y1 = script_getnum(st,8);
11256 map_foreachinarea(soundeffect_sub, map_mapname2mapid(map), x0, y0, x1, y1, BL_PC, name, type);
11257 }
11258 else
11259 {
11260 ShowError("buildin_soundeffectall: insufficient arguments for specific area broadcast.\n");
11261 }
11262
11263 return 0;
11264}
11265/*==========================================
11266 * pet status recovery [Valaris] / Rewritten by [Skotlex]
11267 *------------------------------------------*/
11268BUILDIN_FUNC(petrecovery)
11269{
11270 struct pet_data *pd;
11271 TBL_PC *sd=script_rid2sd(st);
11272
11273 if(sd==NULL || sd->pd==NULL)
11274 return 0;
11275
11276 pd=sd->pd;
11277
11278 if (pd->recovery)
11279 { //Halt previous bonus
11280 if (pd->recovery->timer != INVALID_TIMER)
11281 delete_timer(pd->recovery->timer, pet_recovery_timer);
11282 } else //Init
11283 pd->recovery = (struct pet_recovery *)aMalloc(sizeof(struct pet_recovery));
11284
11285 pd->recovery->type = (sc_type)script_getnum(st,2);
11286 pd->recovery->delay = script_getnum(st,3);
11287 pd->recovery->timer = INVALID_TIMER;
11288
11289 return 0;
11290}
11291
11292/*==========================================
11293 * pet healing [Valaris] //Rewritten by [Skotlex]
11294 *------------------------------------------*/
11295BUILDIN_FUNC(petheal)
11296{
11297 struct pet_data *pd;
11298 TBL_PC *sd=script_rid2sd(st);
11299
11300 if(sd==NULL || sd->pd==NULL)
11301 return 0;
11302
11303 pd=sd->pd;
11304 if (pd->s_skill)
11305 { //Clear previous skill
11306 if (pd->s_skill->timer != INVALID_TIMER)
11307 {
11308 if (pd->s_skill->id)
11309 delete_timer(pd->s_skill->timer, pet_skill_support_timer);
11310 else
11311 delete_timer(pd->s_skill->timer, pet_heal_timer);
11312 }
11313 } else //init memory
11314 pd->s_skill = (struct pet_skill_support *) aMalloc(sizeof(struct pet_skill_support));
11315
11316 pd->s_skill->id=0; //This id identifies that it IS petheal rather than pet_skillsupport
11317 //Use the lv as the amount to heal
11318 pd->s_skill->lv=script_getnum(st,2);
11319 pd->s_skill->delay=script_getnum(st,3);
11320 pd->s_skill->hp=script_getnum(st,4);
11321 pd->s_skill->sp=script_getnum(st,5);
11322
11323 //Use delay as initial offset to avoid skill/heal exploits
11324 if (battle_config.pet_equip_required && pd->pet.equip == 0)
11325 pd->s_skill->timer = INVALID_TIMER;
11326 else
11327 pd->s_skill->timer = add_timer(gettick()+pd->s_skill->delay*1000,pet_heal_timer,sd->bl.id,0);
11328
11329 return 0;
11330}
11331
11332/*==========================================
11333 * pet attack skills [Valaris] //Rewritten by [Skotlex]
11334 *------------------------------------------*/
11335/// petskillattack <skill id>,<level>,<rate>,<bonusrate>
11336/// petskillattack "<skill name>",<level>,<rate>,<bonusrate>
11337BUILDIN_FUNC(petskillattack)
11338{
11339 struct pet_data *pd;
11340 TBL_PC *sd=script_rid2sd(st);
11341
11342 if(sd==NULL || sd->pd==NULL)
11343 return 0;
11344
11345 pd=sd->pd;
11346 if (pd->a_skill == NULL)
11347 pd->a_skill = (struct pet_skill_attack *)aMalloc(sizeof(struct pet_skill_attack));
11348
11349 pd->a_skill->id=( script_isstring(st,2) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
11350 pd->a_skill->lv=script_getnum(st,3);
11351 pd->a_skill->div_ = 0;
11352 pd->a_skill->rate=script_getnum(st,4);
11353 pd->a_skill->bonusrate=script_getnum(st,5);
11354
11355 return 0;
11356}
11357
11358/*==========================================
11359 * pet attack skills [Valaris]
11360 *------------------------------------------*/
11361/// petskillattack2 <skill id>,<level>,<div>,<rate>,<bonusrate>
11362/// petskillattack2 "<skill name>",<level>,<div>,<rate>,<bonusrate>
11363BUILDIN_FUNC(petskillattack2)
11364{
11365 struct pet_data *pd;
11366 TBL_PC *sd=script_rid2sd(st);
11367
11368 if(sd==NULL || sd->pd==NULL)
11369 return 0;
11370
11371 pd=sd->pd;
11372 if (pd->a_skill == NULL)
11373 pd->a_skill = (struct pet_skill_attack *)aMalloc(sizeof(struct pet_skill_attack));
11374
11375 pd->a_skill->id=( script_isstring(st,2) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
11376 pd->a_skill->lv=script_getnum(st,3);
11377 pd->a_skill->div_ = script_getnum(st,4);
11378 pd->a_skill->rate=script_getnum(st,5);
11379 pd->a_skill->bonusrate=script_getnum(st,6);
11380
11381 return 0;
11382}
11383
11384/*==========================================
11385 * pet support skills [Skotlex]
11386 *------------------------------------------*/
11387/// petskillsupport <skill id>,<level>,<delay>,<hp>,<sp>
11388/// petskillsupport "<skill name>",<level>,<delay>,<hp>,<sp>
11389BUILDIN_FUNC(petskillsupport)
11390{
11391 struct pet_data *pd;
11392 TBL_PC *sd=script_rid2sd(st);
11393
11394 if(sd==NULL || sd->pd==NULL)
11395 return 0;
11396
11397 pd=sd->pd;
11398 if (pd->s_skill)
11399 { //Clear previous skill
11400 if (pd->s_skill->timer != INVALID_TIMER)
11401 {
11402 if (pd->s_skill->id)
11403 delete_timer(pd->s_skill->timer, pet_skill_support_timer);
11404 else
11405 delete_timer(pd->s_skill->timer, pet_heal_timer);
11406 }
11407 } else //init memory
11408 pd->s_skill = (struct pet_skill_support *) aMalloc(sizeof(struct pet_skill_support));
11409
11410 pd->s_skill->id=( script_isstring(st,2) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
11411 pd->s_skill->lv=script_getnum(st,3);
11412 pd->s_skill->delay=script_getnum(st,4);
11413 pd->s_skill->hp=script_getnum(st,5);
11414 pd->s_skill->sp=script_getnum(st,6);
11415
11416 //Use delay as initial offset to avoid skill/heal exploits
11417 if (battle_config.pet_equip_required && pd->pet.equip == 0)
11418 pd->s_skill->timer = INVALID_TIMER;
11419 else
11420 pd->s_skill->timer = add_timer(gettick()+pd->s_skill->delay*1000,pet_skill_support_timer,sd->bl.id,0);
11421
11422 return 0;
11423}
11424
11425/*==========================================
11426 * Scripted skill effects [Celest]
11427 *------------------------------------------*/
11428/// skilleffect <skill id>,<level>
11429/// skilleffect "<skill name>",<level>
11430BUILDIN_FUNC(skilleffect)
11431{
11432 TBL_PC *sd;
11433
11434 int skillid=( script_isstring(st,2) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
11435 int skilllv=script_getnum(st,3);
11436 sd=script_rid2sd(st);
11437
11438 clif_skill_nodamage(&sd->bl,&sd->bl,skillid,skilllv,1);
11439
11440 return 0;
11441}
11442
11443/*==========================================
11444 * NPC skill effects [Valaris]
11445 *------------------------------------------*/
11446/// npcskilleffect <skill id>,<level>,<x>,<y>
11447/// npcskilleffect "<skill name>",<level>,<x>,<y>
11448BUILDIN_FUNC(npcskilleffect)
11449{
11450 struct block_list *bl= map_id2bl(st->oid);
11451
11452 int skillid=( script_isstring(st,2) ? skill_name2id(script_getstr(st,2)) : script_getnum(st,2) );
11453 int skilllv=script_getnum(st,3);
11454 int x=script_getnum(st,4);
11455 int y=script_getnum(st,5);
11456
11457 if (bl)
11458 clif_skill_poseffect(bl,skillid,skilllv,x,y,gettick());
11459
11460 return 0;
11461}
11462
11463/*==========================================
11464 * Special effects [Valaris]
11465 *------------------------------------------*/
11466BUILDIN_FUNC(specialeffect)
11467{
11468 struct block_list *bl=map_id2bl(st->oid);
11469 int type = script_getnum(st,2);
11470 enum send_target target = script_hasdata(st,3) ? (send_target)script_getnum(st,3) : AREA;
11471
11472 if(bl==NULL)
11473 return 0;
11474
11475 if( script_hasdata(st,4) )
11476 {
11477 TBL_NPC *nd = npc_name2id(script_getstr(st,4));
11478 if(nd)
11479 clif_specialeffect(&nd->bl, type, target);
11480 }
11481 else
11482 {
11483 if (target == SELF) {
11484 TBL_PC *sd=script_rid2sd(st);
11485 if (sd)
11486 clif_specialeffect_single(bl,type,sd->fd);
11487 } else {
11488 clif_specialeffect(bl, type, target);
11489 }
11490 }
11491
11492 return 0;
11493}
11494
11495BUILDIN_FUNC(specialeffect2)
11496{
11497 TBL_PC *sd=script_rid2sd(st);
11498 int type = script_getnum(st,2);
11499 enum send_target target = script_hasdata(st,3) ? (send_target)script_getnum(st,3) : AREA;
11500
11501 if( script_hasdata(st,4) )
11502 sd = map_nick2sd(script_getstr(st,4));
11503
11504 if (sd)
11505 clif_specialeffect(&sd->bl, type, target);
11506
11507 return 0;
11508}
11509
11510/*==========================================
11511 * Nude [Valaris]
11512 *------------------------------------------*/
11513BUILDIN_FUNC(nude)
11514{
11515 TBL_PC *sd=script_rid2sd(st);
11516 int i,calcflag=0;
11517
11518 if(sd==NULL)
11519 return 0;
11520
11521 for(i=0;i<11;i++)
11522 if(sd->equip_index[i] >= 0) {
11523 if(!calcflag)
11524 calcflag=1;
11525 pc_unequipitem(sd,sd->equip_index[i],2);
11526 }
11527
11528 if(calcflag)
11529 status_calc_pc(sd,0);
11530
11531 return 0;
11532}
11533
11534/*==========================================
11535 * gmcommand [MouseJstr]
11536 *
11537 * suggested on the forums...
11538 * splitted into atcommand & charcommand by [Skotlex]
11539 *------------------------------------------*/
11540BUILDIN_FUNC(atcommand)
11541{
11542 TBL_PC dummy_sd;
11543 TBL_PC* sd;
11544 int fd;
11545 const char* cmd;
11546
11547 cmd = script_getstr(st,2);
11548
11549 if (st->rid) {
11550 sd = script_rid2sd(st);
11551 fd = sd->fd;
11552 } else { //Use a dummy character.
11553 sd = &dummy_sd;
11554 fd = 0;
11555
11556 memset(&dummy_sd, 0, sizeof(TBL_PC));
11557 if (st->oid)
11558 {
11559 struct block_list* bl = map_id2bl(st->oid);
11560 memcpy(&dummy_sd.bl, bl, sizeof(struct block_list));
11561 if (bl->type == BL_NPC)
11562 safestrncpy(dummy_sd.status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH);
11563 }
11564 }
11565
11566 // compatibility with previous implementation (deprecated!)
11567 if(cmd[0] != atcommand_symbol)
11568 {
11569 cmd += strlen(sd->status.name);
11570 while(*cmd != atcommand_symbol && *cmd != 0)
11571 cmd++;
11572 }
11573
11574 is_atcommand(fd, sd, cmd, 0);
11575 return 0;
11576}
11577
11578BUILDIN_FUNC(charcommand)
11579{
11580 TBL_PC dummy_sd;
11581 TBL_PC* sd;
11582 int fd;
11583 const char* cmd;
11584
11585 cmd = script_getstr(st,2);
11586
11587 if (st->rid) {
11588 sd = script_rid2sd(st);
11589 fd = sd->fd;
11590 } else { //Use a dummy character.
11591 sd = &dummy_sd;
11592 fd = 0;
11593
11594 memset(&dummy_sd, 0, sizeof(TBL_PC));
11595 if (st->oid)
11596 {
11597 struct block_list* bl = map_id2bl(st->oid);
11598 memcpy(&dummy_sd.bl, bl, sizeof(struct block_list));
11599 if (bl->type == BL_NPC)
11600 safestrncpy(dummy_sd.status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH);
11601 }
11602 }
11603
11604 if (*cmd != charcommand_symbol) {
11605 ShowWarning("script: buildin_charcommand: No '#' symbol!\n");
11606 script_reportsrc(st);
11607 return 1;
11608 }
11609
11610 is_atcommand(fd, sd, cmd, 0);
11611 return 0;
11612}
11613
11614/*==========================================
11615 * Displays a message for the player only (like system messages like "you got an apple" )
11616 *------------------------------------------*/
11617BUILDIN_FUNC(dispbottom)
11618{
11619 TBL_PC *sd=script_rid2sd(st);
11620 const char *message;
11621 message=script_getstr(st,2);
11622 if(sd)
11623 clif_disp_onlyself(sd,message,(int)strlen(message));
11624 return 0;
11625}
11626
11627/*==========================================
11628 * All The Players Full Recovery
11629 * (HP/SP full restore and resurrect if need)
11630 *------------------------------------------*/
11631BUILDIN_FUNC(recovery)
11632{
11633 TBL_PC* sd;
11634 struct s_mapiterator* iter;
11635
11636 iter = mapit_getallusers();
11637 for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter) )
11638 {
11639 if(pc_isdead(sd))
11640 status_revive(&sd->bl, 100, 100);
11641 else
11642 status_percent_heal(&sd->bl, 100, 100);
11643 clif_displaymessage(sd->fd,"You have been recovered!");
11644 }
11645 mapit_free(iter);
11646 return 0;
11647}
11648/*==========================================
11649 * Get your pet info: getpetinfo(n)
11650 * n -> 0:pet_id 1:pet_class 2:pet_name
11651 * 3:friendly 4:hungry, 5: rename flag.
11652 *------------------------------------------*/
11653BUILDIN_FUNC(getpetinfo)
11654{
11655 TBL_PC *sd=script_rid2sd(st);
11656 TBL_PET *pd;
11657 int type=script_getnum(st,2);
11658
11659 if(!sd || !sd->pd) {
11660 if (type == 2)
11661 script_pushconststr(st,"null");
11662 else
11663 script_pushint(st,0);
11664 return 0;
11665 }
11666 pd = sd->pd;
11667 switch(type){
11668 case 0: script_pushint(st,pd->pet.pet_id); break;
11669 case 1: script_pushint(st,pd->pet.class_); break;
11670 case 2: script_pushstrcopy(st,pd->pet.name); break;
11671 case 3: script_pushint(st,pd->pet.intimate); break;
11672 case 4: script_pushint(st,pd->pet.hungry); break;
11673 case 5: script_pushint(st,pd->pet.rename_flag); break;
11674 default:
11675 script_pushint(st,0);
11676 break;
11677 }
11678 return 0;
11679}
11680
11681/*==========================================
11682 * Get your homunculus info: gethominfo(n)
11683 * n -> 0:hom_id 1:class 2:name
11684 * 3:friendly 4:hungry, 5: rename flag.
11685 * 6: level
11686 *------------------------------------------*/
11687BUILDIN_FUNC(gethominfo)
11688{
11689 TBL_PC *sd=script_rid2sd(st);
11690 TBL_HOM *hd;
11691 int type=script_getnum(st,2);
11692
11693 hd = sd?sd->hd:NULL;
11694 if(!merc_is_hom_active(hd))
11695 {
11696 if (type == 2)
11697 script_pushconststr(st,"null");
11698 else
11699 script_pushint(st,0);
11700 return 0;
11701 }
11702
11703 switch(type){
11704 case 0: script_pushint(st,hd->homunculus.hom_id); break;
11705 case 1: script_pushint(st,hd->homunculus.class_); break;
11706 case 2: script_pushstrcopy(st,hd->homunculus.name); break;
11707 case 3: script_pushint(st,hd->homunculus.intimacy); break;
11708 case 4: script_pushint(st,hd->homunculus.hunger); break;
11709 case 5: script_pushint(st,hd->homunculus.rename_flag); break;
11710 case 6: script_pushint(st,hd->homunculus.level); break;
11711 default:
11712 script_pushint(st,0);
11713 break;
11714 }
11715 return 0;
11716}
11717
11718/// Retrieves information about character's mercenary
11719/// getmercinfo <type>[,<char id>];
11720BUILDIN_FUNC(getmercinfo)
11721{
11722 int type, char_id;
11723 struct map_session_data* sd;
11724 struct mercenary_data* md;
11725
11726 type = script_getnum(st,2);
11727
11728 if( script_hasdata(st,3) )
11729 {
11730 char_id = script_getnum(st,3);
11731
11732 if( ( sd = map_charid2sd(char_id) ) == NULL )
11733 {
11734 ShowError("buildin_getmercinfo: No such character (char_id=%d).\n", char_id);
11735 script_pushnil(st);
11736 return 1;
11737 }
11738 }
11739 else
11740 {
11741 if( ( sd = script_rid2sd(st) ) == NULL )
11742 {
11743 script_pushnil(st);
11744 return 0;
11745 }
11746 }
11747
11748 md = ( sd->status.mer_id && sd->md ) ? sd->md : NULL;
11749
11750 switch( type )
11751 {
11752 case 0: script_pushint(st,md ? md->mercenary.mercenary_id : 0); break;
11753 case 1: script_pushint(st,md ? md->mercenary.class_ : 0); break;
11754 case 2:
11755 if( md )
11756 script_pushstrcopy(st,md->db->name);
11757 else
11758 script_pushconststr(st,"");
11759 break;
11760 case 3: script_pushint(st,md ? mercenary_get_faith(md) : 0); break;
11761 case 4: script_pushint(st,md ? mercenary_get_calls(md) : 0); break;
11762 case 5: script_pushint(st,md ? md->mercenary.kill_count : 0); break;
11763 case 6: script_pushint(st,md ? mercenary_get_lifetime(md) : 0); break;
11764 case 7: script_pushint(st,md ? md->db->lv : 0); break;
11765 default:
11766 ShowError("buildin_getmercinfo: Invalid type %d (char_id=%d).\n", type, sd->status.char_id);
11767 script_pushnil(st);
11768 return 1;
11769 }
11770
11771 return 0;
11772}
11773
11774/*==========================================
11775 * Shows wether your inventory(and equips) contain
11776 selected card or not.
11777 checkequipedcard(4001);
11778 *------------------------------------------*/
11779BUILDIN_FUNC(checkequipedcard)
11780{
11781 TBL_PC *sd=script_rid2sd(st);
11782 int n,i,c=0;
11783 c=script_getnum(st,2);
11784
11785 if(sd){
11786 for(i=0;i<MAX_INVENTORY;i++){
11787 if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount && sd->inventory_data[i]){
11788 if (itemdb_isspecial(sd->status.inventory[i].card[0]))
11789 continue;
11790 for(n=0;n<sd->inventory_data[i]->slot;n++){
11791 if(sd->status.inventory[i].card[n]==c){
11792 script_pushint(st,1);
11793 return 0;
11794 }
11795 }
11796 }
11797 }
11798 }
11799 script_pushint(st,0);
11800 return 0;
11801}
11802
11803BUILDIN_FUNC(jump_zero)
11804{
11805 int sel;
11806 sel=script_getnum(st,2);
11807 if(!sel) {
11808 int pos;
11809 if( !data_islabel(script_getdata(st,3)) ){
11810 ShowError("script: jump_zero: not label !\n");
11811 st->state=END;
11812 return 1;
11813 }
11814
11815 pos=script_getnum(st,3);
11816 st->pos=pos;
11817 st->state=GOTO;
11818 }
11819 return 0;
11820}
11821
11822/*==========================================
11823 * GetMapMobs
11824 returns mob counts on a set map:
11825 e.g. GetMapMobs("prontera")
11826 use "this" - for player's map
11827 *------------------------------------------*/
11828BUILDIN_FUNC(getmapmobs)
11829{
11830 const char *str=NULL;
11831 int m=-1,bx,by;
11832 int count=0;
11833 struct block_list *bl;
11834
11835 str=script_getstr(st,2);
11836
11837 if(strcmp(str,"this")==0){
11838 TBL_PC *sd=script_rid2sd(st);
11839 if(sd)
11840 m=sd->bl.m;
11841 else{
11842 script_pushint(st,-1);
11843 return 0;
11844 }
11845 }else
11846 m=map_mapname2mapid(str);
11847
11848 if(m < 0){
11849 script_pushint(st,-1);
11850 return 0;
11851 }
11852
11853 for(by=0;by<=(map[m].ys-1)/BLOCK_SIZE;by++)
11854 for(bx=0;bx<=(map[m].xs-1)/BLOCK_SIZE;bx++)
11855 for( bl = map[m].block_mob[bx+by*map[m].bxs] ; bl != NULL ; bl = bl->next )
11856 if(bl->x>=0 && bl->x<=map[m].xs-1 && bl->y>=0 && bl->y<=map[m].ys-1)
11857 count++;
11858
11859 script_pushint(st,count);
11860 return 0;
11861}
11862
11863/*==========================================
11864 * movenpc [MouseJstr]
11865 *------------------------------------------*/
11866BUILDIN_FUNC(movenpc)
11867{
11868 TBL_NPC *nd = NULL;
11869 const char *npc;
11870 int x,y;
11871
11872 npc = script_getstr(st,2);
11873 x = script_getnum(st,3);
11874 y = script_getnum(st,4);
11875
11876 if ((nd = npc_name2id(npc)) == NULL)
11877 return -1;
11878
11879 if (script_hasdata(st,5))
11880 nd->ud.dir = script_getnum(st,5) % 8;
11881 npc_movenpc(nd, x, y);
11882 return 0;
11883}
11884
11885/*==========================================
11886 * message [MouseJstr]
11887 *------------------------------------------*/
11888BUILDIN_FUNC(message)
11889{
11890 const char *msg,*player;
11891 TBL_PC *pl_sd = NULL;
11892
11893 player = script_getstr(st,2);
11894 msg = script_getstr(st,3);
11895
11896 if((pl_sd=map_nick2sd((char *) player)) == NULL)
11897 return 0;
11898 clif_displaymessage(pl_sd->fd, msg);
11899
11900 return 0;
11901}
11902
11903/*==========================================
11904 * npctalk (sends message to surrounding area)
11905 *------------------------------------------*/
11906BUILDIN_FUNC(npctalk)
11907{
11908 const char* str;
11909 char name[NAME_LENGTH], message[256];
11910
11911 struct npc_data* nd = (struct npc_data *)map_id2bl(st->oid);
11912 str = script_getstr(st,2);
11913
11914 if(nd)
11915 {
11916 safestrncpy(name, nd->name, sizeof(name));
11917 strtok(name, "#"); // discard extra name identifier if present
11918 safesnprintf(message, sizeof(message), "%s : %s", name, str);
11919 clif_message(&nd->bl, message);
11920 }
11921
11922 return 0;
11923}
11924
11925// change npc walkspeed [Valaris]
11926BUILDIN_FUNC(npcspeed)
11927{
11928 struct npc_data* nd;
11929 int speed;
11930
11931 speed = script_getnum(st,2);
11932 nd =(struct npc_data *)map_id2bl(st->oid);
11933
11934 if( nd )
11935 {
11936 nd->speed = speed;
11937 nd->ud.state.speed_changed = 1;
11938 }
11939
11940 return 0;
11941}
11942// make an npc walk to a position [Valaris]
11943BUILDIN_FUNC(npcwalkto)
11944{
11945 struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid);
11946 int x=0,y=0;
11947
11948 x=script_getnum(st,2);
11949 y=script_getnum(st,3);
11950
11951 if(nd) {
11952 unit_walktoxy(&nd->bl,x,y,0);
11953 }
11954
11955 return 0;
11956}
11957// stop an npc's movement [Valaris]
11958BUILDIN_FUNC(npcstop)
11959{
11960 struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid);
11961
11962 if(nd) {
11963 unit_stop_walking(&nd->bl,1|4);
11964 }
11965
11966 return 0;
11967}
11968
11969
11970/*==========================================
11971 * getlook char info. getlook(arg)
11972 *------------------------------------------*/
11973BUILDIN_FUNC(getlook)
11974{
11975 int type,val;
11976 TBL_PC *sd;
11977 sd=script_rid2sd(st);
11978
11979 type=script_getnum(st,2);
11980 val=-1;
11981 switch(type) {
11982 case LOOK_HAIR: val=sd->status.hair; break; //1
11983 case LOOK_WEAPON: val=sd->status.weapon; break; //2
11984 case LOOK_HEAD_BOTTOM: val=sd->status.head_bottom; break; //3
11985 case LOOK_HEAD_TOP: val=sd->status.head_top; break; //4
11986 case LOOK_HEAD_MID: val=sd->status.head_mid; break; //5
11987 case LOOK_HAIR_COLOR: val=sd->status.hair_color; break; //6
11988 case LOOK_CLOTHES_COLOR: val=sd->status.clothes_color; break; //7
11989 case LOOK_SHIELD: val=sd->status.shield; break; //8
11990 case LOOK_SHOES: break; //9
11991 }
11992
11993 script_pushint(st,val);
11994 return 0;
11995}
11996
11997/*==========================================
11998 * get char save point. argument: 0- map name, 1- x, 2- y
11999 *------------------------------------------*/
12000BUILDIN_FUNC(getsavepoint)
12001{
12002 TBL_PC* sd;
12003 int type;
12004
12005 sd = script_rid2sd(st);
12006 if (sd == NULL) {
12007 script_pushint(st,0);
12008 return 0;
12009 }
12010
12011 type = script_getnum(st,2);
12012
12013 switch(type) {
12014 case 0: script_pushstrcopy(st,mapindex_id2name(sd->status.save_point.map)); break;
12015 case 1: script_pushint(st,sd->status.save_point.x); break;
12016 case 2: script_pushint(st,sd->status.save_point.y); break;
12017 default:
12018 script_pushint(st,0);
12019 break;
12020 }
12021 return 0;
12022}
12023
12024/*==========================================
12025 * Get position for char/npc/pet/mob objects. Added by Lorky
12026 *
12027 * int getMapXY(MapName$,MapX,MapY,type,[CharName$]);
12028 * where type:
12029 * MapName$ - String variable for output map name
12030 * MapX - Integer variable for output coord X
12031 * MapY - Integer variable for output coord Y
12032 * type - type of object
12033 * 0 - Character coord
12034 * 1 - NPC coord
12035 * 2 - Pet coord
12036 * 3 - Mob coord (not released)
12037 * 4 - Homun coord
12038 * CharName$ - Name object. If miss or "this" the current object
12039 *
12040 * Return:
12041 * 0 - success
12042 * -1 - some error, MapName$,MapX,MapY contains unknown value.
12043 *------------------------------------------*/
12044BUILDIN_FUNC(getmapxy)
12045{
12046 struct block_list *bl = NULL;
12047 TBL_PC *sd=NULL;
12048
12049 int num;
12050 const char *name;
12051 char prefix;
12052
12053 int x,y,type;
12054 char mapname[MAP_NAME_LENGTH];
12055
12056 if( !data_isreference(script_getdata(st,2)) ){
12057 ShowWarning("script: buildin_getmapxy: not mapname variable\n");
12058 script_pushint(st,-1);
12059 return 1;
12060 }
12061 if( !data_isreference(script_getdata(st,3)) ){
12062 ShowWarning("script: buildin_getmapxy: not mapx variable\n");
12063 script_pushint(st,-1);
12064 return 1;
12065 }
12066 if( !data_isreference(script_getdata(st,4)) ){
12067 ShowWarning("script: buildin_getmapxy: not mapy variable\n");
12068 script_pushint(st,-1);
12069 return 1;
12070 }
12071
12072 // Possible needly check function parameters on C_STR,C_INT,C_INT
12073 type=script_getnum(st,5);
12074
12075 switch (type){
12076 case 0: //Get Character Position
12077 if( script_hasdata(st,6) )
12078 sd=map_nick2sd(script_getstr(st,6));
12079 else
12080 sd=script_rid2sd(st);
12081
12082 if (sd)
12083 bl = &sd->bl;
12084 break;
12085 case 1: //Get NPC Position
12086 if( script_hasdata(st,6) )
12087 {
12088 struct npc_data *nd;
12089 nd=npc_name2id(script_getstr(st,6));
12090 if (nd)
12091 bl = &nd->bl;
12092 } else //In case the origin is not an npc?
12093 bl=map_id2bl(st->oid);
12094 break;
12095 case 2: //Get Pet Position
12096 if(script_hasdata(st,6))
12097 sd=map_nick2sd(script_getstr(st,6));
12098 else
12099 sd=script_rid2sd(st);
12100
12101 if (sd && sd->pd)
12102 bl = &sd->pd->bl;
12103 break;
12104 case 3: //Get Mob Position
12105 break; //Not supported?
12106 case 4: //Get Homun Position
12107 if(script_hasdata(st,6))
12108 sd=map_nick2sd(script_getstr(st,6));
12109 else
12110 sd=script_rid2sd(st);
12111
12112 if (sd && sd->hd)
12113 bl = &sd->hd->bl;
12114 break;
12115 default:
12116 ShowWarning("script: buildin_getmapxy: Invalid type %d\n", type);
12117 script_pushint(st,-1);
12118 return 1;
12119 }
12120 if (!bl) { //No object found.
12121 script_pushint(st,-1);
12122 return 0;
12123 }
12124
12125 x= bl->x;
12126 y= bl->y;
12127 safestrncpy(mapname, map[bl->m].name, MAP_NAME_LENGTH);
12128
12129 //Set MapName$
12130 num=st->stack->stack_data[st->start+2].u.num;
12131 name=get_str(num&0x00ffffff);
12132 prefix=*name;
12133
12134 if(not_server_variable(prefix))
12135 sd=script_rid2sd(st);
12136 else
12137 sd=NULL;
12138 set_reg(st,sd,num,name,(void*)mapname,script_getref(st,2));
12139
12140 //Set MapX
12141 num=st->stack->stack_data[st->start+3].u.num;
12142 name=get_str(num&0x00ffffff);
12143 prefix=*name;
12144
12145 if(not_server_variable(prefix))
12146 sd=script_rid2sd(st);
12147 else
12148 sd=NULL;
12149 set_reg(st,sd,num,name,(void*)x,script_getref(st,3));
12150
12151 //Set MapY
12152 num=st->stack->stack_data[st->start+4].u.num;
12153 name=get_str(num&0x00ffffff);
12154 prefix=*name;
12155
12156 if(not_server_variable(prefix))
12157 sd=script_rid2sd(st);
12158 else
12159 sd=NULL;
12160 set_reg(st,sd,num,name,(void*)y,script_getref(st,4));
12161
12162 //Return Success value
12163 script_pushint(st,0);
12164 return 0;
12165}
12166
12167/*==========================================
12168 * Allows player to write NPC logs (i.e. Bank NPC, etc) [Lupus]
12169 *------------------------------------------*/
12170BUILDIN_FUNC(logmes)
12171{
12172 const char *str;
12173 TBL_PC* sd;
12174
12175 sd = script_rid2sd(st);
12176 if( sd == NULL )
12177 return 1;
12178
12179 str = script_getstr(st,2);
12180 log_npc(sd,str);
12181 return 0;
12182}
12183
12184BUILDIN_FUNC(summon)
12185{
12186 int _class, timeout=0;
12187 const char *str,*event="";
12188 TBL_PC *sd;
12189 struct mob_data *md;
12190 int tick = gettick();
12191
12192 sd=script_rid2sd(st);
12193 if (!sd) return 0;
12194
12195 str =script_getstr(st,2);
12196 _class=script_getnum(st,3);
12197 if( script_hasdata(st,4) )
12198 timeout=script_getnum(st,4);
12199 if( script_hasdata(st,5) ){
12200 event=script_getstr(st,5);
12201 check_event(st, event);
12202 }
12203
12204 clif_skill_poseffect(&sd->bl,AM_CALLHOMUN,1,sd->bl.x,sd->bl.y,tick);
12205
12206 md = mob_once_spawn_sub(&sd->bl, sd->bl.m, sd->bl.x, sd->bl.y, str, _class, event);
12207 if (md) {
12208 md->master_id=sd->bl.id;
12209 md->special_state.ai=1;
12210 if( md->deletetimer != INVALID_TIMER )
12211 delete_timer(md->deletetimer, mob_timer_delete);
12212 md->deletetimer = add_timer(tick+(timeout>0?timeout*1000:60000),mob_timer_delete,md->bl.id,0);
12213 mob_spawn (md); //Now it is ready for spawning.
12214 clif_specialeffect(&md->bl,344,AREA);
12215 sc_start4(&md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, 60000);
12216 }
12217 return 0;
12218}
12219
12220/*==========================================
12221 * Checks whether it is daytime/nighttime
12222 *------------------------------------------*/
12223BUILDIN_FUNC(isnight)
12224{
12225 script_pushint(st,(night_flag == 1));
12226 return 0;
12227}
12228
12229BUILDIN_FUNC(isday)
12230{
12231 script_pushint(st,(night_flag == 0));
12232 return 0;
12233}
12234
12235/*================================================
12236 * Check how many items/cards in the list are
12237 * equipped - used for 2/15's cards patch [celest]
12238 *------------------------------------------------*/
12239BUILDIN_FUNC(isequippedcnt)
12240{
12241 TBL_PC *sd;
12242 int i, j, k, id = 1;
12243 int ret = 0;
12244
12245 sd = script_rid2sd(st);
12246 if (!sd) { //If the player is not attached it is a script error anyway... but better prevent the map server from crashing...
12247 script_pushint(st,0);
12248 return 0;
12249 }
12250
12251 for (i=0; id!=0; i++) {
12252 FETCH (i+2, id) else id = 0;
12253 if (id <= 0)
12254 continue;
12255
12256 for (j=0; j<EQI_MAX; j++) {
12257 int index;
12258 index = sd->equip_index[j];
12259 if(index < 0) continue;
12260 if(j == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == index) continue;
12261 if(j == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == index) continue;
12262 if(j == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == index || sd->equip_index[EQI_HEAD_LOW] == index)) continue;
12263
12264 if(!sd->inventory_data[index])
12265 continue;
12266
12267 if (itemdb_type(id) != IT_CARD) { //No card. Count amount in inventory.
12268 if (sd->inventory_data[index]->nameid == id)
12269 ret+= sd->status.inventory[index].amount;
12270 } else { //Count cards.
12271 if (itemdb_isspecial(sd->status.inventory[index].card[0]))
12272 continue; //No cards
12273 for(k=0; k<sd->inventory_data[index]->slot; k++) {
12274 if (sd->status.inventory[index].card[k] == id)
12275 ret++; //[Lupus]
12276 }
12277 }
12278 }
12279 }
12280
12281 script_pushint(st,ret);
12282 return 0;
12283}
12284
12285/*================================================
12286 * Check whether another card has been
12287 * equipped - used for 2/15's cards patch [celest]
12288 * -- Items checked cannot be reused in another
12289 * card set to prevent exploits
12290 *------------------------------------------------*/
12291BUILDIN_FUNC(isequipped)
12292{
12293 TBL_PC *sd;
12294 int i, j, k, id = 1;
12295 int index, flag;
12296 int ret = -1;
12297 //Original hash to reverse it when full check fails.
12298 unsigned int setitem_hash = 0, setitem_hash2 = 0;
12299
12300 sd = script_rid2sd(st);
12301
12302 if (!sd) { //If the player is not attached it is a script error anyway... but better prevent the map server from crashing...
12303 script_pushint(st,0);
12304 return 0;
12305 }
12306
12307 setitem_hash = sd->setitem_hash;
12308 setitem_hash2 = sd->setitem_hash2;
12309 for (i=0; id!=0; i++)
12310 {
12311 FETCH (i+2, id) else id = 0;
12312 if (id <= 0)
12313 continue;
12314 flag = 0;
12315 for (j=0; j<EQI_MAX; j++)
12316 {
12317 index = sd->equip_index[j];
12318 if(index < 0) continue;
12319 if(j == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == index) continue;
12320 if(j == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == index) continue;
12321 if(j == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == index || sd->equip_index[EQI_HEAD_LOW] == index)) continue;
12322
12323 if(!sd->inventory_data[index])
12324 continue;
12325
12326 if (itemdb_type(id) != IT_CARD) {
12327 if (sd->inventory_data[index]->nameid != id)
12328 continue;
12329 flag = 1;
12330 break;
12331 } else { //Cards
12332 if (sd->inventory_data[index]->slot == 0 ||
12333 itemdb_isspecial(sd->status.inventory[index].card[0]))
12334 continue;
12335
12336 for (k = 0; k < sd->inventory_data[index]->slot; k++)
12337 { //New hash system which should support up to 4 slots on any equipment. [Skotlex]
12338 unsigned int hash = 0;
12339 if (sd->status.inventory[index].card[k] != id)
12340 continue;
12341
12342 hash = 1<<((j<5?j:j-5)*4 + k);
12343 // check if card is already used by another set
12344 if ((j<5?sd->setitem_hash:sd->setitem_hash2) & hash)
12345 continue;
12346
12347 // We have found a match
12348 flag = 1;
12349 // Set hash so this card cannot be used by another
12350 if (j<5)
12351 sd->setitem_hash |= hash;
12352 else
12353 sd->setitem_hash2 |= hash;
12354 break;
12355 }
12356 }
12357 if (flag) break; //Card found
12358 }
12359 if (ret == -1)
12360 ret = flag;
12361 else
12362 ret &= flag;
12363 if (!ret) break;
12364 }
12365 if (!ret)
12366 { //When check fails, restore original hash values. [Skotlex]
12367 sd->setitem_hash = setitem_hash;
12368 sd->setitem_hash2 = setitem_hash2;
12369 }
12370 script_pushint(st,ret);
12371 return 0;
12372}
12373
12374/*================================================
12375 * Check how many given inserted cards in the CURRENT
12376 * weapon - used for 2/15's cards patch [Lupus]
12377 *------------------------------------------------*/
12378BUILDIN_FUNC(cardscnt)
12379{
12380 TBL_PC *sd;
12381 int i, k, id = 1;
12382 int ret = 0;
12383 int index;
12384
12385 sd = script_rid2sd(st);
12386
12387 for (i=0; id!=0; i++) {
12388 FETCH (i+2, id) else id = 0;
12389 if (id <= 0)
12390 continue;
12391
12392 index = current_equip_item_index; //we get CURRENT WEAPON inventory index from status.c [Lupus]
12393 if(index < 0) continue;
12394
12395 if(!sd->inventory_data[index])
12396 continue;
12397
12398 if(itemdb_type(id) != IT_CARD) {
12399 if (sd->inventory_data[index]->nameid == id)
12400 ret+= sd->status.inventory[index].amount;
12401 } else {
12402 if (itemdb_isspecial(sd->status.inventory[index].card[0]))
12403 continue;
12404 for(k=0; k<sd->inventory_data[index]->slot; k++) {
12405 if (sd->status.inventory[index].card[k] == id)
12406 ret++;
12407 }
12408 }
12409 }
12410 script_pushint(st,ret);
12411// script_pushint(st,current_equip_item_index);
12412 return 0;
12413}
12414
12415/*=======================================================
12416 * Returns the refined number of the current item, or an
12417 * item with inventory index specified
12418 *-------------------------------------------------------*/
12419BUILDIN_FUNC(getrefine)
12420{
12421 TBL_PC *sd;
12422 if ((sd = script_rid2sd(st))!= NULL)
12423 script_pushint(st,sd->status.inventory[current_equip_item_index].refine);
12424 else
12425 script_pushint(st,0);
12426 return 0;
12427}
12428
12429/*=======================================================
12430 * Day/Night controls
12431 *-------------------------------------------------------*/
12432BUILDIN_FUNC(night)
12433{
12434 if (night_flag != 1) map_night_timer(night_timer_tid, 0, 0, 1);
12435 return 0;
12436}
12437BUILDIN_FUNC(day)
12438{
12439 if (night_flag != 0) map_day_timer(day_timer_tid, 0, 0, 1);
12440 return 0;
12441}
12442
12443//=======================================================
12444// Unequip [Spectre]
12445//-------------------------------------------------------
12446BUILDIN_FUNC(unequip)
12447{
12448 int i;
12449 size_t num;
12450 TBL_PC *sd;
12451
12452 num = script_getnum(st,2);
12453 sd = script_rid2sd(st);
12454 if( sd != NULL && num >= 1 && num <= ARRAYLENGTH(equip) )
12455 {
12456 i = pc_checkequip(sd,equip[num-1]);
12457 if (i >= 0)
12458 pc_unequipitem(sd,i,1|2);
12459 }
12460 return 0;
12461}
12462
12463BUILDIN_FUNC(equip)
12464{
12465 int nameid=0,i;
12466 TBL_PC *sd;
12467 struct item_data *item_data;
12468
12469 sd = script_rid2sd(st);
12470
12471 nameid=script_getnum(st,2);
12472 if((item_data = itemdb_exists(nameid)) == NULL)
12473 {
12474 ShowError("wrong item ID : equipitem(%i)\n",nameid);
12475 return 1;
12476 }
12477 ARR_FIND( 0, MAX_INVENTORY, i, sd->status.inventory[i].nameid == nameid );
12478 if( i < MAX_INVENTORY )
12479 pc_equipitem(sd,i,item_data->equip);
12480
12481 return 0;
12482}
12483
12484BUILDIN_FUNC(autoequip)
12485{
12486 int nameid, flag;
12487 struct item_data *item_data;
12488 nameid=script_getnum(st,2);
12489 flag=script_getnum(st,3);
12490
12491 if( ( item_data = itemdb_exists(nameid) ) == NULL )
12492 {
12493 ShowError("buildin_autoequip: Invalid item '%d'.\n", nameid);
12494 return 1;
12495 }
12496
12497 if( !itemdb_isequip2(item_data) )
12498 {
12499 ShowError("buildin_autoequip: Item '%d' cannot be equipped.\n", nameid);
12500 return 1;
12501 }
12502
12503 item_data->flag.autoequip = flag>0?1:0;
12504 return 0;
12505}
12506
12507BUILDIN_FUNC(setbattleflag)
12508{
12509 const char *flag, *value;
12510
12511 flag = script_getstr(st,2);
12512 value = script_getstr(st,3); // HACK: Retrieve number as string (auto-converted) for battle_set_value
12513
12514 if (battle_set_value(flag, value) == 0)
12515 ShowWarning("buildin_setbattleflag: unknown battle_config flag '%s'\n",flag);
12516 else
12517 ShowInfo("buildin_setbattleflag: battle_config flag '%s' is now set to '%s'.\n",flag,value);
12518
12519 return 0;
12520}
12521
12522BUILDIN_FUNC(getbattleflag)
12523{
12524 const char *flag;
12525 flag = script_getstr(st,2);
12526 script_pushint(st,battle_get_value(flag));
12527 return 0;
12528}
12529
12530//=======================================================
12531// strlen [Valaris]
12532//-------------------------------------------------------
12533BUILDIN_FUNC(getstrlen)
12534{
12535
12536 const char *str = script_getstr(st,2);
12537 int len = (int)strlen(str);
12538
12539 script_pushint(st,len);
12540 return 0;
12541}
12542
12543//=======================================================
12544// isalpha [Valaris]
12545//-------------------------------------------------------
12546BUILDIN_FUNC(charisalpha)
12547{
12548 const char *str=script_getstr(st,2);
12549 int pos=script_getnum(st,3);
12550
12551 int val = ( pos >= 0 && (unsigned int)pos < strlen(str) && ISALPHA(str[pos]) )? 1: 0;
12552
12553 script_pushint(st,val);
12554 return 0;
12555}
12556
12557//=======================================================
12558// charisupper <str>, <index>
12559//-------------------------------------------------------
12560BUILDIN_FUNC(charisupper)
12561{
12562 const char *str = script_getstr(st,2);
12563 int pos = script_getnum(st,3);
12564
12565 int val = ( pos >= 0 && (unsigned int)pos < strlen(str) && ISUPPER(str[pos]) )? 1: 0;
12566
12567 script_pushint(st,val);
12568 return 0;
12569}
12570
12571//=======================================================
12572// charislower <str>, <index>
12573//-------------------------------------------------------
12574BUILDIN_FUNC(charislower)
12575{
12576 const char *str = script_getstr(st,2);
12577 int pos = script_getnum(st,3);
12578
12579 int val = ( pos >= 0 && (unsigned int)pos < strlen(str) && ISLOWER(str[pos]) )? 1: 0;
12580
12581 script_pushint(st,val);
12582 return 0;
12583}
12584//=======================================================
12585// charat <str>, <index>
12586//-------------------------------------------------------
12587BUILDIN_FUNC(charat)
12588{
12589 const char *str = script_getstr(st,2);
12590 int pos = script_getnum(st,3);
12591
12592 if( pos >= 0 && (unsigned int)pos < strlen(str) )
12593 {
12594 char output[2];
12595 output[0] = str[pos];
12596 output[1] = '\0';
12597 script_pushstrcopy(st, output);
12598 }
12599 else
12600 {
12601 script_pushconststr(st, "");
12602 }
12603
12604 return 0;
12605}
12606
12607//=======================================================
12608// setchar <string>, <char>, <index>
12609//-------------------------------------------------------
12610BUILDIN_FUNC(setchar)
12611{
12612 const char *str = script_getstr(st,2);
12613 const char *c = script_getstr(st,3);
12614 int index = script_getnum(st,4);
12615 char *output = aStrdup(str);
12616
12617 if( index >= 0 && (unsigned int)index < strlen(output) )
12618 output[index] = *c;
12619
12620 script_pushstr(st, output);
12621 return 0;
12622}
12623
12624//=======================================================
12625// insertchar <string>, <char>, <index>
12626//-------------------------------------------------------
12627BUILDIN_FUNC(insertchar)
12628{
12629 const char *str = script_getstr(st,2);
12630 const char *c = script_getstr(st,3);
12631 int index = script_getnum(st,4);
12632 char *output;
12633 size_t len = strlen(str);
12634
12635 if(index < 0)
12636 index = 0;
12637 else if(index > len)
12638 index = len;
12639
12640 output = (char*)aMalloc(len + 2);
12641
12642 memcpy(output, str, index);
12643 output[index] = c[0];
12644 memcpy(&output[index+1], &str[index], len - index);
12645 output[len+1] = '\0';
12646
12647 script_pushstr(st, output);
12648 return 0;
12649}
12650
12651//=======================================================
12652// delchar <string>, <index>
12653//-------------------------------------------------------
12654BUILDIN_FUNC(delchar)
12655{
12656 const char *str = script_getstr(st,2);
12657 int index = script_getnum(st,3);
12658 char *output;
12659 size_t len = strlen(str);
12660
12661 if( index < 0 || index >= len )
12662 { // no change
12663 script_pushstrcopy(st, str);
12664 return 0;
12665 }
12666
12667 output = (char*)aMalloc(len);
12668
12669 memcpy(output, str, index);
12670 memcpy(&output[index], &str[index+1], len - index);
12671
12672 script_pushstr(st, output);
12673 return 0;
12674}
12675
12676//=======================================================
12677// strtoupper <str>
12678//-------------------------------------------------------
12679BUILDIN_FUNC(strtoupper)
12680{
12681 const char *str = script_getstr(st,2);
12682 char *output = aStrdup(str);
12683 char *cursor = output;
12684
12685 while (*cursor != '\0') {
12686 *cursor = TOUPPER(*cursor);
12687 cursor++;
12688 }
12689
12690 script_pushstr(st, output);
12691 return 0;
12692}
12693
12694//=======================================================
12695// strtolower <str>
12696//-------------------------------------------------------
12697BUILDIN_FUNC(strtolower)
12698{
12699 const char *str = script_getstr(st,2);
12700 char *output = aStrdup(str);
12701 char *cursor = output;
12702
12703 while (*cursor != '\0') {
12704 *cursor = TOLOWER(*cursor);
12705 cursor++;
12706 }
12707
12708 script_pushstr(st, output);
12709 return 0;
12710}
12711//=======================================================
12712// substr <str>, <start>, <end>
12713//-------------------------------------------------------
12714BUILDIN_FUNC(substr)
12715{
12716 const char *str = script_getstr(st,2);
12717 int start = script_getnum(st,3);
12718 int end = script_getnum(st,4);
12719
12720 if( start >= 0 && start <= end && (unsigned int)end < strlen(str) )
12721 {
12722 int len = end + 1 - start;
12723 char* output = (char*)aMalloc(len + 1);
12724 memcpy(output, &str[start], len);
12725 output[len] = '\0';
12726 script_pushstr(st, output);
12727 }
12728 else
12729 {
12730 script_pushconststr(st, "");
12731 }
12732
12733 return 0;
12734}
12735
12736//=======================================================
12737// explode <dest_string_array>, <str>, <delimiter>
12738// Note: delimiter is limited to 1 char
12739//-------------------------------------------------------
12740BUILDIN_FUNC(explode)
12741{
12742 struct script_data* data = script_getdata(st, 2);
12743 const char *str = script_getstr(st,3);
12744 const char delimiter = script_getstr(st, 4)[0];
12745 int32 id;
12746 size_t len = strlen(str);
12747 int i = 0, j = 0;
12748 int index;
12749
12750 char *temp;
12751 const char* name;
12752
12753 TBL_PC* sd = NULL;
12754
12755 if( !data_isreference(data) )
12756 {
12757 ShowError("script:explode: not a variable\n");
12758 script_reportdata(data);
12759 st->state = END;
12760 return 1;// not a variable
12761 }
12762
12763 id = reference_getid(data);
12764 index = reference_getindex(data);
12765 name = reference_getname(data);
12766
12767 if( not_array_variable(*name) )
12768 {
12769 ShowError("script:explode: illegal scope\n");
12770 script_reportdata(data);
12771 st->state = END;
12772 return 1;// not supported
12773 }
12774
12775 if( !is_string_variable(name) )
12776 {
12777 ShowError("script:explode: not string array\n");
12778 script_reportdata(data);
12779 st->state = END;
12780 return 1;// data type mismatch
12781 }
12782
12783 if( not_server_variable(*name) )
12784 {
12785 sd = script_rid2sd(st);
12786 if( sd == NULL )
12787 return 0;// no player attached
12788 }
12789
12790 temp = (char*)aMalloc(len + 1);
12791
12792 for( i = 0, j = 0; i < len; ++i )
12793 {
12794 if( index < SCRIPT_MAX_ARRAYSIZE-1 && str[i] == delimiter )
12795 { // break string at delimiter while there is space in the array
12796 temp[j] = '\0';
12797 set_reg(st, sd, reference_uid(id, index), name, (void*)temp, reference_getref(data));
12798 ++index;
12799 j = 0;
12800 }
12801 else
12802 {
12803 temp[j] = str[i];
12804 ++j;
12805 }
12806 }
12807 //set last string
12808 temp[j] = '\0';
12809 set_reg(st, sd, reference_uid(id, index), name, (void*)temp, reference_getref(data));
12810
12811 aFree(temp);
12812 return 0;
12813}
12814//=======================================================
12815// implode <string_array>
12816// implode <string_array>, <glue>
12817//-------------------------------------------------------
12818BUILDIN_FUNC(implode)
12819{
12820 struct script_data* data = script_getdata(st, 2);
12821 const char* name;
12822 int32 array_size, id;
12823
12824 TBL_PC* sd = NULL;
12825
12826 if( !data_isreference(data) )
12827 {
12828 ShowError("script:implode: not a variable\n");
12829 script_reportdata(data);
12830 st->state = END;
12831 return 1;// not a variable
12832 }
12833
12834 id = reference_getid(data);
12835 name = reference_getname(data);
12836
12837 if( not_array_variable(*name) )
12838 {
12839 ShowError("script:implode: illegal scope\n");
12840 script_reportdata(data);
12841 st->state = END;
12842 return 1;// not supported
12843 }
12844
12845 if( !is_string_variable(name) )
12846 {
12847 ShowError("script:implode: not string array\n");
12848 script_reportdata(data);
12849 st->state = END;
12850 return 1;// data type mismatch
12851 }
12852
12853 if( not_server_variable(*name) )
12854 {
12855 sd = script_rid2sd(st);
12856 if( sd == NULL )
12857 return 0;// no player attached
12858 }
12859
12860 //count chars
12861 array_size = getarraysize(st, id, reference_getindex(data), is_string_variable(name), reference_getref(data));
12862
12863 if( array_size < 0 || array_size >= SCRIPT_MAX_ARRAYSIZE )
12864 {
12865 ShowError("script:implode: invalid array length = %d\n", array_size);
12866 script_reportdata(data);
12867 st->state = END;
12868 return -1;
12869 }
12870
12871 if( array_size == 0 ) //empty array check (AmsTaff)
12872 {
12873 ShowWarning("script:implode: array length = 0\n");
12874 script_reportdata(data);
12875 script_reportsrc(st);
12876 script_pushconststr(st, "NULL"); // XXX why return "NULL" for an empty array? [flaviojs]
12877 }
12878 else
12879 {
12880 const char* str[SCRIPT_MAX_ARRAYSIZE];
12881 size_t len[SCRIPT_MAX_ARRAYSIZE];
12882 size_t total_len = 0;
12883 const char* glue = "";
12884 size_t glue_len = 0;
12885 char *output;
12886 int i, k;
12887
12888 // parse data
12889 for( i = 0; i < array_size; ++i )
12890 {
12891 str[i] = (const char*)get_val2(st, reference_uid(id, i), reference_getref(data)); // leave string data in the stack
12892 len[i] = strlen(str[i]);
12893 total_len += len[i];
12894 }
12895
12896 if( script_hasdata(st,3) )
12897 {
12898 glue = script_getstr(st,3);
12899 glue_len = strlen(glue);
12900 total_len += glue_len * (array_size - 1);
12901 }
12902
12903 //build output
12904 output = (char*)aMalloc(total_len + 1);
12905 for( i = 0, k = 0; i < array_size; ++i )
12906 {
12907 memcpy(&output[k], str[i], len[i]);
12908 k += len[i];
12909 if( glue_len > 0 && i < array_size - 1 )
12910 {
12911 memcpy(&output[k], glue, glue_len);
12912 k += glue_len;
12913 }
12914 }
12915 output[k] = '\0';
12916 script_removetop(st, -array_size, 0); // clear string data in the stack
12917
12918 script_pushstr(st, output);
12919 }
12920
12921 return 0;
12922}
12923
12924/// Changes the display name and/or display class of the npc.
12925/// Returns 0 is successful, 1 if the npc does not exist.
12926///
12927/// setnpcdisplay("<npc name>", "<new display name>", <new class id>, <new size>) -> <int>
12928/// setnpcdisplay("<npc name>", "<new display name>", <new class id>) -> <int>
12929/// setnpcdisplay("<npc name>", "<new display name>") -> <int>
12930/// setnpcdisplay("<npc name>", <new class id>) -> <int>
12931BUILDIN_FUNC(setnpcdisplay)
12932{
12933 const char* name;
12934 const char* newname = NULL;
12935 int class_ = -1, size = -1;
12936 struct script_data* data;
12937 struct npc_data* nd;
12938
12939 name = script_getstr(st,2);
12940 data = script_getdata(st,3);
12941
12942 if( script_hasdata(st,4) )
12943 class_ = script_getnum(st,4);
12944 if( script_hasdata(st,5) )
12945 size = script_getnum(st,5);
12946
12947 get_val(st, data);
12948 if( data_isstring(data) )
12949 newname = conv_str(st,data);
12950 else if( data_isint(data) )
12951 class_ = conv_num(st,data);
12952 else
12953 {
12954 ShowError("script:setnpcdisplay: expected a string or number\n");
12955 script_reportdata(data);
12956 return 1;
12957 }
12958
12959 nd = npc_name2id(name);
12960 if( nd == NULL )
12961 {// not found
12962 script_pushint(st,1);
12963 return 0;
12964 }
12965
12966 // update npc
12967 if( newname )
12968 npc_setdisplayname(nd, newname);
12969
12970 if( size != -1 && size != (int)nd->size )
12971 nd->size = size;
12972 else
12973 size = -1;
12974
12975 if( class_ != -1 && nd->class_ != class_ )
12976 npc_setclass(nd, class_);
12977 else if( size != -1 )
12978 { // Required to update the visual size
12979 clif_clearunit_area(&nd->bl, CLR_OUTSIGHT);
12980 clif_spawn(&nd->bl);
12981 }
12982
12983 script_pushint(st,0);
12984 return 0;
12985}
12986
12987BUILDIN_FUNC(atoi)
12988{
12989 const char *value;
12990 value = script_getstr(st,2);
12991 script_pushint(st,atoi(value));
12992 return 0;
12993}
12994
12995// case-insensitive substring search [lordalfa]
12996BUILDIN_FUNC(compare)
12997{
12998 const char *message;
12999 const char *cmpstring;
13000 message = script_getstr(st,2);
13001 cmpstring = script_getstr(st,3);
13002 script_pushint(st,(stristr(message,cmpstring) != NULL));
13003 return 0;
13004}
13005
13006// [zBuffer] List of mathematics commands --->
13007BUILDIN_FUNC(sqrt)
13008{
13009 double i, a;
13010 i = script_getnum(st,2);
13011 a = sqrt(i);
13012 script_pushint(st,(int)a);
13013 return 0;
13014}
13015
13016BUILDIN_FUNC(pow)
13017{
13018 double i, a, b;
13019 a = script_getnum(st,2);
13020 b = script_getnum(st,3);
13021 i = pow(a,b);
13022 script_pushint(st,(int)i);
13023 return 0;
13024}
13025
13026BUILDIN_FUNC(distance)
13027{
13028 int x0, y0, x1, y1;
13029
13030 x0 = script_getnum(st,2);
13031 y0 = script_getnum(st,3);
13032 x1 = script_getnum(st,4);
13033 y1 = script_getnum(st,5);
13034
13035 script_pushint(st,distance_xy(x0,y0,x1,y1));
13036 return 0;
13037}
13038
13039// <--- [zBuffer] List of mathematics commands
13040
13041BUILDIN_FUNC(md5)
13042{
13043 const char *tmpstr;
13044 char *md5str;
13045
13046 tmpstr = script_getstr(st,2);
13047 md5str = (char *)aMallocA((32+1)*sizeof(char));
13048 MD5_String(tmpstr, md5str);
13049 script_pushstr(st, md5str);
13050 return 0;
13051}
13052
13053// [zBuffer] List of dynamic var commands --->
13054
13055BUILDIN_FUNC(setd)
13056{
13057 TBL_PC *sd=NULL;
13058 char varname[100];
13059 const char *buffer;
13060 int elem;
13061 buffer = script_getstr(st, 2);
13062
13063 if(sscanf(buffer, "%99[^[][%d]", varname, &elem) < 2)
13064 elem = 0;
13065
13066 if( not_server_variable(*varname) )
13067 {
13068 sd = script_rid2sd(st);
13069 if( sd == NULL )
13070 {
13071 ShowError("script:setd: no player attached for player variable '%s'\n", buffer);
13072 return 0;
13073 }
13074 }
13075
13076 if( is_string_variable(varname) ) {
13077 setd_sub(st, sd, varname, elem, (void *)script_getstr(st, 3), NULL);
13078 } else {
13079 setd_sub(st, sd, varname, elem, (void *)script_getnum(st, 3), NULL);
13080 }
13081
13082 return 0;
13083}
13084
13085#ifndef TXT_ONLY
13086int buildin_query_sql_sub(struct script_state* st, Sql* handle)
13087{
13088 int i, j;
13089 TBL_PC* sd = NULL;
13090 const char* query;
13091 struct script_data* data;
13092 const char* name;
13093 int max_rows = SCRIPT_MAX_ARRAYSIZE;// maximum number of rows
13094 int num_vars;
13095 int num_cols;
13096
13097 // check target variables
13098 for( i = 3; script_hasdata(st,i); ++i )
13099 {
13100 data = script_getdata(st, i);
13101 if( data_isreference(data) && reference_tovariable(data) )
13102 {// it's a variable
13103 name = reference_getname(data);
13104 if( not_server_variable(*name) && sd == NULL )
13105 {// requires a player
13106 sd = script_rid2sd(st);
13107 if( sd == NULL )
13108 {// no player attached
13109 script_reportdata(data);
13110 st->state = END;
13111 return 1;
13112 }
13113 }
13114 if( not_array_variable(*name) )
13115 max_rows = 1;// not an array, limit to one row
13116 }
13117 else
13118 {
13119 ShowError("script:query_sql: not a variable\n");
13120 script_reportdata(data);
13121 st->state = END;
13122 return 1;
13123 }
13124 }
13125 num_vars = i - 3;
13126
13127 // Execute the query
13128 query = script_getstr(st,2);
13129 if( SQL_ERROR == Sql_QueryStr(handle, query) )
13130 {
13131 Sql_ShowDebug(handle);
13132 script_pushint(st, 0);
13133 return 1;
13134 }
13135
13136 if( Sql_NumRows(handle) == 0 )
13137 {// No data received
13138 Sql_FreeResult(handle);
13139 script_pushint(st, 0);
13140 return 0;
13141 }
13142
13143 // Count the number of columns to store
13144 num_cols = Sql_NumColumns(handle);
13145 if( num_vars < num_cols )
13146 {
13147 ShowWarning("script:query_sql: Too many columns, discarding last %u columns.\n", (unsigned int)(num_cols-num_vars));
13148 script_reportsrc(st);
13149 }
13150 else if( num_vars > num_cols )
13151 {
13152 ShowWarning("script:query_sql: Too many variables (%u extra).\n", (unsigned int)(num_vars-num_cols));
13153 script_reportsrc(st);
13154 }
13155
13156 // Store data
13157 for( i = 0; i < max_rows && SQL_SUCCESS == Sql_NextRow(handle); ++i )
13158 {
13159 for( j = 0; j < num_vars; ++j )
13160 {
13161 char* str = NULL;
13162
13163 if( j < num_cols )
13164 Sql_GetData(handle, j, &str, NULL);
13165
13166 data = script_getdata(st, j+3);
13167 name = reference_getname(data);
13168 if( is_string_variable(name) )
13169 setd_sub(st, sd, name, i, (void *)(str?str:""), reference_getref(data));
13170 else
13171 setd_sub(st, sd, name, i, (void *)(str?atoi(str):0), reference_getref(data));
13172 }
13173 }
13174 if( i == max_rows && max_rows < Sql_NumRows(handle) )
13175 {
13176 ShowWarning("script:query_sql: Only %d/%u rows have been stored.\n", max_rows, (unsigned int)Sql_NumRows(handle));
13177 script_reportsrc(st);
13178 }
13179
13180 // Free data
13181 Sql_FreeResult(handle);
13182 script_pushint(st, i);
13183 return 0;
13184}
13185#endif
13186
13187BUILDIN_FUNC(query_sql)
13188{
13189#ifndef TXT_ONLY
13190 return buildin_query_sql_sub(st, mmysql_handle);
13191#else
13192 //for TXT version, we always return -1
13193 script_pushint(st,-1);
13194 return 0;
13195#endif
13196}
13197
13198BUILDIN_FUNC(query_logsql)
13199{
13200#ifndef TXT_ONLY
13201 if( !log_config.sql_logs )
13202 {// logmysql_handle == NULL
13203 ShowWarning("buildin_query_logsql: SQL logs are disabled, query '%s' will not be executed.\n", script_getstr(st,2));
13204 script_pushint(st,-1);
13205 return 1;
13206 }
13207
13208 return buildin_query_sql_sub(st, logmysql_handle);
13209#else
13210 //for TXT version, we always return -1
13211 script_pushint(st,-1);
13212 return 0;
13213#endif
13214}
13215
13216//Allows escaping of a given string.
13217BUILDIN_FUNC(escape_sql)
13218{
13219 const char *str;
13220 char *esc_str;
13221 size_t len;
13222
13223 str = script_getstr(st,2);
13224 len = strlen(str);
13225 esc_str = (char*)aMallocA(len*2+1);
13226#if defined(TXT_ONLY)
13227 jstrescapecpy(esc_str, str);
13228#else
13229 Sql_EscapeStringLen(mmysql_handle, esc_str, str, len);
13230#endif
13231 script_pushstr(st, esc_str);
13232 return 0;
13233}
13234
13235BUILDIN_FUNC(getd)
13236{
13237 const char* p;
13238 const char* name;
13239 int namelen;
13240 bool isarray;
13241 long idx;
13242 struct script_data* data;
13243
13244 p = script_getstr(st, 2);
13245 p = skip_space(p);
13246
13247 // parse name
13248 name = p; // not NUL terminated (not needed)
13249 namelen = skip_word(p) - p;
13250 p += namelen;
13251 p = skip_space(p);
13252 // parse index (optional)
13253 isarray = false;
13254 idx = 0;
13255 if( p[0] == '[' )
13256 {
13257 char* end = NULL;
13258 const char* p2 = skip_space(p + 1);
13259 idx = strtol(p2, &end, 0);
13260 if( p2 != NULL && p2 != end )
13261 { // has a numeric index
13262 p2 = skip_space(end);
13263 if( p2[0] == ']' )
13264 {
13265 p = skip_space(p2 + 1);
13266 isarray = true;
13267 }
13268 }
13269 }
13270
13271 // validate
13272 if( p[0] != '\0' )
13273 {
13274 ShowError("script:getd: failed to parse '%s'\n", p);
13275 script_reportdata(script_getdata(st, 2));
13276 st->state = END;
13277 return 1;
13278 }
13279 if( namelen == 0 )
13280 {
13281 ShowError("script:getd: variable name is empty\n");
13282 script_reportdata(script_getdata(st, 2));
13283 st->state = END;
13284 return 1;
13285 }
13286 if( isarray && not_array_variable(name[0]) )
13287 {
13288 ShowError("script:getd: not an array variable\n");
13289 script_reportdata(script_getdata(st, 2));
13290 st->state = END;
13291 return 1;
13292 }
13293 if( idx < 0 || idx >= SCRIPT_MAX_ARRAYSIZE )
13294 {
13295 ShowError("script:getd: index=%ld is invalid, must be a number from 0 to %d\n", idx, SCRIPT_MAX_ARRAYSIZE - 1);
13296 script_reportdata(script_getdata(st, 2));
13297 st->state = END;
13298 return 1;
13299 }
13300
13301 // generate reference
13302 data = push_val(st->stack, C_NAME, reference_uid(add_word(name), idx));
13303 if( reference_tonil(data) )
13304 str_data[reference_getid(data)].type = C_NAME; // unused name, make it a reference to variable
13305 //XXX references can point to other types of data, not just variables
13306
13307 return 0;
13308}
13309
13310// <--- [zBuffer] List of dynamic var commands
13311// Pet stat [Lance]
13312BUILDIN_FUNC(petstat)
13313{
13314 TBL_PC *sd = NULL;
13315 struct pet_data *pd;
13316 int flag = script_getnum(st,2);
13317 sd = script_rid2sd(st);
13318 if(!sd || !sd->status.pet_id || !sd->pd){
13319 if(flag == 2)
13320 script_pushconststr(st, "");
13321 else
13322 script_pushint(st,0);
13323 return 0;
13324 }
13325 pd = sd->pd;
13326 switch(flag){
13327 case 1: script_pushint(st,(int)pd->pet.class_); break;
13328 case 2: script_pushstrcopy(st, pd->pet.name); break;
13329 case 3: script_pushint(st,(int)pd->pet.level); break;
13330 case 4: script_pushint(st,(int)pd->pet.hungry); break;
13331 case 5: script_pushint(st,(int)pd->pet.intimate); break;
13332 default:
13333 script_pushint(st,0);
13334 break;
13335 }
13336 return 0;
13337}
13338
13339BUILDIN_FUNC(callshop)
13340{
13341 TBL_PC *sd = NULL;
13342 struct npc_data *nd;
13343 const char *shopname;
13344 int flag = 0;
13345 sd = script_rid2sd(st);
13346 if (!sd) {
13347 script_pushint(st,0);
13348 return 0;
13349 }
13350 shopname = script_getstr(st, 2);
13351 if( script_hasdata(st,3) )
13352 flag = script_getnum(st,3);
13353 nd = npc_name2id(shopname);
13354 if( !nd || nd->bl.type != BL_NPC || (nd->subtype != SHOP && nd->subtype != CASHSHOP) )
13355 {
13356 ShowError("buildin_callshop: Shop [%s] not found (or NPC is not shop type)\n", shopname);
13357 script_pushint(st,0);
13358 return 1;
13359 }
13360
13361 if( nd->subtype == SHOP )
13362 {
13363 switch( flag )
13364 {
13365 case 1: npc_buysellsel(sd,nd->bl.id,0); break; //Buy window
13366 case 2: npc_buysellsel(sd,nd->bl.id,1); break; //Sell window
13367 default: clif_npcbuysell(sd,nd->bl.id); break; //Show menu
13368 }
13369 }
13370 else
13371 clif_cashshop_show(sd, nd);
13372
13373 sd->npc_shopid = nd->bl.id;
13374 script_pushint(st,1);
13375 return 0;
13376}
13377
13378BUILDIN_FUNC(npcshopitem)
13379{
13380 const char* npcname = script_getstr(st, 2);
13381 struct npc_data* nd = npc_name2id(npcname);
13382 int n, i;
13383 int amount;
13384
13385 if( !nd || ( nd->subtype != SHOP && nd->subtype != CASHSHOP ) )
13386 { //Not found.
13387 script_pushint(st,0);
13388 return 0;
13389 }
13390
13391 // get the count of new entries
13392 amount = (script_lastdata(st)-2)/2;
13393
13394 // generate new shop item list
13395 RECREATE(nd->u.shop.shop_item, struct npc_item_list, amount);
13396 for( n = 0, i = 3; n < amount; n++, i+=2 )
13397 {
13398 nd->u.shop.shop_item[n].nameid = script_getnum(st,i);
13399 nd->u.shop.shop_item[n].value = script_getnum(st,i+1);
13400 }
13401 nd->u.shop.count = n;
13402
13403 script_pushint(st,1);
13404 return 0;
13405}
13406
13407BUILDIN_FUNC(npcshopadditem)
13408{
13409 const char* npcname = script_getstr(st,2);
13410 struct npc_data* nd = npc_name2id(npcname);
13411 int n, i;
13412 int amount;
13413
13414 if( !nd || ( nd->subtype != SHOP && nd->subtype != CASHSHOP ) )
13415 { //Not found.
13416 script_pushint(st,0);
13417 return 0;
13418 }
13419
13420 // get the count of new entries
13421 amount = (script_lastdata(st)-2)/2;
13422
13423 // append new items to existing shop item list
13424 RECREATE(nd->u.shop.shop_item, struct npc_item_list, nd->u.shop.count+amount);
13425 for( n = nd->u.shop.count, i = 3; n < nd->u.shop.count+amount; n++, i+=2 )
13426 {
13427 nd->u.shop.shop_item[n].nameid = script_getnum(st,i);
13428 nd->u.shop.shop_item[n].value = script_getnum(st,i+1);
13429 }
13430 nd->u.shop.count = n;
13431
13432 script_pushint(st,1);
13433 return 0;
13434}
13435
13436BUILDIN_FUNC(npcshopdelitem)
13437{
13438 const char* npcname = script_getstr(st,2);
13439 struct npc_data* nd = npc_name2id(npcname);
13440 unsigned int nameid;
13441 int n, i;
13442 int amount;
13443 int size;
13444
13445 if( !nd || ( nd->subtype != SHOP && nd->subtype != CASHSHOP ) )
13446 { //Not found.
13447 script_pushint(st,0);
13448 return 0;
13449 }
13450
13451 amount = script_lastdata(st)-2;
13452 size = nd->u.shop.count;
13453
13454 // remove specified items from the shop item list
13455 for( i = 3; i < 3 + amount; i++ )
13456 {
13457 nameid = script_getnum(st,i);
13458
13459 ARR_FIND( 0, size, n, nd->u.shop.shop_item[n].nameid == nameid );
13460 if( n < size )
13461 {
13462 memmove(&nd->u.shop.shop_item[n], &nd->u.shop.shop_item[n+1], sizeof(nd->u.shop.shop_item[0])*(size-n));
13463 size--;
13464 }
13465 }
13466
13467 RECREATE(nd->u.shop.shop_item, struct npc_item_list, size);
13468 nd->u.shop.count = size;
13469
13470 script_pushint(st,1);
13471 return 0;
13472}
13473
13474//Sets a script to attach to a shop npc.
13475BUILDIN_FUNC(npcshopattach)
13476{
13477 const char* npcname = script_getstr(st,2);
13478 struct npc_data* nd = npc_name2id(npcname);
13479 int flag = 1;
13480
13481 if( script_hasdata(st,3) )
13482 flag = script_getnum(st,3);
13483
13484 if( !nd || nd->subtype != SHOP )
13485 { //Not found.
13486 script_pushint(st,0);
13487 return 0;
13488 }
13489
13490 if (flag)
13491 nd->master_nd = ((struct npc_data *)map_id2bl(st->oid));
13492 else
13493 nd->master_nd = NULL;
13494
13495 script_pushint(st,1);
13496 return 0;
13497}
13498
13499/*==========================================
13500 * Returns some values of an item [Lupus]
13501 * Price, Weight, etc...
13502 setitemscript(itemID,"{new item bonus script}",[n]);
13503 Where n:
13504 0 - script
13505 1 - Equip script
13506 2 - Unequip script
13507 *------------------------------------------*/
13508BUILDIN_FUNC(setitemscript)
13509{
13510 int item_id,n=0;
13511 const char *script;
13512 struct item_data *i_data;
13513 struct script_code **dstscript;
13514
13515 item_id = script_getnum(st,2);
13516 script = script_getstr(st,3);
13517 if( script_hasdata(st,4) )
13518 n=script_getnum(st,4);
13519 i_data = itemdb_exists(item_id);
13520
13521 if (!i_data || script==NULL || ( script[0] && script[0]!='{' )) {
13522 script_pushint(st,0);
13523 return 0;
13524 }
13525 switch (n) {
13526 case 2:
13527 dstscript = &i_data->unequip_script;
13528 break;
13529 case 1:
13530 dstscript = &i_data->equip_script;
13531 break;
13532 default:
13533 dstscript = &i_data->script;
13534 break;
13535 }
13536 if(*dstscript)
13537 script_free_code(*dstscript);
13538
13539 *dstscript = script[0] ? parse_script(script, "script_setitemscript", 0, 0) : NULL;
13540 script_pushint(st,1);
13541 return 0;
13542}
13543
13544/* Work In Progress [Lupus]
13545BUILDIN_FUNC(addmonsterdrop)
13546{
13547 int class_,item_id,chance;
13548 class_=script_getnum(st,2);
13549 item_id=script_getnum(st,3);
13550 chance=script_getnum(st,4);
13551 if(class_>1000 && item_id>500 && chance>0) {
13552 script_pushint(st,1);
13553 } else {
13554 script_pushint(st,0);
13555 }
13556}
13557
13558BUILDIN_FUNC(delmonsterdrop)
13559{
13560 int class_,item_id;
13561 class_=script_getnum(st,2);
13562 item_id=script_getnum(st,3);
13563 if(class_>1000 && item_id>500) {
13564 script_pushint(st,1);
13565 } else {
13566 script_pushint(st,0);
13567 }
13568}
13569*/
13570
13571/*==========================================
13572 * Returns some values of a monster [Lupus]
13573 * Name, Level, race, size, etc...
13574 getmonsterinfo(monsterID,queryIndex);
13575 *------------------------------------------*/
13576BUILDIN_FUNC(getmonsterinfo)
13577{
13578 struct mob_db *mob;
13579 int mob_id;
13580
13581 mob_id = script_getnum(st,2);
13582 if (!mobdb_checkid(mob_id)) {
13583 ShowError("buildin_getmonsterinfo: Wrong Monster ID: %i\n", mob_id);
13584 if ( !script_getnum(st,3) ) //requested a string
13585 script_pushconststr(st,"null");
13586 else
13587 script_pushint(st,-1);
13588 return -1;
13589 }
13590 mob = mob_db(mob_id);
13591 switch ( script_getnum(st,3) ) {
13592 case 0: script_pushstrcopy(st,mob->jname); break;
13593 case 1: script_pushint(st,mob->lv); break;
13594 case 2: script_pushint(st,mob->status.max_hp); break;
13595 case 3: script_pushint(st,mob->base_exp); break;
13596 case 4: script_pushint(st,mob->job_exp); break;
13597 case 5: script_pushint(st,mob->status.rhw.atk); break;
13598 case 6: script_pushint(st,mob->status.rhw.atk2); break;
13599 case 7: script_pushint(st,mob->status.def); break;
13600 case 8: script_pushint(st,mob->status.mdef); break;
13601 case 9: script_pushint(st,mob->status.str); break;
13602 case 10: script_pushint(st,mob->status.agi); break;
13603 case 11: script_pushint(st,mob->status.vit); break;
13604 case 12: script_pushint(st,mob->status.int_); break;
13605 case 13: script_pushint(st,mob->status.dex); break;
13606 case 14: script_pushint(st,mob->status.luk); break;
13607 case 15: script_pushint(st,mob->status.rhw.range); break;
13608 case 16: script_pushint(st,mob->range2); break;
13609 case 17: script_pushint(st,mob->range3); break;
13610 case 18: script_pushint(st,mob->status.size); break;
13611 case 19: script_pushint(st,mob->status.race); break;
13612 case 20: script_pushint(st,mob->status.def_ele); break;
13613 case 21: script_pushint(st,mob->status.mode); break;
13614 default: script_pushint(st,-1); //wrong Index
13615 }
13616 return 0;
13617}
13618
13619BUILDIN_FUNC(checkvending) // check vending [Nab4]
13620{
13621 TBL_PC *sd = NULL;
13622
13623 if(script_hasdata(st,2))
13624 sd = map_nick2sd(script_getstr(st,2));
13625 else
13626 sd = script_rid2sd(st);
13627
13628 if(sd)
13629 script_pushint(st,sd->state.vending);
13630 else
13631 script_pushint(st,0);
13632
13633 return 0;
13634}
13635
13636
13637BUILDIN_FUNC(checkchatting) // check chatting [Marka]
13638{
13639 TBL_PC *sd = NULL;
13640
13641 if(script_hasdata(st,2))
13642 sd = map_nick2sd(script_getstr(st,2));
13643 else
13644 sd = script_rid2sd(st);
13645
13646 if(sd)
13647 script_pushint(st,(sd->chatID != 0));
13648 else
13649 script_pushint(st,0);
13650
13651 return 0;
13652}
13653
13654BUILDIN_FUNC(searchitem)
13655{
13656 struct script_data* data = script_getdata(st, 2);
13657 const char *itemname = script_getstr(st,3);
13658 struct item_data *items[MAX_SEARCH];
13659 int count;
13660
13661 char* name;
13662 int32 start;
13663 int32 id;
13664 int32 i;
13665 TBL_PC* sd = NULL;
13666
13667 if ((items[0] = itemdb_exists(atoi(itemname))))
13668 count = 1;
13669 else {
13670 count = itemdb_searchname_array(items, ARRAYLENGTH(items), itemname);
13671 if (count > MAX_SEARCH) count = MAX_SEARCH;
13672 }
13673
13674 if (!count) {
13675 script_pushint(st, 0);
13676 return 0;
13677 }
13678
13679 if( !data_isreference(data) )
13680 {
13681 ShowError("script:searchitem: not a variable\n");
13682 script_reportdata(data);
13683 st->state = END;
13684 return 1;// not a variable
13685 }
13686
13687 id = reference_getid(data);
13688 start = reference_getindex(data);
13689 name = reference_getname(data);
13690 if( not_array_variable(*name) )
13691 {
13692 ShowError("script:searchitem: illegal scope\n");
13693 script_reportdata(data);
13694 st->state = END;
13695 return 1;// not supported
13696 }
13697
13698 if( not_server_variable(*name) )
13699 {
13700 sd = script_rid2sd(st);
13701 if( sd == NULL )
13702 return 0;// no player attached
13703 }
13704
13705 if( is_string_variable(name) )
13706 {// string array
13707 ShowError("script:searchitem: not an integer array reference\n");
13708 script_reportdata(data);
13709 st->state = END;
13710 return 1;// not supported
13711 }
13712
13713 for( i = 0; i < count; ++start, ++i )
13714 {// Set array
13715 void* v = (void*)items[i]->nameid;
13716 set_reg(st, sd, reference_uid(id, start), name, v, reference_getref(data));
13717 }
13718
13719 script_pushint(st, count);
13720 return 0;
13721}
13722
13723int axtoi(const char *hexStg)
13724{
13725 int n = 0; // position in string
13726 int m = 0; // position in digit[] to shift
13727 int count; // loop index
13728 int intValue = 0; // integer value of hex string
13729 int digit[11]; // hold values to convert
13730 while (n < 10) {
13731 if (hexStg[n]=='\0')
13732 break;
13733 if (hexStg[n] > 0x29 && hexStg[n] < 0x40 ) //if 0 to 9
13734 digit[n] = hexStg[n] & 0x0f; //convert to int
13735 else if (hexStg[n] >='a' && hexStg[n] <= 'f') //if a to f
13736 digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int
13737 else if (hexStg[n] >='A' && hexStg[n] <= 'F') //if A to F
13738 digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int
13739 else break;
13740 n++;
13741 }
13742 count = n;
13743 m = n - 1;
13744 n = 0;
13745 while(n < count) {
13746 // digit[n] is value of hex digit at position n
13747 // (m << 2) is the number of positions to shift
13748 // OR the bits into return value
13749 intValue = intValue | (digit[n] << (m << 2));
13750 m--; // adjust the position to set
13751 n++; // next digit to process
13752 }
13753 return (intValue);
13754}
13755
13756// [Lance] Hex string to integer converter
13757BUILDIN_FUNC(axtoi)
13758{
13759 const char *hex = script_getstr(st,2);
13760 script_pushint(st,axtoi(hex));
13761 return 0;
13762}
13763
13764// [zBuffer] List of player cont commands --->
13765BUILDIN_FUNC(rid2name)
13766{
13767 struct block_list *bl = NULL;
13768 int rid = script_getnum(st,2);
13769 if((bl = map_id2bl(rid)))
13770 {
13771 switch(bl->type) {
13772 case BL_MOB: script_pushstrcopy(st,((TBL_MOB*)bl)->name); break;
13773 case BL_PC: script_pushstrcopy(st,((TBL_PC*)bl)->status.name); break;
13774 case BL_NPC: script_pushstrcopy(st,((TBL_NPC*)bl)->exname); break;
13775 case BL_PET: script_pushstrcopy(st,((TBL_PET*)bl)->pet.name); break;
13776 case BL_HOM: script_pushstrcopy(st,((TBL_HOM*)bl)->homunculus.name); break;
13777 case BL_MER: script_pushstrcopy(st,((TBL_MER*)bl)->db->name); break;
13778 default:
13779 ShowError("buildin_rid2name: BL type unknown.\n");
13780 script_pushconststr(st,"");
13781 break;
13782 }
13783 } else {
13784 ShowError("buildin_rid2name: invalid RID\n");
13785 script_pushconststr(st,"(null)");
13786 }
13787 return 0;
13788}
13789
13790BUILDIN_FUNC(pcblockmove)
13791{
13792 int id, flag;
13793 TBL_PC *sd = NULL;
13794
13795 id = script_getnum(st,2);
13796 flag = script_getnum(st,3);
13797
13798 if(id)
13799 sd = map_id2sd(id);
13800 else
13801 sd = script_rid2sd(st);
13802
13803 if(sd)
13804 sd->state.blockedmove = flag > 0;
13805
13806 return 0;
13807}
13808
13809BUILDIN_FUNC(pcfollow)
13810{
13811 int id, targetid;
13812 TBL_PC *sd = NULL;
13813
13814
13815 id = script_getnum(st,2);
13816 targetid = script_getnum(st,3);
13817
13818 if(id)
13819 sd = map_id2sd(id);
13820 else
13821 sd = script_rid2sd(st);
13822
13823 if(sd)
13824 pc_follow(sd, targetid);
13825
13826 return 0;
13827}
13828
13829BUILDIN_FUNC(pcstopfollow)
13830{
13831 int id;
13832 TBL_PC *sd = NULL;
13833
13834
13835 id = script_getnum(st,2);
13836
13837 if(id)
13838 sd = map_id2sd(id);
13839 else
13840 sd = script_rid2sd(st);
13841
13842 if(sd)
13843 pc_stop_following(sd);
13844
13845 return 0;
13846}
13847// <--- [zBuffer] List of player cont commands
13848// [zBuffer] List of mob control commands --->
13849//## TODO always return if the request/whatever was successfull [FlavioJS]
13850
13851/// Makes the unit walk to target position or map
13852/// Returns if it was successfull
13853///
13854/// unitwalk(<unit_id>,<x>,<y>) -> <bool>
13855/// unitwalk(<unit_id>,<map_id>) -> <bool>
13856BUILDIN_FUNC(unitwalk)
13857{
13858 struct block_list* bl;
13859
13860 bl = map_id2bl(script_getnum(st,2));
13861 if( bl == NULL )
13862 {
13863 script_pushint(st, 0);
13864 }
13865 else if( script_hasdata(st,4) )
13866 {
13867 int x = script_getnum(st,3);
13868 int y = script_getnum(st,4);
13869 script_pushint(st, unit_walktoxy(bl,x,y,0));// We'll use harder calculations.
13870 }
13871 else
13872 {
13873 int map_id = script_getnum(st,3);
13874 script_pushint(st, unit_walktobl(bl,map_id2bl(map_id),65025,1));
13875 }
13876
13877 return 0;
13878}
13879
13880/// Kills the unit
13881///
13882/// unitkill <unit_id>;
13883BUILDIN_FUNC(unitkill)
13884{
13885 struct block_list* bl = map_id2bl(script_getnum(st,2));
13886 if( bl != NULL )
13887 status_kill(bl);
13888
13889 return 0;
13890}
13891
13892/// Warps the unit to the target position in the target map
13893/// Returns if it was successfull
13894///
13895/// unitwarp(<unit_id>,"<map name>",<x>,<y>) -> <bool>
13896BUILDIN_FUNC(unitwarp)
13897{
13898 int unit_id;
13899 int map;
13900 short x;
13901 short y;
13902 struct block_list* bl;
13903 const char *mapname;
13904
13905 unit_id = script_getnum(st,2);
13906 mapname = script_getstr(st, 3);
13907 x = (short)script_getnum(st,4);
13908 y = (short)script_getnum(st,5);
13909
13910 if (!unit_id) //Warp the script's runner
13911 bl = map_id2bl(st->rid);
13912 else
13913 bl = map_id2bl(unit_id);
13914
13915 if( strcmp(mapname,"this") == 0 )
13916 map = bl?bl->m:-1;
13917 else
13918 map = map_mapname2mapid(mapname);
13919
13920 if( map >= 0 && bl != NULL )
13921 script_pushint(st, unit_warp(bl,map,x,y,CLR_OUTSIGHT));
13922 else
13923 script_pushint(st, 0);
13924
13925 return 0;
13926}
13927
13928/// Makes the unit attack the target.
13929/// If the unit is a player and <action type> is not 0, it does a continuous
13930/// attack instead of a single attack.
13931/// Returns if the request was successfull.
13932///
13933/// unitattack(<unit_id>,"<target name>"{,<action type>}) -> <bool>
13934/// unitattack(<unit_id>,<target_id>{,<action type>}) -> <bool>
13935BUILDIN_FUNC(unitattack)
13936{
13937 struct block_list* unit_bl;
13938 struct block_list* target_bl = NULL;
13939 struct script_data* data;
13940 int actiontype = 0;
13941
13942 // get unit
13943 unit_bl = map_id2bl(script_getnum(st,2));
13944 if( unit_bl == NULL ) {
13945 script_pushint(st, 0);
13946 return 0;
13947 }
13948
13949 data = script_getdata(st, 3);
13950 get_val(st, data);
13951 if( data_isstring(data) )
13952 {
13953 TBL_PC* sd = map_nick2sd(conv_str(st, data));
13954 if( sd != NULL )
13955 target_bl = &sd->bl;
13956 } else
13957 target_bl = map_id2bl(conv_num(st, data));
13958 // request the attack
13959 if( target_bl == NULL )
13960 {
13961 script_pushint(st, 0);
13962 return 0;
13963 }
13964
13965 // get actiontype
13966 if( script_hasdata(st,4) )
13967 actiontype = script_getnum(st,4);
13968
13969 switch( unit_bl->type )
13970 {
13971 case BL_PC:
13972 clif_parse_ActionRequest_sub(((TBL_PC *)unit_bl), actiontype > 0 ? 0x07 : 0x00, target_bl->id, gettick());
13973 script_pushint(st, 1);
13974 return 0;
13975 case BL_MOB:
13976 ((TBL_MOB *)unit_bl)->target_id = target_bl->id;
13977 break;
13978 case BL_PET:
13979 ((TBL_PET *)unit_bl)->target_id = target_bl->id;
13980 break;
13981 default:
13982 ShowError("script:unitattack: unsupported source unit type %d\n", unit_bl->type);
13983 script_pushint(st, 0);
13984 return 1;
13985 }
13986 script_pushint(st, unit_walktobl(unit_bl, target_bl, 65025, 2));
13987 return 0;
13988}
13989
13990/// Makes the unit stop attacking and moving
13991///
13992/// unitstop <unit_id>;
13993BUILDIN_FUNC(unitstop)
13994{
13995 int unit_id;
13996 struct block_list* bl;
13997
13998 unit_id = script_getnum(st,2);
13999
14000 bl = map_id2bl(unit_id);
14001 if( bl != NULL )
14002 {
14003 unit_stop_attack(bl);
14004 unit_stop_walking(bl,4);
14005 if( bl->type == BL_MOB )
14006 ((TBL_MOB*)bl)->target_id = 0;
14007 }
14008
14009 return 0;
14010}
14011
14012/// Makes the unit say the message
14013///
14014/// unittalk <unit_id>,"<message>";
14015BUILDIN_FUNC(unittalk)
14016{
14017 int unit_id;
14018 const char* message;
14019 struct block_list* bl;
14020
14021 unit_id = script_getnum(st,2);
14022 message = script_getstr(st, 3);
14023
14024 bl = map_id2bl(unit_id);
14025 if( bl != NULL )
14026 {
14027 struct StringBuf sbuf;
14028 StringBuf_Init(&sbuf);
14029 StringBuf_Printf(&sbuf, "%s : %s", status_get_name(bl), message);
14030 clif_message(bl, StringBuf_Value(&sbuf));
14031 if( bl->type == BL_PC )
14032 clif_displaymessage(((TBL_PC*)bl)->fd, StringBuf_Value(&sbuf));
14033 StringBuf_Destroy(&sbuf);
14034 }
14035
14036 return 0;
14037}
14038
14039/// Makes the unit do an emotion
14040///
14041/// unitemote <unit_id>,<emotion>;
14042///
14043/// @see e_* in const.txt
14044BUILDIN_FUNC(unitemote)
14045{
14046 int unit_id;
14047 int emotion;
14048 struct block_list* bl;
14049
14050 unit_id = script_getnum(st,2);
14051 emotion = script_getnum(st,3);
14052 bl = map_id2bl(unit_id);
14053 if( bl != NULL )
14054 clif_emotion(bl, emotion);
14055
14056 return 0;
14057}
14058
14059/// Makes the unit cast the skill on the target or self if no target is specified
14060///
14061/// unitskilluseid <unit_id>,<skill_id>,<skill_lv>{,<target_id>};
14062/// unitskilluseid <unit_id>,"<skill name>",<skill_lv>{,<target_id>};
14063BUILDIN_FUNC(unitskilluseid)
14064{
14065 int unit_id;
14066 int skill_id;
14067 int skill_lv;
14068 int target_id;
14069 struct block_list* bl;
14070
14071 unit_id = script_getnum(st,2);
14072 skill_id = ( script_isstring(st,3) ? skill_name2id(script_getstr(st,3)) : script_getnum(st,3) );
14073 skill_lv = script_getnum(st,4);
14074 target_id = ( script_hasdata(st,5) ? script_getnum(st,5) : unit_id );
14075
14076 bl = map_id2bl(unit_id);
14077 if( bl != NULL )
14078 unit_skilluse_id(bl, target_id, skill_id, skill_lv);
14079
14080 return 0;
14081}
14082
14083/// Makes the unit cast the skill on the target position.
14084///
14085/// unitskillusepos <unit_id>,<skill_id>,<skill_lv>,<target_x>,<target_y>;
14086/// unitskillusepos <unit_id>,"<skill name>",<skill_lv>,<target_x>,<target_y>;
14087BUILDIN_FUNC(unitskillusepos)
14088{
14089 int unit_id;
14090 int skill_id;
14091 int skill_lv;
14092 int skill_x;
14093 int skill_y;
14094 struct block_list* bl;
14095
14096 unit_id = script_getnum(st,2);
14097 skill_id = ( script_isstring(st,3) ? skill_name2id(script_getstr(st,3)) : script_getnum(st,3) );
14098 skill_lv = script_getnum(st,4);
14099 skill_x = script_getnum(st,5);
14100 skill_y = script_getnum(st,6);
14101
14102 bl = map_id2bl(unit_id);
14103 if( bl != NULL )
14104 unit_skilluse_pos(bl, skill_x, skill_y, skill_id, skill_lv);
14105
14106 return 0;
14107}
14108
14109// <--- [zBuffer] List of mob control commands
14110
14111/// Pauses the execution of the script, detaching the player
14112///
14113/// sleep <mili seconds>;
14114BUILDIN_FUNC(sleep)
14115{
14116 int ticks;
14117
14118 ticks = script_getnum(st,2);
14119
14120 // detach the player
14121 script_detach_rid(st);
14122
14123 if( ticks <= 0 )
14124 {// do nothing
14125 }
14126 else if( st->sleep.tick == 0 )
14127 {// sleep for the target amount of time
14128 st->state = RERUNLINE;
14129 st->sleep.tick = ticks;
14130 }
14131 else
14132 {// sleep time is over
14133 st->state = RUN;
14134 st->sleep.tick = 0;
14135 }
14136 return 0;
14137}
14138
14139/// Pauses the execution of the script, keeping the player attached
14140/// Returns if a player is still attached
14141///
14142/// sleep2(<mili secconds>) -> <bool>
14143BUILDIN_FUNC(sleep2)
14144{
14145 int ticks;
14146
14147 ticks = script_getnum(st,2);
14148
14149 if( ticks <= 0 )
14150 {// do nothing
14151 script_pushint(st, (map_id2sd(st->rid)!=NULL));
14152 }
14153 else if( !st->sleep.tick )
14154 {// sleep for the target amount of time
14155 st->state = RERUNLINE;
14156 st->sleep.tick = ticks;
14157 }
14158 else
14159 {// sleep time is over
14160 st->state = RUN;
14161 st->sleep.tick = 0;
14162 script_pushint(st, (map_id2sd(st->rid)!=NULL));
14163 }
14164 return 0;
14165}
14166
14167/// Awakes all the sleep timers of the target npc
14168///
14169/// awake "<npc name>";
14170BUILDIN_FUNC(awake)
14171{
14172 struct npc_data* nd;
14173 struct linkdb_node *node = (struct linkdb_node *)sleep_db;
14174
14175 nd = npc_name2id(script_getstr(st, 2));
14176 if( nd == NULL ) {
14177 ShowError("awake: NPC \"%s\" not found\n", script_getstr(st, 2));
14178 return 1;
14179 }
14180
14181 while( node )
14182 {
14183 if( (int)node->key == nd->bl.id )
14184 {// sleep timer for the npc
14185 struct script_state* tst = (struct script_state*)node->data;
14186 TBL_PC* sd = map_id2sd(tst->rid);
14187
14188 if( tst->sleep.timer == INVALID_TIMER )
14189 {// already awake ???
14190 node = node->next;
14191 continue;
14192 }
14193 if( (sd && sd->status.char_id != tst->sleep.charid) || (tst->rid && !sd))
14194 {// char not online anymore / another char of the same account is online - Cancel execution
14195 tst->state = END;
14196 tst->rid = 0;
14197 }
14198
14199 delete_timer(tst->sleep.timer, run_script_timer);
14200 node = script_erase_sleepdb(node);
14201 tst->sleep.timer = INVALID_TIMER;
14202 if(tst->state != RERUNLINE)
14203 tst->sleep.tick = 0;
14204 run_script_main(tst);
14205 }
14206 else
14207 {
14208 node = node->next;
14209 }
14210 }
14211 return 0;
14212}
14213
14214/// Returns a reference to a variable of the target NPC.
14215/// Returns 0 if an error occurs.
14216///
14217/// getvariableofnpc(<variable>, "<npc name>") -> <reference>
14218BUILDIN_FUNC(getvariableofnpc)
14219{
14220 struct script_data* data;
14221 const char* name;
14222 struct npc_data* nd;
14223
14224 data = script_getdata(st,2);
14225 if( !data_isreference(data) )
14226 {// Not a reference (aka varaible name)
14227 ShowError("script:getvariableofnpc: not a variable\n");
14228 script_reportdata(data);
14229 script_pushnil(st);
14230 st->state = END;
14231 return 1;
14232 }
14233
14234 name = reference_getname(data);
14235 if( *name != '.' || name[1] == '@' )
14236 {// not a npc variable
14237 ShowError("script:getvariableofnpc: invalid scope (not npc variable)\n");
14238 script_reportdata(data);
14239 script_pushnil(st);
14240 st->state = END;
14241 return 1;
14242 }
14243
14244 nd = npc_name2id(script_getstr(st,3));
14245 if( nd == NULL || nd->subtype != SCRIPT || nd->u.scr.script == NULL )
14246 {// NPC not found or has no script
14247 ShowError("script:getvariableofnpc: can't find npc %s\n", script_getstr(st,3));
14248 script_pushnil(st);
14249 st->state = END;
14250 return 1;
14251 }
14252
14253 push_val2(st->stack, C_NAME, reference_getuid(data), &nd->u.scr.script->script_vars );
14254 return 0;
14255}
14256
14257/// Opens a warp portal.
14258/// Has no "portal opening" effect/sound, it opens the portal immediately.
14259///
14260/// warpportal <source x>,<source y>,"<target map>",<target x>,<target y>;
14261///
14262/// @author blackhole89
14263BUILDIN_FUNC(warpportal)
14264{
14265 int spx;
14266 int spy;
14267 unsigned short mapindex;
14268 int tpx;
14269 int tpy;
14270 struct skill_unit_group* group;
14271 struct block_list* bl;
14272
14273 bl = map_id2bl(st->oid);
14274 if( bl == NULL )
14275 {
14276 ShowError("script:warpportal: npc is needed\n");
14277 return 1;
14278 }
14279
14280 spx = script_getnum(st,2);
14281 spy = script_getnum(st,3);
14282 mapindex = mapindex_name2id(script_getstr(st, 4));
14283 tpx = script_getnum(st,5);
14284 tpy = script_getnum(st,6);
14285
14286 if( mapindex == 0 )
14287 return 0;// map not found
14288
14289 group = skill_unitsetting(bl, AL_WARP, 4, spx, spy, 0);
14290 if( group == NULL )
14291 return 0;// failed
14292 group->val2 = (tpx<<16) | tpy;
14293 group->val3 = mapindex;
14294
14295 return 0;
14296}
14297
14298BUILDIN_FUNC(openmail)
14299{
14300 TBL_PC* sd;
14301
14302 sd = script_rid2sd(st);
14303 if( sd == NULL )
14304 return 0;
14305
14306#ifndef TXT_ONLY
14307 mail_openmail(sd);
14308#endif
14309 return 0;
14310}
14311
14312BUILDIN_FUNC(openauction)
14313{
14314 TBL_PC* sd;
14315
14316 sd = script_rid2sd(st);
14317 if( sd == NULL )
14318 return 0;
14319
14320#ifndef TXT_ONLY
14321 clif_Auction_openwindow(sd);
14322#endif
14323 return 0;
14324}
14325
14326/// Retrieves the value of the specified flag of the specified cell.
14327///
14328/// checkcell("<map name>",<x>,<y>,<type>) -> <bool>
14329///
14330/// @see cell_chk* constants in const.txt for the types
14331BUILDIN_FUNC(checkcell)
14332{
14333 int m = map_mapname2mapid(script_getstr(st,2));
14334 int x = script_getnum(st,3);
14335 int y = script_getnum(st,4);
14336 cell_chk type = (cell_chk)script_getnum(st,5);
14337
14338 script_pushint(st, map_getcell(m, x, y, type));
14339
14340 return 0;
14341}
14342
14343/// Modifies flags of cells in the specified area.
14344///
14345/// setcell "<map name>",<x1>,<y1>,<x2>,<y2>,<type>,<flag>;
14346///
14347/// @see cell_* constants in const.txt for the types
14348BUILDIN_FUNC(setcell)
14349{
14350 int m = map_mapname2mapid(script_getstr(st,2));
14351 int x1 = script_getnum(st,3);
14352 int y1 = script_getnum(st,4);
14353 int x2 = script_getnum(st,5);
14354 int y2 = script_getnum(st,6);
14355 cell_t type = (cell_t)script_getnum(st,7);
14356 bool flag = (bool)script_getnum(st,8);
14357
14358 int x,y;
14359
14360 if( x1 > x2 ) swap(x1,x2);
14361 if( y1 > y2 ) swap(y1,y2);
14362
14363 for( y = y1; y <= y2; ++y )
14364 for( x = x1; x <= x2; ++x )
14365 map_setcell(m, x, y, type, flag);
14366
14367 return 0;
14368}
14369
14370/*==========================================
14371 * Mercenary Commands
14372 *------------------------------------------*/
14373BUILDIN_FUNC(mercenary_create)
14374{
14375#ifndef TXT_ONLY
14376 struct map_session_data *sd;
14377 int class_, contract_time;
14378
14379 if( (sd = script_rid2sd(st)) == NULL || sd->md || sd->status.mer_id != 0 )
14380 return 0;
14381
14382 class_ = script_getnum(st,2);
14383
14384 if( !merc_class(class_) )
14385 return 0;
14386
14387 contract_time = script_getnum(st,3);
14388 merc_create(sd, class_, contract_time);
14389#endif
14390 return 0;
14391}
14392
14393BUILDIN_FUNC(mercenary_heal)
14394{
14395 struct map_session_data *sd = script_rid2sd(st);
14396 int hp, sp;
14397
14398 if( sd == NULL || sd->md == NULL )
14399 return 0;
14400 hp = script_getnum(st,2);
14401 sp = script_getnum(st,3);
14402
14403 status_heal(&sd->md->bl, hp, sp, 0);
14404 return 0;
14405}
14406
14407BUILDIN_FUNC(mercenary_sc_start)
14408{
14409 struct map_session_data *sd = script_rid2sd(st);
14410 enum sc_type type;
14411 int tick, val1;
14412
14413 if( sd == NULL || sd->md == NULL )
14414 return 0;
14415
14416 type = (sc_type)script_getnum(st,2);
14417 tick = script_getnum(st,3);
14418 val1 = script_getnum(st,4);
14419
14420 status_change_start(&sd->md->bl, type, 10000, val1, 0, 0, 0, tick, 2);
14421 return 0;
14422}
14423
14424BUILDIN_FUNC(mercenary_get_calls)
14425{
14426 struct map_session_data *sd = script_rid2sd(st);
14427 int guild;
14428
14429 if( sd == NULL )
14430 return 0;
14431
14432 guild = script_getnum(st,2);
14433 switch( guild )
14434 {
14435 case ARCH_MERC_GUILD:
14436 script_pushint(st,sd->status.arch_calls);
14437 break;
14438 case SPEAR_MERC_GUILD:
14439 script_pushint(st,sd->status.spear_calls);
14440 break;
14441 case SWORD_MERC_GUILD:
14442 script_pushint(st,sd->status.sword_calls);
14443 break;
14444 default:
14445 script_pushint(st,0);
14446 break;
14447 }
14448
14449 return 0;
14450}
14451
14452BUILDIN_FUNC(mercenary_set_calls)
14453{
14454 struct map_session_data *sd = script_rid2sd(st);
14455 int guild, value, *calls;
14456
14457 if( sd == NULL )
14458 return 0;
14459
14460 guild = script_getnum(st,2);
14461 value = script_getnum(st,3);
14462
14463 switch( guild )
14464 {
14465 case ARCH_MERC_GUILD:
14466 calls = &sd->status.arch_calls;
14467 break;
14468 case SPEAR_MERC_GUILD:
14469 calls = &sd->status.spear_calls;
14470 break;
14471 case SWORD_MERC_GUILD:
14472 calls = &sd->status.sword_calls;
14473 break;
14474 default:
14475 return 0; // Invalid Guild
14476 }
14477
14478 *calls += value;
14479 *calls = cap_value(*calls, 0, INT_MAX);
14480
14481 return 0;
14482}
14483
14484BUILDIN_FUNC(mercenary_get_faith)
14485{
14486 struct map_session_data *sd = script_rid2sd(st);
14487 int guild;
14488
14489 if( sd == NULL )
14490 return 0;
14491
14492 guild = script_getnum(st,2);
14493 switch( guild )
14494 {
14495 case ARCH_MERC_GUILD:
14496 script_pushint(st,sd->status.arch_faith);
14497 break;
14498 case SPEAR_MERC_GUILD:
14499 script_pushint(st,sd->status.spear_faith);
14500 break;
14501 case SWORD_MERC_GUILD:
14502 script_pushint(st,sd->status.sword_faith);
14503 break;
14504 default:
14505 script_pushint(st,0);
14506 break;
14507 }
14508
14509 return 0;
14510}
14511
14512BUILDIN_FUNC(mercenary_set_faith)
14513{
14514 struct map_session_data *sd = script_rid2sd(st);
14515 int guild, value, *calls;
14516
14517 if( sd == NULL )
14518 return 0;
14519
14520 guild = script_getnum(st,2);
14521 value = script_getnum(st,3);
14522
14523 switch( guild )
14524 {
14525 case ARCH_MERC_GUILD:
14526 calls = &sd->status.arch_faith;
14527 break;
14528 case SPEAR_MERC_GUILD:
14529 calls = &sd->status.spear_faith;
14530 break;
14531 case SWORD_MERC_GUILD:
14532 calls = &sd->status.sword_faith;
14533 break;
14534 default:
14535 return 0; // Invalid Guild
14536 }
14537
14538 *calls += value;
14539 *calls = cap_value(*calls, 0, INT_MAX);
14540 if( mercenary_get_guild(sd->md) == guild )
14541 clif_mercenary_updatestatus(sd,SP_MERCFAITH);
14542
14543 return 0;
14544}
14545
14546/*------------------------------------------
14547 * Book Reading
14548 *------------------------------------------*/
14549BUILDIN_FUNC(readbook)
14550{
14551 struct map_session_data *sd;
14552 int book_id, page;
14553
14554 if( (sd = script_rid2sd(st)) == NULL )
14555 return 0;
14556
14557 book_id = script_getnum(st,2);
14558 page = script_getnum(st,3);
14559
14560 clif_readbook(sd->fd, book_id, page);
14561 return 0;
14562}
14563
14564/******************
14565Questlog script commands
14566*******************/
14567
14568BUILDIN_FUNC(setquest)
14569{
14570 TBL_PC * sd = script_rid2sd(st);
14571
14572 quest_add(sd, script_getnum(st, 2));
14573 return 0;
14574}
14575
14576BUILDIN_FUNC(erasequest)
14577{
14578 TBL_PC * sd = script_rid2sd(st);
14579
14580 quest_delete(sd, script_getnum(st, 2));
14581 return 0;
14582}
14583
14584BUILDIN_FUNC(completequest)
14585{
14586 TBL_PC * sd = script_rid2sd(st);
14587
14588 quest_update_status(sd, script_getnum(st, 2), Q_COMPLETE);
14589 return 0;
14590}
14591
14592BUILDIN_FUNC(changequest)
14593{
14594 TBL_PC * sd = script_rid2sd(st);
14595
14596 quest_change(sd, script_getnum(st, 2),script_getnum(st, 3));
14597 return 0;
14598}
14599
14600BUILDIN_FUNC(checkquest)
14601{
14602 TBL_PC * sd = script_rid2sd(st);
14603 quest_check_type type = HAVEQUEST;
14604
14605 if( script_hasdata(st, 3) )
14606 type = (quest_check_type)script_getnum(st, 3);
14607
14608 script_pushint(st, quest_check(sd, script_getnum(st, 2), type));
14609
14610 return 0;
14611}
14612
14613BUILDIN_FUNC(showevent)
14614{
14615 TBL_PC *sd = script_rid2sd(st);
14616 struct npc_data *nd = map_id2nd(st->oid);
14617 int state, color;
14618
14619 if( sd == NULL || nd == NULL )
14620 return 0;
14621 state = script_getnum(st, 2);
14622 color = script_getnum(st, 3);
14623
14624 if( color < 0 || color > 4 )
14625 color = 0; // set default color
14626
14627 clif_quest_show_event(sd, &nd->bl, state, color);
14628 return 0;
14629}
14630
14631/*==========================================
14632 * BattleGround System
14633 *------------------------------------------*/
14634BUILDIN_FUNC(waitingroom2bg)
14635{
14636 struct npc_data *nd;
14637 struct chat_data *cd;
14638 const char *map_name, *ev = "", *dev = "";
14639 int x, y, i, mapindex = 0, bg_id, n;
14640 struct map_session_data *sd;
14641
14642 if( script_hasdata(st,7) )
14643 nd = npc_name2id(script_getstr(st,7));
14644 else
14645 nd = (struct npc_data *)map_id2bl(st->oid);
14646
14647 if( nd == NULL || (cd = (struct chat_data *)map_id2bl(nd->chat_id)) == NULL )
14648 {
14649 script_pushint(st,0);
14650 return 0;
14651 }
14652
14653 map_name = script_getstr(st,2);
14654 if( strcmp(map_name,"-") != 0 )
14655 {
14656 mapindex = mapindex_name2id(map_name);
14657 if( mapindex == 0 )
14658 { // Invalid Map
14659 script_pushint(st,0);
14660 return 0;
14661 }
14662 }
14663
14664 x = script_getnum(st,3);
14665 y = script_getnum(st,4);
14666 ev = script_getstr(st,5); // Logout Event
14667 dev = script_getstr(st,6); // Die Event
14668
14669 if( (bg_id = bg_create(mapindex, x, y, ev, dev)) == 0 )
14670 { // Creation failed
14671 script_pushint(st,0);
14672 return 0;
14673 }
14674
14675 n = cd->users;
14676 for( i = 0; i < n && i < MAX_BG_MEMBERS; i++ )
14677 {
14678 if( (sd = cd->usersd[i]) != NULL && bg_team_join(bg_id, sd) )
14679 mapreg_setreg(reference_uid(add_str("$@arenamembers"), i), sd->bl.id);
14680 else
14681 mapreg_setreg(reference_uid(add_str("$@arenamembers"), i), 0);
14682 }
14683
14684 mapreg_setreg(add_str("$@arenamembersnum"), i);
14685 script_pushint(st,bg_id);
14686 return 0;
14687}
14688
14689BUILDIN_FUNC(waitingroom2bg_single)
14690{
14691 const char* map_name;
14692 struct npc_data *nd;
14693 struct chat_data *cd;
14694 struct map_session_data *sd;
14695 int x, y, mapindex, bg_id;
14696
14697 bg_id = script_getnum(st,2);
14698 map_name = script_getstr(st,3);
14699 if( (mapindex = mapindex_name2id(map_name)) == 0 )
14700 return 0; // Invalid Map
14701
14702 x = script_getnum(st,4);
14703 y = script_getnum(st,5);
14704 nd = npc_name2id(script_getstr(st,6));
14705
14706 if( nd == NULL || (cd = (struct chat_data *)map_id2bl(nd->chat_id)) == NULL || cd->users <= 0 )
14707 return 0;
14708
14709 if( (sd = cd->usersd[0]) == NULL )
14710 return 0;
14711
14712 if( bg_team_join(bg_id, sd) )
14713 {
14714 pc_setpos(sd, mapindex, x, y, CLR_TELEPORT);
14715 script_pushint(st,1);
14716 }
14717 else
14718 script_pushint(st,0);
14719
14720 return 0;
14721}
14722
14723BUILDIN_FUNC(bg_team_setxy)
14724{
14725 struct battleground_data *bg;
14726 int bg_id;
14727
14728 bg_id = script_getnum(st,2);
14729 if( (bg = bg_team_search(bg_id)) == NULL )
14730 return 0;
14731
14732 bg->x = script_getnum(st,3);
14733 bg->y = script_getnum(st,4);
14734 return 0;
14735}
14736
14737BUILDIN_FUNC(bg_warp)
14738{
14739 int x, y, mapindex, bg_id;
14740 const char* map_name;
14741
14742 bg_id = script_getnum(st,2);
14743 map_name = script_getstr(st,3);
14744 if( (mapindex = mapindex_name2id(map_name)) == 0 )
14745 return 0; // Invalid Map
14746 x = script_getnum(st,4);
14747 y = script_getnum(st,5);
14748 bg_team_warp(bg_id, mapindex, x, y);
14749 return 0;
14750}
14751
14752BUILDIN_FUNC(bg_monster)
14753{
14754 int class_ = 0, x = 0, y = 0, bg_id = 0;
14755 const char *str,*map, *evt="";
14756
14757 bg_id = script_getnum(st,2);
14758 map = script_getstr(st,3);
14759 x = script_getnum(st,4);
14760 y = script_getnum(st,5);
14761 str = script_getstr(st,6);
14762 class_ = script_getnum(st,7);
14763 if( script_hasdata(st,8) ) evt = script_getstr(st,8);
14764 check_event(st, evt);
14765 script_pushint(st, mob_spawn_bg(map,x,y,str,class_,evt,bg_id));
14766 return 0;
14767}
14768
14769BUILDIN_FUNC(bg_monster_set_team)
14770{
14771 struct mob_data *md;
14772 struct block_list *mbl;
14773 int id = script_getnum(st,2),
14774 bg_id = script_getnum(st,3);
14775
14776 if( (mbl = map_id2bl(id)) == NULL || mbl->type != BL_MOB )
14777 return 0;
14778 md = (TBL_MOB *)mbl;
14779 md->bg_id = bg_id;
14780
14781 mob_stop_attack(md);
14782 mob_stop_walking(md, 0);
14783 md->target_id = md->attacked_id = 0;
14784 clif_charnameack(0, &md->bl);
14785
14786 return 0;
14787}
14788
14789BUILDIN_FUNC(bg_leave)
14790{
14791 struct map_session_data *sd = script_rid2sd(st);
14792 if( sd == NULL || !sd->bg_id )
14793 return 0;
14794
14795 bg_team_leave(sd,0);
14796 return 0;
14797}
14798
14799BUILDIN_FUNC(bg_destroy)
14800{
14801 int bg_id = script_getnum(st,2);
14802 bg_team_delete(bg_id);
14803 return 0;
14804}
14805
14806BUILDIN_FUNC(bg_getareausers)
14807{
14808 const char *str;
14809 int m, x0, y0, x1, y1, bg_id;
14810 int i = 0, c = 0;
14811 struct battleground_data *bg = NULL;
14812 struct map_session_data *sd;
14813
14814 bg_id = script_getnum(st,2);
14815 str = script_getstr(st,3);
14816
14817 if( (bg = bg_team_search(bg_id)) == NULL || (m = map_mapname2mapid(str)) < 0 )
14818 {
14819 script_pushint(st,0);
14820 return 0;
14821 }
14822
14823 x0 = script_getnum(st,4);
14824 y0 = script_getnum(st,5);
14825 x1 = script_getnum(st,6);
14826 y1 = script_getnum(st,7);
14827
14828 for( i = 0; i < MAX_BG_MEMBERS; i++ )
14829 {
14830 if( (sd = bg->members[i].sd) == NULL )
14831 continue;
14832 if( sd->bl.m != m || sd->bl.x < x0 || sd->bl.y < y0 || sd->bl.x > x1 || sd->bl.y > y1 )
14833 continue;
14834 c++;
14835 }
14836
14837 script_pushint(st,c);
14838 return 0;
14839}
14840
14841BUILDIN_FUNC(bg_updatescore)
14842{
14843 const char *str;
14844 int m;
14845
14846 str = script_getstr(st,2);
14847 if( (m = map_mapname2mapid(str)) < 0 )
14848 return 0;
14849
14850 map[m].bgscore_lion = script_getnum(st,3);
14851 map[m].bgscore_eagle = script_getnum(st,4);
14852
14853 clif_bg_updatescore(m);
14854 return 0;
14855}
14856
14857BUILDIN_FUNC(bg_get_data)
14858{
14859 struct battleground_data *bg;
14860 int bg_id = script_getnum(st,2),
14861 type = script_getnum(st,3);
14862
14863 if( (bg = bg_team_search(bg_id)) == NULL )
14864 {
14865 script_pushint(st,0);
14866 return 0;
14867 }
14868
14869 switch( type )
14870 {
14871 case 0: script_pushint(st, bg->count); break;
14872 default:
14873 ShowError("script:bg_get_data: unknown data identifier %d\n", type);
14874 break;
14875 }
14876
14877 return 0;
14878}
14879
14880/*==========================================
14881 * Instancing Script Commands
14882 *------------------------------------------*/
14883
14884BUILDIN_FUNC(instance_create)
14885{
14886 const char *name;
14887 int party_id, res;
14888
14889 name = script_getstr(st, 2);
14890 party_id = script_getnum(st, 3);
14891
14892 res = instance_create(party_id, name);
14893 if( res == -4 ) // Already exists
14894 {
14895 script_pushint(st, -1);
14896 return 0;
14897 }
14898 else if( res < 0 )
14899 {
14900 const char *err;
14901 switch(res)
14902 {
14903 case -3: err = "No free instances"; break;
14904 case -2: err = "Invalid party ID"; break;
14905 case -1: err = "Invalid type"; break;
14906 default: err = "Unknown"; break;
14907 }
14908 ShowError("buildin_instance_create: %s [%d].\n", err, res);
14909 script_pushint(st, -2);
14910 return 0;
14911 }
14912
14913 script_pushint(st, res);
14914 return 0;
14915}
14916
14917BUILDIN_FUNC(instance_destroy)
14918{
14919 int instance_id;
14920 struct map_session_data *sd;
14921 struct party_data *p;
14922
14923 if( script_hasdata(st, 2) )
14924 instance_id = script_getnum(st, 2);
14925 else if( st->instance_id )
14926 instance_id = st->instance_id;
14927 else if( (sd = script_rid2sd(st)) != NULL && sd->status.party_id && (p = party_search(sd->status.party_id)) != NULL && p->instance_id )
14928 instance_id = p->instance_id;
14929 else return 0;
14930
14931 if( instance_id <= 0 || instance_id >= MAX_INSTANCE )
14932 {
14933 ShowError("buildin_instance_destroy: Trying to destroy invalid instance %d.\n", instance_id);
14934 return 0;
14935 }
14936
14937 instance_destroy(instance_id);
14938 return 0;
14939}
14940
14941BUILDIN_FUNC(instance_attachmap)
14942{
14943 const char *name;
14944 int m;
14945 int instance_id;
14946 bool usebasename = false;
14947
14948 name = script_getstr(st,2);
14949 instance_id = script_getnum(st,3);
14950 if( script_hasdata(st,4) && script_getnum(st,4) > 0)
14951 usebasename = true;
14952
14953 if( (m = instance_add_map(name, instance_id, usebasename)) < 0 ) // [Saithis]
14954 {
14955 ShowError("buildin_instance_attachmap: instance creation failed (%s): %d\n", name, m);
14956 script_pushconststr(st, "");
14957 return 0;
14958 }
14959 script_pushconststr(st, map[m].name);
14960
14961 return 0;
14962}
14963
14964BUILDIN_FUNC(instance_detachmap)
14965{
14966 struct map_session_data *sd;
14967 struct party_data *p;
14968 const char *str;
14969 int m, instance_id;
14970
14971 str = script_getstr(st, 2);
14972 if( script_hasdata(st, 3) )
14973 instance_id = script_getnum(st, 3);
14974 else if( st->instance_id )
14975 instance_id = st->instance_id;
14976 else if( (sd = script_rid2sd(st)) != NULL && sd->status.party_id && (p = party_search(sd->status.party_id)) != NULL && p->instance_id )
14977 instance_id = p->instance_id;
14978 else return 0;
14979
14980 if( (m = map_mapname2mapid(str)) < 0 || (m = instance_map2imap(m,instance_id)) < 0 )
14981 {
14982 ShowError("buildin_instance_detachmap: Trying to detach invalid map %s\n", str);
14983 return 0;
14984 }
14985
14986 instance_del_map(m);
14987 return 0;
14988}
14989
14990BUILDIN_FUNC(instance_attach)
14991{
14992 int instance_id;
14993
14994 instance_id = script_getnum(st, 2);
14995 if( instance_id <= 0 || instance_id >= MAX_INSTANCE )
14996 return 0;
14997
14998 st->instance_id = instance_id;
14999 return 0;
15000}
15001
15002BUILDIN_FUNC(instance_id)
15003{
15004 int type, instance_id;
15005 struct map_session_data *sd;
15006 struct party_data *p;
15007
15008 if( script_hasdata(st, 2) )
15009 {
15010 type = script_getnum(st, 2);
15011 if( type == 0 )
15012 instance_id = st->instance_id;
15013 else if( type == 1 && (sd = script_rid2sd(st)) != NULL && sd->status.party_id && (p = party_search(sd->status.party_id)) != NULL )
15014 instance_id = p->instance_id;
15015 else
15016 instance_id = 0;
15017 }
15018 else
15019 instance_id = st->instance_id;
15020
15021 script_pushint(st, instance_id);
15022 return 0;
15023}
15024
15025BUILDIN_FUNC(instance_set_timeout)
15026{
15027 int progress_timeout, idle_timeout;
15028 int instance_id;
15029 struct map_session_data *sd;
15030 struct party_data *p;
15031
15032 progress_timeout = script_getnum(st, 2);
15033 idle_timeout = script_getnum(st, 3);
15034
15035 if( script_hasdata(st, 4) )
15036 instance_id = script_getnum(st, 4);
15037 else if( st->instance_id )
15038 instance_id = st->instance_id;
15039 else if( (sd = script_rid2sd(st)) != NULL && sd->status.party_id && (p = party_search(sd->status.party_id)) != NULL && p->instance_id )
15040 instance_id = p->instance_id;
15041 else return 0;
15042
15043 if( instance_id > 0 )
15044 instance_set_timeout(instance_id, progress_timeout, idle_timeout);
15045
15046 return 0;
15047}
15048
15049BUILDIN_FUNC(instance_init)
15050{
15051 int instance_id = script_getnum(st, 2);
15052
15053 if( instance[instance_id].state != INSTANCE_IDLE )
15054 {
15055 ShowError("instance_init: instance already initialized.\n");
15056 return 0;
15057 }
15058
15059 instance_init(instance_id);
15060 return 0;
15061}
15062
15063BUILDIN_FUNC(instance_announce)
15064{
15065 int instance_id = script_getnum(st,2);
15066 const char *mes = script_getstr(st,3);
15067 int flag = script_getnum(st,4);
15068 const char *fontColor = script_hasdata(st,5) ? script_getstr(st,5) : NULL;
15069 int fontType = script_hasdata(st,6) ? script_getnum(st,6) : 0x190; // default fontType (FW_NORMAL)
15070 int fontSize = script_hasdata(st,7) ? script_getnum(st,7) : 12; // default fontSize
15071 int fontAlign = script_hasdata(st,8) ? script_getnum(st,8) : 0; // default fontAlign
15072 int fontY = script_hasdata(st,9) ? script_getnum(st,9) : 0; // default fontY
15073
15074 int i;
15075 struct map_session_data *sd;
15076 struct party_data *p;
15077
15078 if( instance_id == 0 )
15079 {
15080 if( st->instance_id )
15081 instance_id = st->instance_id;
15082 else if( (sd = script_rid2sd(st)) != NULL && sd->status.party_id && (p = party_search(sd->status.party_id)) != NULL && p->instance_id )
15083 instance_id = p->instance_id;
15084 else return 0;
15085 }
15086
15087 if( instance_id <= 0 || instance_id >= MAX_INSTANCE )
15088 return 0;
15089
15090 for( i = 0; i < instance[instance_id].num_map; i++ )
15091 map_foreachinmap(buildin_announce_sub, instance[instance_id].map[i], BL_PC,
15092 mes, strlen(mes)+1, flag&0xf0, fontColor, fontType, fontSize, fontAlign, fontY);
15093
15094 return 0;
15095}
15096
15097BUILDIN_FUNC(instance_npcname)
15098{
15099 const char *str;
15100 int instance_id = 0;
15101
15102 struct map_session_data *sd;
15103 struct party_data *p;
15104 struct npc_data *nd;
15105
15106 str = script_getstr(st, 2);
15107 if( script_hasdata(st, 3) )
15108 instance_id = script_getnum(st, 3);
15109 else if( st->instance_id )
15110 instance_id = st->instance_id;
15111 else if( (sd = script_rid2sd(st)) != NULL && sd->status.party_id && (p = party_search(sd->status.party_id)) != NULL && p->instance_id )
15112 instance_id = p->instance_id;
15113
15114 if( instance_id && (nd = npc_name2id(str)) != NULL )
15115 {
15116 static char npcname[NAME_LENGTH];
15117 snprintf(npcname, sizeof(npcname), "dup_%d_%d", instance_id, nd->bl.id);
15118 script_pushconststr(st,npcname);
15119 }
15120 else
15121 {
15122 ShowError("script:instance_npcname: invalid instance NPC (instance_id: %d, NPC name: \"%s\".)\n", instance_id, str);
15123 st->state = END;
15124 return 1;
15125 }
15126
15127 return 0;
15128}
15129
15130BUILDIN_FUNC(has_instance)
15131{
15132 struct map_session_data *sd;
15133 struct party_data *p;
15134 const char *str;
15135 int m, instance_id = 0;
15136
15137 str = script_getstr(st, 2);
15138 if( script_hasdata(st, 3) )
15139 instance_id = script_getnum(st, 3);
15140 else if( st->instance_id )
15141 instance_id = st->instance_id;
15142 else if( (sd = script_rid2sd(st)) != NULL && sd->status.party_id && (p = party_search(sd->status.party_id)) != NULL && p->instance_id )
15143 instance_id = p->instance_id;
15144
15145 if( !instance_id || (m = map_mapname2mapid(str)) < 0 || (m = instance_map2imap(m, instance_id)) < 0 )
15146 {
15147 script_pushconststr(st, "");
15148 return 0;
15149 }
15150
15151 script_pushconststr(st, map[m].name);
15152 return 0;
15153}
15154
15155BUILDIN_FUNC(instance_warpall)
15156{
15157 struct map_session_data *pl_sd;
15158 int m, i, instance_id;
15159 const char *mapn;
15160 int x, y;
15161 unsigned short mapindex;
15162 struct party_data *p = NULL;
15163
15164 mapn = script_getstr(st,2);
15165 x = script_getnum(st,3);
15166 y = script_getnum(st,4);
15167 if( script_hasdata(st,5) )
15168 instance_id = script_getnum(st,5);
15169 else if( st->instance_id )
15170 instance_id = st->instance_id;
15171 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 )
15172 instance_id = p->instance_id;
15173 else return 0;
15174
15175 if( (m = map_mapname2mapid(mapn)) < 0 || (map[m].flag.src4instance && (m = instance_mapid2imapid(m, instance_id)) < 0) )
15176 return 0;
15177
15178 if( !(p = party_search(instance[instance_id].party_id)) )
15179 return 0;
15180
15181 mapindex = map_id2index(m);
15182 for( i = 0; i < MAX_PARTY; i++ )
15183 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);
15184
15185 return 0;
15186}
15187
15188/*==========================================
15189 * Custom Fonts
15190 *------------------------------------------*/
15191BUILDIN_FUNC(setfont)
15192{
15193 struct map_session_data *sd = script_rid2sd(st);
15194 int font = script_getnum(st,2);
15195 if( sd == NULL )
15196 return 0;
15197
15198 if( sd->user_font != font )
15199 sd->user_font = font;
15200 else
15201 sd->user_font = 0;
15202
15203 clif_font(sd);
15204 return 0;
15205}
15206
15207static int buildin_mobuseskill_sub(struct block_list *bl,va_list ap)
15208{
15209 TBL_MOB* md = (TBL_MOB*)bl;
15210 struct block_list *tbl;
15211 int mobid = va_arg(ap,int);
15212 int skillid = va_arg(ap,int);
15213 int skilllv = va_arg(ap,int);
15214 int casttime = va_arg(ap,int);
15215 int cancel = va_arg(ap,int);
15216 int emotion = va_arg(ap,int);
15217 int target = va_arg(ap,int);
15218
15219 if( md->class_ != mobid )
15220 return 0;
15221
15222 // 0:self, 1:target, 2:master, default:random
15223 switch( target )
15224 {
15225 case 0: tbl = map_id2bl(md->bl.id); break;
15226 case 1: tbl = map_id2bl(md->target_id); break;
15227 case 2: tbl = map_id2bl(md->master_id); break;
15228 default:tbl = battle_getenemy(&md->bl, DEFAULT_ENEMY_TYPE(md),skill_get_range2(&md->bl, skillid, skilllv)); break;
15229 }
15230
15231 if( !tbl )
15232 return 0;
15233
15234 if( md->ud.skilltimer != INVALID_TIMER ) // Cancel the casting skill.
15235 unit_skillcastcancel(bl,0);
15236
15237 if( skill_get_casttype(skillid) == CAST_GROUND )
15238 unit_skilluse_pos2(&md->bl, tbl->x, tbl->y, skillid, skilllv, casttime, cancel);
15239 else
15240 unit_skilluse_id2(&md->bl, tbl->id, skillid, skilllv, casttime, cancel);
15241
15242 clif_emotion(&md->bl, emotion);
15243
15244 return 0;
15245}
15246/*==========================================
15247 * areamobuseskill "Map Name",<x>,<y>,<range>,<Mob ID>,"Skill Name"/<Skill ID>,<Skill Lv>,<Cast Time>,<Cancelable>,<Emotion>,<Target Type>;
15248 *------------------------------------------*/
15249BUILDIN_FUNC(areamobuseskill)
15250{
15251 struct block_list center;
15252 int m,range,mobid,skillid,skilllv,casttime,emotion,target,cancel;
15253
15254 if( (m = map_mapname2mapid(script_getstr(st,2))) < 0 )
15255 {
15256 ShowError("areamobuseskill: invalid map name.\n");
15257 return 0;
15258 }
15259
15260 if( map[m].flag.src4instance && st->instance_id && (m = instance_mapid2imapid(m, st->instance_id)) < 0 )
15261 return 0;
15262
15263 center.m = m;
15264 center.x = script_getnum(st,3);
15265 center.y = script_getnum(st,4);
15266 range = script_getnum(st,5);
15267 mobid = script_getnum(st,6);
15268 skillid = ( script_isstring(st,7) ? skill_name2id(script_getstr(st,7)) : script_getnum(st,7) );
15269 if( (skilllv = script_getnum(st,8)) > battle_config.mob_max_skilllvl )
15270 skilllv = battle_config.mob_max_skilllvl;
15271
15272 casttime = script_getnum(st,9);
15273 cancel = script_getnum(st,10);
15274 emotion = script_getnum(st,11);
15275 target = script_getnum(st,12);
15276
15277 map_foreachinrange(buildin_mobuseskill_sub, ¢er, range, BL_MOB, mobid, skillid, skilllv, casttime, cancel, emotion, target);
15278 return 0;
15279}
15280
15281
15282BUILDIN_FUNC(progressbar)
15283{
15284#if PACKETVER >= 20080318
15285 struct map_session_data * sd = script_rid2sd(st);
15286 const char * color;
15287 unsigned int second;
15288
15289 if( !st || !sd )
15290 return 0;
15291
15292 st->state = STOP;
15293
15294 color = script_getstr(st,2);
15295 second = script_getnum(st,3);
15296
15297 sd->progressbar.npc_id = st->oid;
15298 sd->progressbar.timeout = gettick() + second*1000;
15299
15300 clif_progressbar(sd, strtol(color, (char **)NULL, 0), second);
15301#endif
15302 return 0;
15303}
15304
15305BUILDIN_FUNC(pushpc)
15306{
15307 int direction, cells, dx, dy;
15308 struct map_session_data* sd;
15309
15310 if((sd = script_rid2sd(st))==NULL)
15311 {
15312 return 0;
15313 }
15314
15315 direction = script_getnum(st,2);
15316 cells = script_getnum(st,3);
15317
15318 if(direction<0 || direction>7)
15319 {
15320 ShowWarning("buildin_pushpc: Invalid direction %d specified.\n", direction);
15321 script_reportsrc(st);
15322
15323 direction%= 8; // trim spin-over
15324 }
15325
15326 if(!cells)
15327 {// zero distance
15328 return 0;
15329 }
15330 else if(cells<0)
15331 {// pushing backwards
15332 direction = (direction+4)%8; // turn around
15333 cells = -cells;
15334 }
15335
15336 dx = dirx[direction];
15337 dy = diry[direction];
15338
15339 unit_blown(&sd->bl, dx, dy, cells, 0);
15340 return 0;
15341}
15342
15343
15344/// Invokes buying store preparation window
15345/// buyingstore <slots>;
15346BUILDIN_FUNC(buyingstore)
15347{
15348 struct map_session_data* sd;
15349
15350 if( ( sd = script_rid2sd(st) ) == NULL )
15351 {
15352 return 0;
15353 }
15354
15355 buyingstore_setup(sd, script_getnum(st,2));
15356 return 0;
15357}
15358
15359
15360/// Invokes search store info window
15361/// searchstores <uses>,<effect>;
15362BUILDIN_FUNC(searchstores)
15363{
15364 unsigned short effect;
15365 unsigned int uses;
15366 struct map_session_data* sd;
15367
15368 if( ( sd = script_rid2sd(st) ) == NULL )
15369 {
15370 return 0;
15371 }
15372
15373 uses = script_getnum(st,2);
15374 effect = script_getnum(st,3);
15375
15376 if( !uses )
15377 {
15378 ShowError("buildin_searchstores: Amount of uses cannot be zero.\n");
15379 return 1;
15380 }
15381
15382 if( effect > 1 )
15383 {
15384 ShowError("buildin_searchstores: Invalid effect id %hu, specified.\n", effect);
15385 return 1;
15386 }
15387
15388 searchstore_open(sd, uses, effect);
15389 return 0;
15390}
15391
15392
15393/// Displays a number as large digital clock.
15394/// showdigit <value>[,<type>];
15395BUILDIN_FUNC(showdigit)
15396{
15397 unsigned int type = 0;
15398 int value;
15399 struct map_session_data* sd;
15400
15401 if( ( sd = script_rid2sd(st) ) == NULL )
15402 {
15403 return 0;
15404 }
15405
15406 value = script_getnum(st,2);
15407
15408 if( script_hasdata(st,3) )
15409 {
15410 type = script_getnum(st,3);
15411
15412 if( type > 3 )
15413 {
15414 ShowError("buildin_showdigit: Invalid type %u.\n", type);
15415 return 1;
15416 }
15417 }
15418
15419 clif_showdigit(sd, (unsigned char)type, value);
15420 return 0;
15421}
15422
15423BUILDIN_FUNC(get_unique_id)
15424{
15425 struct map_session_data* sd = script_rid2sd(st);
15426
15427 if (sd == NULL)
15428 {
15429 script_pushint(st,0);
15430 return 0;
15431 }
15432
15433 script_pushint(st, session[sd->fd]->gepard_info.unique_id);
15434
15435 return 0;
15436}
15437
15438// declarations that were supposed to be exported from npc_chat.c
15439#ifdef PCRE_SUPPORT
15440BUILDIN_FUNC(defpattern);
15441BUILDIN_FUNC(activatepset);
15442BUILDIN_FUNC(deactivatepset);
15443BUILDIN_FUNC(deletepset);
15444#endif
15445
15446/// script command definitions
15447/// for an explanation on args, see add_buildin_func
15448struct script_function buildin_func[] = {
15449 // NPC interaction
15450 BUILDIN_DEF(get_unique_id,""),
15451 BUILDIN_DEF(mes,"s"),
15452 BUILDIN_DEF(next,""),
15453 BUILDIN_DEF(close,""),
15454 BUILDIN_DEF(close2,""),
15455 BUILDIN_DEF(menu,"sl*"),
15456 BUILDIN_DEF(select,"s*"), //for future jA script compatibility
15457 BUILDIN_DEF(prompt,"s*"),
15458 //
15459 BUILDIN_DEF(goto,"l"),
15460 BUILDIN_DEF(callsub,"l*"),
15461 BUILDIN_DEF(callfunc,"s*"),
15462 BUILDIN_DEF(return,"?"),
15463 BUILDIN_DEF(getarg,"i?"),
15464 BUILDIN_DEF(jobchange,"i?"),
15465 BUILDIN_DEF(jobname,"i"),
15466 BUILDIN_DEF(input,"r??"),
15467 BUILDIN_DEF(warp,"sii"),
15468 BUILDIN_DEF(areawarp,"siiiisii"),
15469 BUILDIN_DEF(warpchar,"siii"), // [LuzZza]
15470 BUILDIN_DEF(warpparty,"siii?"), // [Fredzilla] [Paradox924X]
15471 BUILDIN_DEF(warpguild,"siii"), // [Fredzilla]
15472 BUILDIN_DEF(setlook,"ii"),
15473 BUILDIN_DEF(changelook,"ii"), // Simulates but don't Store it
15474 BUILDIN_DEF(set,"rv"),
15475 BUILDIN_DEF(setarray,"rv*"),
15476 BUILDIN_DEF(cleararray,"rvi"),
15477 BUILDIN_DEF(copyarray,"rri"),
15478 BUILDIN_DEF(getarraysize,"r"),
15479 BUILDIN_DEF(deletearray,"r?"),
15480 BUILDIN_DEF(getelementofarray,"ri"),
15481 BUILDIN_DEF(getitem,"vi?"),
15482 BUILDIN_DEF(rentitem,"vi"),
15483 BUILDIN_DEF(getitem2,"viiiiiiii?"),
15484 BUILDIN_DEF(getnameditem,"vv"),
15485 BUILDIN_DEF2(grouprandomitem,"groupranditem","i"),
15486 BUILDIN_DEF(makeitem,"visii"),
15487 BUILDIN_DEF(delitem,"vi?"),
15488 BUILDIN_DEF(delitem2,"viiiiiiii?"),
15489 BUILDIN_DEF2(enableitemuse,"enable_items",""),
15490 BUILDIN_DEF2(disableitemuse,"disable_items",""),
15491 BUILDIN_DEF(cutin,"si"),
15492 BUILDIN_DEF(viewpoint,"iiiii"),
15493 BUILDIN_DEF(heal,"ii"),
15494 BUILDIN_DEF(itemheal,"ii"),
15495 BUILDIN_DEF(percentheal,"ii"),
15496 BUILDIN_DEF(rand,"i?"),
15497 BUILDIN_DEF(countitem,"v"),
15498 BUILDIN_DEF(countitem2,"viiiiiii"),
15499 BUILDIN_DEF(checkweight,"vi"),
15500 BUILDIN_DEF(readparam,"i?"),
15501 BUILDIN_DEF(getcharid,"i?"),
15502 BUILDIN_DEF(getnpcid,"i?"),
15503 BUILDIN_DEF(getpartyname,"i"),
15504 BUILDIN_DEF(getpartymember,"i?"),
15505 BUILDIN_DEF(getpartyleader,"i?"),
15506 BUILDIN_DEF(getguildname,"i"),
15507 BUILDIN_DEF(getguildmaster,"i"),
15508 BUILDIN_DEF(getguildmasterid,"i"),
15509 BUILDIN_DEF(strcharinfo,"i"),
15510 BUILDIN_DEF(strnpcinfo,"i"),
15511 BUILDIN_DEF(getequipid,"i"),
15512 BUILDIN_DEF(getequipname,"i"),
15513 BUILDIN_DEF(getbrokenid,"i"), // [Valaris]
15514 BUILDIN_DEF(repair,"i"), // [Valaris]
15515 BUILDIN_DEF(getequipisequiped,"i"),
15516 BUILDIN_DEF(getequipisenableref,"i"),
15517 BUILDIN_DEF(getequipisidentify,"i"),
15518 BUILDIN_DEF(getequiprefinerycnt,"i"),
15519 BUILDIN_DEF(getequipweaponlv,"i"),
15520 BUILDIN_DEF(getequippercentrefinery,"i"),
15521 BUILDIN_DEF(successrefitem,"i"),
15522 BUILDIN_DEF(failedrefitem,"i"),
15523 BUILDIN_DEF(statusup,"i"),
15524 BUILDIN_DEF(statusup2,"ii"),
15525 BUILDIN_DEF(bonus,"iv"),
15526 BUILDIN_DEF2(bonus,"bonus2","ivi"),
15527 BUILDIN_DEF2(bonus,"bonus3","ivii"),
15528 BUILDIN_DEF2(bonus,"bonus4","ivvii"),
15529 BUILDIN_DEF2(bonus,"bonus5","ivviii"),
15530 BUILDIN_DEF(autobonus,"sii??"),
15531 BUILDIN_DEF(autobonus2,"sii??"),
15532 BUILDIN_DEF(autobonus3,"siiv?"),
15533 BUILDIN_DEF(skill,"vi?"),
15534 BUILDIN_DEF(addtoskill,"vi?"), // [Valaris]
15535 BUILDIN_DEF(guildskill,"vi"),
15536 BUILDIN_DEF(getskilllv,"v"),
15537 BUILDIN_DEF(getgdskilllv,"iv"),
15538 BUILDIN_DEF(basicskillcheck,""),
15539 BUILDIN_DEF(getgmlevel,""),
15540 BUILDIN_DEF(end,""),
15541 BUILDIN_DEF(checkoption,"i"),
15542 BUILDIN_DEF(setoption,"i?"),
15543 BUILDIN_DEF(setcart,"?"),
15544 BUILDIN_DEF(checkcart,""),
15545 BUILDIN_DEF(setfalcon,"?"),
15546 BUILDIN_DEF(checkfalcon,""),
15547 BUILDIN_DEF(setriding,"?"),
15548 BUILDIN_DEF(checkriding,""),
15549 BUILDIN_DEF2(savepoint,"save","sii"),
15550 BUILDIN_DEF(savepoint,"sii"),
15551 BUILDIN_DEF(gettimetick,"i"),
15552 BUILDIN_DEF(gettime,"i"),
15553 BUILDIN_DEF(gettimestr,"si"),
15554 BUILDIN_DEF(openstorage,""),
15555 BUILDIN_DEF(guildopenstorage,""),
15556 BUILDIN_DEF(itemskill,"vi"),
15557 BUILDIN_DEF(produce,"i"),
15558 BUILDIN_DEF(cooking,"i"),
15559 BUILDIN_DEF(monster,"siisii?"),
15560 BUILDIN_DEF(getmobdrops,"i"),
15561 BUILDIN_DEF(areamonster,"siiiisii?"),
15562 BUILDIN_DEF(killmonster,"ss?"),
15563 BUILDIN_DEF(killmonsterall,"s?"),
15564 BUILDIN_DEF(clone,"siisi????"),
15565 BUILDIN_DEF(doevent,"s"),
15566 BUILDIN_DEF(donpcevent,"s"),
15567 BUILDIN_DEF(cmdothernpc,"ss"),
15568 BUILDIN_DEF(addtimer,"is"),
15569 BUILDIN_DEF(deltimer,"s"),
15570 BUILDIN_DEF(addtimercount,"si"),
15571 BUILDIN_DEF(initnpctimer,"??"),
15572 BUILDIN_DEF(stopnpctimer,"??"),
15573 BUILDIN_DEF(startnpctimer,"??"),
15574 BUILDIN_DEF(setnpctimer,"i?"),
15575 BUILDIN_DEF(getnpctimer,"i?"),
15576 BUILDIN_DEF(attachnpctimer,"?"), // attached the player id to the npc timer [Celest]
15577 BUILDIN_DEF(detachnpctimer,"?"), // detached the player id from the npc timer [Celest]
15578 BUILDIN_DEF(playerattached,""), // returns id of the current attached player. [Skotlex]
15579 BUILDIN_DEF(announce,"si?????"),
15580 BUILDIN_DEF(mapannounce,"ssi?????"),
15581 BUILDIN_DEF(areaannounce,"siiiisi?????"),
15582 BUILDIN_DEF(getusers,"i"),
15583 BUILDIN_DEF(getmapguildusers,"si"),
15584 BUILDIN_DEF(getmapusers,"s"),
15585 BUILDIN_DEF(getareausers,"siiii"),
15586 BUILDIN_DEF(getareadropitem,"siiiiv"),
15587 BUILDIN_DEF(enablenpc,"s"),
15588 BUILDIN_DEF(disablenpc,"s"),
15589 BUILDIN_DEF(hideoffnpc,"s"),
15590 BUILDIN_DEF(hideonnpc,"s"),
15591 BUILDIN_DEF(sc_start,"iii?"),
15592 BUILDIN_DEF(sc_start2,"iiii?"),
15593 BUILDIN_DEF(sc_start4,"iiiiii?"),
15594 BUILDIN_DEF(sc_end,"i?"),
15595 BUILDIN_DEF(getscrate,"ii?"),
15596 BUILDIN_DEF(debugmes,"s"),
15597 BUILDIN_DEF2(catchpet,"pet","i"),
15598 BUILDIN_DEF2(birthpet,"bpet",""),
15599 BUILDIN_DEF(resetlvl,"i"),
15600 BUILDIN_DEF(resetstatus,""),
15601 BUILDIN_DEF(resetskill,""),
15602 BUILDIN_DEF(skillpointcount,""),
15603 BUILDIN_DEF(changebase,"i?"),
15604 BUILDIN_DEF(changesex,""),
15605 BUILDIN_DEF(waitingroom,"si?????"),
15606 BUILDIN_DEF(delwaitingroom,"?"),
15607 BUILDIN_DEF2(waitingroomkickall,"kickwaitingroomall","?"),
15608 BUILDIN_DEF(enablewaitingroomevent,"?"),
15609 BUILDIN_DEF(disablewaitingroomevent,"?"),
15610 BUILDIN_DEF2(enablewaitingroomevent,"enablearena",""), // Added by RoVeRT
15611 BUILDIN_DEF2(disablewaitingroomevent,"disablearena",""), // Added by RoVeRT
15612 BUILDIN_DEF(getwaitingroomstate,"i?"),
15613 BUILDIN_DEF(warpwaitingpc,"sii?"),
15614 BUILDIN_DEF(attachrid,"i"),
15615 BUILDIN_DEF(detachrid,""),
15616 BUILDIN_DEF(isloggedin,"i?"),
15617 BUILDIN_DEF(setmapflagnosave,"ssii"),
15618 BUILDIN_DEF(getmapflag,"si"),
15619 BUILDIN_DEF(setmapflag,"si?"),
15620 BUILDIN_DEF(removemapflag,"si"),
15621 BUILDIN_DEF(pvpon,"s"),
15622 BUILDIN_DEF(pvpoff,"s"),
15623 BUILDIN_DEF(gvgon,"s"),
15624 BUILDIN_DEF(gvgoff,"s"),
15625 BUILDIN_DEF(emotion,"i??"),
15626 BUILDIN_DEF(maprespawnguildid,"sii"),
15627 BUILDIN_DEF(agitstart,""), // <Agit>
15628 BUILDIN_DEF(agitend,""),
15629 BUILDIN_DEF(agitcheck,""), // <Agitcheck>
15630 BUILDIN_DEF(flagemblem,"i"), // Flag Emblem
15631 BUILDIN_DEF(getcastlename,"s"),
15632 BUILDIN_DEF(getcastledata,"si?"),
15633 BUILDIN_DEF(setcastledata,"sii"),
15634 BUILDIN_DEF(requestguildinfo,"i?"),
15635 BUILDIN_DEF(getequipcardcnt,"i"),
15636 BUILDIN_DEF(successremovecards,"i"),
15637 BUILDIN_DEF(failedremovecards,"ii"),
15638 BUILDIN_DEF(marriage,"s"),
15639 BUILDIN_DEF2(wedding_effect,"wedding",""),
15640 BUILDIN_DEF(divorce,""),
15641 BUILDIN_DEF(ispartneron,""),
15642 BUILDIN_DEF(getpartnerid,""),
15643 BUILDIN_DEF(getchildid,""),
15644 BUILDIN_DEF(getmotherid,""),
15645 BUILDIN_DEF(getfatherid,""),
15646 BUILDIN_DEF(warppartner,"sii"),
15647 BUILDIN_DEF(getitemname,"v"),
15648 BUILDIN_DEF(getitemslots,"i"),
15649 BUILDIN_DEF(makepet,"i"),
15650 BUILDIN_DEF(getexp,"ii"),
15651 BUILDIN_DEF(getinventorylist,""),
15652 BUILDIN_DEF(getskilllist,""),
15653 BUILDIN_DEF(clearitem,""),
15654 BUILDIN_DEF(classchange,"ii"),
15655 BUILDIN_DEF(misceffect,"i"),
15656 BUILDIN_DEF(playBGM,"s"),
15657 BUILDIN_DEF(playBGMall,"s?????"),
15658 BUILDIN_DEF(soundeffect,"si"),
15659 BUILDIN_DEF(soundeffectall,"si?????"), // SoundEffectAll [Codemaster]
15660 BUILDIN_DEF(strmobinfo,"ii"), // display mob data [Valaris]
15661 BUILDIN_DEF(guardian,"siisi??"), // summon guardians
15662 BUILDIN_DEF(guardianinfo,"sii"), // display guardian data [Valaris]
15663 BUILDIN_DEF(petskillbonus,"iiii"), // [Valaris]
15664 BUILDIN_DEF(petrecovery,"ii"), // [Valaris]
15665 BUILDIN_DEF(petloot,"i"), // [Valaris]
15666 BUILDIN_DEF(petheal,"iiii"), // [Valaris]
15667 BUILDIN_DEF(petskillattack,"viii"), // [Skotlex]
15668 BUILDIN_DEF(petskillattack2,"viiii"), // [Valaris]
15669 BUILDIN_DEF(petskillsupport,"viiii"), // [Skotlex]
15670 BUILDIN_DEF(skilleffect,"vi"), // skill effect [Celest]
15671 BUILDIN_DEF(npcskilleffect,"viii"), // npc skill effect [Valaris]
15672 BUILDIN_DEF(specialeffect,"i??"), // npc skill effect [Valaris]
15673 BUILDIN_DEF(specialeffect2,"i??"), // skill effect on players[Valaris]
15674 BUILDIN_DEF(nude,""), // nude command [Valaris]
15675 BUILDIN_DEF(mapwarp,"ssii??"), // Added by RoVeRT
15676 BUILDIN_DEF(atcommand,"s"), // [MouseJstr]
15677 BUILDIN_DEF(charcommand,"s"), // [MouseJstr]
15678 BUILDIN_DEF(movenpc,"sii?"), // [MouseJstr]
15679 BUILDIN_DEF(message,"ss"), // [MouseJstr]
15680 BUILDIN_DEF(npctalk,"s"), // [Valaris]
15681 BUILDIN_DEF(mobcount,"ss"),
15682 BUILDIN_DEF(getlook,"i"),
15683 BUILDIN_DEF(getsavepoint,"i"),
15684 BUILDIN_DEF(npcspeed,"i"), // [Valaris]
15685 BUILDIN_DEF(npcwalkto,"ii"), // [Valaris]
15686 BUILDIN_DEF(npcstop,""), // [Valaris]
15687 BUILDIN_DEF(getmapxy,"rrri?"), //by Lorky [Lupus]
15688 BUILDIN_DEF(checkoption1,"i"),
15689 BUILDIN_DEF(checkoption2,"i"),
15690 BUILDIN_DEF(guildgetexp,"i"),
15691 BUILDIN_DEF(guildchangegm,"is"),
15692 BUILDIN_DEF(logmes,"s"), //this command actls as MES but rints info into LOG file either SQL/TXT [Lupus]
15693 BUILDIN_DEF(summon,"si??"), // summons a slave monster [Celest]
15694 BUILDIN_DEF(isnight,""), // check whether it is night time [Celest]
15695 BUILDIN_DEF(isday,""), // check whether it is day time [Celest]
15696 BUILDIN_DEF(isequipped,"i*"), // check whether another item/card has been equipped [Celest]
15697 BUILDIN_DEF(isequippedcnt,"i*"), // check how many items/cards are being equipped [Celest]
15698 BUILDIN_DEF(cardscnt,"i*"), // check how many items/cards are being equipped in the same arm [Lupus]
15699 BUILDIN_DEF(getrefine,""), // returns the refined number of the current item, or an item with index specified [celest]
15700 BUILDIN_DEF(night,""), // sets the server to night time
15701 BUILDIN_DEF(day,""), // sets the server to day time
15702#ifdef PCRE_SUPPORT
15703 BUILDIN_DEF(defpattern,"iss"), // Define pattern to listen for [MouseJstr]
15704 BUILDIN_DEF(activatepset,"i"), // Activate a pattern set [MouseJstr]
15705 BUILDIN_DEF(deactivatepset,"i"), // Deactive a pattern set [MouseJstr]
15706 BUILDIN_DEF(deletepset,"i"), // Delete a pattern set [MouseJstr]
15707#endif
15708 BUILDIN_DEF(dispbottom,"s"), //added from jA [Lupus]
15709 BUILDIN_DEF(getusersname,""),
15710 BUILDIN_DEF(recovery,""),
15711 BUILDIN_DEF(getpetinfo,"i"),
15712 BUILDIN_DEF(gethominfo,"i"),
15713 BUILDIN_DEF(getmercinfo,"i?"),
15714 BUILDIN_DEF(checkequipedcard,"i"),
15715 BUILDIN_DEF(jump_zero,"il"), //for future jA script compatibility
15716 BUILDIN_DEF(globalmes,"s?"),
15717 BUILDIN_DEF(getmapmobs,"s"), //end jA addition
15718 BUILDIN_DEF(unequip,"i"), // unequip command [Spectre]
15719 BUILDIN_DEF(getstrlen,"s"), //strlen [Valaris]
15720 BUILDIN_DEF(charisalpha,"si"), //isalpha [Valaris]
15721 BUILDIN_DEF(charat,"si"),
15722 BUILDIN_DEF(setchar,"ssi"),
15723 BUILDIN_DEF(insertchar,"ssi"),
15724 BUILDIN_DEF(delchar,"si"),
15725 BUILDIN_DEF(strtoupper,"s"),
15726 BUILDIN_DEF(strtolower,"s"),
15727 BUILDIN_DEF(charisupper, "si"),
15728 BUILDIN_DEF(charislower, "si"),
15729 BUILDIN_DEF(substr,"sii"),
15730 BUILDIN_DEF(explode, "rss"),
15731 BUILDIN_DEF(implode, "r?"),
15732 BUILDIN_DEF(setnpcdisplay,"sv??"),
15733 BUILDIN_DEF(compare,"ss"), // Lordalfa - To bring strstr to scripting Engine.
15734 BUILDIN_DEF(getiteminfo,"ii"), //[Lupus] returns Items Buy / sell Price, etc info
15735 BUILDIN_DEF(setiteminfo,"iii"), //[Lupus] set Items Buy / sell Price, etc info
15736 BUILDIN_DEF(getequipcardid,"ii"), //[Lupus] returns CARD ID or other info from CARD slot N of equipped item
15737 // [zBuffer] List of mathematics commands --->
15738 BUILDIN_DEF(sqrt,"i"),
15739 BUILDIN_DEF(pow,"ii"),
15740 BUILDIN_DEF(distance,"iiii"),
15741 // <--- [zBuffer] List of mathematics commands
15742 BUILDIN_DEF(md5,"s"),
15743 // [zBuffer] List of dynamic var commands --->
15744 BUILDIN_DEF(getd,"s"),
15745 BUILDIN_DEF(setd,"sv"),
15746 // <--- [zBuffer] List of dynamic var commands
15747 BUILDIN_DEF(petstat,"i"),
15748 BUILDIN_DEF(callshop,"s?"), // [Skotlex]
15749 BUILDIN_DEF(npcshopitem,"sii*"), // [Lance]
15750 BUILDIN_DEF(npcshopadditem,"sii*"),
15751 BUILDIN_DEF(npcshopdelitem,"si*"),
15752 BUILDIN_DEF(npcshopattach,"s?"),
15753 BUILDIN_DEF(equip,"i"),
15754 BUILDIN_DEF(autoequip,"ii"),
15755 BUILDIN_DEF(setbattleflag,"si"),
15756 BUILDIN_DEF(getbattleflag,"s"),
15757 BUILDIN_DEF(setitemscript,"is?"), //Set NEW item bonus script. Lupus
15758 BUILDIN_DEF(disguise,"i"), //disguise player. Lupus
15759 BUILDIN_DEF(undisguise,""), //undisguise player. Lupus
15760 BUILDIN_DEF(getmonsterinfo,"ii"), //Lupus
15761 BUILDIN_DEF(axtoi,"s"),
15762 BUILDIN_DEF(query_sql,"s*"),
15763 BUILDIN_DEF(query_logsql,"s*"),
15764 BUILDIN_DEF(escape_sql,"v"),
15765 BUILDIN_DEF(atoi,"s"),
15766 // [zBuffer] List of player cont commands --->
15767 BUILDIN_DEF(rid2name,"i"),
15768 BUILDIN_DEF(pcfollow,"ii"),
15769 BUILDIN_DEF(pcstopfollow,"i"),
15770 BUILDIN_DEF(pcblockmove,"ii"),
15771 // <--- [zBuffer] List of player cont commands
15772 // [zBuffer] List of mob control commands --->
15773 BUILDIN_DEF(unitwalk,"ii?"),
15774 BUILDIN_DEF(unitkill,"i"),
15775 BUILDIN_DEF(unitwarp,"isii"),
15776 BUILDIN_DEF(unitattack,"iv?"),
15777 BUILDIN_DEF(unitstop,"i"),
15778 BUILDIN_DEF(unittalk,"is"),
15779 BUILDIN_DEF(unitemote,"ii"),
15780 BUILDIN_DEF(unitskilluseid,"ivi?"), // originally by Qamera [Celest]
15781 BUILDIN_DEF(unitskillusepos,"iviii"), // [Celest]
15782// <--- [zBuffer] List of mob control commands
15783 BUILDIN_DEF(sleep,"i"),
15784 BUILDIN_DEF(sleep2,"i"),
15785 BUILDIN_DEF(awake,"s"),
15786 BUILDIN_DEF(getvariableofnpc,"rs"),
15787 BUILDIN_DEF(warpportal,"iisii"),
15788 BUILDIN_DEF2(homunculus_evolution,"homevolution",""), //[orn]
15789 BUILDIN_DEF2(homunculus_shuffle,"homshuffle",""), //[Zephyrus]
15790 BUILDIN_DEF(eaclass,"?"), //[Skotlex]
15791 BUILDIN_DEF(roclass,"i?"), //[Skotlex]
15792 BUILDIN_DEF(checkvending,"?"),
15793 BUILDIN_DEF(checkchatting,"?"),
15794 BUILDIN_DEF(openmail,""),
15795 BUILDIN_DEF(openauction,""),
15796 BUILDIN_DEF(checkcell,"siii"),
15797 BUILDIN_DEF(setcell,"siiiiii"),
15798 BUILDIN_DEF(setwall,"siiiiis"),
15799 BUILDIN_DEF(delwall,"s"),
15800 BUILDIN_DEF(searchitem,"rs"),
15801 BUILDIN_DEF(mercenary_create,"ii"),
15802 BUILDIN_DEF(mercenary_heal,"ii"),
15803 BUILDIN_DEF(mercenary_sc_start,"iii"),
15804 BUILDIN_DEF(mercenary_get_calls,"i"),
15805 BUILDIN_DEF(mercenary_get_faith,"i"),
15806 BUILDIN_DEF(mercenary_set_calls,"ii"),
15807 BUILDIN_DEF(mercenary_set_faith,"ii"),
15808 BUILDIN_DEF(readbook,"ii"),
15809 BUILDIN_DEF(setfont,"i"),
15810 BUILDIN_DEF(areamobuseskill,"siiiiviiiii"),
15811 BUILDIN_DEF(progressbar,"si"),
15812 BUILDIN_DEF(pushpc,"ii"),
15813 BUILDIN_DEF(buyingstore,"i"),
15814 BUILDIN_DEF(searchstores,"ii"),
15815 BUILDIN_DEF(showdigit,"i?"),
15816 // WoE SE
15817 BUILDIN_DEF(agitstart2,""),
15818 BUILDIN_DEF(agitend2,""),
15819 BUILDIN_DEF(agitcheck2,""),
15820 // BattleGround
15821 BUILDIN_DEF(waitingroom2bg,"siiss?"),
15822 BUILDIN_DEF(waitingroom2bg_single,"isiis"),
15823 BUILDIN_DEF(bg_team_setxy,"iii"),
15824 BUILDIN_DEF(bg_warp,"isii"),
15825 BUILDIN_DEF(bg_monster,"isiisi?"),
15826 BUILDIN_DEF(bg_monster_set_team,"ii"),
15827 BUILDIN_DEF(bg_leave,""),
15828 BUILDIN_DEF(bg_destroy,"i"),
15829 BUILDIN_DEF(areapercentheal,"siiiiii"),
15830 BUILDIN_DEF(bg_get_data,"ii"),
15831 BUILDIN_DEF(bg_getareausers,"isiiii"),
15832 BUILDIN_DEF(bg_updatescore,"sii"),
15833
15834 // Instancing
15835 BUILDIN_DEF(instance_create,"si"),
15836 BUILDIN_DEF(instance_destroy,"?"),
15837 BUILDIN_DEF(instance_attachmap,"si?"),
15838 BUILDIN_DEF(instance_detachmap,"s?"),
15839 BUILDIN_DEF(instance_attach,"i"),
15840 BUILDIN_DEF(instance_id,"?"),
15841 BUILDIN_DEF(instance_set_timeout,"ii?"),
15842 BUILDIN_DEF(instance_init,"i"),
15843 BUILDIN_DEF(instance_announce,"isi?????"),
15844 BUILDIN_DEF(instance_npcname,"s?"),
15845 BUILDIN_DEF(has_instance,"s?"),
15846 BUILDIN_DEF(instance_warpall,"sii?"),
15847
15848 //Quest Log System [Inkfish]
15849 BUILDIN_DEF(setquest, "i"),
15850 BUILDIN_DEF(erasequest, "i"),
15851 BUILDIN_DEF(completequest, "i"),
15852 BUILDIN_DEF(checkquest, "i?"),
15853 BUILDIN_DEF(changequest, "ii"),
15854 BUILDIN_DEF(showevent, "ii"),
15855 {NULL,NULL,NULL},
15856};