mirror of
https://github.com/HerculesWS/Hercules
synced 2026-08-15 12:23:13 -04:00
1188 lines
42 KiB
Text
1188 lines
42 KiB
Text
//================= Hercules Script =======================================
|
|
//= _ _ _
|
|
//= | | | | | |
|
|
//= | |_| | ___ _ __ ___ _ _| | ___ ___
|
|
//= | _ |/ _ \ '__/ __| | | | |/ _ \/ __|
|
|
//= | | | | __/ | | (__| |_| | | __/\__ \
|
|
//= \_| |_/\___|_| \___|\__,_|_|\___||___/
|
|
//================= License ===============================================
|
|
//= This file is part of Hercules.
|
|
//= http://herc.ws - http://github.com/HerculesWS/Hercules
|
|
//=
|
|
//= Copyright (C) 2013-2026 Hercules Dev Team
|
|
//= Copyright (C) 2013-2021 Haru
|
|
//=
|
|
//= Hercules is free software: you can redistribute it and/or modify
|
|
//= it under the terms of the GNU General Public License as published by
|
|
//= the Free Software Foundation, either version 3 of the License, or
|
|
//= (at your option) any later version.
|
|
//=
|
|
//= This program is distributed in the hope that it will be useful,
|
|
//= but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
//= MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
//= GNU General Public License for more details.
|
|
//=
|
|
//= You should have received a copy of the GNU General Public License
|
|
//= along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
//=========================================================================
|
|
//= Script engine self-tests
|
|
//================= Description ===========================================
|
|
//= Script to test operators and possibly other elements of the script
|
|
//= engine, useful for regression testing.
|
|
//================= Current Version =======================================
|
|
//= 2.0
|
|
//=========================================================================
|
|
|
|
function script F_TestReturnValue {
|
|
return getarg(0);
|
|
}
|
|
|
|
function script F_TestScopeVars {
|
|
.@x = 2;
|
|
return .@x+1;
|
|
}
|
|
|
|
function script F_TestNPCVars {
|
|
.x = 2;
|
|
return .x+1;
|
|
}
|
|
|
|
function script F_TestDeepNestedScope {
|
|
if (getarg(0) <= 0)
|
|
return getarg(1); // Stop recursion
|
|
if (getarg(1))
|
|
return callfunc("F_TestDeepNestedScope", getarg(0)-1, getarg(1)); // Recursion step
|
|
.@x = 1;
|
|
return callfunc("F_TestDeepNestedScope", getarg(0)-1, .@x); // First step
|
|
}
|
|
|
|
function script F_TestDeepNestedScopeNPC2 {
|
|
if (getarg(0) <= 0)
|
|
return getarg(1); // Stop recursion
|
|
if (getarg(1))
|
|
return callfunc("F_TestDeepNestedScopeNPC", getarg(0)-1, getarg(1)); // Recursion step
|
|
.x = 1;
|
|
return callfunc("F_TestDeepNestedScopeNPC", getarg(0)-1, .x); // First step
|
|
}
|
|
|
|
function script F_TestDeepNestedScopeNPC {
|
|
if (getarg(0) <= 0)
|
|
return getarg(1); // Stop recursion
|
|
if (getarg(1))
|
|
return callfunc("F_TestDeepNestedScopeNPC2", getarg(0)-1, getarg(1)); // Recursion step
|
|
.x = 1;
|
|
return callfunc("F_TestDeepNestedScopeNPC2", getarg(0)-1, .x); // First step
|
|
}
|
|
|
|
function script F_TestNestedScope {
|
|
.@x = 1;
|
|
.@y = callfunc("F_TestReturnValue", .@x);
|
|
return .@y;
|
|
}
|
|
|
|
function script F_TestNestedScopeNPC {
|
|
.x = 1;
|
|
.y = callfunc("F_TestReturnValue", .x);
|
|
return .y;
|
|
}
|
|
|
|
function script F_TestArrayRefs {
|
|
return getelementofarray(getarg(0), getarraysize(getarg(0)) - 1);
|
|
}
|
|
|
|
function script F_TestReturnArrayRef {
|
|
setarray getarg(0), 5, 6, 7, 8;
|
|
return getarraysize(getarg(0));
|
|
}
|
|
|
|
function script F_TestScopeArrays {
|
|
setarray .@x, 1, 2, 3, 4;
|
|
copyarray .@y, getarg(0), getarraysize(getarg(0));
|
|
return getarraysize(.@y);
|
|
}
|
|
|
|
function script F_TestNPCArrays {
|
|
setarray .x, 1, 2, 3, 4;
|
|
copyarray .y, getarg(0), getarraysize(getarg(0));
|
|
return getarraysize(.y);
|
|
}
|
|
|
|
function script F_TestVarOfAnotherNPC {
|
|
return getvariableofnpc(.x, getarg(0));
|
|
}
|
|
|
|
- script TestVarOfAnotherNPC FAKE_NPC,{
|
|
// Used to test getvariableofnpc()
|
|
end;
|
|
}
|
|
|
|
- script export test FAKE_NPC,{
|
|
|
|
function OnInit {
|
|
// functions labels should not be able to be called as events
|
|
// if a regression occurs, this function could end up being called when
|
|
// Hercules processes OnInit event calls (issue #2137)
|
|
|
|
// NOTE: If script_config.functions_as_events is enabled (defaults: off)
|
|
// and this this function is marked as public, it will trigger the
|
|
// warning and fail the unit test regardless.
|
|
|
|
$@something_bad_happened[0] = true;
|
|
end;
|
|
}
|
|
|
|
private function Private {
|
|
// function explicitly marked as private
|
|
return;
|
|
}
|
|
|
|
public function Public {
|
|
// this is for testing public local functions and ownership of the
|
|
// script
|
|
|
|
return getnpcid();
|
|
}
|
|
|
|
public function RefTest {
|
|
// this is to check if references are passed around properly
|
|
|
|
return set(getarg(0), 1337);
|
|
}
|
|
}
|
|
|
|
function script F_TestCalendarNextTime {
|
|
.@local_hour = gettime(GETTIME_HOUR, true);
|
|
.@local_min = gettime(GETTIME_MINUTE, true);
|
|
.@result_fromlocal = getcalendartime(.@local_hour, .@local_min, -1, -1, true);
|
|
|
|
.@utc_hour = gettime(GETTIME_HOUR, false);
|
|
.@utc_min = gettime(GETTIME_MINUTE, false);
|
|
.@result_fromutc = getcalendartime(.@utc_hour, .@utc_min, -1, -1, false);
|
|
|
|
.@expected = gettimetick(GETTIMETICK_UNIXTIME) + 24 * 60 * 60;
|
|
|
|
// We give it a range of 70 seconds more or less in the result because:
|
|
// 1. getcalendartime doesn't take seconds into account, so we may have differing seconds;
|
|
// 2. We can't mock time, the second may change during the commands execution,
|
|
// so we give it a few seconds to spare.
|
|
// This still gives a good test, because we are looking for 24 hours into the future,
|
|
// ~3 minutes aren't really an issue for correcteness here.
|
|
.@local_check = (.@result_fromlocal >= .@expected - 70 && .@result_fromlocal <= .@expected + 70);
|
|
.@utc_check = (.@result_fromutc >= .@expected - 70 && .@result_fromutc <= .@expected + 70);
|
|
|
|
return .@local_check && .@utc_check;
|
|
}
|
|
|
|
function script F_TestGetItemLink_Etc {
|
|
.@str$ = getitemlink(Jellopy, 0, 0, 0, 0);
|
|
.@str2$ = getitemlink(Jellopy);
|
|
|
|
// Sanity check, optional parameters should not affect result
|
|
if (.@str$ != .@str2$) {
|
|
return false;
|
|
}
|
|
|
|
.@pass = false;
|
|
if (PACKETVER < 20150923) {
|
|
.@pass = (.@str$ == getiteminfo(Jellopy, ITEMINFO_NAME));
|
|
} else if (PACKETVER < 20161116) {
|
|
.@pass = (.@str$ == "<ITEM>000000eF'00'00'00'00</ITEM>");
|
|
} else if (PACKETVER < 20200916) {
|
|
.@pass = (.@str$ == "<ITEML>000000eF&00(00(00(00(00</ITEML>");
|
|
} else {
|
|
.@pass = (.@str$ == "<ITEML>000000eF&00'00)00)00)00)00</ITEML>");
|
|
}
|
|
|
|
return .@pass;
|
|
}
|
|
|
|
function script F_TestGetItemLink_Headgear {
|
|
.@str$ = getitemlink(Hat, 0, 0, 0, 0);
|
|
.@str2$ = getitemlink(Hat);
|
|
|
|
// Sanity check, optional parameters should not affect result
|
|
if (.@str$ != .@str2$) {
|
|
return false;
|
|
}
|
|
|
|
.@pass = false;
|
|
if (PACKETVER < 20150923) {
|
|
.@pass = (.@str$ == getiteminfo(Hat, ITEMINFO_NAME));
|
|
} else if (PACKETVER < 20161116) {
|
|
.@pass = (.@str$ == "<ITEM>000481zO'00'00'00'00</ITEM>");
|
|
} else if (PACKETVER < 20200916) {
|
|
.@pass = (.@str$ == "<ITEML>000481zO&0g(00(00(00(00</ITEML>");
|
|
} else {
|
|
.@pass = (.@str$ == "<ITEML>000481zO&0g'00)00)00)00)00</ITEML>");
|
|
}
|
|
|
|
return .@pass;
|
|
}
|
|
|
|
function script F_TestGetItemLink_BaseWeapon {
|
|
.@str$ = getitemlink(Knife, 0, 0, 0, 0);
|
|
.@str2$ = getitemlink(Knife);
|
|
|
|
// Sanity check, optional parameters should not affect result
|
|
if (.@str$ != .@str2$) {
|
|
return false;
|
|
}
|
|
|
|
.@pass = false;
|
|
if (PACKETVER < 20150923) {
|
|
.@pass = (.@str$ == getiteminfo(Knife, ITEMINFO_NAME));
|
|
} else if (PACKETVER < 20161116) {
|
|
.@pass = (.@str$ == "<ITEM>000021jn'00'00'00'00</ITEM>");
|
|
} else if (PACKETVER < 20200916) {
|
|
.@pass = (.@str$ == "<ITEML>000021jn&00(00(00(00(00</ITEML>");
|
|
} else {
|
|
.@pass = (.@str$ == "<ITEML>000021jn&00'00)00)00)00)00</ITEML>");
|
|
}
|
|
|
|
return .@pass;
|
|
}
|
|
|
|
function script F_TestGetItemLink_FullWeapon {
|
|
setarray(.@cards[0], Fabre_Card, Necromancer_Card, 0, Agility1);
|
|
setarray(.@options[0], WEAPON_ATTR_GROUND, 1, 0, VAR_MAXHPAMOUNT, 10, 0);
|
|
.@str$ = getitemlink(Knife, 10, .@cards, .@options, 2);
|
|
|
|
.@pass = false;
|
|
if (PACKETVER < 20150923) {
|
|
.@pass = (.@str$ == getiteminfo(Knife, ITEMINFO_NAME));
|
|
} else if (PACKETVER < 20161116) {
|
|
.@pass = (.@str$ == "<ITEM>000021jn%0a'12y'19C'00'1ei)2R*00+01)01*00+0a</ITEM>");
|
|
} else if (PACKETVER < 20200916) {
|
|
.@pass = (.@str$ == "<ITEML>000021jn%0a&00(12y(19C(00(1ei*2R+00,01*01+00,0a</ITEML>");
|
|
} else {
|
|
.@pass = (.@str$ == "<ITEML>000021jn%0a&00'02)12y)19C)00)1ei+2R,00-01+01,00-0a</ITEML>");
|
|
}
|
|
|
|
return .@pass;
|
|
}
|
|
|
|
function script F_TestMesNavigation_Basic {
|
|
.@str$ = mesnavigation("Somewhere", "prt_fild08", 100, 105);
|
|
|
|
.@pass = false;
|
|
if (PACKETVER < 20111010) {
|
|
.@pass = (.@str$ == "Somewhere (prt_fild08 100, 105)");
|
|
} else {
|
|
.@pass = (.@str$ == "<NAVI>Somewhere<INFO>prt_fild08,100,105,</INFO></NAVI>");
|
|
}
|
|
|
|
return .@pass;
|
|
}
|
|
|
|
function script F_TestMesNavigation_Complete {
|
|
.@str$ = mesnavigation("Some NPC", "prt_fild08", 175, 370, true, NAV_MODE_ALL, NAV_NONE);
|
|
|
|
.@pass = false;
|
|
if (PACKETVER < 20111010) {
|
|
.@pass = (.@str$ == "Some NPC (prt_fild08 175, 370)");
|
|
} else {
|
|
.@pass = (.@str$ == "<NAVI>Some NPC<INFO>prt_fild08,175,370,0,0,1,0</INFO></NAVI>");
|
|
}
|
|
|
|
return .@pass;
|
|
}
|
|
|
|
function script F_TestMesNavigation_Search {
|
|
.@str$ = mesnavigation("Some Monster", "PORING", 0, 0, true, NAV_MODE_MOB, NAV_WINDOW_SEARCH);
|
|
|
|
.@pass = false;
|
|
if (PACKETVER < 20130800) {
|
|
.@pass = (.@str$ == "Some Monster");
|
|
} else {
|
|
.@pass = (.@str$ == "<NAVI>Some Monster<INFO>PORING,0,0,3,-222</INFO></NAVI>");
|
|
}
|
|
|
|
return .@pass;
|
|
}
|
|
|
|
function script F_TestMesMobSpawn_Basic {
|
|
.@str$ = mesmobspawn(PORING);
|
|
|
|
.@pass = false;
|
|
if (PACKETVER < 20130800) {
|
|
.@pass = (.@str$ == "Poring");
|
|
} else {
|
|
.@pass = (.@str$ == "<NAVI>Poring<INFO>PORING,0,0,3,-222</INFO></NAVI>");
|
|
}
|
|
|
|
return .@pass;
|
|
}
|
|
|
|
function script F_TestMesMobSpawn_WithLabel {
|
|
.@str$ = mesmobspawn(PORING, "Target");
|
|
|
|
.@pass = false;
|
|
if (PACKETVER < 20130800) {
|
|
.@pass = (.@str$ == "Target");
|
|
} else {
|
|
.@pass = (.@str$ == "<NAVI>Target<INFO>PORING,0,0,3,-222</INFO></NAVI>");
|
|
}
|
|
|
|
return .@pass;
|
|
}
|
|
|
|
function script F_TestMesUrl_Basic {
|
|
.@str$ = mesurl("Herc", "https://herc.ws/");
|
|
|
|
.@pass = false;
|
|
if (PACKETVER < 20111010) {
|
|
.@pass = (.@str$ == "Herc (URL: https://herc.ws/)");
|
|
} else {
|
|
.@pass = (.@str$ == "<URL>Herc<INFO>https://herc.ws/</INFO></URL>");
|
|
}
|
|
|
|
return .@pass;
|
|
}
|
|
|
|
function script F_TestMesUrl_Dimensions {
|
|
.@str$ = mesurl("Herc", "https://herc.ws/", 800, 600);
|
|
|
|
.@pass = false;
|
|
if (PACKETVER < 20111010) {
|
|
.@pass = (.@str$ == "Herc (URL: https://herc.ws/)");
|
|
} else if (PACKETVER < 20181024) {
|
|
.@pass = (.@str$ == "<URL>Herc<INFO>https://herc.ws/,800,600</INFO></URL>");
|
|
} else {
|
|
// dimensions are no longer supported since it now uses users' default browser.
|
|
.@pass = (.@str$ == "<URL>Herc<INFO>https://herc.ws/</INFO></URL>");
|
|
}
|
|
|
|
return .@pass;
|
|
}
|
|
|
|
function script F_TestMesTipBox {
|
|
.@str$ = mestipbox("Some tip", 1);
|
|
|
|
.@pass = false;
|
|
if (PACKETVER < 20170712) {
|
|
.@pass = (.@str$ == "Some tip");
|
|
} else {
|
|
.@pass = (.@str$ == "<TIPBOX>Some tip<INFO>1</INFO></TIPBOX>");
|
|
}
|
|
|
|
return .@pass;
|
|
}
|
|
|
|
function script HerculesSelfTestHelper {
|
|
if (.once > 0)
|
|
return .errors;
|
|
.once = 1;
|
|
.errors = 0;
|
|
|
|
// number literals
|
|
callsub(OnCheck, "decimal number literal", 255, 255);
|
|
callsub(OnCheck, "hexadecimal number literal", 0xFF, 255);
|
|
callsub(OnCheck, "octal number literal", 0o377, 255);
|
|
callsub(OnCheck, "binary number literal", 0b11111111, 255);
|
|
callsub(OnCheck, "binary literal bitwise OR", 0b11110000 | 0xF, 255);
|
|
callsub(OnCheck, "decimal literal with separator", 2_5_5, 255);
|
|
callsub(OnCheck, "binary literal with separator", 0b_1111_1111, 255);
|
|
|
|
// Callsub (basic)
|
|
callsub(OnCheck, "Callsub", 1, 1);
|
|
callsub(OnCheck, "Callsub (getarg default values)", 1);
|
|
|
|
|
|
// Array subscript
|
|
setarray .@a, 3, 2, 1;
|
|
callsub(OnCheck, "Array subscript", .@a[2]);
|
|
|
|
|
|
// Increment and decrement operators ++, --
|
|
.@x = 1;
|
|
.@y = .@x++; // .@y = .@x; .@x = .@x + 1;
|
|
callsub(OnCheck, "Suffix increment ++", .@y);
|
|
callsub(OnCheck, "Suffix increment ++", .@x, 2);
|
|
.@x = 1;
|
|
.@y = .@x--; // .@y = .@x; .@x = .@x - 1;
|
|
callsub(OnCheck, "Suffix decrement --", .@y);
|
|
callsub(OnCheck, "Suffix decrement --", .@x, 0);
|
|
.@x = 0;
|
|
.@y = ++.@x; // .@x = .@x + 1; .@y = .@x;
|
|
callsub(OnCheck, "Prefix increment ++", .@y);
|
|
callsub(OnCheck, "Prefix increment ++", .@x);
|
|
.@x = 2;
|
|
.@y = --.@x; // .@x = .@x - 1; .@y = .@x;
|
|
callsub(OnCheck, "Prefix decrement --", .@y);
|
|
callsub(OnCheck, "Prefix decrement --", .@x);
|
|
|
|
// Increment and decrement operators after a condition
|
|
.@x = 0;
|
|
if (1) .@x++;
|
|
callsub(OnCheck, "Suffix increment ++ after (condition)", .@x);
|
|
.@x = 2;
|
|
if (1) .@x--;
|
|
callsub(OnCheck, "Suffix decrement -- after (condition)", .@x);
|
|
.@x = 0;
|
|
if (1) ++.@x;
|
|
callsub(OnCheck, "Prefix increment ++ after (condition)", .@x);
|
|
.@x = 2;
|
|
if (1) --.@x;
|
|
callsub(OnCheck, "Prefix decrement -- after (condition)", .@x);
|
|
|
|
// Order of [] and --/++
|
|
.@a[1] = 0;
|
|
.@a[1]++; // .@a[1] = .@a[1] + 1;
|
|
callsub(OnCheck, "Order of [] and ++", .@a[1]);
|
|
.@a[1] = 2;
|
|
.@a[1]--; // .@a[1] = .@a[1] - 1;
|
|
callsub(OnCheck, "Order of [] and --", .@a[1]);
|
|
|
|
|
|
// Unary operators -, !, ~
|
|
.@x = 1;
|
|
.@y = -.@x; // .@y = 0 - .@x;
|
|
callsub(OnCheck, "Unary operator -", .@y, -1);
|
|
.@x = 1;
|
|
.@y = !.@x; // if(.@x == 0) .@y = 1; else .@y = 0;
|
|
callsub(OnCheck, "Unary operator !", .@y, 0);
|
|
.@x = 0x00000001;
|
|
.@y = ~.@x; // One's complement of 0x00000001 is 0xfffffffe, which is -2
|
|
callsub(OnCheck, "Unary operator ~", .@y, -2);
|
|
|
|
// Associativity of unary operators -, !, ~
|
|
.@x = 1;
|
|
.@y = ~ ! .@x; // .@y = ~(!.@x);
|
|
callsub(OnCheck, "Associativity of unary ~ and !", .@y, -1);
|
|
.@x = 0;
|
|
.@y = - ! .@x; // .@y = -(!.@x);
|
|
callsub(OnCheck, "Associativity of unary - and !", .@y, -1);
|
|
.@x = 1;
|
|
.@y = ~ - .@x; // .@y = ~(-.@x);
|
|
callsub(OnCheck, "Associativity of unary ~ and -", .@y, 0);
|
|
.@x = 1;
|
|
.@y = - ~ .@x; // .@y = -(~.@x);
|
|
callsub(OnCheck, "Associativity of unary - and ~", .@y, 2);
|
|
|
|
// Order of unary -, !, ~ and prefix/suffix ++/--
|
|
.@x = 2;
|
|
.@y = - --.@x; // .@y = -(--.@x);
|
|
callsub(OnCheck, "Order of unary - and prefix --", .@y, -1);
|
|
callsub(OnCheck, "Order of unary - and prefix --", .@x);
|
|
.@x = 1;
|
|
.@y = - .@x--; // .@y = -(.@x--);
|
|
callsub(OnCheck, "Order of unary - and suffix --", .@y, -1);
|
|
callsub(OnCheck, "Order of unary - and suffix --", .@x, 0);
|
|
.@x = 0;
|
|
.@y = - ++.@x; // .@y = -(++.@x);
|
|
callsub(OnCheck, "Order of unary - and prefix ++", .@y, -1);
|
|
callsub(OnCheck, "Order of unary - and prefix ++", .@x);
|
|
.@x = 1;
|
|
.@y = - .@x++; // .@y = -(.@x++);
|
|
callsub(OnCheck, "Order of unary - and suffix ++", .@y, -1);
|
|
callsub(OnCheck, "Order of unary - and suffix ++", .@x, 2);
|
|
.@x = 1;
|
|
.@y = !--.@x; // .@y = !(--.@x);
|
|
callsub(OnCheck, "Order of unary ! and prefix --", .@y);
|
|
callsub(OnCheck, "Order of unary ! and prefix --", .@x, 0);
|
|
.@x = 1;
|
|
.@y = !.@x--; // .@y = !(.@x--);
|
|
callsub(OnCheck, "Order of unary ! and suffix --", .@y, 0);
|
|
callsub(OnCheck, "Order of unary ! and suffix --", .@x, 0);
|
|
.@x = 0;
|
|
.@y = !++.@x; // .@y = !(++.@x);
|
|
callsub(OnCheck, "Order of unary ! and prefix ++", .@y, 0);
|
|
callsub(OnCheck, "Order of unary ! and prefix ++", .@x);
|
|
.@x = 0;
|
|
.@y = !.@x++; // .@y = !(.@x++);
|
|
callsub(OnCheck, "Order of unary ! and suffix ++", .@y);
|
|
callsub(OnCheck, "Order of unary ! and suffix ++", .@x);
|
|
.@x = 2;
|
|
.@y = ~--.@x; // .@y = ~(--.@x);
|
|
callsub(OnCheck, "Order of unary ~ and prefix --", .@y, -2);
|
|
callsub(OnCheck, "Order of unary ~ and prefix --", .@x, 1);
|
|
.@x = 1;
|
|
.@y = ~.@x--; // .@y = ~(.@x--);
|
|
callsub(OnCheck, "Order of unary ~ and suffix --", .@y, -2);
|
|
callsub(OnCheck, "Order of unary ~ and suffix --", .@x, 0);
|
|
.@x = 0;
|
|
.@y = ~++.@x; // .@y = ~(++.@x);
|
|
callsub(OnCheck, "Order of unary ~ and prefix ++", .@y, -2);
|
|
callsub(OnCheck, "Order of unary ~ and prefix ++", .@x, 1);
|
|
.@x = 1;
|
|
.@y = ~.@x++; // .@y = ~(.@x++);
|
|
callsub(OnCheck, "Order of unary ~ and suffix ++", .@y, -2);
|
|
callsub(OnCheck, "Order of unary ~ and suffix ++", .@x, 2);
|
|
|
|
// Binary *, /, % operators
|
|
.@x = 2 * 3; // .@x = 6;
|
|
callsub(OnCheck, "Binary * operator", .@x, 6);
|
|
.@x = 7 / 2; // .@x = 3;
|
|
callsub(OnCheck, "Binary / operator", .@x, 3);
|
|
.@x = 7 % 2; // .@x = 1;
|
|
callsub(OnCheck, "Binary % operator", .@x, 1);
|
|
|
|
// Associativity of *, /, %
|
|
.@x = 8 * 3 / 2; // .@x = (8 * 3) / 2;
|
|
callsub(OnCheck, "Associativity of * and /", .@x, 12);
|
|
|
|
// Order of binary *%/ and unary !-~
|
|
.@x = 2 * ! 3; // .@x = 2 * (!3);
|
|
callsub(OnCheck, "Order of binary * and unary !", .@x, 0);
|
|
.@x = ~ 1 * 2; // .@x = (~1) * 2;
|
|
callsub(OnCheck, "Order of unary ~ and binary *", .@x, -4);
|
|
|
|
|
|
// Binary +, - operators
|
|
.@x = 1 + 3; // .@x = 4;
|
|
callsub(OnCheck, "Binary + operator", .@x, 4);
|
|
.@x = 1 - 3; // .@x = -2;
|
|
callsub(OnCheck, "Binary - operator", .@x, -2);
|
|
|
|
// Associativity of +,-
|
|
.@x = 0x7fffffff - 0x7ffffff0 + 1; // .@x = (0x7fffffff - 0x7ffffff0) + 1; (without overflow)
|
|
callsub(OnCheck, "Associativity of + and -", .@x, 16);
|
|
|
|
// Order of +, - and *, /, %
|
|
.@x = 1 + 3 * 2; // .@x = 1 + (3 * 2);
|
|
callsub(OnCheck, "Order of + and *", .@x, 7);
|
|
|
|
|
|
// Binary ** operator
|
|
.@x = 2 ** 3; // .@x = 8;
|
|
callsub(OnCheck, "Binary ** operator", .@x, 8);
|
|
|
|
// Associativity of **
|
|
.@x = 2 ** 3 ** 2; // .@x = (2 ** 3) ** 2;
|
|
callsub(OnCheck, "Associativity of **", .@x, 64);
|
|
|
|
// Order of ** and *
|
|
.@x = 5 * 2 ** 3 * 2; // .@x = 5 * (2 ** 3) * 2;
|
|
callsub(OnCheck, "Order of ** and *", .@x, 80);
|
|
|
|
|
|
// << and >> operators
|
|
.@x = 1<<3; // .@x = 1*2*2*2;
|
|
callsub(OnCheck, "Left shift << operator", .@x, 8);
|
|
.@x = 12>>2; // .@x = 12/2/2;
|
|
callsub(OnCheck, "Right shift >> operator", .@x, 3);
|
|
|
|
// Associativity of << and >>
|
|
.@x = 0x40000000 >> 4 << 2; // .@x = (0x40000000 >> 4) << 2
|
|
callsub(OnCheck, "Associativity of >> and <<", .@x, 0x10000000);
|
|
|
|
// Order of <</>> and +/-
|
|
.@x = 4 << 2 + 1; // .@x = 4 << (2+1);
|
|
callsub(OnCheck, "Order of << and +", .@x, 32);
|
|
|
|
|
|
// <, <=, >, >= operators
|
|
.@x = (1 < 2); // true
|
|
.@y = (2 < 2); // false
|
|
callsub(OnCheck, "< operator", .@x);
|
|
callsub(OnCheck, "< operator", .@y, 0);
|
|
.@x = (1 <= 2); // true
|
|
.@y = (2 <= 2); // true
|
|
callsub(OnCheck, "<= operator", .@x);
|
|
callsub(OnCheck, "<= operator", .@y);
|
|
.@x = (2 > 1); // true
|
|
.@y = (2 > 2); // false
|
|
callsub(OnCheck, "> operator", .@x);
|
|
callsub(OnCheck, "> operator", .@y, 0);
|
|
.@x = (2 >= 1); // true
|
|
.@y = (2 >= 2); // true
|
|
callsub(OnCheck, ">= operator", .@x);
|
|
callsub(OnCheck, ">= operator", .@y);
|
|
|
|
// Associativity of <,<=,>,>=
|
|
.@x = 1 > 0 > 0; // (1 > 0) > 0 --> 1 > 0 --> true
|
|
callsub(OnCheck, "Associativity of > operators", .@x);
|
|
|
|
// Order of >>/<< and </<=/>/>=
|
|
.@x = 1 < 1 << 2; // .@x = 1 < (1<<2);
|
|
callsub(OnCheck, "Order of < and <<", .@x);
|
|
|
|
|
|
// ==, !=, ~=, ~! operators
|
|
.@x = (0 == 0); // true
|
|
.@y = (1 == 0); // false
|
|
callsub(OnCheck, "== operator", .@x);
|
|
callsub(OnCheck, "== operator", .@y, 0);
|
|
.@x = (1 != 0); // true
|
|
.@y = (1 != 1); // false
|
|
callsub(OnCheck, "!= operator", .@x);
|
|
callsub(OnCheck, "!= operator", .@y, 0);
|
|
.@x$ = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "
|
|
"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. "
|
|
"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. "
|
|
"Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
|
|
.@y = (.@x$ ~= "^Lorem.*, ([a-z]*).*(Duis).* ([a-z.]*)$");
|
|
callsub(OnCheck, "~= operator", .@y, 4);
|
|
callsub(OnCheck, "~= operator", $@regexmatchcount, 4);
|
|
if( $@regexmatchcount == 4 ) {
|
|
callsub(OnCheck, "~= operator", $@regexmatch$[0], .@x$);
|
|
callsub(OnCheck, "~= operator", $@regexmatch$[1], "quis");
|
|
callsub(OnCheck, "~= operator", $@regexmatch$[2], "Duis");
|
|
callsub(OnCheck, "~= operator", $@regexmatch$[3], "laborum.");
|
|
}
|
|
.@y = (.@x$ ~! "^Not Lorem.*, ([a-z]*).*(Duis).* ([a-z.]*)$");
|
|
callsub(OnCheck, "~! operator", .@y);
|
|
|
|
// Associativity of ==, !=
|
|
.@x = (1 == 0 == 0); // (1 == 0) == 0 --> 0 == 0 --> 1
|
|
.@y = (1 != 0 == 0); // (1 != 0) == 0 --> 1 == 0 --> 0
|
|
callsub(OnCheck, "Associativity of != and == operators", .@x);
|
|
callsub(OnCheck, "Associativity of != and == operators", .@y, 0);
|
|
|
|
// Order of </<=/>/>= and ==/!=
|
|
.@x = (1 == 2 > 1); // true
|
|
.@y = (1 < 2 == 1); // true
|
|
callsub(OnCheck, "Order of <,>,==", .@x);
|
|
callsub(OnCheck, "Order of <,>,==", .@y);
|
|
|
|
|
|
.@x$ = "string "
|
|
"concatenation" /* test */ " succeeded";
|
|
callsub(OnCheckStr, "String concatenation", .@x$, "string concatenation succeeded");
|
|
|
|
|
|
// Bitwise & operator
|
|
.@x = (7&4); // 0111 & 0100 --> 0100
|
|
.@y = (4&1); // 0100 & 0001 --> 0000
|
|
callsub(OnCheck, "Bitwise & operator", .@x, 4);
|
|
callsub(OnCheck, "Bitwise & operator", .@y, 0);
|
|
|
|
// Order of & and ==/!=
|
|
.@x = (4 == 7 & 4); // (4 == 7)&4
|
|
.@y = (1 & 3 != 1); // 1 & (3 != 1)
|
|
callsub(OnCheck, "Order of ==/!= and &", .@x, 0);
|
|
callsub(OnCheck, "Order of ==/!= and &", .@y);
|
|
|
|
|
|
// Bitwise ^ operator
|
|
.@x = (3^1); // 0011 ^ 0001 --> 0010
|
|
callsub(OnCheck, "Bitwise ^ operator", .@x, 2);
|
|
|
|
// Order of ^ and &
|
|
.@x = (0 & 2 ^ 2); // (0 & 2) ^ 2 --> (0000 & 0010) | 0010 --> 0000 ^ 0010 --> 0010
|
|
.@y = (2 ^ 2 & 0); // 2 ^ (2 & 0) --> 0010 | (0010 & 0000) --> 0010 ^ 0000 --> 0010
|
|
callsub(OnCheck, "Order of ^ and &", .@x, 2);
|
|
callsub(OnCheck, "Order of ^ and &", .@y, 2);
|
|
|
|
|
|
// Bitwise | operator
|
|
.@x = (3|4); // 0011 | 0100 --> 0111
|
|
.@y = (4|1); // 0100 | 0001 --> 0101
|
|
callsub(OnCheck, "Bitwise | operator", .@x, 7);
|
|
callsub(OnCheck, "Bitwise | operator", .@y, 5);
|
|
|
|
// Order of ^ and |
|
|
.@x = (2 ^ 2 | 2); // (2 ^ 1) | 4 --> (0010 ^ 0010) | 0010 --> 0000 | 0010 --> 0010
|
|
.@y = (2 | 2 ^ 2); // 4 | (1 ^ 2) --> 0010 | (0010 ^ 0010) --> 0010 | 0000 --> 0010
|
|
callsub(OnCheck, "Order of | and ^", .@x, 2);
|
|
callsub(OnCheck, "Order of | and ^", .@y, 2);
|
|
|
|
|
|
// Logical && operator
|
|
.@x = (1 && 1); // true
|
|
.@y = (0 && 1); // false
|
|
callsub(OnCheck, "Logical && operator", .@x);
|
|
callsub(OnCheck, "Logical && operator", .@y, 0);
|
|
|
|
// Associativity of && and short-circuit
|
|
.@x = 0;
|
|
.@y = (1 && 0 && (.@x = 1)); // should short circuit as false before evaluating the assignment
|
|
//FIXME callsub(OnCheck, "Short-circuit of &&", .@x, 0);
|
|
callsub(OnCheck, "Associativity of &&", .@y, 0);
|
|
|
|
// Order of bitwise | and logical &&
|
|
.@x = (1 && 0 | 4); // 1 && (0|4)
|
|
.@y = (4 | 0 && 1); // (4|0) && 1
|
|
callsub(OnCheck, "Order of && and |", .@x);
|
|
callsub(OnCheck, "Order of && and |", .@y);
|
|
|
|
|
|
// Logical || operator
|
|
.@x = (1 || 1); // true
|
|
.@y = (0 || 1); // true
|
|
callsub(OnCheck, "Logical || operator", .@x);
|
|
callsub(OnCheck, "Logical || operator", .@y);
|
|
|
|
// Associativity of || and short-circuit
|
|
.@x = 0;
|
|
.@y = (1 || 0 || (.@x = 1)); // should short circuit as true before evaluating the assignment
|
|
//FIXME callsub(OnCheck, "Short-circuit of ||", .@x, 0);
|
|
callsub(OnCheck, "Associativity of ||", .@y);
|
|
|
|
// Order of logical && and ||
|
|
.@x = (0 && 1 || 1); // (0 && 1) || 1
|
|
.@y = (1 || 1 && 0); // 1 || (1 && 0)
|
|
callsub(OnCheck, "Order of && and ||", .@x);
|
|
callsub(OnCheck, "Order of && and ||", .@y);
|
|
|
|
// Ternary conditional operator ?:
|
|
.@x = (1 ? 2 : 3); // 2
|
|
.@y = (0 ? 2 : 3); // 3
|
|
callsub(OnCheck, "Ternary conditional operator", .@x, 2);
|
|
callsub(OnCheck, "Ternary conditional operator", .@y, 3);
|
|
|
|
// Ternary conditional operator ?: (with strings)
|
|
.@x = ("0" ? 4 : 5); // 4
|
|
.@y = ("" ? 4 : 5); // 5
|
|
callsub(OnCheck, "Ternary conditional operator (strings)", .@x, 4);
|
|
callsub(OnCheck, "Ternary conditional operator (strings)", .@y, 5);
|
|
|
|
// Associativity of ?:
|
|
.@x = (1 ? 2 : 0 ? 3 : 4);
|
|
.@y = (1 ? 1 ? 2 : 3 : 5);
|
|
callsub(OnCheck, "Associativity of ?:", .@x, 2);
|
|
callsub(OnCheck, "Associativity of ?:", .@y, 2);
|
|
|
|
// Order of logical || and ternary ?:
|
|
.@x = (1 ? 0 : 0 || 1); // 1 ? 0 : (0 || 1) --> false
|
|
callsub(OnCheck, "Order of || and ?:", .@x, 0);
|
|
|
|
|
|
// Assignment operators
|
|
.@x = 1;
|
|
callsub(OnCheck, "Direct assignment operator =", .@x);
|
|
.@x += 7; // 1 + 7
|
|
callsub(OnCheck, "Assignment by sum +=", .@x, 8);
|
|
.@x -= 1; // 8 - 1
|
|
callsub(OnCheck, "Assignment by difference -=", .@x, 7);
|
|
.@x *= 2; // 7 * 2
|
|
callsub(OnCheck, "Assignment by product *=", .@x, 14);
|
|
.@x /= 2; // 14 / 2
|
|
callsub(OnCheck, "Assignment by quotient /=", .@x, 7);
|
|
.@x %= 4; // 7 % 4
|
|
callsub(OnCheck, "Assignment by remainder %=", .@x, 3);
|
|
.@x <<= 2; // 3 << 2
|
|
callsub(OnCheck, "Assignment by bitwise left shift <<=", .@x, 12);
|
|
.@x >>= 1; // 12 >> 1
|
|
callsub(OnCheck, "Assignment by bitwise right shift >>=", .@x, 6);
|
|
.@x &= 5; // 6 & 5 (0110 & 0101 --> 0100)
|
|
callsub(OnCheck, "Assignment by bitwise and &=", .@x, 4);
|
|
.@x ^= 5; // 4 ^ 5 (0100 ^ 0101 --> 0001)
|
|
callsub(OnCheck, "Assignment by bitwise xor ^=", .@x, 1);
|
|
.@x |= 2; // 1 | 2 (0001 | 0010 --> 0011)
|
|
callsub(OnCheck, "Assignment by bitwise or |=", .@x, 3);
|
|
|
|
// Associativity of assignment operators
|
|
.@x = 0; .@y = 0;
|
|
.@x = .@y = 1;
|
|
callsub(OnCheck, "Associativity of =", .@x);
|
|
callsub(OnCheck, "Associativity of =", .@y);
|
|
.@x = 0; .@y = 1;
|
|
.@x = .@y += 4;
|
|
callsub(OnCheck, "Associativity of = and +=", .@x, 5);
|
|
callsub(OnCheck, "Associativity of = and +=", .@y, 5);
|
|
.@x = 5; .@y = 3;
|
|
.@z = 8;
|
|
.@x *= .@y += 1;
|
|
callsub(OnCheck, "Associativity of *= and +=", .@x, 20);
|
|
callsub(OnCheck, "Associativity of *= and +=", .@y, 4);
|
|
|
|
.@x = 1; .@y = 3;
|
|
.@x += .@y * 10;
|
|
callsub(OnCheck, "Order of += and *", .@x, 31);
|
|
.@x = 1; .@y = 3;
|
|
.@x = .@y != 3 ? .@y = 2 : 4;
|
|
callsub(OnCheck, "Order of = and ?:", .@x, 4);
|
|
callsub(OnCheck, "Short-circuit/lazy evaluation of ?:", .@y, 3);
|
|
|
|
.@x = 0;
|
|
if (0)
|
|
if (1)
|
|
.@x = 2;
|
|
else
|
|
.@x = 3;
|
|
callsub(OnCheck, "Dangling else", .@x, 0);
|
|
|
|
|
|
// Array operations
|
|
.@x[0] = 1;
|
|
callsub(OnCheck, "Array size (single value)", getarraysize(.@x), 1);
|
|
.@x[0] = 0;
|
|
callsub(OnCheck, "Array size (single value removal)", getarraysize(.@x), 0);
|
|
|
|
.@x[0] = 1;
|
|
.@x[1] = 2;
|
|
.@x[2] = 3;
|
|
.@x[5] = 4;
|
|
.@x[8] = 5;
|
|
.@x[9] = 0;
|
|
setarray .@y[0], 1, 2, 3, 0, 0, 4, 0, 0, 5;
|
|
callsub(OnCheck, "Array size (assignment)", getarraysize(.@x), 9);
|
|
callsub(OnCheck, "Array size (setarray)", getarraysize(.@y), 9);
|
|
for (.@i = 0; .@i < 10; ++.@i) {
|
|
callsub(OnCheck, "Array subscript and setarray [" + .@i + "]", .@x[.@i], .@y[.@i]);
|
|
}
|
|
|
|
cleararray .@x[1], 8, 6;
|
|
callsub(OnCheck, "cleararray (value) [0]", .@x[0], 1);
|
|
for (.@i = 1; .@i < 7; ++.@i) {
|
|
callsub(OnCheck, "cleararray (value) [" + .@i + "]", .@x[.@i], 8);
|
|
}
|
|
callsub(OnCheck, "cleararray (value) [7]", .@x[7], 0);
|
|
callsub(OnCheck, "cleararray (value) [8]", .@x[8], 5);
|
|
callsub(OnCheck, "cleararray (value) [9]", .@x[9], 0);
|
|
|
|
cleararray .@x, 0, getarraysize(.@x);
|
|
cleararray .@y, 0, getarraysize(.@y);
|
|
callsub(OnCheck, "cleararray and getarraysize", getarraysize(.@x), 0);
|
|
for (.@i = 0; .@i < 10; ++.@i) {
|
|
callsub(OnCheck, "cleararray (zero) [" + .@i + "]", .@x[.@i], 0);
|
|
}
|
|
|
|
cleararray .@x, 0, getarraysize(.@x);
|
|
setarray .@x[1], 1, 2, 0, 0, 0, 6, 7, 8, 0, 0, 0, 13, 14, 15, 16;
|
|
deletearray .@x;
|
|
callsub(OnCheck, "deletearray (clear) and getarraysize", getarraysize(.@x), 0);
|
|
for (.@i = 0; .@i < 18; ++.@i) {
|
|
callsub(OnCheck, "deletearray (clear) [" + .@i + "]", .@x[.@i], 0);
|
|
}
|
|
|
|
deletearray .@x;
|
|
deletearray .@y;
|
|
setarray .@x[1], 1, 2, 0, 0, 0, 6, 7, 8, 0, 0, 0, 0, 13, 14, 15, 16;
|
|
setarray .@y, 0, 1, 2, 0, 0, 0, 6, 7, 8, 0, 0, 0, 13, 14, 15, 16;
|
|
deletearray .@x[9], 1;
|
|
callsub(OnCheck, "deletearray (single) and getarraysize", getarraysize(.@x), 16);
|
|
for (.@i = 0; .@i < 18; ++.@i) {
|
|
callsub(OnCheck, "deletearray (single) [" + .@i + "]", .@x[.@i], .@y[.@i]);
|
|
}
|
|
|
|
deletearray .@x;
|
|
deletearray .@y;
|
|
setarray .@x[1], 1, 2, 0, 0, 0, 6, 7, 8, 0, 0, 0, 13, 14, 15, 16;
|
|
setarray .@y, 0, 1, 6, 7, 8, 0, 0, 0, 13, 14, 15, 16;
|
|
deletearray .@x[2], 4;
|
|
callsub(OnCheck, "deletearray (multiple) and getarraysize", getarraysize(.@x), 12);
|
|
for (.@i = 0; .@i < 18; ++.@i) {
|
|
callsub(OnCheck, "deletearray (multiple) [" + .@i + "]", .@x[.@i], .@y[.@i]);
|
|
}
|
|
|
|
deletearray .@x;
|
|
deletearray .@y;
|
|
setarray .@x[1], 1, 2, 0, 0, 0, 6, 7, 8, 0, 0, 0, 13, 14, 15, 16;
|
|
setarray .@y, 0, 1;
|
|
deletearray .@x[2], 1000;
|
|
callsub(OnCheck, "deletearray (large count) and getarraysize", getarraysize(.@x), 2);
|
|
for (.@i = 0; .@i < 18; ++.@i) {
|
|
callsub(OnCheck, "deletearray (large count) [" + .@i + "]", .@x[.@i], .@y[.@i]);
|
|
}
|
|
|
|
deletearray .@x;
|
|
deletearray .@y;
|
|
setarray .@x[1], 1, 2, 0, 0, 0, 6, 7, 8, 0, 0, 0, 13, 14, 15, 16;
|
|
setarray .@y, 0, 1;
|
|
deletearray .@x[2];
|
|
callsub(OnCheck, "deletearray (truncate) and getarraysize", getarraysize(.@x), 2);
|
|
for (.@i = 0; .@i < 18; ++.@i) {
|
|
callsub(OnCheck, "deletearray (truncate) [" + .@i + "]", .@x[.@i], .@y[.@i]);
|
|
}
|
|
|
|
deletearray .@x;
|
|
.@x[1] = 2;
|
|
.@x[65536] = 1;
|
|
callsub(OnCheck, "large array index", .@x[65536], 1);
|
|
callsub(OnCheck, "large array index and getarraysize", getarraysize(.@x), 65537);
|
|
.@x[65536] = 0;
|
|
callsub(OnCheck, "large array index (shrink)", .@x[65536], 0);
|
|
callsub(OnCheck, "large array index and getarraysize (shrink)", getarraysize(.@x), 2);
|
|
.@x[1] = 0;
|
|
callsub(OnCheck, "array shrink", .@x[1], 0);
|
|
callsub(OnCheck, "array shrink and getarraysize", getarraysize(.@x), 0);
|
|
|
|
// min and max
|
|
callsub(OnCheck, "min()", min(5, -10, 8, 3, -2, 1000), -10);
|
|
callsub(OnCheck, "max()", max(5, -10, 8, 3, -2, 1000), 1000);
|
|
|
|
|
|
// Constants
|
|
callsub(OnCheck, "'true' constant", true, 1);
|
|
callsub(OnCheck, "'false' constant", false, 0);
|
|
callsub(OnCheck, "'PORING' mob ID", PORING, 1002);
|
|
callsub(OnCheck, "'NV_BASIC' skill ID", NV_BASIC, 1);
|
|
callsub(OnCheck, "'Red_Potion' item ID", Red_Potion, 501);
|
|
callsub(OnCheck, "'Monsters_Feed' item ID", Monsters_Feed, 528);
|
|
|
|
|
|
// setd/getd
|
|
.@x = 1; .@x$ = ".@x";
|
|
callsub(OnCheck, "getd", getd(".@x"), 1);
|
|
callsub(OnCheck, "getd arguments", getd(.@x$), 1);
|
|
.@y = 0; .@y$ = ".@y";
|
|
setd(".@y", .@x);
|
|
callsub(OnCheck, "setd", .@y, 1);
|
|
setd(.@y$, 2);
|
|
callsub(OnCheck, "setd arguments", .@y, 2);
|
|
set getd(".@x"), getd(".@y");
|
|
callsub(OnCheck, "set getd", .@x, .@y);
|
|
.@y = 1;
|
|
setd(".@x", getd(".@y"));
|
|
callsub(OnCheck, "setd getd", .@x, .@y);
|
|
|
|
// getd types
|
|
callsub(OnCheck, "Getdatatype (getd: param)", getdatatype(getd("Hp")), DATATYPE_INT | DATATYPE_PARAM);
|
|
callsub(OnCheck, "Getdatatype (getd: const)", getdatatype(getd("DATATYPE_CONST")), DATATYPE_INT | DATATYPE_CONST);
|
|
callsub(OnCheck, "Getdatatype (getd: numeric var)", getdatatype(getd(".@foo")), DATATYPE_INT | DATATYPE_VAR);
|
|
callsub(OnCheck, "Getdatatype (getd: string var)", getdatatype(getd(".@foo$")), DATATYPE_STR | DATATYPE_VAR);
|
|
|
|
// getvariableofnpc
|
|
.x = 2;
|
|
set getvariableofnpc(.x, "TestVarOfAnotherNPC"), 1;
|
|
callsub(OnCheck, "Setting NPC variables of another NPC", getvariableofnpc(.x, "TestVarOfAnotherNPC"), 1);
|
|
callsub(OnCheck, "Setting NPC variables of another NPC (local variable overwrite check)", .x, 2);
|
|
|
|
// Callsub (advanced)
|
|
callsub(OnCheck, "Callsub return value", callsub(OnTestReturnValue, 1));
|
|
.@x = 1;
|
|
callsub(OnCheck, "Callsub return with scope variables", callsub(OnTestScopeVars), 3);
|
|
callsub(OnCheck, "Callsub (parent scope vars isolation)", .@x, 1);
|
|
callsub(OnCheck, "Callsub (nested scopes)", callsub(OnTestNestedScope), 1);
|
|
callsub(OnCheck, "Callsub (deeply nested scopes)", callsub(OnTestDeepNestedScope, 30, 0), 1);
|
|
.@x = 1;
|
|
.@y = callsub(OnSetReference, .@x);
|
|
callsub(OnCheck, "Callsub (setting references)", .@y, 2);
|
|
callsub(OnCheck, "Callsub (setting references)", .@x, 2);
|
|
deletearray .@x;
|
|
setarray .@x, 1, 2, 3, 4;
|
|
callsub(OnCheck, "Callsub (array references)", callsub(OnTestArrayRefs, .@x), 4);
|
|
deletearray .@x;
|
|
.@y = callsub(OnTestReturnArrayRef, .@x);
|
|
callsub(OnCheck, "Callsub return array references (size check)", getarraysize(.@x), .@y);
|
|
callsub(OnCheck, "Callsub return array references", getelementofarray(.@x, 3), 8);
|
|
deletearray .@x;
|
|
deletearray .@y;
|
|
setarray .@x, 1, 2;
|
|
.@z = getarraysize(.@x);
|
|
setarray .@y, 5, 6, 7, 8, 9;
|
|
callsub(OnCheck, "Callsub (copyarray from reference with the same name)", getarraysize(.@y), callsub(OnTestScopeArrays, .@y));
|
|
callsub(OnCheck, "Callsub (parent array vars isolation)", getarraysize(.@x), .@z);
|
|
deletearray .@x;
|
|
deletearray .@y;
|
|
.x = 2;
|
|
set getvariableofnpc(.x, "TestVarOfAnotherNPC"), 1;
|
|
callsub(OnCheck, "Callsub (return NPC variables from another NPC)", callsub(OnTestVarOfAnotherNPC, "TestVarOfAnotherNPC"), 1);
|
|
callsub(OnCheck, "Callsub (return NPC variables from another NPC - local variable overwrite check)", .x, 2);
|
|
|
|
// Callfunc
|
|
callsub(OnCheck, "Callfunc return value", callfunc("F_TestReturnValue", 1));
|
|
.@x = 1;
|
|
callsub(OnCheck, "Callfunc return with scope variables", callfunc("F_TestScopeVars"), 3);
|
|
callsub(OnCheck, "Callfunc (parent scope vars isolation)", .@x, 1);
|
|
callsub(OnCheck, "Callfunc (nested scopes)", callfunc("F_TestNestedScope"), 1);
|
|
callsub(OnCheck, "Callfunc (deeply nested scopes)", callfunc("F_TestDeepNestedScope", 30, 0), 1);
|
|
deletearray .@x;
|
|
setarray .@x, 1, 2, 3, 4;
|
|
callsub(OnCheck, "Callfunc (array references)", callfunc("F_TestArrayRefs", .@x), 4);
|
|
deletearray .@x;
|
|
.@y = callfunc("F_TestReturnArrayRef", .@x);
|
|
callsub(OnCheck, "Callfunc return array references (size check)", getarraysize(.@x), .@y);
|
|
callsub(OnCheck, "Callfunc return array references", getelementofarray(.@x, 3), 8);
|
|
deletearray .@x;
|
|
deletearray .@y;
|
|
setarray .@x, 1, 2;
|
|
.@z = getarraysize(.@x);
|
|
setarray .@y, 5, 6, 7, 8, 9;
|
|
callsub(OnCheck, "Callfunc (copyarray from reference with the same name)", getarraysize(.@y), callfunc("F_TestScopeArrays", .@y));
|
|
callsub(OnCheck, "Callfunc (parent array vars isolation)", getarraysize(.@x), .@z);
|
|
deletearray .@x;
|
|
deletearray .@y;
|
|
.x = 1;
|
|
callsub(OnCheck, "Callfunc return with NPC variables", callfunc("F_TestNPCVars"), 3);
|
|
callsub(OnCheck, "Callfunc (parent NPC vars isolation)", .x, 1);
|
|
callsub(OnCheck, "Callfunc (nested scopes and NPC variables)", callfunc("F_TestNestedScopeNPC"), 1);
|
|
callsub(OnCheck, "Callfunc (deeply nested scopes and NPC variables)", callfunc("F_TestDeepNestedScopeNPC", 30, 0), 1);
|
|
deletearray .x;
|
|
setarray .x, 1, 2, 3, 4;
|
|
callsub(OnCheck, "Callfunc (array references and NPC variables)", callfunc("F_TestArrayRefs", .x), 4);
|
|
deletearray .x;
|
|
.y = callfunc("F_TestReturnArrayRef", .x);
|
|
callsub(OnCheck, "Callfunc return array references with NPC variables (size check)", getarraysize(.x), .y);
|
|
callsub(OnCheck, "Callfunc return array references wuth NPC variables", getelementofarray(.x, 3), 8);
|
|
deletearray .x;
|
|
deletearray .y;
|
|
setarray .x, 1, 2;
|
|
.@z = getarraysize(.@x);
|
|
setarray .y, 5, 6, 7, 8, 9;
|
|
callsub(OnCheck, "Callfunc (copyarray from NPC variable reference with the same name)", getarraysize(.@y), callfunc("F_TestNPCArrays", .@y));
|
|
callsub(OnCheck, "Callfunc (parent array NPC vars isolation)", getarraysize(.@x), .@z);
|
|
deletearray .x;
|
|
deletearray .y;
|
|
.x = 2;
|
|
set getvariableofnpc(.x, "TestVarOfAnotherNPC"), 1;
|
|
callsub(OnCheck, "Callfunc (return NPC variables from another NPC)", callfunc("F_TestVarOfAnotherNPC", "TestVarOfAnotherNPC"), 1);
|
|
callsub(OnCheck, "Callfunc (return NPC variables from another NPC - local variable overwrite check)", .x, 2);
|
|
|
|
callsub(OnCheckStr, "sprintf (%%)", sprintf("'%%'"), "'%'");
|
|
callsub(OnCheckStr, "sprintf (%d)", sprintf("'%d'", 5), "'5'");
|
|
callsub(OnCheckStr, "sprintf (neg. %d)", sprintf("'%d'", -5), "'-5'");
|
|
callsub(OnCheckStr, "sprintf (%u)", sprintf("'%u'", 5), "'5'");
|
|
callsub(OnCheckStr, "sprintf (%x)", sprintf("'%x'", 10), "'a'");
|
|
callsub(OnCheckStr, "sprintf (%X)", sprintf("'%X'", 31), "'1F'");
|
|
callsub(OnCheckStr, "sprintf (%s)", sprintf("'%s'", "Hello World!"), "'Hello World!'");
|
|
callsub(OnCheckStr, "sprintf (%c)", sprintf("'%c'", "Hello World!"), "'H'");
|
|
callsub(OnCheckStr, "sprintf (%+d)", sprintf("'%+d'", 5), "'+5'");
|
|
callsub(OnCheckStr, "sprintf (%{n}d)", sprintf("'%5d'", 5), "' 5'");
|
|
callsub(OnCheckStr, "sprintf (%-{n}d)", sprintf("'%-5d'", 5), "'5 '");
|
|
callsub(OnCheckStr, "sprintf (%-+{n}d)", sprintf("'%-+5d'", 5), "'+5 '");
|
|
callsub(OnCheckStr, "sprintf (%+0{n}d)", sprintf("'%+05d'", 5), "'+0005'");
|
|
callsub(OnCheckStr, "sprintf (%0*d)", sprintf("'%0*d'", 5, 10), "'00010'");
|
|
callsub(OnCheckStr, "sprintf (Two args)", sprintf("'%+05d' '%x'", 5, 0x7f), "'+0005' '7f'");
|
|
callsub(OnCheckStr, "sprintf (positional)", sprintf("'%2$+05d'", 5, 6), "'+0006'");
|
|
callsub(OnCheckStr, "sprintf (positional)", sprintf("'%2$s' '%1$c'", "First", "Second"), "'Second' 'F'");
|
|
.@x = 0;
|
|
/*@TRUE
|
|
.@x = 1;
|
|
//@*/
|
|
callsub(OnCheck, "Conditional comment (TRUE)", .@x, 1);
|
|
.@x = 0;
|
|
/*@!TRUE
|
|
.@x = 1;
|
|
//@*/
|
|
callsub(OnCheck, "Conditional comment (!TRUE)", .@x, 0);
|
|
.@x = 0;
|
|
/*@TRUE*/
|
|
.@x = 1;
|
|
//@*/
|
|
callsub(OnCheck, "Conditional comment with fallback (TRUE)", .@x, 1);
|
|
.@x = 0;
|
|
/*@!TRUE*/
|
|
.@x = 1;
|
|
//@*/
|
|
callsub(OnCheck, "Conditional comment with fallback (!TRUE)", .@x, 0);
|
|
|
|
callsub(OnCheck, "Getdatatype (integer)", getdatatype(5), DATATYPE_INT);
|
|
callsub(OnCheck, "Getdatatype (constant string)", getdatatype("foo"), DATATYPE_STR | DATATYPE_CONST);
|
|
callsub(OnCheck, "Getdatatype (parameter)", getdatatype(Hp), DATATYPE_INT | DATATYPE_PARAM);
|
|
callsub(OnCheck, "Getdatatype (numeric variable)", getdatatype(.@x), DATATYPE_INT | DATATYPE_VAR);
|
|
callsub(OnCheck, "Getdatatype (string variable)", getdatatype(.@x$), DATATYPE_STR | DATATYPE_VAR);
|
|
callsub(OnCheck, "Getdatatype (label)", getdatatype(OnTestGetdatatype), DATATYPE_LABEL);
|
|
callsub(OnCheck, "Getdatatype (constant)", getdatatype(DATATYPE_CONST), DATATYPE_INT | DATATYPE_CONST);
|
|
callsub(OnCheck, "Getdatatype (returned integer)", getdatatype(callsub(OnTestReturnValue, 5)), DATATYPE_INT);
|
|
callsub(OnCheck, "Getdatatype (returned string)", getdatatype(callsub(OnTestReturnValue, "foo")), DATATYPE_STR | DATATYPE_CONST);
|
|
callsub(OnCheck, "Getdatatype (getarg default value)", callsub(OnTestGetdatatypeDefault), DATATYPE_INT);
|
|
callsub(OnCheck, "Getdatatype (getarg integer value)", callsub(OnTestGetdatatype, 5), DATATYPE_INT);
|
|
callsub(OnCheck, "Getdatatype (getarg string)", callsub(OnTestGetdatatype, "foo"), DATATYPE_STR | DATATYPE_CONST);
|
|
|
|
callsub(OnCheck, "data_to_string (NIL)", data_to_string(), "");
|
|
callsub(OnCheck, "data_to_string (empty string)", data_to_string(""), "");
|
|
callsub(OnCheck, "data_to_string (string)", data_to_string("foo"), "foo");
|
|
callsub(OnCheck, "data_to_string (integer)", data_to_string(5), "5");
|
|
callsub(OnCheck, "data_to_string (parameter)", data_to_string(Hp), "Hp");
|
|
callsub(OnCheck, "data_to_string (constant)", data_to_string(DATATYPE_CONST), "DATATYPE_CONST");
|
|
callsub(OnCheck, "data_to_string (label)", data_to_string(OnTestGetdatatype), "OnTestGetdatatype");
|
|
callsub(OnCheck, "data_to_string (string variable)", data_to_string(.@x$), ".@x$");
|
|
callsub(OnCheck, "data_to_string (integer variable)", data_to_string(.@x), ".@x");
|
|
|
|
"export test"::RefTest(.@refTest = 69);
|
|
callsub(OnCheck, "function as event (regression)", $@something_bad_happened[0], false);
|
|
callsub(OnCheck, "public local function ownership", "export test"::Public(), getnpcid());
|
|
callsub(OnCheck, "public local function var reference test", .@refTest, 1337);
|
|
callsub(OnCheck, "programatic public local call", callfunctionofnpc("export test", "RefTest", .@refTest = 1), 1337);
|
|
|
|
callsub(OnCheck, "getcalendartime: next occurence of current Hour/Minute", F_TestCalendarNextTime(), true);
|
|
|
|
callsub(OnCheck, "getitemlink: etc tag", F_TestGetItemLink_Etc(), true);
|
|
callsub(OnCheck, "getitemlink: headgear tag", F_TestGetItemLink_Headgear(), true);
|
|
callsub(OnCheck, "getitemlink: basic weapon tag", F_TestGetItemLink_BaseWeapon(), true);
|
|
callsub(OnCheck, "getitemlink: complete weapon tag", F_TestGetItemLink_FullWeapon(), true);
|
|
|
|
callsub(OnCheck, "mesnavigation: basic destination", F_TestMesNavigation_Basic(), true);
|
|
callsub(OnCheck, "mesnavigation: all params", F_TestMesNavigation_Complete(), true);
|
|
callsub(OnCheck, "mesnavigation: monster spawn search", F_TestMesNavigation_Search(), true);
|
|
|
|
callsub(OnCheck, "mesmobspawn: basic usage", F_TestMesMobSpawn_Basic(), true);
|
|
callsub(OnCheck, "mesmobspawn: with label", F_TestMesMobSpawn_WithLabel(), true);
|
|
|
|
callsub(OnCheck, "mesurl: basic usage", F_TestMesUrl_Basic(), true);
|
|
callsub(OnCheck, "mesurl: with dimensions", F_TestMesUrl_Dimensions(), true);
|
|
|
|
callsub(OnCheck, "mestipbox", F_TestMesTipBox(), true);
|
|
|
|
if (.errors) {
|
|
consolemes(CONSOLEMES_DEBUG, "Script engine self-test [ \033[0;31mFAILED\033[0m ]");
|
|
consolemes(CONSOLEMES_DEBUG, "**** The test was completed with " + .errors + " errors. ****");
|
|
} else {
|
|
consolemes(CONSOLEMES_DEBUG, "Script engine self-test [ \033[0;32mPASSED\033[0m ]");
|
|
}
|
|
return .errors;
|
|
end;
|
|
|
|
OnTestReturnValue:
|
|
return getarg(0);
|
|
|
|
OnTestScopeVars:
|
|
.@x = 2;
|
|
return .@x+1;
|
|
|
|
OnTestDeepNestedScope:
|
|
if (getarg(0) <= 0)
|
|
return getarg(1); // Stop recursion
|
|
if (getarg(1))
|
|
return callsub(OnTestDeepNestedScope, getarg(0)-1, getarg(1)); // Recursion step
|
|
.@x = 1;
|
|
return callsub(OnTestDeepNestedScope, getarg(0)-1, .@x); // First step
|
|
|
|
OnTestNestedScope:
|
|
.@x = 1;
|
|
.@y = callsub(OnTestReturnValue, .@x);
|
|
return .@y;
|
|
|
|
OnTestArrayRefs:
|
|
return getelementofarray(getarg(0), getarraysize(getarg(0)) - 1);
|
|
|
|
OnTestReturnArrayRef:
|
|
setarray getarg(0), 5, 6, 7, 8;
|
|
return getarraysize(getarg(0));
|
|
|
|
OnTestScopeArrays:
|
|
setarray .@x, 1, 2, 3, 4;
|
|
copyarray .@y, getarg(0), getarraysize(getarg(0));
|
|
return getarraysize(.@y);
|
|
|
|
OnTestVarOfAnotherNPC:
|
|
return getvariableofnpc(.x, getarg(0));
|
|
|
|
OnTestGetdatatypeDefault:
|
|
return getdatatype(getarg(0, 0));
|
|
|
|
OnTestGetdatatype:
|
|
return getdatatype(getarg(0));
|
|
|
|
OnReportError:
|
|
.@msg$ = getarg(0,"Unknown Error");
|
|
.@val$ = getarg(1,"");
|
|
.@ref$ = getarg(2,"");
|
|
if (.errors == 1)
|
|
consolemes(CONSOLEMES_DEBUG, "**** WARNING: Any self-test results past this point are unreliable because of previous errors. ****");
|
|
consolemes(CONSOLEMES_DEBUG, "Error: "+.@msg$+": '"+.@val$+"' (found) != '"+.@ref$+"' (expected)");
|
|
++.errors;
|
|
//end;
|
|
return;
|
|
|
|
OnCheck:
|
|
.@msg$ = getarg(0,"Unknown Error");
|
|
.@val = getarg(1,0);
|
|
.@ref = getarg(2,1);
|
|
if (.@val != .@ref) {
|
|
callsub(OnReportError, .@msg$, ""+.@val, ""+.@ref); // String coercion
|
|
}
|
|
return;
|
|
OnCheckStr:
|
|
.@msg$ = getarg(0,"Unknown Error");
|
|
.@val$ = getarg(1,"");
|
|
.@ref$ = getarg(2,"");
|
|
if (.@val$ != .@ref$) {
|
|
callsub(OnReportError, .@msg$, .@val$, .@ref$);
|
|
}
|
|
return;
|
|
OnSetReference:
|
|
set getarg(0), getarg(0) + 1;
|
|
return getarg(0);
|
|
}
|
|
|
|
- script HerculesSelfTest FAKE_NPC,{
|
|
end;
|
|
|
|
OnInit:
|
|
callfunc("HerculesSelfTestHelper");
|
|
end;
|
|
}
|