summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesusaves <cpntb1@ymail.com>2019-03-06 12:49:10 -0300
committerJesusaves <cpntb1@ymail.com>2019-03-06 12:49:10 -0300
commit48551c2016339956979f2c9f73115af36c1a0292 (patch)
tree05007879cfe76d4858d2510e937b1656c20beb0e
parent23ac38921f6f9f58e619b41f7467dff7e6a00df7 (diff)
parent600fac0c6e0d07dd99aeccf443e2262239b64aea (diff)
downloadserverdata-jesusalva/resync.tar.gz
serverdata-jesusalva/resync.tar.bz2
serverdata-jesusalva/resync.tar.xz
serverdata-jesusalva/resync.zip
Merge branch 'jesusalva/resync' of gitlab.com:jesusalva/evolsrc into jesusalva/resyncjesusalva/resync
-rw-r--r--conf/atcommand.conf1
-rw-r--r--db/constants.conf3
-rw-r--r--db/craft_db.conf87
-rw-r--r--db/quest_db.conf4
-rw-r--r--db/re/item_db.conf13
-rw-r--r--maps/re/001-3-0.mcachebin1261 -> 1296 bytes
-rw-r--r--npc/000-0-0/sailors.txt1
-rw-r--r--npc/000-2-1/peter.txt445
-rw-r--r--npc/000-2-2/doors.txt14
-rw-r--r--npc/000-2-2/ratto.txt109
-rw-r--r--npc/001-1/manhole.txt34
-rw-r--r--npc/001-2-11/mona.txt52
-rw-r--r--npc/001-2-22/peter.txt445
-rw-r--r--npc/001-2-23/doors.txt18
-rw-r--r--npc/001-2-23/ratto.txt109
-rw-r--r--npc/001-3-0/_import.txt1
-rw-r--r--npc/001-3-0/_mobs.txt4
-rw-r--r--npc/001-3-0/mundane.txt142
-rw-r--r--npc/008-2-16/_import.txt2
-rw-r--r--npc/008-2-16/stove.txt88
-rw-r--r--npc/008-2-16/yannika.txt300
-rw-r--r--npc/commands/debug-quest.txt3
-rw-r--r--npc/functions/quest-debug/003-ShipQuests_Peter.txt18
-rw-r--r--npc/functions/quest-debug/041-General_Cooking.txt51
-rw-r--r--npc/functions/util.txt41
-rw-r--r--npc/items/recipes.txt60
-rw-r--r--npc/scripts.conf2
27 files changed, 1413 insertions, 634 deletions
diff --git a/conf/atcommand.conf b/conf/atcommand.conf
index 91485f3b..57356202 100644
--- a/conf/atcommand.conf
+++ b/conf/atcommand.conf
@@ -23,6 +23,7 @@ aliases: {
mobinfo: ["monsterinfo", "mi"]
iteminfo: ["ii"]
time: ["date", "serverdate", "servertime"]
+ tonpc: ["npc"]
autotrade: ["at"]
help: ["h"]
jumpto: ["goto", "warpto"]
diff --git a/db/constants.conf b/db/constants.conf
index 2deefebd..c778d20a 100644
--- a/db/constants.conf
+++ b/db/constants.conf
@@ -4171,6 +4171,9 @@ constants_db: {
REDPLUSH_INN: 1
CURRENT_INN: 2
+ comment__: "CRAFT enum"
+ CRAFT_SANDWICH: 4
+
comment__: "Being actions"
ACTION_STAND: 0
ACTION_MOVE: 1
diff --git a/db/craft_db.conf b/db/craft_db.conf
index c010081e..589fd3a7 100644
--- a/db/craft_db.conf
+++ b/db/craft_db.conf
@@ -54,6 +54,7 @@ craft_db: (
},
******************************************************************************/
+// Pet Egg Recipes
{
Id: 0
Name: "CraftEgg"
@@ -107,6 +108,8 @@ craft_db: (
Priority: 10
Price: 100
},
+
+// Generic Item Recipes
{
Id: 1
Name: "CraftPiouFeathers"
@@ -213,6 +216,8 @@ craft_db: (
Price: 0
ReturnCode: 123
},
+
+// Dye Recipes
{
Id: 2
Name: "CraftOrangeDye"
@@ -256,6 +261,8 @@ craft_db: (
}
Priority: 10
},
+
+// Equipment recipes
{
Id: 3
Name: "CraftItemWithDye"
@@ -304,4 +311,84 @@ craft_db: (
Priority: 10
},
+// Cooking
+// for Flag field, please see constants.conf (CRAFT enum)
+{
+ Id: 5
+ Name: "CraftCarpSandwich"
+ Flag: 4
+ SourceItems:
+ (
+ {
+ Bread: 1
+ LettuceLeaf: 3
+ Cheese: 2
+ CommonCarp: 1
+ },
+ {
+ Bread: 1
+ LettuceLeaf: 3
+ Cheese: 2
+ GrassCarp: 1
+ },
+ )
+ CreateItems:
+ (
+ {
+ CarpSandwich: 1
+ },
+ )
+ RequiredItems: {
+ RecipeBook: 1
+ }
+ Priority: 10
+},
+{
+ Id: 6
+ Name: "CraftPioulegSandwich"
+ Flag: 4
+ SourceItems:
+ (
+ {
+ Bread: 1
+ LettuceLeaf: 3
+ Cheese: 2
+ PiouLegs: 1
+ },
+ )
+ CreateItems:
+ (
+ {
+ PioulegSandwich: 1
+ },
+ )
+ RequiredItems: {
+ RecipeBook: 1
+ }
+ Priority: 10
+},
+{
+ Id: 7
+ Name: "CraftMananaSandwich"
+ Flag: 4
+ SourceItems:
+ (
+ {
+ Bread: 1
+ LettuceLeaf: 3
+ Cheese: 2
+ Manana: 1
+ },
+ )
+ CreateItems:
+ (
+ {
+ MananaSandwich: 1
+ },
+ )
+ RequiredItems: {
+ RecipeBook: 1
+ }
+ Priority: 10
+},
)
diff --git a/db/quest_db.conf b/db/quest_db.conf
index bc8acb82..2eef4e8d 100644
--- a/db/quest_db.conf
+++ b/db/quest_db.conf
@@ -182,6 +182,10 @@ quest_db: (
Name: "HurnscaldQuests_WoodenShield"
},
{
+ Id: 41
+ Name: "General_Cooking"
+},
+{
Id: 1000
Name: "Test_testing1"
},
diff --git a/db/re/item_db.conf b/db/re/item_db.conf
index ac6719cb..acf02a2f 100644
--- a/db/re/item_db.conf
+++ b/db/re/item_db.conf
@@ -1272,6 +1272,19 @@ item_db: (
">
},
{
+ Id: 539
+ AegisName: "RecipeBook"
+ Name: "Recipe Book"
+ Type: "IT_USABLE"
+ Buy: 80
+ Sell: 10
+ Weight: 20
+ KeepAfterUse: true
+ Script: <"
+ doevent "#RecipeBook::OnUse";
+ ">
+},
+{
Id: 560
AegisName: "CarpSandwich"
Name: "Carp Sandwich"
diff --git a/maps/re/001-3-0.mcache b/maps/re/001-3-0.mcache
index 7dd92e07..1c422edc 100644
--- a/maps/re/001-3-0.mcache
+++ b/maps/re/001-3-0.mcache
Binary files differ
diff --git a/npc/000-0-0/sailors.txt b/npc/000-0-0/sailors.txt
index 5aa56deb..87ed2b34 100644
--- a/npc/000-0-0/sailors.txt
+++ b/npc/000-0-0/sailors.txt
@@ -69,6 +69,7 @@ OnTalk:
addtimer(45000,"Magic Arpan::OnSlow");
warp "000-2-1", 50, 38;
savepoint "000-2-1", 50, 38;
+ percentheal 100, 100;
closeclientdialog;
close;
diff --git a/npc/000-2-1/peter.txt b/npc/000-2-1/peter.txt
index 341087a2..eaade56e 100644
--- a/npc/000-2-1/peter.txt
+++ b/npc/000-2-1/peter.txt
@@ -3,6 +3,7 @@
// 4144
// Ablu
// Alastrim
+// Jesusalva
// Qwerty Dragon
// Reid
// Vasily_Makarov
@@ -12,98 +13,58 @@
// ShipQuests
// Variable:
// ShipQuests_Peter
-// Values:
+// Values is a bitmask:
// 0 Doesn't know the quest.
-// 1 Task given.
-// 2 Task given and reward expected.
-// 3 Task completed without reward.
-// 4 Asked for reward after completion of the task.
-// 5 Task done and reward given.
-// 6 Did not start the quest.
+// 1 Task given. (To prevent bugs because zero is a valid instance id)
+// 2 Already completed the first stage
+// 4 Already completed the second stage
+// 8 Already completed the third stage
+// ...
+// =15 Completed every stage.
+// Setq2:
+// Number of killed Rattos:
+// & 1 - Ratto 1
+// & 2 - Ratto 2
+// & 4 - Ratto 3
+// & 8 - Ratto 4
+// = 15: All rattos killed
+// (Adding more monsters etc. is possible, but be careful with the == 15 checks)
+// Setq3:
+// Instance ID (so we can destroy it later if needed, and check it too)
// Others:
-// .@peter = Peter variable.
+// .@q = Peter variable.
+// PETER_TIME = gettimetick(2) for daily
+// @peter = Control Variable
+// @pt_mob = Control Variable
+// @MAP_NAME$ = Control Variable
// "000-2-2" - map with mobs.
-// "$@RAT_SAILOR_HELPER$" - Name of the participant.
-// "$@RAT_SAILOR_DEATHS - Number of deaths when the participant starts the fight.
-// "$@RAT_SAILOR_CONTROL" - Explanation of each index of the array.
-// "$@RAT_SAILOR_OLD_HELPER$" - Name of the participant.
-// "$@RAT_SAILOR_COUNTDOWN" - Seconds since the epoch of when the player done the quest.
-// [1] = Shows status of ratto number 1 (1 is dead and 0 is alive).
-// [2] = Shows status of ratto number 2 (1 is dead and 0 is alive).
-// [3] = Shows status of ratto number 3 (1 is dead and 0 is alive).
-// [4] = Shows status of ratto number 4 (1 is dead and 0 is alive).
-// [5] = Shows how many seconds passed since ratto number 1 died.
-// [6] = Shows how many seconds passed since ratto number 2 died.
-// [7] = Shows how many seconds passed since ratto number 3 died.
-// [8] = Shows how many seconds passed since ratto number 4 died.
-// [9] = Shows how many seconds passed since the player started the quest.
-// [10] = Shows how many seconds passed since the player done the quest.
000-2-1,72,34,0 script AreaNPC NPC_HIDDEN,0,1,{
-
+ end;
OnTouch:
- if (BaseLevel < 5) goto L_Stop;
- if ($@RAT_SAILOR_COUNTDOWN == 0) goto L_NoCountDown;
- if ((gettimetick(2) - $@RAT_SAILOR_COUNTDOWN) < 10) goto L_NoGoodTick;
- if (($@RAT_SAILOR_OLD_HELPER$ == strcharinfo(0)) && ((gettimetick(2) - $@RAT_SAILOR_COUNTDOWN) < 60)) goto L_NoGoodTick;
- $@RAT_SAILOR_COUNTDOWN = 0;
-
-L_NoCountDown:
- if ($@RAT_SAILOR_HELPER$ != "") goto L_Occupied;
- .@peter = getq(ShipQuests_Peter);
- if (.@peter < 1 || .@peter > 5) goto L_Task;
- if (.@peter == 1 || .@peter == 2) goto L_Rfail;
- if (.@peter == 3 || .@peter == 4) goto L_Rwin;
- if (.@peter > 5) goto L_SecondTime;
- doevent "Peter::OnReturnWin";
- close;
-
-L_Stop:
- doevent "Peter::OnStop";
-
- close;
-
-L_Occupied:
- doevent "Peter::OnDontneedHelp";
-
- close;
-
-L_Task:
- doevent "Peter::OnGiveTask";
-
- close;
-
-L_Rfail:
- doevent "Peter::OnReturnFail";
-
- close;
-
-L_Rwin:
- doevent "Peter::OnReturnWin";
-
- close;
-
-L_NoGoodTick:
- doevent "Peter::OnNoGoodTick";
-
+ doevent "Peter::OnPeterMain";
close;
}
000-2-1,70,35,0 script Peter NPC_RATTO_SAILOR,{
+ goto L_Main;
+
+OnPeterMain:
+L_Main:
+ .@q = getq(ShipQuests_Peter);
+ .@q2 = getq2(ShipQuests_Peter);
+ .@q3 = getq3(ShipQuests_Peter);
if (BaseLevel < 5) goto OnTooWeak;
- if ($@RAT_SAILOR_COUNTDOWN == 0) goto L_NoCountDown;
- if ((gettimetick(2) - $@RAT_SAILOR_COUNTDOWN) < 10) goto OnNoGoodTick;
- if (($@RAT_SAILOR_OLD_HELPER$ == strcharinfo(0)) && ((gettimetick(2) - $@RAT_SAILOR_COUNTDOWN) < 60)) goto OnNoGoodTick;
- $@RAT_SAILOR_COUNTDOWN = 0;
-L_NoCountDown:
- .@peter = getq(ShipQuests_Peter);
- if (.@peter == 1 || .@peter == 2) goto OnReturnFail;
- if (.@peter == 3 || .@peter == 4 || .@peter == 5) goto OnReturnWin;
+ if (!.@q || !isinstance(.@q3) || .@q3 <= 0) goto L_Task;
+ if (.@q2 < 15) goto L_ReturnFail;
+ dispbottom l("I am broken?! Please report! Debug data: @@ (@@)", .@q, .@q2);
+ close;
OnGiveTask:
- setq ShipQuests_Peter, 6;
- .@peter = getq(ShipQuests_Peter);
+L_Task:
+ if (!.@q)
+ setq ShipQuests_Peter, 1, 0, -1;
mesn;
mesq lg("Hey, girl!", "Hey, man!");
next;
@@ -112,225 +73,227 @@ OnGiveTask:
menu
l("Yeah, but what reward will I get?"), L_BonusTask,
- l("Why not, I need to train anyway."), L_Task,
+ l("Why not, I need to train anyway."), L_BonusTask,
l("No, they are way too dangerous for me!"), -;
mes "";
mesn;
mesq l("Hehe, hehe. Well, come back if you change your mind.");
- goto L_Quit;
+ close;
+
+// Friendly reminder that you have about 20 secs to finish
+OnLowTime:
+ if ((getmap() ~= "000-2-1") || (getmap() ~= "nard*"))
+ dispbottom lg("I'm starting to feel dizzy... I shouldn't stay here much longer.");
+ end;
+// Minimum Quest Level (any difficulty setting) is on L_Main (and currently is 5)
OnTooWeak:
mesn;
mesq lg("I need someone to help me clean the edge of the ship, but you aren't strong enough for now.");
- goto L_Quit;
+ close;
+/*
OnStop:
- warp "000-2-1", 72, 36;
+ slide 72, 36;
mesn;
mesq l("You can't go there!");
close;
+*/
+// This is cast if player dies in Basement, but not automatically (bad design?)
+// instance_destroy() is being recklessy called here, some sanity check is good.
OnReturnFail:
+L_ReturnFail:
+ .@q3 = getq3(ShipQuests_Peter);
+ //instance_destroy(.@q3); // This would allow players to try again at once, but is DANGEROUS!
+ setq2 ShipQuests_Peter, 0;
+ setq3 ShipQuests_Peter, -1;
mesn;
mesq l("I see it's not so easy to get rid of these rattos. Do you want to try again?");
next;
menu
l("Yeah, but I would like to make sure I get a reward."), L_BonusTask,
- l("Why not, I need to train anyway."), L_Task,
+ l("Why not, I need to train anyway."), L_BonusTask,
l("No, they are way too dangerous for me!"), -;
mes "";
mesn;
mesq l("Hehe, hehe. Well, come back if you change your mind.");
- goto L_Quit;
-
-OnReturnWin:
- .@peter = getq(ShipQuests_Peter);
- mesn;
- mesq l("Thanks again for helping me. Drats these rattos for infesting our fair vessal!");
- next;
- mesq l("They are a permanent problem so I will always need your help to exterminate them in order to keep their number under control.");
- next;
- mesq l("Your help is very welcome indeed. Unfortunately, I can give you a reward for the first extermination only.");
- next;
-
- if (.@peter == 3 || .@peter == 4)
- menu
- l("Did you say reward? I want it!"), L_BonusTask,
- l("I am not worried about rewards. I just want to help."), L_Task,
- l("Sorry, I am not in the mood for another fight with these rattos."), -;
-
- if (.@peter == 5)
- menu
- l("No problem, I can help you anyway."), L_Task,
- l("Sorry, I am not in the mood for another fight with these rattos."), -;
-
- mes "";
- mesn;
- mesq l("Hehe, hehe. Well, come back if you change your mind.");
-
close;
+
L_BonusTask:
mes "";
mesn;
- mesq l("What if I give you 1000 Esperin for that job, is it ok?");
+ mesq l("There are three kind of monsters which frequently or seldomly attacks our fair vessel.");
next;
-
- menu
- lg("Okay, I'm ready to work!"), -,
- l("What? This reward is too small!"), L_Quit;
-
- .@peter = getq(ShipQuests_Peter);
- if ($@RAT_SAILOR_HELPER$ != "") goto OnDontneedHelp;
- if (.@peter == 6) setq ShipQuests_Peter, 2;
- if (.@peter == 3) setq ShipQuests_Peter, 4;
- .@peter = getq(ShipQuests_Peter);
- goto L_Start;
-
-L_Task:
- .@peter = getq(ShipQuests_Peter);
- if ($@RAT_SAILOR_HELPER$ != "") goto OnDontneedHelp;
- if (.@peter == 6) setq ShipQuests_Peter, 1;
- .@peter = getq(ShipQuests_Peter);
-
-L_Start:
- mes "";
mesn;
- mesq l("Okay, you can start!");
-
-OnStartOutside:
- if ($@RAT_SAILOR_HELPER$ != "") goto OnDontneedHelp;
- $@RAT_SAILOR_HELPER$ = strcharinfo(0);
- $@RAT_SAILOR_DEATHS = PC_DIE_COUNTER;
- initnpctimer;
- warp "000-2-2", 48, 28;
- doevent "RattosControl::OnSpawn";
-
- goto L_Quit;
-
-OnTimer2000:
- if (attachrid(getcharid(3, $@RAT_SAILOR_HELPER$)) == 0) goto L_Logoff;
- $@RAT_SAILOR_CONTROL[9] = $@RAT_SAILOR_CONTROL[9] + 2;
- if ($@RAT_SAILOR_CONTROL[9] > 100) goto L_Timeout;
- if (PC_DIE_COUNTER > $@RAT_SAILOR_DEATHS) goto L_Dead;
- if ($@RAT_SAILOR_CONTROL[1] && $@RAT_SAILOR_CONTROL[2] && $@RAT_SAILOR_CONTROL[3] && $@RAT_SAILOR_CONTROL[4]) goto L_Done;
- if (getmapusers("000-2-2") == 0) goto L_CleaningEnd;
- goto L_CheckRattos;
-
- end;
-
-L_CheckRattos:
- if ($@RAT_SAILOR_CONTROL[1]) $@RAT_SAILOR_CONTROL[5] = $@RAT_SAILOR_CONTROL[5] + 2;
- if ($@RAT_SAILOR_CONTROL[2]) $@RAT_SAILOR_CONTROL[6] = $@RAT_SAILOR_CONTROL[6] + 2;
- if ($@RAT_SAILOR_CONTROL[3]) $@RAT_SAILOR_CONTROL[7] = $@RAT_SAILOR_CONTROL[7] + 2;
- if ($@RAT_SAILOR_CONTROL[4]) $@RAT_SAILOR_CONTROL[8] = $@RAT_SAILOR_CONTROL[8] + 2;
- if ($@RAT_SAILOR_CONTROL[5] > 45) doevent "RattosControl::OnRatto1Respawn";
- if ($@RAT_SAILOR_CONTROL[6] > 45) doevent "RattosControl::OnRatto2Respawn";
- if ($@RAT_SAILOR_CONTROL[7] > 45) doevent "RattosControl::OnRatto3Respawn";
- if ($@RAT_SAILOR_CONTROL[8] > 45) doevent "RattosControl::OnRatto4Respawn";
-
-L_NotYet:
- setnpctimer 0;
-
- end;
-
-OnDontneedHelp:
- mesn;
- mesq l("I don't need your help right now, come back later.");
+ .@q = getq(ShipQuests_Peter);
+ if (!(.@q & 2)) {
+ mes l("- I currently need your help with @@.", getmonsterlink(Tortuga));
+ mes l("I'll give you @@ GP for this job.", 500);
+ mes "";
+ }
+ if (!(.@q & 4)) {
+ mes l("- I currently need your help with @@.", getmonsterlink(Ratto));
+ mes l("I'll give you @@ GP for this job.", 1000);
+ mes "";
+ }
+ if (!(.@q & 8)) {
+ mes l("- I currently need your help with @@.", getmonsterlink(Croc));
+ mes l("I'll give you @@ GP for this job.", 1500);
+ mes "";
+ }
+ // If you already took all three bounties, you can only repeat the quest daily
+ if (.@q == 15 && PETER_TIME <= gettimetick(2)) {
+ mes l("- I currently need your help with @@.", getmonsterlink(Ratto));
+ mes l("I'll give you @@ GP for this job.", 750);
+ } else if (.@q == 15) {
+ mes l("I don't need your help right now, but maybe tomorrow, who knows?");
+ close;
+ }
next;
- mesq l("@@ is helping me.", $@RAT_SAILOR_HELPER$);
- goto L_Quit;
+ select
+ l("I'm not feeling like it today... Sorry."),
+ rif(!(.@q & 2), l("I will take the @@ Bounty.", "Tortuga")),
+ rif(!(.@q & 4), l("I will take the @@ Bounty.", "Ratto")),
+ rif(!(.@q & 8), l("I will take the @@ Bounty.", "Croc")),
+ rif(.@q == 15, l("Why not, I need to train anyway."));
-L_Timeout:
- mesn;
- mesq l("Hey! Be careful. You can't stay in this basement for so long, you're going to get sick. Come outside and take a break, maybe you can try again later.");
- warp "000-2-1", 72, 36;
+ if (@menu == 1)
+ close;
- goto L_CleaningClose;
+ @peter=@menu;
-L_Logoff:
- goto L_CleaningEnd;
+ goto L_Start;
-L_Dead:
-// Warps the dead body outside, so it does not interfere with the getmapusers check.
- if (getmapusers("000-2-2") > 0) warp "000-2-1", 72, 36;
+// In Moubootaur Legends, there's a small tutorial about Hit'n'run here
+// I didn't add it here but that can be arranged
+L_Start:
+// Init Instance
+OnStartOutside:
+ .@ID=getcharid(0);
+ @MAP_NAME$="nard@"+str(.@ID); // Max 4 chars for map name
+ .@INSTID = instance_create("ratto@a"+(.@ID), getcharid(3), IOT_CHAR);
+ .@instanceMapName$ = instance_attachmap("000-2-2", .@INSTID, 0, @MAP_NAME$);
+
+ // Instance already exists, or something went wrong
+ if (.@instanceMapName$ == "") {
+ mesn;
+ mesq l("Actually, you just took a bounty, right?");
+ next;
+ mesn;
+ mesq l("Why don't you take a break? Breath in some fresh air. The basement is pretty damp.");
+ close;
+ }
+
+ setq2 ShipQuests_Peter, 0;
+ setq3 ShipQuests_Peter, .@INSTID;
+
+ // It'll be self-destroyed when time runs out (3 minutes)
+ instance_set_timeout(180, 180, .@INSTID);
+ instance_init(.@INSTID);
+
+ // Save in a less reliable way the challenge you took
+ if (@peter == 2) {
+ @peter=2;
+ @pt_mob=Tortuga;
+ } else if (@peter == 3) {
+ @peter=4;
+ @pt_mob=Ratto;
+ } else if (@peter == 4) {
+ @peter=8;
+ @pt_mob=Croc;
+ } else {
+ @peter=0;
+ @pt_mob=Ratto;
+ }
+
+ warp @MAP_NAME$, 48, 28;
+ // Control how much time you have left
+ addtimer(120000, "Peter::OnLowTime");
+ addtimer(140000, "Peter::OnTimeout");
+
+ // Spawn the Monsters
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl::OnRatto1Death";
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl::OnRatto2Death";
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl::OnRatto3Death";
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl::OnRatto4Death";
+
+ dispbottom l("Okay, you can start!");
+ closeclientdialog;
+ close;
- goto L_CleaningEnd;
+// TODO: This is very reckless, instance_destroy() could possibly affect others
+// If you agree with me, we can force player to wait until instance expire on its
+// own (3 minutes after start) instead of allowing immediate retry. That's safer,
+// and code will end up looking like Mundane (exploiting attach_map failures)
-L_Done:
- $@RAT_SAILOR_CONTROL[10] = $@RAT_SAILOR_CONTROL[10] + 2;
- if($@RAT_SAILOR_CONTROL[10] < 5) goto L_NotYet;
- .@peter = getq(ShipQuests_Peter);
- if (.@peter == 2 || .@peter == 4) goto L_Reward;
+// (Or if you are set in disregarding this, just uncomment instance_destroy.)
+// (Don't blame me if server SIGSEGV's because that, though)
+OnTimeout:
+ if (!(getmap() ~= "000-2-2") && !(getmap() ~= "nard*"))
+ end;
warp "000-2-1", 72, 36;
-
- goto L_Thanks;
-
-L_CleaningEnd:
- stopnpctimer;
- $@RAT_SAILOR_HELPER$ = "";
- $@RAT_SAILOR_DEATHS = 0;
- cleararray $@RAT_SAILOR_CONTROL, 0, 11;
- killmonster "000-2-2", "RattosControl::OnRatto1Death";
- killmonster "000-2-2", "RattosControl::OnRatto2Death";
- killmonster "000-2-2", "RattosControl::OnRatto3Death";
- killmonster "000-2-2", "RattosControl::OnRatto4Death";
-
- end;
-
-L_CleaningClose:
- stopnpctimer;
- $@RAT_SAILOR_OLD_HELPER$ = $@RAT_SAILOR_HELPER$;
- $@RAT_SAILOR_HELPER$ = "";
- $@RAT_SAILOR_DEATHS = 0;
- cleararray $@RAT_SAILOR_CONTROL, 0, 11;
- killmonster "000-2-2", "RattosControl::OnRatto1Death";
- killmonster "000-2-2", "RattosControl::OnRatto2Death";
- killmonster "000-2-2", "RattosControl::OnRatto3Death";
- killmonster "000-2-2", "RattosControl::OnRatto4Death";
- $@RAT_SAILOR_COUNTDOWN = gettimetick(2);
-
+ .@q3 = getq3(ShipQuests_Peter);
+ //instance_destroy(.@q3);
+ setq2 ShipQuests_Peter, 0;
+ setq3 ShipQuests_Peter, -1;
+ mesn;
+ mesq l("Hey! Be careful. You can't stay in this basement for so long, you're going to get sick. Come outside and take a break, maybe you can try again later.");
close;
-L_Reward:
- warp "000-2-1", 72, 36;
- setq ShipQuests_Peter, 5;
- .@peter = getq(ShipQuests_Peter);
+// This is called by npc/000-2-2/ratto.txt and completes the quest
+// Just like OnReturnFail and OnTimeout, this recklessy destroys the instance
+// It's not _buggy_, it is just reckless. I would like a setting to restrict it
+// to destroy only instances owned by the char, or to destroy by name :p
+OnDone:
+ .@q3 = getq3(ShipQuests_Peter);
+ //instance_destroy(.@q3);
+ if (@peter)
+ setq ShipQuests_Peter, getq(ShipQuests_Peter)|@peter, 0, -1;
+
+ .@q = getq(ShipQuests_Peter);
mesn;
mesq l("Good job!") + " " + l("Here's your reward!");
- getexp 100, 0;
- Zeny = Zeny + 1000;
- message strcharinfo(0), l("You receive @@ E!", 1000);
-
- goto L_CleaningClose;
-L_Thanks:
- mesn;
- mesq l("Thanks for helping me!");
- .@peter = getq(ShipQuests_Peter);
- if (.@peter == 1) setq ShipQuests_Peter, 3;
- .@peter = getq(ShipQuests_Peter);
-
- goto L_CleaningClose;
-
-L_Quit:
- .@peter = 0;
+ // Before handling the rewards, we should be sure we'll handle daily loop.
+ // You're already in daily phase if @peter is zero.
+ // PS. This is not exactly "daily", this is actually a forced 24-hours wait.
+ if (!@peter) {
+ PETER_TIME=gettimetick(2)+24*60*60;
+ @peter=1; // This allows you to get 32 EXP from daily repeat. Tweak as needed.
+ }
+
+ // You get some EXP based on difficulty taken
+ getexp @peter*32, @peter;
+
+ // We don't need @peter anymore, so reuse it to give you GP rewards
+ switch (@peter) {
+ case 2: @peter=500; break;
+ case 4: @peter=1000; break;
+ case 8: @peter=1500; break;
+ default: @peter=750; break;
+ }
+
+ Zeny = Zeny + @peter;
+ message strcharinfo(0), l("You receive @@ E!", @peter);
+
+ // Some cleanup. Shouldn't cause bugs but it's absence causes a ugly behavior.
+ deltimer("Peter::OnLowTime");
+ deltimer("Peter::OnTimeout");
+ @peter=0;
close;
-OnNoGoodTick:
- mesn;
- mesq l("I don't need your help right now, come back later.");
- close;
OnInit:
.sex = G_MALE;
diff --git a/npc/000-2-2/doors.txt b/npc/000-2-2/doors.txt
index 414545ef..c97a7c5d 100644
--- a/npc/000-2-2/doors.txt
+++ b/npc/000-2-2/doors.txt
@@ -2,6 +2,7 @@
// Authors:
// Ablu
// Alastrim
+// Jesusalva
// Reid
// Description:
// Doors NPCs.
@@ -9,32 +10,37 @@
000-2-2,48,29,0 script DoorUpwards NPC_HIDDEN,0,0,{
OnTouch:
+ // Actually this will never work because Instanced map
if (mobcount("000-2-2","all") > 0) goto L_Warn;
goto L_Warp;
L_Warn:
.@q = getq(ShipQuests_Peter);
- if (.@q == 5) goto L_Warp;
+ if (.@q >= 15) goto L_Warp;
mesn "Narrator";
- mesc(l("There are still some rattos left! Do you want to abort the quest?"), 9);
+ mesc(l("There are still some monsters left! Do you want to abort the quest?"), 9);
next;
menu
l("Yes."), L_Warp,
l("No."), -;
- warp "000-2-2", 48, 28;
+ slide 48, 28;
closeclientdialog;
close;
L_Warp:
warp "000-2-1", 72, 36;
+
+ deltimer("Peter::OnLowTime");
+ deltimer("Peter::OnTimeout");
closeclientdialog;
close;
}
+// Besides the door, Alige is hiding himself and would rather not be disturbed
000-2-2,24,31,0 script LeftDoor NPC_HIDDEN,0,0,{
OnTouch:
@@ -45,7 +51,7 @@ OnTouch:
next;
menu
- rif(countitem(718) > 0, l("Use the key.")), L_Warp,
+ rif(countitem(JohanneKey) > 0, l("Use the key.")), L_Warp,
l("Break the door."), L_Break,
l("Go away."), -;
diff --git a/npc/000-2-2/ratto.txt b/npc/000-2-2/ratto.txt
index 1392d571..14f98201 100644
--- a/npc/000-2-2/ratto.txt
+++ b/npc/000-2-2/ratto.txt
@@ -1,68 +1,97 @@
-// Evol scripts.
-// Authors:
-// Ablu
-// Alastrim
-// Reid
+// Evol Script.
+// Author:
+// Ablu
+// Alastrim
+// Jesusalva
+// Reid
// Description:
// Ratto killer.
+// The only "lose" conditions are:
+// 1- dying, but this is not handled anywhere
+// 2- Time running out, Peter handles that automatically.
+// Note that if you die here, you won't be able to return and will need to
+// start the quest over again. (I wonder why it is not handled by an OnDeath event)
+// iirc, logout will automatically destroy the instance and clear timers, so it
+// doesn't needs the script writer to handle logout cleanup (only death).
-// $@RAT_SAILOR_CONTROL array explanation:
-// [1] = Shows status of ratto number 1 (1 is dead and 0 is alive).
-// [2] = Shows status of ratto number 2 (1 is dead and 0 is alive).
-// [3] = Shows status of ratto number 3 (1 is dead and 0 is alive).
-// [4] = Shows status of ratto number 4 (1 is dead and 0 is alive).
-// [5] = Shows how many seconds passed since ratto number 1 died.
-// [6] = Shows how many seconds passed since ratto number 2 died.
-// [7] = Shows how many seconds passed since ratto number 3 died.
-// [8] = Shows how many seconds passed since ratto number 4 died.
-// [9] = Shows how many seconds passed since the player started the quest.
-
-000-2-2,47,30,0 script RattosControl NPC_HIDDEN,{
-
-OnSpawn:
- areamonster "000-2-2", 23, 19, 50, 40, "Ratto", 1005, 1, "RattosControl::OnRatto1Death";
- areamonster "000-2-2", 23, 19, 50, 40, "Ratto", 1005, 1, "RattosControl::OnRatto2Death";
- areamonster "000-2-2", 23, 19, 50, 40, "Ratto", 1005, 1, "RattosControl::OnRatto3Death";
- areamonster "000-2-2", 23, 19, 50, 40, "Ratto", 1005, 1, "RattosControl::OnRatto4Death";
- close;
+000-2-2,0,0,0 script RattosControl NPC_HIDDEN,{
+ end;
+// Each monster on the basement have its own respawn cycle.
+// We use a XOR (^) operand to mark that the killed monster is not dead anymore.
+// This is to reproduce as accurate as possible the legacy behavior of the quest.
OnRatto1Respawn:
- areamonster "000-2-2", 23, 19, 50, 40, "Ratto", 1005, 1, "RattosControl::OnRatto1Death";
- $@RAT_SAILOR_CONTROL[1] = 0;
- $@RAT_SAILOR_CONTROL[5] = 0;
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2^1;
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl::OnRatto1Death";
end;
OnRatto2Respawn:
- areamonster "000-2-2", 23, 19, 50, 40, "Ratto", 1005, 1, "RattosControl::OnRatto2Death";
- $@RAT_SAILOR_CONTROL[2] = 0;
- $@RAT_SAILOR_CONTROL[6] = 0;
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2^2;
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl::OnRatto2Death";
end;
OnRatto3Respawn:
- areamonster "000-2-2", 23, 19, 50, 40, "Ratto", 1005, 1, "RattosControl::OnRatto3Death";
- $@RAT_SAILOR_CONTROL[3] = 0;
- $@RAT_SAILOR_CONTROL[7] = 0;
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2^4;
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl::OnRatto3Death";
end;
OnRatto4Respawn:
- areamonster "000-2-2", 23, 19, 50, 40, "Ratto", 1005, 1, "RattosControl::OnRatto4Death";
- $@RAT_SAILOR_CONTROL[4] = 0;
- $@RAT_SAILOR_CONTROL[8] = 0;
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2^8;
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl::OnRatto4Death";
end;
+// When you kill a monster on basement, we must check the mob as dead, see if you
+// finally killed the last one and quest is complete, and add a timer to respawn it
+// after 1m25s (for flavor purposes, makes quest harder though)
OnRatto1Death:
- $@RAT_SAILOR_CONTROL[1] = 1;
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2|1;
+ .@q2=getq2(ShipQuests_Peter);
+ if (.@q2 == 15)
+ goto L_Victor;
+ addtimer(85000, "RattosControl::OnRatto1Respawn");
end;
OnRatto2Death:
- $@RAT_SAILOR_CONTROL[2] = 1;
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2|2;
+ .@q2=getq2(ShipQuests_Peter);
+ if (.@q2 == 15)
+ goto L_Victor;
+ addtimer(85000, "RattosControl::OnRatto2Respawn");
end;
OnRatto3Death:
- $@RAT_SAILOR_CONTROL[3] = 1;
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2|4;
+ .@q2=getq2(ShipQuests_Peter);
+ if (.@q2 == 15)
+ goto L_Victor;
+ addtimer(85000, "RattosControl::OnRatto3Respawn");
end;
OnRatto4Death:
- $@RAT_SAILOR_CONTROL[4] = 1;
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2|8;
+ .@q2=getq2(ShipQuests_Peter);
+ if (.@q2 == 15)
+ goto L_Victor;
+ addtimer(85000, "RattosControl::OnRatto4Respawn");
+ end;
+
+// This label is reached when all rattos are dead. We clear the respawn timers
+// (as we are going to delete the instance map anyway), warp you outside, and
+// from there onwards, Peter handles properly rewarding you.
+L_Victor:
+ warp "000-2-1", 72, 36;
+ deltimer("RattosControl::OnRatto1Respawn");
+ deltimer("RattosControl::OnRatto2Respawn");
+ deltimer("RattosControl::OnRatto3Respawn");
+ deltimer("RattosControl::OnRatto4Respawn");
+ doevent("Peter::OnDone");
end;
}
diff --git a/npc/001-1/manhole.txt b/npc/001-1/manhole.txt
index 856689a3..3e8a5bc8 100644
--- a/npc/001-1/manhole.txt
+++ b/npc/001-1/manhole.txt
@@ -1,5 +1,6 @@
// Evol scripts.
// Author:
+// Jesusalva
// Reid
// Description:
// A manhole near Mona's house.
@@ -11,32 +12,14 @@
001-1,152,52,0 script #manhole1-001-1 NPC_NO_SPRITE,{
- if (getq(ArtisQuests_MonaDad) < 1) {
- end;
- }
-
- narrator(S_LAST_BLANK_LINE | S_LAST_NEXT,
- l("You hear some creeping and crawling sounds from the murkiness below."),
- l("..."),
- l("Do you want to enter in sewer?"));
-
+ .@i=manhole_interact("001-3-0");
closeclientdialog();
- if (askyesno() == 1) slide_or_warp("001-3-0", 152, 56);
- close;
-
-OnTouch:
- // (has_instance2 wasn't checked if it works)
- if (getq(ArtisQuests_MonaDad) == 2 && has_instance2("mona@"+strcharinfo(0)) >= 0) {
- mesn l("Mundane");
- mesq l("Thanks for saving me. This is enough, I'll watch if Mona is fine and return to Sewers later.");
- next;
- inventoryplace WoodenBow, 1;
- mesn l("Mundane");
- mesq lg("Here, take this @@ as a gift. I'm sure someone as skilled you will make a good use of my old weapon.", "Here, take this @@ as a gift. I'm sure someone as skilled you will make a good use of my old weapon.", getitemlink(WoodenBow));
- getitem WoodenBow, 1;
- setq(ArtisQuests_MonaDad, 3);
+ if (.@i == -1) {
+ slide_or_warp("001-3-0", 152, 56);
+ } else if (.@i == TrainingArrow || .@i == WoodenBow) {
+ npctalk3 l("(You hear a faint sound in distance, but can't say what sound it was.)");
}
- end;
+ close;
OnInit:
.sex = G_OTHER;
@@ -51,7 +34,7 @@ OnInit:
if (.@i == -1) {
slide_or_warp("001-3-0", 196, 36);
} else if (.@i == TrainingArrow || .@i == WoodenBow) {
- npctalk3 l("Mundane: Hey! Is someone there? Please, help, it's so dark down here!");
+ npctalk3 l("???: Hey! Is someone there? Please, help, it's so dark down here!");
}
close;
@@ -106,3 +89,4 @@ OnInit:
// To quickly create more sewer mouths we can use:
//001-1,86,131,0 duplicate(#manhole3-001-1) #manhole4-001-1 NPC_NO_SPRITE
+
diff --git a/npc/001-2-11/mona.txt b/npc/001-2-11/mona.txt
index 17a72631..366b658c 100644
--- a/npc/001-2-11/mona.txt
+++ b/npc/001-2-11/mona.txt
@@ -1,13 +1,20 @@
// Evol scripts.
// Author:
// Reid
+// Jesusalva
// Description:
-// A rich girl holding a candle.
+// A rich girl holding a candle. Her father went to examine weird noises on
+// sewers and still haven't come back. Her mother is gone, but it is not clear
+// if she died, abandoned them, or something else.
// Variable:
// ArtisQuests_MonaDad
// Quest states:
// 0 - Quest not started
// 1 - Mona explained that her dad was missing
+// 2 - Player is bringing Mundane out of Sewers
+// 3 - Quest is complete
+// Note:
+// Any misformatted code is Jesusalva's fault.
001-2-11,39,30,0 script Mona NPC_MONA,{
@@ -50,13 +57,51 @@
close;
}
+ // You're here to report that Mundane is out of the sewers.
+ // Forcing you to enter an instanced map would require more work.
+ // This means adding a warp NPC and a global instance.
+ // Global Instances get reset every 10 days or so, it would need a patch
+ // only to support Global Instances and in general is not a smart thing to do.
+ function check_daddy_quest
+ {
+ // Did you really brought Mundane to sewer exit (152, 56)?
+ // We need to add 1 tile in each direction of tolerance because addtimer()
+ // is not exactly what I would call “a reliable way to do stuff”
+ // Note that @variables sometimes get erasen AT RANDOM.
+ // If this problem happens, move it char variables.
+ // (that might cause problems with logout though.)
+ // Temporary variables give you a time limit to report back...
+ if (@MUNDANE_OLDX >= 151 && @MUNDANE_OLDX <= 153 &&
+ @MUNDANE_OLDY >= 55 && @MUNDANE_OLDY <= 57) {
+ // There's no need to check if instance still exists, because
+ // when the instance expires, you get warped to *somewhere*.
+ // This means the timer will die and MUNDANE_OLD* variables will stop
+ // being updated.
+ inventoryplace WoodenBow, 1;
+ speech 0x0,
+ l("Daddy finally came back home! He grabbed a snack and said he would be returning to the sewers."),
+ lg("He did said to you take this @@ as a gift. He says you are very skilled and will make a good use of his old weapon.",
+ "He did said to you take this @@ as a gift. He says you are very skilled and will make a good use of his old weapon.",
+ getitemlink(WoodenBow)),
+ l("He was never the same since mommy vanished...");
+ getitem WoodenBow, 1;
+ setq(ArtisQuests_MonaDad, 3);
+ close;
+ }
+ }
+
+ // Here the script really starts
if (getq(ArtisQuests_MonaDad) == 0)
{
find_daddy_quest();
}
else if (getq(ArtisQuests_MonaDad) == 3)
{
- npctalkonce l("Thanks for finding daddy... I wish he spent more time with me...");
+ npctalkonce l("Thanks for finding daddy... I wish he spent more time with me..."); // TODO: Sophialla
+ }
+ else if (getq(ArtisQuests_MonaDad) == 2)
+ {
+ check_daddy_quest();
}
else
{
@@ -68,6 +113,7 @@
OnInit:
.sex = G_FEMALE;
- .distance = 2;
+ .distance = 3;
end;
}
+
diff --git a/npc/001-2-22/peter.txt b/npc/001-2-22/peter.txt
index 0365392a..7fefb5f2 100644
--- a/npc/001-2-22/peter.txt
+++ b/npc/001-2-22/peter.txt
@@ -3,6 +3,7 @@
// 4144
// Ablu
// Alastrim
+// Jesusalva
// Qwerty Dragon
// Reid
// Vasily_Makarov
@@ -12,98 +13,58 @@
// ShipQuests
// Variable:
// ShipQuests_Peter
-// Values:
+// Values is a bitmask:
// 0 Doesn't know the quest.
-// 1 Task given.
-// 2 Task given and reward expected.
-// 3 Task completed without reward.
-// 4 Asked for reward after completion of the task.
-// 5 Task done and reward given.
-// 6 Did not start the quest.
+// 1 Task given. (To prevent bugs because zero is a valid instance id)
+// 2 Already completed the first stage
+// 4 Already completed the second stage
+// 8 Already completed the third stage
+// ...
+// =15 Completed every stage.
+// Setq2:
+// Number of killed Rattos:
+// & 1 - Ratto 1
+// & 2 - Ratto 2
+// & 4 - Ratto 3
+// & 8 - Ratto 4
+// = 15: All rattos killed
+// (Adding more monsters etc. is possible, but be careful with the == 15 checks)
+// Setq3:
+// Instance ID (so we can destroy it later if needed, and check it too)
// Others:
-// .@peter = Peter#001-2-22 variable.
+// .@q = Peter variable.
+// PETER_TIME = gettimetick(2) for daily
+// @peter = Control Variable
+// @pt_mob = Control Variable
+// @MAP_NAME$ = Control Variable
// "001-2-23" - map with mobs.
-// "$@ARTIS_RAT1_HELPER$" - Name of the participant.
-// "$@ARTIS_RAT1_DEATHS - Number of deaths when the participant starts the fight.
-// "$@ARTIS_RAT1_CONTROL" - Explanation of each index of the array.
-// "$@ARTIS_RAT1_OLD_HELPER$" - Name of the participant.
-// "$@ARTIS_RAT1_COUNTDOWN" - Seconds since the epoch of when the player done the quest.
-// [1] = Shows status of ratto number 1 (1 is dead and 0 is alive).
-// [2] = Shows status of ratto number 2 (1 is dead and 0 is alive).
-// [3] = Shows status of ratto number 3 (1 is dead and 0 is alive).
-// [4] = Shows status of ratto number 4 (1 is dead and 0 is alive).
-// [5] = Shows how many seconds passed since ratto number 1 died.
-// [6] = Shows how many seconds passed since ratto number 2 died.
-// [7] = Shows how many seconds passed since ratto number 3 died.
-// [8] = Shows how many seconds passed since ratto number 4 died.
-// [9] = Shows how many seconds passed since the player started the quest.
-// [10] = Shows how many seconds passed since the player done the quest.
-
-001-2-22,72,34,0 script AreaNPC#001-2-22 NPC_HIDDEN,0,1,{
+001-2-22,72,34,0 script AreaNPC#Artis NPC_HIDDEN,0,1,{
+ end;
OnTouch:
- if (BaseLevel < 5) goto L_Stop;
- if ($@ARTIS_RAT1_COUNTDOWN == 0) goto L_NoCountDown;
- if ((gettimetick(2) - $@ARTIS_RAT1_COUNTDOWN) < 10) goto L_NoGoodTick;
- if (($@ARTIS_RAT1_OLD_HELPER$ == strcharinfo(0)) && ((gettimetick(2) - $@ARTIS_RAT1_COUNTDOWN) < 60)) goto L_NoGoodTick;
- $@ARTIS_RAT1_COUNTDOWN = 0;
-
-L_NoCountDown:
- if ($@ARTIS_RAT1_HELPER$ != "") goto L_Occupied;
- .@peter = getq(ShipQuests_Peter);
- if (.@peter < 1 || .@peter > 5) goto L_Task;
- if (.@peter == 1 || .@peter == 2) goto L_Rfail;
- if (.@peter == 3 || .@peter == 4) goto L_Rwin;
- if (.@peter > 5) goto L_SecondTime;
- doevent "Peter#001-2-22::OnReturnWin";
- close;
-
-L_Stop:
- doevent "Peter#001-2-22::OnStop";
-
- close;
-
-L_Occupied:
- doevent "Peter#001-2-22::OnDontneedHelp";
-
- close;
-
-L_Task:
- doevent "Peter#001-2-22::OnGiveTask";
-
- close;
-
-L_Rfail:
- doevent "Peter#001-2-22::OnReturnFail";
-
- close;
-
-L_Rwin:
- doevent "Peter#001-2-22::OnReturnWin";
-
- close;
-
-L_NoGoodTick:
- doevent "Peter#001-2-22::OnNoGoodTick";
-
+ doevent "Peter::OnPeterMain";
close;
}
-001-2-22,70,35,0 script Peter#001-2-22 NPC_RATTO_SAILOR,{
+001-2-22,70,35,0 script Peter#Artis NPC_RATTO_SAILOR,{
+ goto L_Main;
+
+OnPeterMain:
+L_Main:
+ .@q = getq(ShipQuests_Peter);
+ .@q2 = getq2(ShipQuests_Peter);
+ .@q3 = getq3(ShipQuests_Peter);
if (BaseLevel < 5) goto OnTooWeak;
- if ($@ARTIS_RAT1_COUNTDOWN == 0) goto L_NoCountDown;
- if ((gettimetick(2) - $@ARTIS_RAT1_COUNTDOWN) < 10) goto OnNoGoodTick;
- if (($@ARTIS_RAT1_OLD_HELPER$ == strcharinfo(0)) && ((gettimetick(2) - $@ARTIS_RAT1_COUNTDOWN) < 60)) goto OnNoGoodTick;
- $@ARTIS_RAT1_COUNTDOWN = 0;
-L_NoCountDown:
- .@peter = getq(ShipQuests_Peter);
- if (.@peter == 1 || .@peter == 2) goto OnReturnFail;
- if (.@peter == 3 || .@peter == 4 || .@peter == 5) goto OnReturnWin;
+ if (!.@q || !isinstance(.@q3) || .@q3 <= 0) goto L_Task;
+ if (.@q2 < 15) goto L_ReturnFail;
+ dispbottom l("I am broken?! Please report! Debug data: @@ (@@)", .@q, .@q2);
+ close;
OnGiveTask:
- setq ShipQuests_Peter, 6;
- .@peter = getq(ShipQuests_Peter);
+L_Task:
+ if (!.@q)
+ setq ShipQuests_Peter, 1, 0, -1;
mesn;
mesq lg("Hey, girl!", "Hey, man!");
next;
@@ -112,221 +73,227 @@ OnGiveTask:
menu
l("Yeah, but what reward will I get?"), L_BonusTask,
- l("Why not, I need to train anyway."), L_Task,
+ l("Why not, I need to train anyway."), L_BonusTask,
l("No, they are way too dangerous for me!"), -;
mes "";
mesn;
mesq l("Hehe, hehe. Well, come back if you change your mind.");
- goto L_Quit;
+ close;
+
+// Friendly reminder that you have about 20 secs to finish
+OnLowTime:
+ if ((getmap() ~= "001-2-22") || (getmap() ~= "nard*"))
+ dispbottom lg("I'm starting to feel dizzy... I shouldn't stay here much longer.");
+ end;
+// Minimum Quest Level (any difficulty setting) is on L_Main (and currently is 5)
OnTooWeak:
mesn;
mesq lg("I need someone to help me clean the edge of the ship, but you aren't strong enough for now.");
- goto L_Quit;
+ close;
+/*
OnStop:
- warp "001-2-22", 72, 36;
+ slide 72, 36;
mesn;
mesq l("You can't go there!");
close;
+*/
+// This is cast if player dies in Basement, but not automatically (bad design?)
+// instance_destroy() is being recklessy called here, some sanity check is good.
OnReturnFail:
+L_ReturnFail:
+ .@q3 = getq3(ShipQuests_Peter);
+ //instance_destroy(.@q3); // This would allow players to try again at once, but is DANGEROUS!
+ setq2 ShipQuests_Peter, 0;
+ setq3 ShipQuests_Peter, -1;
mesn;
mesq l("I see it's not so easy to get rid of these rattos. Do you want to try again?");
next;
menu
l("Yeah, but I would like to make sure I get a reward."), L_BonusTask,
- l("Why not, I need to train anyway."), L_Task,
+ l("Why not, I need to train anyway."), L_BonusTask,
l("No, they are way too dangerous for me!"), -;
mes "";
mesn;
mesq l("Hehe, hehe. Well, come back if you change your mind.");
- goto L_Quit;
-
-OnReturnWin:
- .@peter = getq(ShipQuests_Peter);
- mesn;
- mesq l("Thanks again for helping me. Drats these rattos for infesting our fair vessal! They are a permanent problem so I will always need your help to exterminate them in order to keep their number under control. Your help is very welcome indeed. Unfortunately, I can give you a reward only for the first extermination.");
- next;
-
- if (.@peter == 3 || .@peter == 4)
- menu
- l("Did you say reward? I want it!"), L_BonusTask,
- l("I am not worried about rewards. I just want to help."), L_Task,
- l("Sorry, I am not in the mood for another fight with these rattos."), -;
-
- if (.@peter == 5)
- menu
- l("No problem, I can help you anyway."), L_Task,
- l("Sorry, I am not in the mood for another fight with these rattos."), -;
-
- mes "";
- mesn;
- mesq l("Hehe, hehe. Well, come back if you change your mind.");
-
close;
+
L_BonusTask:
mes "";
mesn;
- mesq l("What if I give you 1000 Esperin for that job, is it ok?");
+ mesq l("There are three kind of monsters which frequently or seldomly attacks our fair vessel.");
next;
-
- menu
- lg("Okay, I'm ready to work!"), -,
- l("What? This reward is too small!"), L_Quit;
-
- .@peter = getq(ShipQuests_Peter);
- if ($@ARTIS_RAT1_HELPER$ != "") goto OnDontneedHelp;
- if (.@peter == 6) setq ShipQuests_Peter, 2;
- if (.@peter == 3) setq ShipQuests_Peter, 4;
- .@peter = getq(ShipQuests_Peter);
- goto L_Start;
-
-L_Task:
- .@peter = getq(ShipQuests_Peter);
- if ($@ARTIS_RAT1_HELPER$ != "") goto OnDontneedHelp;
- if (.@peter == 6) setq ShipQuests_Peter, 1;
- .@peter = getq(ShipQuests_Peter);
-
-L_Start:
- mes "";
- mesn;
- mesq l("Okay, you can start!");
-
-OnStartOutside:
- if ($@ARTIS_RAT1_HELPER$ != "") goto OnDontneedHelp;
- $@ARTIS_RAT1_HELPER$ = strcharinfo(0);
- $@ARTIS_RAT1_DEATHS = PC_DIE_COUNTER;
- initnpctimer;
- warp "001-2-23", 48, 28;
- doevent "RattosControl#001-2-23::OnSpawn";
-
- goto L_Quit;
-
-OnTimer2000:
- if (attachrid(getcharid(3, $@ARTIS_RAT1_HELPER$)) == 0) goto L_Logoff;
- $@ARTIS_RAT1_CONTROL[9] = $@ARTIS_RAT1_CONTROL[9] + 2;
- if ($@ARTIS_RAT1_CONTROL[9] > 100) goto L_Timeout;
- if (PC_DIE_COUNTER > $@ARTIS_RAT1_DEATHS) goto L_Dead;
- if ($@ARTIS_RAT1_CONTROL[1] && $@ARTIS_RAT1_CONTROL[2] && $@ARTIS_RAT1_CONTROL[3] && $@ARTIS_RAT1_CONTROL[4]) goto L_Done;
- if (getmapusers("001-2-23") == 0) goto L_CleaningEnd;
- goto L_CheckRattos;
-
- end;
-
-L_CheckRattos:
- if ($@ARTIS_RAT1_CONTROL[1]) $@ARTIS_RAT1_CONTROL[5] = $@ARTIS_RAT1_CONTROL[5] + 2;
- if ($@ARTIS_RAT1_CONTROL[2]) $@ARTIS_RAT1_CONTROL[6] = $@ARTIS_RAT1_CONTROL[6] + 2;
- if ($@ARTIS_RAT1_CONTROL[3]) $@ARTIS_RAT1_CONTROL[7] = $@ARTIS_RAT1_CONTROL[7] + 2;
- if ($@ARTIS_RAT1_CONTROL[4]) $@ARTIS_RAT1_CONTROL[8] = $@ARTIS_RAT1_CONTROL[8] + 2;
- if ($@ARTIS_RAT1_CONTROL[5] > 45) doevent "RattosControl#001-2-23::OnRatto1Respawn";
- if ($@ARTIS_RAT1_CONTROL[6] > 45) doevent "RattosControl#001-2-23::OnRatto2Respawn";
- if ($@ARTIS_RAT1_CONTROL[7] > 45) doevent "RattosControl#001-2-23::OnRatto3Respawn";
- if ($@ARTIS_RAT1_CONTROL[8] > 45) doevent "RattosControl#001-2-23::OnRatto4Respawn";
-
-L_NotYet:
- setnpctimer 0;
-
- end;
-
-OnDontneedHelp:
mesn;
- mesq l("I don't need your help right now, come back later.");
+ .@q = getq(ShipQuests_Peter);
+ if (!(.@q & 2)) {
+ mes l("- I currently need your help with @@.", getmonsterlink(Tortuga));
+ mes l("I'll give you @@ GP for this job.", 500);
+ mes "";
+ }
+ if (!(.@q & 4)) {
+ mes l("- I currently need your help with @@.", getmonsterlink(Ratto));
+ mes l("I'll give you @@ GP for this job.", 1000);
+ mes "";
+ }
+ if (!(.@q & 8)) {
+ mes l("- I currently need your help with @@.", getmonsterlink(Croc));
+ mes l("I'll give you @@ GP for this job.", 1500);
+ mes "";
+ }
+ // If you already took all three bounties, you can only repeat the quest daily
+ if (.@q == 15 && PETER_TIME <= gettimetick(2)) {
+ mes l("- I currently need your help with @@.", getmonsterlink(Ratto));
+ mes l("I'll give you @@ GP for this job.", 750);
+ } else if (.@q == 15) {
+ mes l("I don't need your help right now, but maybe tomorrow, who knows?");
+ close;
+ }
next;
- mesq l("@@ is helping me.", $@ARTIS_RAT1_HELPER$);
- goto L_Quit;
+ select
+ l("I'm not feeling like it today... Sorry."),
+ rif(!(.@q & 2), l("I will take the @@ Bounty.", "Tortuga")),
+ rif(!(.@q & 4), l("I will take the @@ Bounty.", "Ratto")),
+ rif(!(.@q & 8), l("I will take the @@ Bounty.", "Croc")),
+ rif(.@q == 15, l("Why not, I need to train anyway."));
-L_Timeout:
- mesn;
- mesq l("Hey! Be careful. You can't stay in this basement for so long, you're going to get sick. Come outside and take a break, maybe you can try again later.");
- warp "001-2-22", 72, 36;
+ if (@menu == 1)
+ close;
- goto L_CleaningClose;
+ @peter=@menu;
-L_Logoff:
- goto L_CleaningEnd;
+ goto L_Start;
-L_Dead:
-// Warps the dead body outside, so it does not interfere with the getmapusers check.
- if (getmapusers("001-2-23") > 0) warp "001-2-22", 72, 36;
+// In Moubootaur Legends, there's a small tutorial about Hit'n'run here
+// I didn't add it here but that can be arranged
+L_Start:
+// Init Instance
+OnStartOutside:
+ .@ID=getcharid(0);
+ @MAP_NAME$="nard@"+str(.@ID); // Max 4 chars for map name
+ .@INSTID = instance_create("ratto@a"+(.@ID), getcharid(3), IOT_CHAR);
+ .@instanceMapName$ = instance_attachmap("001-2-23", .@INSTID, 0, @MAP_NAME$);
+
+ // Instance already exists, or something went wrong
+ if (.@instanceMapName$ == "") {
+ mesn;
+ mesq l("Actually, you just took a bounty, right?");
+ next;
+ mesn;
+ mesq l("Why don't you take a break? Breath in some fresh air. The basement is pretty damp.");
+ close;
+ }
+
+ setq2 ShipQuests_Peter, 0;
+ setq3 ShipQuests_Peter, .@INSTID;
+
+ // It'll be self-destroyed when time runs out (3 minutes)
+ instance_set_timeout(180, 180, .@INSTID);
+ instance_init(.@INSTID);
+
+ // Save in a less reliable way the challenge you took
+ if (@peter == 2) {
+ @peter=2;
+ @pt_mob=Tortuga;
+ } else if (@peter == 3) {
+ @peter=4;
+ @pt_mob=Ratto;
+ } else if (@peter == 4) {
+ @peter=8;
+ @pt_mob=Croc;
+ } else {
+ @peter=0;
+ @pt_mob=Ratto;
+ }
+
+ warp @MAP_NAME$, 48, 28;
+ // Control how much time you have left
+ addtimer(120000, "Peter#Artis::OnLowTime");
+ addtimer(140000, "Peter#Artis::OnTimeout");
+
+ // Spawn the Monsters
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl::OnRatto1Death";
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl::OnRatto2Death";
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl::OnRatto3Death";
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl::OnRatto4Death";
+
+ dispbottom l("Okay, you can start!");
+ closeclientdialog;
+ close;
- goto L_CleaningEnd;
+// TODO: This is very reckless, instance_destroy() could possibly affect others
+// If you agree with me, we can force player to wait until instance expire on its
+// own (3 minutes after start) instead of allowing immediate retry. That's safer,
+// and code will end up looking like Mundane (exploiting attach_map failures)
-L_Done:
- $@ARTIS_RAT1_CONTROL[10] = $@ARTIS_RAT1_CONTROL[10] + 2;
- if($@ARTIS_RAT1_CONTROL[10] < 5) goto L_NotYet;
- .@peter = getq(ShipQuests_Peter);
- if (.@peter == 2 || .@peter == 4) goto L_Reward;
+// (Or if you are set in disregarding this, just uncomment instance_destroy.)
+// (Don't blame me if server SIGSEGV's because that, though)
+OnTimeout:
+ if (!(getmap() ~= "001-2-23") && !(getmap() ~= "nard*"))
+ end;
warp "001-2-22", 72, 36;
-
- goto L_Thanks;
-
-L_CleaningEnd:
- stopnpctimer;
- $@ARTIS_RAT1_HELPER$ = "";
- $@ARTIS_RAT1_DEATHS = 0;
- cleararray $@ARTIS_RAT1_CONTROL, 0, 11;
- killmonster "001-2-23", "RattosControl#001-2-23::OnRatto1Death";
- killmonster "001-2-23", "RattosControl#001-2-23::OnRatto2Death";
- killmonster "001-2-23", "RattosControl#001-2-23::OnRatto3Death";
- killmonster "001-2-23", "RattosControl#001-2-23::OnRatto4Death";
-
- end;
-
-L_CleaningClose:
- stopnpctimer;
- $@ARTIS_RAT1_OLD_HELPER$ = $@ARTIS_RAT1_HELPER$;
- $@ARTIS_RAT1_HELPER$ = "";
- $@ARTIS_RAT1_DEATHS = 0;
- cleararray $@ARTIS_RAT1_CONTROL, 0, 11;
- killmonster "001-2-23", "RattosControl#001-2-23::OnRatto1Death";
- killmonster "001-2-23", "RattosControl#001-2-23::OnRatto2Death";
- killmonster "001-2-23", "RattosControl#001-2-23::OnRatto3Death";
- killmonster "001-2-23", "RattosControl#001-2-23::OnRatto4Death";
- $@ARTIS_RAT1_COUNTDOWN = gettimetick(2);
-
+ .@q3 = getq3(ShipQuests_Peter);
+ //instance_destroy(.@q3);
+ setq2 ShipQuests_Peter, 0;
+ setq3 ShipQuests_Peter, -1;
+ mesn;
+ mesq l("Hey! Be careful. You can't stay in this basement for so long, you're going to get sick. Come outside and take a break, maybe you can try again later.");
close;
-L_Reward:
- warp "001-2-22", 72, 36;
- setq ShipQuests_Peter, 5;
- .@peter = getq(ShipQuests_Peter);
+// This is called by npc/001-2-23/ratto.txt and completes the quest
+// Just like OnReturnFail and OnTimeout, this recklessy destroys the instance
+// It's not _buggy_, it is just reckless. I would like a setting to restrict it
+// to destroy only instances owned by the char, or to destroy by name :p
+OnDone:
+ .@q3 = getq3(ShipQuests_Peter);
+ //instance_destroy(.@q3);
+ if (@peter)
+ setq ShipQuests_Peter, getq(ShipQuests_Peter)|@peter, 0, -1;
+
+ .@q = getq(ShipQuests_Peter);
mesn;
mesq l("Good job!") + " " + l("Here's your reward!");
- getexp 100, 0;
- Zeny = Zeny + 1000;
- message strcharinfo(0), l("You receive @@ E!", 1000);
- goto L_CleaningClose;
-
-L_Thanks:
- mesn;
- mesq l("Thanks for helping me!");
- .@peter = getq(ShipQuests_Peter);
- if (.@peter == 1) setq ShipQuests_Peter, 3;
- .@peter = getq(ShipQuests_Peter);
-
- goto L_CleaningClose;
-
-L_Quit:
- .@peter = 0;
+ // Before handling the rewards, we should be sure we'll handle daily loop.
+ // You're already in daily phase if @peter is zero.
+ // PS. This is not exactly "daily", this is actually a forced 24-hours wait.
+ if (!@peter) {
+ PETER_TIME=gettimetick(2)+24*60*60;
+ @peter=1; // This allows you to get 32 EXP from daily repeat. Tweak as needed.
+ }
+
+ // You get some EXP based on difficulty taken
+ getexp @peter*32, @peter;
+
+ // We don't need @peter anymore, so reuse it to give you GP rewards
+ switch (@peter) {
+ case 2: @peter=500; break;
+ case 4: @peter=1000; break;
+ case 8: @peter=1500; break;
+ default: @peter=750; break;
+ }
+
+ Zeny = Zeny + @peter;
+ message strcharinfo(0), l("You receive @@ E!", @peter);
+
+ // Some cleanup. Shouldn't cause bugs but it's absence causes a ugly behavior.
+ deltimer("Peter#Artis::OnLowTime");
+ deltimer("Peter#Artis::OnTimeout");
+ @peter=0;
close;
-OnNoGoodTick:
- mesn;
- mesq l("I don't need your help right now, come back later.");
- close;
OnInit:
.sex = G_MALE;
diff --git a/npc/001-2-23/doors.txt b/npc/001-2-23/doors.txt
index cba40446..9c91e824 100644
--- a/npc/001-2-23/doors.txt
+++ b/npc/001-2-23/doors.txt
@@ -2,40 +2,46 @@
// Authors:
// Ablu
// Alastrim
+// Jesusalva
// Reid
// Description:
// Doors NPCs.
-001-2-23,48,29,0 script DoorUpwards#001-2-23 NPC_HIDDEN,0,0,{
+001-2-23,48,29,0 script DoorUpwards#Artis NPC_HIDDEN,0,0,{
OnTouch:
+ // Actually this will never work because Instanced map
if (mobcount("001-2-23","all") > 0) goto L_Warn;
goto L_Warp;
L_Warn:
.@q = getq(ShipQuests_Peter);
- if (.@q == 5) goto L_Warp;
+ if (.@q >= 15) goto L_Warp;
mesn "Narrator";
- mesc(l("There are still some rattos left! Do you want to abort the quest?"), 9);
+ mesc(l("There are still some monsters left! Do you want to abort the quest?"), 9);
next;
menu
l("Yes."), L_Warp,
l("No."), -;
- warp "001-2-23", 48, 28;
+ slide 48, 28;
closeclientdialog;
close;
L_Warp:
warp "001-2-22", 72, 36;
+
+ deltimer("Peter#Artis::OnLowTime");
+ deltimer("Peter#Artis::OnTimeout");
closeclientdialog;
close;
}
-001-2-23,24,31,0 script LeftDoor#001-2-23 NPC_HIDDEN,0,0,{
+// Besides the door, Alige is hiding himself and would rather not be disturbed
+001-2-23,24,31,0 script LeftDoor#Artis NPC_HIDDEN,0,0,{
OnTouch:
mesn "Narrator";
@@ -45,7 +51,7 @@ OnTouch:
next;
menu
- rif(countitem(718) > 0, l("Use the key.")), L_Warp,
+ rif(countitem(JohanneKey) > 0, l("Use the key.")), L_Warp,
l("Break the door."), L_Break,
l("Go away."), -;
diff --git a/npc/001-2-23/ratto.txt b/npc/001-2-23/ratto.txt
index 91a822d3..9b4130f6 100644
--- a/npc/001-2-23/ratto.txt
+++ b/npc/001-2-23/ratto.txt
@@ -1,68 +1,97 @@
-// Evol scripts.
-// Authors:
-// Ablu
-// Alastrim
-// Reid
+// Evol Script.
+// Author:
+// Ablu
+// Alastrim
+// Jesusalva
+// Reid
// Description:
// Ratto killer.
+// The only "lose" conditions are:
+// 1- dying, but this is not handled anywhere
+// 2- Time running out, Peter handles that automatically.
+// Note that if you die here, you won't be able to return and will need to
+// start the quest over again. (I wonder why it is not handled by an OnDeath event)
+// iirc, logout will automatically destroy the instance and clear timers, so it
+// doesn't needs the script writer to handle logout cleanup (only death).
-// $@ARTIS_RAT1_CONTROL array explanation:
-// [1] = Shows status of ratto number 1 (1 is dead and 0 is alive).
-// [2] = Shows status of ratto number 2 (1 is dead and 0 is alive).
-// [3] = Shows status of ratto number 3 (1 is dead and 0 is alive).
-// [4] = Shows status of ratto number 4 (1 is dead and 0 is alive).
-// [5] = Shows how many seconds passed since ratto number 1 died.
-// [6] = Shows how many seconds passed since ratto number 2 died.
-// [7] = Shows how many seconds passed since ratto number 3 died.
-// [8] = Shows how many seconds passed since ratto number 4 died.
-// [9] = Shows how many seconds passed since the player started the quest.
-
-001-2-23,47,30,0 script RattosControl#001-2-23 NPC_HIDDEN,{
-
-OnSpawn:
- areamonster "001-2-23", 23, 19, 50, 40, "Ratto", 1005, 1, "RattosControl#001-2-23::OnRatto1Death";
- areamonster "001-2-23", 23, 19, 50, 40, "Ratto", 1005, 1, "RattosControl#001-2-23::OnRatto2Death";
- areamonster "001-2-23", 23, 19, 50, 40, "Ratto", 1005, 1, "RattosControl#001-2-23::OnRatto3Death";
- areamonster "001-2-23", 23, 19, 50, 40, "Ratto", 1005, 1, "RattosControl#001-2-23::OnRatto4Death";
- close;
+001-2-23,0,0,0 script RattosControl#Artis NPC_HIDDEN,{
+ end;
+// Each monster on the basement have its own respawn cycle.
+// We use a XOR (^) operand to mark that the killed monster is not dead anymore.
+// This is to reproduce as accurate as possible the legacy behavior of the quest.
OnRatto1Respawn:
- areamonster "001-2-23", 23, 19, 50, 40, "Ratto", 1005, 1, "RattosControl#001-2-23::OnRatto1Death";
- $@ARTIS_RAT1_CONTROL[1] = 0;
- $@ARTIS_RAT1_CONTROL[5] = 0;
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2^1;
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl#Artis::OnRatto1Death";
end;
OnRatto2Respawn:
- areamonster "001-2-23", 23, 19, 50, 40, "Ratto", 1005, 1, "RattosControl#001-2-23::OnRatto2Death";
- $@ARTIS_RAT1_CONTROL[2] = 0;
- $@ARTIS_RAT1_CONTROL[6] = 0;
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2^2;
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl#Artis::OnRatto2Death";
end;
OnRatto3Respawn:
- areamonster "001-2-23", 23, 19, 50, 40, "Ratto", 1005, 1, "RattosControl#001-2-23::OnRatto3Death";
- $@ARTIS_RAT1_CONTROL[3] = 0;
- $@ARTIS_RAT1_CONTROL[7] = 0;
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2^4;
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl#Artis::OnRatto3Death";
end;
OnRatto4Respawn:
- areamonster "001-2-23", 23, 19, 50, 40, "Ratto", 1005, 1, "RattosControl#001-2-23::OnRatto4Death";
- $@ARTIS_RAT1_CONTROL[4] = 0;
- $@ARTIS_RAT1_CONTROL[8] = 0;
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2^8;
+ areamonster @MAP_NAME$, 23, 19, 57, 40, strmobinfo(1, @pt_mob), @pt_mob, 1, "RattosControl#Artis::OnRatto4Death";
end;
+// When you kill a monster on basement, we must check the mob as dead, see if you
+// finally killed the last one and quest is complete, and add a timer to respawn it
+// after 1m25s (for flavor purposes, makes quest harder though)
OnRatto1Death:
- $@ARTIS_RAT1_CONTROL[1] = 1;
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2|1;
+ .@q2=getq2(ShipQuests_Peter);
+ if (.@q2 == 15)
+ goto L_Victor;
+ addtimer(85000, "RattosControl#Artis::OnRatto1Respawn");
end;
OnRatto2Death:
- $@ARTIS_RAT1_CONTROL[2] = 1;
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2|2;
+ .@q2=getq2(ShipQuests_Peter);
+ if (.@q2 == 15)
+ goto L_Victor;
+ addtimer(85000, "RattosControl#Artis::OnRatto2Respawn");
end;
OnRatto3Death:
- $@ARTIS_RAT1_CONTROL[3] = 1;
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2|4;
+ .@q2=getq2(ShipQuests_Peter);
+ if (.@q2 == 15)
+ goto L_Victor;
+ addtimer(85000, "RattosControl#Artis::OnRatto3Respawn");
end;
OnRatto4Death:
- $@ARTIS_RAT1_CONTROL[4] = 1;
+ .@q2=getq2(ShipQuests_Peter);
+ setq2 ShipQuests_Peter, .@q2|8;
+ .@q2=getq2(ShipQuests_Peter);
+ if (.@q2 == 15)
+ goto L_Victor;
+ addtimer(85000, "RattosControl#Artis::OnRatto4Respawn");
+ end;
+
+// This label is reached when all rattos are dead. We clear the respawn timers
+// (as we are going to delete the instance map anyway), warp you outside, and
+// from there onwards, Peter handles properly rewarding you.
+L_Victor:
+ warp "001-2-22", 72, 36;
+ deltimer("RattosControl#Artis::OnRatto1Respawn");
+ deltimer("RattosControl#Artis::OnRatto2Respawn");
+ deltimer("RattosControl#Artis::OnRatto3Respawn");
+ deltimer("RattosControl#Artis::OnRatto4Respawn");
+ doevent("Peter#Artis::OnDone");
end;
}
diff --git a/npc/001-3-0/_import.txt b/npc/001-3-0/_import.txt
index 5ead6439..a4262ee3 100644
--- a/npc/001-3-0/_import.txt
+++ b/npc/001-3-0/_import.txt
@@ -1,5 +1,6 @@
// Map 001-3-0: Sewer
// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-3-0/mundane.txt",
"npc/001-3-0/_mobs.txt",
"npc/001-3-0/_warps.txt",
"npc/001-3-0/mundane.txt",
diff --git a/npc/001-3-0/_mobs.txt b/npc/001-3-0/_mobs.txt
index 88caa962..fff529b1 100644
--- a/npc/001-3-0/_mobs.txt
+++ b/npc/001-3-0/_mobs.txt
@@ -6,7 +6,7 @@
001-3-0,101,111,8,3 monster Ratto 1005,4,30000,15000
001-3-0,145,68,2,2 monster Ratto 1005,2,60000,30000
001-3-0,146,28,2,1 monster Ratto 1005,2,60000,30000
-001-3-0,90,65,3,3 monster Ratto 1005,3,35000,15000
+001-3-0,89,66,2,4 monster Ratto 1005,3,35000,15000
001-3-0,56,50,8,4 monster Ratto 1005,4,35000,15000
001-3-0,42,102,3,3 monster Ratto 1005,3,40000,20000
001-3-0,157,80,2,2 monster Green Slime 1024,3,15000,80000
@@ -15,7 +15,7 @@
001-3-0,175,50,0,4 monster Ratto 1005,2,60000,30000
001-3-0,175,64,3,2 monster Cave Maggot 1027,4,5000,15000
001-3-0,104,75,48,43 monster Cave Maggot 1027,25,500,2000
-001-3-0,90,67,2,5 monster Cave Maggot 1027,3,500,2000
+001-3-0,90,68,1,6 monster Cave Maggot 1027,3,500,2000
001-3-0,128,86,3,5 monster Green Slime 1024,3,500,2000
001-3-0,42,103,3,5 monster Green Slime 1024,3,500,2000
001-3-0,120,85,7,2 monster Little Green Slime 1025,2,500,2000
diff --git a/npc/001-3-0/mundane.txt b/npc/001-3-0/mundane.txt
index ff4d51b9..b653fa0d 100644
--- a/npc/001-3-0/mundane.txt
+++ b/npc/001-3-0/mundane.txt
@@ -1,13 +1,23 @@
-
// Evol Scripts
// Author:
// Jesusalva
// Description:
// Mundane (anagram of Unnamed) is Mona's father
-
-// Note: Due technical limitations do not make Mundane move
-// Note: Temporary sprite
-001-3-0,161,59,0 script Mundane NPC_MUNDANE,{
+// He likes to smoke cigarettes while looking for the strange sounds.
+// He is an old bowman of the Legion. He was married but it is not clear
+// what happened to his wife.
+// Lore Problems:
+// If he is missing for a week already, how is he eating anyway?
+// Also, is he afraid of blubs/rattos or of Green Slimes?
+
+// Note: Jesusalva is not someone to care a lot with code styling, and he uses
+// a convention of his own, gumi will need to cleanse the code before it gets
+// compliant with Evol Coding Style Guidelines.
+// Note 2: Logout is not handled. Making logout at an instanced map may randomly
+// warp you back to Drasil Island (000-1) or something like that. I don't know.
+// This behavior remains to be checked.
+
+001-3-0,96,66,0 script Mundane NPC_MUNDANE,{
function quest_completed
{
@@ -17,14 +27,21 @@
close;
}
+ function quest_inprogress
+ {
+ speech(0x0,
+ l("We need to get out of here soon. I'm scared of the Slimes!"));
+ close;
+ }
+
function rescue_mundane
{
speech(S_LAST_NEXT,
- l("Scary... I am afraid of these blubs and rattos... And worse, I am lost..."),
- l("I already killed many strong monsters, but I everyone have fears, right?!"),
- l("My daughter is probably worried with me. Could you perhaps lead me out of here?"));
+ l("Scary... I am afraid of these Slimes, Rattos and Maggots... And worse, I am lost..."),
+ l("I already killed many strong monsters, but everyone has fears, right?!"),
+ l("My daughter is probably worried about me. Could you perhaps lead me out of here?"));
- switch (select(l("Yes, follow me!"), l("Not now. You see, I am also afraid of Blubs and Rattos!")))
+ switch (select(l("Yes, follow me!"), l("Not now. You see, I am also afraid of Slimes and Rattos!")))
{
case 1:
mes "";
@@ -38,11 +55,11 @@
}
.@ID=getcharid(0);
.@MAP_NAME$="mona@"+str(.@ID);
- .@MUNDANE_INSTID = instance_create("001-3-0@a"+(.@ID), getcharid(3), IOT_CHAR);
+ @MUNDANE_INSTID = instance_create("001-3-0@a"+(.@ID), getcharid(3), IOT_CHAR);
//debugmes "You are "+str(.@ID);
- //if (.@MUNDANE_INSTID < 0) debugmes "Error: No instance ID";
- //debugmes "new instance id: " + str(.@MUNDANE_INSTID);
+ //if (@MUNDANE_INSTID < 0) debugmes "Error: No instance ID";
+ //debugmes "new instance id: " + str(@MUNDANE_INSTID);
// XXX - Important Note - XXX
// We currently have only FOUR chars to name the map. "001-3-0" or "mundane" have 7 chars, so that cannot be used.
@@ -50,27 +67,49 @@
//
// Rationale: We have only 11 chars available, but 7 are reserved. So, longest name would be "abcd" + "@" + getcharid(0)
// Some test reported that (apparently) we have 15 whitespaces at map name start, not sure why.
- .@instanceMapName$ = instance_attachmap("001-3-0", .@MUNDANE_INSTID, 0, .@MAP_NAME$);
-
- //if (.@instanceMapName$ == "") debugmes "Error: Map 001-3-0 X failed";
- //debugmes "Created map: "+ str(.@instanceMapName$);
+ .@instanceMapName$ = instance_attachmap("001-3-0", @MUNDANE_INSTID, 0, .@MAP_NAME$);
+
+ // This can be a bug, but most likely is because instance already exists.
+ // I don't know what would happen if we continue, so let's "penalize" the player
+ if (.@instanceMapName$ == "") {
+ speech(0x0,
+ l("Wait... You are that @@ from earlier, aren't you?", strcharinfo(0)),
+ l("If my memory serves me right, you died just before. Why don't you go out to buy better equipment?"));
+ close;
+ }
// You have 5 minutes to complete the quest. This does not results in failure by itself, getq2 does that
- instance_set_timeout(300, 300, .@MUNDANE_INSTID);
- instance_init(.@MUNDANE_INSTID);
+ instance_set_timeout(300, 300, @MUNDANE_INSTID);
+ instance_init(@MUNDANE_INSTID);
dispbottom(l("Mona Father's is right behind you. You have five minutes to bring him out of sewers!"));
// Not sure if Green Slimes are exactly what we want here - and shouldn't it be "Slime"? (mind upper-case)
areamonster(.@MAP_NAME$, 119, 51, 162, 85, l("Green Slime"), slime, 3);
+ areamonster(.@MAP_NAME$, 190, 65, 193, 68, l("Ratto"), Ratto, 5);
+ areamonster(.@MAP_NAME$, 90, 67, 92, 72, l("Cave Maggot"), CaveMaggot, 3);
+ areamonster(.@MAP_NAME$, 99, 106, 102, 111, l("Green Slime"), slime, 3);
+ areamonster(.@MAP_NAME$, 115, 93, 115, 75, l("Green Slime"), slime, 3);
+ areamonster(.@MAP_NAME$, 120, 85, 7, 2, l("Little Green Slime"), slime-littleslime, 7);
+ areamonster(.@MAP_NAME$, 114, 65, 121, 68, l("Cave Maggot"), CaveMaggot, 5);
+ areamonster(.@MAP_NAME$, 137, 76, 130, 87, l("Spider"), Spider, 4);
+ areamonster(.@MAP_NAME$, 98, 92, 101, 94, l("Green Slime"), slime, 3);
setq ArtisQuests_MonaDad, 2;
- warp(.@MAP_NAME$, 161,59);
+ warp(.@MAP_NAME$, 96,66);
+ addtimer(150, "Mundane::OnMove");
+
+ // Important temporary variables
+ @MUNDANE_OLDX=96;
+ @MUNDANE_OLDY=66;
close;
}
.@q=getq(ArtisQuests_MonaDad);
- if (.@q != 1) quest_completed();
+ if (.@q >= 3) quest_completed();
+ if (.@q == 2) quest_inprogress();
if (.@q == 1) rescue_mundane();
+ // Impossible situation, but let's not trust this. You must talk to Mona first!
+ if (.@q == 0) quest_completed();
hello;
end;
@@ -80,16 +119,75 @@ OnInit:
.distance = 3;
end;
+/*
+// If we are to use a fake-NPC (a monster which actually is a NPC, for example),
+// We need to uncomment this code block. As we are moving the actual NPC, this is
+// not needed (and harmful, too)
OnInstanceInit:
disablenpc(instance_npcname(.name$));
end;
+*/
+
+// This functions serves two major purposes:
+// 1- Move Mundane accordingly
+// 2- Be able to determine if you brought Mundane to exit or cheat (warp, etc.)
+// NOTE: Using instance_npcname(.name$) can be unreliable at times.
+// It should work with addtimer(), but if it breaks, move @MUNDANE_INSTID to
+// the @ varspace, and use instance_npcname(.name$, @MUNDANE_INSTID)
+// That'll fix any problem when playtesting.
+OnMove:
+ getmapxy(.@m$, .@x, .@y, 0);
+ // You left the map, we don't need to move NPC anymore
+ if (!(.@m$ ~= "mona@*") && (.@m$ != "001-3-0")) {
+ disablenpc(instance_npcname(.name$, @MUNDANE_INSTID));
+ // This check shouldn't be needed but better safe than sorry
+ if (.@m$ == "001-1")
+ dispbottom l("Mundane ran straight home. He must be missing his daughter.");
+ end;
+ }
+ // We actually won't move the NPC to your position, but to where you were last.
+ // The NPC should not walk right in you because I thought it looks weird ingame.
+ if (.@x == @MUNDANE_OLDX && .@y == @MUNDANE_OLDY) {
+ addtimer(150, "Mundane::OnMove");
+ end;
+ }
+
+ // movenpc() will cause NPC to "jump" to player position.
+ // npcwalkto(x, y) could be better, but there are concerns about instance NPC,
+ // and the server code behind this function would need to be changed to actually
+ // use NPC walking animation (instead of just sliding it around).
+ //
+ // Mind the note about instance_npcname and about ignoring your position
+ // We should in future at least figure out the right direction to display too
+ movenpc(instance_npcname(.name$, @MUNDANE_INSTID), @MUNDANE_OLDX, @MUNDANE_OLDY);
+
+ // We now update the misleading @MUNDANE_OLD* variable with your current
+ // position.
+ @MUNDANE_OLDX=.@x;
+ @MUNDANE_OLDY=.@y;
+ // We must handle this every 150ms or so, which is player walk delay.
+ // When you leave the map this timer will die.
+ addtimer(150, "Mundane::OnMove");
+ end;
OnPCDieEvent:
if (getq(ArtisQuests_MonaDad) != 2) end;
setq ArtisQuests_MonaDad, 1;
dispbottom l("What a pity! You've died.");
- //warp("Save",0,0); // That works, but won't revive you without recovery();
+
+ // We must disable Mona's Dad NPC sprite if you are still on the map
+ // This will cause the NPC to "vanish", player is left to guess that he ran
+ // back to where he originally was.
+ // (ie. The NPC won't be fine without you if we have code to handle that).
+ getmapxy(.@m$, .@x, .@y, 0);
+ if (.@m$ ~= "mona@*") {
+ disablenpc(instance_npcname(.name$, @MUNDANE_INSTID));
+ }
+
+ // Uncommenting the code piece will warp you back to your savepoint.
+ // It's better to don't use this if the previous code works.
+ //recovery();
+ //warp("Save",0,0);
end;
}
-// >>>>>>> Initial proof-of-concept version, works, but quest cannot be completed yet
diff --git a/npc/008-2-16/_import.txt b/npc/008-2-16/_import.txt
index 90da3caf..5f5ea192 100644
--- a/npc/008-2-16/_import.txt
+++ b/npc/008-2-16/_import.txt
@@ -1,3 +1,5 @@
// Map 008-2-16: Hurnscald Cottage
// This file is generated automatically. All manually added changes will be removed when running the Converter.
"npc/008-2-16/_warps.txt",
+"npc/008-2-16/stove.txt",
+"npc/008-2-16/yannika.txt",
diff --git a/npc/008-2-16/stove.txt b/npc/008-2-16/stove.txt
new file mode 100644
index 00000000..91036c44
--- /dev/null
+++ b/npc/008-2-16/stove.txt
@@ -0,0 +1,88 @@
+// Evol scripts.
+// Author:
+// Jesusalva
+// Description:
+// Stove to make sandwiches
+
+008-2-16,32,29,0 script Stove NPC_NO_SPRITE,{
+ // If player haven't finished Hinnak quest yet, they can't use the stove
+ .@q=getq(HurnscaldQuests_Hinnak);
+ if (.@q < 3)
+ {
+ setcamnpc "Yannika";
+ mesn l("Yannika");
+ mesq l("Please don't touch my stove without my authorization.");
+ close;
+ }
+
+ // Cooking loop
+ do
+ {
+ mesc lg("It is time to make some sandwiches myself!");
+ mes "##B" + l("Drag and drop the items from your inventory in the frames.") + "##b";
+
+ // Crafting skin with 4 columns
+ setskin "craft4";
+ .@var$ = requestcraft(4); // Limit: 4 items
+ .@craft = initcraft(.@var$);
+ .@entry = findcraftentry(.@craft, CRAFT_SANDWICH);
+ setskin "";
+
+ // Does the recipe exist and is a sandwich?
+ if (.@entry < 0)
+ {
+ narrator
+ l("You don't know how to make a sandwich with that."),
+ l("Do you want to try again?");
+ if (askyesno() == ASK_YES)
+ .@tryAgain=true;
+ else
+ .@tryAgain=false;
+ }
+ else
+ {
+ // Did player cheat? If not, proceed with the craft
+ if (!validatecraft(.@craft))
+ {
+ narrator
+ l("Where are the ingredients?");
+ .@tryAgain=true;
+ }
+ else
+ {
+ // Even if the recipe is right, if you don't have it on your
+ // recipe book, it should be deemed invalid.
+ if (COOKING_RECIPES[.@entry])
+ {
+ usecraft .@craft;
+ narrator
+ l("Done!"),
+ l("Do you want to try again?");
+ }
+ else
+ {
+ narrator
+ l("You don't know how to make a sandwich with that."),
+ l("Do you want to try again?");
+ }
+
+ if (askyesno() == ASK_YES)
+ .@tryAgain=true;
+ else
+ .@tryAgain=false;
+ }
+ }
+
+ // Clear unused variables and clear the screen.
+ deletecraft .@craft;
+ clear;
+ } while (.@tryAgain);
+
+ closeclientdialog;
+ close;
+
+OnInit:
+ .sex = G_OTHER;
+ .distance = 2;
+ end;
+}
diff --git a/npc/008-2-16/yannika.txt b/npc/008-2-16/yannika.txt
index 0e311eee..7223b70c 100644
--- a/npc/008-2-16/yannika.txt
+++ b/npc/008-2-16/yannika.txt
@@ -1,20 +1,310 @@
// Evol scripts.
// Author:
// Micksha
+// Jesusalva
// Description:
// Yannika, Hinnaks Wife.
-// THIS IS A PLACEHOLDER!
+// Makes delicious sandwiches for the player
+// Variables:
+// General_Cooking
+// 0: Doesn't knows the quest
+// 1: Received the quest for the Cookbook
+// 2: Completed the quest for the Cookbook
+// COOKING_RECIPES
+// Controls which recipes you know and doesn't.
+// It is an array with Craft Constants.
008-2-16,28,29,0 script Yannika NPC_YANNIKA,{
- speech
- l("Hi Sir."),
- l("Sandwiches? Lets wait for Jesusalva to add something here."),
- lg("Come back later.");
+ // Quest state 0
+ function yannika_intro
+ {
+ speech
+ lg(l("Hello madam."), l("Hi Sir.")),
+ l("Thanks for helping my husband Hinnak."),
+ l("Could you please bring me 2 new knives?"),
+ l("Hinnak wasted all my good kitchen knives trying to get rid of his accursed Pinkies.");
+
+ select
+ l("Yes, sure thing."),
+ lg("Not my problem.");
+
+ if (@menu == 1)
+ {
+ speech
+ l("I'll be waiting for you, then!");
+ setq .quest, 1;
+ next;
+ }
+ }
+
+ // Quest state 1
+ function yannika_knives
+ {
+ speech
+ lg(l("Hello madam."), l("Hi Sir.")),
+ l("Thanks for helping my husband Hinnak."),
+ l("Did you brought me 2 new knives?");
+
+ select
+ rif(countitem(Knife) >= 2, l("Yes, here they are.")),
+ lg("Not yet, I'll be back.");
+
+ if (@menu == 1)
+ {
+ // No need to countitem() because it is already at the menu
+ // Technically, a hacked client could bypass earlier check though
+ // Jesusalva doesn't likes hacks, so he puts delitem first.
+ // delitem halts the script if it cannot delete all items.
+ inventoryplace RecipeBook, 1;
+ delitem Knife, 2;
+ getitem RecipeBook, 1;
+ setq .quest, 2;
+
+ speech
+ l("Many thanks. I can now do sandwiches again!"),
+ l("Well, of course. First of all, you need a @@. You can have mine, if you want.", getitemlink(RecipeBook)),
+ l("The recipes, of course, you must collect yourself. Even sandwiches are not so simple as to simply put ingredients and hope for the best."),
+ l("Cooking is an art. You need to know how to cook something. You can use my stove to prepare."),
+ lg("Or, you can just forget all that, and let me prepare sandwiches for you, too! %%H"), // %%H - Smile Emote
+ l("Oh, but I'll still need the book. Even if all pages are white.");
+ next;
+ }
+ }
+
+ // Learn a new Sandwich Recipe
+ // yannika_recipe ( Craft ID, Ammo 1, Item 1, Ammo 2, Item 2, Sandwich ID )
+ function yannika_recipe
+ {
+ .@craft=getarg(0);
+ .@ammo1=getarg(1);
+ .@item1=getarg(2);
+ .@ammo2=getarg(3);
+ .@item2=getarg(4);
+ .@sanid=getarg(5);
+ speech
+ l("I do know a recipe with this!"),
+ l("You'll need to bring me @@ @@ and @@ @@ for the recipe.", .@ammo1, getitemlink(.@item1), .@ammo2, getitemlink(.@item2));
+
+ select
+ l("Yes, in fact, you can take them now."),
+ l("Maybe later.");
+
+ if (@menu == 1)
+ {
+ if (countitem(.@item1) < .@ammo1 ||
+ countitem(.@item2) < .@ammo2)
+ {
+ speech
+ l("You don't have everything I have asked for.");
+ close;
+ }
+ delitem .@item1, .@ammo1;
+ delitem .@item2, .@ammo2;
+ COOKING_RECIPES[.@craft]=true;
+ speech
+ l("This is how you do it! HAAH!");
+ next;
+ mesc l("You learned how to cook @@.", getitemlink(.@sanid));
+ next;
+ }
+ return;
+ }
+
+ // Yannika can make sandwiches for players
+ function sudo_make_sandwich
+ {
+ speech
+ l("When cooking, the order of ingredients matter."),
+ l("Even a simple sandwich will be ruined if you place lettuce above the cheese!"),
+ l("Anyway, to make a sandwich, you'll need to place, in this order:"),
+ l("1x @@, 3x @@, 2x @@, and the ingredient of your choice.", getitemlink(Bread), getitemlink(LettuceLeaf), getitemlink(Cheese));
+
+ do
+ {
+ mes "##B" + l("Drag and drop the items from your inventory in the frames.") + "##b";
+
+ // Crafting skin with 4 columns
+ setskin "craft4";
+ .@var$ = requestcraft(4); // Limit: 4 items
+ .@craft = initcraft(.@var$);
+ .@entry = findcraftentry(.@craft, CRAFT_SANDWICH);
+ setskin "";
+
+ // Does the recipe exist and is a sandwich?
+ if (.@entry < 0)
+ {
+ speech
+ l("Sorry. I can't make a sandwich with that."),
+ l("Do you want to try again?");
+ if (askyesno() == ASK_YES)
+ .@tryAgain=true;
+ else
+ .@tryAgain=false;
+ }
+ else
+ {
+ // Did player cheat? If not, proceed with the craft
+ if (!validatecraft(.@craft))
+ {
+ speech
+ l("Sorry, my eyesight is a bit poor nowadays. Where are the ingredients?");
+ .@tryAgain=true;
+ }
+ else
+ {
+ usecraft .@craft;
+ speech
+ l("@@ skillfully cuts the bread in half, throws the ingredients in air, and they land in the sandwich!", .name$),
+ l("There you go. Please enjoy yourself! ^.^");
+
+ .@tryAgain=false;
+ }
+ }
+
+ // Clear unused variables and clear the screen. Then print recipe again.
+ deletecraft .@craft;
+ if (.@tryAgain) {
+ clear;
+ mesc l("1x @@, 3x @@, 2x @@, and the ingredient of your choice.", getitemlink(Bread), getitemlink(LettuceLeaf), getitemlink(Cheese));
+ }
+ } while (.@tryAgain);
+ return;
+ }
+
+ // Teach player how to cook, providing a recipe book if they don't have one
+ function teach_cooking
+ {
+ // Check if your stats aren't enough (bonuses aren't counted)
+ if (readparam(bInt) < 10 ||
+ readparam(bDex) < 20)
+ {
+ speech
+ l("Well, cooking is an art, and thus, you need intelligence and dexterity to learn."),
+ l("Please come again with at least 10 INT and 20 DEX. Stat Bonuses aren't counted.");
+ close;
+ }
+
+ speech
+ l("Well, of course, I can show you how to cook sandwiches. But you'll need to bring ingredients for practice."),
+ l("Why don't you show me a main ingredient, and I'll tell you what can be done?");
+
+ do
+ {
+ mes "##B" + l("Drag and drop an item from your inventory.") + "##b";
+ .@id = requestitem();
+
+ // If ID is invalid
+ if (.@id < 1) {
+ speech
+ l("Out of creativity already? Don't worry, I don't judge! Hehe.");
+ close;
+ }
+ // If you are cheating ManaPlus interface
+ if (countitem(.@id) < 1) {
+ mesc l("You do not have the item!");
+ close;
+ }
+
+ // Now we will switch your result and check recipe on the meanwhile
+ switch (.@id)
+ {
+ case CommonCarp:
+ case GrassCarp:
+ if (COOKING_RECIPES[CraftCarpSandwich])
+ {
+ speech
+ lg("Haha, silly you! You already know the recipe! Read the @@ if you forgot!", getitemlink(RecipeBook));
+ }
+ else
+ {
+ yannika_recipe(CraftCarpSandwich, 2, GrassCarp, 10, CommonCarp, CarpSandwich);
+ }
+ break;
+
+ case Manana:
+ if (COOKING_RECIPES[CraftMananaSandwich])
+ {
+ speech
+ lg("Haha, silly you! You already know the recipe! Read the @@ if you forgot!", getitemlink(RecipeBook));
+ }
+ else
+ {
+ yannika_recipe(CraftMananaSandwich, 3, Carrot, 30, Manana, MananaSandwich);
+ }
+ break;
+
+ case PiouLegs:
+ if (COOKING_RECIPES[CraftPioulegSandwich])
+ {
+ speech
+ lg("Haha, silly you! You already know the recipe! Read the @@ if you forgot!", getitemlink(RecipeBook));
+ }
+ else
+ {
+ yannika_recipe(CraftPioulegSandwich, 10, Croconut, 20, PiouLegs, PioulegSandwich);
+ }
+ break;
+
+ default:
+ speech
+ l("Sorry, I don't know any recipe with this."),
+ l("Maybe you have more luck with something else?");
+ next;
+ break;
+ }
+ } while (true);
+
+ return;
+ }
+
+ // If player haven't finished Hinnak quest yet, Yannika says so
+ .@q=getq(HurnscaldQuests_Hinnak);
+ if (.@q < 3)
+ {
+ speech
+ lg(l("Hello madam."), l("Hi Sir.")),
+ l("Isn't my husband Hinnak so hardworking?"),
+ lg("Come back later.");
+ close;
+ }
+
+ // Player completed Hinnak quest, we can continue in making Sandwiches
+ switch (getq(.quest))
+ {
+ case 0:
+ yannika_intro();
+ break;
+ case 1:
+ yannika_knives();
+ break;
+ case 2:
+ speech
+ lg(l("Hello madam."), l("Hi Sir.")),
+ l("Thanks for helping my husband Hinnak."),
+ l("He likes to eat sandwiches. A good thing they are so easy to make!");
+
+ select
+ l("Easy to make? Could you make one for me?"),
+ l("Easy to make? Could you teach me how to make them?"),
+ l("Good to know, thanks.");
+
+ if (@menu == 1)
+ sudo_make_sandwich();
+ else if (@menu == 2)
+ teach_cooking();
+
+ next;
+ break;
+ }
+ closeclientdialog;
+ goodbye;
close;
OnInit:
.sex = G_FEMALE;
.distance = 2;
+ .quest=General_Cooking;
+
end;
}
diff --git a/npc/commands/debug-quest.txt b/npc/commands/debug-quest.txt
index 468e5af2..1c3e0b5c 100644
--- a/npc/commands/debug-quest.txt
+++ b/npc/commands/debug-quest.txt
@@ -129,7 +129,8 @@ function script GlobalQuestDebug {
l("Cookies"), General_Cookies,
"Rumly", General_Rumly,
l("Narrator"), General_Narrator,
- "Janus", General_Janus;
+ "Janus", General_Janus,
+ l("Cooking"), General_Cooking;
switch (@menuret)
{
diff --git a/npc/functions/quest-debug/003-ShipQuests_Peter.txt b/npc/functions/quest-debug/003-ShipQuests_Peter.txt
index e08e1eb2..4732d238 100644
--- a/npc/functions/quest-debug/003-ShipQuests_Peter.txt
+++ b/npc/functions/quest-debug/003-ShipQuests_Peter.txt
@@ -1,6 +1,9 @@
// Peter quest debug
// Author:
// gumi
+// jesusalva
+// Notes:
+// Using l() usually is not a good idea (translating debug text? What?)
function script QuestDebug3 {
do
@@ -10,16 +13,19 @@ function script QuestDebug3 {
mes "ShipQuests_Peter";
mes "---";
mes l("Quest state: @@", getq(ShipQuests_Peter));
+ mes l("Killed mob bitmask: @@", getq2(ShipQuests_Peter));
+ mes l("Instance ID: @@", getq3(ShipQuests_Peter));
next;
+ .@q=getq(ShipQuests_Peter);
+
GenericQuestDebug ShipQuests_Peter,
l("Does not have the quest"), 0,
- l("Peter needs help"), 6,
- l("Peter asks to kill rattos"), 1,
- l("Killed rattos"), 2,
- l("Got no reward"), 3,
- l("Peter asks to kill rattos again"), 4,
- l("Peter gave reward"), 5;
+ l("Peter needs help"), 1,
+ l("Toggle Tortuga Bounty"), .@q^2,
+ l("Toggle Ratto Bounty"), .@q^4,
+ l("Toggle Croc Bounty"), .@q^8,
+ l("Quest complete"), 15;
if (@menuret < 0)
{
diff --git a/npc/functions/quest-debug/041-General_Cooking.txt b/npc/functions/quest-debug/041-General_Cooking.txt
new file mode 100644
index 00000000..592df547
--- /dev/null
+++ b/npc/functions/quest-debug/041-General_Cooking.txt
@@ -0,0 +1,51 @@
+// Cooking quest debug
+// Author:
+// Jesusalva
+
+function script QuestDebug41 {
+ do
+ {
+ clear;
+ setnpcdialogtitle l("Quest debug");
+ mes "General_Cooking";
+ mes "---";
+ mes l("Quest state: @@", getq(General_Cooking));
+ mes l("Known Recipes: @@", array_entries(COOKING_RECIPES));
+ next;
+
+ select
+ l("Return"),
+ l("Reset Quest"),
+ l("Complete Quest"),
+ l("Get a Recipe Book"),
+ l("Learn all recipes"),
+ l("Reset all recipes");
+
+ switch (@menu)
+ {
+ case 2:
+ setq General_Cooking, 0;
+ break;
+ case 3:
+ setq General_Cooking, 2;
+ break;
+ case 4:
+ getitem RecipeBook, 1;
+ break;
+ case 5:
+ COOKING_RECIPES[CraftCarpSandwich]=true;
+ COOKING_RECIPES[CraftMananaSandwich]=true;
+ COOKING_RECIPES[CraftPioulegSandwich]=true;
+ break;
+ case 6:
+ COOKING_RECIPES[CraftCarpSandwich]=false;
+ COOKING_RECIPES[CraftMananaSandwich]=false;
+ COOKING_RECIPES[CraftPioulegSandwich]=false;
+ break;
+
+ }
+
+ return;
+
+ } while (@menu != 1);
+}
diff --git a/npc/functions/util.txt b/npc/functions/util.txt
index 0c6080b1..2cb28573 100644
--- a/npc/functions/util.txt
+++ b/npc/functions/util.txt
@@ -1,5 +1,6 @@
// Evol functions.
// Authors:
+// Jesusalva
// Reid
// Description:
// Util functions
@@ -33,3 +34,43 @@ function script season_direction {
return (.@current_month / 3 + .@is_after_season_day) % 4;
}
+
+// This is part of Jesusalva script toolkit to make his life easier when writing
+// quests. Many of these are actually redudant functions.
+
+// Four different flavours of setq() to quickly preserve old values
+function script setq1 {
+ // Quest, val1 , val2 , val3 , time
+ setq getarg(0), getarg(1), getq2(getarg(0)), getq3(getarg(0)), getqtime(getarg(0));
+ return;
+}
+
+function script setq2 {
+ // Quest, val1 , val2 , val3 , time
+ setq getarg(0), getq(getarg(0)), getarg(1), getq3(getarg(0)), getqtime(getarg(0));
+ return;
+}
+
+function script setq3 {
+ // Quest, val1 , val2 , val3 , time
+ setq getarg(0), getq(getarg(0)), getq2(getarg(0)), getarg(1), getqtime(getarg(0));
+ return;
+}
+
+function script setqtime {
+ // Quest, val1 , val2 , val3 , time
+ setq getarg(0), getq(getarg(0)), getq2(getarg(0)), getq3(getarg(0)), getarg(1);
+ return;
+}
+
+// Function to quickly disregard part of getmapxy().
+// If you use this function too much, you'll lose efficiency, and it'll be better
+// to use getmapxy() normally to save to temporary variables.
+// Can take one optional argument (unittype argument).
+function script getmap {
+ if (getmapxy(.@mapName$, .@xpos, .@ypos, getarg(0,0)) != 0)
+ return false;
+ return .@mapName$;
+}
+
+
diff --git a/npc/items/recipes.txt b/npc/items/recipes.txt
new file mode 100644
index 00000000..3fb3309c
--- /dev/null
+++ b/npc/items/recipes.txt
@@ -0,0 +1,60 @@
+// Evol script.
+// Author:
+// Jesusalva
+// Micksha
+// Description:
+// Contains recipe books for Evol Online
+
+- script #RecipeBook NPC_HIDDEN,{
+
+ function read_book {
+
+ setnpcdialogtitle l(.book_name$);
+
+ mesc l("Eating is a necessity, but cooking is an art.");
+ mesc l("(All items must be placed exactly in this order for cooking work.)");
+ next;
+ mesc l("List of known cooking recipes:");
+ mes "";
+ mes ".:: " + l("Sandwiches") + " ::.";
+ mes "";
+ if (COOKING_RECIPES[CraftCarpSandwich]) {
+ mes l("@@", getitemlink(CarpSandwich));
+ mesc l("* @@ @@", 1, getitemlink(Bread));
+ mesc l("* @@ @@", 3, getitemlink(LettuceLeaf));
+ mesc l("* @@ @@", 2, getitemlink(Cheese));
+ mesc l("* @@ @@", 1, getitemlink(CommonCarp));
+ mes "";
+ }
+ if (COOKING_RECIPES[CraftPioulegSandwich]) {
+ mes l("@@", getitemlink(PioulegSandwich));
+ mesc l("* @@ @@", 1, getitemlink(Bread));
+ mesc l("* @@ @@", 3, getitemlink(LettuceLeaf));
+ mesc l("* @@ @@", 2, getitemlink(Cheese));
+ mesc l("* @@ @@", 1, getitemlink(PiouLegs));
+ mes "";
+ }
+ if (COOKING_RECIPES[CraftMananaSandwich]) {
+ mes l("@@", getitemlink(MananaSandwich));
+ mesc l("* @@ @@", 1, getitemlink(Bread));
+ mesc l("* @@ @@", 3, getitemlink(LettuceLeaf));
+ mesc l("* @@ @@", 2, getitemlink(Cheese));
+ mesc l("* @@ @@", 1, getitemlink(Manana));
+ mes "";
+ }
+
+ close;
+ }
+
+OnUse:
+ if (openbook())
+ read_book;
+ closeclientdialog();
+ close;
+
+OnInit:
+ .book_name$ = getitemname(RecipeBook);
+ .sex = G_OTHER;
+ .distance = 1;
+ end;
+}
diff --git a/npc/scripts.conf b/npc/scripts.conf
index 8763f633..8185ef56 100644
--- a/npc/scripts.conf
+++ b/npc/scripts.conf
@@ -93,11 +93,13 @@
"npc/functions/quest-debug/038-HurnscaldQuests_Inspector.txt",
"npc/functions/quest-debug/039-HurnscaldQuests_ForestBow.txt",
"npc/functions/quest-debug/040-HurnscaldQuests_WoodenShield.txt",
+"npc/functions/quest-debug/041-General_Cooking.txt",
// Item functions
"npc/items/croconut.txt",
"npc/items/shovel.txt",
"npc/items/rand_sc_heal.txt",
+"npc/items/recipes.txt",
// custom atcommands
"npc/commands/music.txt",