// Evol scripts.
// Authors:
// 4144
// Ablu
// Alastrim
// Jesusalva
// Qwerty Dragon
// Reid
// Vasily_Makarov
// Description:
// Rat hunter.
// 4+2 bits array:
// ShipQuests
// Variable:
// ShipQuests_Peter
// Values is a bitmask:
// 0 Doesn't know 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:
// .@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.
000-2-1,72,34,0 script AreaNPC NPC_HIDDEN,0,1,{
end;
OnTouch:
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 (!.@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:
L_Task:
if (!.@q)
setq ShipQuests_Peter, 1, 0, -1;
mesn;
mesq l("Hey there!");
next;
mesq l("I need somebody who can rid the hold of the ship of these rattos. Can you help me?");
next;
menu
l("Yeah, but what reward will I get?"), L_BonusTask,
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.");
close;
// Friendly reminder that you have about 20 secs to finish
OnLowTime:
if ((getmap() ~= "000-2-1") || (getmap() ~= "nard*"))
dispbottom l("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 l("I need someone to help me clean the edge of the ship, but you aren't strong enough for now.");
close;
/*
OnStop:
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_BonusTask,
l("No, they are way too dangerous for me!"), -;
mes "";
mesn;
mesq l("Hehe, hehe. Well, come back if you change your mind.");
close;
L_BonusTask:
mes "";
mesn;
mesq l("There are three kind of monsters which frequently or seldomly attacks our fair vessel.");
next;
mesn;
.@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;
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."));
if (@menu == 1)
close;
@peter=@menu;
goto L_Start;
// 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;
// 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)
// (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;
.@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;
// 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:
warp "000-2-1", 72, 36;
.@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!");
// 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 += @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;
OnInit:
.distance = 3;
end;
}