summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMicksha <ms-shaman@gmx.de>2019-03-05 23:44:58 +0000
committerMicksha <ms-shaman@gmx.de>2019-03-05 23:44:58 +0000
commit8885ac72ad393f428b25c4b0e4c1f12825eee9ad (patch)
tree0192e90b9c8396728c9e07dc3b89346644a68b95
parente773b5ede6fad4d200428b0b4a0b1f6984751429 (diff)
parent61e80d9ef9641a24f90838e8ea9cc2911a0e6c85 (diff)
downloadserverdata-8885ac72ad393f428b25c4b0e4c1f12825eee9ad.tar.gz
serverdata-8885ac72ad393f428b25c4b0e4c1f12825eee9ad.tar.bz2
serverdata-8885ac72ad393f428b25c4b0e4c1f12825eee9ad.tar.xz
serverdata-8885ac72ad393f428b25c4b0e4c1f12825eee9ad.zip
Merge branch 'jesusalva/Peter' into 'master'
Jesusalva/peter See merge request evol/serverdata!151
-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-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/functions/quest-debug/003-ShipQuests_Peter.txt18
-rw-r--r--npc/functions/util.txt41
8 files changed, 623 insertions, 576 deletions
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-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/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/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$;
+}
+
+