// TMW2 Scripts // Author: // Jesusalva // Description: // Celestia Yeti King's quest. This controls Soren's House and the three keysigns. // Key #1 // Perform the rite at the Fountain // Key #2 // Perform the rite at the south lake // Key #3 // Perform the rite at the Button Area // // If the same player performs the rite on different places, HE'LL BE PENALIZED. // Performing the rite spawn monsters, so watch out. // Notes: // I had two options: // getvariableofnpc(, "") // This way, each summon point would have .caster and .lifetime // getvariableofpc(, {, }) // This way, I could use @cast_places to control stuff. // // Obviously NPC variables was more sane. // // The use of compareandsetq HurnscaldQuest_Celestia // Ensures you're NOT capable of skipping to final stage in order to finish // the quest. Nice attempt, but that won't work. The scripts will advance, // but you'll stay at the same quest state, and when it's checked, you will // be with bound hands. soren,105,57,0 script Soren's House NPC_NO_SPRITE,0,0,{ end; OnTouch: .@st1=getvariableofnpc(.lifetime, "Soren's Fountain")-gettimetick(2); .@st2=getvariableofnpc(.lifetime, "Soren's Lake")-gettimetick(2); .@st3=getvariableofnpc(.lifetime, "Soren's Gizmo")-gettimetick(2); if (.@st1 > 0 && .@st2 > 0 && .@st3 > 0) { @soren_penalty=0; compareandsetq HurnscaldQuest_Celestia, 3, 4; doevent("#SorenSanctum::OnStart"); warp "soren-2", 32, 36; end; } else { mesn l("Soren's House Tutorial"); mesc l("There's a strong magic barrier. We need to disarm it in order to enter there."); mesc l("There are three singularities on this island. If I disarm more than one, I'll have a penalty."); mesc l("I should have full mana before attempting to disarm one."); mesc l("Also, if I move away from the singularity during disarm process, it'll be lost."); mesc l("The singularities keep arming themselves up again, so I have roughly five minutes between first disarm and entering here."); mesc l("We should split our team, and have someone to protect our backs. Otherwise, we might not do it."); // Protip: stock Elixir Of Life if you need to do this quest with less than 3 team members close; } end; // Some cleanup might be needed to don't raise difficulty infinitely // So every day, at 03:23 AM, if no one is trying the quest, it'll get rid // of the non-permanent monsters on Soren Village & Soren House. // FIXME: It also clears up Groata Grotto OnClock0323: if (getareausers("soren") == 0 && getareausers("soren-2") == 0 && getareausers("001-6") == 0 && getareausers("001-7") == 0) { killmonster("soren", "all"); killmonster("soren-2", "all"); } if ($@GROTTO && getareausers("006-0") == 0 && getareausers("006-3") == 0 && getareausers("006-5") == 0) { killmonster("006-5", "all"); $@GROATA = 0; $@GROTTO = 0; enablenpc "#006-5_49_54"; } end; } soren,105,92,0 script Soren's Fountain NPC_NO_SPRITE,{ // Initial Checks if (.lifetime > gettimetick(2)) { npctalk l("This singularity will remain disarmed for @@ more!", FuzzyTime(.lifetime, 2, 2)); end; } if (.st) { npctalk l("A disarm process is already running."); end; } // Main menu mesc l("Attempt to disarm the singularity?"); if (askyesno() == ASK_YES) { .casterId=getcharid(3); .st=1; npctalk l("@@ started disarm process. Please stand by.", strcharinfo(0)); initnpctimer; if (getvariableofnpc(.casterId, "Soren's Fountain") == .casterId) @sorenp=10; else @sorenp=0; } close; // Waves (total: 6 waves + 1 optional) OnTimer5000: OnTimer10300: OnTimer14000: OnTimer18000: OnTimer25000: OnTimer28000: OnTimer31000: if (!attachrid(.casterId)) { npctalk "Disarm process aborted: Disarmer is gone."; stopnpctimer; .st=0; end; } if (!reachable(.x, .y, .distance)) { npctalk l("Disarm process aborted: Disarmer is out of reach."); stopnpctimer; .st=0; end; } if (Sp < MaxSp/100*15) { npctalk l("Disarm process aborted: Insufficient mana to proceed."); stopnpctimer; .st=0; end; } if (ispcdead()) { npctalk l("Disarm process aborted: Disarmer is dead."); stopnpctimer; .st=0; end; } // Penalty Handler. .@val=-2; if (getvariableofnpc(.casterId, "Soren's Lake") == .casterId) .@val=.@val-10; if (getvariableofnpc(.casterId, "Soren's Gizmo") == .casterId) .@val=.@val-10; if (@sorenp) .@val-=@sorenp; percentheal (.@val/2), -13+.@val; // Monster Gen .@amount=rand2(.st/3+1, .st/2+1)+getareausers("soren", 12); .@mid=rand2(1,3)+.st; switch (.@mid) { case 1: case 2: .@monsterId = CaveMaggot ; break; case 3: case 4: .@monsterId = RedSlime ; break; case 5: case 6: .@monsterId = LavaSlime ; break; case 7: case 8: .@monsterId = any(Snake, GrassSnake, OldSnake, MountainSnake) ; break; default: // case 9: .@monsterId = any(Yeti, Yeti, MountainSnake) ; break; } // Item Gen .@mid=rand(1,7)+.st; switch (.@mid) { case 1: case 2: .@itemId = Acorn ; break; case 3: case 4: .@itemId = any(BugLeg, ChocolateMouboo) ; break; case 5: case 6: .@itemId = OrangeCupcake ; break; case 7: case 8: .@itemId = CherryCake ; break; case 9: case 10: .@itemId = Chagashroom ; break; case 11: .@itemId = GingerBreadMan ; break; case 12: .@itemId = rand2(Diamond, Amethyst) ; break; default: // case 13 .@itemId = rand2(CopperOre, TitaniumOre) ; break; } // Defines .@lx=.x-.distance; .@ly=.y-.distance; .@ux=.x+.distance; .@uy=.y+.distance; // Core function areamonster .map$, .@lx, .@ly, .@ux, .@uy, strmobinfo(1, .@monsterId), .@monsterId, .@amount; makeitem(.@itemId, 1, .map$, rand2(.@lx, .@ux), rand2(.@ly, .@uy)); ++.st; specialeffect(54); // If we're done with waves if (.st >= 7) { getexp rand2(1, 100), rand2(1, 10); .lifetime=gettimetick(2)+330+rand2(0, 60); npctalk l("Disarmed with success for: @@", FuzzyTime(.lifetime, 2, 2)); stopnpctimer; .st=0; specialeffect(27); } end; OnInit: .sex = G_OTHER; .distance = 3; .casterId=0; // getcharid(0) → 3 is account number!! .lifetime=0; // When will this gate expire (six minutes) (gettimetick(2) + (60*5)) .st=0; // Status after started end; } soren,104,143,0 script Soren's Lake NPC_NO_SPRITE,{ // Initial Checks if (.lifetime > gettimetick(2)) { npctalk l("This singularity will remain disarmed for @@ more!", FuzzyTime(.lifetime, 2, 2)); end; } if (.st) { npctalk l("A disarm process is already running."); end; } // Main menu mesc l("Attempt to disarm the singularity?"); if (askyesno() == ASK_YES) { .casterId=getcharid(3); .st=1; npctalk l("@@ started disarm process. Please stand by.", strcharinfo(0)); initnpctimer; if (getvariableofnpc(.casterId, "Soren's Lake") == .casterId) @sorenp=10; else @sorenp=0; } close; // Waves (total: 6 waves + 1 optional) OnTimer4500: OnTimer11300: OnTimer17000: OnTimer22000: OnTimer26200: OnTimer29100: OnTimer30900: if (!attachrid(.casterId)) { npctalk "Disarm process aborted: Disarmer is gone."; stopnpctimer; .st=0; end; } if (!reachable(.x, .y, .distance)) { npctalk l("Disarm process aborted: Disarmer is out of reach."); stopnpctimer; .st=0; end; } if (Sp < MaxSp/100*15) { npctalk l("Disarm process aborted: Insufficient mana to proceed."); stopnpctimer; .st=0; end; } if (ispcdead()) { npctalk l("Disarm process aborted: Disarmer is dead."); stopnpctimer; .st=0; end; } // Penalty Handler. .@val=-2; if (getvariableofnpc(.casterId, "Soren's Fountain") == .casterId) .@val=.@val-10; if (getvariableofnpc(.casterId, "Soren's Gizmo") == .casterId) .@val=.@val-10; if (@sorenp) .@val-=@sorenp; percentheal (.@val/2), -13+.@val; // Monster Gen. Lake spawns less .@amount=rand2(.st/3+1, .st/2+1)+getareausers("soren", 12)-1; .@mid=rand2(1,3)+.st; switch (.@mid) { case 1: case 2: .@monsterId = CaveMaggot ; break; case 3: case 4: .@monsterId = RedSlime ; break; case 5: case 6: .@monsterId = LavaSlime ; break; case 7: case 8: .@monsterId = any(Snake, GrassSnake, OldSnake, MountainSnake) ; break; default: // case 9: .@monsterId = any(Yeti, Yeti, MountainSnake) ; break; } // Item Gen have a different mechanic here .@mid=rand(.st, .st*2+1); switch (.@mid) { case 1: case 2: .@itemId = Acorn ; break; case 3: case 4: .@itemId = any(BugLeg, ChocolateMouboo) ; break; case 5: case 6: .@itemId = OrangeCupcake ; break; case 7: case 8: .@itemId = CherryCake ; break; case 9: case 10: .@itemId = Chagashroom ; break; case 11: .@itemId = HastePotion ; break; case 12: .@itemId = rand2(Diamond, Amethyst) ; break; default: // case 13 .@itemId = rand2(CopperOre, TitaniumOre) ; break; } // Defines for Lake are fixed on the same spot. .@lx=104; .@ux=104; .@ly=141; .@uy=141; // Core function areamonster .map$, .@lx, .@ly, .@ux, .@uy, strmobinfo(1, .@monsterId), .@monsterId, .@amount; makeitem(.@itemId, 1, .map$, rand2(.@lx, .@ux), rand2(.@ly, .@uy)); ++.st; // If we're done with waves if (.st >= 7) { .lifetime=gettimetick(2)+330+rand2(0, 60); npctalk l("Disarmed with success for: @@", FuzzyTime(.lifetime, 2, 2)); stopnpctimer; .st=0; } end; OnInit: .sex = G_OTHER; .distance = 2; .casterId=""; // getcharid(3) → Account number!! .lifetime=0; // When will this gate expire (five~six minutes) (gettimetick(2) + (60*5)) .st=0; // Status after started end; } soren,107,37,0 script Soren's Gizmo NPC_NO_SPRITE,{ // Initial Checks if (.lifetime > gettimetick(2)) { npctalk l("This singularity will remain disarmed for @@ more!", FuzzyTime(.lifetime, 2, 2)); end; } if (.st) { npctalk l("A disarm process is already running."); end; } // Main menu mesc l("Attempt to disarm the singularity?"); if (askyesno() == ASK_YES) { .casterId=getcharid(3); .st=1; npctalk l("@@ started disarm process. Please stand by.", strcharinfo(0)); initnpctimer; if (getvariableofnpc(.casterId, "Soren's Gizmo") == .casterId) @sorenp=10; else @sorenp=0; } close; // Waves (total: 6 waves + 1 optional) OnTimer6200: OnTimer9300: OnTimer13900: OnTimer17200: OnTimer24500: OnTimer27400: OnTimer31200: if (!attachrid(.casterId)) { npctalk "Disarm process aborted: Disarmer is gone."; stopnpctimer; .st=0; end; } if (!reachable(.x, .y, .distance)) { npctalk l("Disarm process aborted: Disarmer is out of reach."); stopnpctimer; .st=0; end; } if (Sp < MaxSp/100*15) { npctalk l("Disarm process aborted: Insufficient mana to proceed."); stopnpctimer; .st=0; end; } if (ispcdead()) { npctalk l("Disarm process aborted: Disarmer is dead."); stopnpctimer; .st=0; end; } // Penalty Handler. .@val=-2; if (getvariableofnpc(.casterId, "Soren's Lake") == .casterId) .@val=.@val-10; if (getvariableofnpc(.casterId, "Soren's Fountain") == .casterId) .@val=.@val-10; if (@sorenp) .@val-=@sorenp; percentheal (.@val/2), -13+.@val; // Monster Gen. Gizmo spawns more monsters because you can move more .@amount=rand2(.st/3+1, .st/2+1)+getareausers("soren", 12)+1; .@mid=rand2(1,3)+.st; switch (.@mid) { case 1: case 2: .@monsterId = CaveMaggot ; break; case 3: case 4: .@monsterId = RedSlime ; break; case 5: case 6: .@monsterId = LavaSlime ; break; case 7: case 8: .@monsterId = any(Snake, GrassSnake, OldSnake, MountainSnake) ; break; default: // case 9: .@monsterId = any(Yeti, Yeti, MountainSnake) ; break; } // Item Gen .@mid=rand(1,7)+.st; switch (.@mid) { case 1: case 2: .@itemId = Acorn ; break; case 3: case 4: .@itemId = any(BugLeg, ChocolateMouboo) ; break; case 5: case 6: .@itemId = OrangeCupcake ; break; case 7: case 8: .@itemId = CherryCake ; break; case 9: case 10: .@itemId = Chagashroom ; break; case 11: .@itemId = HastePotion ; break; case 12: .@itemId = rand2(Diamond, Amethyst) ; break; default: // case 13 .@itemId = rand2(CopperOre, TitaniumOre) ; break; } // Defines .@lx=.x-.distance; .@ly=.y-.distance; .@ux=.x+.distance; .@uy=.y+.distance; // Core function areamonster .map$, .@lx, .@ly, .@ux, .@uy, strmobinfo(1, .@monsterId), .@monsterId, .@amount; makeitem(.@itemId, 1, .map$, rand2(.@lx, .@ux), rand2(.@ly, .@uy)); ++.st; // If we're done with waves if (.st >= 7) { .lifetime=gettimetick(2)+330+rand2(0, 60); npctalk l("Disarmed with success for: @@", FuzzyTime(.lifetime, 2, 2)); stopnpctimer; .st=0; } end; OnInit: .sex = G_OTHER; .distance = 4; .casterId=""; // getcharid(3) → Account number!! .lifetime=0; // When will this gate expire (five~six minutes) (gettimetick(2) + (60*5)) .st=0; // Status after started end; } 029-0,143,120,0 duplicate(Guild Storage) Guild Storekeeper#FoS NPC_TERRY