forked from rathena/rathena
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathscript_commands.txt
10517 lines (7677 loc) · 378 KB
/
script_commands.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//===== rAthena Documentation================================
//= rAthena Script Commands
//===== By:==================================================
//= rAthena Dev Team
//===== Last Updated:========================================
//= 20180831
//===== Description:=========================================
//= A reference manual for the rAthena scripting language.
//= Commands are sorted depending on their functionality.
//===========================================================
This document is a reference manual for all the scripting commands and functions
available in rAthena. It is not a simple tutorial. When people tell you to
"Read The F***ing Manual", they mean this.
This is not a place to teach you basic programming. This document will not teach
you basic programming by itself. It's more of a reference for those who have at
least a vague idea of what they want to do and want to know what tools they have
available to do it. We've tried to keep it as simple as possible, but if you
don't understand it, getting a clear book on programming in general will help
better than yelling around the forum for help.
A little learning never caused anyone's head to explode.
Structure
---------
The script commands are listed in no particular order, but are grouped by
relative function.
*Name of the command and parameters (if any).
Descriptive text
Small example if possible. Will usually be incomplete, it's there just to
give you an idea of how it works in practice.
To find a specific command, use Ctrl+F, (or whatever keys call up a search
function in whatever you're reading this with) put an asterisk (*) followed by the command
name, and it should find the command description for you.
If you find anything missing, please let us know!
Syntax
------
Throughout this document, wherever a command wants an argument, it is given in
<angle brackets>. This doesn't mean you should type the angle brackets. If an
argument of a command is optional, it is given in {curly brackets}. You've
doubtlessly seen this convention somewhere. If a command can optionally take
an unspecified number of arguments, you'll see a list like this:
command <argument>{,<argument>...<argument>}
This still means they will want to be separated by commas.
Where a command wants a string, it will be given in "quotes", if it's a number,
it will be given without them. Normally, you can put an expression, like a bunch
of functions or operators returning a value, in (round brackets) instead of most
numbers. Round brackets will not always be required, but they're often a good
idea.
Wherever you refer to a map name, it's always 'map name' (.gat suffix is deprecated).
Script loading structure
------------------------
Scripts are loaded by the map server as referenced in the 'conf/map_athena.conf'
configuration file, but in the default configuration, it doesn't load any script
files itself. Instead, it loads the file 'npc/(pre-)re/scripts_main.conf' which itself
contains references to other files. The actual scripts are loaded from txt
files, which are linked up like this:
npc: <path to a filename>
Any line like this, invoked, ultimately, by 'map_athena.conf' will load up the
script contained in this file, which will make the script available. No file
will get loaded twice to prevent possible errors.
Another configuration file option of relevance is:
delnpc: <path to a filename>
This will unload a specified script filename from memory, which, while
seemingly useless, may sometimes be required.
Whenever '//' is encountered in a line upon reading, everything beyond this on
that line is considered to be a comment and is ignored. This works wherever you
place it.
// This line will be ignored when processing the script.
Block comments can also be used, where you can place /* and */ between any text you
wish rAthena to ignore.
Example:
/* This text,
* no matter which new line you start
* is ignored, until the following
* symbol is encountered: */
The asterisks (*) in front of each line is a personal preference and is not required.
Upon loading all the files, the server will execute all the top-level commands
in them. No variables exist yet at this point, no commands can be called other
than those given in this section. These commands set up the basic structure - create
NPC objects, spawn monster objects, set map flags, etc. No code is actually
executed at this point. The top-level commands are pretty confusing, since
they aren't structured like you would expect (command name first), but rather,
normally start with a map name.
What's more confusing about the top-level commands is that most of them use a
tab symbol to divide their arguments.
To prevent problems and confusion, the tab symbols are written as '%TAB%'
throughout this document, even though this makes the text a bit less readable.
Using an invisible symbol to denote arguments is one of the bad things about
this language.
Here is a list of valid top-level commands:
** Set a map flag:
<map name>%TAB%mapflag%TAB%<flag>
This will, upon loading, set a specified map flag on a map you like. These are
normally in files inside 'npc/mapflag' and are loaded first, so by the time the
server's up, all the maps have the flags they should have. Map flags determine
the behavior of the map in various situations. For more details, see 'setmapflag'
and 'doc/mapflags.txt'.
** Create a permanent monster spawn:
<map name>{,<x>{,<y>{,<xs>{,<ys>}}}}%TAB%monster%TAB%<monster name>{,<monster level>}%TAB%<mob id>,<amount>{,<delay1>{,<delay2>{,<event>{,<mob size>{,<mob ai>}}}}}
Map name is the name of the map the monsters will spawn on. x,y are the
coordinates where the mob should spawn. If xs and ys are non-zero, they
specify the 'radius' of a spawn-rectangle area centered at x,y.
Putting zeros instead of these coordinates will spawn the monsters randomly.
Note this is only the initial spawn zone, as mobs random-walk, they are free
to move away from their specified spawn region.
Monster name is the name the monsters will have on screen, and has no relation
whatsoever to their names anywhere else. It's the mob id that counts, which
identifies monster record in 'mob_db.txt' database of monsters. If the mob name
is given as "--ja--", the 'japanese name' field from the monster database is
used, (which, in rAthena, actually contains an English name) if it's "--en--",
it's the 'english name' from the monster database (which contains an uppercase
name used to summon the monster with a GM command).
You can specify a custom level to use for the mob different from the one of
the database by adjoining the level after the name with a comma. eg:
"Poring,50" for a name will spawn a monster with name Poring and level 50.
Amount is the amount of monsters that will be spawned when this command is
executed, it is affected by spawn rates in 'battle_athena.conf'.
Delay1 and delay2 control monster respawn delays - the first one is the fixed
base respawn time, and the second is random variance on top of the base time.
Both values are given in milliseconds (1000 = 1 second).
Note that the server also enforces a minimum respawn delay of 5 seconds.
Event is a script event to be executed when the mob is killed. The event must
be in the form "NPCName::OnEventName" to execute, and the event name label
should start with "On". As with all events, if the NPC is an on-touch NPC, the
player who triggers the script must be within 'trigger' range for the event to
work.
There are two optional fields for monster size and AI.
<mob size> can be:
Size_Small (0)
Size_Medium (1)
Size_Large (2)
<mob ai> can be:
AI_NONE (0) (default)
AI_ATTACK (1) (attack/friendly)
AI_SPHERE (2) (Alchemist skill)
AI_FLORA (3) (Alchemist skill)
AI_ZANZOU (4) (Kagerou/Oboro skill)
AI_LEGION (5) (Sera skill)
AI_FAW (6) (Mechanic skill)
Alternately, a monster spawned using 'boss_monster' instead of 'monster' is able
to be detected on the map with the SC_BOSSMAPINFO status (used by Convex Mirror).
** NPC names
/!\ WARNING: this applies to warps, NPCs, duplicates and shops /!\
NPC names are kinda special and are formatted this way:
<Display name>{::<Unique name>}
All NPCs need to have a unique name that is used for identification purposes.
When you have to identify a NPC by its name, you should use <Unique name>.
If <Unique name> is not provided, use <Display name> instead.
The client has a special feature when displaying names:
if the display name contains a '#' character, it hides that part of the name.
ex: if your NPC is named 'Hunter#hunter1', it will be displayed as 'Hunter'
<Display name> must be at most 24 characters in length.
<Unique name> must be at most 24 characters in length.
** Define a warp point
<from mapname>,<fromX>,<fromY>,<facing>%TAB%warp%TAB%<warp name>%TAB%<spanx>,<spany>,<to mapname>,<toX>,<toY>
<from mapname>,<fromX>,<fromY>,<facing>%TAB%warp2%TAB%<warp name>%TAB%<spanx>,<spany>,<to mapname>,<toX>,<toY>
This will define a warp NPC that will warp a player between maps, and while most
arguments of that are obvious, some deserve special mention.
SpanX and SpanY will make the warp sensitive to a character who didn't step
directly on it, but walked into a zone which is centered on the warp from
coordinates and is SpanX in each direction across the X axis and SpanY in each
direction across the Y axis.
Warp NPC objects also have a name, because you can use it to refer to them later
with 'enablenpc'/'disablenpc'
Facing of a warp object is irrelevant, it is not used in the code and all
current scripts have a zero in there.
Unlike 'warp', 'warp2' will also be triggered by hidden player.
** Define an NPC object.
<map name>,<x>,<y>,<facing>%TAB%script%TAB%<NPC Name>%TAB%<sprite id>,{<code>}
<map name>,<x>,<y>,<facing>%TAB%script%TAB%<NPC Name>%TAB%<sprite id>,<triggerX>,<triggerY>,{<code>}
This will place an NPC object on a specified map at the specified location, and
is a top-level command you will use the most in your custom scripting. The NPCs
are triggered by clicking on them, and/or by walking in their trigger area, if
defined, see that below.
Facing is a direction the NPC sprite will face in. Not all NPC sprites have
different images depending on the direction you look from, so for some facing
will be meaningless. Facings are counted counterclockwise in increments of 45
degrees, where 0 means facing towards the top of the map. (So to turn the sprite
towards the bottom of the map, you use facing 4, and to make it look southeast
it's facing 5.)
Sprite ID is the sprite number or constant used to display this particular NPC.
You may also use a monster's ID instead to display a monster sprite for this NPC.
It is possible to use a job sprite as well, but you must first define it as a
monster sprite in 'mob_avail.txt', a full description on how to do this is not
in the scope of this manual.
A '-1' Sprite ID will make the NPC invisible (and unclickable).
A '111' Sprite ID will make an NPC which does not have a sprite, but is still
clickable, which is useful if you want to make a clickable object of the 3D
terrain.
TriggerX and triggerY, if given, will define an area, centered on NPC and
spanning triggerX cells in every direction across X and triggerY in every
direction across Y. Walking into that area will trigger the NPC. If no
'OnTouch:' special label is present in the NPC code, the execution will start
from the beginning of the script, otherwise, it will start from the 'OnTouch:'
label. Monsters can also trigger the NPC, though the label 'OnTouchNPC:' is
used in this case.
The code part is the script code that will execute whenever the NPC is
triggered. It may contain commands and function calls, descriptions of which
compose most of this document. It has to be in curly brackets, unlike elsewhere
where we use curly brackets, these do NOT signify an optional parameter.
** Define a 'floating' NPC object.
-%TAB%script%TAB%<NPC Name>%TAB%-1,{<code>}
This will define an NPC object not triggerable by normal means. This would
normally mean it's pointless since it can't do anything, but there are
exceptions, mostly related to running scripts at specified time, which is what
these floating NPC objects are for. More on that below.
** Define a shop/cashshop/itemshop/pointshop NPC.
-%TAB%shop%TAB%<NPC Name>%TAB%<sprite id>{,discount},<itemid>:<price>{,<itemid>:<price>...}
<map name>,<x>,<y>,<facing>%TAB%shop%TAB%<NPC Name>%TAB%<sprite id>{,discount},<itemid>:<price>{,<itemid>:<price>...}
-%TAB%cashshop%TAB%<NPC Name>%TAB%<sprite id>,<itemid>:<price>{,<itemid>:<price>...}
<map name>,<x>,<y>,<facing>%TAB%cashshop%TAB%<NPC Name>%TAB%<sprite id>,<itemid>:<price>{,<itemid>:<price>...}
-%TAB%itemshop%TAB%<NPC Name>%TAB%<sprite id>,<costitemid>{:<discount>},<itemid>:<price>{,<itemid>:<price>...}
<map name>,<x>,<y>,<facing>%TAB%itemshop%TAB%<NPC Name>%TAB%<sprite id>,<costitemid>{:<discount>},<itemid>:<price>{,<itemid>:<price>...}
-%TAB%pointshop%TAB%<NPC Name>%TAB%<sprite id>,<costvariable>{:<discount>},<itemid>:<price>{,<itemid>:<price>...}
<map name>,<x>,<y>,<facing>%TAB%pointshop%TAB%<NPC Name>%TAB%<sprite id>,<costvariable>{:<discount>},<itemid>:<price>{,<itemid>:<price>...}
<map name>,<x>,<y>,<facing>%TAB%marketshop%TAB%<NPC Name>%TAB%<sprite id>,<itemid>:<price>:<quantity>{,<itemid>:<price>:<quantity>...}
This will define a shop NPC, which, when triggered (which can only be done by
clicking) will cause a shop window to come up. No code whatsoever runs in shop
NPCs and you can't change the prices otherwise than by editing the script
itself.
The Item ID is the number of item in the 'item_db.txt' database. If Price is set
to -1, the 'buy price' given in the item database will be used. Otherwise, the
price you gave will be used for this item, which is how you create differing
prices for items in different shops.
Optionally you can specify the discount option and set it to "yes" or "no", to enable or disable discounting.
There are other types of shops available:
cashshop - use "cashshop" in place of "shop" to use the Cash Shop interface, allowing
you to buy items with special points that are stored as account variables
called #CASHPOINTS and #KAFRAPOINTS. This type of shop will not allow you to sell
items at it, only make purchases. The layout used to define sale items still count, and
"<price>" refers to how many points will be spent purchasing the them.
"itemshop" and "pointshop" use the Shop interface, allowing you to buy items with a specific
item or special points from a variable. 'pointshop' only supports permanent character variables,
temporary character variables, permanent local account variables or permanent global account
variables. These variables must be of integer type, not string. 'discount' flag is an
optional value which makes the price at that shop become affected by discount skill.
** Define an warp/shop/cashshop/itemshop/pointshop/NPC duplicate.
warp/warp2: <map name>,<x>,<y>,<facing>%TAB%duplicate(<label>)%TAB%<NPC Name>%TAB%<spanx>,<spany>
shop/cashshop/itemshop/pointshop/npc: -%TAB%duplicate(<label>)%TAB%<NPC Name>%TAB%<sprite id>
shop/cashshop/itemshop/pointshop/npc: <map name>,<x>,<y>,<facing>%TAB%duplicate(<label>)%TAB%<NPC Name>%TAB%<sprite id>
npc: -%TAB%duplicate(<label>)%TAB%<NPC Name>%TAB%<sprite id>,<triggerX>,<triggerY>
npc: <map name>,<x>,<y>,<facing>%TAB%duplicate(<label>)%TAB%<NPC Name>%TAB%<sprite id>,<triggerX>,<triggerY>
This will duplicate an warp/shop/cashshop/itemshop/pointshop/NPC referred to by 'label'.
Warp duplicates inherit the target location.
Shop/cashshop/itemshop/pointshop duplicates inherit the item list.
NPC duplicates inherit the script code.
The rest (name, location, facing, sprite ID, span/trigger area)
is obtained from the definition of the duplicate (not inherited).
** Define a function object
function%TAB%script%TAB%<function name>%TAB%{<code>}
This will define a function object, callable with the 'callfunc' command (see
below). This object will load on every map server separately, so you can get at
it from anywhere. It's not possible to call the code in this object by
anything other than the 'callfunc' script command.
The code part is the script code that will execute whenever the function is
called with 'callfunc'. It has to be in curly brackets, unlike elsewhere where
we use curly brackets, these do NOT signify an optional parameter.
Once an object is defined which has a 'code' field to its definition, it
contains script commands which can actually be triggered and executed.
~ RID? GID? ~
What a RID is and why do you need to know
-----------------------------------------
Most scripting commands and functions will want to request data about a
character, store variables referenced to that character, send stuff to the
client connected to that specific character. Whenever a script is invoked by a
character, it is passed a so-called RID - this is the account ID number of a
character that caused the code to execute by clicking on it, walking into its
OnTouch zone, or otherwise.
If you are only writing common NPCs, you don't need to bother with it. However,
if you use functions, if you use timers, if you use clock-based script
activation, you need to be aware of all cases when a script execution can be
triggered without a RID attached. This will make a lot of commands and functions
unusable, since they want data from a specific character, want to send stuff to
a specific client, want to store variables specific to that character, and they
would not know what character to work on if there's no RID.
Unless you use 'attachrid' to explicitly attach a character to the script first.
Whenever we say 'invoking character', we mean 'the character who's RID is
attached to the running script. The script function "playerattached" can be
used to check which is the currently attached player to the script (it will
return 0 if the there is no player attached or the attached player no longer
is logged on to the map-server).
But what about GID?
-------------------
GID stands for the Game ID of something, this can either be the GID obtained
through mobspawn (mob control commands) or the account ID of a character.
Another way would be to right click on a mob, NPC or char as GM sprited char
to view the GID.
See also 'getpetinfo', 'getmercinfo', 'gethominfo', and 'geteleminfo'.
This is mostly used for the new version of skill and the mob control commands
implemented.
Item and pet scripts
--------------------
Each item in the item database has three special fields - Script , OnEquip_Script
and OnUnequip_Script. The first is script code run every time a character equips the item,
with the RID of the equipping character. Every time they unequip an item, all
temporary bonuses given by the script commands are cleared, and all the scripts
are executed once again to rebuild them. This also happens in several other
situations (like upon login) but the full list is currently unknown.
OnEquip_Script is a piece of script code run whenever the item is used by a character
by double-clicking on it. OnUnequip_Script runs whenever the
equipment is unequip by a character
Not all script commands work properly in the item scripts. Where commands and
functions are known to be meant specifically for use in item scripts, they are
described as such.
Every pet in the pet database has a PetScript field, which determines pet
behavior. It is invoked wherever a pet of the specified type is spawned.
(hatched from an egg, or loaded from the char server when a character who had
that pet following them connects) This may occur in some other situations as
well. Don't expect anything other than commands definitely marked as usable in
pet scripts to work in there reliably.
Numbers
-------
Beside the common decimal numbers, which are nothing special whatsoever (though
do not expect to use fractions, since ALL numbers are integer in this language),
the script engine also handles hexadecimal numbers, which are otherwise
identical. Writing a number like '0x<hex digits>' will make it recognized as a
hexadecimal value. Notice that 0x10 is equal to 16. Also notice that if you try
to 'mes 0x10' it will print '16'.
Number values can't exceed the limits of an integer variable: Any number
greater than INT_MAX (2147483647) or smaller than INT_MIN (-2147483648) will
be capped to those values and will cause a warning to be reported.
Variables
---------
The meat of every programming language is variables - places where you store
data.
In the rAthena scripting language, variable names are not case sensitive.
Variables are divided into and uniquely identified by the combination of:
prefix - determines the scope and extent (or lifetime) of the variable
name - an identifier consisting of '_' and alphanumeric characters
postfix - determines the type of the variable: integer or string
Scope can be:
global - global to all servers
local - local to the server
account - attached to the account of the character identified by RID
character - attached to the character identified by RID
npc - attached to the NPC
scope - attached to the scope of the instance
Extent can be:
permanent - They still exist when the server resets.
temporary - They cease to exist when the server resets.
Prefix: scope and extent
nothing - A permanent variable attached to the character, the default variable
type. They are stored by char-server in the `char_reg_num` and
`char_reg_str`.
"@" - A temporary variable attached to the character.
SVN versions before 2094 revision and RC5 version will also treat
'l' as a temporary variable prefix, so beware of having variable
names starting with 'l' if you want full backward compatibility.
"$" - A global permanent variable.
They are stored by map-server in database table `mapreg`.
"$@" - A global temporary variable.
This is important for scripts which are called with no RID
attached, that is, not triggered by a specific character object.
"." - A NPC variable.
They exist in the NPC and disappear when the server restarts or the
NPC is reloaded. Can be accessed from inside the NPC or by calling
'getvariableofnpc'. Function objects can also have .variables which
are accessible from inside the function, however 'getvariableofnpc'
does NOT work on function objects.
".@" - A scope variable.
They are unique to the instance and scope. Each instance has its
own scope that ends when the script ends. Calling a function with
callsub/callfunc starts a new scope, returning from the function
ends it. When a scope ends, its variables are converted to values
('return .@var;' returns a value, not a reference).
"'" - An instance variable.
These are used with the instancing system and are unique to each
instance type. Can be accessed from inside the instance or by calling
'getvariableofinstance'.
"#" - A permanent local account variable.
They are stored by char-server in the `acc_reg_num` table and
`acc_reg_str`.
"##" - A permanent global account variable stored by the login server.
They are stored in the `global_acc_reg_num` table and
`global_acc_reg_str`.
The only difference you will note from normal # variables is when
you have multiple char-servers connected to the same login server.
The # variables are unique to each char-server, while the ## variables
are shared by all these char-servers.
Postfix: integer or string
nothing - integer variable, can store positive and negative numbers, but only
whole numbers (so don't expect to do any fractional math)
'$' - string variable, can store text
Examples:
name - permanent character integer variable
name$ - permanent character string variable
@name - temporary character integer variable
@name$ - temporary character string variable
$name - permanent global integer variable
$name$ - permanent global string variable
$@name - temporary global integer variable
$@name$ - temporary global string variable
.name - NPC integer variable
.name$ - NPC string variable
.@name - scope integer variable
.@name$ - scope string variable
'name - instance integer variable
'name$ - instance string variable
#name - permanent local account integer variable
#name$ - permanent local account string variable
##name - permanent global account integer variable
##name$ - permanent global account string variable
If a variable was never set, it is considered to equal zero for integer
variables or an empty string ("", nothing between the quotes) for string
variables. Once you set it to that, the variable is as good as forgotten
forever, and no trace remains of it even if it was stored with character or
account data.
Some variables are special, that is, they are already defined for you by the
scripting engine. You can see the full list in 'src/map/script_constants.hpp', which
is a file you should read, since it also allows you to replace lots of numbered
arguments for many commands with easier to read text. The special variables most
commonly used are all permanent character-based variables:
Zeny - Amount of Zeny.
Hp - Current amount of hit points.
MaxHp - Maximum amount of hit points.
Sp - Current spell points.
MaxSp - Maximum amount of spell points.
StatusPoint - Amount of status points remaining.
SkillPoint - Amount of skill points remaining.
BaseLevel - Character's base level.
JobLevel - Character's job level.
BaseExp - Amount of base experience points.
JobExp - Amount of job experience points.
NextBaseExp - Amount of base experience points needed to reach the next level.
NextJobExp - Amount of job experience points needed to reach the next level.
Weight - Amount of weight the character currently carries.
MaxWeight - Maximum weight the character can carry.
Sex - 0 if female, 1 if male.
Class - Character's job.
Upper - 0 if the character is a normal class, 1 if advanced, 2 if baby.
BaseClass - The character's 1-1 'normal' job, regardless of Upper value.
For example, this will return Job_Acolyte for Acolyte, Priest/Monk,
High Priest/Champion, and Arch Bishop/Sura. If the character has not
reached a 1-1 class, it will return Job_Novice.
BaseJob - The character's 'normal' job, regardless of Upper value.
For example, this will return Job_Acolyte for Acolyte,
Baby Acolyte, and High Acolyte.
Karma - The character's karma. Karma system is not fully functional, but
this doesn't mean this doesn't work at all. Not tested.
Manner - The character's manner rating. Becomes negative if the player
utters words forbidden through the use of 'manner.txt' client-side
file.
While these behave as variables, do not always expect to just set them - it is
not certain whether this will work for all of them. Whenever there is a command
or a function to set something, it's usually preferable to use that instead. The
notable exception is Zeny, which you can and often will address directly -
setting it will make the character own this number of Zeny.
If you try to set Zeny to a negative number, the script will be terminated with an error.
Some source-end constants can also be accessed in scripts. This list is located in
'src/map/script_constants.hpp', which contains constants such as server defines and status options:
PACKETVER, MAX_LEVEL, MAX_STORAGE, MAX_INVENTORY, MAX_CART, MAX_ZENY, MAX_PARTY,
MAX_GUILD, MAX_GUILDLEVEL, MAX_GUILD_STORAGE, MAX_BG_MEMBERS, MAX_CHAT_USERS,
VIP_SCRIPT, MIN_STORAGE
Option_Nothing, Option_Sight, Option_Hide, Option_Cloak, Option_Falcon, Option_Riding,
Option_Invisible, Option_Orcish, Option_Wedding, Option_Chasewalk, Option_Flying,
Option_Xmas, Option_Transform, Option_Summer, Option_Dragon1, Option_Wug,
Option_Wugrider, Option_Madogear, Option_Dragon2, Option_Dragon3, Option_Dragon4,
Option_Dragon5, Option_Hanbok, Option_Oktoberfest, Option_Dragon, Option_Costume
Assigning variables
--------- ---------
Variables can be accessed and modified much like in other programming languages.
.@x = 100;
.@x = .@y = 100;
Support for modifying variable values using 'set' is still supported (and required
to exist for this new method to work) so previous scripts will continue to work.
When assigning values, all operator methods are supported which exist in the below
'Operators' section. For instance:
.@x += 100;
.@x -= 100;
.@x *= 2;
.@x /= 2;
.@x %= 5;
.@x >>= 2;
.@x <<= 2;
Will all work. For more information on available operators, see the Operators section
described below. All operators listed there may be placed in-front of the '=' sign
when modifying variables to perform the action as required.
Note:
!! Currently the scripting engine does not support directly copying array variables.
!! In order to copy arrays between variables the use of 'copyarray' function is still
!! required.
Strings
-------
To include symbol '"' in a string you should use prefix '\"'
Arrays
------
Arrays (in rAthena at least) are essentially a set of variables going under the
same name. You can tell between the specific variables of an array with an
'array index', a number of a variable in that array:
<variable name>[<array index>]
All variable types can be used as arrays.
Variables stored in this way, inside an array, are also called 'array elements'.
Arrays are specifically useful for storing a set of similar data (like several
item IDs for example) and then looping through it. You can address any array
variable as if it was a normal variable:
set .@arrayofnumbers[0],1;
You can also do things like using a variable (or an expression, or even a
value from another array) to get at an array value:
set .@x,100;
set .@arrayofnumbers[.@x],10;
This will make .@arrayofnumbers[100] equal to 10.
Index numbering always starts with 0 and arrays can hold over 2 billion
variables. As such, the (guaranteed) allowed values for indices are in the
range 0 ~ 2147483647.
And array indexes probably can't be negative. Nobody tested what happens when
you try to get a negatively numbered variable from an array, but it's not going
to be pretty.
Arrays can naturally store strings:
.@menulines$[0] is the 0th element of the .@menulines$ array of strings. Notice
the '$', normally denoting a string variable, before the square brackets that
denotes an array index.
Variable References
-------------------
//##TODO
Operators
---------
Operators are things you can do to variables and numbers. They are either the
common mathematical operations or conditional operators
+ - will add two numbers. If you try to add two strings, the result will be a
string glued together at the +. You can add a number to a string, and the
result will be a string. No other math operators work with strings.
- - will subtract two numbers.
* - will multiply two numbers.
/ - will divide two numbers. Note that this is an integer division, i.e.
7/2 is not equal 3.5, it's equal 3.
% - will give you the remainder of the division. 7%2 is equal to 1.
There are also conditional operators. This has to do with the conditional
command 'if' and they are meant to return either 1 if the condition is satisfied
and 0 if it isn't. (That's what they call 'boolean' variables. 0 means 'False'.
Anything except the zero is 'True' Odd as it is, -1 and -5 and anything below
zero will also be True.)
You can compare numbers to each other and you compare strings to each other, but
you can not compare numbers to strings.
== - Is true if both sides are equal. For strings, it means they are the same.
>= - True if the first value is equal to, or greater than, the second value.
<= - True if the first value is equal to, or less than, the second value
> - True if the first value greater than the second value
< - True if the first value is less than the second value
!= - True if the first value IS NOT equal to the second one
Examples:
1 == 1 is True.
1<2 is True while 1>2 is False.
.@x>2 is True if .@x is equal to 3. But it isn't true if .@x is 2.
Only ' == ' and '!=' have been tested for comparing strings. Since there's no way
to code a seriously complex data structure in this language, trying to sort
strings by alphabet would be pointless anyway.
Comparisons can be stacked in the same condition:
&& - Is True if and only if BOTH sides are true.
('1 == 1 && 2 == 2' is true. '2 == 1 && 1 == 1' is false.)
|| - Is True if either side of this expression is True.
1 == 1 && 2 == 2 is True.
1 == 1 && 2 == 1 is False.
1 == 1 || 2 == 1 is True.
Logical bitwise operators work only on numbers, and they are the following:
<< - Left shift.
>> - Right shift.
Left shift moves the binary 1(s) of a number n positions to the left,
which is the same as multiplying by 2, n times.
In the other hand, Right shift moves the binary 1(s) of a number n positions
to the right, which is the same as dividing by 2, n times.
Example:
set b,2;
set a, b << 3;
mes a;
set a, a >> 2;
mes a;
The first mes command would display 16, which is the same as 2 x (2 x 2 x 2) = 16.
The second mes command would display 4, which is the same as 16 / 2 = 8. 8 / 2 = 4.
& - And.
| - Or.
The bitwise operator AND (&) is used to test two values against each other,
and results in setting bits which are active in both arguments. This can
be used for a few things, but in rAthena this operator is usually used to
create bit-masks in scripts.
The bitwise operator OR (|)sets to 1 a binary position if the binary position
of one of the numbers is 1. This way a variable can hold several values we can check,
known as bit-mask. A variable currently can hold up to 32 bit-masks (from position 0
to position 1). This is a cheap(skate) and easy way to avoid using arrays to store several checks
that a player can have.
A bit-mask basically is (ab)using the variables bits to set various options in
one variable. With the current limit if variables it is possible to store 32
different options in one variable (by using the bits on position 0 to 31).
Example(s):
- Basic example of the & operator, bit example:
10 & 2 = 2
Why? :
10 = 2^1 + 2^3 (2 + 8), so in bits, it would be 1010
2 = 2^1 (2), so in bits (same size) it would be 0010
The & (AND) operator sets bits which are active (1) in both arguments, so in the
example 1010 & 0010, only the 2^1 bit is active (1) in both. Resulting in the bit
0010, which is 2.
- Basic example of creating and using a bit-mask:
set .@options,2|4|16; //(note: this is the same as 2+4+16, or 22)
if (.@options & 1) mes "Option 1 is activated";
if (.@options & 2) mes "Option 2 is activated";
if (.@options & 4) mes "Option 3 is activated";
if (.@options & 8) mes "Option 4 is activated";
if (.@options & 16) mes "Options 5 is activated";
This would return the messages about option 2, 3 and 5 being shown (since we've set
the 2,4 and 16 bit to 1).
^ - Xor.
The bitwise operator XOR (eXclusive OR) sets a binary position to 0 if both
numbers have the same value in the said position. On the other hand, it
sets to 1 if they have different values in the said binary position.
This is another way of setting and unsetting bits in bit-masks.
Example:
- First let's set the quests that are currently in progress:
set inProgress,1|8|16; // quest 1,8 and 16 are in progress
- After playing for a bit, the player starts another quest:
if (inProgress&2 == 0) {
// this will set the bit for quest 2 (inProgress has that bit set to 0)
set inProgress,inProgress^2;
mes "Quest 2: find a newbie and be helpful to him for an hour.";
close;
}
- After spending some time reading info on Xor's, the player finally completes quest 1:
if (inProgress&1 && isComplete) {
// this will unset the bit for quest 1 (inProgress has that bit set to 1)
set inProgress,inProgress^1;
mes "Quest 1 complete!! You unlocked the secrets of the Xor dynasty, use them wisely.";
close;
}
Unary operators with only with a single number, which follows the operator, and
are following:
- - Negation.
The sign of the number will be reversed. If the number was positive, it will
become negative and vice versa.
Example:
set .@myvar,10;
mes "Negative 10 is " + (-.@myvar);
! - Logical Not.
Reverses the boolean result of an expression. True will become false and
false will become true.
Example:
if (!callfunc("F_dosomething"))
{
mes "Doing something failed.";
close;
}
~ - Bitwise Not.
Reverses each bit in a number, also known as one's complement. Cleared bits
are set, and set bits are cleared.
Example:
- Ensure, that quest 2 is disabled, while keeping all other active, if they are.
set inProgress,inProgress&(~2); // same as set inProgress,inProgress&0xfffffffd
Ternary operators take three expressions (numbers, strings or boolean), and are
following:
?: - Conditional operator
Very useful e.g. to replace
if (Sex) mes "..."; else mes "...";
clauses with simple
mes "Welcome, " + (Sex?"Mr.":"Mrs.") + " " + strcharinfo(0);
or to replace any other simple if-else clauses. It might be worth
mentioning that ?: has low priority and has to be enclosed with
parenthesis in most (if not all) cases.
Labels
------
Within executable script code, some lines can be labels:
<label name>:
Labels are points of reference in your script, which can be used to route
execution with 'goto', 'menu' and 'jump_zero' commands, invoked with 'doevent'
and 'donpcevent' commands and are otherwise essential. A label's name may not be
longer than 22 characters. (23rd is the ':'.) There is some confusion in the
source about whether it's 22, 23 or 24 all over the place, so keeping labels
under 22 characters could be wise. It may only contain alphanumeric characters
and underscore. In addition to labels you name yourself, there are also some
special labels which the script engine will start execution from if a special
event happens:
OnClock<hour><minute>:
OnMinute<minute>:
OnHour<hour>:
On<weekday><hour><minute>:
OnDay<month><day>:
This will execute when the server clock hits the specified date or time. Hours
and minutes are given in military time. ('0105' will mean 01:05 AM). Weekdays
are Sun,Mon,Tue,Wed,Thu,Fri,Sat. Months are 01 to 12, days are 01 to 31.
Remember the zero.
OnInit:
OnInterIfInit:
OnInterIfInitOnce:
OnInit will execute every time the scripts loading is complete, including when
they are reloaded with @reloadscript command. OnInterIfInit will execute when
the map server connects to a char server, OnInterIfInitOnce will only execute
once and will not execute if the map server reconnects to the char server later.
OnAgitStart:
OnAgitEnd:
OnAgitInit:
OnAgitStart2:
OnAgitEnd2:
OnAgitInit2:
OnAgitStart3:
OnAgitEnd3:
OnAgitInit3:
OnAgitStart will run whenever the server shifts into WoE mode, whether it is
done with @agitstart GM command or with 'AgitStart' script command. OnAgitEnd
will do likewise for the end of WoE.
OnAgitInit will run when data for all castles and all guilds that hold a castle
is received by map-server from the char-server after initial connect.
No RID will be attached while any of the above mentioned labels are triggered, so
no character or account-based variables will be accessible, until you attach a
RID with 'attachrid' (see below).
The above also applies to, the last three labels, the only difference is that
these labels are used exclusively for WoE SE, and are called independently.
OnInstanceInit:
This label will be executed when an instance is created and initialized through
the 'instance_create' command. It will run again if @reloadscript is used while
an instance is in progress.
OnInstanceDestroy:
This label will be executed when an instance is destroyed by a timeout, exceeding
the keepalive time or through the 'instance_destroy' command. It will be called
exactly before the instance will be destroyed and all other NPCs of the instance
will still be available at this point of time.
OnTouch:
This label will be executed if a trigger area is defined for the NPC object it's
in. If it isn't present, the execution will start from the beginning of the NPC
code. The RID of the triggering character object will be attached.
OnTouch_:
Similar to OnTouch, but will only run one instance. Another character is
chosen once the triggering character leaves the area.
OnTouchNPC:
Similar to OnTouch, but will only trigger for monsters. For this case, by using
'getattachedrid' will returns GID (ID that returned when use 'monster').
OnPCLoginEvent:
OnPCLogoutEvent:
OnPCBaseLvUpEvent:
OnPCJobLvUpEvent:
It's pretty obvious when these four special labels will be invoked.
OnPCDieEvent:
This special label triggers when a player dies. The variable 'killerrid' is
set to the ID of the killer.
OnPCKillEvent:
This special label triggers when a player kills another player. The variable
'killedrid' is set to the ID of the player killed.
OnNPCKillEvent:
This special label triggers when a player kills a monster without label.
The variable 'killedrid' is set to the Class (mob ID) of the monster killed.
The variable 'killedgid' is set to the ID (unique mob game ID) of the monster killed.
OnPCLoadMapEvent:
This special label triggers when a player steps in a map marked with the
'loadevent' mapflag and attaches its RID. The fact that this label requires a
mapflag for it to work is because, otherwise, it'd be server-wide and trigger
every time a player would change maps. Imagine the server load with 1,000 players
(oh the pain...)
OnWhisperGlobal:
This special label triggers when a player whispers the NPC, and will run with the
player's RID attached. It can accept up to ten parameters, which will be stored
into separate temporary character string variables @whispervar0$ to @whispervar9$.
See 'doc/whisper_sys.txt' for further documentation.
Only the special labels which are not associated with any script command are
listed here. There are other kinds of labels which may be triggered in a similar
manner, but they are described with their associated commands.
On<label name>:
These special labels are used with Mob scripts mostly, and script commands
that requires you to point/link a command to a mob or another NPC, giving a label
name to start from. The label name can be any of your liking, but must be
started with "On".
Example:
monster "prontera",123,42,"Poringz0rd",2341,23,"Master::OnThisMobDeath";
amatsu,13,152,4 script Master 767,{
mes "Hi there";
close;
OnThisMobDeath:
announce "Hey, " + strcharinfo(0) + " just killed a Poringz0rd!",bc_blue|bc_all;
end;
}
Each time you kill one, that announce will appear in blue to everyone.
"Global" labels
There's a catch with labels and doevent. If you call a label (using doevent)
and called label is in NPC that has trigger area, that label must end with
"Global" to work globally (i.e. if RID is outside of the trigger area, which
usually happens since otherwise there would be no point calling the label with
doevent, because OnTouch would do the job). For further reference look for