diff options
Diffstat (limited to 'npc/008-1')
-rw-r--r-- | npc/008-1/4144.txt | 90 | ||||
-rw-r--r-- | npc/008-1/_import.txt | 29 | ||||
-rw-r--r-- | npc/008-1/_mobs.txt | 124 | ||||
-rw-r--r-- | npc/008-1/_warps.txt | 33 | ||||
-rw-r--r-- | npc/008-1/auldsbel.txt | 53 | ||||
-rw-r--r-- | npc/008-1/banu.txt | 20 | ||||
-rw-r--r-- | npc/008-1/blossom.txt | 77 | ||||
-rw-r--r-- | npc/008-1/confused-tree.txt | 972 | ||||
-rw-r--r-- | npc/008-1/crane.txt | 92 | ||||
-rw-r--r-- | npc/008-1/doors.txt | 43 | ||||
-rw-r--r-- | npc/008-1/hinnak.txt | 354 | ||||
-rw-r--r-- | npc/008-1/jack.txt | 314 | ||||
-rw-r--r-- | npc/008-1/mapflags.txt | 1 | ||||
-rw-r--r-- | npc/008-1/marine.txt | 17 | ||||
-rw-r--r-- | npc/008-1/mikhail.txt | 123 | ||||
-rw-r--r-- | npc/008-1/milly.txt | 119 | ||||
-rw-r--r-- | npc/008-1/old-man.txt | 89 | ||||
-rw-r--r-- | npc/008-1/old-woman.txt | 136 | ||||
-rw-r--r-- | npc/008-1/oscar.txt | 19 | ||||
-rw-r--r-- | npc/008-1/rossy.txt | 391 | ||||
-rw-r--r-- | npc/008-1/sabine.txt | 63 | ||||
-rw-r--r-- | npc/008-1/sergeant-ryan.txt | 71 | ||||
-rw-r--r-- | npc/008-1/shop.txt | 50 | ||||
-rw-r--r-- | npc/008-1/sign.txt | 45 | ||||
-rw-r--r-- | npc/008-1/snarfles.txt | 97 | ||||
-rw-r--r-- | npc/008-1/soul-menhir.txt | 9 | ||||
-rw-r--r-- | npc/008-1/voltain.txt | 18 | ||||
-rw-r--r-- | npc/008-1/wateranimation.txt | 21 |
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 + |