summaryrefslogtreecommitdiff
path: root/npc/008-1
diff options
context:
space:
mode:
Diffstat (limited to 'npc/008-1')
-rw-r--r--npc/008-1/4144.txt90
-rw-r--r--npc/008-1/_import.txt29
-rw-r--r--npc/008-1/_mobs.txt124
-rw-r--r--npc/008-1/_warps.txt33
-rw-r--r--npc/008-1/auldsbel.txt53
-rw-r--r--npc/008-1/banu.txt20
-rw-r--r--npc/008-1/blossom.txt77
-rw-r--r--npc/008-1/confused-tree.txt972
-rw-r--r--npc/008-1/crane.txt92
-rw-r--r--npc/008-1/doors.txt43
-rw-r--r--npc/008-1/hinnak.txt354
-rw-r--r--npc/008-1/jack.txt314
-rw-r--r--npc/008-1/mapflags.txt1
-rw-r--r--npc/008-1/marine.txt17
-rw-r--r--npc/008-1/mikhail.txt123
-rw-r--r--npc/008-1/milly.txt119
-rw-r--r--npc/008-1/old-man.txt89
-rw-r--r--npc/008-1/old-woman.txt136
-rw-r--r--npc/008-1/oscar.txt19
-rw-r--r--npc/008-1/rossy.txt391
-rw-r--r--npc/008-1/sabine.txt63
-rw-r--r--npc/008-1/sergeant-ryan.txt71
-rw-r--r--npc/008-1/shop.txt50
-rw-r--r--npc/008-1/sign.txt45
-rw-r--r--npc/008-1/snarfles.txt97
-rw-r--r--npc/008-1/soul-menhir.txt9
-rw-r--r--npc/008-1/voltain.txt18
-rw-r--r--npc/008-1/wateranimation.txt21
28 files changed, 3470 insertions, 0 deletions
diff --git a/npc/008-1/4144.txt b/npc/008-1/4144.txt
new file mode 100644
index 00000000..2c0ec327
--- /dev/null
+++ b/npc/008-1/4144.txt
@@ -0,0 +1,90 @@
+// Evol Script
+// Author:
+// Jesusalva
+// WildX
+// Description:
+// Andrei is not an human, according to studies conducted by TMW Team.
+// He seems to be a highly advanced artificial intelligence.
+// The fact that he was never seen contributes to this theory.
+// Other members opinions:
+// “4144 is a bot which sits on Hurnscald.” ~ Sagratha, 2016
+
+008-1,246,105,0 script Andrei NPC_PLAYER,{
+ function sittingBot;
+ function zealiteLore;
+ // TODO: Maybe we should use Karma here? For discussion
+ @is_billygates=(strcharinfo(0) == "WildX");
+ speech
+ l("Hi.");
+ next;
+ do
+ {
+ select
+ l("Hello."),
+ l("Can I sit on you?"),
+ l("What are you doing?");
+ mes "";
+ switch (@menu)
+ {
+ case 1:
+ break;
+ case 2:
+ sittingBot();
+ break;
+ case 3:
+ zealiteLore();
+ break;
+ }
+ } while (@menu != 1);
+
+ close;
+
+ // Sitting Bot
+ function sittingBot
+ {
+ // This is just an easter egg (for now)
+ if (@is_billygates) {
+ speech S_LAST_NEXT,
+ l("Only if everyone agrees. You'll need to do a vote for that."),
+ l("Just kidding.");
+ }
+
+ // Main dialog
+ speech S_LAST_NEXT,
+ l("I don't care, but there might be some adventurers and staff who might care."),
+ l("That's why you should always ask. This is good social etiqutte, you know?"),
+ l("Anyway, I would advise you to sit closer to the Soul Menhir, instead.");
+ return;
+ }
+
+ // Zealite Info
+ function zealiteLore
+ {
+ speech S_LAST_NEXT,
+ l("I am maintaing Hurnscald's Soul Menhir in working conditions."),
+ l("Soul Menhirs are pieces of Zealite Ore, really needed to cast magic around here."),
+ l("They are not like your usual Terra Ore. Zealite is way more magical and powerful."),
+ l("This is why sometimes people try to steal shards from it... Poor fools.");
+ // Note: On TMW-BR, it is possible to "hit" Soul Menhirs for shards, which allow you to
+ // instantly teleport back to savepoint, even if lore-wise that was prohibted.
+ // This reference doesn't means it is actually possible to try that at all here.
+ return;
+ }
+
+// TODO: Replace with a good sprite and dye robes in green
+OnInit:
+ .@npcId = getnpcid(.name$);
+ setunitdata(.@npcId, UDT_HEADTOP, FancyHat); // Wizard Hat
+ setunitdata(.@npcId, UDT_HEADMIDDLE, SilkRobe);
+ setunitdata(.@npcId, UDT_HEADBOTTOM, CottonGloves);
+ setunitdata(.@npcId, UDT_WEAPON, CottonBoots);
+
+ // What is 4144's hair? He is always wearing his wizard hat
+ setunitdata(.@npcId, UDT_HAIRSTYLE, 7);
+ setunitdata(.@npcId, UDT_HAIRCOLOR, rand(1,20));
+ npcsit;
+
+ .distance = 4;
+ end;
+}
+
diff --git a/npc/008-1/_import.txt b/npc/008-1/_import.txt
new file mode 100644
index 00000000..d09f8c88
--- /dev/null
+++ b/npc/008-1/_import.txt
@@ -0,0 +1,29 @@
+// Map 008-1: Hurnscald
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-1/4144.txt",
+"npc/008-1/_mobs.txt",
+"npc/008-1/_warps.txt",
+"npc/008-1/auldsbel.txt",
+"npc/008-1/banu.txt",
+"npc/008-1/blossom.txt",
+"npc/008-1/confused-tree.txt",
+"npc/008-1/crane.txt",
+"npc/008-1/doors.txt",
+"npc/008-1/hinnak.txt",
+"npc/008-1/jack.txt",
+"npc/008-1/mapflags.txt",
+"npc/008-1/marine.txt",
+"npc/008-1/mikhail.txt",
+"npc/008-1/milly.txt",
+"npc/008-1/old-man.txt",
+"npc/008-1/old-woman.txt",
+"npc/008-1/oscar.txt",
+"npc/008-1/rossy.txt",
+"npc/008-1/sabine.txt",
+"npc/008-1/sergeant-ryan.txt",
+"npc/008-1/shop.txt",
+"npc/008-1/sign.txt",
+"npc/008-1/snarfles.txt",
+"npc/008-1/soul-menhir.txt",
+"npc/008-1/voltain.txt",
+"npc/008-1/wateranimation.txt",
diff --git a/npc/008-1/_mobs.txt b/npc/008-1/_mobs.txt
new file mode 100644
index 00000000..4ca22849
--- /dev/null
+++ b/npc/008-1/_mobs.txt
@@ -0,0 +1,124 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-1: Hurnscald mobs
+008-1,270,86,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,271,89,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,273,87,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,276,88,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,275,90,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,280,87,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,279,89,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,282,89,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,283,86,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,203,70,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,198,70,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,193,70,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,188,70,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,183,70,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,185,72,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,203,74,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,198,74,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,193,74,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,188,74,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,180,76,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,185,76,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,190,76,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,195,76,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,198,78,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,193,78,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,188,78,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,183,78,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,180,80,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,200,80,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,160,97,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,154,95,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,148,97,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,160,101,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,156,105,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,154,99,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,152,101,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,152,105,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,146,99,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,146,103,0,0 monster Manana Tree 1017,1,420000,240000
+008-1,200,120,2,6 monster Mauve Plant 1036,3,1000,20000
+008-1,184,53,2,2 monster Cobalt Plant 1039,2,1000,30000
+008-1,183,143,6,2 monster Alizarin Plant 1037,3,1000,25000
+008-1,169,142,2,2 monster Pink Flower 1034,1,100,10000
+008-1,159,145,2,2 monster Pink Flower 1034,1,100,20000
+008-1,148,150,2,2 monster Pink Flower 1034,1,100,50000
+008-1,85,120,7,9 monster Mouboo 1023,5,30000,60000
+008-1,79,63,11,2 monster Spider 1044,2,4000,8000
+008-1,290,101,5,3 monster Butterfly 1032,3,10000,10000
+008-1,267,127,2,2 monster Butterfly 1032,2,10000,10000
+008-1,235,118,9,9 monster Butterfly 1032,3,10000,10000
+008-1,241,58,5,3 monster Butterfly 1032,3,10000,10000
+008-1,292,165,5,3 monster Butterfly 1032,3,10000,10000
+008-1,207,139,5,3 monster Butterfly 1032,3,10000,10000
+008-1,165,147,5,3 monster Butterfly 1032,3,10000,10000
+008-1,181,213,14,10 monster Log Head 1031,2,5000,30000
+008-1,244,160,31,11 monster Mana Bug 1035,7,10000,10000
+008-1,232,60,17,26 monster Mana Bug 1035,7,10000,10000
+008-1,275,103,1,0 monster Clover Patch 1033,1,10000,30000
+008-1,277,152,2,1 monster Clover Patch 1033,1,10000,30000
+008-1,203,130,1,0 monster Clover Patch 1033,1,10000,30000
+008-1,156,149,1,0 monster Clover Patch 1033,1,10000,30000
+008-1,193,113,1,0 monster Clover Patch 1033,1,10000,30000
+008-1,289,140,6,2 monster Maggot 1026,3,500,10000
+008-1,285,65,6,2 monster Maggot 1026,3,500,10000
+008-1,170,70,6,2 monster Maggot 1026,3,500,10000
+008-1,65,136,6,2 monster Maggot 1026,3,500,10000
+008-1,47,132,11,15 monster Forest Maggot 1028,7,500,2500
+008-1,120,113,16,11 monster Butterfly 1032,3,10000,10000
+008-1,104,183,11,7 monster Log Head 1031,3,5000,30000
+008-1,203,167,9,10 monster Log Head 1031,2,5000,30000
+008-1,66,185,7,11 monster Log Head 1031,2,5000,30000
+008-1,258,68,5,3 monster Pinkie 1030,2,3000,12000
+008-1,257,88,5,3 monster Pinkie 1030,2,3000,12000
+008-1,295,80,4,5 monster Pinkie 1030,3,2000,8000
+008-1,295,62,5,3 monster Pinkie 1030,2,3000,12000
+008-1,279,46,17,7 monster Silkworm 1040,4,3000,6000
+008-1,220,168,17,7 monster Silkworm 1040,2,3000,6000
+008-1,144,160,21,9 monster Silkworm 1040,4,3000,6000
+008-1,68,167,14,9 monster Silkworm 1040,3,3000,6000
+008-1,46,193,16,28 monster Grass Snake 1042,7,3000,12000
+008-1,166,114,14,5 monster Spiky Mushroom 1049,2,3000,6000
+008-1,128,48,4,5 monster Bandit 1063,1,4000,11000
+008-1,186,33,6,7 monster Spiky Mushroom 1049,4,3000,6000
+008-1,84,77,4,2 monster Scorpion 1043,1,6000,12000
+008-1,106,62,7,4 monster Mouboo 1023,1,30000,120000
+008-1,211,65,2,2 monster Pink Flower 1034,1,100,10000
+008-1,213,123,2,2 monster Pink Flower 1034,1,100,10000
+008-1,37,210,3,12 monster Wicked Mushroom 1050,7,3000,12000
+008-1,54,94,14,13 monster Spiky Mushroom 1049,2,3000,6000
+008-1,146,183,36,25 monster Forest Maggot 1028,12,500,2500
+008-1,77,96,7,5 monster Forest Maggot 1028,3,500,2500
+008-1,185,187,21,11 monster Butterfly 1032,3,10000,10000
+008-1,267,68,30,35 monster Squirrel 1041,7,10000,30000
+008-1,178,180,36,30 monster Squirrel 1041,12,10000,30000
+008-1,161,34,6,7 monster Scorpion 1043,2,6000,12000
+008-1,47,98,23,49 monster Butterfly 1032,5,10000,10000
+008-1,140,144,2,6 monster Mauve Plant 1036,3,1000,2000
+008-1,192,147,3,2 monster Gamboge Plant 1038,2,1000,10000
+008-1,197,136,2,5 monster Cobalt Plant 1039,2,1000,30000
+008-1,109,93,14,5 monster Spiky Mushroom 1049,2,3000,6000
+008-1,111,68,8,3 monster Robin Bandit 1064,2,8000,12000
+008-1,126,80,8,3 monster Bandit 1063,2,5500,8000
+008-1,122,44,4,7 monster Robin Bandit 1064,1,3000,8000
+008-1,259,116,31,20 monster Maggot 1026,6,500,10000
+008-1,221,70,8,11 monster Small Frog 1086,3,3000,30000
+008-1,190,166,8,11 monster Small Frog 1086,2,3000,30000
+008-1,88,197,8,26 monster Small Frog 1086,4,3000,30000
+008-1,228,62,15,11 monster Big Frog 1087,1,6000,60000
+008-1,225,162,15,11 monster Big Frog 1087,1,6000,60000
+008-1,88,190,15,11 monster Big Frog 1087,1,6000,60000
+008-1,124,173,20,23 monster Mouboo 1023,5,30000,60000
+008-1,162,42,36,12 monster Butterfly 1032,3,10000,10000
+008-1,186,52,2,0 monster Mauve Plant 1036,1,1000,20000
+008-1,179,25,5,3 monster Pinkie 1030,2,3000,12000
+008-1,228,107,5,12 monster Brotherhood Fighter 1081,2,6000,18000
+008-1,249,143,18,3 monster Brotherhood Fighter 1081,2,12000,18000
+008-1,283,158,7,5 monster Forest Maggot 1028,3,500,2500
+008-1,66,191,17,27 monster Forest Maggot 1028,5,5000,25000
+008-1,55,204,17,8 monster Spider 1044,2,4000,8000
+008-1,73,54,17,12 monster Bluepar 1088,2,12000,36000
+008-1,33,33,11,12 monster Wolvern 1117,2,10000,10000
+008-1,82,162,38,14 monster Wolvern 1117,3,18000,60000
diff --git a/npc/008-1/_warps.txt b/npc/008-1/_warps.txt
new file mode 100644
index 00000000..af0621c9
--- /dev/null
+++ b/npc/008-1/_warps.txt
@@ -0,0 +1,33 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-1: Hurnscald warps
+008-1,276,122,0 warp #008-1_276_122 0,0,008-2-0,26,23
+008-1,274,125,0 warp #008-1_274_125 0,0,008-2-0,23,34
+008-1,259,118,0 warp #008-1_259_118 0,0,008-2-1,33,42
+008-1,261,111,0 warp #008-1_261_111 0,0,008-2-1,38,27
+008-1,236,102,0 warp #008-1_236_102 0,0,008-2-2,28,33
+008-1,260,105,0 warp #008-1_260_105 0,0,008-2-6,27,32
+008-1,272,102,0 warp #008-1_272_102 0,0,008-2-7,36,28
+008-1,292,118,0 warp #008-1_292_118 0,0,008-2-8,36,38
+008-1,243,115,0 warp #008-1_243_115 0,0,008-2-9,30,34
+008-1,273,116,0 warp #008-1_273_116 0,0,008-2-10,37,33
+008-1,275,74,0 warp #008-1_275_74 0,0,008-2-16,25,33
+008-1,281,103,0 warp #008-1_281_103 0,0,008-2-12,30,31
+008-1,122,114,0 warp #008-1_122_114 0,0,008-2-22,30,34
+008-1,71,128,0 warp #008-1_71_128 0,0,008-2-23,52,39
+008-1,106,221,0 warp #008-1_106_221 0,0,008-2-24,32,45
+008-1,236,39,0 warp #008-1_236_39 0,0,008-2-17,52,39
+008-1,151,80,0 warp #008-1_151_80 0,0,008-2-15,35,33
+008-1,256,203,0 warp #008-1_256_203 0,0,008-2-20,25,31
+008-1,128,138,0 warp #008-1_128_138 0,0,008-3-1,35,34
+008-1,250,23,0 warp #008-1_250_23 1,0,008-3-4,88,76
+008-1,283,26,0 warp #008-1_283_26 0,0,008-3-3,37,56
+008-1,287,113,0 warp #008-1_287_113 0,0,008-2-8,26,28
+008-1,252,211,0 warp #008-1_252_211 0,0,008-2-21,22,42
+008-1,257,130,0 warp #008-1_257_130 0,0,008-2-28,25,31
+008-1,233,131,0 warp #008-1_233_131 0,0,008-2-29,36,24
+008-1,287,133,0 warp #008-1_287_133 0,0,008-2-30,52,39
+008-1,20,85,0 warp #008-1_20_85 0,1,008-1-1,246,85
+008-1,165,171,0 warp #008-1_165_171 0,0,008-3-2,175,21
+008-1,289,125,0 warp #008-1_289_125 0,0,008-2-31,29,25
+008-1,22,216,0 warp #008-1_22_216 0,0,009-1,248,48
+008-1,109,82,0 warp #008-1_109_82 0,0,008-3-5,92,107
diff --git a/npc/008-1/auldsbel.txt b/npc/008-1/auldsbel.txt
new file mode 100644
index 00000000..316bf604
--- /dev/null
+++ b/npc/008-1/auldsbel.txt
@@ -0,0 +1,53 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Auldsbel the Magician.
+// THIS IS A PLACEHOLDER!
+
+008-1,119,114,0 script Auldsbel NPC_WIZARD,{
+ // Placeholder please remove
+ if (!MASTERBOOK_PAGES)
+ {
+ inventoryplace MasterBook, 1;
+ getitem MasterBook, 1;
+ MASTERBOOK_PAGES=1;
+ mesc l("Auldsbel discretly stuffs a book on your backpack.");
+ next;
+ speech
+ l("Don't tell anyone about this. Once you kill you a boss, you can try to learn the boss skill by using the book."),
+ l("Beware you have a limited number of pages. Do not let the Legion or the Brotherhood find out you have one."),
+ l("And by the way. I know nothing about this book. And I don't know how to get more pages either.");
+ close;
+ }
+ speech
+ l("Hello."),
+ l("Oh, you look more interested in magic.. the brotherhood did forbid most of the interesting paths of magic, but boring baby spells are still allowed.");
+ // Give poor Auldsbel some weak magic D:
+ if (!MAGIC_CLU[EVOL_MONSTER_IDENTIFY]) {
+ mesn;
+ mesq l("May I interest you in an useless skill?");
+ ShowAbizit(true);
+ next;
+ mesc l("Identify Monsters - Unlocks the %s chat command.", "##B/mi##b");
+ mesc l("It will analyse and inform about the monster stats and drops.");
+ mesc l("If multiple monsters have same name, all of them will be listed.");
+ mesc l("Alias: %s", "##B@monsterinfo##b");
+ next;
+ mesn;
+ mesq l("May I interest you in an useless skill?");
+ mesc l("Skill: %s", getskillname(EVOL_MONSTER_IDENTIFY));
+ // FIXME You know that learn_magic has its own prompt, right?
+ if (askyesno() == ASK_YES) {
+ learn_magic(EVOL_MONSTER_IDENTIFY);
+ }
+ } else {
+ mesn;
+ mesq l("If you come back later, I may teach you something. But psst, practising magic is quite dangerous these days.");
+ }
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-1/banu.txt b/npc/008-1/banu.txt
new file mode 100644
index 00000000..05209a2c
--- /dev/null
+++ b/npc/008-1/banu.txt
@@ -0,0 +1,20 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Banu, the old lady.
+// THIS IS A PLACEHOLDER!
+
+008-1,244,88,0 script Banu NPC_OLD_LADY,{
+ speech
+ l("Hello."),
+ l("You don't have a scythe, by chance? I am too old to mew this field all alone."),
+ l("I asked Hinnak, but he wants at least a beer in exchange for his scythe."),
+ l("But I hate alcohol, so thats not an option for me.");
+
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-1/blossom.txt b/npc/008-1/blossom.txt
new file mode 100644
index 00000000..57782b20
--- /dev/null
+++ b/npc/008-1/blossom.txt
@@ -0,0 +1,77 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Blossom the flower-seller girl.
+// THIS IS A PLACEHOLDER!
+
+008-1,198,138,0 script Blossom NPC_BLOSSOM,{
+ speech
+ l("Hi, my name is Blossom."),
+ l("Strange, it seems I became younger lately."),
+ l("Are you in need of some flowers?");
+
+ do
+ {
+ select
+ l("I love flowers! What do you have for sale?"),
+ l("Not now, thank you."),
+ l("Dont you know something about fertility? I heard rumors."),
+ l("Do you sell Flower Seeds?");
+
+ mes "";
+ switch (@menu)
+ {
+ case 1:
+ closeclientdialog;
+ shop "#Invisible008-1";
+ close;
+ case 2:
+ speech S_FIRST_BLANK_LINE,
+ l("Oh, ok. Come back later if you need something.");
+ close;
+ case 3:
+ /*
+ speech S_FIRST_BLANK_LINE,
+ l("I heard something too. A girl named Galimatia seems to need help. If only those lazy developers could tell her what she needs.");
+ */
+ mesn;
+ mesq l("I heard something too. A girl named Galimatia seems to need help.");
+ next;
+ mesn;
+ mesq l("But I believe Oscar gave her a fertility recipe...?");
+ next;
+ mesn;
+ mesq l("...Oops, I'm not supposed to say that. Oscar is... Well... Either a genius or a madman, I can't say.");
+ break;
+ case 4:
+ mesn;
+ mesq l("No I don't, but I can exchange them. 3 %s for a %s.", getitemlink(GrassSeeds), getitemlink(FlowerSeeds));
+ next;
+ /*
+ // TODO: Add Andra
+ mesn;
+ mesq l("If you need the opposite, look for Andra.");
+ */
+ if (countitem(GrassSeeds) < 3)
+ break;
+
+ mesc l("Trade with %s?", .name$);
+ if (askyesno() == ASK_YES) {
+ inventoryplace FlowerSeeds, 1;
+ delitem GrassSeeds, 3;
+ getitem FlowerSeeds, 1;
+ mesn;
+ mesq l("Thanks for the trade.");
+ next;
+ }
+ break;
+ }
+ } while (true);
+
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-1/confused-tree.txt b/npc/008-1/confused-tree.txt
new file mode 100644
index 00000000..aead40ed
--- /dev/null
+++ b/npc/008-1/confused-tree.txt
@@ -0,0 +1,972 @@
+// Evol scripts.
+// Author:
+// gumi
+// Based on CrazyTree, originally made by:
+// gumi
+// pclouds
+// veryape
+// wushin
+// Description:
+// emulated confused tree prototype
+
+// ~t lowercase hot word regex
+
+008-1,255,109,0 script Confused Tree NPC_CONFUSED_TREE,14,14,{
+
+ function tree_panel {
+ if (is_trusted() == false && #Tree_Trusted == false)
+ {
+ narrator(l("You see a tree."));
+ if (getq(HurnscaldQuests_Inspector) == 2)
+ {
+ select(
+ l("Have you seen anything strange lately?"),
+ l("Do you know anything about the recent robberies?"));
+
+ narrator(S_FIRST_BLANK_LINE,
+ l("..."),
+ l("It doesn't reply."));
+ }
+ close;
+ }
+
+ function clear_db {
+ clear();
+ mes(l("##BWARNING:##b you are about to permanently empty the quote database."));
+ next();
+ mes(l("Do you want to continue?"));
+
+ select(
+ l("Abort!"),
+ l("Empty the quote DB"));
+
+ if (@menu == 2)
+ {
+ .@sentence$ = "I am an idiot";
+ mes(l("Please write the following sentence:"));
+ mes("");
+ mesf(" ##B%s.", .@sentence$);
+ input(.@confirm$);
+
+ if (!startswith(strtoupper(.@confirm$), strtoupper(.@sentence$))) {
+ mes(l("Invalid!"));
+ close;
+ }
+
+ query_sql("TRUNCATE TABLE tree_quotes;");
+ mes(l("Database erased."));
+ next();
+ }
+
+ return;
+ }
+
+ function list_commands {
+ clear();
+ mes(l("To grab a quote:"));
+ mes(col(" ~grab ##Bplayer name##b", 7));
+ next();
+ mes(l("To get a quote:"));
+ mes(col(" ~quote anyone", 7));
+ mes(col(" ~quote ##Bplayer name##b", 7));
+ mes(col(" ~quote ##B#number##b", 7));
+ next();
+ mes(l("To remove a quote:"));
+ mes(col(" ~remove quote ##B#number##b", 7));
+ mes(col(" ~remove last quote", 7));
+ next();
+ mes(l("Last seen:"));
+ mes(col(" ~seen ##Bplayer name##b", 7));
+ next();
+ mes(l("To ignore a player:"));
+ mes(col(" ~ignore ##Bplayer name##b", 7));
+ next();
+ mes(l("To unignore a player:"));
+ mes(col(" ~unignore ##Bplayer name##b", 7));
+ next();
+
+ if (is_admin())
+ {
+ mes(l("To trust a player:"));
+ mes(col(" ~trust ##Bplayer name##b", 7));
+ next();
+ mes(l("To de-trust a player:"));
+ mes(col(" ~untrust ##Bplayer name##b", 7));
+ next();
+ }
+ return;
+ }
+
+ do
+ {
+ clear();
+ setnpcdialogtitle(l("Tree Control Panel"));
+ mes(l("Oh noes! You found my secret backdoor!"));
+ next();
+ mes(l("Please select an option:"));
+
+ select(
+ l("List the commands"),
+ rif(is_admin(), l("Empty the quote DB")),
+ l("Dance for me"));
+
+ switch (@menu)
+ {
+ case 1: list_commands(); break;
+ case 2: clear_db(); break;
+ default: speech(l("Too lazy.")); close;
+ }
+
+ } while (true);
+
+ end;
+ }
+
+ // utility functions below
+
+ function check_is_ignored {
+ .@val = htget(.ignore_ht, strcharinfo(PC_NAME), 0);
+
+ if (.@val > gettimetick(2))
+ {
+ ++.ignored_times;
+ end;
+ }
+
+ else if (.@val > 0)
+ {
+ htput(.ignore_ht, strcharinfo(PC_NAME), 0); // remove expired entries
+ }
+
+ return;
+ }
+
+ function special_name {
+ .@name$ = strcharinfo(PC_NAME);
+ .@low$ = strtolower(.@name$);
+
+ if (rand(.sname_rate) == 0)
+ {
+ for (.@i = 0; .@i < .alias; .@i += 2)
+ {
+ if (.@low$ ~= .alias$[.@i])
+ {
+ explode(.@aliases$, .alias$[.@i+1], "`");
+ .@name$ = .@aliases$[rand(getarraysize(.@aliases$))];
+ break;
+ }
+ }
+ }
+
+ return .@name$;
+ }
+
+ function face {
+ if (gettimetick(2) - .last_emote < .emote_rate)
+ {
+ ++.ignored_times;
+ return;
+ }
+
+ .last_emote = gettimetick(2);
+ return emotion(getarg(0, E_SURPRISE));
+ }
+
+ function rp {
+ // used for queries
+ return replacestr(getarg(0,""), "~t", strtolower("(?:" + .name$ + "|" + .hotwords$ + ")"));
+ }
+
+ function format_reply {
+ // used for replies
+ .@str$ = getarg(0, "");
+
+ // search for {{mustaches}}
+ while (.@str$ ~= "{{([^}]+)}}")
+ {
+ .@sub$ = replacestr($@regexmatch$[1], " ", ""); // remove whitespaces
+ .@sub$ = strtolower(.@sub$); // always lowercase the var name
+ .@capitalize = .@titlecase = .@allcaps = false;
+
+ if (charat(.@sub$, 0) == "^")
+ {
+ .@capitalize = true;
+ .@sub$ = substr(.@sub$, 1, getstrlen(.@sub$) - 1); // strip first char
+ }
+
+ else if (charat(.@sub$, 0) == "+")
+ {
+ .@titlecase = true;
+ .@sub$ = substr(.@sub$, 1, getstrlen(.@sub$) - 1); // strip first char
+ }
+
+ else if (charat(.@sub$, 0) == "!")
+ {
+ .@allcaps = true;
+ .@sub$ = substr(.@sub$, 1, getstrlen(.@sub$) - 1); // strip first char
+ }
+
+ if (compare(.@sub$, ",")) {
+ .@var$ = sprintf(".H%s$", substr(md5(.@sub$), 0, 25));
+
+ if (getelementofarray(getd(.@var$), 1) == "") {
+ explode(.@sub2$, .@sub$, ",");
+ .@size = 1;
+
+ for (.@i = 0; .@i < getarraysize(.@sub2$); ++.@i) {
+ .@subsize = getd(sprintf(".D_%s", .@sub2$));
+ copyarray(getelementofarray(getd(.@var$), .@size), getd(sprintf(".D_%s$[1]", .@sub2$)), .@subsize);
+ .@size += .@subsize;
+ }
+ }
+ } else {
+ .@var$ = sprintf(".D_%s$", .@sub$);
+ }
+
+ .@rep$ = relative_array_random(getd(.@var$));
+
+ if (.@capitalize) .@rep$ = capitalize(.@rep$);
+ else if (.@titlecase) .@rep$ = titlecase(.@rep$);
+ else if (.@allcaps) .@rep$ = strtoupper(.@rep$);
+
+ .@str$ = replacestr(.@str$, $@regexmatch$[0], .@rep$); // remove the mustache, replace by value
+ }
+
+ // search for emotes
+ if (.@str$ ~= "%%([^ ])")
+ {
+ // only handling a few of them
+ switch (ord($@regexmatch$[1]))
+ {
+ case 73: face(any(E_WINK, E_ANGEL)); break;
+ case 83: face(any(E_SAD, E_CRYING)); break;
+ case 85: face(E_SURPRISE); break;
+ case 93: face(any(E_HEARTEYE, E_HEART)); break;
+ case 94: face(E_DISGUST); break;
+ case 99: face(E_DEAD); break;
+ case 105: face(E_CRYING); break;
+ case 106:
+ case 91: face(any(E_SPEECH, E_BLAH)); break;
+ case 107: face(E_INSULTBUBBLE); break;
+ default: .@unhandled = true;
+ }
+
+ if (.@unhandled != true)
+ {
+ if (.@str$ == $@regexmatch$[0]) end; // don't send handled, emote-only messages
+ .@str$ = replacestr(.@str$, " "+ $@regexmatch$[0], ""); // otherwise strip the emote
+ }
+ }
+
+ // built-in variables
+ .@str$ = replacestr(.@str$, "~n", .name$); // npc name
+ .@str$ = replacestr(.@str$, "~p", special_name()); // player name or special name
+ .@str$ = replacestr(.@str$, "~P", strcharinfo(PC_NAME)); // unaltered player name
+
+ return rp(.@str$);
+ }
+
+ function strip_colors {
+ .@str$ = replacestr(getarg(0, ""), "##0", "");
+ .@str$ = replacestr(.@str$, "##1", "");
+ .@str$ = replacestr(.@str$, "##2", "");
+ .@str$ = replacestr(.@str$, "##3", "");
+ .@str$ = replacestr(.@str$, "##4", "");
+ .@str$ = replacestr(.@str$, "##5", "");
+ .@str$ = replacestr(.@str$, "##6", "");
+ .@str$ = replacestr(.@str$, "##7", "");
+ .@str$ = replacestr(.@str$, "##8", "");
+ .@str$ = replacestr(.@str$, "##9", "");
+ return replacestr(.@str$, "##a", "");
+ }
+
+ function strip_formatting {
+ .@str$ = strip_colors(getarg(0, ""));
+ .@str$ = replacestr(.@str$, "##B", "");
+ return replacestr(.@str$, "##b", "");
+ }
+
+ function delayed_reply {
+ ++.answered_times;
+ @tree_reply$ = getarg(0, "");
+ addtimer(.delay_reply, .name$ + "::OnDoReply");
+ return;
+ }
+
+ function reply {
+ .@reply$ = format_reply(getarg(0, ""));
+ getmapxy(.@pc_map$, .@pc_x, .@pc_y, UNITTYPE_PC); // get char location
+
+ if (((.@reply$ == .last_reply$ && gettimetick(2) - .last_reply < .repeat_rate)
+ || gettimetick(2) - .last_reply < .talk_rate
+ || (gettimetick(2) - .blocked < .block_time && is_trusted() == false)
+ || .@pc_map$ != .map$
+ || distance(.x, .y, .@pc_x, .@pc_y) > .distance
+ || .@reply$ == "")
+ && is_dev() == false)
+ {
+ ++.ignored_times;
+ return;
+ }
+
+ .last_reply = gettimetick(2);
+ .last_reply$= .@reply$;
+
+ delayed_reply(.@reply$);
+ return;
+ }
+
+ function seen_me {
+ if (playerattached() > 0 && htexists(.seen_ht))
+ {
+ htput(.seen_ht, strcharinfo(PC_NAME), gettimetick(2));
+ }
+ return;
+ }
+
+ function have_you_seen {
+ .@player$ = getarg(0, "");
+ .@player = getcharid(CHAR_ID_ACCOUNT, .@player$);
+
+ if (.@player > 0)
+ {
+ // nested if, because they don't short-circuit
+ if (checkoption(Option_Invisible, .@player) == false) {
+ delayed_reply(sprintf("Player `%s` is currently online.", .@player$));
+ end;
+ }
+ }
+
+ .@time = htget(.seen_ht, .@player$, 0);
+
+ if (.@time < 1)
+ delayed_reply(sprintf("I haven't seen player `%s` today.", .@player$));
+
+ else
+ delayed_reply(sprintf("Player `%s` was last seen %s.", .@player$, FuzzyTime(.@time, 0, 99)));
+
+ end;
+ }
+
+ function special_drops {
+ .@drop$ = relative_array_random(.drops$);
+ .@name$ = strcharinfo(PC_NAME);
+ .@low$ = strtolower(.@name$);
+
+ if (rand(.sdrop_rate) == 0)
+ {
+ for (.@i = 0; .@i < .sdrops; .@i += 2)
+ {
+ if (.@low$ ~= .sdrops$[.@i])
+ {
+ explode(.@d$, .sdrops$[.@i+1], "`");
+ .@drop$ = .@d$[rand(getarraysize(.@d$))];
+ break;
+ }
+ }
+ }
+
+ return .@drop$;
+ }
+
+ function roll_dice {
+ .@dices = max(min(getarg(0, 1), 8), 1); // 1..8
+ .@sides = max((getarg(1, 6) < 1 ? 6 : getarg(1, 6)), 1); // 1..MAX_INT
+
+ .@result$ = sprintf("*rolls the dice%s: %d",
+ rif(.@dices > 1, "s"), rand(1, .@sides)); // first dice
+
+ for (.@d = 1; .@d < .@dices; ++.@d)
+ {
+ .@result$ += ", " + rand(1, .@sides);
+ }
+
+ return .@result$ + ".*";
+ }
+
+ function flip_coin {
+ .@coins = getarg(0, 1);
+
+ .@result$ = sprintf("*flips the coin%s: %s",
+ rif(.@coins > 1, "s"), (rand(2) == 1 ? "heads" : "tails")); // first coin
+
+ for (.@c = 1; .@c < .@coins; ++.@c)
+ {
+ .@result$ += ", " + (rand(2) == 1 ? "heads" : "tails");
+ }
+
+ return .@result$ + ".*";
+ }
+
+ function roulette {
+ if (.roulette == 1)
+ {
+ npctalk("*pulls the trigger: *##BBANG##b*.*");
+ delayed_reply("*reloads and spins the chambers.*");
+ .roulette = rand(1, 7); // the Nagant_M1895 has 7 chambers
+
+ // now the fun part
+ nude();
+ percentheal(-100, 0);
+ }
+
+ else
+ {
+ delayed_reply("*pulls the trigger: *click*.*");
+ .roulette = (.roulette == 7 ? 1 : .roulette + 1);
+ }
+
+ end;
+ }
+
+ function monologue_player {
+ return sprintf("Your current monologue is at least %d line%s long.",
+ @monologue, rif(@monologue != 1, "s"));
+ }
+
+ function who_player {
+ return sprintf("You seem to be ##B~P##b [%i:%i].",
+ getcharid(CHAR_ID_ACCOUNT), getcharid(CHAR_ID_CHAR));
+ }
+
+ function make_quote_table {
+ // Do not modify this
+ query_sql("CREATE TABLE IF NOT EXISTS `tree_quotes` ("
+ " `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,"
+ " `char_id` INT(11) UNSIGNED NOT NULL DEFAULT '0',"
+ " `grabber` INT(11) UNSIGNED NOT NULL DEFAULT '0',"
+ " `timestamp` INT(10) UNSIGNED NOT NULL DEFAULT '0',"
+ " `message` VARCHAR(150) NOT NULL DEFAULT '',"
+ " PRIMARY KEY (`id`),"
+ " KEY `char_id` (`char_id`),"
+ " KEY `grabber` (`grabber`)"
+ ") ENGINE=MyISAM;");
+
+ .last_query = gettimetick(2);
+ return;
+ }
+
+ function grab_quote {
+ .@name$ = getarg(0, "");
+
+ if (gettimetick(2) - .last_query < (is_trusted() ? .qpoll_rate : .qpoll_rate2))
+ {
+ ++.ignored_times;
+ end;
+ }
+
+ if (.@name$ == strcharinfo(PC_NAME))
+ {
+ delayed_reply("##BError: You may not grab yourself.");
+ end;
+ }
+
+ explode(.@tmp$[0], htget(.msg_ht, .@name$, ""), ":"); // get last message, if any
+ htput(.msg_ht, .@name$, ""); // ensure you can't grab twice the same message
+
+ .@char_id = atoi(.@tmp$[0]); // grab the char id part
+
+ if (.@char_id < 1)
+ {
+ delayed_reply(sprintf("##BError: I couldn't find anything to grab from player `%s`.", .@name$));
+ end;
+ }
+
+ .@msg$ = implode(.@tmp$, ":"); // put it back together
+ .@start = getstrlen(.@tmp$[0]) + getstrlen(.@tmp$[1]) + 2; // char:time:msg <= we just want the msg part
+ .@msg$ = escape_sql(strip_formatting(substr(.@msg$, .@start, getstrlen(.@msg$) - 1))); // sanitize
+
+ if (.@msg$ == "")
+ {
+ delayed_reply("##BError: Message is empty or malformed. It cannot be grabbed.");
+ end;
+ }
+
+ else if (.@msg$ ~= "^[!#~@]?(?:grab)?shield(?:ed)?(?:[:.!]? .*)?$")
+ {
+ delayed_reply("##BError: Message is shielded.");
+ end;
+ }
+
+ query_sql(sprintf("INSERT INTO tree_quotes (char_id,grabber,timestamp,message) VALUES (%i,%i,%i,'%s');",
+ .@char_id, getcharid(CHAR_ID_CHAR), gettimetick(2), .@msg$));
+
+ query_sql("SELECT MAX(id) FROM tree_quotes;", .q_last_id); // get the last quote id
+
+ .last_query = gettimetick(2);
+
+ delayed_reply(sprintf("Success: Quote grabbed. (#%i)", .q_last_id));
+ end;
+ }
+
+ function remove_quote {
+ .@tmp = getarg(0, 0);
+
+ if (gettimetick(2) - .last_query < (is_trusted() ? .qpoll_rate : .qpoll_rate2))
+ {
+ ++.ignored_times;
+ end;
+ }
+
+ query_sql(sprintf("SELECT id FROM tree_quotes WHERE id = %i ORDER BY id DESC LIMIT 1;", .@tmp), .@id); // check if it exists
+
+ if (.@id < 1)
+ {
+ delayed_reply(sprintf("##BError: I couldn't find quote #%i in the database.", .@tmp));
+ end;
+ }
+
+ query_sql(sprintf("DELETE FROM tree_quotes WHERE id = %i ORDER BY id DESC LIMIT 1;", .@id));
+
+ .last_query = gettimetick(2);
+
+ delayed_reply(sprintf("Success: Quote removed. (#%i)", .@id));
+ end;
+ }
+
+ function cite_quote {
+ .@id = getarg(0,0);
+
+ if (gettimetick(2) - .last_query < (is_trusted() ? .qpoll_rate : .qpoll_rate2))
+ {
+ ++.ignored_times;
+ end;
+ }
+
+ query_sql(sprintf("SELECT t.id, c.name AS grabee, d.name AS grabber, t.timestamp, t.message "
+ "FROM `tree_quotes` t "
+ "JOIN `char` c ON t.char_id = c.char_id "
+ "JOIN `char` d ON t.grabber = d.char_id "
+ "WHERE t.id=%i ORDER BY t.id DESC LIMIT 1;",
+ .@id),
+ .@nid[0], .@grabee$[0], .@grabber$[0], .@time[0], .@msg$[0]);
+
+ .last_query = gettimetick(2);
+
+ if (.@nid[0] < 1)
+ {
+ delayed_reply(sprintf("##BError: I couldn't find quote #%i in the database.", .@id));
+ end;
+ }
+
+ delayed_reply(sprintf("<%s> ##B%s##b ##a— grabbed by %s %s.",
+ .@grabee$[0], .@msg$[0], .@grabber$[0], FuzzyTime(.@time[0],0,1)));
+ end;
+ }
+
+ function random_quote {
+ .@name$ = escape_sql(getarg(0, ""));
+
+ if (gettimetick(2) - .last_query < (is_trusted() ? .qpoll_rate : .qpoll_rate2))
+ {
+ ++.ignored_times;
+ end;
+ }
+
+ query_sql("SELECT t.id, c.name AS grabee, d.name AS grabber, t.timestamp, t.message "
+ "FROM `char` c "
+ "JOIN `tree_quotes` t ON t.char_id = c.char_id "
+ "JOIN `char` d ON d.char_id = t.grabber " +
+ rif(.@name$ != "", sprintf("WHERE c.name='%s' ", .@name$)) +
+ "ORDER BY RAND() LIMIT 1;",
+ .@nid[0], .@grabee$[0], .@grabber$[0], .@time[0], .@msg$[0]);
+
+ .last_query = gettimetick(2);
+
+ if (.@nid[0] < 1)
+ {
+ if (.@name$ != "")
+ delayed_reply(sprintf("##BError: I couldn't find any quote from `%s` in the database.", getarg(0, "")));
+ else
+ delayed_reply("##BError: The quote database is empty.");
+ end;
+ }
+
+ delayed_reply(sprintf("<%s> ##B%s##b ##a— grabbed by %s %s. (#%i)",
+ .@grabee$[0], .@msg$[0], .@grabber$[0], FuzzyTime(.@time[0],0,1), .@nid[0]));
+ end;
+ }
+
+ function trigger_hotword {
+ .@o$ = getarg(0, ""); // original lowercase
+ .@m$ = replacestr(.@o$, "*", ""); // original lowercase clean
+
+
+ if (.@m$ ~= "(?:^| )tell(?: (?:me|him|her|us|them))? a(?:n ?other| lame| bad| boring)? joke")
+ reply(relative_array_random(.jokes$));
+
+ else if (.@m$ ~= "(?:^| )heal me(?:$|[^a-z])")
+ reply(relative_array_random(.healing$));
+ // XXX: maybe actually heal the player once in a while
+
+ else if (.@m$ ~= "(?:^| )(?:what|who) are you")
+ reply(relative_array_random(.whoami$));
+
+ else if (.@m$ ~= rp("(?:^| )(?:hi+|hello|heya?|hiya|good (?:morning|afternoon))[^a-z]* .*~t|~t.* (?:hi+|hello|heya?|hiya)"))
+ {
+ .blocked = 0;
+ .@rpl$ = relative_array_random(.greetings$);
+ reply(.@rpl$);
+ }
+
+ else if (.@o$ ~= rp("(?:^[*]| )(?:kicks?|shakes?) .*~t"))
+ reply(special_drops());
+
+ else if (.@o$ ~= rp("(?:^[*]| )(?:cuts?|nukes?|kills?|chops? down|saws?|hews?|murders?) .*~t"))
+ reply(relative_array_random(.kill$));
+
+ else if (.@o$ ~= rp("(?:^[*]| )pokes? .*~t"))
+ reply(relative_array_random(.poke$));
+
+ else if (.@o$ ~= rp("(?:^[*]| )(?:waters?|pees?|licks?) .*~t"))
+ reply(relative_array_random(.disgusting$));
+
+ else if (compare(.@m$, " answer ") && .@m$ ~= "(?:life|universe|everything)(?:$|[^a-z])")
+ reply(relative_array_random(.answer$));
+
+ else if (.@o$ ~= rp("(?:^[*]| )(?:burns?|incinerates?|ignites?) .*~t"))
+ reply(relative_array_random(.burning$));
+ // XXX: maybe here send a fire particle effect
+
+ else if (.@m$ ~= rp("(?:^| )die ~t"))
+ reply(relative_array_random(.die$));
+
+ else if (.@o$ ~= rp("(?:^[*]| )bites? .*~t|(?:^[*]| )drops? .* on ~t"))
+ reply(relative_array_random(.silly$));
+
+ else if (.@m$ ~= rp("(?:^| )(?:loves?|hugs?|kiss(es)?) .*~t|~t.* love(?:$|[^a-z])"))
+ reply(relative_array_random(.love$));
+
+ else if (.@m$ ~= rp("(?:^| )dance .*~t|~t.* dance(?:$|[^a-z])"))
+ reply(relative_array_random(.dance$));
+
+ else if (.@m$ ~= rp("(?:^| )hates? .*~t"))
+ reply(relative_array_random(.hate$));
+
+ else if (.@o$ ~= rp("(?:^[*]| )(?:eats?|shoots?|plucks?|tortures?|slaps?|slaps?|poisons?|breaks?|stabs?|throws?|punch(?:es)?) .*~t"))
+ reply(relative_array_random(.pain$));
+
+ else if (.@o$ ~= rp("(?:^[*]| )(?:climbs?|rides?|mounts?) .*~t"))
+ reply(relative_array_random(.climb$));
+
+ else if (.@m$ ~= "(?:^| )(?:see y(?:a|ou)|good night|(?:bye)?bye+)(?:$|[^a-z])")
+ reply(relative_array_random(.bye$));
+
+ else if (.@m$ ~= rp("(?:^| )bad ~t"))
+ reply(relative_array_random(.bad$));
+
+ else if (.@m$ ~= "(?:^| )(?:how old are you|uptime)(?:$|[^a-z])")
+ reply("%%B Server uptime: " + FuzzyTime(.uptime, 1, 99) + ".");
+
+ else if (.@m$ ~= "(?:^| )how chatty are you(?:$|[^a-z])")
+ reply("%%B Answered " + .answered_times + " times, ignored " + .ignored_times + " times.");
+
+ else if (.@m$ ~= "(?:^| )what.* version(?:$|[^a-z])")
+ reply("%%B ~n, version " + .version + "."); // XXX: maybe return Hercules version and serverdata commit instead
+
+ else if (.@m$ ~= "(?:^| )(?:(?:8|eight)[ -]?ball|(?:should|would|will|do|does) (?:i|you|he|she|it|we|they))(?:$|[^a-z])")
+ reply(relative_array_random(.eightball$));
+
+ else if (.@m$ ~= "(?:^| )roll(?: a| the)? dice(?:$|[^a-z])")
+ reply(roll_dice(1, 6));
+
+ else if (.@m$ ~= "(?:^| )roll(?: a)? ([1-8])d((?:[1-9][0-9]{0,10})?)(?:$|[^0-9a-z])")
+ reply(roll_dice(atoi($@regexmatch$[1]), atoi($@regexmatch$[2])));
+
+ else if (.@m$ ~= "(?:^| )roll ([1-8]) dices?(?:$|[^a-z])")
+ reply(roll_dice(atoi($@regexmatch$[1]), 6));
+
+ else if (.@m$ ~= "(?:^| )(?:flip|toss)(?: a| the)? coin(?:$|[^a-z])")
+ reply(flip_coin(1));
+
+ else if (.@m$ ~= "(?:^| )(?:flip|toss) ([1-8]) coins?(?:$|[^a-z])")
+ reply(flip_coin(atoi($@regexmatch$[1])));
+
+ else if (.@m$ ~= "(?:^| )(?:press|pull)(?: the)? trigger(?:$|[^a-z])")
+ roulette();
+
+ else if (.@m$ ~= "(?:^| )(?:how long|what) is(?: my)? monologue(?:$|[^a-z])")
+ reply(monologue_player());
+
+ else if (.@m$ ~= "(?:^| )who am i(?:$|[^a-z])")
+ reply(who_player());
+
+ else if (.@m$ ~= "(?:^| )shut up(?:$|[^a-z])")
+ {
+ reply(relative_array_random(.shut_up$));
+ .blocked = gettimetick(2);
+ }
+
+ else if (rand(.dunno_rate) == 0)
+ reply(relative_array_random(.no_idea$));
+
+ else
+ ++.ignored_times;
+
+ end;
+ }
+
+ function trigger_hiall {
+ if (rand(.hiall_rate) == 0)
+ reply(relative_array_random(.greetings$));
+
+ else
+ ++.ignored_times;
+
+ end;
+ }
+
+OnClick:
+ tree_panel();
+ end;
+
+
+OnTalkNearby:
+ .@no_nick$ = strip(strip_formatting(substr($@p0$, getstrlen(strcharinfo(PC_NAME)) + 3, getstrlen($@p0$) - 1))); // not very obvious stuff
+ .@no_nick_lower$ = strtolower(.@no_nick$); // FIXME: hercules doesn't have a way to do case insensitive regex yet
+ .@no_nick_clean$ = replacestr(.@no_nick_lower$, "*", "");
+
+ htput(.msg_ht, strcharinfo(PC_NAME), getcharid(CHAR_ID_CHAR) + ":" + gettimetick(2) + ":" + .@no_nick$); // log last message, for quotegrabs
+ .lastsender = getcharid(CHAR_ID_CHAR); // for monologue
+
+ .last_activity = gettimetick(2); // for the auto-janitor
+
+ if ((is_trusted() || #Tree_Trusted) && charat(.@no_nick$, 0) == .symbol$)
+ {
+ if (.@no_nick$ ~= "^.grab \"?([^#:@\"]{4,23})\"?$")
+ reply(grab_quote($@regexmatch$[1]));
+
+ else if (.@no_nick$ ~= "^.(?:ungrab|remove|delete)(?: quote)? #([0-9]+)$")
+ reply(remove_quote(atoi($@regexmatch$[1])));
+
+ else if (.@no_nick$ ~= "^.(?:ungrab|remove|delete)(?: last(?: quote)?)?$")
+ reply(remove_quote(.q_last_id));
+
+ else if (.@no_nick$ ~= "^.(?:quote|cite) #([0-9]+)$")
+ reply(cite_quote(atoi($@regexmatch$[1])));
+
+ else if (.@no_nick$ ~= "^.(?:(?:random )?quote|cite)(?: anyone| someone| random)?$")
+ reply(random_quote());
+
+ else if (.@no_nick$ ~= "^.(?:quote|cite) \"?([^#:@\"]{4,23})\"?$")
+ reply(random_quote($@regexmatch$[1]));
+
+ else if (.@no_nick$ ~= "^.seen \"?([^#:@\"]{4,23})\"?$")
+ reply(have_you_seen($@regexmatch$[1]));
+
+ // to allow trusted testers to reboot without knowing the exit code
+ else if (debug && .@no_nick$ ~= "^.re(?:boot|load|start)(?:(?: the)? server)?$")
+ {
+ announce("The server is rebooting. This may take a couple minutes.", bc_all);
+ sleep2(1000);
+ atcommand("@serverexit 104");
+ }
+
+ // exit, pull all, clean, build, reboot
+ else if (debug && .@no_nick$ ~= "^.re-?build(?:(?: the)? server)?$")
+ {
+ announce("The server is rebuilding. This will take several minutes.", bc_all);
+ sleep2(1000);
+ atcommand("@serverexit 108");
+ }
+
+ else if (.@no_nick$ ~= "^.(?:add )?ignored? \"?([^#:@\"]{4,23})\"?$")
+ {
+ .@chr = getcharid(CHAR_ID_ACCOUNT, $@regexmatch$[1]);
+ if (.@chr < 1)
+ {
+ reply("##BError: Player not found or not online.");
+ end;
+ }
+ htput(.ignore_ht, strcharinfo(PC_NAME, .@chr), gettimetick(2) + 3600);
+ reply(sprintf("Success: Player `%s` is now ignored for 1 hour.",
+ strcharinfo(PC_NAME, .@chr)));
+ }
+
+ else if (.@no_nick$ ~= "^.(?:un|de-?|remove )ignored? \"?([^#:@\"]{4,23})\"?$")
+ {
+ .@chr = getcharid(CHAR_ID_ACCOUNT, $@regexmatch$[1]);
+ if (.@chr < 1)
+ {
+ reply("##BError: Player not found or not online.");
+ end;
+ }
+ htput(.ignore_ht, strcharinfo(PC_NAME, .@chr), 0);
+ reply(sprintf("Success: Player `%s` is no longer ignored.",
+ strcharinfo(PC_NAME, .@chr)));
+ }
+
+ else if (is_admin() && .@no_nick$ ~= "^.(?:add )?trust(?:ed)? \"?([^#:@\"]{4,23})\"?$")
+ {
+ .@chr = getcharid(CHAR_ID_ACCOUNT, $@regexmatch$[1]);
+ if (.@chr < 1)
+ {
+ reply("##BError: Player not found or not online.");
+ end;
+ }
+ set(getvariableofpc(#Tree_Trusted, .@chr), true);
+ reply(sprintf("Success: Player `%s` can now use restricted commands.",
+ strcharinfo(PC_NAME, .@chr)));
+ }
+
+ else if (is_admin() && .@no_nick$ ~= "^.(?:un|de-?|remove )trust(?:ed)? \"?([^#:@\"]{4,23})\"?$")
+ {
+ .@chr = getcharid(CHAR_ID_ACCOUNT, $@regexmatch$[1]);
+ if (.@chr < 1)
+ {
+ reply("##BError: Player not found or not online.");
+ end;
+ }
+ set(getvariableofpc(#Tree_Trusted, .@chr), false);
+ reply(sprintf("Success: Player `%s` can no longer use restricted commands.",
+ strcharinfo(PC_NAME, .@chr)));
+ }
+
+ else
+ reply("##BError: Command not found or invalid syntax.");
+ }
+
+ else if (.@no_nick_lower$ ~= rp("^(~t[^a-z ]* .*|(?:.* (?:~t[^a-z ]* .*|~t[^ a-z]*)))$"))
+ {
+ check_is_ignored();
+ trigger_hotword($@regexmatch$[1]);
+ }
+
+ else if (.@no_nick_clean$ ~= "^(hi(ya)?|hello|heya?) (all|friends|every(one|body))")
+ {
+ check_is_ignored();
+ trigger_hiall();
+ }
+
+ else
+ {
+ if (.lastsender == getcharid(CHAR_ID_CHAR))
+ @monologue++;
+
+ else
+ @monologue = 1;
+ }
+
+ // TODO: eliza mode, whisper eliza mode
+ end;
+
+OnTouch:
+ if (rand(.touch_rate) == 0) {
+ face();
+ }
+ end;
+
+OnDoReply:
+ if (@tree_reply$ != "") {
+ npctalk(@tree_reply$);
+ @tree_reply$ = "";
+ }
+ end;
+
+OnPCLogoutEvent:
+ seen_me();
+ end;
+
+OnTimer3600000:
+ // scheduled janitor
+ .@now = gettimetick(2);
+ initnpctimer(); // schedule next
+
+ if (.last_activity > (.@now - 3600)) {
+ end; // last activity is too recent
+ }
+
+ // cleanup routine below
+ .lastsender = 0;
+ .last_activity = 0;
+ .last_reply = 0;
+ .last_emote = 0;
+ .last_query = 0;
+ .blocked = 0;
+ .enable_janitor = 0;
+
+ htclear(.msg_ht); // empty the message table (quotegrabs)
+ htclear(.ignore_ht); // empty the ignore table
+
+ .@it = htiterator(.seen_ht); // allocate new iterator
+ for (.@key$ = htinextkey(.@it); hticheck(.@it); .@key$ = htinextkey(.@it)) {
+ if (.@key$ == "") {
+ continue;
+ }
+
+ if (htget(.seen_ht, .@key$, 0) < (.@now - 86400)) {
+ htput(.seen_ht, .@key$, 0); // remove from hash table if older than 24h
+ }
+ }
+ htidelete(.@it); // free the iterator
+
+ face(); // do an emote (because why not)
+ end;
+
+
+OnDay0320:
+ .dir = DOWNLEFT;
+ end;
+
+
+OnDay0621:
+ .dir = LEFT;
+ end;
+
+
+OnDay0922:
+ .dir = UPLEFT;
+ end;
+
+
+OnDay1221:
+ .dir = DOWN;
+ end;
+
+
+OnInit:
+ // config below
+ .hotwords$ = "tree"; // what hot words the npc should listen to, besides its own name (regex)
+ .distance = 14; // the npc will only listen to player within X tiles
+ .dir = season_direction(); // sprite direction according to the season
+ .talk_rate = 1; // min number of seconds to wait between replies
+ .repeat_rate = 1; // min number of seconds to wait before sending the same message twice in a row
+ .block_time = 600; // how long to stay quiet after someone says shut up, in seconds
+ .emote_rate = 3; // min number of seconds to wait between emotes
+ .sdrop_rate = 8; // 1 in X chances to get a special drop
+ .sname_rate = 8; // 1 in X chances to get a special name
+ .dunno_rate = 2; // 1 in X chances to get a reply when the command is not found
+ .hiall_rate = 2; // 1 in X chances to reply to a "hi everyone"
+ .touch_rate = 4; // 1 in X chances to trigger the OnTouch action
+ .qpoll_rate = 1; // min number of seconds to wait before calling the sql db again for GMs
+ .qpoll_rate2 = 5; // min number of seconds to wait before calling the sql db again for non-GMs (currently unused)
+ .delay_reply = 250; // number of ms to wait to reply
+ .enable_janitor = true; // automatically free memory when idle
+ .symbol$ = "~"; // symbol for GM-only commands
+
+ // register some arrays
+ callfunc("TREE_dictionaries");
+
+ // do random stuff
+ make_quote_table();
+ face();
+
+ // boring stuff below
+ .version[0] = 21; // increase this when you make a change
+ .version[1] = 1;
+ .uptime = gettimetick(2);
+ .alwaysVisible = true; // the NPC doesn't de-spawn when moving away
+ .pid = 1; // regex pattern id
+ .msg_ht = htnew(); // hashtable id for message history
+ .seen_ht = htnew(); // hashtable id for seen log
+ .ignore_ht = htnew(); // hashtable id for ignored players
+ .roulette = rand(1, 7); // spin the chambers
+ defpattern(.pid, "^(.*)$", "OnTalkNearby");
+ activatepset(.pid);
+ if (.enable_janitor) {
+ initnpctimer();
+ }
+}
+
+// Duplicates below
+//000-1,42,63,0 duplicate(Confused Tree) Confused Palm Tree NPC_NO_SPRITE,14,14
diff --git a/npc/008-1/crane.txt b/npc/008-1/crane.txt
new file mode 100644
index 00000000..3a22fa47
--- /dev/null
+++ b/npc/008-1/crane.txt
@@ -0,0 +1,92 @@
+// TMW scripts.
+// Author:
+// Micksha
+// Description:
+// Crane is Snarfles' apprentice, who secretly eats mouboo steak and enjoys.
+
+008-1,97,113,0 script Crane NPC_SNARFLES,{
+ function foodQuest;
+
+ mesn;
+ mesq l("Heya. I am Crane, Snarfle's apprentice.");
+ if (getq(General_SmearedHands) <= 3 && getq2(General_SmearedHands) != 1)
+ foodQuest();
+ close;
+
+function foodQuest {
+ .@q=getq(General_SmearedHands);
+ next;
+ mesn;
+ mesq l("Don't tell him, but, I secretly love %s!", getitemlink(MoubooSteak));
+ switch (.@q) {
+ case 1:
+ next;
+ mesn strcharinfo(0);
+ select
+ l("Do you know a recipe for %s?", getitemname(BarbecuePlate)),
+ l("Okay, I won't.");
+ mes "";
+ if (@menu == 2)
+ break;
+ mesn;
+ mesq l("Ah sure, it is a simple recipe, I could even make one for you and give you the recipe, but...");
+ next;
+ mesn;
+ mesq l("I always get smeared hands eating it and cannot play cards anymore with Snarfles.");
+ next;
+ mesn;
+ mesq l("Well, if you find me a solution for that problem, I can give you the recipe. What do you say?");
+ next;
+ mesc l("WARNING: If you accept this quest, you'll be struck at the %s route!", b(l("Carnivour"))), 1;
+ mesc l("This will also make %s's Quest unavailable.", b("Snarfles")), 1;
+ mesc l("This decision cannot be changed later."), 1;
+ next;
+ mesc l("Accept this request?"), 1;
+ if (askyesno() == ASK_YES) {
+ setq General_SmearedHands, 2, CARNIVOROUS; // 2 = Carnivorous
+ mesn;
+ mesq l("Great! I'll be eager for your return!");
+ }
+ break;
+ case 2:
+ mesn;
+ mesq l("Have you found a solution for my smeared hands problem?");
+ next;
+ select
+ l("No, not yet.");
+ mes "";
+ mesn;
+ mesq l("I've heard they're related to the earl of sandwich, so maybe a sandwich maker could help... *sigh* I want to play cards...");
+ break;
+ case 3:
+ mesn strcharinfo(0);
+ select
+ l("Have you tried putting it in a bread already?"),
+ l("I'll keep looking for solutions for your problem.");
+ mes "";
+ if (@menu == 2)
+ return;
+ mesn;
+ mesq l("Actually... No. Have been too afraid of it tasting foul.");
+ next;
+ mesn strcharinfo(0);
+ mesq l("Really? Tiki, Candor's chef, liked it very much.");
+ next;
+ mesn;
+ mesq l("Wha - Really?! Tiki said it tasted good??! I'm saved! You're truly my savior!!");
+ next;
+ mesn;
+ mesq l("I'll put the %s recipe on your %s. Thanks, you saved my day!", getitemlink(BarbecuePlate), getitemlink(RecipeBook));
+ RECIPES[CraftBarbecuePlate]=true;
+ getitembound BarbecuePlate, 1, IBT_ACCOUNT;
+ setq1 General_SmearedHands, 4; // Finished
+ default:
+ return;
+ }
+ return;
+}
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-1/doors.txt b/npc/008-1/doors.txt
new file mode 100644
index 00000000..7ad1d705
--- /dev/null
+++ b/npc/008-1/doors.txt
@@ -0,0 +1,43 @@
+// The Mana World scripts.
+// Author:
+// Jesusalva
+// Description:
+// Rossy Quest
+
+008-1,49,157,0 script #RossyCaveInit NPC_HIDDEN,0,0,{
+ end;
+
+OnTouch:
+ if (getq(HurnscaldQuests_Rossy) != 16)
+ {
+ // Normal warping
+ warp "008-3-0", 129, 112;
+ }
+ else
+ {
+ // HurnscaldQuests_Rossy
+ // (MAIN QUEST, CAVE CONTROL, INSTANCE CONTROL)
+ .@inst=getq3(HurnscaldQuests_Rossy);
+ .@mapn$="ross@"+getcharid(0);
+ // NOTE: .@inst >= 0 skipped now that inst=0 refers to La Marine
+ if (isinstance(.@inst) && instanceowner(.@inst) == getcharid(3))
+ {
+ // Renew instance for 15 minutes
+ //instance_set_timeout(900, 900, .@inst);
+ // FIXME: Clean unkilled monsters
+ } else {
+ .@inst = instance_create("ROSSY "+getcharid(0), getcharid(3), IOT_CHAR);
+ instance_attachmap("008-3-0", .@inst, false, .@mapn$);
+ // Instance lasts 20 minutes
+ instance_set_timeout(ROSSY_INSTIME, ROSSY_INSTIME, .@inst);
+ instance_init(.@inst);
+ setq3 HurnscaldQuests_Rossy, .@inst;
+ // Reset quest progress
+ setq2 HurnscaldQuests_Rossy, 0;
+ @rossylock=false;
+ }
+ // Warp to instanced map
+ warp .@mapn$, 129, 112;
+ }
+ end;
+}
diff --git a/npc/008-1/hinnak.txt b/npc/008-1/hinnak.txt
new file mode 100644
index 00000000..65d050e7
--- /dev/null
+++ b/npc/008-1/hinnak.txt
@@ -0,0 +1,354 @@
+// Evol scripts.
+// Author:
+// gumi, Micksha
+// Quest states:
+// [1] 0 - cannot do the quest
+// [1] 1 - can do the quest
+// [1] 2 - hinnak asked for help
+// [1] 3 - helped hinnak
+// [2] kill counter
+// Description:
+
+// Hinnak needs help to get rid of the same stuff than ever.
+
+008-1,270,74,0 script Hinnak#008-1 NPC_HINNAK,{
+
+ if (BaseLevel < .min_level)
+ {
+ npctalk3 generic(1 | 16 | 64);
+ end;
+ }
+
+ function hinn_new_player
+ {
+ if(getequipid(EQI_HEAD_TOP) == .bad_hat)
+ {
+ narrator 4,
+ l("The farmer lunges at you with a farming implement.");
+ heal -50, 0;
+
+ selectd
+ l("I'm out of here."),
+ l("Whoa, what are you doing?");
+
+ if (@menu == 1)
+ {
+ return;
+ }
+
+ speech 4 | 1,
+ l("Sorry, you look like a pinkie."),
+ l("They've been destroying my fields, and I guess I got a bit worked up.");
+ }
+
+ else
+ {
+ speech 4,
+ l("Argh!"),
+ l("I hate them!"),
+ l("I @#$% hate them!"),
+ l("I @#$% hate these @#$% pinkies!");
+
+ selectd
+ l("You need some anger control therapy."),
+ l("Why do you hate them?");
+
+ if (@menu == 1)
+ {
+ return;
+ }
+
+ speech 4 | 1,
+ l("These @#$% beasts are jumping around in my fields destroying all my harvest."),
+ l("But they are too fast."),
+ l("I can't catch them.");
+ }
+
+ selectd
+ l("Want me to help you?");
+
+ speech 4 | 1,
+ l("Yes, you look quite fast."),
+ l("Maybe you can catch some of them."),
+ l("That will pay them a lesson."),
+ l("Slay some of them and bring me %d of their antennae.", .drop_count);
+
+ setq .quest, 2, 0;
+
+ selectd
+ l("How much is this worth to you?");
+
+ speech 1,
+ l("Well, I can't offer you much."),
+ l("But I got an old scythe laying around."),
+ l("Maybe you can use it as a weapon.");
+
+ close;
+ }
+
+ function hinn_help
+ {
+ if (getequipid(EQI_HEAD_TOP) == .bad_hat)
+ {
+ narrator 4,
+ l("The farmer glares at your hat.");
+ }
+
+ speech 4,
+ l("Have you got the %d antennae?", .drop_count);
+
+ selectd
+ l("Not yet, but I am working on it."),
+ rif(countitem(.monster_drop) >= .drop_count, l("Sure, here they are!"));
+
+ if (@menu == 1)
+ {
+ return;
+ }
+
+ if (getq2(.quest) < .kill_count)
+ {
+ speech 1,
+ l("Don't try to fool me!"),
+ l("I know you didn't kill them yourself!"),
+ l("Kill at least %d pinkies and come back.", .kill_count);
+ close;
+ }
+
+ speech 1,
+ l("Thank you very much"),
+ l("As promised, here's my old scythe."),
+ l("Maybe you can use it as a weapon."),
+ l("It is a bit cumbersome but its strikes are deadly.");
+
+ if (countitem(.monster_drop) >= .drop_count)
+ {
+ delitem .monster_drop, .drop_count;
+ getitem .reward_item, 1;
+ quest_gp(.maxLevel, .reward_money);
+ //getexp .reward_exp, 0;
+ setq .quest, 3;
+ }
+ close;
+ }
+
+ function hinn_thanks
+ {
+ if (getequipid(EQI_HEAD_TOP) == .bad_hat)
+ {
+ speech 4,
+ l("That better be a trophy on your head.");
+
+ selectd
+ l("It is.");
+
+ speech 4 | 1,
+ l("Good then."),
+ l("Thanks for your help with the pinkies.");
+ }
+
+ else
+ {
+ speech 4,
+ l("Good to see you again."),
+ l("Thanks again for helping me with the pinkies!");
+ }
+
+ selectd
+ l("Sure, any time!"),
+ l("Anything else you want me to do?"),
+ l("You're welcome. Bye!");
+
+ if (@menu == 3)
+ {
+ return;
+ }
+
+ speech 4 | 1,
+ l("Actually, it's been a long day."),
+ l("If it's no trouble, could you get me a %s?",
+ getitemlink(.drink_item));
+
+ selectd
+ rif(countitem(.drink_item) >= 1, l("Here you are.")),
+ l("Sure, I'll go get one. Bye!"),
+ l("You shouldn't drink while working!");
+
+ do
+ {
+ switch (@menu)
+ {
+ case 2: return;
+ case 3:
+ speech 1,
+ l("Well, I'm done for the day, and I'm quite old enough to decide when I can have a %s, thank you!",
+ getitemname(.drink_item));
+ selectd
+ rif(countitem(.drink_item) >= 1, l("Sorry... here you are.")),
+ l("I don't have any.");
+ break;
+ default:
+ if (countitem(.drink_item) < 1)
+ {
+ return;
+ }
+ delitem .drink_item, 1;
+
+ narrator 4 | 8 | 2 | 1,
+ l("%s takes a sip.", .name$);
+
+ speech 4,
+ l("Aaah!"),
+ l("Nothing like a well-deserved %s after a long day of tending the crops!",
+ getitemname(.drink_item)),
+ l("Thanks, that was very kind of you!");
+
+ narrator 4 | 8 | 1 | 2,
+ l("He takes another sip.");
+
+ speech 4,
+ l("Thanks!"),
+ l("You know, I had the strangest thing happen to me."),
+ l("I had this patch of ground that was really clumpy; lots of clay, you see."),
+ l("Right over there."),
+ // TODO: move cam to the spot
+ l("Looks much better now, doesn't it?"),
+ // TODO: restore cam
+ l("But how I got there is kind of scary..."),
+ l("I'd been trying to break it up for a while, but that kind of work is a pain."),
+ l("So my wife said that I should go and see the witch, just in case she knows something."),
+ l("And sure enough I ask the witch, and she has a look at it."),
+ l("“Nothing I can do”, she says, “but I can ask a friend”."),
+ l("So the next day another witch shows up."),
+ l("Gorgeous woman, but when she looked at me, the scares went scuttling down my spine..."),
+ l("First thing she asked was if I'm a farmer."),
+ l("Said her friend had told her that I needed help."),
+ l("I show her what the problem is, and she tells me to go inside and wait.");
+
+ narrator 4 | 8 | 1 | 2,
+ l("%s drains his mug in one long sip, then hesitates.", .name$);
+
+ speech 4,
+ l("So I go inside."),
+ l("I'm barely in when it starts raining outside, pouring cats and mouboos!"),
+ l("Not so weird, perhaps, except that it was been bright and sunny just a second before!"),
+ l("So I rush out, my wife telling me to leave the witch alone, and I see her standing there in the middle of the rain..."),
+ l("None of the raindrops touched her, as if they were afraid!"),
+ l("Then she yells out some gobbledygook word, and out of the ground there comes a swarm of maggots, crawling and digging and climbing over each other's backs..."),
+ // XXX: maybe here insert a reference to SUSAN?
+ l("And then she turns to me!"),
+ l("Seeing her gaze, for a moment there I thought she would turn me into a pinkie, for sure..."),
+ l("But all she says is, “had you stayed inside, you wouldn't be wet now”.");
+
+ selectd
+ l("Hahaha!"),
+ l("Whoah, scary..."),
+ l("What was that gobbledygook word?"),
+ l("I better go now. Bye.");
+
+ switch (@menu)
+ {
+ case 1:
+ speech 1,
+ l("Yeah, funny now..."),
+ l("But you should've seen that gaze!"),
+ l("Ah, well, never mind.");
+ close;
+ case 2:
+ speech 1,
+ l("Yeah, you could say that...");
+ close;
+ case 3:
+ speech 1,
+ l("Oh, I can't be sure..."),
+ l("But something like “Nanaj princino”, I think."); // this is "Dwarven Princess" translated to Esperanto
+ close;
+ }
+ return;
+ }
+ } while(true);
+ }
+
+ // OnTalk:
+
+ if (getq(.quest_inspector) == 11)
+ {
+ selectd
+ l("Did you see anyone in a mask come by here at night?"),
+ l("Did you see anyone with a large satchel come by here at night?"),
+ l("Hello.");
+
+ switch (@menu)
+ {
+ case 1:
+ speech
+ l("No."),
+ l("It tends to be too dark to see a mask.");
+ close;
+
+ case 2:
+ speech
+ l("Yes, I saw someone with a large sack on their back go to the mining camp.");
+ close;
+ }
+ }
+
+ switch (getq(.quest))
+ {
+ case 0:
+ case 1: hinn_new_player; break;
+ case 2: hinn_help; break;
+ default: hinn_thanks;
+ }
+
+ closeclientdialog();
+ close;
+
+OnNPCKillEvent:
+ // XXX: maybe have a OnTakeScript on the pinky antena item so we count pickups instead of kills
+ if (killedrid == .monster_id && getq(.quest) == 2 &&
+ getq2(.quest) < .kill_count && strcharinfo(PC_MAP) == .map$)
+ {
+ setq .quest, 2, getq2(.quest) + 1;
+ }
+ end;
+
+OnPCLoginEvent:
+OnPCBaseLvUpEvent:
+ if (BaseLevel >= .min_level && getq(.quest) < 1)
+ {
+ setq .quest, 1; // allow the player to do the quest
+ dispbottom l("New quest available: %s (level %d+)",
+ getquestlink(.quest), .min_level); // XXX: requires new manaplus versions, maybe show a different message for old versions?
+ }
+ end;
+
+OnInit:
+ .min_level = 15; // min level to do the quest
+ .maxLevel = getiteminfo(Scythe, ITEMINFO_ELV) + 20;
+ .monster_id = Pinkie; // monster to kill
+ .monster_drop = PinkAntennae; // monster drop to collect
+ .drop_count = 10; // amount of that drop needed
+ .kill_count = 10; // min number of kills
+ .reward_item = Scythe; // reward item
+ .reward_money = 0; // reward money
+ .reward_exp = 0; // reward exp
+ .bad_hat = PinkieHat; // hinnak attacks you when you wear this hat
+ .drink_item = Beer; // the item hinnak asks to drink
+
+ .quest = HurnscaldQuests_Hinnak;
+ .quest_inspector = HurnscaldQuests_Inspector;
+ .quest_debug = .quest;
+ .distance = 3;
+
+////////// UNFINISHED //////////
+////////////////////////////////
+// REMOVE THIS CODE WHEN THIS //
+// NPC IS NO LONGER A WIP //////
+////////////////////////////////
+//if (!debug) disablenpc(.name$);
+///////// UNFINISHED ///////////
+
+ end;
+}
+
diff --git a/npc/008-1/jack.txt b/npc/008-1/jack.txt
new file mode 100644
index 00000000..fd16d965
--- /dev/null
+++ b/npc/008-1/jack.txt
@@ -0,0 +1,314 @@
+// Evol scripts.
+// Author:
+// gumi
+// Quest states (forest bow):
+// [1] 0 - cannot do the quest
+// [1] 1 - can do the quest
+// [1] 2 - alan wants to ask jack
+// [1] 3 - jack explained problem
+// [1] 4 - alan asks to find wood
+// [1] 5 - found perfect wood
+// [1] 6 - got the bow
+// [2] fail count
+// [3] unused
+// [t] unused
+// Quest states (wooden shield):
+// [1] 0 - cannot do the quest
+// [1] 1 - can do the quest
+// [1] 2 - jack proposes shield
+// [1] 3 - player accepted quest
+// [1] 4 - got the shield
+// [2] unused
+// [3] unused
+// [t] unused
+// Description:
+// Jack Lumber, the handsome lumberjack
+
+
+008-1,241,116,0 script Jack NPC_LUMBERJACK,{
+
+ function bow_intro {
+ speech(4,
+ l("Why not?!"),
+ l("I value my life, that's why!"));
+
+ selectd(l("What do you mean?"));
+
+ speech(4,
+ l("A week ago, I was going to chop down one of those twigleaf trees in the forest to the southwest."),
+ l("These twigleafs are the trees that give me the living wood you speak of."), // XXX: were Log Heads named "Twigleaf" at some point in the past?
+ l("I was just chopping away with my axe, and guess what happened?"),
+ l("One of its branches hit me!"),
+ l("At first, I thought it fell down or the wind blew it, but it hurt!"),
+ l("After I shook it off and struck the tree again with my axe, another branch hit me!"),
+ l("I got angry and started to chop off all the low-hanging branches so this couldn't happen anymore."),
+ l("Even after all that though, I still can't believe what happened next."));
+
+ selectd(l("What happened?"));
+
+ speech(4,
+ l("You'll think I'm insane if I tell you..."));
+
+ selectd(l("I won't. I promise."));
+
+ speech(4,
+ l("Alright, well..."),
+ l("After I chopped off a few branches, the whole tree started to move!"),
+ l("Its roots tore out of the earth, all the branches started to wave around, and a face appeared on the trunk."),
+ l("The whole tree CAME TO LIFE! It was mad!"));
+
+ selectd(l("Did you run away?"), l("Did you fight it?"));
+
+ speech(4,
+ l("I fought it, of course!"),
+ l("I took my axe and attacked the beast!"),
+ l("It hit me here *points at a bruise on his shoulder*, here *lifts his trouser leg to show another bruise*, and here *lifts his shirt and reveals even worse bruises*."), // XXX: that's kinda dirty imho... maybe we could use the narrator?
+ l("But I didn't give up!"),
+ l("I chopped away at it, branch after branch, and in the end I chopped off its roots, and it fell to the ground, motionless."));
+
+ selectd(l("So you beat the monster? Then why are you so scared?"));
+
+ speech(4,
+ l("Well, I was exhausted and had to rest."),
+ l("A few minutes passed, and suddenly I was practically surrounded by a dozen or more of these living trees!"));
+
+ selectd(l("Did you fight them too?"));
+
+ speech(4,
+ l("Are you crazy?"),
+ l("I barely destroyed one of those beasts."),
+ l("I was in no shape to fight again!"),
+ l("I ran away as fast as I could, and lucky for me the monsters aren't that fast on their tiny root legs, Ha!"));
+
+ selectd(l("So, I guess you aren't chopping down trees anymore?"));
+
+ speech(4,
+ l("I still do; it's my job."),
+ l("But I'll no longer chop those twigleafs, I'll tell you that."),
+ l("I know the bow master wants some twigleaf wood, but I don't care."),
+ l("I won't risk MY life for a few gold pieces!"),
+ l("If you really want to, just go to the southwest, but I can't help you."),
+ l("I won't go there ever again."));
+
+ selectd(l("Southwest you say? OK, thank you."));
+
+ speech(l("Don't say I didn't warn you!"));
+
+ // What a huge text wall, I feel sorry for the players
+
+ close2;
+ setq(.quest_bow, 3);
+ end;
+ }
+
+ function bow_good_luck {
+ if (getq(.quest_inspector) == 2)
+ {
+ speech(4,
+ l("Good luck hunting those tree monsters – you'll need it."));
+
+ selectd(l("Have you seen anything that might be connected to the recent robberies in town?"));
+
+ speech(l("Sorry, no."));
+ close;
+ }
+
+ npctalk3(l("Good luck hunting those tree monsters – you'll need it."));
+ end;
+ }
+
+ function shield_intro {
+ speech(4,
+ l("I have an idea."),
+ l("What would you say about a new shield?"));
+
+ setq(.quest_shield, 2);
+
+ selectd(
+ l("No thanks."),
+ l("Yes, please!"),
+ rif(getq(.quest_inspector) == 2, l("Have you seen anything that might be connected to the recent robberies in town?")));
+
+ switch (@menu)
+ {
+ case 1: closeclientdialog(); close;
+ case 2:
+ speech(
+ l("All I need is %d %s.", .logs_amount, getitemlink(.logs_item)),
+ l("This needn't be high quality wood; pretty much any log you can find should work."),
+ l("Oh, and I'll also need %s E for other materials.", format_number(.shield_cost)));
+
+ close2;
+ setq(.quest_shield, 3);
+ end;
+ case 3: speech(l("Sorry, no.")); close;
+ }
+ }
+
+ function bow_congrats {
+ speech(4,
+ l("You've finally found that perfect piece of living wood that Alan needs to make a Forest Bow, haven't you?"));
+
+ selectd(
+ l("I couldn't afford the bow, though..."),
+ l("No, I'm still looking."),
+ l("Yes, I've got the Forest bow now."),
+ l("I'm a melee warrior, I don't need bows."),
+ rif(getq(.quest_inspector) == 2, l("Have you seen anything that might be connected to the recent robberies in town?")));
+
+ switch (@menu)
+ {
+ case 3:
+ if (getq(.quest_bow) <= 5)
+ {
+ speech(4,
+ l("Hrmph."),
+ l("I'm someone who respects those speaking the truth."));
+ }
+ // fallthrough
+ case 1:
+ case 4:
+ speech(4,
+ l("You no doubt remember how I struggled with those beasts, fighting for my life."),
+ l("Scared me, those seven-branched little stumps did!"),
+ l("Never since that day have I strayed near them, and yet there you are, cutting them down one by one."),
+ l("I'm proud of you – to dare to fight those trunks is admirable indeed."),
+ l("You're as strong as if you were my own child!"));
+
+ shield_intro;
+ break;
+ case 2: speech(l("You should go talk to Alan again.")); close;
+ case 5: speech(l("Sorry, no.")); close;
+ }
+ }
+
+ function shield_make {
+ speech(4,
+ l("Do you have the %d %s and %s E for the shield?",
+ .logs_amount, getitemlink(.logs_item), format_number(.shield_cost)));
+
+ selectd(
+ rif(countitem(.logs_item) >= .logs_amount && Zeny >= .shield_cost,
+ l("Here it is.")),
+ l("I'll come back later."));
+
+ if (@menu != 1) {
+ closeclientdialog();
+ close;
+ }
+
+ speech(4,
+ l("Have a seat."));
+
+ narrator(4,
+ l("Jack saws the logs into pieces and then sands them until they are smooth to the touch."),
+ l("Applying some strong-smelling liquid, he tans them to a darker hue."),
+ l("Grabbing one of two leftover pieces, he begins to carve it into a round shape, then repeats this with the second piece – shield handles from what you can tell."),
+ l("Meanwhile, the sun has dried the other pieces."),
+ l("Jack places them next to each other, adds a frame, and nails everything together."),
+ l("The resulting shield looks usable already, but Jack applies another liquid to it and leaves it to dry for a few moments."),
+ l("Finally, he hands the shield to you."));
+
+ if (checkweight(.shield_item, 1) != true)
+ {
+ speech(
+ l("It seems you can't carry the %s.", getitemlink(.shield_item)),
+ l("Come back when you do."));
+ close;
+ }
+
+ if (Zeny < .shield_cost || countitem(.logs_item) < .logs_amount)
+ close; // double-check
+
+ setq(.quest_shield, 4);
+ delitem(.logs_item, .logs_amount);
+ getitem(.shield_item, 1);
+ Zeny -= .shield_cost;
+ quest_xp(.maxLevel, .shield_exp);
+
+ speech(
+ l("Enjoy your new shield!"));
+
+ close;
+ }
+
+ function wood_daily {
+ speech(4,
+ l("I hope that my shield will serve you well!"));
+
+ selectd(
+ l("Me too."),
+ rif(getq(.quest_inspector) == 2, l("Have you seen anything that might be connected to the recent robberies in town?")));
+
+ switch (@menu)
+ {
+ case 2: speech(l("Sorry, no.")); close;
+ }
+
+ closeclientdialog(); // TODO: daily quest (needs the generic daily quest script)
+ close;
+ }
+
+ // OnTalk:
+ switch (getq(.quest_shield))
+ {
+ case 2: shield_intro; break;
+ case 3: shield_make; break;
+ case 4: wood_daily; break;
+ }
+
+ switch (getq(.quest_bow))
+ {
+ case 3:
+ case 4: bow_good_luck; break;
+ case 5:
+ case 6: bow_congrats; break;
+ }
+
+ // initial intro
+ {
+ speech(4,
+ l("Hello there!"),
+ l("My name is Jack Lumber, the enemy of all trees."),
+ l("If you need some firewood, just let me know."));
+
+ selectd(
+ l("I'll keep that in mind."),
+ rif(getq(.quest_inspector) == 2, l("Have you seen anything that might be connected to the recent robberies in town?")),
+ rif(getq(.quest_bow) == 2, l("I heard you aren't delivering any more living wood. Why not?")));
+
+ switch (@menu)
+ {
+ case 2: speech(l("Sorry, no.")); close;
+ case 3: bow_intro; break;
+ }
+
+ }
+
+ closeclientdialog();
+ close;
+
+OnInit:
+ .logs_item = RawLog;
+ .logs_amount = 40; // XXX: maybe nlogn?
+ .shield_cost = 5000; // XXX: maybe nlogn?
+ .shield_exp = 2500;
+ .shield_item = WoodenShield;
+ .maxLevel = getiteminfo(WoodenShield, ITEMINFO_ELV) + 20;
+
+ .quest_bow = HurnscaldQuests_ForestBow;
+ .quest_shield = HurnscaldQuests_WoodenShield;
+ .quest_inspector = HurnscaldQuests_Inspector;
+ .quest_debug = .quest_bow;
+ .distance = 3;
+
+////////// UNFINISHED //////////
+////////////////////////////////
+// REMOVE THIS CODE WHEN THIS //
+// NPC IS NO LONGER A WIP //////
+////////////////////////////////
+//if (!debug) disablenpc(.name$);
+///////// UNFINISHED ///////////
+
+ end;
+}
diff --git a/npc/008-1/mapflags.txt b/npc/008-1/mapflags.txt
new file mode 100644
index 00000000..f2680964
--- /dev/null
+++ b/npc/008-1/mapflags.txt
@@ -0,0 +1 @@
+008-1 mapflag town
diff --git a/npc/008-1/marine.txt b/npc/008-1/marine.txt
new file mode 100644
index 00000000..ca448a2e
--- /dev/null
+++ b/npc/008-1/marine.txt
@@ -0,0 +1,17 @@
+// Moubootaur Legends scripts.
+// Authors:
+// Jesusalva
+// Description:
+// This script controls access to Ships, fixing variables.
+
+// Use NPC_LA_MARINE if needed
+008-1,327,104,0 script La Marine#H NPC_HIDDEN,0,0,{
+ end;
+
+OnTouch:
+ EnterTown("Hurns");
+
+ warp "marine@"+LOCATION$, 42, 26;
+ closedialog;
+ close;
+}
diff --git a/npc/008-1/mikhail.txt b/npc/008-1/mikhail.txt
new file mode 100644
index 00000000..24806baf
--- /dev/null
+++ b/npc/008-1/mikhail.txt
@@ -0,0 +1,123 @@
+// Evol scripts.
+// Author:
+// gumi
+// Quest states:
+// [1] 0 - cannot do the quest
+// [1] 1 - can do the quest
+// [1] 2 - bernard wants roasted maggot
+// [1] 3 - brought maggot
+// [1] 4 - bernard wants maggot slime
+// [1] 5 - brought maggot slime
+// [1] 6 - mikhail needs maggot slime
+// [1] 7 - brought maggot slime
+// [2] unused
+// [3] unused
+// [t] unused
+// Description:
+// takes part in the slime soup quest (Bernard)
+
+008-1,298,95,0 script Mikhail NPC_MIKHAIL,{
+
+ function soup_scared {
+ speech 4,
+ l("Hello..."),
+ l("I'm supposed to be helping Bernard from the Inn but...");
+
+ narrator 4,
+ l("His eyes grow wide");
+
+ speech 4,
+ l("Eeekkk another one.");
+
+ narrator
+ l("It seems that the boy would like to say more, but seems too terrified at the moment."),
+ l("Maybe you should help someone else first, so that he sees your intentions are good.");
+
+ close;
+ }
+
+ function soup_intro2 {
+ speech 4,
+ l("Bernard sent me to get %d %s from the %s in the fields, but they scare me so bad!",
+ .third_item_qty, getitemlink(.third_item), getmonsterlink(.third_item_mob)),
+ l("You look like a nice person."),
+ l("Would you go get them for me?");
+
+ selectd
+ l("Of course, I'll go get them for you.");
+
+ speech
+ l("Thank you so much!"),
+ l("I'll wait for you here.");
+
+ setq .quest, 6;
+ close;
+ }
+
+ function soup_reminder_slime2 {
+ speech
+ l("Did you bring me the %d %s I need?",
+ .third_item_qty, getitemlink(.third_item)),
+ l("It doesn't look like you have them all...");
+ close;
+ }
+
+ function soup_reward_slime2 {
+ speech
+ l("Did you bring me the %d %s I need?",
+ .third_item_qty, getitemlink(.third_item)),
+ l("Ooh!"),
+ l("Thank you so much!"),
+ l("I can get back to Bernard now!");
+
+ if (countitem(.third_item) < .third_item_qty)
+ close; // double-check
+
+ delitem .third_item, .third_item_qty;
+ setq .quest, 7;
+ quest_xp(.maxLevel, .third_reward_exp);
+ close;
+ }
+
+ function soup_thanks_slime2 {
+ speech
+ l("Thanks again for helping me!") + " %%Q";
+
+ close;
+ }
+
+ switch(getq(.quest))
+ {
+
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4: soup_scared; break;
+ case 5: soup_intro2; break;
+ case 6:
+ if (countitem(.third_item) < .third_item_qty)
+ soup_reminder_slime2;
+ else
+ soup_reward_slime2;
+ break;
+ default: soup_thanks_slime2;
+ }
+
+ closeclientdialog();
+ close;
+
+OnInit:
+ .third_item = MaggotSlime;
+ .third_item_qty = 5;
+ .third_item_mob = Maggot;
+
+ .maxLevel = 30;
+ .third_reward_exp = 100;
+
+ .quest = HurnscaldQuests_Soup;
+ .quest_debug = .quest;
+ .distance = 3;
+
+ end;
+}
diff --git a/npc/008-1/milly.txt b/npc/008-1/milly.txt
new file mode 100644
index 00000000..320ef3bf
--- /dev/null
+++ b/npc/008-1/milly.txt
@@ -0,0 +1,119 @@
+// Evol scripts.
+// Author:
+// gumi
+// Quest states (inspector):
+// [1] 0 - cannot do the quest
+// [1] 1 - can do the quest
+// [1] 2 - talked to inspector (1) <= start
+// [1] 3 - talked to old woman (1)
+// [1] 4 - talked to old woman (2)
+// [1] 5 - talked to inspector (2)
+// [1] 6 - talked to troupe leader (1)
+// [1] 7 - talked to inspector (3)
+// [1] 8 - talked to old man
+// [1] 9 - talked to old woman (3)
+// [1] 10 - talked to inspector (4)
+// [1] 11 - talked to old woman (4)
+// [1] 12 - talked to malek
+// [1] 13 - searched the bookcase
+// [1] 14 - talked to inspector (5)
+// [1] 15 - talked to troupe leader (2) <= reward
+// [1] 16 - talked to inspector (6) <= reward, end
+// [2] unused
+// [3] unused
+// [t] unused
+// Description:
+// robberies in hurnscald
+
+// Give player a Beanie Copter after 1,000,000 kills (server-wide)
+function script GetBeanieCopter {
+ // Double-check against possible malpractices
+ if ($MONSTERS_KILLED % 1000000 == 0) {
+ announce(sprintf("Congratulations, \"%s\", on killing the %sth monster!.", strcharinfo(0), format_number($MONSTERS_KILLED)), bc_all);
+ getitem BeanieCopter, 1;
+ dispbottom l("How strange, this monster dropped a very rare hat!");
+ }
+ return;
+}
+
+008-1,282,114,0 script Milly NPC_GIRL_MILLY,{
+
+ // TODO: make the actual beanie copter quest after those are finished:
+ // [X] Inspector quest
+ // [ ] Bone knife quest
+ // [ ] Setzer quest
+ // [ ] Rossy quest
+ // [ ] Cindy quest
+
+ .@q_inspector = getq(.quest_inspector);
+
+ speech(4,
+ l("Hello traveler, welcome to Hurnscald."),
+ l("Have you met Kfahr yet?"),
+ l("He is the greatest hero that ever walked the land of Hurnscald!"));
+
+ selectd(
+ l("Hi! No, I haven't seen him yet."),
+ l("Where can I find him?"),
+ l("Mh, I don't care for heroes."),
+ l("Hello, yes I have met him."),
+ rif(.@q_inspector == 2, l("Have you seen anything strange lately?")),
+ rif(.@q_inspector == 2, l("Do you know anything about the recent robberies?")));
+
+ switch (@menu)
+ {
+ case 3:
+ speech(4,
+ l("What?"),
+ l("Surely you do not appreciate what a hero he is!"),
+ l("Mh, or perhaps honor is dead in you; for you to be so slow to comprehend the good that his exploits have wrought for us."), // XXX: this sentence seems too complicated to come from a child's mouth
+ l("Put on your thinking cap and be propelled into high adventure!"),
+ l("Go to Kfahr, and listen to his stories."),
+ l("You can't have met him."),
+ l("No one who has met him would say such silly things."));
+ // fallthrough
+
+ case 1:
+ speech(4,
+ l("I highly recommend you seek him out!"));
+ // fallthrough
+
+ case 2:
+ speech(
+ l("He is a regular at the inn, located in the north-west part of town."),
+ l("If you are lucky he might tell you a story about his adventures."));
+ break;
+
+ case 4:
+ speech(
+ l("Oh, I hope you stayed and listened to his stories about his adventures."));
+ break;
+
+ case 5:
+ speech(
+ l("I haven't seen anything strange."));
+ break;
+
+ case 6:
+ speech(
+ l("No, sorry."));
+ break;
+ }
+
+ close;
+
+OnInit:
+ .quest_inspector = HurnscaldQuests_Inspector;
+ .quest_debug = .quest_inspector; // TODO: change this to the milly quest debug when it exists
+ .distance = 3;
+
+////////// UNFINISHED //////////
+////////////////////////////////
+// REMOVE THIS CODE WHEN THIS //
+// NPC IS NO LONGER A WIP //////
+////////////////////////////////
+//if (!debug) disablenpc(.name$);
+///////// UNFINISHED ///////////
+
+ end;
+}
diff --git a/npc/008-1/old-man.txt b/npc/008-1/old-man.txt
new file mode 100644
index 00000000..5b0e2f51
--- /dev/null
+++ b/npc/008-1/old-man.txt
@@ -0,0 +1,89 @@
+// Evol scripts.
+// Author:
+// gumi
+// Quest states:
+// [1] 0 - cannot do the quest
+// [1] 1 - can do the quest
+// [1] 2 - talked to inspector (1) <= start
+// [1] 3 - talked to old woman (1)
+// [1] 4 - talked to old woman (2)
+// [1] 5 - talked to inspector (2)
+// [1] 6 - talked to troupe leader (1)
+// [1] 7 - talked to inspector (3)
+// [1] 8 - talked to old man
+// [1] 9 - talked to old woman (3)
+// [1] 10 - talked to inspector (4)
+// [1] 11 - talked to old woman (4)
+// [1] 12 - talked to malek
+// [1] 13 - searched the bookcase
+// [1] 14 - talked to inspector (5)
+// [1] 15 - talked to troupe leader (2) <= reward
+// [1] 16 - talked to inspector (6) <= reward, end
+// [2] unused
+// [3] unused
+// [t] unused
+// Description:
+// robberies in hurnscald
+
+008-1,290,139,0 script Old Man NPC_OLD_MAN_HURNS,{
+
+ function oldman_ask {
+ speech(4,
+ l("Hi there, need something?"));
+
+ selectd(
+ l("Have you seen anything strange lately?"),
+ l("Do you know anything about the recent robberies?"));
+
+ speech(
+ l("I'm sorry, but I didn't see anything."),
+ l("You should ask my old woman."));
+ close;
+ }
+
+ function oldman_accuse {
+ speech(4,
+ l("Found anything new?"));
+
+ selectd(
+ l("The leader of the troupe said you hung around them a lot while they were in town."));
+
+ speech(
+ l("Yes, I hung around the theater a lot."),
+ l("I was an actor when I was younger."),
+ l("But I wasn't there that night."),
+ l("Me and the wife were at home all night."));
+
+ close2;
+ setq(.quest_inspector, 8);
+ end;
+ }
+
+ // OnTalk:
+ switch (getq(.quest_inspector))
+ {
+ case 2: oldman_ask; break;
+ case 7: oldman_accuse; break;
+ }
+
+ // initial intro
+ npctalk3(l("Don't let those monsters get to you."));
+ end;
+
+OnInit:
+ .quest_inspector = HurnscaldQuests_Inspector;
+ .quest_debug = .quest_inspector;
+ .distance = 1; // this npc has bad hearing
+ .speed = 2000; // this npc is very old
+ // TODO: move graph (after the Hurnscald map is finalized)
+
+////////// UNFINISHED //////////
+////////////////////////////////
+// REMOVE THIS CODE WHEN THIS //
+// NPC IS NO LONGER A WIP //////
+////////////////////////////////
+//if (!debug) disablenpc(.name$);
+///////// UNFINISHED ///////////
+
+ end;
+}
diff --git a/npc/008-1/old-woman.txt b/npc/008-1/old-woman.txt
new file mode 100644
index 00000000..89789b70
--- /dev/null
+++ b/npc/008-1/old-woman.txt
@@ -0,0 +1,136 @@
+/// Evol scripts.
+// Author:
+// gumi
+// Quest states:
+// [1] 0 - cannot do the quest
+// [1] 1 - can do the quest
+// [1] 2 - talked to inspector (1) <= start
+// [1] 3 - talked to old woman (1)
+// [1] 4 - talked to old woman (2)
+// [1] 5 - talked to inspector (2)
+// [1] 6 - talked to troupe leader (1)
+// [1] 7 - talked to inspector (3)
+// [1] 8 - talked to old man
+// [1] 9 - talked to old woman (3)
+// [1] 10 - talked to inspector (4)
+// [1] 11 - talked to old woman (4)
+// [1] 12 - talked to malek
+// [1] 13 - searched the bookcase
+// [1] 14 - talked to inspector (5)
+// [1] 15 - talked to troupe leader (2) <= reward
+// [1] 16 - talked to inspector (6) <= reward, end
+// [2] unused
+// [3] unused
+// [t] unused
+// Description:
+// Old Lady in the flower field, Robberies in Hurnscald.
+
+008-1,231,114,0 script Old Woman NPC_OLD_LADY,{
+
+ function is_inspector {
+ return (getequipcardid(EQI_HEAD_MID, 0) == NavyBlueCottonDye &&
+ getequipcardid(EQI_HEAD_LOW, 0) == NavyBlueCottonDye);
+ }
+
+ function oldwoman_ask {
+ speech(4,
+ l("Hello deary."));
+
+ selectd(
+ l("Have you seen anything strange lately?"),
+ l("Do you know anything about the recent robberies?"));
+
+ .@q = getq(.quest_inspector);
+
+ if (!is_inspector())
+ {
+ speech(l("Yes, but I'm only talking to the inspector himself!"));
+
+ close2;
+ if (.@q < 3)
+ setq(.quest_inspector, 3);
+ end;
+ }
+
+ if (.@q == 2 || .@q == 3)
+ {
+ speech(
+ l("I saw someone sneaking around town wearing a theater mask."),
+ l("It looked like one of the masks used by the troupe that was in town recently."));
+
+ close2;
+ setq(.quest_inspector, 4);
+ }
+
+ else if (.@q == 10)
+ {
+ speech(
+ l("I've remembered something else."),
+ l("The night the troupe left, I saw someone with a theater mask take a large satchel out of town."),
+ l("He was heading north."));
+
+ close2;
+ setq(.quest_inspector, 11);
+ }
+
+ end;
+ }
+
+ function oldwoman_alibi {
+ speech(4,
+ l("Hello deary."));
+
+ selectd(
+ l("Was your husband with you at home all night the last night that the troupe was in town?"));
+
+ speech(
+ l("Yes, we were both at home all night."));
+
+ close2;
+ setq(.quest_inspector, 9);
+ end;
+ }
+
+ function oldwoman_filler {
+ npctalk3(l("I hope you catch that naughty person!"));
+ end;
+ }
+
+ // OnTalk:
+ switch (getq(.quest_inspector))
+ {
+ case 2:
+ case 3: oldwoman_ask; break;
+ case 4:
+ case 5:
+ case 6:
+ case 7: oldwoman_filler; break;
+ case 8:
+ case 9: oldwoman_alibi; break;
+ case 10: oldwoman_ask; break;
+ }
+
+ // initial intro
+ if (BaseLevel < 40)
+ npctalk3(l("Watch out for these flowers. They don't like to be messed with."));
+ else
+ npctalk3(l("Hello deary."));
+ end;
+
+OnInit:
+ .quest_inspector = HurnscaldQuests_Inspector;
+ .quest_debug = .quest_inspector;
+ .distance = 1; // this npc has bad hearing
+ .speed = 2000; // this npc is very old
+ // TODO: move graph (after the Hurnscald map is finalized)
+
+////////// UNFINISHED //////////
+////////////////////////////////
+// REMOVE THIS CODE WHEN THIS //
+// NPC IS NO LONGER A WIP //////
+////////////////////////////////
+//if (!debug) disablenpc(.name$);
+///////// UNFINISHED ///////////
+
+ end;
+}
diff --git a/npc/008-1/oscar.txt b/npc/008-1/oscar.txt
new file mode 100644
index 00000000..2ea42456
--- /dev/null
+++ b/npc/008-1/oscar.txt
@@ -0,0 +1,19 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Oscar the farmer.
+// THIS IS A PLACEHOLDER! Read Dimond Chef before editing.
+
+008-1,160,77,0 script Oscar NPC_CAUL,{
+ speech
+ l("Hi, my name is Oscar."),
+ l("I used to be a farmer, but my magic attempts were banned by the gouvernment."),
+ l("Now I remain poor and unemployed.");
+
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-1/rossy.txt b/npc/008-1/rossy.txt
new file mode 100644
index 00000000..f0acfa67
--- /dev/null
+++ b/npc/008-1/rossy.txt
@@ -0,0 +1,391 @@
+// The Mana World scripts.
+// Author:
+// Jesusalva
+// Description:
+// Daughter of Olana and sister of Juliet. PLACEHOLDER SPRITE
+
+008-1,62,220,0 script Rossy NPC_TANISHA,{
+ function rossyFirstmet;
+ function rossyBasket;
+ function rossyLetter;
+ function rossyPotionList;
+ function rossyPotionDone;
+ function rossyDeliverRoses;
+ function rossyDeliverTulip;
+ function rossyJulietIntro;
+ .@q=getq(HurnscaldQuests_Rossy);
+ mesn;
+ mesq l("Hello, wanderer.");
+ switch (.@q) {
+ case 1:
+ rossyFirstmet();
+ break;
+ case 3:
+ rossyBasket();
+ break;
+ case 6:
+ rossyLetter();
+ break;
+ case 7:
+ rossyPotionList();
+ break;
+ case 8:
+ mesn;
+ mesq l("What, you still have my potion with you??");
+ next;
+ mesn;
+ mesq l("Could you please deliver it to %s in the magic academy? He is the head of alchemy.", b("David"));
+ break;
+ case 9:
+ case 10:
+ rossyPotionDone();
+ break;
+ case 11:
+ rossyDeliverRoses();
+ break;
+ case 13:
+ rossyDeliverTulip();
+ break;
+ case 14:
+ mesn;
+ mesq l("Go and tell my mother that she is the nicest mother in the world.");
+ next;
+ select
+ l("Right on it."),
+ l("Did you find your sister? I am starting to get worried too.");
+ mes "";
+ if (@menu == 2) {
+ mesn;
+ if (BaseLevel < .minLevel_rescue)
+ mesq l("I think I have an idea where Juliet might be. Come back in a few levels, and I will tell you if she is ok.");
+ else
+ mesq l("I think I have an idea where she might be. Come back in a few minutes, I will tell you if she is ok.");
+ }
+ break;
+ case 15:
+ rossyJulietIntro();
+ break;
+ case 16:
+ mesn;
+ mesq l("Oh no! Juliet ... why would you go to that scary place? ... Please help her, %s!", strcharinfo(0));
+ mesc l("The cave is %s", b(l("Northwest of here.")));
+ break;
+ case 17:
+ mesn;
+ mesq l("Hey %s!", strcharinfo(0));
+ next;
+ mesn;
+ mesq l("Thanks for finding Juliet again. I'm so relieved!");
+ next;
+ mesn;
+ mesq l("...I still wonder what was that thing Juliet was running from... Hm? Nothing! Just thinking out loud.");
+ break;
+ // Default messages
+ case 12:
+ mesc l("Achooo!");
+ // FALLTHROUGH
+ default:
+ mesn;
+ mesq l("I'm being lazy right now, so please %s", any(
+ l("don't tell devs I'm slacking off again."),
+ l("tell my mother there is no reason to worry."),
+ l("don't worry with me.")
+ ));
+ }
+ close;
+
+function rossyFirstmet {
+ mesc l("A young girl looks at you in tears.");
+ next;
+ select
+ l("Hey there... Why are you crying? Are you hurt?"),
+ l("Sorry kid, I don't have time to play with children.");
+ mes "";
+ if (@menu == 2)
+ return;
+ mesn l("Young Girl");
+ mesq l("No. I'm crying because I lost all my fruits. My sister and I were collecting some near Dimond's Cove, but then I stumbled on a giant snail and it attacked us!");
+ next;
+ mesn l("Young Girl");
+ mesq l("But we were lucky, because the snail is really slow and we ran away from it. Juliet ran to the left and I ran to the right. The snail got pretty confused, because we are identical twins. The problem is that I dropped the basket full of fruits on the ground and that evil snail ate them all! And now I can't find Juliet to help me collect more fruits.");
+ next;
+ mesn strcharinfo(0);
+ select
+ l("Did you say \"Juliet\"? I talked to your mother Olana, She's very worried about you!");
+ mes "";
+ // You know she is Rossy, so mesn; won't need args anymore
+ mesn;
+ mesq l("Really? But she let us play in the woods. There's no reason to be worried – unless....");
+ next;
+ mesn;
+ mesc l("Rossy suddenly gets a strange look on her face, mumbling something about Juliet.");
+ mesq l("Could you do me a favor? Please, tell my mother that we're alright. There's ... well ... there's no reason to worry about us.");
+ next;
+ select
+ l("Very well, if you say so...."),
+ l("Sorry, but I really don't have time for this.");
+ mes "";
+ if (@menu == 2) {
+ mesn;
+ mesq l("Then why bother? Weird person...");
+ return;
+ }
+ setq HurnscaldQuests_Rossy, 2;
+ mesn;
+ mesq l("Thank you very much!");
+ return;
+}
+
+function rossyBasket {
+ mesn;
+ mesq l("Hey, that is nice of you to come back. I was thinking about giving a basket full of %s to my mother, to make her happy, you know.", getitemlink(Blueberries));
+ next;
+ mesn;
+ mesq l("But I would need at least %d berries, and it would take ages to get so many by myself!", .blueberries_amount);
+ next;
+ select
+ l("That is no problem for me. Just wait and I will come back with the cherries."),
+ l("Ask Juliet, not me."),
+ rif(countitem(Blueberries), l("Hey, I have some in my backpack!")),
+ l("You should get them yourself.");
+ mes "";
+ if (@menu == 2) {
+ mesn;
+ mesq l("Juliet ran to the left, and I'm pretty sure she is doing the same.");
+ }
+ if (@menu != 3)
+ return;
+ if (countitem(Blueberries) < .blueberries_amount) {
+ mesn;
+ mesq l("You do, but that's not enough. I need %d %s.", .blueberries_amount, getitemlink(Blueberries));
+ }
+ delitem Blueberries, .blueberries_amount;
+ quest_xp(.maxLevel, 2000);
+ quest_jxp(.maxLevel, 500);
+ setq HurnscaldQuests_Rossy, 4;
+ // FIXME: Perhaps give player a [Berries Bag] item? Hmm.
+ mesn;
+ mesq l("I can't believe it! You got all the berries needed! Lemme just wrap them and... done! Please give them to my mother. Tell her that it is a gift from me and Juliet, and that there's no reason to worry about us."); // Lemme = Let me
+ next;
+ mesn;
+ mesc l("%s mumbles to herself.", .name$);
+ mesq l("I hope...");
+ next;
+ mesn;
+ mesq l("Oh, and after you give the berries to my mother, please come back here. Err, if you have some free time, of course.");
+ return;
+}
+
+function rossyLetter {
+ mesn;
+ mesq l("I'm being lazy right now, so please %s", any(
+ l("don't tell devs I'm slacking off again."),
+ l("tell my mother there is no reason to worry."),
+ l("don't worry with me.")
+ ));
+ next;
+ select
+ l("Hocus sent a letter to you."),
+ l("Erm, okay.");
+ mes "";
+ if (@menu == 2)
+ return;
+ mesn;
+ mesq l("The Grandmaster? %%U Lemme read...");
+ next;
+ mesn;
+ mesc l("%s's face suddenly turns pale.", .name$);
+ mesq l("Oh no! I completely forgot. The exam! Dang, I knew I should not have picked Alchemy for study...");
+ next;
+ mesn;
+ mesc l("%s looks at you with beady eyes.", .name$);
+ mesq l("I haven't found Juliet yet, and I don't even have any of the ingredients required. Could you get them for me? Pretty please? %%J");
+ next;
+ select
+ l("Alright, tell me what I must get."),
+ l("Your cute face will not convince me - Your test, your responsibility.");
+ mes "";
+ if (@menu == 2) {
+ mesn;
+ mesq l("Yes, I know. I really should have started it earlier... But I can't look for Juliet AND get the ingredients at the same time. Some of them are only found in Tulimshar.");
+ next;
+ mesn;
+ mesq l("You don't even know how Juliet looks. Please come back if you reconsider. Please. Juliet could be being eaten by a creature, as we speak. %%i");
+ return;
+ }
+ setq HurnscaldQuests_Rossy, 7, 0;
+ mesn;
+ mesq l("Excellent! So, as for the materials I need to brew the potion...");
+ next;
+ rossyPotionList();
+ return;
+}
+
+function rossyPotionList {
+ .@t=getq2(HurnscaldQuests_Rossy);
+ // Potion submitted
+ if (.@t) {
+ // Finished!
+ if (.@t < gettimetick(2)) {
+ // Yay
+ mesn;
+ mesq l("I'm done! Thanks for the help. It is just the shade of blue I wanted.");
+ next;
+ mesn;
+ mesq l("Could you please deliver it to %s in the magic academy? He is the head of alchemy.", b("David"));
+ setq HurnscaldQuests_Rossy, 8, 0;
+ } else {
+ // Brewing
+ mesn;
+ mesq l("Please be patient... I'll be done in %s.", FuzzyTime(.@t));
+ }
+ return;
+ }
+
+ // Potion not yet finished
+ //mesf("- %d/%d %s", countitem(CactusDrink), 24, getitemlink(CactusDrink));
+ mesf("- %d/%d %s", countitem(MaggotSlime), 32, getitemlink(MaggotSlime));
+ mesf("- %d/%d %s", countitem(GambogeHerb), 50, getitemlink(GambogeHerb));
+ mesf("- %d/%d %s", countitem(AlizarinHerb), 43, getitemlink(AlizarinHerb));
+ mesf("- %d/%d %s", countitem(BugLeg), 30, getitemlink(BugLeg));
+ mesf("- %d/%d %s", countitem(Pearl), 1, getitemlink(Pearl));
+ next;
+ mesn;
+ mesq l("Do you have these materials with you?");
+ next;
+ select
+ l("Not yet."),
+ l("Yes, here they are!"),
+ l("No, but I'll be right back.");
+ mes "";
+ if (@menu != 2)
+ return;
+ if (countitem(MaggotSlime) < 32 ||
+ countitem(GambogeHerb) < 50 ||
+ countitem(AlizarinHerb) < 43 ||
+ countitem(BugLeg) < 30 ||
+ //countitem(CactusDrink) < 24 ||
+ countitem(Pearl) < 1) {
+ mesn;
+ mesq l("You would lie to a poor, small, frail girl like me? %%S");
+ next;
+ mesn;
+ mesq l("Don't you think that to be very coward on your part?");
+ return;
+ }
+ //delitem CactusDrink, 24;
+ delitem MaggotSlime, 32;
+ delitem GambogeHerb, 50;
+ delitem AlizarinHerb, 43;
+ delitem BugLeg, 30;
+ delitem Pearl, 1;
+ setq2 HurnscaldQuests_Rossy, gettimetick(2)+900;
+ mesn;
+ mesq l("Perfect! Please allow me some time to brew this potion. It should be ready in 15 minutes or so.");
+ return;
+}
+
+function rossyPotionDone {
+ mesn;
+ mesq l("So... How did it go?");
+ next;
+ select
+ l("David said it was \"okay-ish\"."),
+ l("David said he would grade it later, but you had nothing to worry about.");
+ mes "";
+ if (@menu == 1) {
+ mesn;
+ mesq l("That's a relief. Okay-ish is actually a pretty good grade in the Academy.");
+ next;
+ }
+ mesn;
+ mesq l("Could you please tell my mother about that? She is already worried with Juliet and me, no need to have her worried about the exam as well.");
+ compareandsetq HurnscaldQuests_Rossy, 9, 10;
+ return;
+}
+
+function rossyDeliverRoses {
+ if (countitem(ARedRose) < 15) {
+ mesn;
+ mesq l("Hello %s.", strcharinfo(0));
+ return;
+ }
+ select
+ l("Your mother was so happy that she asked me to bring you these flowers.");
+ mes "";
+ delitem ARedRose, 15;
+ setq HurnscaldQuests_Rossy, 12;
+ mesn;
+ mesq l("How nice!");
+ next;
+ mesn;
+ mesc l("Rossy takes the flowers from your hands and suddenly throws them on the ground. She begins sneezing.");
+ next;
+ select
+ l("I presume you don't like roses, right?"),
+ l("Are you feeling well?");
+ mes "";
+ mesn;
+ mesq l("I am allergic to roses; my mother should already know that!");
+ next;
+ mesn strcharinfo(0);
+ mesc l("Maybe we should talk to Olana about this.");
+ return;
+}
+
+function rossyDeliverTulip {
+ if (countitem(ARedTulip) < 15) {
+ mesc l("Achooo!");
+ mesn;
+ mesq l("I'm being lazy right now, so please %s", any(
+ l("don't tell devs I'm slacking off again."),
+ l("tell my mother there is no reason to worry."),
+ l("don't worry with me.")
+ ));
+ return;
+ }
+ select
+ l("Your mother is sorry about the roses. Here are some beautiful red tulips instead.");
+ mes "";
+ delitem ARedTulip, 15;
+ setq HurnscaldQuests_Rossy, 14;
+ quest_xp(.maxLevel, 2500);
+ quest_jxp(.maxLevel, 250);
+ mesn;
+ mesq l("That's better! Go and tell my mother that she is the nicest mother in the world.");
+ next;
+ mesn;
+ mesq l("However... Now I should really find my sister. Come back later.");
+ return;
+}
+
+function rossyJulietIntro {
+ if (BaseLevel < .minLevel_rescue) {
+ mesn;
+ mesq l("I think I have an idea where Juliet might be. Come back in a few levels, and I will tell you if she is ok.");
+ return;
+ }
+ mesn;
+ mesq l("%s, you have to help me! I saw Juliet, but something was wrong!!", strcharinfo(0));
+ next;
+ select
+ l("Calm down and tell me what happened.");
+ mes "";
+ mesn;
+ mesq l("No time for that! She was running away from something and entered a cave not far from here. I heard her scream. Please, can you enter the cave and save her? I'm so scared!");
+ next;
+ mesc l("%s is too distressed to be of any help. It might be a better idea to go inside the cave and look for Juliet.", .name$);
+ mesc l("The cave is %s", b(l("Northwest of here.")));
+ setq HurnscaldQuests_Rossy, 16;
+ return;
+}
+
+OnInit:
+ .distance = 4;
+
+ // Quest conf
+ .blueberries_amount=30;
+ .minLevel_rescue = 60;
+ .maxLevel = 90;
+ end;
+}
diff --git a/npc/008-1/sabine.txt b/npc/008-1/sabine.txt
new file mode 100644
index 00000000..dc2b11b7
--- /dev/null
+++ b/npc/008-1/sabine.txt
@@ -0,0 +1,63 @@
+// Evol scripts.
+// Author:
+// gumi
+// Quest states:
+// [1] 0 - cannot do the quest
+// [1] 1 - can do the quest
+// [1] 2 - talked to inspector (1) <= start
+// [1] 3 - talked to old woman (1)
+// [1] 4 - talked to old woman (2)
+// [1] 5 - talked to inspector (2)
+// [1] 6 - talked to troupe leader (1)
+// [1] 7 - talked to inspector (3)
+// [1] 8 - talked to old man
+// [1] 9 - talked to old woman (3)
+// [1] 10 - talked to inspector (4)
+// [1] 11 - talked to old woman (4)
+// [1] 12 - talked to malek
+// [1] 13 - searched the bookcase
+// [1] 14 - talked to inspector (5)
+// [1] 15 - talked to troupe leader (2) <= reward
+// [1] 16 - talked to inspector (6) <= reward, end
+// [2] unused
+// [3] unused
+// [t] unused
+// Description:
+// robberies in hurnscald
+
+008-1,291,97,0 script Sabine NPC_SABINE,{
+
+ if (getq(.quest_inspector) != 2)
+ {
+ npctalk3(generic(1 | 16));
+ end;
+ }
+
+ speech(4,
+ l("Isn't this place pretty?"),
+ l("I love hanging out here!"));
+
+ selectd(
+ l("Have you seen anything strange lately?"),
+ l("Do you know anything about the recent robberies?"));
+
+ speech(
+ l("No, sorry."));
+
+ close;
+
+OnInit:
+ .quest_inspector = HurnscaldQuests_Inspector;
+ .quest_debug = .quest_inspector;
+ .distance = 3;
+
+////////// UNFINISHED //////////
+////////////////////////////////
+// REMOVE THIS CODE WHEN THIS //
+// NPC IS NO LONGER A WIP //////
+////////////////////////////////
+//if (!debug) disablenpc(.name$);
+///////// UNFINISHED ///////////
+
+ end;
+}
diff --git a/npc/008-1/sergeant-ryan.txt b/npc/008-1/sergeant-ryan.txt
new file mode 100644
index 00000000..975587e4
--- /dev/null
+++ b/npc/008-1/sergeant-ryan.txt
@@ -0,0 +1,71 @@
+// Evol scripts.
+// Author:
+// Livio
+// Description:
+// Save Sergeant Ryan
+
+008-1,55,47,0 script Sergeant Ryan NPC_RAIJIN_MALE_BROTHERHOOD,{
+function advanceQuest;
+function advanceQuest {
+ setq(General_CptHal, getq(General_CptHal) + 1);
+ return;
+}
+
+ if (getq(General_CptHal)<=3) {
+ speech
+ l("Aaah!!! Dammit!!!"),
+ l("It hurts like hell, #@%!!!!"),
+ l("Go away, my comrades will be here soon!");
+ }
+ if (getq(General_CptHal)==3) {
+ select l("No. They won't because Hal sent me to look after you, Tom Hanks.");
+ speech l("Aaah!!! What?");
+ select l("You are hurt! Looks like I have to save private Ryan...");
+ speech l("I'm a Sergeant. I could teach you a lesson or two if it wasn't for my leg.");
+ select l("Does it hurts if I touch here?");
+ speech l("@#@%&#@*!!!");
+ select l("This leg is badly hurt! Let me look out for something to heal it.");
+ speech l("Grr... I'm so nuts that I want to get even first with damn wolverns.");
+ speech l("Bring me:");
+ printIngredients(.REQ0_INGREDIENTS, .REQ0_INGREDIENTS_AMOUNT);
+ next;
+ advanceQuest();
+ close;
+ }
+ if (getq(General_CptHal)==4) {
+ if (checkForItems(.REQ0_INGREDIENTS, .REQ0_INGREDIENTS_AMOUNT)) {
+ speech l("Yeah, finally!!!");
+ next;
+ BaseExp += 15 * BaseLevel;
+ Zeny += 50;
+ advanceQuest();
+ delitem(.REQ0_INGREDIENTS, .REQ0_INGREDIENTS_AMOUNT);
+ speech l("Go tell Hal that I'm fine and I will go on with the mission as soon as possible.");
+ } else {
+ speech l("What are you doing here?!? I need:");
+ printIngredients(.REQ0_INGREDIENTS, .REQ0_INGREDIENTS_AMOUNT);
+ speech l("Come on, kill those bastards!!! Wolverns must pay the price of tasting my damn leg!!!");
+ select l("Fine. But PETA is not going to be happy about it...");
+ speech l("@#@%&#@*!!!");
+ }
+ close;
+ }
+ if (getq(General_CptHal)>=5) {
+ speech l("Thanks! Now move, I have a mission to accomplish.");
+ }
+ close;
+
+OnInit:
+ // NPC ITEM REQUESTS
+ setarray(.REQ0_INGREDIENTS,
+ WolvernPelt,
+ BottleOfWater
+ );
+ setarray(.REQ0_INGREDIENTS_AMOUNT,
+ 1,
+ 1
+ );
+
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-1/shop.txt b/npc/008-1/shop.txt
new file mode 100644
index 00000000..b2b4a406
--- /dev/null
+++ b/npc/008-1/shop.txt
@@ -0,0 +1,50 @@
+// Evol scripts.
+// Authors:
+// 4144
+// Micksha
+// Reid
+// toams
+// Description:
+// Blossom flower shop.
+
+008-1,201,136,0 trader #Invisible008-1 NPC_HIDDEN,{
+
+OnInit:
+ tradertype(NST_MARKET);
+
+ sellitem ARedRose, -1, 50;
+ sellitem AWhiteRose, -1, 50;
+ sellitem AYellowRose, -1, 50;
+ sellitem ABlueRose, -1, 20;
+ sellitem ARedTulip, -1, 50;
+ sellitem AWhiteTulip, -1, 50;
+ sellitem AYellowTulip, -1, 50;
+
+ .distance = 10;
+ end;
+
+OnClock0000:
+ restoreshopitem ARedRose, 10;
+ restoreshopitem AWhiteRose, 10;
+ restoreshopitem AYellowRose, 10;
+ restoreshopitem ABlueRose, 5;
+ restoreshopitem ARedTulip, 10;
+ restoreshopitem AWhiteTulip, 10;
+ restoreshopitem AYellowTulip, 10;
+OnClock0800:
+ restoreshopitem ARedRose, 10;
+ restoreshopitem AWhiteRose, 10;
+ restoreshopitem AYellowRose, 10;
+ restoreshopitem ABlueRose, 5;
+ restoreshopitem ARedTulip, 10;
+ restoreshopitem AWhiteTulip, 10;
+ restoreshopitem AYellowTulip, 10;
+OnClock1600:
+ restoreshopitem ARedRose, 10;
+ restoreshopitem AWhiteRose, 10;
+ restoreshopitem AYellowRose, 10;
+ restoreshopitem ABlueRose, 5;
+ restoreshopitem ARedTulip, 10;
+ restoreshopitem AWhiteTulip, 10;
+ restoreshopitem AYellowTulip, 10;
+}
diff --git a/npc/008-1/sign.txt b/npc/008-1/sign.txt
new file mode 100644
index 00000000..950fe996
--- /dev/null
+++ b/npc/008-1/sign.txt
@@ -0,0 +1,45 @@
+// Evol scripts.
+// Authors:
+// Micksha
+// Description:
+// Sign pillars in Hurnscald.
+
+008-1,142,105,0 script Sign#008-1-central NPC_NO_SPRITE,{
+ npctalkonce l("Right: Hurnscald | Down: Dimond's Cove | Left: West Woodland | Up: Nivalis (under construction)");
+ close;
+OnInit:
+ .distance = 2;
+ end;
+}
+
+008-1,126,160,0 script Sign#008-1-south NPC_NO_SPRITE,{
+ npctalkonce l("Down: Dimond's Cove | Left: Swamp");
+ close;
+OnInit:
+ .distance = 2;
+ end;
+}
+
+008-1,246,177,0 script Sign#008-1-southeast NPC_NO_SPRITE,{
+ npctalkonce l("Left: Dimond's Cove | Up: Hurnscald | Right: Forsaken Inn");
+ close;
+OnInit:
+ .distance = 2;
+ end;
+}
+
+008-1,251,104,0 script Sign#008-1-hurns NPC_NO_SPRITE,{
+ npctalkonce l("Left: West Woodland | Up: North Mine | Right: Harbor | Down: other directions");
+ close;
+OnInit:
+ .distance = 2;
+ end;
+}
+
+008-1,247,105,0 script Sign#008-1-4144 NPC_NO_SPRITE,{
+ npctalkonce l("This place is dedicated to 4144, the alltime Hero.");
+ close;
+OnInit:
+ .distance = 1;
+ end;
+}
diff --git a/npc/008-1/snarfles.txt b/npc/008-1/snarfles.txt
new file mode 100644
index 00000000..d4de8ed0
--- /dev/null
+++ b/npc/008-1/snarfles.txt
@@ -0,0 +1,97 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Snarfles the mouboo farmer.
+// THIS IS A PLACEHOLDER!
+
+008-1,79,118,0 script Snarfles NPC_SNARFLES,{
+ function foodQuest;
+ speech
+ l("My Mouboos, my beloved Mouboos!"),
+ l("Oh, hi, isn't it cool to live among all those Mouboos? I don't understand how some people can eat Mouboo steak."),
+ l("Murderers!");
+ if (getq(General_SmearedHands) <= 3 && getq2(General_SmearedHands) != 2)
+ foodQuest();
+ close;
+
+function foodQuest {
+ .@q=getq(General_SmearedHands);
+ next;
+ mesn;
+ mesq l("Ah... I could use some Asparagus with Hollondaise now...");
+ switch (.@q) {
+ case 1:
+ next;
+ mesn strcharinfo(0);
+ select
+ l("\"Asparagus with Hollondaise\"? What's that?"),
+ menuaction(l("Leave"));
+ mes "";
+ if (@menu == 2)
+ break;
+ mesn;
+ mesq l("Some call it %s, but it is so tasty...", getitemlink(VeggiePlate));
+ next;
+ mesn;
+ mesq l("I could even make one for you and give the recipe, but...");
+ next;
+ mesn;
+ mesq l("I always get smeared hands eating it and cannot play cards anymore with Crane.");
+ next;
+ mesn;
+ mesq l("Well, if you find me a solution for that problem, I can give you the recipe. What do you say?");
+ next;
+ mesc l("WARNING: If you accept this quest, you'll be struck at the %s route!", b(l("Vegetarian"))), 1;
+ mesc l("This will also make %s's Quest unavailable.", b("Crane")), 1;
+ mesc l("This decision cannot be changed later."), 1;
+ next;
+ mesc l("Accept this request?"), 1;
+ if (askyesno() == ASK_YES) {
+ setq General_SmearedHands, 2, VEGAN; // 1 = Vegan
+ mesn;
+ mesq l("Great! I'll be eager for your return!");
+ }
+ break;
+ case 2:
+ mesn;
+ mesq l("Have you found a solution for my smeared hands problem?");
+ next;
+ select
+ l("No, not yet.");
+ mes "";
+ mesn;
+ mesq l("I've heard they're related to the earl of sandwich, so maybe a sandwich maker could help... *sigh* I want to play cards...");
+ break;
+ case 3:
+ mesn strcharinfo(0);
+ select
+ l("Have you tried putting it in a bread already?"),
+ l("I'll keep looking for solutions for your problem.");
+ mes "";
+ if (@menu == 2)
+ return;
+ mesn;
+ mesq l("Actually... No. Have been too afraid of it tasting foul.");
+ next;
+ mesn strcharinfo(0);
+ mesq l("Really? Tiki, Candor's chef, liked it very much.");
+ next;
+ mesn;
+ mesq l("Wha - Really?! Tiki said it tasted good??! I'm saved! You're truly my savior!!");
+ next;
+ mesn;
+ mesq l("I'll put the %s recipe on your %s. Thanks, you saved my day!", getitemlink(VeggiePlate), getitemlink(RecipeBook));
+ RECIPES[CraftVeggiePlate]=true;
+ getitembound VeggiePlate, 1, IBT_ACCOUNT;
+ setq1 General_SmearedHands, 4; // Finished
+ default:
+ return;
+ }
+ return;
+}
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-1/soul-menhir.txt b/npc/008-1/soul-menhir.txt
new file mode 100644
index 00000000..61112de5
--- /dev/null
+++ b/npc/008-1/soul-menhir.txt
@@ -0,0 +1,9 @@
+// The Mana World scripts.
+// Author:
+// gumi
+// Jesusalva
+// Description:
+// place of power, mana refills faster when sitting nearby
+
+008-1,252,111,0 duplicate(Soul Menhir) Soul Menhir#hurn_1_7_200 NPC_NO_SPRITE
+
diff --git a/npc/008-1/voltain.txt b/npc/008-1/voltain.txt
new file mode 100644
index 00000000..ce41f10b
--- /dev/null
+++ b/npc/008-1/voltain.txt
@@ -0,0 +1,18 @@
+// The Mana World scripts.
+// Author:
+// Micksha
+// Description:
+// Voltain the dark druid.
+// THIS IS A PLACEHOLDER!
+
+008-1,182,155,0 script Voltain NPC_DARK_DRUID,{
+ speech
+ l("Go away, I have to think about new evil doings."),
+ l("GO AWAY, I SAID!");
+
+ close;
+
+OnInit:
+ .distance = 4;
+ end;
+}
diff --git a/npc/008-1/wateranimation.txt b/npc/008-1/wateranimation.txt
new file mode 100644
index 00000000..ce72d893
--- /dev/null
+++ b/npc/008-1/wateranimation.txt
@@ -0,0 +1,21 @@
+// The Mana World scripts.
+// Description:
+// Water animations, splash, fishes, etc...
+
+008-1,90,223,0 duplicate(#fish_river) #hurns_fish01 NPC_WATER_SPLASH
+008-1,86,177,0 duplicate(#fish_river) #hurns_fish02 NPC_WATER_SPLASH
+008-1,85,186,0 duplicate(#fish_river) #hurns_fish03 NPC_WATER_SPLASH
+008-1,89,208,0 duplicate(#fish_river) #hurns_fish04 NPC_WATER_SPLASH
+008-1,139,91,0 duplicate(#fish_river) #hurns_fish05 NPC_WATER_SPLASH
+008-1,64,36,0 duplicate(#fish_river) #hurns_fish06 NPC_WATER_SPLASH
+008-1,55,30,0 duplicate(#fish_river) #hurns_fish07 NPC_WATER_SPLASH
+008-1,46,35,0 duplicate(#fish_river) #hurns_fish08 NPC_WATER_SPLASH
+008-1,105,55,0 duplicate(#fish_river) #hurns_fish09 NPC_WATER_SPLASH
+008-1,214,155,0 duplicate(#fish_river) #hurns_fish10 NPC_WATER_SPLASH
+008-1,216,153,0 duplicate(#fish_river) #hurns_fish11 NPC_WATER_SPLASH
+008-1,225,26,0 duplicate(#fish_river) #hurns_fish12 NPC_WATER_SPLASH
+008-1,220,49,0 duplicate(#fish_river) #hurns_fish13 NPC_WATER_SPLASH
+008-1,220,57,0 duplicate(#fish_river) #hurns_fish14 NPC_WATER_SPLASH
+008-1,233,56,0 duplicate(#fish_river) #hurns_fish15 NPC_WATER_SPLASH
+008-1,230,51,0 duplicate(#fish_river) #hurns_fish16 NPC_WATER_SPLASH
+