summaryrefslogtreecommitdiff
path: root/npc/functions
diff options
context:
space:
mode:
authorJesusaves <cpntb1@ymail.com>2020-12-06 19:30:53 +0000
committerJesusaves <cpntb1@ymail.com>2020-12-06 19:30:53 +0000
commit5195432edc23040407c7ae84061e9db0c2cbebf1 (patch)
tree91a042a0d2a9735e2907bb4daec4c3b0dd368721 /npc/functions
parent3db95edc1d79e290c3d18ec6f2f6af9b42b89396 (diff)
downloadserverdata-5195432edc23040407c7ae84061e9db0c2cbebf1.tar.gz
serverdata-5195432edc23040407c7ae84061e9db0c2cbebf1.tar.bz2
serverdata-5195432edc23040407c7ae84061e9db0c2cbebf1.tar.xz
serverdata-5195432edc23040407c7ae84061e9db0c2cbebf1.zip
* Lena's quest
* Add Inn to towns * Add Merchant Guild to towns * Add Soul Menhir to Towns * Add Barbers to towns * Add General Store to towns * Some work for blacksmith & tailoring * Kadiya's placeholder (no quest for r1, sorry D:) * Anwar Quest * Joaquim Quest * Updates on Artis Blacksmith and Julia's intro * some work on fishing spots * Bosses and Master Skill Book ("about" one per region) * Asphodel Moors population (no quests and incomplete)
Diffstat (limited to 'npc/functions')
-rw-r--r--npc/functions/barber.txt67
-rw-r--r--npc/functions/crafting.txt4
-rw-r--r--npc/functions/fishing.txt112
-rw-r--r--npc/functions/main.txt82
-rw-r--r--npc/functions/music.txt58
-rw-r--r--npc/functions/resetstatus.txt117
-rw-r--r--npc/functions/soul-menhir.txt75
7 files changed, 492 insertions, 23 deletions
diff --git a/npc/functions/barber.txt b/npc/functions/barber.txt
index 3d2e3014..54402750 100644
--- a/npc/functions/barber.txt
+++ b/npc/functions/barber.txt
@@ -7,6 +7,8 @@
// Description:
// Function for supporting barber NPC.
+// BarberSayStyle({what})
+// what: 1 = Style; 2 = Color; 3 = Style + Color in dialog
function script BarberSayStyle {
.@get_color = getlook(LOOK_HAIR_COLOR);
@@ -14,7 +16,7 @@ function script BarberSayStyle {
.@style_name$ = $@hairstyle$[.@get_look];
.@color_name$ = $@haircolor$[.@get_color];
- switch (getarg(0))
+ switch (getarg(0, 3))
{
case 1:
message strcharinfo(0), l("@@", .@style_name$);
@@ -59,7 +61,7 @@ function script BarberChangeStyle {
} while (.@rand_hair == getlook(LOOK_HAIR));
setlook LOOK_HAIR, .@rand_hair;
setlook LOOK_HAIR_COLOR, getlook(LOOK_HAIR_COLOR);
- BarberSayStyle 1;
+ BarberSayStyle(1);
break;
default:
// and here "- 1" because the first choice is taken by the random
@@ -98,7 +100,7 @@ function script BarberChangeColor {
.@rand_color = rand(0, .@hairsizearray);
} while (.@rand_color == getlook(LOOK_HAIR_COLOR));
setlook LOOK_HAIR_COLOR, .@rand_color;
- BarberSayStyle 2;
+ BarberSayStyle(2);
break;
default:
setlook LOOK_HAIR_COLOR, (@menu - 2);
@@ -138,9 +140,9 @@ function script BarberChangeRace {
mes l("What's your race?");
menuint
- get_race(GETRACE_FULL, KaizeiViro), KaizeiViro,
- get_race(GETRACE_FULL, ArgaesViro), ArgaesViro,
- get_race(GETRACE_FULL, TonoriViro), TonoriViro,
+ get_race(GETRACE_FULL, KaizeiTalpan), KaizeiTalpan,
+ get_race(GETRACE_FULL, ArgaesTalpan), ArgaesTalpan,
+ get_race(GETRACE_FULL, TonoriTalpan), TonoriTalpan,
get_race(GETRACE_FULL, CaveUkar), CaveUkar,
get_race(GETRACE_FULL, MountainUkar), MountainUkar,
get_race(GETRACE_FULL, SeaTritan), SeaTritan,
@@ -163,3 +165,56 @@ function script BarberChangeRace {
jobchange(@menuret); // STUPID idea, but imposed by Hercules
return;
}
+
+// Jack of all trades
+// Barber({intro=True})
+function script Barber {
+ if (getarg(0, true)) {
+ mesn;
+ mesq lg("Hello, young lady.", "Hello, young man.");
+ next;
+ }
+ mesq l("What would you like me to do?");
+ next;
+ do
+ {
+ select
+ l("What is my current hairstyle and hair color?"),
+ l("I'd like to get a different style."),
+ l("Can you do something with my color?"),
+ l("How about changing my body type?"),
+ l("I'm fine for now, thank you.");
+
+ switch (@menu)
+ {
+ case 1:
+ BarberSayStyle();
+ break;
+ case 2:
+ BarberChangeStyle;
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Enjoy your new style."),
+ l("Anything else?");
+ break;
+ case 3:
+ BarberChangeColor;
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("I hope you like this color."),
+ l("Anything else?");
+ break;
+ case 4:
+ BarberChangeBodyType();
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("You look fantastic."),
+ l("Anything else?");
+ break;
+ case 5:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Feel free to come visit me another time.");
+
+ goodbye;
+ }
+ } while (true);
+ return;
+}
+
diff --git a/npc/functions/crafting.txt b/npc/functions/crafting.txt
index 05a9d9a6..fa5fa84e 100644
--- a/npc/functions/crafting.txt
+++ b/npc/functions/crafting.txt
@@ -1,6 +1,7 @@
// Moubootaur Legends Script
// Author:
// Jesusalva
+// Gumi
// Description:
// Smith System (Unified)
// Notes:
@@ -80,7 +81,8 @@ function script SmithSystem {
// I'm using the same EXP formula from Moubootaur Legends
// Which is based on the item sell price
.@xp=getiteminfo(.@it, ITEMINFO_SELLPRICE);
- getexp .@xp+BaseLevel, (.@xp/3)+BaseLevel+JobLevel;
+ quest_xp(.@lv+10, .@xp+BaseLevel);
+ quest_jxp(.@lv+10, (.@xp/3)+BaseLevel+JobLevel);
.success=true;
} else {
.success=false;
diff --git a/npc/functions/fishing.txt b/npc/functions/fishing.txt
index fee0acb7..4dcb4882 100644
--- a/npc/functions/fishing.txt
+++ b/npc/functions/fishing.txt
@@ -3,6 +3,8 @@
// gumi
// omatt
// Travolta
+// Reid
+// Jesusalva
// Description:
// Fishing functions.
// Variable
@@ -287,3 +289,113 @@ function script fishing {
return 0;
}
+
+
+////////////////////
+// Fishing Templates
+
+// #fish_basic - has only carps (freshwater)
+- script #fish_basic NPC_WATER_SPLASH,{
+
+ fishing(); // begin or continue fishing
+ close;
+
+OnInit:
+ .distance = 5;
+ setarray .fish_ids, 0,
+ CommonCarp, 25,
+ GrassCarp, 1;
+ .fishing_rod = FishingRod; // Equipment to fish here
+ .catch_time = 5000; // must catch the fish within X ms after the line sinks
+ .wait_time_min = 4000; // min amount of time to wait for the line to sink
+ .wait_time_max = 18000; // max amount of time to wait for the line to sink
+ end;
+}
+
+
+// #fish_seawater - has only tuna
+- script #fish_seawater NPC_WATER_SPLASH,{
+
+ fishing(); // begin or continue fishing
+ close;
+
+OnInit:
+ .distance = 5;
+ setarray .fish_ids, 0,
+ Tuna, 15,
+ Salmon, 1;
+ .fishing_rod = FishingRod; // Equipment to fish here
+ .catch_time = 4000; // must catch the fish within X ms after the line sinks
+ .wait_time_min = 8000; // min amount of time to wait for the line to sink
+ .wait_time_max = 18000; // max amount of time to wait for the line to sink
+ end;
+}
+
+
+
+// #fish_river - A balanced fishing spot for Woodlands (Trout)
+- script #fish_river NPC_WATER_SPLASH,{
+
+ fishing(); // begin or continue fishing
+ close;
+
+OnInit:
+ .distance = 5;
+ setarray .fish_ids, 0,
+ CommonCarp, 25,
+ Trout, 20,
+ GrassCarp, 5,
+ Salmon, 1;
+ .fishing_rod = FishingRod; // Equipment to fish here
+ .catch_time = 5500; // must catch the fish within X ms after the line sinks
+ .wait_time_min = 5000; // min amount of time to wait for the line to sink
+ .wait_time_max = 16000; // max amount of time to wait for the line to sink
+ end;
+}
+
+
+
+
+// #fish_river2 - A balanced fishing spot for Candor (Salmon)
+- script #fish_river2 NPC_WATER_SPLASH,{
+
+ fishing(); // begin or continue fishing
+ close;
+
+OnInit:
+ .distance = 5;
+ setarray .fish_ids, 0,
+ CommonCarp, 25,
+ Salmon, 20,
+ GrassCarp, 5,
+ Trout, 1;
+ .fishing_rod = FishingRod; // Equipment to fish here
+ .catch_time = 5500; // must catch the fish within X ms after the line sinks
+ .wait_time_min = 5000; // min amount of time to wait for the line to sink
+ .wait_time_max = 16000; // max amount of time to wait for the line to sink
+ end;
+}
+
+
+
+
+// #fish_frozen - A fishing spot with cold waters (for Nivalis)
+- script #fish_frozen NPC_WATER_SPLASH,{
+
+ fishing(); // begin or continue fishing
+ close;
+
+OnInit:
+ .distance = 5;
+ setarray .fish_ids, 0,
+ CommonCarp, 25,
+ Codfish, 20,
+ GrassCarp, 5,
+ Salmon, 1;
+ .fishing_rod = FishingRod; // Equipment to fish here
+ .catch_time = 5500; // must catch the fish within X ms after the line sinks
+ .wait_time_min = 5000; // min amount of time to wait for the line to sink
+ .wait_time_max = 16000; // max amount of time to wait for the line to sink
+ end;
+}
+
diff --git a/npc/functions/main.txt b/npc/functions/main.txt
index 3be6b6fb..28b61c7c 100644
--- a/npc/functions/main.txt
+++ b/npc/functions/main.txt
@@ -289,7 +289,7 @@ function script get_race {
// We also allow this to run without player attached for... science.
if (playerattached())
{
- setarray .@allraces$, l("Viro"), l("Viro"), l("Viro"),
+ setarray .@allraces$, l("Human"), l("Human"), l("Human"),
l("Ukar"), l("Ukar"),
l("Tritan"), l("Tritan"),
l("Raijin"), l("Raijin"),
@@ -302,7 +302,7 @@ function script get_race {
}
else
{
- setarray .@allraces$, ("Viro"), ("Viro"), ("Viro"),
+ setarray .@allraces$, ("Human"), ("Human"), ("Human"),
("Ukar"), ("Ukar"),
("Tritan"), ("Tritan"),
("Raijin"), ("Raijin"),
@@ -365,3 +365,81 @@ function script getmap {
return getmapname();
}
+// Quest Rewards
+// quest_xp(maxLevel, reward, {multiplier=1})
+function script quest_xp {
+ //.@minLevel=getarg(0);
+ .@maxLevel=getarg(0);
+ .@reward=getarg(1);
+ .@mult=getarg(2, 1);
+ if (BaseLevel <= .@maxLevel) {
+ getexp .@reward*.@mult, 0;
+ return;
+ }
+ // You'll forsake 2% every over level
+ .@mult*=100;
+ .@mult-=((BaseLevel - .@maxLevel) * 2);
+ .@mult=max(10, .@mult);
+ getexp .@reward*.@mult/100, 0;
+ return;
+}
+
+// quest_jxp(maxLevel, reward, {multiplier=1})
+function script quest_jxp {
+ //.@minLevel=getarg(0);
+ .@maxLevel=getarg(0);
+ .@reward=getarg(1);
+ .@mult=getarg(2, 1);
+ if (BaseLevel < .@maxLevel) {
+ getexp 0, .@reward*.@mult;
+ return;
+ }
+ // You'll forsake 2% every over level
+ .@mult*=100;
+ .@mult-=((BaseLevel - .@maxLevel) * 2);
+ .@mult=max(10, .@mult);
+ getexp 0, .@reward*.@mult/100;
+ return;
+}
+
+// quest_gp(maxLevel, reward, {multiplier=1})
+function script quest_gp {
+ //.@minLevel=getarg(0);
+ .@maxLevel=getarg(0);
+ .@reward=getarg(1);
+ .@mult=getarg(2, 1);
+ if (BaseLevel <= .@maxLevel) {
+ Zeny+=.@reward*.@mult;
+ return;
+ }
+ // You'll forsake 2% every over level
+ .@mult*=100;
+ .@mult-=((BaseLevel - .@maxLevel) * 2);
+ .@mult=max(10, .@mult);
+ Zeny+=.@reward*.@mult/100;
+ return;
+}
+
+// quest_item(maxLevel, item, {amount=1}, {bound=0})
+function script quest_item {
+ //.@minLevel=getarg(0);
+ .@maxLevel=getarg(0);
+ .@reward=getarg(1);
+ .@mult=getarg(2, 1);
+ .@bind=getarg(3, 0);
+ // Item will not be obtained if you are overlevel
+ if (BaseLevel > .@maxLevel && .@mult <= 1)
+ return;
+ // If it comes in pairs, you'll only get 1
+ if (BaseLevel > .@maxLevel)
+ .@mult=1;
+ // Obtain item bound if needed
+ if (.@bind)
+ getitembound .@reward, .@mult, .@bind;
+ else
+ getitem .@reward, .@mult;
+ return;
+}
+
+
+
diff --git a/npc/functions/music.txt b/npc/functions/music.txt
index c8937583..18a8fbe7 100644
--- a/npc/functions/music.txt
+++ b/npc/functions/music.txt
@@ -2,6 +2,7 @@
// Author:
// Jesusalva
// Gumi
+// Ledmitz
// Description:
// Music functions
//
@@ -11,18 +12,19 @@
// "jukebox"::HurnscaldPrompt(); → Makes a menuint for selecting hurns tracks
// "jukebox"::JukeboxMusic(ID); → Changes music based on prompted ID
// "jukebox"::BroadcastMusic(MAP, ID); → Changes music based on prompted ID
+// TODO: Check if you have the music unlocked? Bitmask? Array?
- script jukebox 32767,{
end;
// Helpers
public function JukeboxMusic {
- changeplayermusic .MUSIC_ARRAY[getarg(0)];
+ changeplayermusic $MUSIC_ARRAY$[getarg(0)] + ".ogg";
return;
}
public function BroadcastMusic {
- changemusic getarg(0), .MUSIC_ARRAY[getarg(1)];
+ changemusic getarg(0), $MUSIC_ARRAY$[getarg(1)] + ".ogg";
return;
}
@@ -32,9 +34,10 @@ public function BroadcastMusic {
public function HurnscaldPrompt {
menuint
"Cancel", -1,
- "Forest of Birches", 0,
- "Adventure Begins", 1,
- "Magick Real", 5;
+ "Johanne - Forest of Birches", 0,
+ "Artis - Adventure Begins", 1,
+ "Argaes - Dariunas' Forest", 20,
+ "Hurnscald - Magick Real", 5;
mes "";
if (@menuret == -1)
close;
@@ -43,15 +46,42 @@ public function HurnscaldPrompt {
// Initialize stuff which will be needed
OnInit:
- .MUSIC_ARRAY[0] = "bartk - in the forest of the birches.ogg";
- .MUSIC_ARRAY[1] = "bartk - the adventure begins.ogg";
- .MUSIC_ARRAY[2] = "eric matyas - ghoulish fun.ogg";
- .MUSIC_ARRAY[3] = "eric matyas - surreal place.ogg";
- .MUSIC_ARRAY[4] = "ezili - ocean sounds.ogg";
- .MUSIC_ARRAY[5] = "magick - real.ogg";
+ $MUSIC_ARRAY$[0] = "johanne";
+ $MUSIC_ARRAY$[1] = "artis";
+ $MUSIC_ARRAY$[2] = "ghoulish";
+ $MUSIC_ARRAY$[3] = "surreal";
+ $MUSIC_ARRAY$[4] = "ocean";
+ $MUSIC_ARRAY$[5] = "real";
+ $MUSIC_ARRAY$[6] = "academy";
+ $MUSIC_ARRAY$[7] = "bandit";
+ $MUSIC_ARRAY$[8] = "barbarians";
+ $MUSIC_ARRAY$[9] = "botcheck";
+ $MUSIC_ARRAY$[10] = "candor";
+ $MUSIC_ARRAY$[11] = "cavesong";
+ $MUSIC_ARRAY$[12] = "chilling";
+ $MUSIC_ARRAY$[13] = "cloudcall";
+ $MUSIC_ARRAY$[14] = "crypt";
+ $MUSIC_ARRAY$[15] = "despair";
+ $MUSIC_ARRAY$[16] = "dimond";
+ $MUSIC_ARRAY$[17] = "explorer";
+ $MUSIC_ARRAY$[18] = "faith";
+ $MUSIC_ARRAY$[19] = "fire";
+ $MUSIC_ARRAY$[20] = "forest";
+ $MUSIC_ARRAY$[21] = "graveyard";
+ $MUSIC_ARRAY$[22] = "hurns";
+ $MUSIC_ARRAY$[23] = "marine";
+ $MUSIC_ARRAY$[24] = "mystique";
+ $MUSIC_ARRAY$[25] = "nightcall";
+ $MUSIC_ARRAY$[26] = "nivalis";
+ $MUSIC_ARRAY$[27] = "ocean";
+ $MUSIC_ARRAY$[28] = "peace";
+ $MUSIC_ARRAY$[29] = "reid";
+ $MUSIC_ARRAY$[30] = "sewer";
+ $MUSIC_ARRAY$[31] = "store";
+ $MUSIC_ARRAY$[32] = "swamp";
+ $MUSIC_ARRAY$[33] = "thunderstorm";
+ $MUSIC_ARRAY$[34] = "waterlude";
+ $MUSIC_ARRAY$[35] = "xmas";
end;
}
-
-
-
diff --git a/npc/functions/resetstatus.txt b/npc/functions/resetstatus.txt
new file mode 100644
index 00000000..bb4b22b4
--- /dev/null
+++ b/npc/functions/resetstatus.txt
@@ -0,0 +1,117 @@
+// Moubootaur Legends Script.
+// Authors:
+// Vasily_Makarov (original from Evol)
+// Jesusalva
+// Description:
+// Status Reset NPC utils
+
+// Reset status and return permanent bonuses
+// StatusResetReinvest( {script=True} )
+function script StatusResetReinvest {
+ /* XXX: Uncommment this for ML Permanent Boost Status Fruit System :XXX
+ // Compulsory check
+ if (getarg(0, true)) {
+ inventoryplace NPCEyes, 6;
+ } else if (!checkweight(NPCEyes, 6)) {
+ getitembound StatusResetPotion, 1, 4;
+ dispbottom l("You cannot carry the fruits.");
+ end; // Die
+ }
+
+ // Permanent boosts were now lost, return the fruits
+ if (STATUSUP_STR) {
+ getitembound StrengthFruit, STATUSUP_STR, 4;
+ STATUSUP_STR=0;
+ }
+ if (STATUSUP_AGI) {
+ getitembound AgilityFruit, STATUSUP_AGI, 4;
+ STATUSUP_AGI=0;
+ }
+ if (STATUSUP_VIT) {
+ getitembound VitalityFruit, STATUSUP_VIT, 4;
+ STATUSUP_VIT=0;
+ }
+ if (STATUSUP_INT) {
+ getitembound IntelligenceFruit, STATUSUP_INT, 4;
+ STATUSUP_INT=0;
+ }
+ if (STATUSUP_DEX) {
+ getitembound DexterityFruit, STATUSUP_DEX, 4;
+ STATUSUP_DEX=0;
+ }
+ if (STATUSUP_LUK) {
+ getitembound LuckFruit, STATUSUP_LUK, 4;
+ STATUSUP_LUK=0;
+ }
+ */
+ resetstatus();
+ return true;
+}
+
+// Return wasSP on success, 0 on failure
+// ConfirmReset( {price} )
+function script ConfirmStatusReset {
+ if (BaseLevel >= 15)
+ .@raw_price=(1000-BaseLevel*10+(BaseLevel*18));
+ else if (BaseLevel >= 10)
+ .@raw_price=(BaseLevel*210-(10*210))/(BaseLevel/10);
+ else
+ .@raw_price=1;
+
+ if (getarg(0,-1) >= 0)
+ .@raw_price=getarg(0,-1);
+
+ //mesc l("WARNING: Permanent boosts will return to their fruit form."), 1;
+ mesc l("WARNING: Status resets cannot be reverted!"), 1;
+
+ switch (select(lg("Yes, I am sure. Please reset my status!"),
+ lg("I need to think about it..."),
+ lg("I won't need it, thank you.")))
+ {
+ case 1:
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Let me just have a quick look at you. Hm... I will need %d GP to reset your stats.", .@raw_price);
+
+ select
+ rif(Zeny >= .@raw_price, l("Here, take as much as you need, I have plenty!")),
+ rif(Zeny > 0 && Zeny < .@raw_price, l("I don't have enough money...")),
+ rif(Zeny == 0, l("Oh no, I don't have any money on me right now.")),
+ l("I have to go, sorry.");
+
+ if (@menu > 1) {
+ return 0;
+ }
+
+ speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
+ l("Thank you."),
+ l("Now stand still... It should not take much time...");
+
+ // Reset status have an inventorycheck, so we charge later.
+ .@wasSP = StatusPoint;
+ StatusResetReinvest();
+
+ // Nothing to do: Do not charge (eg. you just got the fruits back)
+ if (StatusPoint == .@wasSP) {
+ speech S_LAST_NEXT,
+ l("It seems that you have no status points to reset!"),
+ l("Come back when you will really need me.");
+ } else {
+ Zeny-=.@raw_price;
+ speech S_LAST_NEXT,
+ l("Let's see... @@ of your status points have just been reset!", StatusPoint - .@wasSP),
+ l("Spend it wisely this time."),
+ l("But you are welcome to reset your stats again! I need the money.");
+ }
+ return .@wasSP;
+
+ case 2:
+ return 0;
+ case 3:
+ return 0;
+ }
+ //Exception("Unknown Error: ConfirmStatusReset() failed");
+ consolemes(CONSOLEMES_ERROR, "Unknown Error: ConfirmStatusReset() failed");
+ return 0;
+
+}
+
diff --git a/npc/functions/soul-menhir.txt b/npc/functions/soul-menhir.txt
new file mode 100644
index 00000000..3d4344c9
--- /dev/null
+++ b/npc/functions/soul-menhir.txt
@@ -0,0 +1,75 @@
+// Evol scripts.
+// Author:
+// gumi
+// Jesusalva
+// Description:
+// place of power, mana refills faster when sitting nearby
+
+- script Soul Menhir NPC_HIDDEN,{
+ if (!@menhir_meditation_message)
+ {
+ dispbottom(l("You feel a strong magic aura. You want to sit near it and meditate."));
+ @menhir_meditation_message=1;
+ }
+ end;
+
+OnRefill:
+ @menhir_lock = false;
+ getmapxy(.@map$, .@x, .@y, UNITTYPE_PC);
+
+ if (.@map$ != .map$ || distance(.x, .y, .@x, .@y) > .refill_distance ||
+ !(issit()))
+ end;
+
+ heal(0, .refill_rate);
+ end;
+
+
+OnTimer500:
+ .@count = getunits(BL_PC, .@units[0], false, .map$, (.x - .refill_distance),
+ (.y - .refill_distance), (.x + .refill_distance), (.y + .refill_distance));
+
+ for (.@i = 0; .@i < .@count; ++.@i)
+ {
+ if (.@units[.@i] < 0) continue; // pre-check, just in case
+ deltimer(.name$ + "::OnRefill", .@units[.@i]);
+ if (gettimer(TIMER_COUNT, .@units[.@i], .name$ + "::OnRefill") > 0 ||
+ getvariableofpc(@menhir_lock, .@units[.@i])) {
+ continue;
+ }
+ set(getvariableofpc(@menhir_lock, .@units[.@i]), true);
+ addtimer(rand(.refill_timer), .name$ + "::OnRefill", .@units[.@i]);
+ }
+
+ initnpctimer();
+ end;
+
+OnInit:
+ // Placeholder menhir doesn't have to run
+ if (.name$ == "Soul Menhir")
+ end;
+
+ // "Next-Generation" parsing system
+ // Syntax: RATE_DISTANCE_TIMER
+ // Soul Menhir#town_rate_dist_timer
+ // example
+ // Soul Menhir#hurns_1_7_200
+ .@n$=strnpcinfo(0, "_0_0_0");
+ explode(.@ni$, .@n$, "_");
+ .refill_rate=atoi(.@ni$[1]);
+ .refill_distance=atoi(.@ni$[2]);
+ .refill_timer=atoi(.@ni$[3]);
+
+ // number of SP to give every refill
+ if (!.refill_rate)
+ .refill_rate = 1;
+ // max distance
+ if (.refill_distance < 0)
+ .refill_distance = 7;
+ // wait rand(X) ms before refill
+ if (.refill_timer < 1)
+ .refill_timer = 200;
+
+ initnpctimer();
+ end;
+}