diff options
author | Jesusaves <cpntb1@ymail.com> | 2019-03-06 12:49:10 -0300 |
---|---|---|
committer | Jesusaves <cpntb1@ymail.com> | 2019-03-06 12:49:10 -0300 |
commit | 48551c2016339956979f2c9f73115af36c1a0292 (patch) | |
tree | 05007879cfe76d4858d2510e937b1656c20beb0e | |
parent | 23ac38921f6f9f58e619b41f7467dff7e6a00df7 (diff) | |
parent | 600fac0c6e0d07dd99aeccf443e2262239b64aea (diff) | |
download | serverdata-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.conf | 1 | ||||
-rw-r--r-- | db/constants.conf | 3 | ||||
-rw-r--r-- | db/craft_db.conf | 87 | ||||
-rw-r--r-- | db/quest_db.conf | 4 | ||||
-rw-r--r-- | db/re/item_db.conf | 13 | ||||
-rw-r--r-- | maps/re/001-3-0.mcache | bin | 1261 -> 1296 bytes | |||
-rw-r--r-- | npc/000-0-0/sailors.txt | 1 | ||||
-rw-r--r-- | npc/000-2-1/peter.txt | 445 | ||||
-rw-r--r-- | npc/000-2-2/doors.txt | 14 | ||||
-rw-r--r-- | npc/000-2-2/ratto.txt | 109 | ||||
-rw-r--r-- | npc/001-1/manhole.txt | 34 | ||||
-rw-r--r-- | npc/001-2-11/mona.txt | 52 | ||||
-rw-r--r-- | npc/001-2-22/peter.txt | 445 | ||||
-rw-r--r-- | npc/001-2-23/doors.txt | 18 | ||||
-rw-r--r-- | npc/001-2-23/ratto.txt | 109 | ||||
-rw-r--r-- | npc/001-3-0/_import.txt | 1 | ||||
-rw-r--r-- | npc/001-3-0/_mobs.txt | 4 | ||||
-rw-r--r-- | npc/001-3-0/mundane.txt | 142 | ||||
-rw-r--r-- | npc/008-2-16/_import.txt | 2 | ||||
-rw-r--r-- | npc/008-2-16/stove.txt | 88 | ||||
-rw-r--r-- | npc/008-2-16/yannika.txt | 300 | ||||
-rw-r--r-- | npc/commands/debug-quest.txt | 3 | ||||
-rw-r--r-- | npc/functions/quest-debug/003-ShipQuests_Peter.txt | 18 | ||||
-rw-r--r-- | npc/functions/quest-debug/041-General_Cooking.txt | 51 | ||||
-rw-r--r-- | npc/functions/util.txt | 41 | ||||
-rw-r--r-- | npc/items/recipes.txt | 60 | ||||
-rw-r--r-- | npc/scripts.conf | 2 |
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 Binary files differindex 7dd92e07..1c422edc 100644 --- a/maps/re/001-3-0.mcache +++ b/maps/re/001-3-0.mcache 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", |