Saturday, November 7, 2020
Linux compiler error that never shown on Visual Studio
right now, if you want to host a Private Ragnarok Online server, its just better to choose Debian or CentOS option
the reason is because if you choose Windows Server Edition on VPS,
the cost of running on Windows is often double or triple compare to Linux environment
because of this, programmer like me who write and compile their plugin/source code with Visual Studio,
it will work fine on Windows environment.
But when apply the code on Live server (Linux environment), it will throw non-sensible error
No.1
warning: implicit declaration of function ‘atoi’ [-Wimplicit-function-declaration]
Avoid using atoi like plague !!
in npc scripting its the only script command to convert string into int
yes, this actually working fine with Visual Studio, but on Linux ...
No.2
error: a label can only be part of a statement and a declaration is not a statement
Sample
this case have to be enclose with curly bracket, like this
No.3
warning: unused variable ‘len’ [-Wunused-variable]
Sample
this is very annoying, because I want to output the value from 4th argument, but the 2nd argument isn't use
on Windows this is fine, but on Linux it throws that error throw off my guard
change
there might be more, will keep this update
Monday, November 2, 2020
Page by page
*mes
sometimes you want to display a long long array list of objects,
for example print out all values from a table
this will throw infinite loop ERROR
the reason is because the script engine has some protection against infinite loop check
conf\map\script.conf
even if you put a *freeloop there, it might still lag the server
in this case, its better to just display page by page
if the *query_sql still cause lag, have to use OFFSET
and this is with page input for your amusement :)
*select
same as above
this will throw infinity loop ERROR
even if you put a LIMIT syntax
this will throw menu length too long / too many options ERROR
this is because the maximum limit of menu length in string (eg: *getstrlen) is 2047
and the maximum limit of menu options is 254
src\map\script.h
and I don't recommend changing this, as you also have to change the packet structure etc ...
so the only way to remedy this ... is again ... page by page
if the query_sql still cause lag, have to use OFFSET
and the page select display for your amusement :)
External Links:
Help - Array in menu
Wednesday, October 14, 2020
How to send Weekly Rewards to players
now I have this script
I want to send the weekly reward to players by mail, here's my take on how to tackle this problem
yup, basically I just added a few more line down there
now, this is what happen when the script first loaded
1. when the server load the script for the first time, it will execute OnInit: and try to save the date of Sunday on that week
- CURDATE() means today is '20201014'
- DAYOFWEEK(CURDATE()) means today is Wednesday(4) -> Sunday is (1)
- that's why needs a -1 , DAYOFWEEK(CURDATE())-1 means -3
- SUBDATE(CURDATE(), INTERVAL (DAYOFWEEK(CURDATE()) -1) DAY)
- SUBDATE('20201014', INTERVAL (3) DAY)
- return '2020-10-11' is the Sunday of that week
- since it return '2020-10-11', have to kill the '-' symbol, use REPLACE syntax to remove that symbol
this value '20201011' is save into $poring_rank_1st_sunday and remain unchange forever
and the script will always try to compare to this value in DATEDIFF
now, this is what happen on the next week when triggering OnSun0000: label
"SELECT DATEDIFF(CURDATE(), '"+ $poring_rank_1st_sunday +"')/7"
- CURDATE() is '20201018', the Sunday on the next week
- DATEDIFF('20201018', '20201011') return 7, since we need to compare in weeks, do a /7, 7/7 = 1
- .this_week_index = 1, $poring_rank_week_index = 0, the value are different now, thus it will try to reset the ladder
and once the ladder is reset, set $poring_rank_week_index(0) into .this_week_index(1) so it won't trigger on OnInit: label again
even doing a @reloadscript, it will compare the week index as 1 == 1, and won't execute ladder reset
only the next week again, compare the week index as 2 == 1, only will execute ladder reset
unlike the monthly reset, which save the actual date,
this one has to increase the week index counter even if there are no ranking in that week
External Links:
Weekly MVP Rewards
How to send Monthly Reward to players
now I have this script
I want to send the monthly reward to players by mail, here's my take on how to tackle this problem
yup, basically I just added a few more line down there
now break it into 3 parts
- when the server first load the script, it will execute OnInit: and store the $poringkill_last_given variable
it will store the value as '202010', 2020 is the year, and 10 is the current month - then on 12:00am, it will execute OnClock0000: label,
with the if (gettime(GETTIME_DAYOFMONTH) != 1) end; to halt the script if it isn't the day 1 of the month
since it is a new month, '202011' is different from '202010' and thus execute the condition below - The second condition of OnInit: label is to make sure it will run L_GiveMonthlyReward: label IF
the server isn't online during 12:00am of day 1 of the
month.
It will compare to the $poringkill_last_given variable every time, if it is different month, then it will execute the statement below
it has to bypass the if (gettime(GETTIME_DAYOFMONTH) != 1) end; so even if the server somehow didn't even online on day 1 of the month, it will still giving out monthly reward for previous month
External Link:
Monthly MVP Rank
Thursday, October 8, 2020
compare regular expression on rAthena & Hercules
The most famous script that uses Regular Expression is GmOcean's Disguise Event
to learn more about Regular Expression, refer to Wikipedia
Visit this site for more in-depth tutorial
This NPC will Copy whatever you type
It's common practice that you should include ^ at the beginning and $ at the end
without it, players can input whitespace to bypass the check
Example:
(.@a$ ~= "asdf") = it can be "asdf", "aaasdf", "asdfffff", " asdf " and so on
(.@a$ ~= "^asdf") = it can be "asdf", "asdffffff", "asdfasdf", "asdf " <-- this just check the begining string
(.@a$ ~= "^asdf$") = it can only be "asdf", no other match
defpattern 1, "([^:]+): asdf","L_0"; <-- it can be "asdf", "asdfffffff", "asdfasdf", "asdf " and so on
defpattern 1, "([^:]+): asdf$","L_0"; <-- only "asdf" will trigger the label L_0, OR "ASDF", "AsDf" and so on ...
yup, *pcre_match is case-sensitive, but *defpattern isn't, remember to keep this in mind
to make *pcre_match case-insensitive, use (?i) flag
to make *defpattern case-sensitive, use (?-i) flag
in practice, this command is most useful to check invalid character input
- only allow 0-9, a-z, A-Z
or follow a format, like MySQL datetime format
for rAthena counterpart, rAthena has *preg_match instead, which follow PHP style input
However unlike Hercules, there are no way to capture the strings within a bracket
rAthena's *preg_match can only returns 0 or 1
correct me if I'm wrong, the source code seems to indicate it can return 0~10 but I couldn't get it display 2 or above
Some older client that diff with multi-language support will return |00 in front of character speech
try check it with *consolemes with the very first script (rAthena is *debugmes)
if that happens, your syntax has to change into
External Links:
Disguise Event fix
defpattern regexp
ignore case sensitive in regexp
Saturday, October 3, 2020
*input with optional min/max parameter
I still see a lot people do this
although this isn't bad by any means, but we can hijack it with *input <var>,<min>,<max>;
yup, just 1 line, do all 3 conditions above
No. 1 - *input script command can return -1,0,1 these 3 values
if the input amount is smaller than <min>, then it will return with the condition -1
since we don't want to close; the script on condition 0 or 1, then put the <min> as 1,
when player input as 0, it will return as condition -1
No. 2 - The <max> can insert with the condition countitem(Poring_Coin), or 100, depends on the script
Or ... just do both by having a *min script command
<-- pick the lowest value in the group
DO NOT UNDERESTIMATE THIS TRICK
This is extremely useful if there is a complex +/- calculation involve
Example this custom bank script
Player only needs to input 9999999999 and it will automatically convert into accepted value without having to pull out a calculator
External Links:
Zeny in separate table
Monday, September 28, 2020
moving word in waitingroom
today I just review another member's script and this part caught my eye
HAHAHA !! this is so cute yet so wasting server resources !!!
I dunno I should praise him for creativity or comment him for being dump for wasting so much server bandwidth for doing this 😅
yes I don't recommend doing this on your live server ...
because every *waitingroom script command means sending one packet to each player surround this npc
... but I'm sooo impressed 😝
Sunday, September 27, 2020
A race condition in npc scripts
today I just reviewed a paid script (I couldn't show because its paid)
and I saw multiple errors and mistakes on the said script !!
this one in particular, is something less well known, but it is VERY important if you are making a Game script
let's give an example
at first glance this script looks bug free, but there is a race condition going on after the *input command
step to reproduce :-
1. open up 4 client, first 2 player claim the reward normally
2. on 3rd client, type 'ragnarok' but don't hit enter yet
3. on 4th client, type 'ragnarok' and hit enter, now the script says the event has ended
4. back on 3rd client, hit the Enter key, now this event has 4 players won this event !
to prevent this from happening, needs to add another check right after the *input command
another example is on my Private MVP Room script, which can be found in rathena repo
https://github.com/rathena/rathena/blob/a4d57cb8a398368c0d720aedc669dff88f73c4d4/npc/custom/etc/mvp_room.txt#L62-L66
now try remove these line
1. let player A register an empty room, but left the menu window open
2. player B register the empty room faster than player A
3. now both player A and player B can go into the same room !
4. if this is register under party/guild, player's B party/guild member couldn't get in even after paying the fees !!
so remember, if you are making a Game or Event script, every time after hitting a next; *menu *select *input *progressbar
the value might have changed from the original value, and might lead to race conditions between players
The Importance of *checkweight
and I saw multiple errors and mistakes on the said script !!
and this is one that MANY ... I mean MANY scripters has made this mistakes !!
if the player is currently overweight, or having more items than *getinventorysize(), the item will drop on the floor
if this actually happens, other players around this npc can come in to steal the reward item while the actual winner still desperately trying to store item
to fix this, all you have to do is add *checkweight script command
or use *rodex_sendmail script command ... or *mail script command for rathena
Friday, February 22, 2019
List pet eggs in your inventory
Hercules Pet egg uses -256 in the card1 field
rathena use 256 ... without the negative
the earliest ... traceable topic is over here
https://rathena.org/board/topic/76954-can-i-request-script-evolution-pet/?sortby=date
and now for the latest script available...
https://drive.google.com/file/d/1hQgJO4MbHIQtymKxnsrxsi37nkJ1eruz/view
the way to retrieve the pet ID is almost similar to the signed item
Signed Item
card1 = 255 or 254
card2 = star crumb + element
card3 = CHAR_ID & (( 1 << 16 ) -1)
card4 = CHAR_ID >> 16
Pet ID
card1 = -256 (Hercules) or 256 (rAthena)
card2 = CHAR_ID & (( 1 << 16 ) -1)
card3 = CHAR_ID >> 16
card4 = 0
External Links:
Pet egg renewal fixingSaturday, February 16, 2019
Hercules script engine is case-sensitive, rAthena isn't
... after rAthena switched to IPB4 ... forum bug tracker down ....
anyway, it goes like this
Joseph open a bug report, claiming some official script doesn't execute the monster label properly
after some debate between the developers, I posted a script and prove them it is true
make one npc with the capital letter, and another one without capital letter -> OnDead - Ondead
click on 'asdf' npc, after kill the monster, the map-server.exe spam error
BrianL immediately add tag [Confirmed] and [Severity-Medium] to this bug report
within a few weeks, both Euphy and Joseph fix all the npc scripts in the emulator, and they mark it as [Solved]
..... the truth is, if you try the above script in latest rAthena, this bug still happen TODAY
this bug can't reproduce in Hercules because Hercules has case-sensitive script engine
Now let's talk about how crazy the script can be, if the script engine is not case-sensitive
other than npc header, 'prontera' and '1_F_MARIA',
script commands, labels, variables and constants are case-insensitive in rAthena
strings that enclosed in " double-quotation mark are not affected
means "this" "--ja--" "all" "All" still has to retain its format
This will throw duplicate label error in rAthena
in Hercules, click on the npc will display "2" properly
So, rAthena users, remember, don't simply use Onmobdead: label in your scripts
because official script already uses OnMobDead, OnMyMobDead, ... etc
... anyways, any official script already using that label name, Don't change into small letters in your scripts
... btw, SQL commands are still case-insensitive,
so me as Hercules user still uses small letters in *query_sql script commands
External Links:
Player Checker NPC... once rAthena forum bug tracker up, will post that bug tracker ID here ...
Friday, February 15, 2019
messagecolor
Download :
Hercules PluginrAthena Patch
Note: this 0.3 version can display chat-box for the player
however the chat-box above your head isn't colorize because there are no known way to do it
Hercules' @fontcolor actually use a trick to disguise the player
https://github.com/HerculesWS/Hercules/issues/1217
https://github.com/HerculesWS/Hercules/issues/1930
and it has some bugs, so its better not to emulate that pattern
.... apparently rAthena @fontcolor is broken ...
Saturday, February 9, 2019
What is dynamic_mob and how it affects scripts
conf/map/battle/monster.conf
This setting means, monsters only spawn on the map when there is a player warp in.
if the map is left empty for 5 minutes, all dynamic spawned monsters, except spawn by boss_monster will remove from the map
it is recommend to turn on dynamic_mob because it help save memory on your live server
Example:
Let's say you login in Prontera town, and type "@asdf", poring and golden_bug are not spawn, only poporing has been spawn
"@rura guild_vs2", warp into the map, all 3 monsters are spawned
"@go 0", return to prontera, after 5 minutes, the poring is remove from the map, only golden_bug and poporing remain
"@reloadscript", return everything as normal, only poporing remain
This means :-
1. All monster spawn dynamically are affected by dynamic_mob, *monster script command are not affected
2. once a player warp into the map, all monsters will spawn normally
3. after 5 minutes the map left empty, all non-boss_monster will be remove
This can cause problem to the script if you want to count how many monsters left in the map
because dynamic_mob will NOT load the monster until a player warp into the map
External Links:
mobs on server startMVP board
Wednesday, February 6, 2019
Allow OnNPCKillEvent to increase kill counter for party members
however this is entirely done with scripting alone
this is a normal template to increase kill counter normally for the killer alone
and this is for party support
Now to break it down part by part
this part is obvious, prevent *getpartymember throw error when the player doesn't own a party
change the scope of the killedrid from player based to script state
so there is no need to use *getvariableofpc (hercules) or *getvar (rAthena)
copy paste this part from script commands.txt
// loop through both and use 'isloggedin' to count online party members
for (.@i = 0; .@i < $@partymembercount; ++.@i)
if (isloggedin($@partymemberaid[.@i], $@partymembercid[.@i]))
.@count_online++;
// We search accountID & charID because a single party can have
// multiple characters from the same account. Without searching
// through the charID, if a player has 2 characters from the same
// account inside the party but only 1 char online, it would count
// their online char twice.
the first 2 conditions is to check the party members are within range of the killer
means if the attached party member having same map with the killer, and within 30 cells of the killer
Why 30 ?? this is actually a magical number
you see, because the OnNPCKillEvent return the mob ID (1002) instead of game ID (11000021)
we can't really use mob controller system to retrieve the coordinate of the monster
so we use the range from the killer instead
I have actually tried to use getbattleflag("area_size") before, but players complained it doesn't work
so I increased the distance to 30 (about twice the length), and they say the script is fixed
weird ... I know, so the number 30 is kinda stuck in most of my scripts
1 possible explanation is this

if the Archer shoot long distances, like using a bow, throw arrow, or mage firebolt, crusader throw shield
then the party member from across the screen should gets the kill
"area_size" is 14, so 14+14 = 28, so 30 works for them
Hp ... you don't want the counter to increase for dead party member
so if that player is dead, Hp is 0, and the condition will become false there
this is to prevent having players increase the kill count by just AFK there
External Links:
Euphy's Hunting Mission ( check this line )Party Share Kill ( tr0n's Quest Board )
Regular Expression Replace in Notepad++
Regular_Expression (Wikipedia)
it can be use to :-
1. generate a huge list of mapflags
2. fix outdated format on the script commands
3. apply a quick fix on CVS style database
4. convert client side item list into array
Example 1. Generate a huge list of mapflags
1. goto db/map_index.txt, copy over the map list
2. there are some lines commented, so find the line with // and remove them by doing this
Find with regular expression Replace with empty string, this effectively leave the line blank
3. Edit -> Line Operations -> Remove Empty lines
4. Find with regular expression Replace with
Example 2. Fix outdated format on the script commands
Find with regular expression Replace with
Example 3. Apply a quick fix on CVS style database
rathena only, Hercules has switched to libconfig formatgoto db/re/item_db.txt
Find with regular expression Replace with Find with regular expression Replace with Find with regular expression Replace with
Example 4: Convert client side item list into array
goto kro/data/cardprefixnametable.txtFind with regular expression Replace with
External Links:
Disable dead branch (Example 1)Convert pow(a,b) into a**b (Example 2)
Swap item type IT_ARMOR and IT_WEAPON (Example 3)
getitemname2 function (Example 4)
Saturday, February 2, 2019
One Character per GM account
Download:
Hercules PatchHercules Plugin
Very simple trick, only allow them to create/login their character on slot 0
if you want to make them limit to 3 characters, then allow them to only use slot 0,1,2
External Links:
One char per GM AccountFriday, February 1, 2019
OnPCStatCalcEvent
it all started by me, found this modification in this topic
about update character's status
since then I have been using it VERY frequently
I'm sure those of you dealing with patch understand this,
I have to upkeep the patch to the latest server revision
eventually I was so fed up, and finally brought it to the development suggestion
See -> OnPCStatCalcEvent <- that's how rAthena got it
When I switch to Hercules, somebody else actually made a pull request on it
https://github.com/HerculesWS/Hercules/pull/351
but it was denied, and thus I released it as a plugin
For a long period of time, the *recalculatestat script command is still broken,
but I finally fix it during my time in Hercules period
Download:
Hercules Pluginhere's the catch
the reason why the *recalculatestat is still broken on rathena,
is because how the way script handling the event queue
Supposedly, we want the bonuses from the OnPCStatCalcEvent: to execute before running the status_calc_pc function
but what actually happen is the script queue up the OnPCStatCalcEvent: label, execute status_calc_pc first
thus all the bonuses from equipment/job bonuses etc has been applied, then OnPCStatCalcEvent: come in too late
since I figure it out, my little trick is delay the OnPCStatCalcEvent: to run AFTER the script execution finish, using a delay timer
I actually explained this to Secret, rathena developer, but she doesn't agree with my method, because this is not thread safe
but whatever ~ at least it working for me
OnPCStatCalcEvent can't run during npc dialog, and spam map-server error along with it
easy to reproduce during the npc dialog, keep change the equipment, you'll lose the str bonus and map-server spam error
conf/map/battle/items.conf
change this to false should stop it
showdigit
there is much more than this
because the decremental counter for type 3 runs 2 ticks per seconds, it is not advise to use type 3
type 2 is much preferred, but it risk in going into negative value, so this is usually how I do it
use showdigit type 2 for the countdown, then sleep for the duration, type 3 with 0 value will remove it
and to use this practically for an event, let's say the event only last 5 minute
========================================================
Now for the weird part of this script command
No.1 it run together with pvp counter
if you enter a PVP map, and try to showdigit, it actually show both of themso NEVER use showdigit inside a PVP map
No.2 log out and log in , the counter continues
this is another weird bug about *showdigit, it only send a value to the clientthe countdown is totally handle by the client
for example from the script above,
if you log out inside the guild_vs2 map, just change character, log in back, the counter still shows
OnPCLogoutEvent also fail to remove it
External Links:
How to put countdownshowdigit will continue to countdown if the player logout
Tuesday, January 29, 2019
Units move diagonally then move in straight line
Because it is moving in such a weird behavior,
a normal distance script command, or Pythagoras distance check isn't accurate
When input X +5, Y -10, phythagoras distance function expected 1650 mili-seconds,
but travel_time function expected 1800 mili-seconds
the result is 1872 mili-seconds
Thus travel_time function should be use instead,
simple, just (2min)² + (max - min) where min is X or Y, which one is smaller, and the opposite for max
See also:
Ragnarok Online use number of Squares to count distanceA simple walking npc script
Monday, January 28, 2019
Daily Quest - use gettimetick(2) or gettimestr ?
but my experience playing other MMORPG games, it actually reset at 12am
yes, I can finish this quest by 11.59pm, and redo it again at 12.00am
I would prefer to use *gettimestr method, unless being explicitly ask redeem the prize every 24 hours
I prefer *gettimestr over gettime(GETTIME_DAYOFYEAR) because I can read the value clearly
gettimestr("%Y%m%d", 9) return 20190128
External Link:
OnHour00 players value recoverDaily Rewards
Delete on char_reg_num on a specific time
Linux compiler error that never shown on Visual Studio
let's just admit Visual Studio sux ... ok ? right now, if you want to host a Private Ragnarok Online server, its just better to choose...
-
I have 2 samples: Topic in hercules script for hercules , script for rathena Same topic in hercules & rathena script for hercules , ...
-
Ever since Hercules forked from rAthena since Jan 2013, Hercules has driven further away from its rAthena parent, many systems and feature...
-
I still see a lot members struggle with this issue, however this is entirely done with scripting alone this is a normal template to incre...




