summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--conf/map/script.conf10
-rw-r--r--db/pre-re/item_db.conf17
-rw-r--r--db/re/item_db.conf17
-rw-r--r--doc/script_commands.txt96
-rw-r--r--npc/dev/test.txt40
-rw-r--r--npc/re/quests/quests_brasilis.txt6
-rw-r--r--sql-files/item_db.sql10
-rw-r--r--sql-files/item_db_re.sql10
-rw-r--r--sql-files/main.sql7
-rw-r--r--sql-files/upgrades/2020-05-01--04-44.sql25
-rw-r--r--sql-files/upgrades/index.txt1
-rw-r--r--src/char/char.c8
-rw-r--r--src/char/inter.c8
-rw-r--r--src/char/mapif.c7
-rw-r--r--src/common/mmo.h5
-rw-r--r--src/login/account.c15
-rw-r--r--src/map/atcommand.c8
-rw-r--r--src/map/clif.c2
-rw-r--r--src/map/intif.c14
-rw-r--r--src/map/map.h8
-rw-r--r--src/map/mapreg_sql.c10
-rw-r--r--src/map/npc.c13
-rw-r--r--src/map/npc.h6
-rw-r--r--src/map/npc_chat.c3
-rw-r--r--src/map/script.c592
-rw-r--r--src/map/script.h22
-rw-r--r--src/map/status.c430
-rw-r--r--src/plugins/HPMHooking/HPMHooking.Defs.inc8
-rw-r--r--src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc8
-rw-r--r--src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc2
-rw-r--r--src/plugins/HPMHooking/HPMHooking_map.Hooks.inc66
31 files changed, 1197 insertions, 277 deletions
diff --git a/conf/map/script.conf b/conf/map/script.conf
index fc4f26965..4eb84edf4 100644
--- a/conf/map/script.conf
+++ b/conf/map/script.conf
@@ -59,6 +59,16 @@ script_configuration: {
// Defaults to INT_MAX.
//input_max_value: 2147483647
input_max_value: 10000000
+
+ // Specifies whether functions not explicitly marked with a "private" or
+ // "public" keyword should be treated as "private" by default.
+ // Default: true
+ functions_private_by_default: true
+
+ // Specifies whether public functions can be invoked as NPC events. This
+ // allows, for example, to use a `public function OnDeath { ... }` instead
+ // of a `OnDeath:` label for mob death events.
+ functions_as_events: false
}
import: "conf/import/script.conf"
diff --git a/db/pre-re/item_db.conf b/db/pre-re/item_db.conf
index 74aeaa460..493a758cc 100644
--- a/db/pre-re/item_db.conf
+++ b/db/pre-re/item_db.conf
@@ -67262,8 +67262,7 @@ item_db: (
Weight: 10
BuyingStore: true
Script: <"
- sc_start(SC_RESIST_PROPERTY_FIRE, 1200000, 20);
- sc_start(SC_RESIST_PROPERTY_WATER, 1200000, -15, 10000, SCFLAG_NOAVOID | SCFLAG_NOICON);
+ sc_start2(SC_RESIST_PROPERTY_FIRE, 1200000, 20, -15);
">
},
{
@@ -67275,8 +67274,7 @@ item_db: (
Weight: 10
BuyingStore: true
Script: <"
- sc_start(SC_RESIST_PROPERTY_WATER, 1200000, 20);
- sc_start(SC_RESIST_PROPERTY_WIND, 1200000, -15, 10000, SCFLAG_NOAVOID | SCFLAG_NOICON);
+ sc_start2(SC_RESIST_PROPERTY_WATER, 1200000, 20, -15);
">
},
{
@@ -67288,8 +67286,7 @@ item_db: (
Weight: 10
BuyingStore: true
Script: <"
- sc_start(SC_RESIST_PROPERTY_GROUND, 1200000, 20);
- sc_start(SC_RESIST_PROPERTY_FIRE, 1200000, -15, 10000, SCFLAG_NOAVOID | SCFLAG_NOICON);
+ sc_start2(SC_RESIST_PROPERTY_GROUND, 1200000, 20, -15);
">
},
{
@@ -67301,8 +67298,7 @@ item_db: (
Weight: 10
BuyingStore: true
Script: <"
- sc_start(SC_RESIST_PROPERTY_WIND, 1200000, 20);
- sc_start(SC_RESIST_PROPERTY_GROUND, 1200000, -15, 10000, SCFLAG_NOAVOID | SCFLAG_NOICON);
+ sc_start2(SC_RESIST_PROPERTY_WIND, 1200000, 20, -15);
">
},
{
@@ -69503,10 +69499,7 @@ item_db: (
Type: "IT_USABLE"
Weight: 10
Script: <"
- sc_start(SC_RESIST_PROPERTY_FIRE, 300000, 20);
- sc_start(SC_RESIST_PROPERTY_WATER, 300000, 20);
- sc_start(SC_RESIST_PROPERTY_WIND, 300000, 20);
- sc_start(SC_RESIST_PROPERTY_GROUND, 300000, 20);
+ sc_start4(SC_ARMOR_RESIST, 300000, 20, 20, 20, 20);
">
},
{
diff --git a/db/re/item_db.conf b/db/re/item_db.conf
index eec334d18..408fb3ef8 100644
--- a/db/re/item_db.conf
+++ b/db/re/item_db.conf
@@ -87138,8 +87138,7 @@ item_db: (
Weight: 10
BuyingStore: true
Script: <"
- sc_start(SC_RESIST_PROPERTY_FIRE, 1200000, 20);
- sc_start(SC_RESIST_PROPERTY_WATER, 1200000, -15, 10000, SCFLAG_NOAVOID | SCFLAG_NOICON);
+ sc_start2(SC_RESIST_PROPERTY_FIRE, 1200000, 20, -15);
">
},
{
@@ -87151,8 +87150,7 @@ item_db: (
Weight: 10
BuyingStore: true
Script: <"
- sc_start(SC_RESIST_PROPERTY_WATER, 1200000, 20);
- sc_start(SC_RESIST_PROPERTY_WIND, 1200000, -15, 10000, SCFLAG_NOAVOID | SCFLAG_NOICON);
+ sc_start2(SC_RESIST_PROPERTY_WATER, 1200000, 20, -15);
">
},
{
@@ -87164,8 +87162,7 @@ item_db: (
Weight: 10
BuyingStore: true
Script: <"
- sc_start(SC_RESIST_PROPERTY_GROUND, 1200000, 20);
- sc_start(SC_RESIST_PROPERTY_FIRE, 1200000, -15, 10000, SCFLAG_NOAVOID | SCFLAG_NOICON);
+ sc_start2(SC_RESIST_PROPERTY_GROUND, 1200000, 20, -15);
">
},
{
@@ -87177,8 +87174,7 @@ item_db: (
Weight: 10
BuyingStore: true
Script: <"
- sc_start(SC_RESIST_PROPERTY_WIND, 1200000, 20);
- sc_start(SC_RESIST_PROPERTY_GROUND, 1200000, -15, 10000, SCFLAG_NOAVOID | SCFLAG_NOICON);
+ sc_start2(SC_RESIST_PROPERTY_WIND, 1200000, 20, -15);
">
},
{
@@ -89402,10 +89398,7 @@ item_db: (
Type: "IT_USABLE"
Weight: 10
Script: <"
- sc_start(SC_RESIST_PROPERTY_FIRE, 300000, 20);
- sc_start(SC_RESIST_PROPERTY_WATER, 300000, 20);
- sc_start(SC_RESIST_PROPERTY_WIND, 300000, 20);
- sc_start(SC_RESIST_PROPERTY_GROUND, 300000, 20);
+ sc_start4(SC_ARMOR_RESIST, 300000, 20, 20, 20, 20);
">
},
{
diff --git a/doc/script_commands.txt b/doc/script_commands.txt
index 3b77aeb2c..a597dfaa2 100644
--- a/doc/script_commands.txt
+++ b/doc/script_commands.txt
@@ -536,7 +536,9 @@ 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. The maximum length of variable name including prefix and
-suffix is 32.
+suffix is 32. Permanent string variables (name$, $name$, #name$, ##name$)
+can store text with a maximum length of 255 characters. All other string
+type variables have no such limitation.
Some variables are special, that is, they are already defined for you by
the scripting engine. You can see the full list somewhere in
@@ -1710,7 +1712,8 @@ The default value of 'min' and 'max' can be set with 'input_min_value' and
For numeric inputs the value is capped to the range [min, max]. Returns 1
if the value was higher than 'max', -1 if lower than 'min' and 0 otherwise.
For string inputs it returns 1 if the string was longer than 'max', -1 is
-shorter than 'min' and 0 otherwise.
+shorter than 'min' and 0 otherwise. Note that an input string has a maximum
+length of 70 characters.
---------------------------------------
@@ -1942,58 +1945,64 @@ will result in error and termination of the script.
---------------------------------------
-*function <function name>;
-*<function name>{(<argument>, ...<argument>)};
-*function <function name> {
+{public | private} *function <function name>;
+{public | private} *function <function name> {
<code>
}
-This works like callfunc(), and is used for cleaner and faster scripting.
-The function must be defined and used within a script, and works like a
-label with arguments.
-Note that the name may only contain alphanumeric characters and underscore.
+In its first form, this syntax declares a local function so it can later be
+defined. In its second form, the syntax both declares and defines a local
+function. Local functions must be defined before being used. Note that the name
+may only contain alphanumeric characters and underscore. Once defined, they can
+be called from the current script as if they were regular built-in commands, and
+can also be called from other scripts if they are marked as public. Local
+functions may be marked as public by simply adding "public" prior to the
+function definition. Functions not marked as public are private by default and
+cannot be called from another script.
Usage:
1. Declare the function.
function <function name>;
2. Call the function anywhere within the script.
- It can also return a value when used with parentheses.
- <function name>;
- 3. Define the function within the script.
+ <function name>();
+ 3. Define the function by adding its script.
<function name> {<code>}
+ Step 1 is optional if the function is defined prior to being called.
+
Example:
-prontera,154,189,4 script Item Seller 767,{
/* Function declaration */
- function SF_Selling;
+ function MyFunction;
- if (Zeny > 50) {
- mes("Welcome!");
- /* Function call */
- SF_Selling();
- } else {
- mes("You need 50z, sorry!");
- }
- close();
+ /* Function call */
+ MyFunction();
/* Function definition */
- function SF_Selling {
- mes("Would you like to buy a phracon for 50z?");
- next();
- if (select("Yes", "No, thanks") == 1) {
- Zeny -= 50;
- getitem(Phracon, 1);
- mes("Thank you!");
- }
+ function MyFunction {
+ // (do something)
return;
}
-}
+
+
+Example with public functions:
+
+ /* Function declaration + definition */
+ public function myFunction {
+ /* notice the "public" before the "function" keyword */
+ return;
+ }
+
+ /* Local call */
+ myFunction();
+
+ /* Call from another script */
+ "npc name"::myFunction();
+
Example with parameters and return value:
-prontera,150,150,0 script TestNPC 123,{
/* Function declaration */
function MyAdd;
@@ -2002,18 +2011,35 @@ prontera,150,150,0 script TestNPC 123,{
input(.@a);
input(.@b);
/* Function call */
- mes(.@a+" + "+.@b+" = "+MyAdd(.@a, .@b));
+ mesf("%i + %i = %i", .@a, .@b, MyAdd(.@a, .@b));
close();
/* Function definition */
function MyAdd {
- return(getarg(0)+getarg(1));
+ return (getarg(0) + getarg(1));
}
-}
---------------------------------------
+*<function name>({<arg>...})
+*"<npc name>"::<function name>({<arg>...})
+*callfunctionofnpc("<function name>", "<npc name>"{, <arg>...});
+
+In its first form, calls a previously defined local function. In its second
+form, calls a previously defined public local function of another NPC. If the
+name of the target NPC or the name of the local function is not known
+beforehand, callfunctionofnpc() can be used instead of the second form.
+See function() above for more details.
+
+Example:
+
+ MyFunction(arg1, arg2, arg3);
+ "MyNPC"::MyFunction(arg1, arg2, arg3);
+ callfunctionofnpc("MyNPC", "MyFunction", arg1, arg2, arg3);
+
+---------------------------------------
+
*is_function("<function name>")
This command checks whether or not a function exists and returns its type.
diff --git a/npc/dev/test.txt b/npc/dev/test.txt
index a9e78489a..c8c842055 100644
--- a/npc/dev/test.txt
+++ b/npc/dev/test.txt
@@ -116,6 +116,40 @@ function script F_TestVarOfAnotherNPC {
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 HerculesSelfTestHelper {
if (.once > 0)
return .errors;
@@ -785,6 +819,12 @@ function script HerculesSelfTestHelper {
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);
+
if (.errors) {
consolemes(CONSOLEMES_DEBUG, "Script engine self-test [ \033[0;31mFAILED\033[0m ]");
consolemes(CONSOLEMES_DEBUG, "**** The test was completed with " + .errors + " errors. ****");
diff --git a/npc/re/quests/quests_brasilis.txt b/npc/re/quests/quests_brasilis.txt
index debaba2e5..1d5578fa0 100644
--- a/npc/re/quests/quests_brasilis.txt
+++ b/npc/re/quests/quests_brasilis.txt
@@ -124,10 +124,10 @@ OnGo:
mes "Ah... who's a good puppy?";
mes "Ok, where are the others?";
}
- if (compare(strnpcinfo(NPC_NAME_UNIQUE),"1")) setarray .@i[0],2,3;
- else if (compare(strnpcinfo(NPC_NAME_UNIQUE),"2")) setarray .@i[0],1,3;
+ if (compare(strnpcinfo(NPC_NAME_HIDDEN),"1")) setarray .@i[0],2,3;
+ else if (compare(strnpcinfo(NPC_NAME_HIDDEN),"2")) setarray .@i[0],1,3;
else setarray .@i[0],1,2;
- donpcevent "Puppy#"+charat(strnpcinfo(NPC_NAME_UNIQUE),0)+.@i[rand(2)]+"::OnEnable";
+ donpcevent "Puppy#"+charat(strnpcinfo(NPC_NAME_HIDDEN),0)+.@i[rand(2)]+"::OnEnable";
hideonnpc strnpcinfo(NPC_NAME);
close;
}
diff --git a/sql-files/item_db.sql b/sql-files/item_db.sql
index ac3cad389..70ecb2094 100644
--- a/sql-files/item_db.sql
+++ b/sql-files/item_db.sql
@@ -4491,10 +4491,10 @@ REPLACE INTO `item_db` VALUES ('12114','Elemental_Fire','Elemental Converter','2
REPLACE INTO `item_db` VALUES ('12115','Elemental_Water','Elemental Converter','2','0','2','1','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','itemskill ITEM_ENCHANTARMS,2;','','');
REPLACE INTO `item_db` VALUES ('12116','Elemental_Earth','Elemental Converter','2','0','2','1','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','itemskill ITEM_ENCHANTARMS,3;','','');
REPLACE INTO `item_db` VALUES ('12117','Elemental_Wind','Elemental Converter','2','0','2','1','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','itemskill ITEM_ENCHANTARMS,5;','','');
-REPLACE INTO `item_db` VALUES ('12118','Resist_Fire','Fireproof Potion','2','0','2','1','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start(SC_RESIST_PROPERTY_FIRE, 1200000, 20); sc_start(SC_RESIST_PROPERTY_WATER, 1200000, -15, 10000, SCFLAG_NOAVOID | SCFLAG_NOICON);','','');
-REPLACE INTO `item_db` VALUES ('12119','Resist_Water','Coldproof Potion','2','0','2','1','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start(SC_RESIST_PROPERTY_WATER, 1200000, 20); sc_start(SC_RESIST_PROPERTY_WIND, 1200000, -15, 10000, SCFLAG_NOAVOID | SCFLAG_NOICON);','','');
-REPLACE INTO `item_db` VALUES ('12120','Resist_Earth','Earthproof Potion','2','0','2','1','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start(SC_RESIST_PROPERTY_GROUND, 1200000, 20); sc_start(SC_RESIST_PROPERTY_FIRE, 1200000, -15, 10000, SCFLAG_NOAVOID | SCFLAG_NOICON);','','');
-REPLACE INTO `item_db` VALUES ('12121','Resist_Wind','Thunderproof Potion','2','0','2','1','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start(SC_RESIST_PROPERTY_WIND, 1200000, 20); sc_start(SC_RESIST_PROPERTY_GROUND, 1200000, -15, 10000, SCFLAG_NOAVOID | SCFLAG_NOICON);','','');
+REPLACE INTO `item_db` VALUES ('12118','Resist_Fire','Fireproof Potion','2','0','2','1','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start2(SC_RESIST_PROPERTY_FIRE, 1200000, 20, -15);','','');
+REPLACE INTO `item_db` VALUES ('12119','Resist_Water','Coldproof Potion','2','0','2','1','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start2(SC_RESIST_PROPERTY_WATER, 1200000, 20, -15);','','');
+REPLACE INTO `item_db` VALUES ('12120','Resist_Earth','Earthproof Potion','2','0','2','1','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start2(SC_RESIST_PROPERTY_GROUND, 1200000, 20, -15);','','');
+REPLACE INTO `item_db` VALUES ('12121','Resist_Wind','Thunderproof Potion','2','0','2','1','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start2(SC_RESIST_PROPERTY_WIND, 1200000, 20, -15);','','');
REPLACE INTO `item_db` VALUES ('12122','Sesame_Pastry','Sesame Pastry','2','0','2','1','70','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start SC_FOOD_BASICHIT,1200000,30;','','');
REPLACE INTO `item_db` VALUES ('12123','Honey_Pastry','Honey Pastry','2','0','2','1','70','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start SC_FOOD_BASICAVOIDANCE,1200000,30;','','');
REPLACE INTO `item_db` VALUES ('12124','Rainbow_Cake','Rainbow Cake','2','0','2','1','70','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start SC_BATKFOOD,1200000,10; sc_start SC_MATKFOOD,120000,10;','','');
@@ -4649,7 +4649,7 @@ REPLACE INTO `item_db` VALUES ('12275','Gold_Pill_2','Taecheongdan','0','0','0',
REPLACE INTO `item_db` VALUES ('12276','Mimic_Scroll','Mimic Scroll','2','0','2','1','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','73',NULL,'0',NULL,'0',NULL,'0','mercenary_create M_MIMIC, 1800000;','','');
REPLACE INTO `item_db` VALUES ('12277','Disguise_Scroll','Disguise Scroll','2','0','2','1','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','73',NULL,'0',NULL,'0',NULL,'0','mercenary_create M_DISGUISE, 1800000;','','');
REPLACE INTO `item_db` VALUES ('12278','Alice_Scroll','Alice Scroll','2','0','2','1','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','73',NULL,'0',NULL,'0',NULL,'0','mercenary_create M_ALICE, 1800000;','','');
-REPLACE INTO `item_db` VALUES ('12279','Undead_Element_Scroll','Undead Elemental Scroll','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start(SC_RESIST_PROPERTY_FIRE, 300000, 20); sc_start(SC_RESIST_PROPERTY_WATER, 300000, 20); sc_start(SC_RESIST_PROPERTY_WIND, 300000, 20); sc_start(SC_RESIST_PROPERTY_GROUND, 300000, 20);','','');
+REPLACE INTO `item_db` VALUES ('12279','Undead_Element_Scroll','Undead Elemental Scroll','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start4(SC_ARMOR_RESIST, 300000, 20, 20, 20, 20);','','');
REPLACE INTO `item_db` VALUES ('12280','Holy_Element_Scroll','Holy Elemental Scroll','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','specialeffect(EF_BENEDICTIO, AREA, playerattached()); sc_start SC_BENEDICTIO,300000,1;','','');
REPLACE INTO `item_db` VALUES ('12281','Tresure_Box_WoE','Event Treasure Box','2','0','20','10','150','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','getrandgroupitem 12281,1;','','');
REPLACE INTO `item_db` VALUES ('12282','Internet_Cafe1','Internet Cafe1','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start SC_FOOD_STR, 5400000, 3; sc_start SC_FOOD_DEX, 5400000, 3; sc_start SC_FOOD_AGI, 5400000, 3; sc_start SC_FOOD_INT, 5400000, 3; sc_start SC_FOOD_VIT, 5400000, 3; sc_start SC_FOOD_LUK, 5400000, 3; sc_start SC_PLUSATTACKPOWER, 5400000, 15; sc_start SC_PLUSMAGICPOWER, 5400000, 15;','','');
diff --git a/sql-files/item_db_re.sql b/sql-files/item_db_re.sql
index b9332701d..c378bbc88 100644
--- a/sql-files/item_db_re.sql
+++ b/sql-files/item_db_re.sql
@@ -5995,10 +5995,10 @@ REPLACE INTO `item_db` VALUES ('12114','Elemental_Fire','Elemental Converter','2
REPLACE INTO `item_db` VALUES ('12115','Elemental_Water','Elemental Converter','2','0','2','1','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','itemskill ITEM_ENCHANTARMS,2;','','');
REPLACE INTO `item_db` VALUES ('12116','Elemental_Earth','Elemental Converter','2','0','2','1','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','itemskill ITEM_ENCHANTARMS,3;','','');
REPLACE INTO `item_db` VALUES ('12117','Elemental_Wind','Elemental Converter','2','0','2','1','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','itemskill ITEM_ENCHANTARMS,5;','','');
-REPLACE INTO `item_db` VALUES ('12118','Resist_Fire','Fireproof Potion','2','0','2','1','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start(SC_RESIST_PROPERTY_FIRE, 1200000, 20); sc_start(SC_RESIST_PROPERTY_WATER, 1200000, -15, 10000, SCFLAG_NOAVOID | SCFLAG_NOICON);','','');
-REPLACE INTO `item_db` VALUES ('12119','Resist_Water','Coldproof Potion','2','0','2','1','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start(SC_RESIST_PROPERTY_WATER, 1200000, 20); sc_start(SC_RESIST_PROPERTY_WIND, 1200000, -15, 10000, SCFLAG_NOAVOID | SCFLAG_NOICON);','','');
-REPLACE INTO `item_db` VALUES ('12120','Resist_Earth','Earthproof Potion','2','0','2','1','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start(SC_RESIST_PROPERTY_GROUND, 1200000, 20); sc_start(SC_RESIST_PROPERTY_FIRE, 1200000, -15, 10000, SCFLAG_NOAVOID | SCFLAG_NOICON);','','');
-REPLACE INTO `item_db` VALUES ('12121','Resist_Wind','Thunderproof Potion','2','0','2','1','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start(SC_RESIST_PROPERTY_WIND, 1200000, 20); sc_start(SC_RESIST_PROPERTY_GROUND, 1200000, -15, 10000, SCFLAG_NOAVOID | SCFLAG_NOICON);','','');
+REPLACE INTO `item_db` VALUES ('12118','Resist_Fire','Fireproof Potion','2','0','2','1','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start2(SC_RESIST_PROPERTY_FIRE, 1200000, 20, -15);','','');
+REPLACE INTO `item_db` VALUES ('12119','Resist_Water','Coldproof Potion','2','0','2','1','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start2(SC_RESIST_PROPERTY_WATER, 1200000, 20, -15);','','');
+REPLACE INTO `item_db` VALUES ('12120','Resist_Earth','Earthproof Potion','2','0','2','1','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start2(SC_RESIST_PROPERTY_GROUND, 1200000, 20, -15);','','');
+REPLACE INTO `item_db` VALUES ('12121','Resist_Wind','Thunderproof Potion','2','0','2','1','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start2(SC_RESIST_PROPERTY_WIND, 1200000, 20, -15);','','');
REPLACE INTO `item_db` VALUES ('12122','Sesame_Pastry','Sesame Pastry','2','0','2','1','70','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start SC_FOOD_BASICHIT,1200000,30;','','');
REPLACE INTO `item_db` VALUES ('12123','Honey_Pastry','Honey Pastry','2','0','2','1','70','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start SC_FOOD_BASICAVOIDANCE, 1200000, 30;','','');
REPLACE INTO `item_db` VALUES ('12124','Rainbow_Cake','Rainbow Cake','2','0','2','1','70','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start SC_PLUSATTACKPOWER, 1200000, 10; sc_start SC_PLUSMAGICPOWER, 120000, 10;','','');
@@ -6153,7 +6153,7 @@ REPLACE INTO `item_db` VALUES ('12275','Gold_Pill_2','Taecheongdan','0','0','0',
REPLACE INTO `item_db` VALUES ('12276','Mimic_Scroll','Mimic Scroll','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','mercenary_create M_MIMIC, 1800000;','','');
REPLACE INTO `item_db` VALUES ('12277','Disguise_Scroll','Disguise Scroll','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','mercenary_create M_DISGUISE, 1800000;','','');
REPLACE INTO `item_db` VALUES ('12278','Alice_Scroll','Alice Contract','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','mercenary_create M_ALICE, 1800000;','','');
-REPLACE INTO `item_db` VALUES ('12279','Undead_Element_Scroll','Undead Elemental Scroll','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start(SC_RESIST_PROPERTY_FIRE, 300000, 20); sc_start(SC_RESIST_PROPERTY_WATER, 300000, 20); sc_start(SC_RESIST_PROPERTY_WIND, 300000, 20); sc_start(SC_RESIST_PROPERTY_GROUND, 300000, 20);','','');
+REPLACE INTO `item_db` VALUES ('12279','Undead_Element_Scroll','Undead Elemental Scroll','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start4(SC_ARMOR_RESIST, 300000, 20, 20, 20, 20);','','');
REPLACE INTO `item_db` VALUES ('12280','Holy_Element_Scroll','Holy Elemental Scroll','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','specialeffect(EF_BENEDICTIO, AREA, playerattached()); sc_start SC_BENEDICTIO,300000,1;','','');
REPLACE INTO `item_db` VALUES ('12281','Tresure_Box_WoE','Event Treasure Box','2','0','20','10','150','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','packageitem();','','');
REPLACE INTO `item_db` VALUES ('12282','Internet_Cafe1','Internet Cafe1','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start SC_FOOD_STR, 5400000, 3; sc_start SC_FOOD_DEX, 5400000, 3; sc_start SC_FOOD_AGI, 5400000, 3; sc_start SC_FOOD_INT, 5400000, 3; sc_start SC_FOOD_VIT, 5400000, 3; sc_start SC_FOOD_LUK, 5400000, 3; sc_start SC_PLUSATTACKPOWER, 5400000, 15; sc_start SC_PLUSMAGICPOWER, 5400000, 15;','','');
diff --git a/sql-files/main.sql b/sql-files/main.sql
index dcd7e543d..d5b7735fc 100644
--- a/sql-files/main.sql
+++ b/sql-files/main.sql
@@ -51,7 +51,7 @@ CREATE TABLE IF NOT EXISTS `acc_reg_str_db` (
`account_id` INT UNSIGNED NOT NULL DEFAULT '0',
`key` VARCHAR(32) BINARY NOT NULL DEFAULT '',
`index` INT UNSIGNED NOT NULL DEFAULT '0',
- `value` VARCHAR(254) NOT NULL DEFAULT '0',
+ `value` VARCHAR(255) NOT NULL DEFAULT '0',
PRIMARY KEY (`account_id`,`key`,`index`),
KEY `account_id` (`account_id`)
) ENGINE=MyISAM;
@@ -275,7 +275,7 @@ CREATE TABLE IF NOT EXISTS `char_reg_str_db` (
`char_id` INT UNSIGNED NOT NULL DEFAULT '0',
`key` VARCHAR(32) BINARY NOT NULL DEFAULT '',
`index` INT UNSIGNED NOT NULL DEFAULT '0',
- `value` VARCHAR(254) NOT NULL DEFAULT '0',
+ `value` VARCHAR(255) NOT NULL DEFAULT '0',
PRIMARY KEY (`char_id`,`key`,`index`),
KEY `char_id` (`char_id`)
) ENGINE=MyISAM;
@@ -372,7 +372,7 @@ CREATE TABLE IF NOT EXISTS `global_acc_reg_str_db` (
`account_id` INT UNSIGNED NOT NULL DEFAULT '0',
`key` VARCHAR(32) BINARY NOT NULL DEFAULT '',
`index` INT UNSIGNED NOT NULL DEFAULT '0',
- `value` VARCHAR(254) NOT NULL DEFAULT '0',
+ `value` VARCHAR(255) NOT NULL DEFAULT '0',
PRIMARY KEY (`account_id`,`key`,`index`),
KEY `account_id` (`account_id`)
) ENGINE=MyISAM;
@@ -938,6 +938,7 @@ INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1574463539); -- 2019-11-2
INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1579817630); -- 2020-01-24--01-09.sql
INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1584838560); -- 2020-03-22--01-56.sql
INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1584842940); -- 2020-03-22--03-09.sql
+INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1588301040); -- 2020-05-01--04-44.sql
--
-- Table structure for table `storage`
diff --git a/sql-files/upgrades/2020-05-01--04-44.sql b/sql-files/upgrades/2020-05-01--04-44.sql
new file mode 100644
index 000000000..6cb5a30ec
--- /dev/null
+++ b/sql-files/upgrades/2020-05-01--04-44.sql
@@ -0,0 +1,25 @@
+#1588301040
+
+-- This file is part of Hercules.
+-- http://herc.ws - http://github.com/HerculesWS/Hercules
+--
+-- Copyright (C) 2019-2020 Hercules Dev Team
+--
+-- 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/>.
+
+ALTER TABLE `acc_reg_str_db` MODIFY `value` VARCHAR(255) NOT NULL DEFAULT '0';
+ALTER TABLE `char_reg_str_db` MODIFY `value` VARCHAR(255) NOT NULL DEFAULT '0';
+ALTER TABLE `global_acc_reg_str_db` MODIFY `value` VARCHAR(255) NOT NULL DEFAULT '0';
+
+INSERT INTO `sql_updates` (`timestamp`) VALUES (1588301040);
diff --git a/sql-files/upgrades/index.txt b/sql-files/upgrades/index.txt
index fdd5fcc5a..64a7793f8 100644
--- a/sql-files/upgrades/index.txt
+++ b/sql-files/upgrades/index.txt
@@ -62,3 +62,4 @@
2020-01-24--01-09.sql
2020-03-22--01-56.sql
2020-03-22--03-09.sql
+2020-05-01--04-44.sql
diff --git a/src/char/char.c b/src/char/char.c
index 0406dbecf..c61b6107a 100644
--- a/src/char/char.c
+++ b/src/char/char.c
@@ -2902,13 +2902,13 @@ static void char_global_accreg_to_login_add(const char *key, unsigned int index,
if( val ) {
char *sval = (char*)val;
- len = strlen(sval)+1;
+ len = strlen(sval);
- WFIFOB(chr->login_fd, nlen) = (unsigned char)len;/* won't be higher; the column size is 254 */
+ WFIFOB(chr->login_fd, nlen) = (unsigned char)len; // Won't be higher; the column size is 255.
nlen += 1;
- safestrncpy(WFIFOP(chr->login_fd,nlen), sval, len);
- nlen += len;
+ safestrncpy(WFIFOP(chr->login_fd, nlen), sval, len + 1);
+ nlen += len + 1;
}
} else {
WFIFOB(chr->login_fd, nlen) = val ? 0 : 1;
diff --git a/src/char/inter.c b/src/char/inter.c
index 2d8d06a9c..5252b3315 100644
--- a/src/char/inter.c
+++ b/src/char/inter.c
@@ -676,13 +676,13 @@ static int inter_accreg_fromsql(int account_id, int char_id, int fd, int type)
plen += 4;
SQL->GetData(inter->sql_handle, 2, &data, NULL);
- len = strlen(data)+1;
+ len = strlen(data);
- WFIFOB(fd, plen) = (unsigned char)len;/* won't be higher; the column size is 254 */
+ WFIFOB(fd, plen) = (unsigned char)len; // Won't be higher; the column size is 255.
plen += 1;
- safestrncpy(WFIFOP(fd,plen), data, len);
- plen += len;
+ safestrncpy(WFIFOP(fd, plen), data, len + 1);
+ plen += len + 1;
WFIFOW(fd, 14) += 1;
diff --git a/src/char/mapif.c b/src/char/mapif.c
index 9077afae4..f0c886586 100644
--- a/src/char/mapif.c
+++ b/src/char/mapif.c
@@ -2030,7 +2030,8 @@ static int mapif_parse_Registry(int fd)
if (count != 0) {
int cursor = 14, i;
- char key[SCRIPT_VARNAME_LENGTH+1], sval[254];
+ char key[SCRIPT_VARNAME_LENGTH + 1];
+ char sval[SCRIPT_STRING_VAR_LENGTH + 1];
bool isLoginActive = sockt->session_is_active(chr->login_fd);
if (isLoginActive)
@@ -2057,8 +2058,8 @@ static int mapif_parse_Registry(int fd)
/* str */
case 2:
len = RFIFOB(fd, cursor);
- safestrncpy(sval, RFIFOP(fd, cursor + 1), min((int)sizeof(sval), len));
- cursor += len + 1;
+ safestrncpy(sval, RFIFOP(fd, cursor + 1), min((int)sizeof(sval), len + 1));
+ cursor += len + 2;
inter->savereg(account_id, char_id, key, index, (intptr_t)sval, true);
break;
case 3:
diff --git a/src/common/mmo.h b/src/common/mmo.h
index 9421f6e35..d2f3aa8f1 100644
--- a/src/common/mmo.h
+++ b/src/common/mmo.h
@@ -380,7 +380,10 @@ STATIC_ASSERT(MAX_ITEM_OPTIONS <= 5, "This value is limited by the client and da
#define JOBL_BABY 0x2000
#define JOBL_THIRD 0x4000
-#define SCRIPT_VARNAME_LENGTH 32 ///< Maximum length of a script variable
+#define SCRIPT_VARNAME_LENGTH 32 ///< Maximum length of a script variable's name including affixes and excluding NULL-terminator.
+STATIC_ASSERT(SCRIPT_VARNAME_LENGTH <= 32, "This value is limited by the inter-server communication and database layout and should only be increased if you know the consequences.");
+#define SCRIPT_STRING_VAR_LENGTH 255 ///< Maximum length of strings stored in script variables excluding NULL-terminator.
+STATIC_ASSERT(SCRIPT_STRING_VAR_LENGTH <= 255, "This value is limited by the inter-server communication and database layout and should only be increased if you know the consequences.");
#define INFINITE_DURATION (-1) // Infinite duration for status changes
diff --git a/src/login/account.c b/src/login/account.c
index 3632c257a..ec0bc81e8 100644
--- a/src/login/account.c
+++ b/src/login/account.c
@@ -632,7 +632,8 @@ static void account_mmo_save_accreg2(AccountDB *self, int fd, int account_id, in
sql_handle = db->accounts;
if (count) {
int cursor = 14, i;
- char key[SCRIPT_VARNAME_LENGTH+1], sval[254];
+ char key[SCRIPT_VARNAME_LENGTH + 1];
+ char sval[SCRIPT_STRING_VAR_LENGTH + 1];
for (i = 0; i < count; i++) {
unsigned int index;
@@ -657,8 +658,8 @@ static void account_mmo_save_accreg2(AccountDB *self, int fd, int account_id, in
/* str */
case 2:
len = RFIFOB(fd, cursor);
- safestrncpy(sval, RFIFOP(fd, cursor + 1), min((int)sizeof(sval), len));
- cursor += len + 1;
+ safestrncpy(sval, RFIFOP(fd, cursor + 1), min((int)sizeof(sval), len + 1));
+ cursor += len + 2;
if( SQL_ERROR == SQL->Query(sql_handle, "REPLACE INTO `%s` (`account_id`,`key`,`index`,`value`) VALUES ('%d','%s','%u','%s')", db->global_acc_reg_str_db, account_id, key, index, sval) )
Sql_ShowDebug(sql_handle);
break;
@@ -719,13 +720,13 @@ static void account_mmo_send_accreg2(AccountDB *self, int fd, int account_id, in
plen += 4;
SQL->GetData(sql_handle, 2, &data, NULL);
- len = strlen(data)+1;
+ len = strlen(data);
- WFIFOB(fd, plen) = (unsigned char)len;/* won't be higher; the column size is 254 */
+ WFIFOB(fd, plen) = (unsigned char)len; // Won't be higher; the column size is 255.
plen += 1;
- safestrncpy(WFIFOP(fd,plen), data, len);
- plen += len;
+ safestrncpy(WFIFOP(fd, plen), data, len + 1);
+ plen += len + 1;
WFIFOW(fd, 14) += 1;
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index 3fe6c8581..54cc9e2c9 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -8916,13 +8916,17 @@ ACMD(accinfo)
/* [Ind] */
ACMD(set)
{
- char reg[SCRIPT_VARNAME_LENGTH+1], val[254];
+ char reg[SCRIPT_VARNAME_LENGTH + 1];
+ char val[SCRIPT_STRING_VAR_LENGTH + 1];
struct script_data* data;
int toset = 0;
bool is_str = false;
size_t len;
- if (!*message || (toset = sscanf(message, "%32s %253[^\n]", reg, val)) < 1) {
+ char format[20];
+ safesnprintf(format, sizeof(format), "%%%ds %%%d[^\\n]", SCRIPT_VARNAME_LENGTH, SCRIPT_STRING_VAR_LENGTH);
+
+ if (*message == '\0' || (toset = sscanf(message, format, reg, val)) < 1) {
clif->message(fd, msg_fd(fd,1367)); // Usage: @set <variable name> <value>
clif->message(fd, msg_fd(fd,1368)); // Usage: ex. "@set PoringCharVar 50"
clif->message(fd, msg_fd(fd,1369)); // Usage: ex. "@set PoringCharVarSTR$ Super Duper String"
diff --git a/src/map/clif.c b/src/map/clif.c
index 7be5c6978..ab13ffe1f 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -11794,7 +11794,7 @@ static void clif_parse_WisMessage(int fd, struct map_session_data *sd)
char *str = target + 4; // Skip the NPC: string part.
struct npc_data *nd;
if ((nd = npc->name2id(str))) {
- char split_data[NUM_WHISPER_VAR][CHAT_SIZE_MAX];
+ char split_data[NUM_WHISPER_VAR][SCRIPT_STRING_VAR_LENGTH + 1];
char *split;
char output[256];
diff --git a/src/map/intif.c b/src/map/intif.c
index a420b7204..276b40780 100644
--- a/src/map/intif.c
+++ b/src/map/intif.c
@@ -218,13 +218,13 @@ static int intif_saveregistry(struct map_session_data *sd)
plen += 1;
if( p->value ) {
- len = strlen(p->value)+1;
+ len = strlen(p->value);
- WFIFOB(inter_fd, plen) = (unsigned char)len;/* won't be higher; the column size is 254 */
+ WFIFOB(inter_fd, plen) = (unsigned char)len; // Won't be higher; the column size is 255.
plen += 1;
- safestrncpy(WFIFOP(inter_fd,plen), p->value, len);
- plen += len;
+ safestrncpy(WFIFOP(inter_fd, plen), p->value, len + 1);
+ plen += len + 1;
} else {
script->reg_destroy_single(sd,key.i64,&p->flag);
}
@@ -1025,7 +1025,7 @@ static void intif_parse_Registers(int fd)
* { keyLength(B), key(<keyLength>), index(L), valLength(B), val(<valLength>) }
**/
if (type) {
- char sval[254];
+ char sval[SCRIPT_STRING_VAR_LENGTH + 1];
for (i = 0; i < max; i++) {
int len = RFIFOB(fd, cursor);
safestrncpy(key, RFIFOP(fd, cursor + 1), min((int)sizeof(key), len));
@@ -1035,8 +1035,8 @@ static void intif_parse_Registers(int fd)
cursor += 4;
len = RFIFOB(fd, cursor);
- safestrncpy(sval, RFIFOP(fd, cursor + 1), min((int)sizeof(sval), len));
- cursor += len + 1;
+ safestrncpy(sval, RFIFOP(fd, cursor + 1), min((int)sizeof(sval), len + 1));
+ cursor += len + 2;
script->set_reg(NULL,sd,reference_uid(script->add_variable(key), index), key, sval, NULL);
}
diff --git a/src/map/map.h b/src/map/map.h
index 64736a6f5..17f210bc3 100644
--- a/src/map/map.h
+++ b/src/map/map.h
@@ -329,6 +329,14 @@ enum bl_type {
enum npc_subtype { WARP, SHOP, SCRIPT, CASHSHOP, TOMB };
+/** optional flags for script labels, used by the label db */
+enum script_label_flags {
+ /** the label can be called from outside the local scope of the NPC */
+ LABEL_IS_EXTERN = 0x1,
+ /** the label is a public or private local NPC function */
+ LABEL_IS_USERFUNC = 0x2,
+};
+
/**
* Race type IDs.
*
diff --git a/src/map/mapreg_sql.c b/src/map/mapreg_sql.c
index 741505e17..2963637da 100644
--- a/src/map/mapreg_sql.c
+++ b/src/map/mapreg_sql.c
@@ -176,9 +176,9 @@ static bool mapreg_setregstr(int64 uid, const char *str)
if(name[1] != '@' && !mapreg->skip_insert) { //put returned null, so we must insert.
char tmp_str[(SCRIPT_VARNAME_LENGTH+1)*2+1];
- char tmp_str2[255*2+1];
+ char tmp_str2[SCRIPT_STRING_VAR_LENGTH * 2 + 1];
SQL->EscapeStringLen(map->mysql_handle, tmp_str, name, strnlen(name, SCRIPT_VARNAME_LENGTH+1));
- SQL->EscapeStringLen(map->mysql_handle, tmp_str2, str, strnlen(str, 255));
+ SQL->EscapeStringLen(map->mysql_handle, tmp_str2, str, strnlen(str, SCRIPT_STRING_VAR_LENGTH));
if( SQL_ERROR == SQL->Query(map->mysql_handle, "INSERT INTO `%s`(`varname`,`index`,`value`) VALUES ('%s','%u','%s')", mapreg->table, tmp_str, i, tmp_str2) )
Sql_ShowDebug(map->mysql_handle);
}
@@ -203,7 +203,7 @@ static void script_load_mapreg(void)
struct SqlStmt *stmt = SQL->StmtMalloc(map->mysql_handle);
char varname[SCRIPT_VARNAME_LENGTH+1];
int index;
- char value[255+1];
+ char value[SCRIPT_STRING_VAR_LENGTH + 1];
uint32 length;
if ( SQL_ERROR == SQL->StmtPrepare(stmt, "SELECT `varname`, `index`, `value` FROM `%s`", mapreg->table)
@@ -261,8 +261,8 @@ static void script_save_mapreg(void)
if( SQL_ERROR == SQL->Query(map->mysql_handle, "UPDATE `%s` SET `value`='%d' WHERE `varname`='%s' AND `index`='%d' LIMIT 1", mapreg->table, m->u.i, name, i) )
Sql_ShowDebug(map->mysql_handle);
} else {
- char tmp_str2[2*255+1];
- SQL->EscapeStringLen(map->mysql_handle, tmp_str2, m->u.str, safestrnlen(m->u.str, 255));
+ char tmp_str2[SCRIPT_STRING_VAR_LENGTH * 2 + 1];
+ SQL->EscapeStringLen(map->mysql_handle, tmp_str2, m->u.str, safestrnlen(m->u.str, SCRIPT_STRING_VAR_LENGTH));
if( SQL_ERROR == SQL->Query(map->mysql_handle, "UPDATE `%s` SET `value`='%s' WHERE `varname`='%s' AND `index`='%d' LIMIT 1", mapreg->table, tmp_str2, name, i) )
Sql_ShowDebug(map->mysql_handle);
}
diff --git a/src/map/npc.c b/src/map/npc.c
index 40ec380ee..2f03623e4 100644
--- a/src/map/npc.c
+++ b/src/map/npc.c
@@ -389,7 +389,10 @@ static int npc_event_export(struct npc_data *nd, int i)
Assert_ret(i >= 0 && i < nd->u.scr.label_list_num);
lname = nd->u.scr.label_list[i].name;
pos = nd->u.scr.label_list[i].pos;
- if ((lname[0] == 'O' || lname[0] == 'o') && (lname[1] == 'N' || lname[1] == 'n')) {
+
+ if ((nd->u.scr.label_list[i].flags & LABEL_IS_EXTERN) != 0
+ && ((nd->u.scr.label_list[i].flags & LABEL_IS_USERFUNC) == 0
+ || script->config.functions_as_events)) {
struct event_data *ev;
struct linkdb_node **label_linkdb = NULL;
char buf[EVENT_NAME_LENGTH];
@@ -3054,11 +3057,11 @@ static int npc_unload(struct npc_data *nd, bool single, bool unload_mobs)
aFree(nd->u.shop.shop_item); /// src check for duplicate shops. [Orcao]
} else if (nd->subtype == SCRIPT) {
char evname[EVENT_NAME_LENGTH];
-
+
snprintf(evname, ARRAYLENGTH(evname), "%s::OnNPCUnload", nd->exname);
struct event_data *ev = strdb_get(npc->ev_db, evname);
-
+
if (ev != NULL)
script->run_npc(nd->u.scr.script, ev->pos, 0, nd->bl.id); /// Run OnNPCUnload.
@@ -3665,6 +3668,7 @@ static void npc_convertlabel_db(struct npc_label_list *label_list, const char *f
for( i = 0; i < script->label_count; i++ ) {
const char* lname = script->get_str(script->labels[i].key);
int lpos = script->labels[i].pos;
+ enum script_label_flags flags = script->labels[i].flags;
struct npc_label_list* label;
const char *p;
size_t len;
@@ -3686,6 +3690,7 @@ static void npc_convertlabel_db(struct npc_label_list *label_list, const char *f
safestrncpy(label->name, lname, sizeof(label->name));
label->pos = lpos;
+ label->flags = flags;
}
}
@@ -5606,7 +5611,7 @@ static int npc_reload(void)
npc->npc_last_npd = NULL;
npc->npc_last_path = NULL;
npc->npc_last_ref = NULL;
-
+
const int npc_new_min = npc->npc_id;
struct s_mapiterator *iter = mapit_geteachiddb();
diff --git a/src/map/npc.h b/src/map/npc.h
index 1585a2bc8..16d7a984b 100644
--- a/src/map/npc.h
+++ b/src/map/npc.h
@@ -56,9 +56,15 @@ enum npc_shop_types {
struct npc_timerevent_list {
int timer,pos;
};
+
+/** list of labels within a NPC (used internally by the label db) */
struct npc_label_list {
+ /** label name */
char name[NAME_LENGTH];
+ /** start point within the script */
int pos;
+ /** optional label flags */
+ enum script_label_flags flags;
};
struct npc_barter_currency {
diff --git a/src/map/npc_chat.c b/src/map/npc_chat.c
index 0ca84cff4..0df323e96 100644
--- a/src/map/npc_chat.c
+++ b/src/map/npc_chat.c
@@ -394,7 +394,8 @@ static int npc_chat_sub(struct block_list *bl, va_list ap)
// save out the matched strings
for (i = 0; i < r; i++)
{
- char var[15], val[255];
+ char var[SCRIPT_VARNAME_LENGTH + 1];
+ char val[SCRIPT_STRING_VAR_LENGTH + 1];
snprintf(var, sizeof(var), "$@p%i$", i);
libpcre->copy_substring(msg, offsets, r, i, val, sizeof(val));
script->set_var(sd, var, val);
diff --git a/src/map/script.c b/src/map/script.c
index 45c954dc0..0fd8bda2a 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -848,79 +848,134 @@ static const char *parse_callfunc(const char *p, int require_paren, int is_custo
nullpo_retr(NULL, p);
// is need add check for arg null pointer below?
- func = script->add_word(p);
- if (script->str_data[func].type == C_FUNC) {
- script->syntax.nested_call++;
- if (script->syntax.last_func != -1) {
- if (script->str_data[func].val == script->buildin_lang_macro_offset) {
- script->syntax.lang_macro_active = true;
- macro = true;
- } else if (script->str_data[func].val == script->buildin_lang_macro_fmtstring_offset) {
- script->syntax.lang_macro_fmtstring_active = true;
- macro = true;
- }
+
+ if (*p == '"') {
+ p2 = ++p; // jump to the start of the word
+
+ // find the closing quote
+ while (*p2 != '"') {
+ ++p2;
}
- if( !macro ) {
- // buildin function
+ if (p2[1] == ':' && p2[2] == ':') {
+ func = script->add_str("callfunctionofnpc");
+ arg = "*"; // we already take care of the "vs" part of "vs*"
+
+ script->syntax.nested_call++;
script->syntax.last_func = script->str_data[func].val;
script->addl(func);
script->addc(C_ARG);
- }
- arg = script->buildin[script->str_data[func].val];
- if (script->str_data[func].deprecated)
- DeprecationWarning(p);
- if( !arg ) arg = &null_arg; // Use a dummy, null string
- } else if( script->str_data[func].type == C_USERFUNC || script->str_data[func].type == C_USERFUNC_POS ) {
- // script defined function
- script->addl(script->buildin_callsub_ref);
- script->addc(C_ARG);
- script->addl(func);
- arg = script->buildin[script->str_data[script->buildin_callsub_ref].val];
- if( *arg == 0 )
- disp_error_message("parse_callfunc: callsub has no arguments, please review its definition",p);
- if( *arg != '*' )
- ++arg; // count func as argument
+ script->addc(C_STR);
+ do {
+ script->addb(*p++); // npc name
+ } while (p < p2);
+ script->addb(0);
+
+ p = p2 + 3; // skip to start of func name
+ p2 = script->skip_word(p);
+
+ script->addc(C_STR);
+ do {
+ script->addb(*p++); // func name
+ } while (p < p2);
+ script->addb(0);
+
+ p = p2; // skip to just before the ()
+ } else {
+ disp_error_message("script:parse_callfunc: invalid public function call syntax!", p2 + 1);
+ }
} else {
+ func = script->add_word(p);
+ if (script->str_data[func].type == C_FUNC) {
+ script->syntax.nested_call++;
+
+ if (script->syntax.last_func != -1) {
+ if (script->str_data[func].val == script->buildin_lang_macro_offset) {
+ script->syntax.lang_macro_active = true;
+ macro = true;
+ } else if (script->str_data[func].val == script->buildin_lang_macro_fmtstring_offset) {
+ script->syntax.lang_macro_fmtstring_active = true;
+ macro = true;
+ }
+ }
+
+ if (!macro) {
+ // buildin function
+ script->syntax.last_func = script->str_data[func].val;
+ script->addl(func);
+ script->addc(C_ARG);
+ }
+
+ arg = script->buildin[script->str_data[func].val];
+
+ if (script->str_data[func].deprecated == 1) {
+ DeprecationWarning(p);
+ }
+
+ if (arg == NULL) {
+ arg = &null_arg; // Use a dummy, null string
+ }
+ } else if (script->str_data[func].type == C_USERFUNC || script->str_data[func].type == C_USERFUNC_POS) {
+ // script defined function
+ script->addl(script->buildin_callsub_ref);
+ script->addc(C_ARG);
+ script->addl(func);
+ arg = script->buildin[script->str_data[script->buildin_callsub_ref].val];
+
+ if (*arg == 0) {
+ disp_error_message("script:parse_callfunc: callsub has no arguments, please review its definition", p);
+ }
+
+ if (*arg != '*') {
+ ++arg; // count func as argument
+ }
+ } else {
#ifdef SCRIPT_CALLFUNC_CHECK
- const char* name = script->get_str(func);
- if( !is_custom && strdb_get(script->userfunc_db, name) == NULL ) {
+ const char *name = script->get_str(func);
+ if (is_custom == 0 && strdb_get(script->userfunc_db, name) == NULL) {
#endif
- disp_error_message("parse_line: expect command, missing function name or calling undeclared function",p);
+ disp_error_message("script:parse_callfunc: expect command, missing function name or calling undeclared function", p);
#ifdef SCRIPT_CALLFUNC_CHECK
- } else {;
- script->addl(script->buildin_callfunc_ref);
- script->addc(C_ARG);
- script->addc(C_STR);
- while( *name ) script->addb(*name ++);
- script->addb(0);
- arg = script->buildin[script->str_data[script->buildin_callfunc_ref].val];
- if( *arg != '*' ) ++ arg;
- }
+ } else {
+ script->addl(script->buildin_callfunc_ref);
+ script->addc(C_ARG);
+ script->addc(C_STR);
+
+ while (*name != '\0') {
+ script->addb(*name++);
+ }
+
+ script->addb(0);
+ arg = script->buildin[script->str_data[script->buildin_callfunc_ref].val];
+
+ if (*arg != '*') {
+ ++ arg;
+ }
+ }
#endif
+ }
}
p = script->skip_word(p);
p = script->skip_space(p);
script->syntax.curly[script->syntax.curly_count].type = TYPE_ARGLIST;
script->syntax.curly[script->syntax.curly_count].count = 0;
- if( *p == ';' )
- {// <func name> ';'
+
+ if (*p == ';') {
+ // <func name> ';'
script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_NO_PAREN;
- } else if( *p == '(' && *(p2=script->skip_space(p+1)) == ')' )
- {// <func name> '(' ')'
+ } else if (*p == '(' && *(p2 = script->skip_space(p + 1)) == ')') {
+ // <func name> '(' ')'
script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_PAREN;
p = p2;
- /*
- } else if( 0 && require_paren && *p != '(' )
- {// <func name>
- script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_NO_PAREN;
- */
- } else {// <func name> <arg list>
- if( require_paren ) {
- if( *p != '(' )
- disp_error_message("need '('",p);
+ } else {
+ // <func name> <arg list>
+ if (require_paren == 1) {
+ if (*p != '(') {
+ disp_error_message("script:parse_callfunc: need '('", p);
+ }
+
++p; // skip '('
script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_PAREN;
} else if( *p == '(' ) {
@@ -928,41 +983,65 @@ static const char *parse_callfunc(const char *p, int require_paren, int is_custo
} else {
script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_NO_PAREN;
}
+
++script->syntax.curly_count;
- while( *arg ) {
- p2=script->parse_subexpr(p,-1);
- if( p == p2 )
- break; // not an argument
- if( *arg != '*' )
- ++arg; // next argument
- p=script->skip_space(p2);
- if( *arg == 0 || *p != ',' )
- break; // no more arguments
+ while (*arg != '\0') {
+ p2 = script->parse_subexpr(p, -1);
+
+ if (p == p2) {
+ // not an argument
+ break;
+ }
+
+ if (*arg != '*') {
+ // next argument
+ ++arg;
+ }
+
+ p = script->skip_space(p2);
+
+ if (*arg == 0 || *p != ',') {
+ // no more arguments
+ break;
+ }
+
++p; // skip comma
}
+
--script->syntax.curly_count;
}
- if( arg && *arg && *arg != '?' && *arg != '*' )
- disp_error_message2("parse_callfunc: not enough arguments, expected ','", p, script->config.warn_func_mismatch_paramnum);
- if( script->syntax.curly[script->syntax.curly_count].type != TYPE_ARGLIST )
- disp_error_message("parse_callfunc: DEBUG last curly is not an argument list",p);
- if( script->syntax.curly[script->syntax.curly_count].flag == ARGLIST_PAREN ) {
- if( *p != ')' )
- disp_error_message("parse_callfunc: expected ')' to close argument list",p);
+
+ if (arg != NULL && *arg != '\0' && *arg != '?' && *arg != '*') {
+ disp_error_message2("script:parse_callfunc: not enough arguments, expected ','", p, script->config.warn_func_mismatch_paramnum);
+ }
+
+ if (script->syntax.curly[script->syntax.curly_count].type != TYPE_ARGLIST) {
+ disp_error_message("parse_callfunc: DEBUG last curly is not an argument list", p);
+ }
+
+ if (script->syntax.curly[script->syntax.curly_count].flag == ARGLIST_PAREN) {
+ if (*p != ')') {
+ disp_error_message("script:parse_callfunc: expected ')' to close argument list", p);
+ }
+
++p;
- if (script->str_data[func].val == script->buildin_lang_macro_offset)
+ if (script->str_data[func].val == script->buildin_lang_macro_offset) {
script->syntax.lang_macro_active = false;
- else if (script->str_data[func].val == script->buildin_lang_macro_fmtstring_offset)
+ } else if (script->str_data[func].val == script->buildin_lang_macro_fmtstring_offset) {
script->syntax.lang_macro_fmtstring_active = false;
+ }
}
if (!macro) {
- if (0 == --script->syntax.nested_call)
+ if (0 == --script->syntax.nested_call) {
script->syntax.last_func = -1;
+ }
+
script->addc(C_FUNC);
}
+
return p;
}
@@ -1230,16 +1309,29 @@ static int script_string_dup(char *str)
*------------------------------------------*/
static const char *parse_simpleexpr(const char *p)
{
- p=script->skip_space(p);
+ p = script->skip_space(p);
nullpo_retr(NULL, p);
- if (*p == ';' || *p == ',')
- disp_error_message("parse_simpleexpr: unexpected end of expression",p);
+
+ if (*p == ';' || *p == ',') {
+ disp_error_message("script:parse_simpleexpr: unexpected end of expression", p);
+ }
+
if (*p == '(') {
return script->parse_simpleexpr_paren(p);
} else if (is_number(p)) {
return script->parse_simpleexpr_number(p);
} else if(*p == '"') {
+ const char *p2 = p + 1;
+
+ while (*p2 != '"') {
+ ++p2;
+ }
+
+ if (p2[1] == ':' && p2[2] == ':') {
+ return script->parse_callfunc(p, 1, 0); // XXX: why does callfunc use int for booleans?
+ }
+
return script->parse_simpleexpr_string(p);
} else {
return script->parse_simpleexpr_name(p);
@@ -1577,6 +1669,85 @@ static const char *parse_line(const char *p)
return p;
}
+/**
+ * parses a local function expression
+ *
+ * expects these formats:
+ * function <name>;
+ * function <name> { <script> }
+ *
+ * this is invoked by script->parse_syntax() after checking whether the function
+ * is public or not
+ *
+ * @param p - a pointer to the start of the function expression
+ * @param is_public - whether this function should be accessible from outside the NPC scope
+ */
+static const char *parse_syntax_function (const char *p, bool is_public)
+{
+ const char *func_name = script->skip_space(p); // the name of the local function
+ p = script->skip_word(func_name);
+
+ if (p == func_name) {
+ disp_error_message("script:parse_syntax_function: function name is missing or invalid", p);
+ }
+
+ const char *p2 = script->skip_space(p);
+
+ if (*p2 == ';') {
+ // function <name> ;
+ // function declaration - just register the name
+ int l = script->add_word(func_name);
+
+ if (script->str_data[l].type == C_NOP) {
+ // register only, if the name was not used by something else
+ script->str_data[l].type = C_USERFUNC;
+ } else if (script->str_data[l].type != C_USERFUNC) {
+ disp_error_message("script:parse_syntax_function: function name is already in use", func_name);
+ }
+
+ // Close condition of if, for, while
+ p = script->parse_syntax_close(p2 + 1);
+ return p;
+ } else if (*p2 == '{') {
+ // function <name> <line/block of code>
+ script->syntax.curly[script->syntax.curly_count].type = TYPE_USERFUNC;
+ script->syntax.curly[script->syntax.curly_count].count = 1;
+ script->syntax.curly[script->syntax.curly_count].index = script->syntax.index++;
+ script->syntax.curly[script->syntax.curly_count].flag = 0;
+ ++script->syntax.curly_count;
+
+ // Jump over the function code
+ char label[256];
+ sprintf(label, "goto __FN%x_FIN;", (unsigned int)script->syntax.curly[script->syntax.curly_count - 1].index);
+ script->syntax.curly[script->syntax.curly_count].type = TYPE_NULL;
+ ++script->syntax.curly_count;
+ script->parse_line(label);
+ --script->syntax.curly_count;
+
+ // Set the position of the function (label)
+ int l = script->add_word(func_name);
+
+ if (script->str_data[l].type == C_NOP || script->str_data[l].type == C_USERFUNC) {
+ // register only, if the name was not used by something else
+ script->str_data[l].type = C_USERFUNC;
+ script->set_label(l, VECTOR_LENGTH(script->buf), p);
+
+ if ((script->parse_options & SCRIPT_USE_LABEL_DB) != 0) {
+ script->label_add(l, VECTOR_LENGTH(script->buf),
+ LABEL_IS_USERFUNC | (is_public ? LABEL_IS_EXTERN : 0));
+ }
+ } else {
+ disp_error_message("script:parse_syntax_function: function name is already in use", func_name);
+ }
+
+ return script->skip_space(p);
+ } else {
+ disp_error_message("script:parse_syntax_function: expected ';' or '{' at function syntax", p);
+ }
+
+ return p;
+}
+
// { ... } Closing process
static const char *parse_curly_close(const char *p)
{
@@ -1920,65 +2091,11 @@ static const char *parse_syntax(const char *p)
script->set_label(l, VECTOR_LENGTH(script->buf), p);
return p;
} else if( p2 - p == 8 && strncmp(p, "function", 8) == 0 ) {
- // internal script function
- const char *func_name;
-
- func_name = script->skip_space(p2);
- p = script->skip_word(func_name);
- if( p == func_name )
- disp_error_message("parse_syntax:function: function name is missing or invalid", p);
- p2 = script->skip_space(p);
- if( *p2 == ';' )
- {// function <name> ;
- // function declaration - just register the name
- int l;
- l = script->add_word(func_name);
- if( script->str_data[l].type == C_NOP )// register only, if the name was not used by something else
- script->str_data[l].type = C_USERFUNC;
- else if( script->str_data[l].type == C_USERFUNC )
- ; // already registered
- else
- disp_error_message("parse_syntax:function: function name is invalid", func_name);
-
- // Close condition of if, for, while
- p = script->parse_syntax_close(p2 + 1);
- return p;
- }
- else if(*p2 == '{')
- {// function <name> <line/block of code>
- char label[256];
- int l;
-
- script->syntax.curly[script->syntax.curly_count].type = TYPE_USERFUNC;
- script->syntax.curly[script->syntax.curly_count].count = 1;
- script->syntax.curly[script->syntax.curly_count].index = script->syntax.index++;
- script->syntax.curly[script->syntax.curly_count].flag = 0;
- ++script->syntax.curly_count;
-
- // Jump over the function code
- sprintf(label, "goto __FN%x_FIN;", (unsigned int)script->syntax.curly[script->syntax.curly_count-1].index);
- script->syntax.curly[script->syntax.curly_count].type = TYPE_NULL;
- ++script->syntax.curly_count;
- script->parse_line(label);
- --script->syntax.curly_count;
-
- // Set the position of the function (label)
- l=script->add_word(func_name);
- if( script->str_data[l].type == C_NOP || script->str_data[l].type == C_USERFUNC )// register only, if the name was not used by something else
- {
- script->str_data[l].type = C_USERFUNC;
- script->set_label(l, VECTOR_LENGTH(script->buf), p);
- if( script->parse_options&SCRIPT_USE_LABEL_DB )
- script->label_add(l, VECTOR_LENGTH(script->buf));
- }
- else
- disp_error_message("parse_syntax:function: function name is invalid", func_name);
-
- return script->skip_space(p);
- }
- else
- {
- disp_error_message("expect ';' or '{' at function syntax",p);
+ // local function not marked as public or private
+ if (script->config.functions_private_by_default) {
+ return script->parse_syntax_function(p2, false);
+ } else {
+ return script->parse_syntax_function(p2, true);
}
}
break;
@@ -2006,6 +2123,26 @@ static const char *parse_syntax(const char *p)
return p;
}
break;
+ case 'p':
+ case 'P':
+ if (p2 - p == 6 && strncmp(p, "public", 6) == 0) {
+ p2 = script->skip_space(p2);
+ const char *p3 = script->skip_word(p2);
+
+ if (p3 - p2 == 8 && strncmp(p2, "function", 8) == 0) {
+ // local function explicitly marked as public
+ return script->parse_syntax_function(p3, true);
+ }
+ } else if (p2 - p == 7 && strncmp(p, "private", 7) == 0) {
+ p2 = script->skip_space(p2);
+ const char *p3 = script->skip_word(p2);
+
+ if (p3 - p2 == 8 && strncmp(p2, "function", 8) == 0) {
+ // local function explicitly marked as private
+ return script->parse_syntax_function(p3, false);
+ }
+ }
+ break;
case 's':
case 'S':
if( p2 - p == 6 && strncmp(p, "switch", 6) == 0 ) {
@@ -2668,25 +2805,32 @@ static struct script_code *parse_script(const char *src, const char *file, int l
}
}
- while( script->syntax.curly_count != 0 || *p != end )
- {
- if( *p == '\0' )
- disp_error_message("unexpected end of script",p);
+ while (script->syntax.curly_count != 0 || *p != end) {
+ if (*p == '\0') {
+ disp_error_message("script:parse_script: unexpected end of script", p);
+ }
+
// Special handling only label
- tmpp=script->skip_space(script->skip_word(p));
- if(*tmpp==':' && !(strncmp(p,"default:",8) == 0 && p + 7 == tmpp)) {
- i=script->add_word(p);
+ tmpp = script->skip_space(script->skip_word(p));
+
+ if (*tmpp == ':' && !(strncmp(p, "default:", 8) == 0 && p + 7 == tmpp)
+ && !(strncmp(p, "function", 8) == 0 && script->skip_space(p + 8) == tmpp)) {
+ i = script->add_word(p);
script->set_label(i, VECTOR_LENGTH(script->buf), p);
- if( script->parse_options&SCRIPT_USE_LABEL_DB )
- script->label_add(i, VECTOR_LENGTH(script->buf));
- p=tmpp+1;
- p=script->skip_space(p);
+
+ if ((script->parse_options & SCRIPT_USE_LABEL_DB) != 0) {
+ bool is_extern = ((p[0] == 'O' || p[0] == 'o') && (p[1] == 'N' || p[1] == 'n'));
+ script->label_add(i, VECTOR_LENGTH(script->buf), is_extern ? LABEL_IS_EXTERN : 0);
+ }
+
+ p = tmpp + 1;
+ p = script->skip_space(p);
continue;
}
// All other lumped
- p=script->parse_line(p);
- p=script->skip_space(p);
+ p = script->parse_line(p);
+ p = script->skip_space(p);
script->parse_nextline(false, p);
}
@@ -3395,6 +3539,32 @@ static void set_reg_instance_num(struct script_state *st, int64 num, const char
}
/**
+ * Validates if a variable is permanent (stored in database) by passed variable name.
+ *
+ * @param name The variable name to validate.
+ * @return True if variable is permanent, otherwise false.
+ *
+ **/
+static bool script_is_permanent_variable(const char *name)
+{
+ nullpo_retr(false, name);
+
+ if (strlen(name) == 0)
+ return false;
+
+ if (ISALNUM(name[0]) != 0)
+ return true; // Permanent characater variable.
+
+ if (name[0] == '#')
+ return true; // Permanent (global) account variable.
+
+ if (strlen(name) > 1 && name[0] == '$' && ISALNUM(name[1]) != 0)
+ return true; // Permanent server variable.
+
+ return false;
+}
+
+/**
* Stores the value of a script variable
*
* @param st current script state.
@@ -3439,6 +3609,18 @@ static int set_reg(struct script_state *st, struct map_session_data *sd, int64 n
if (is_string_variable(name)) {// string variable
const char *str = (const char*)value;
+ if (script->is_permanent_variable(name) && strlen(str) > SCRIPT_STRING_VAR_LENGTH) {
+ ShowError("script:set_reg: Value of variable %s is too long: %lu! Maximum is %d. Skipping...\n",
+ name, strlen(str), SCRIPT_STRING_VAR_LENGTH);
+
+ if (st != NULL) {
+ script->reportsrc(st);
+ st->state = END;
+ }
+
+ return 0;
+ }
+
switch (prefix) {
case '@':
if (ref) {
@@ -4828,6 +5010,8 @@ static bool script_config_read(const char *filename, bool imported)
libconfig->setting_lookup_bool_real(setting, "warn_func_mismatch_paramnum", &script->config.warn_func_mismatch_paramnum);
libconfig->setting_lookup_bool_real(setting, "warn_func_mismatch_argtypes", &script->config.warn_func_mismatch_argtypes);
+ libconfig->setting_lookup_bool_real(setting, "functions_private_by_default", &script->config.functions_private_by_default);
+ libconfig->setting_lookup_bool_real(setting, "functions_as_events", &script->config.functions_as_events);
libconfig->setting_lookup_int(setting, "check_cmdcount", &script->config.check_cmdcount);
libconfig->setting_lookup_int(setting, "check_gotocount", &script->config.check_gotocount);
libconfig->setting_lookup_int(setting, "input_min_value", &script->config.input_min_value);
@@ -6397,6 +6581,111 @@ static BUILDIN(callfunc)
return true;
}
+
+/**
+ * Calls a local function within a NPC as if it was part of the current scope.
+ * Resumes execution in the previous scope once the NPC function returns. This
+ * is essentially a clone of buildin_callsub that can run in arbitrary NPCs.
+ *
+ * Usage:
+ * callfunctionofnpc("<npc name>", "<function name>"{, <arg>...})
+ * callfunctionofnpc(<npc id>, "<function name>"{, <arg>...})
+ *
+ * This buildin is also used internally by this syntax:
+ * "<npc name>"::<function name>({<arg>...})
+ */
+static BUILDIN(callfunctionofnpc) {
+ struct npc_data *nd = NULL;
+
+ if (script_isstring(st, 2)) {
+ nd = npc->name2id(script_getstr(st, 2));
+ } else {
+ nd = map->id2nd(script_getnum(st, 2));
+ }
+
+ if (nd == NULL) {
+ ShowError("script:callfunctionofnpc: NPC not found.\n");
+ st->state = END;
+ return false;
+ }
+
+ const char *function_name = script_getstr(st, 3);
+ int pos = -1;
+
+ // find the function label within the label list of the NPC
+ for (int i = 0; i < nd->u.scr.label_list_num; ++i) {
+ if (strcmp(nd->u.scr.label_list[i].name, function_name) == 0) {
+ if ((nd->u.scr.label_list[i].flags & LABEL_IS_EXTERN) != 0
+ && (nd->u.scr.label_list[i].flags & LABEL_IS_USERFUNC) != 0) {
+ // function label found: set the start location
+ pos = nd->u.scr.label_list[i].pos;
+ } else if ((nd->u.scr.label_list[i].flags & LABEL_IS_USERFUNC) != 0) {
+ ShowError("script:callfunctionofnpc: function '%s' is not marked as public in NPC '%s'.\n", function_name, nd->name);
+ st->state = END;
+ return false;
+ }
+ break;
+ }
+ }
+
+ if (pos < 0) {
+ ShowError("script:callfunctionofnpc: function '%s' not found in NPC '%s'!\n", function_name, nd->name);
+ st->state = END;
+ return false;
+ }
+
+ // alloc a reg_db reference of the current scope for the new scope
+ struct reg_db *ref = (struct reg_db *)aCalloc(sizeof(struct reg_db), 2);
+ // scope variables (.@var)
+ ref[0].vars = st->stack->scope.vars;
+ ref[0].arrays = st->stack->scope.arrays;
+ // npc variables (.var)
+ ref[1].vars = st->script->local.vars;
+ ref[1].arrays = st->script->local.arrays;
+
+ int i = 0;
+
+ // make sure the arguments we push retain their current reg_db references:
+ // this allows to do things like set(getarg(0), ...)
+ for (i = st->start + 4; i < st->end; i++) {
+ struct script_data *data = script->push_copy(st->stack, i);
+
+ if (data_isreference(data) && data->ref == NULL) {
+ const char *name = reference_getname(data);
+
+ if (name[0] == '.') {
+ data->ref = (name[1] == '@' ? &ref[0] : &ref[1]);
+ }
+ }
+ }
+
+ // save the previous scope
+ struct script_retinfo *ri = NULL;
+ CREATE(ri, struct script_retinfo, 1);
+ ri->script = st->script; // script code
+ ri->scope.vars = st->stack->scope.vars; // scope variables
+ ri->scope.arrays = st->stack->scope.arrays; // scope arrays
+ ri->pos = st->pos; // script location
+ ri->nargs = i - st->start - 4; // argument count
+ ri->defsp = st->stack->defsp; // default stack pointer
+ script->push_retinfo(st->stack, ri, ref);
+
+ // change the current scope to the scope of the function
+ st->pos = pos;
+ st->script = nd->u.scr.script;
+ st->stack->defsp = st->stack->sp;
+ st->state = GOTO;
+ st->stack->scope.vars = i64db_alloc(DB_OPT_RELEASE_DATA);
+ st->stack->scope.arrays = idb_alloc(DB_OPT_BASE);
+
+ // make sure local reg_db of the other NPC is initialized
+ if (st->script->local.vars == NULL) {
+ st->script->local.vars = i64db_alloc(DB_OPT_RELEASE_DATA);
+ }
+
+ return true;
+}
+
/*==========================================
* subroutine call
*------------------------------------------*/
@@ -27390,6 +27679,8 @@ static void script_parse_builtin(void)
BUILDIN_DEF(identify, "i"),
BUILDIN_DEF(identifyidx, "i"),
BUILDIN_DEF(openlapineddukddakboxui, "i"),
+
+ BUILDIN_DEF(callfunctionofnpc, "vs*"),
};
int i, len = ARRAYLENGTH(BUILDIN);
RECREATE(script->buildin, char *, script->buildin_count + len); // Pre-alloc to speed up
@@ -27401,7 +27692,7 @@ static void script_parse_builtin(void)
#undef BUILDIN_DEF
#undef BUILDIN_DEF2
-static void script_label_add(int key, int pos)
+static void script_label_add(int key, int pos, enum script_label_flags flags)
{
int idx = script->label_count;
@@ -27412,6 +27703,7 @@ static void script_label_add(int key, int pos)
script->labels[idx].key = key;
script->labels[idx].pos = pos;
+ script->labels[idx].flags = flags;
script->label_count++;
}
@@ -28223,6 +28515,7 @@ void script_defaults(void)
script->parse_syntax_close = parse_syntax_close;
script->parse_syntax_close_sub = parse_syntax_close_sub;
script->parse_syntax = parse_syntax;
+ script->parse_syntax_function = parse_syntax_function;
script->get_com = get_com;
script->get_num = get_num;
script->op2name = script_op2name;
@@ -28255,6 +28548,7 @@ void script_defaults(void)
script->load_parameters = script_load_parameters;
script->print_line = script_print_line;
script->errorwarning_sub = script_errorwarning_sub;
+ script->is_permanent_variable = script_is_permanent_variable;
script->set_reg = set_reg;
script->set_reg_ref_str = set_reg_npcscope_str;
script->set_reg_pc_ref_str = set_reg_pc_ref_str;
@@ -28326,6 +28620,8 @@ void script_defaults(void)
script->config.ontouch_name = "OnTouch_"; //ontouch_name (runs on first visible char to enter area, picks another char if the first char leaves)
script->config.ontouch2_name = "OnTouch"; //ontouch2_name (run whenever a char walks into the OnTouch area)
script->config.onuntouch_name = "OnUnTouch"; //onuntouch_name (run whenever a char walks from the OnTouch area)
+ script->config.functions_private_by_default = true;
+ script->config.functions_as_events = false;
// for ENABLE_CASE_CHECK
script->calc_hash_ci = calc_hash_ci;
diff --git a/src/map/script.h b/src/map/script.h
index 511497a66..df5297ac0 100644
--- a/src/map/script.h
+++ b/src/map/script.h
@@ -584,6 +584,8 @@ enum itemskill_flag {
struct Script_Config {
bool warn_func_mismatch_argtypes;
bool warn_func_mismatch_paramnum;
+ bool functions_private_by_default;
+ bool functions_as_events;
int check_cmdcount;
int check_gotocount;
int input_min_value;
@@ -725,8 +727,14 @@ struct str_data_struct {
uint8 deprecated : 1;
};
+/** a label within a script (does not use the label db) */
struct script_label_entry {
- int key,pos;
+ /** label name (held within str_data) */
+ int key;
+ /** position within the script */
+ int pos;
+ /** optional flags for the label */
+ enum script_label_flags flags;
};
struct script_syntax_data {
@@ -917,7 +925,7 @@ struct script_interface {
void (*set_constant) (const char *name, int value, bool is_parameter, bool is_deprecated);
void (*set_constant2) (const char *name, int value, bool is_parameter, bool is_deprecated);
bool (*get_constant) (const char* name, int* value);
- void (*label_add)(int key, int pos);
+ void (*label_add)(int key, int pos, enum script_label_flags flags);
void (*run) (struct script_code *rootscript, int pos, int rid, int oid);
void (*run_npc) (struct script_code *rootscript, int pos, int rid, int oid);
void (*run_pet) (struct script_code *rootscript, int pos, int rid, int oid);
@@ -948,10 +956,11 @@ struct script_interface {
int (*queue_create) (void);
bool (*queue_clear) (int idx);
/* */
- const char * (*parse_curly_close) (const char *p);
- const char * (*parse_syntax_close) (const char *p);
- const char * (*parse_syntax_close_sub) (const char *p, int *flag);
- const char * (*parse_syntax) (const char *p);
+ const char *(*parse_curly_close) (const char *p);
+ const char *(*parse_syntax_close) (const char *p);
+ const char *(*parse_syntax_close_sub) (const char *p, int *flag);
+ const char *(*parse_syntax) (const char *p);
+ const char *(*parse_syntax_function) (const char *p, bool is_public);
c_op (*get_com) (const struct script_buf *scriptbuf, int *pos);
int (*get_num) (const struct script_buf *scriptbuf, int *pos);
const char* (*op2name) (int op);
@@ -984,6 +993,7 @@ struct script_interface {
void (*load_parameters) (void);
const char* (*print_line) (StringBuf *buf, const char *p, const char *mark, int line);
void (*errorwarning_sub) (StringBuf *buf, const char *src, const char *file, int start_line, const char *error_msg, const char *error_pos);
+ bool (*is_permanent_variable) (const char *name);
int (*set_reg) (struct script_state *st, struct map_session_data *sd, int64 num, const char *name, const void *value, struct reg_db *ref);
void (*set_reg_ref_str) (struct script_state* st, struct reg_db *n, int64 num, const char* name, const char *str);
void (*set_reg_pc_ref_str) (struct script_state* st, struct reg_db *n, int64 num, const char* name, const char *str);
diff --git a/src/map/status.c b/src/map/status.c
index 9a274c080..dc49f7e4e 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -866,6 +866,10 @@ static void initChangeTables(void)
status->dbs->ChangeFlagTable[SC_WEDDING] |= SCB_SPEED;
status->dbs->ChangeFlagTable[SC_ARMORPROPERTY] |= SCB_ALL;
status->dbs->ChangeFlagTable[SC_ARMOR_RESIST] |= SCB_ALL;
+ status->dbs->ChangeFlagTable[SC_RESIST_PROPERTY_WATER] |= SCB_ALL;
+ status->dbs->ChangeFlagTable[SC_RESIST_PROPERTY_GROUND] |= SCB_ALL;
+ status->dbs->ChangeFlagTable[SC_RESIST_PROPERTY_FIRE] |= SCB_ALL;
+ status->dbs->ChangeFlagTable[SC_RESIST_PROPERTY_WIND] |= SCB_ALL;
status->dbs->ChangeFlagTable[SC_ATKER_BLOOD] |= SCB_ALL;
status->dbs->ChangeFlagTable[SC_WALKSPEED] |= SCB_SPEED;
status->dbs->ChangeFlagTable[SC_TARGET_BLOOD] |= SCB_ALL;
@@ -3030,6 +3034,22 @@ static int status_calc_pc_(struct map_session_data *sd, enum e_status_calc_opt o
sd->subele[ELE_FIRE] += sc->data[SC_ARMOR_RESIST]->val3;
sd->subele[ELE_WIND] += sc->data[SC_ARMOR_RESIST]->val4;
}
+ if (sc->data[SC_RESIST_PROPERTY_WATER] != NULL) { // Coldproof Potion
+ sd->subele[ELE_WATER] += sc->data[SC_RESIST_PROPERTY_WATER]->val1;
+ sd->subele[ELE_WIND] += sc->data[SC_RESIST_PROPERTY_WATER]->val2;
+ }
+ if (sc->data[SC_RESIST_PROPERTY_GROUND] != NULL) { // Earthproof Potion
+ sd->subele[ELE_EARTH] += sc->data[SC_RESIST_PROPERTY_GROUND]->val1;
+ sd->subele[ELE_FIRE] += sc->data[SC_RESIST_PROPERTY_GROUND]->val2;
+ }
+ if (sc->data[SC_RESIST_PROPERTY_FIRE] != NULL) { // Fireproof Potion
+ sd->subele[ELE_FIRE] += sc->data[SC_RESIST_PROPERTY_FIRE]->val1;
+ sd->subele[ELE_WATER] += sc->data[SC_RESIST_PROPERTY_FIRE]->val2;
+ }
+ if (sc->data[SC_RESIST_PROPERTY_WIND] != NULL) { // Thunderproof Potion
+ sd->subele[ELE_WIND] += sc->data[SC_RESIST_PROPERTY_WIND]->val1;
+ sd->subele[ELE_EARTH] += sc->data[SC_RESIST_PROPERTY_WIND]->val2;
+ }
if (sc->data[SC_FIRE_CLOAK_OPTION]) {
i = sc->data[SC_FIRE_CLOAK_OPTION]->val2;
sd->subele[ELE_FIRE] += i;
@@ -7754,6 +7774,10 @@ static int status_change_start_sub(struct block_list *src, struct block_list *bl
case SC_ENCHANTARMS:
case SC_ARMORPROPERTY:
case SC_ARMOR_RESIST:
+ case SC_RESIST_PROPERTY_WATER:
+ case SC_RESIST_PROPERTY_GROUND:
+ case SC_RESIST_PROPERTY_FIRE:
+ case SC_RESIST_PROPERTY_WIND:
break;
case SC_GOSPEL:
//Must not override a casting gospel char.
@@ -8702,6 +8726,210 @@ static int status_change_start_sub(struct block_list *src, struct block_list *bl
//associated, and yet are not wrong/unknown. [Skotlex]
//break;
}
+ case SC_ARMOR_RESIST: {
+ struct status_change_entry *sce_water = sc->data[SC_RESIST_PROPERTY_WATER];
+ struct status_change_entry *sce_ground = sc->data[SC_RESIST_PROPERTY_GROUND];
+ struct status_change_entry *sce_fire = sc->data[SC_RESIST_PROPERTY_FIRE];
+ struct status_change_entry *sce_wind = sc->data[SC_RESIST_PROPERTY_WIND];
+
+ // Water
+ int sum_water = val1 + ((sce_fire != NULL) ? sce_fire->val2 : 0);
+ bool show_icon = true;
+ if (sce_water != NULL && sce_water->timer != INVALID_TIMER) {
+ const struct TimerData *td = timer->get(sce_water->timer);
+ if (td != NULL) {
+ sum_water += sce_water->val1;
+ int left = (int)DIFF_TICK(td->tick, timer->gettick());
+ if (left > total_tick && sum_water - val1 > 0)
+ show_icon = false;
+ }
+ }
+ if (val1 > 0 && sum_water > 0 && show_icon) {
+ int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WATER);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_WATER);
+ clif->status_change(bl, sc_icn, sc_typ, 1, total_tick, 0, 0, 0);
+ } else if (sum_water <= 0) {
+ clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_WATER));
+ }
+
+ // Ground
+ int sum_ground = val2 + ((sce_wind != NULL) ? sce_wind->val2 : 0);
+ show_icon = true;
+ if (sce_ground != NULL && sce_ground->timer != INVALID_TIMER) {
+ const struct TimerData *td = timer->get(sce_ground->timer);
+ if (td != NULL) {
+ sum_ground += sce_ground->val1;
+ int left = (int)DIFF_TICK(td->tick, timer->gettick());
+ if (left > total_tick && sum_ground - val2 > 0)
+ show_icon = false;
+ }
+ }
+ if (val2 > 0 && sum_ground > 0 && show_icon) {
+ int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_GROUND);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_GROUND);
+ clif->status_change(bl, sc_icn, sc_typ, 1, total_tick, 0, 0, 0);
+ } else if (sum_ground <= 0) {
+ clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_GROUND));
+ }
+
+ // Fire
+ int sum_fire = val3 + ((sce_ground != NULL) ? sce_ground->val2 : 0);
+ show_icon = true;
+ if (sce_fire != NULL && sce_fire->timer != INVALID_TIMER) {
+ const struct TimerData *td = timer->get(sce_fire->timer);
+ if (td != NULL) {
+ sum_fire += sce_fire->val1;
+ int left = (int)DIFF_TICK(td->tick, timer->gettick());
+ if (left > total_tick && sum_fire - val3 > 0)
+ show_icon = false;
+ }
+ }
+ if (val3 > 0 && sum_fire > 0 && show_icon) {
+ int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_FIRE);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_FIRE);
+ clif->status_change(bl, sc_icn, sc_typ, 1, total_tick, 0, 0, 0);
+ } else if (sum_fire <= 0) {
+ clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_FIRE));
+ }
+
+ // Wind
+ int sum_wind = val4 + ((sce_water != NULL) ? sce_water->val2 : 0);
+ show_icon = true;
+ if (sce_wind != NULL && sce_wind->timer != INVALID_TIMER) {
+ const struct TimerData *td = timer->get(sce_wind->timer);
+ if (td != NULL) {
+ sum_wind += sce_wind->val1;
+ int left = (int)DIFF_TICK(td->tick, timer->gettick());
+ if (left > total_tick && sum_wind - val4 > 0)
+ show_icon = false;
+ }
+ }
+ if (val4 > 0 && sum_wind > 0 && show_icon) {
+ int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WIND);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_WIND);
+ clif->status_change(bl, sc_icn, sc_typ, 1, total_tick, 0, 0, 0);
+ } else if (sum_wind <= 0) {
+ clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_WIND));
+ }
+
+ break;
+ }
+ case SC_RESIST_PROPERTY_WATER: {
+ struct status_change_entry *sce_all = sc->data[SC_ARMOR_RESIST];
+ struct status_change_entry *sce_fire = sc->data[SC_RESIST_PROPERTY_FIRE];
+ struct status_change_entry *sce_wind = sc->data[SC_RESIST_PROPERTY_WIND];
+
+ // Water
+ int sum_water = val1 + ((sce_fire != NULL) ? sce_fire->val2 : 0);
+ if (sce_all != NULL && sce_all->timer != INVALID_TIMER) {
+ const struct TimerData *td = timer->get(sce_all->timer);
+ if (td != NULL) {
+ sum_water += sce_all->val1;
+ int left = (int)DIFF_TICK(td->tick, timer->gettick());
+ if (left > total_tick && sum_water - val1 > 0)
+ flag |= SCFLAG_NOICON;
+ }
+ }
+ if (sum_water <= 0) {
+ clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_WATER));
+ flag |= SCFLAG_NOICON;
+ }
+
+ // Wind
+ int sum_wind = val2 + ((sce_wind != NULL) ? sce_wind->val1 : 0);
+ sum_wind += (sce_all != NULL) ? sce_all->val4 : 0;
+ if (sum_wind <= 0)
+ clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_WIND));
+
+ break;
+ }
+ case SC_RESIST_PROPERTY_GROUND: {
+ struct status_change_entry *sce_all = sc->data[SC_ARMOR_RESIST];
+ struct status_change_entry *sce_wind = sc->data[SC_RESIST_PROPERTY_WIND];
+ struct status_change_entry *sce_fire = sc->data[SC_RESIST_PROPERTY_FIRE];
+
+ // Ground
+ int sum_ground = val1 + ((sce_wind != NULL) ? sce_wind->val2 : 0);
+ if (sce_all != NULL && sce_all->timer != INVALID_TIMER) {
+ const struct TimerData *td = timer->get(sce_all->timer);
+ if (td != NULL) {
+ sum_ground += sce_all->val2;
+ int left = (int)DIFF_TICK(td->tick, timer->gettick());
+ if (left > total_tick && sum_ground - val1 > 0)
+ flag |= SCFLAG_NOICON;
+ }
+ }
+ if (sum_ground <= 0) {
+ clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_GROUND));
+ flag |= SCFLAG_NOICON;
+ }
+
+ // Fire
+ int sum_fire = val2 + ((sce_fire != NULL) ? sce_fire->val1 : 0);
+ sum_fire += (sce_all != NULL) ? sce_all->val3 : 0;
+ if (sum_fire <= 0)
+ clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_FIRE));
+
+ break;
+ }
+ case SC_RESIST_PROPERTY_FIRE: {
+ struct status_change_entry *sce_all = sc->data[SC_ARMOR_RESIST];
+ struct status_change_entry *sce_ground = sc->data[SC_RESIST_PROPERTY_GROUND];
+ struct status_change_entry *sce_water = sc->data[SC_RESIST_PROPERTY_WATER];
+
+ // Fire
+ int sum_fire = val1 + ((sce_ground != NULL) ? sce_ground->val2 : 0);
+ if (sce_all != NULL && sce_all->timer != INVALID_TIMER) {
+ const struct TimerData *td = timer->get(sce_all->timer);
+ if (td != NULL) {
+ sum_fire += sce_all->val3;
+ int left = (int)DIFF_TICK(td->tick, timer->gettick());
+ if (left > total_tick && sum_fire - val1 > 0)
+ flag |= SCFLAG_NOICON;
+ }
+ }
+ if (sum_fire <= 0) {
+ clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_FIRE));
+ flag |= SCFLAG_NOICON;
+ }
+
+ // Water
+ int sum_water = val2 + ((sce_water != NULL) ? sce_water->val1 : 0);
+ sum_water += (sce_all != NULL) ? sce_all->val1 : 0;
+ if (sum_water <= 0)
+ clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_WATER));
+
+ break;
+ }
+ case SC_RESIST_PROPERTY_WIND: {
+ struct status_change_entry *sce_all = sc->data[SC_ARMOR_RESIST];
+ struct status_change_entry *sce_water = sc->data[SC_RESIST_PROPERTY_WATER];
+ struct status_change_entry *sce_ground = sc->data[SC_RESIST_PROPERTY_GROUND];
+
+ // Wind
+ int sum_wind = val1 + ((sce_water != NULL) ? sce_water->val2 : 0);
+ if (sce_all != NULL && sce_all->timer != INVALID_TIMER) {
+ const struct TimerData *td = timer->get(sce_all->timer);
+ if (td != NULL) {
+ sum_wind += sce_all->val4;
+ int left = (int)DIFF_TICK(td->tick, timer->gettick());
+ if (left > total_tick && sum_wind - val1 > 0)
+ flag |= SCFLAG_NOICON;
+ }
+ }
+ if (sum_wind <= 0) {
+ clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_WIND));
+ flag |= SCFLAG_NOICON;
+ }
+
+ // Ground
+ int sum_ground = val2 + ((sce_ground != NULL) ? sce_ground->val1 : 0);
+ sum_ground += (sce_all != NULL) ? sce_all->val2 : 0;
+ if (sum_ground <= 0)
+ clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_GROUND));
+
+ break;
+ }
case SC_MER_FLEE:
case SC_MER_ATK:
case SC_MER_HIT:
@@ -10628,6 +10856,9 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid,
vd = status->get_viewdata(bl);
calc_flag = status->dbs->ChangeFlagTable[type];
+
+ bool remove_icon = true;
+
switch(type) {
case SC_GRANITIC_ARMOR:
{
@@ -11059,6 +11290,202 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid,
break;
}
break;
+ case SC_ARMOR_RESIST: {
+ struct status_change_entry *sce_water = sc->data[SC_RESIST_PROPERTY_WATER];
+ struct status_change_entry *sce_ground = sc->data[SC_RESIST_PROPERTY_GROUND];
+ struct status_change_entry *sce_fire = sc->data[SC_RESIST_PROPERTY_FIRE];
+ struct status_change_entry *sce_wind = sc->data[SC_RESIST_PROPERTY_WIND];
+
+ // Water
+ clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_WATER));
+ if (sce_water != NULL && sce_water->timer != INVALID_TIMER) {
+ int sum_water = sce_water->val1 + ((sce_fire != NULL) ? sce_fire->val2 : 0);
+ const struct TimerData *td = timer->get(sce_water->timer);
+ if (td != NULL && sce_water->val1 > 0 && sum_water > 0) {
+ int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WATER);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_WATER);
+ int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick());
+ int sc_ttl = sce_water->total_tick;
+ clif->status_change_sub(bl, sc_icn, sc_typ, 1, sc_tck, sc_ttl, 0, 0, 0);
+ }
+ }
+
+ // Ground
+ clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_GROUND));
+ if (sce_ground != NULL && sce_ground->timer != INVALID_TIMER) {
+ int sum_ground = sce_ground->val1 + ((sce_wind != NULL) ? sce_wind->val2 : 0);
+ const struct TimerData *td = timer->get(sce_ground->timer);
+ if (td != NULL && sce_ground->val1 > 0 && sum_ground > 0) {
+ int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_GROUND);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_GROUND);
+ int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick());
+ int sc_ttl = sce_ground->total_tick;
+ clif->status_change_sub(bl, sc_icn, sc_typ, 1, sc_tck, sc_ttl, 0, 0, 0);
+ }
+ }
+
+ // Fire
+ clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_FIRE));
+ if (sce_fire != NULL && sce_fire->timer != INVALID_TIMER) {
+ int sum_fire = sce_fire->val1 + ((sce_ground != NULL) ? sce_ground->val2 : 0);
+ const struct TimerData *td = timer->get(sce_fire->timer);
+ if (td != NULL && sce_fire->val1 > 0 && sum_fire > 0) {
+ int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_FIRE);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_FIRE);
+ int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick());
+ int sc_ttl = sce_fire->total_tick;
+ clif->status_change_sub(bl, sc_icn, sc_typ, 1, sc_tck, sc_ttl, 0, 0, 0);
+ }
+ }
+
+ // Wind
+ clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_WIND));
+ if (sce_wind != NULL && sce_wind->timer != INVALID_TIMER) {
+ int sum_wind = sce_wind->val1 + ((sce_water != NULL) ? sce_water->val2 : 0);
+ const struct TimerData *td = timer->get(sce_wind->timer);
+ if (td != NULL && sce_wind->val1 > 0 && sum_wind > 0) {
+ int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WIND);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_WIND);
+ int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick());
+ int sc_ttl = sce_wind->total_tick;
+ clif->status_change_sub(bl, sc_icn, sc_typ, 1, sc_tck, sc_ttl, 0, 0, 0);
+ }
+ }
+
+ break;
+ }
+ case SC_RESIST_PROPERTY_WATER:
+ if (sc->data[SC_ARMOR_RESIST] != NULL && sc->data[SC_ARMOR_RESIST]->timer != INVALID_TIMER) {
+ const struct TimerData *td = timer->get(sc->data[SC_ARMOR_RESIST]->timer);
+ if (td == NULL)
+ break;
+
+ // Water
+ int sum_water = sc->data[SC_ARMOR_RESIST]->val1;
+ if (sc->data[SC_RESIST_PROPERTY_FIRE] != NULL)
+ sum_water += sc->data[SC_RESIST_PROPERTY_FIRE]->val2;
+ if (sc->data[SC_ARMOR_RESIST]->val1 > 0 && sum_water > 0) {
+ int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WATER);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_WATER);
+ int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick());
+ int sc_ttl = sc->data[SC_ARMOR_RESIST]->total_tick;
+ clif->status_change_sub(bl, sc_icn, sc_typ, 1, sc_tck, sc_ttl, 0, 0, 0);
+ remove_icon = false;
+ }
+
+ // Wind
+ int sum_wind = sc->data[SC_ARMOR_RESIST]->val4;
+ if (sc->data[SC_RESIST_PROPERTY_WIND] != NULL)
+ sum_wind += sc->data[SC_RESIST_PROPERTY_WIND]->val1;
+ if (sc->data[SC_ARMOR_RESIST]->val4 > 0 && sum_wind > 0) {
+ int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WIND);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_WIND);
+ int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick());
+ int sc_ttl = sc->data[SC_ARMOR_RESIST]->total_tick;
+ clif->status_change_sub(bl, sc_icn, sc_typ, 1, sc_tck, sc_ttl, 0, 0, 0);
+ }
+ }
+
+ break;
+ case SC_RESIST_PROPERTY_GROUND:
+ if (sc->data[SC_ARMOR_RESIST] != NULL && sc->data[SC_ARMOR_RESIST]->timer != INVALID_TIMER) {
+ const struct TimerData *td = timer->get(sc->data[SC_ARMOR_RESIST]->timer);
+ if (td == NULL)
+ break;
+
+ // Ground
+ int sum_ground = sc->data[SC_ARMOR_RESIST]->val2;
+ if (sc->data[SC_RESIST_PROPERTY_WIND] != NULL)
+ sum_ground += sc->data[SC_RESIST_PROPERTY_WIND]->val2;
+ if (sc->data[SC_ARMOR_RESIST]->val2 > 0 && sum_ground > 0) {
+ int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_GROUND);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_GROUND);
+ int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick());
+ int sc_ttl = sc->data[SC_ARMOR_RESIST]->total_tick;
+ clif->status_change_sub(bl, sc_icn, sc_typ, 1, sc_tck, sc_ttl, 0, 0, 0);
+ remove_icon = false;
+ }
+
+ // Fire
+ int sum_fire = sc->data[SC_ARMOR_RESIST]->val3;
+ if (sc->data[SC_RESIST_PROPERTY_FIRE] != NULL)
+ sum_fire += sc->data[SC_RESIST_PROPERTY_FIRE]->val1;
+ if (sc->data[SC_ARMOR_RESIST]->val3 > 0 && sum_fire > 0) {
+ int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_FIRE);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_FIRE);
+ int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick());
+ int sc_ttl = sc->data[SC_ARMOR_RESIST]->total_tick;
+ clif->status_change_sub(bl, sc_icn, sc_typ, 1, sc_tck, sc_ttl, 0, 0, 0);
+ }
+ }
+
+ break;
+ case SC_RESIST_PROPERTY_FIRE:
+ if (sc->data[SC_ARMOR_RESIST] != NULL && sc->data[SC_ARMOR_RESIST]->timer != INVALID_TIMER) {
+ const struct TimerData *td = timer->get(sc->data[SC_ARMOR_RESIST]->timer);
+ if (td == NULL)
+ break;
+
+ // Fire
+ int sum_fire = sc->data[SC_ARMOR_RESIST]->val3;
+ if (sc->data[SC_RESIST_PROPERTY_GROUND] != NULL)
+ sum_fire += sc->data[SC_RESIST_PROPERTY_GROUND]->val2;
+ if (sc->data[SC_ARMOR_RESIST]->val3 > 0 && sum_fire > 0) {
+ int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_FIRE);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_FIRE);
+ int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick());
+ int sc_ttl = sc->data[SC_ARMOR_RESIST]->total_tick;
+ clif->status_change_sub(bl, sc_icn, sc_typ, 1, sc_tck, sc_ttl, 0, 0, 0);
+ remove_icon = false;
+ }
+
+ // Water
+ int sum_water = sc->data[SC_ARMOR_RESIST]->val1;
+ if (sc->data[SC_RESIST_PROPERTY_WATER] != NULL)
+ sum_water += sc->data[SC_RESIST_PROPERTY_WATER]->val1;
+ if (sc->data[SC_ARMOR_RESIST]->val1 > 0 && sum_water > 0) {
+ int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WATER);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_WATER);
+ int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick());
+ int sc_ttl = sc->data[SC_ARMOR_RESIST]->total_tick;
+ clif->status_change_sub(bl, sc_icn, sc_typ, 1, sc_tck, sc_ttl, 0, 0, 0);
+ }
+ }
+
+ break;
+ case SC_RESIST_PROPERTY_WIND:
+ if (sc->data[SC_ARMOR_RESIST] != NULL && sc->data[SC_ARMOR_RESIST]->timer != INVALID_TIMER) {
+ const struct TimerData *td = timer->get(sc->data[SC_ARMOR_RESIST]->timer);
+ if (td == NULL)
+ break;
+
+ // Wind
+ int sum_wind = sc->data[SC_ARMOR_RESIST]->val4;
+ if (sc->data[SC_RESIST_PROPERTY_WATER] != NULL)
+ sum_wind += sc->data[SC_RESIST_PROPERTY_WATER]->val2;
+ if (sc->data[SC_ARMOR_RESIST]->val4 > 0 && sum_wind > 0) {
+ int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WIND);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_WIND);
+ int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick());
+ int sc_ttl = sc->data[SC_ARMOR_RESIST]->total_tick;
+ clif->status_change_sub(bl, sc_icn, sc_typ, 1, sc_tck, sc_ttl, 0, 0, 0);
+ remove_icon = false;
+ }
+
+ // Ground
+ int sum_ground = sc->data[SC_ARMOR_RESIST]->val2;
+ if (sc->data[SC_RESIST_PROPERTY_GROUND] != NULL)
+ sum_ground += sc->data[SC_RESIST_PROPERTY_GROUND]->val1;
+ if (sc->data[SC_ARMOR_RESIST]->val2 > 0 && sum_ground > 0) {
+ int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_GROUND);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_GROUND);
+ int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick());
+ int sc_ttl = sc->data[SC_ARMOR_RESIST]->total_tick;
+ clif->status_change_sub(bl, sc_icn, sc_typ, 1, sc_tck, sc_ttl, 0, 0, 0);
+ }
+ }
+
+ break;
}
opt_flag = 1;
@@ -11272,7 +11699,8 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid,
#endif
//On Aegis, when turning off a status change, first goes the sc packet, then the option packet.
- clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(type));
+ if (remove_icon)
+ clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(type));
if( opt_flag&8 ) //bugreport:681
clif->changeoption2(bl);
diff --git a/src/plugins/HPMHooking/HPMHooking.Defs.inc b/src/plugins/HPMHooking/HPMHooking.Defs.inc
index 80ba50d73..d20766956 100644
--- a/src/plugins/HPMHooking/HPMHooking.Defs.inc
+++ b/src/plugins/HPMHooking/HPMHooking.Defs.inc
@@ -6858,8 +6858,8 @@ typedef void (*HPMHOOK_pre_script_set_constant2) (const char **name, int *value,
typedef void (*HPMHOOK_post_script_set_constant2) (const char *name, int value, bool is_parameter, bool is_deprecated);
typedef bool (*HPMHOOK_pre_script_get_constant) (const char **name, int **value);
typedef bool (*HPMHOOK_post_script_get_constant) (bool retVal___, const char *name, int *value);
-typedef void (*HPMHOOK_pre_script_label_add) (int *key, int *pos);
-typedef void (*HPMHOOK_post_script_label_add) (int key, int pos);
+typedef void (*HPMHOOK_pre_script_label_add) (int *key, int *pos, enum script_label_flags *flags);
+typedef void (*HPMHOOK_post_script_label_add) (int key, int pos, enum script_label_flags flags);
typedef void (*HPMHOOK_pre_script_run) (struct script_code **rootscript, int *pos, int *rid, int *oid);
typedef void (*HPMHOOK_post_script_run) (struct script_code *rootscript, int pos, int rid, int oid);
typedef void (*HPMHOOK_pre_script_run_npc) (struct script_code **rootscript, int *pos, int *rid, int *oid);
@@ -6924,6 +6924,8 @@ typedef const char* (*HPMHOOK_pre_script_parse_syntax_close_sub) (const char **p
typedef const char* (*HPMHOOK_post_script_parse_syntax_close_sub) (const char* retVal___, const char *p, int *flag);
typedef const char* (*HPMHOOK_pre_script_parse_syntax) (const char **p);
typedef const char* (*HPMHOOK_post_script_parse_syntax) (const char* retVal___, const char *p);
+typedef const char* (*HPMHOOK_pre_script_parse_syntax_function) (const char **p, bool *is_public);
+typedef const char* (*HPMHOOK_post_script_parse_syntax_function) (const char* retVal___, const char *p, bool is_public);
typedef c_op (*HPMHOOK_pre_script_get_com) (const struct script_buf **scriptbuf, int **pos);
typedef c_op (*HPMHOOK_post_script_get_com) (c_op retVal___, const struct script_buf *scriptbuf, int *pos);
typedef int (*HPMHOOK_pre_script_get_num) (const struct script_buf **scriptbuf, int **pos);
@@ -6988,6 +6990,8 @@ typedef const char* (*HPMHOOK_pre_script_print_line) (StringBuf **buf, const cha
typedef const char* (*HPMHOOK_post_script_print_line) (const char* retVal___, StringBuf *buf, const char *p, const char *mark, int line);
typedef void (*HPMHOOK_pre_script_errorwarning_sub) (StringBuf **buf, const char **src, const char **file, int *start_line, const char **error_msg, const char **error_pos);
typedef void (*HPMHOOK_post_script_errorwarning_sub) (StringBuf *buf, const char *src, const char *file, int start_line, const char *error_msg, const char *error_pos);
+typedef bool (*HPMHOOK_pre_script_is_permanent_variable) (const char **name);
+typedef bool (*HPMHOOK_post_script_is_permanent_variable) (bool retVal___, const char *name);
typedef int (*HPMHOOK_pre_script_set_reg) (struct script_state **st, struct map_session_data **sd, int64 *num, const char **name, const void **value, struct reg_db **ref);
typedef int (*HPMHOOK_post_script_set_reg) (int retVal___, struct script_state *st, struct map_session_data *sd, int64 num, const char *name, const void *value, struct reg_db *ref);
typedef void (*HPMHOOK_pre_script_set_reg_ref_str) (struct script_state **st, struct reg_db **n, int64 *num, const char **name, const char **str);
diff --git a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc
index 70bc309f3..02ba063ed 100644
--- a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc
+++ b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc
@@ -5454,6 +5454,8 @@ struct {
struct HPMHookPoint *HP_script_parse_syntax_close_sub_post;
struct HPMHookPoint *HP_script_parse_syntax_pre;
struct HPMHookPoint *HP_script_parse_syntax_post;
+ struct HPMHookPoint *HP_script_parse_syntax_function_pre;
+ struct HPMHookPoint *HP_script_parse_syntax_function_post;
struct HPMHookPoint *HP_script_get_com_pre;
struct HPMHookPoint *HP_script_get_com_post;
struct HPMHookPoint *HP_script_get_num_pre;
@@ -5518,6 +5520,8 @@ struct {
struct HPMHookPoint *HP_script_print_line_post;
struct HPMHookPoint *HP_script_errorwarning_sub_pre;
struct HPMHookPoint *HP_script_errorwarning_sub_post;
+ struct HPMHookPoint *HP_script_is_permanent_variable_pre;
+ struct HPMHookPoint *HP_script_is_permanent_variable_post;
struct HPMHookPoint *HP_script_set_reg_pre;
struct HPMHookPoint *HP_script_set_reg_post;
struct HPMHookPoint *HP_script_set_reg_ref_str_pre;
@@ -12353,6 +12357,8 @@ struct {
int HP_script_parse_syntax_close_sub_post;
int HP_script_parse_syntax_pre;
int HP_script_parse_syntax_post;
+ int HP_script_parse_syntax_function_pre;
+ int HP_script_parse_syntax_function_post;
int HP_script_get_com_pre;
int HP_script_get_com_post;
int HP_script_get_num_pre;
@@ -12417,6 +12423,8 @@ struct {
int HP_script_print_line_post;
int HP_script_errorwarning_sub_pre;
int HP_script_errorwarning_sub_post;
+ int HP_script_is_permanent_variable_pre;
+ int HP_script_is_permanent_variable_post;
int HP_script_set_reg_pre;
int HP_script_set_reg_post;
int HP_script_set_reg_ref_str_pre;
diff --git a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc
index c9b673a1f..4a36c5a1e 100644
--- a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc
+++ b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc
@@ -2793,6 +2793,7 @@ struct HookingPointData HookingPoints[] = {
{ HP_POP(script->parse_syntax_close, HP_script_parse_syntax_close) },
{ HP_POP(script->parse_syntax_close_sub, HP_script_parse_syntax_close_sub) },
{ HP_POP(script->parse_syntax, HP_script_parse_syntax) },
+ { HP_POP(script->parse_syntax_function, HP_script_parse_syntax_function) },
{ HP_POP(script->get_com, HP_script_get_com) },
{ HP_POP(script->get_num, HP_script_get_num) },
{ HP_POP(script->op2name, HP_script_op2name) },
@@ -2825,6 +2826,7 @@ struct HookingPointData HookingPoints[] = {
{ HP_POP(script->load_parameters, HP_script_load_parameters) },
{ HP_POP(script->print_line, HP_script_print_line) },
{ HP_POP(script->errorwarning_sub, HP_script_errorwarning_sub) },
+ { HP_POP(script->is_permanent_variable, HP_script_is_permanent_variable) },
{ HP_POP(script->set_reg, HP_script_set_reg) },
{ HP_POP(script->set_reg_ref_str, HP_script_set_reg_ref_str) },
{ HP_POP(script->set_reg_pc_ref_str, HP_script_set_reg_pc_ref_str) },
diff --git a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc
index 599cbfdfd..f0e395b64 100644
--- a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc
+++ b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc
@@ -71749,14 +71749,14 @@ bool HP_script_get_constant(const char *name, int *value) {
}
return retVal___;
}
-void HP_script_label_add(int key, int pos) {
+void HP_script_label_add(int key, int pos, enum script_label_flags flags) {
int hIndex = 0;
if (HPMHooks.count.HP_script_label_add_pre > 0) {
- void (*preHookFunc) (int *key, int *pos);
+ void (*preHookFunc) (int *key, int *pos, enum script_label_flags *flags);
*HPMforce_return = false;
for (hIndex = 0; hIndex < HPMHooks.count.HP_script_label_add_pre; hIndex++) {
preHookFunc = HPMHooks.list.HP_script_label_add_pre[hIndex].func;
- preHookFunc(&key, &pos);
+ preHookFunc(&key, &pos, &flags);
}
if (*HPMforce_return) {
*HPMforce_return = false;
@@ -71764,13 +71764,13 @@ void HP_script_label_add(int key, int pos) {
}
}
{
- HPMHooks.source.script.label_add(key, pos);
+ HPMHooks.source.script.label_add(key, pos, flags);
}
if (HPMHooks.count.HP_script_label_add_post > 0) {
- void (*postHookFunc) (int key, int pos);
+ void (*postHookFunc) (int key, int pos, enum script_label_flags flags);
for (hIndex = 0; hIndex < HPMHooks.count.HP_script_label_add_post; hIndex++) {
postHookFunc = HPMHooks.list.HP_script_label_add_post[hIndex].func;
- postHookFunc(key, pos);
+ postHookFunc(key, pos, flags);
}
}
return;
@@ -72625,6 +72625,33 @@ const char* HP_script_parse_syntax(const char *p) {
}
return retVal___;
}
+const char* HP_script_parse_syntax_function(const char *p, bool is_public) {
+ int hIndex = 0;
+ const char* retVal___ = NULL;
+ if (HPMHooks.count.HP_script_parse_syntax_function_pre > 0) {
+ const char* (*preHookFunc) (const char **p, bool *is_public);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_script_parse_syntax_function_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_script_parse_syntax_function_pre[hIndex].func;
+ retVal___ = preHookFunc(&p, &is_public);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.script.parse_syntax_function(p, is_public);
+ }
+ if (HPMHooks.count.HP_script_parse_syntax_function_post > 0) {
+ const char* (*postHookFunc) (const char* retVal___, const char *p, bool is_public);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_script_parse_syntax_function_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_script_parse_syntax_function_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, p, is_public);
+ }
+ }
+ return retVal___;
+}
c_op HP_script_get_com(const struct script_buf *scriptbuf, int *pos) {
int hIndex = 0;
c_op retVal___ = C_NOP;
@@ -73473,6 +73500,33 @@ void HP_script_errorwarning_sub(StringBuf *buf, const char *src, const char *fil
}
return;
}
+bool HP_script_is_permanent_variable(const char *name) {
+ int hIndex = 0;
+ bool retVal___ = false;
+ if (HPMHooks.count.HP_script_is_permanent_variable_pre > 0) {
+ bool (*preHookFunc) (const char **name);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_script_is_permanent_variable_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_script_is_permanent_variable_pre[hIndex].func;
+ retVal___ = preHookFunc(&name);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.script.is_permanent_variable(name);
+ }
+ if (HPMHooks.count.HP_script_is_permanent_variable_post > 0) {
+ bool (*postHookFunc) (bool retVal___, const char *name);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_script_is_permanent_variable_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_script_is_permanent_variable_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, name);
+ }
+ }
+ return retVal___;
+}
int HP_script_set_reg(struct script_state *st, struct map_session_data *sd, int64 num, const char *name, const void *value, struct reg_db *ref) {
int hIndex = 0;
int retVal___ = 0;