// 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 lg("Hey, girl!", "Hey, man!"); 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 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."); 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; }