diff options
Diffstat (limited to 'npc/001-15/ctrl.c')
-rw-r--r-- | npc/001-15/ctrl.c | 960 |
1 files changed, 960 insertions, 0 deletions
diff --git a/npc/001-15/ctrl.c b/npc/001-15/ctrl.c new file mode 100644 index 000000000..928a53bdc --- /dev/null +++ b/npc/001-15/ctrl.c @@ -0,0 +1,960 @@ +// TMW2 scripts. +// Author: +// Jesusalva +// Description: +// Moubootaur Legends :: Final Showdown +// +001-15 mapflag zone FinalMMO +// Do we need a battlegrounds MF? + +001-15,0,0,0 script #Moubootaur NPC_HIDDEN,{ + end; + +public function DeathHandler; +public function ReviveHandler; + +function _boostMe { + .@mg = getarg(0); + .@bat=getunitdata(.@mg, UDT_ATKMAX); + .@bai=getunitdata(.@mg, UDT_ATKMIN); + .@bdf=getunitdata(.@mg, UDT_DEF); + .@bcr=getunitdata(.@mg, UDT_CRIT); + .@bag=getunitdata(.@mg, UDT_AGI); + .@bf = getarg(1, $@ML_SHOWDOWN) + 3; + .@s=.@bf+rand2(5); + .@bat = .@bat * (.@bf / 2); + .@bcr = .@bcr * (.@bf / 2); + setunitdata(.@mg, UDT_ATKMAX, .@bat+(.@s*5)); + setunitdata(.@mg, UDT_DEF, .@bdf+(.@s*4)); + setunitdata(.@mg, UDT_CRIT, .@bcr+(.@s*3)); + setunitdata(.@mg, UDT_ATKMIN, .@bai+(.@s*2)); + setunitdata(.@mg, UDT_AGI, .@bag+(.@s*1)); + return; +} + +// Maybe this should be a function +public function MapMode { + // Define the planned new map mode + .@new_mode = rand2(10); + + // Revert the old map mode + switch (.mapMode) { + case ML_MAPMODE_PVP: + pvpoff("001-15"); break; + case ML_MAPMODE_NOCHAT: + removemapflag("001-15",mf_nocommand); + removemapflag("001-15",mf_nochat); + break; + case ML_MAPMODE_NOPETS: + removemapflag("001-15",mf_nopet); + break; + default: + break; + } + + // Set the new map mode + switch (.@new_mode) { + case ML_MAPMODE_PVP: + pvpon("001-15"); break; + case ML_MAPMODE_NOCHAT: + setmapflag("001-15",mf_nocommand,true); + setmapflag("001-15",mf_nochat,true); + break; + case ML_MAPMODE_NOPETS: + setmapflag("001-15",mf_nopet,true); + break; + default: + break; + } + + // Save the new map mode + .mapMode = .@new_mode; + + // TODO: update/set map mask (visual information) + return; +} + +OnDoT: + if (ispcdead()) DeathHandler(true); + percentheal -1, 0; + end; + +// The functions which the Generals call when they die +OnBlue: + if (!playerattached()) { + .@x=72; .@y=41; + } else { + getmapxy(.@m$, .@x, .@y, 0); + } + makeitem(MKeyWater, 1, "001-15", .@x+any(-1,0,1), .@y+any(-1,0,1)); + .@m=monster("001-15", .@x-3, .@y-3, .@x+3, .@y+3, strmobinfo(1, FlyingUnderling), FlyingUnderling, 1); + _boostMe(.@m, 3); + end; + +OnBrown: + if (!playerattached()) { + .@x=25; .@y=55; + } else { + getmapxy(.@m$, .@x, .@y, 0); + } + makeitem(MKeyEarth, 1, "001-15", .@x+any(-1,0,1), .@y+any(-1,0,1)); + .@m=monster("001-15", .@x-3, .@y-3, .@x+3, .@y+3, strmobinfo(1, FlyingUnderling), FlyingUnderling, 1); + _boostMe(.@m, 3); + end; + +OnRed: + if (!playerattached()) { + .@x=74; .@y=55; + } else { + getmapxy(.@m$, .@x, .@y, 0); + } + makeitem(MKeyFire, 1, "001-15", .@x+any(-1,0,1), .@y+any(-1,0,1)); + .@m=monster("001-15", .@x-3, .@y-3, .@x+3, .@y+3, strmobinfo(1, FlyingUnderling), FlyingUnderling, 1); + _boostMe(.@m, 3); + end; + +OnGreen: + if (!playerattached()) { + .@x=42; .@y=36; + } else { + getmapxy(.@m$, .@x, .@y, 0); + } + makeitem(MKeyWind, 1, "001-15", .@x+any(-1,0,1), .@y+any(-1,0,1)); + .@m=monster("001-15", .@x-3, .@y-3, .@x+3, .@y+3, strmobinfo(1, FlyingUnderling), FlyingUnderling, 1); + _boostMe(.@m, 3); + end; + +OnWhite: + if (!playerattached()) { + .@x=25; .@y=25; + } else { + getmapxy(.@m$, .@x, .@y, 0); + } + makeitem(MKeySacred, 1, "001-15", .@x+any(-1,0,1), .@y+any(-1,0,1)); + .@m=monster("001-15", .@x-3, .@y-3, .@x+3, .@y+3, strmobinfo(1, FlyingUnderling), FlyingUnderling, 1); + _boostMe(.@m, 3); + end; + +OnGolden: + if (!playerattached()) { + .@x=40; .@y=50; + } else { + getmapxy(.@m$, .@x, .@y, 0); + } + makeitem(MKeyMana, 1, "001-15", .@x+any(-1,0,1), .@y+any(-1,0,1)); + .@m=monster("001-15", .@x-3, .@y-3, .@x+3, .@y+3, strmobinfo(1, FlyingUnderling), FlyingUnderling, 1); + _boostMe(.@m, 3); + end; + +OnPurple: + if (!playerattached()) { + .@x=70; .@y=30; + } else { + getmapxy(.@m$, .@x, .@y, 0); + } + makeitem(MKeyDeath, 1, "001-15", .@x+any(-1,0,1), .@y+any(-1,0,1)); + .@m=monster("001-15", .@x-3, .@y-3, .@x+3, .@y+3, strmobinfo(1, FlyingUnderling), FlyingUnderling, 1); + _boostMe(.@m, 3); + end; + +OnBlack: + if (!playerattached()) { + .@x=25; .@y=40; + } else { + getmapxy(.@m$, .@x, .@y, 0); + } + makeitem(MKeyEvil, 1, "001-15", .@x+any(-1,0,1), .@y+any(-1,0,1)); + .@m=monster("001-15", .@x-3, .@y-3, .@x+3, .@y+3, strmobinfo(1, FlyingUnderling), FlyingUnderling, 1); + _boostMe(.@m, 3); + end; + + + + + +// Setup first stage +OnFirstStage: + // Eliminate all existing keys + DelItemFromEveryPlayer(MKeyWater); + DelItemFromEveryPlayer(MKeyEarth); + DelItemFromEveryPlayer(MKeyFire); + DelItemFromEveryPlayer(MKeyWind); + DelItemFromEveryPlayer(MKeySacred); + DelItemFromEveryPlayer(MKeyMana); + DelItemFromEveryPlayer(MKeyDeath); + DelItemFromEveryPlayer(MKeyEvil); + + // Spawn the map-wide reinforcements, 20 units for 8 generals + areamonster("001-15", 20, 20, 80, 59, strmobinfo(1, FlyingUnderling), FlyingUnderling, 20); + + // Spawn all Generals and their personal guard + areamonster("001-15", 62, 37, 76, 45, strmobinfo(1, GunnerUnderling), GunnerUnderling, 2); + areamonster("001-15", 62, 37, 76, 45, strmobinfo(1, HalberdUnderling), HalberdUnderling, 2); + areamonster("001-15", 62, 37, 76, 45, strmobinfo(1, WizardUnderling), WizardUnderling, 2); + areamonster("001-15", 62, 37, 76, 45, strmobinfo(1, BansheeUnderling), BansheeUnderling, 2); + .@gen = monster("001-15", 72, 41, "Guardian of Water", TopUnderling, 1, "#Moubootaur::OnBlue"); + _boostMe(.@gen, 6); + + areamonster("001-15", 20, 50, 32, 59, strmobinfo(1, GunnerUnderling), GunnerUnderling, 2); + areamonster("001-15", 20, 50, 32, 59, strmobinfo(1, HalberdUnderling), HalberdUnderling, 2); + areamonster("001-15", 20, 50, 32, 59, strmobinfo(1, WizardUnderling), WizardUnderling, 2); + areamonster("001-15", 20, 50, 32, 59, strmobinfo(1, BansheeUnderling), BansheeUnderling, 2); + .@gen = monster("001-15", 25, 55, "Guardian of Earth", TopUnderling, 1, "#Moubootaur::OnEarth"); + _boostMe(.@gen, 6); + + areamonster("001-15", 68, 51, 80, 59, strmobinfo(1, GunnerUnderling), GunnerUnderling, 2); + areamonster("001-15", 68, 51, 80, 59, strmobinfo(1, HalberdUnderling), HalberdUnderling, 2); + areamonster("001-15", 68, 51, 80, 59, strmobinfo(1, WizardUnderling), WizardUnderling, 2); + areamonster("001-15", 68, 51, 80, 59, strmobinfo(1, BansheeUnderling), BansheeUnderling, 2); + .@gen = monster("001-15", 74, 55, "Guardian of Fire", TopUnderling, 1, "#Moubootaur::OnRed"); + _boostMe(.@gen, 6); + + areamonster("001-15", 35, 23, 47, 40, strmobinfo(1, GunnerUnderling), GunnerUnderling, 2); + areamonster("001-15", 35, 23, 47, 40, strmobinfo(1, HalberdUnderling), HalberdUnderling, 2); + areamonster("001-15", 35, 23, 47, 40, strmobinfo(1, WizardUnderling), WizardUnderling, 2); + areamonster("001-15", 35, 23, 47, 40, strmobinfo(1, BansheeUnderling), BansheeUnderling, 2); + .@gen = monster("001-15", 42, 36, "Guardian of Wind", TopUnderling, 1, "#Moubootaur::OnGreen"); + _boostMe(.@gen, 6); + + areamonster("001-15", 20, 20, 32, 30, strmobinfo(1, GunnerUnderling), GunnerUnderling, 2); + areamonster("001-15", 20, 20, 32, 30, strmobinfo(1, HalberdUnderling), HalberdUnderling, 2); + areamonster("001-15", 20, 20, 32, 30, strmobinfo(1, WizardUnderling), WizardUnderling, 2); + areamonster("001-15", 20, 20, 32, 30, strmobinfo(1, BansheeUnderling), BansheeUnderling, 2); + .@gen = monster("001-15", 25, 25, "Guardian of Sacred", TopUnderling, 1, "#Moubootaur::OnWhite"); + _boostMe(.@gen, 6); + + areamonster("001-15", 33, 43, 46, 56, strmobinfo(1, GunnerUnderling), GunnerUnderling, 2); + areamonster("001-15", 33, 43, 46, 56, strmobinfo(1, HalberdUnderling), HalberdUnderling, 2); + areamonster("001-15", 33, 43, 46, 56, strmobinfo(1, WizardUnderling), WizardUnderling, 2); + areamonster("001-15", 33, 43, 46, 56, strmobinfo(1, BansheeUnderling), BansheeUnderling, 2); + .@gen = monster("001-15", 40, 50, "Guardian of Mana", TopUnderling, 1, "#Moubootaur::OnGolden"); + _boostMe(.@gen, 6); + + areamonster("001-15", 64, 24, 77, 33, strmobinfo(1, GunnerUnderling), GunnerUnderling, 2); + areamonster("001-15", 64, 24, 77, 33, strmobinfo(1, HalberdUnderling), HalberdUnderling, 2); + areamonster("001-15", 64, 24, 77, 33, strmobinfo(1, WizardUnderling), WizardUnderling, 2); + areamonster("001-15", 64, 24, 77, 33, strmobinfo(1, BansheeUnderling), BansheeUnderling, 2); + .@gen = monster("001-15", 70, 30, "Guardian of Death", TopUnderling, 1, "#Moubootaur::OnPurple"); + _boostMe(.@gen, 6); + + areamonster("001-15", 21, 33, 30, 47, strmobinfo(1, GunnerUnderling), GunnerUnderling, 2); + areamonster("001-15", 21, 33, 30, 47, strmobinfo(1, HalberdUnderling), HalberdUnderling, 2); + areamonster("001-15", 21, 33, 30, 47, strmobinfo(1, WizardUnderling), WizardUnderling, 2); + areamonster("001-15", 21, 33, 30, 47, strmobinfo(1, BansheeUnderling), BansheeUnderling, 2); + .@gen = monster("001-15", 25, 40, "Guardian of Evil", TopUnderling, 1, "#Moubootaur::OnBlack"); + _boostMe(.@gen, 6); + + end; + + + + + + + + + +// **MOUBOOTAUR HEARTBEAT** +OnTimer25000: +OnTimer20000: +OnTimer15000: + consolewarn("Warning, fail-safe mechanism triggered to Moubootaur (Awakened)."); +OnTimer10000: + .mana += any(1,2,3,5); // Recover mana + + // Moubootaur Showdown Effects + if (getvariableofnpc(.mapMode, "#Moubootaur") == ML_MAPMODE_DOT) { + maptimer2("001-15", 10, "#Moubootaur::OnDoT"); + } + + // TODO: Defeat Conditions + // TODO: Work in Progress + + + // Maybe we need to advance the turn + .tbet += 1; + if (!(.tbet % 9)) { + // Reset turn cycle (90s) and advance turn counter + .tbet=0; + .turn+=1; + + // Change map mode + if ($@ML_SHOWDOWN >= 3) + MapMode(); + + // Spawn the air corps + if ($@ML_SHOWDOWN >= 2) { + for (.@i=0; .@i<5; .@i++) { + .@m=areamonster("001-15", 49, 30, 60, 42, strmobinfo(1, FlyingUnderling), FlyingUnderling, 1); + _boostMe(.@m); // Will boost according to showdown state + } + } + // TODO: Tally Battlegrounds results + } + + initnpctimer; + end; + + + + + + + + + + + +// Scope: MLDIE_ +// DeathHandler( end = false , dead = true ) +public function DeathHandler { + // First death, handle it! + debugmes "Change Class from %d to %d", Class, Skelli; + if (Class != Skelli) { + MLDIE_Class = Class; + jobchange Skelli; + } + // Save your equipment selection for a quick equip() after unstoring + // (Handled by ReviveHandler) + for ( .@i=EQI_HEAD_TOP ; .@i<=EQI_SHADOW_ACC_L ; .@i++ ) { + array_push( MLDIE_Eqp, getequipid(.@i) ); + } + + // All your items go away to Special Storage + charcommand("@storeall 6"); + // All your money goes away to Special Storage + MLDIE_Zeny += Zeny; + Zeny = 0; + + // Permanent Debuff is handled by hub functions + + // TODO: Death NPC which recovers all your items + // (Do we have bindings for unstoring? We might need a new C-level function) + // + // (Also, we need to check if Death NPC already exists) + // (And this check must be independent on your Class) + // (DeathNPC should call ReviveHandler if Class is Skelli or ...?) + // (Also, we're failing to revive you here D:) + + // TODO: Check if DeathNpc already exists + // TODO: If not and getmap is 001-15, create it + // TODO: Else, create it close to a random player in map + // TODO: If that fails, create in entrance + // TODO: We need a way to distinguish undead players from normal players? + // (Will we use Benjamin sprite? What npc_duplicate gives us to track?) + // NPC_GUARD_DEAD, NPC_INJURIED_GIRL, or can we make it dynamic? + + // Eliminate any key you may have and revive the trupe + // No state check is necessary; the keys should not be duplicated + if (countitem(MKeyWater)) { + delitem MKeyWater, 1; + .@gen = monster("001-15", 72, 41, "Guardian of Water", TopUnderling, 1, "#Moubootaur::OnBlue"); + _boostMe(.@gen, 12); + } + if (countitem(MKeyEarth)) { + delitem MKeyEarth, 1; + .@gen = monster("001-15", 25, 55, "Guardian of Earth", TopUnderling, 1, "#Moubootaur::OnEarth"); + _boostMe(.@gen, 12); + } + if (countitem(MKeyFire)) { + delitem MKeyFire, 1; + .@gen = monster("001-15", 74, 55, "Guardian of Fire", TopUnderling, 1, "#Moubootaur::OnRed"); + _boostMe(.@gen, 12); + } + if (countitem(MKeyWind)) { + delitem MKeyWind, 1; + .@gen = monster("001-15", 42, 36, "Guardian of Wind", TopUnderling, 1, "#Moubootaur::OnGreen"); + _boostMe(.@gen, 12); + } + if (countitem(MKeySacred)) { + delitem MKeySacred, 1; + .@gen = monster("001-15", 25, 25, "Guardian of Sacred", TopUnderling, 1, "#Moubootaur::OnWhite"); + _boostMe(.@gen, 12); + } + if (countitem(MKeyMana)) { + delitem MKeyMana, 1; + .@gen = monster("001-15", 40, 50, "Guardian of Mana", TopUnderling, 1, "#Moubootaur::OnGolden"); + _boostMe(.@gen, 12); + } + if (countitem(MKeyDeath)) { + delitem MKeyDeath, 1; + .@gen = monster("001-15", 70, 30, "Guardian of Death", TopUnderling, 1, "#Moubootaur::OnPurple"); + _boostMe(.@gen, 12); + } + if (countitem(MKeyEvil)) { + delitem MKeyEvil, 1; + .@gen = monster("001-15", 25, 40, "Guardian of Evil", TopUnderling, 1, "#Moubootaur::OnBlack"); + _boostMe(.@gen, 12); + } + + // Warp you to the respawn area if set (and revives you) + if (getarg(1, true)) { + debugmes "Now reviving ML victim..."; + atcommand("@alive"); + warp "001-15", rand2(84, 87), rand2(21, 26); + } + + // Prevent you from being slaughtered right after + // By granting you **4** seconds of invincibility! + // TODO: Check if this works correctly + sc_start SC_INVINCIBLE, rand(4000,4900), 1, 10000, SCFLAG_NOAVOID|SCFLAG_FIXEDTICK|SCFLAG_NOICON; + + debugmes "We have now completed the Death Handler"; + + // We were instructed to terminate the interaction + if (getarg(0, false)) + end; + // Otherwise, return the control to caller + return; +} + + + + + + + + +// Undo everything DeathHandler did, and takes same arguments +public function ReviveHandler { + // TODO: "#Moubootaur"::PermanentDebuffs() if getmap() == 001-15 + // Restore your Class + jobchange MLDIE_Class; + Zeny += MLDIE_Zeny; + // Reset these variables + MLDIE_Class = 0; + MLDIE_Zeny = 0; + + // TODO: !! Unstash all your items !! + unstoreall(6); + /* This code does not work + sc_start SC_INVINCIBLE, 99999, 1, 10000, SCFLAG_NOAVOID|SCFLAG_FIXEDTICK|SCFLAG_NOICON; + openstorage(6, STORAGE_ACCESS_GET); + sc_end SC_INVINCIBLE; + sc_start SC_INVINCIBLEOFF, 1, 1; + */ + + // Re-equip your items + // Do not call equip() if < 1, it can be negative after all + for (.@i=0 ; .@i < getarraysize(MLDIE_Eqp) ; .@i++) { + if (MLDIE_Eqp[.@i] > 1) + equip(MLDIE_Eqp[.@i]); + } + deletearray MLDIE_Eqp; + + // TODO: Eliminate DeathNPC if it exists + + // We were instructed to terminate the interaction + if (getarg(0, false)) + end; + // Otherwise, return the control to caller + return; +} + +// Begin Introduction Cutscene (Event Start!!) +OnIntroCutscene: + // Reset Showdown Status (Clear Previous Attempts) + stopnpctimer; + $@ML_SHOWDOWN=1; + .turn = 0; + .tbet = 0; + .ML = 0; + disablenpc "#ML_EastWarp"; + disablenpc "#MLWA+"; + + // Create Andrei Sakar + .HERO=monster("001-15", 55, 47, "Andrei Sakar", ManaGhost, 1); + immortal(.HERO); + sc_start SC_STUN, 99990, 1, 10000, SCFLAG_NOAVOID|SCFLAG_FIXEDTICK, .HERO; + + // This is the prologue cutscene. It's kinda long so everyone has time to arrive. + sleep(1000); + unittalk(.HERO, "Oooohhhh. Someone actually came!"); + sleep(5000); + unittalk(.HERO, "Maybe I should wait a while to see if more people show up!"); + sleep(5000); + unittalk(.HERO, "Sorry, I haven't existed properly for a while."); + sleep(5000); + unittalk(.HERO, "But this is the Mana Plane section of the World Heart, so it matters not."); + sleep(10000); + unittalk(.HERO, "Anyway, my name is Andrei, and I used to be a legendary hero of this world."); + sleep(8000); + unittalk(.HERO, "Then, during a campaign to the Fortress, I noticed the lack of aid from Artis region."); + sleep(8000); + unittalk(.HERO, "While investigating Artis, Isbamuth minions killed me as a sacrifice to revive the Moubootaur."); + sleep(9000); + unittalk(.HERO, "I'm not entirely sure why. Mr. Saves should have prevented Talpans from allying with the Moubootaur and monsters from allying with Elli, but I assume exceptions were made. Likely a bug!"); + sleep(14000); + unittalk(.HERO, "Anyway, this means I'm unable to use the Soul Menhir and became a lost soul. Same will happen to all of you, shall you die here!"); + sleep(8000); + unittalk(.HERO, "But if you find your corpse back, or one of the Obelisks of Power, you might be able to return."); + sleep(7000); + // Official justification in case your body (Death NPC) is not available. + unittalk(.HERO, "Even if your body is consumed like mine was, the Obelisk of Power can still bring you back. However..."); + sleep(7500); + unittalk(.HERO, "Elli still has jurisdiction over Talpans. She probably vetoed my return, because I couldn't revive! Hahahah."); + sleep(7500); + /* TODO: Apply Elli's curse to all players */ + unittalk(.HERO, "Anyway! The Moubootaur is in the area ahead plotting something, but you'll need to find a way to enable the warp I'm standing on first."); + sleep(10000); + unittalk(.HERO, "I'll enable the warp to the west so you can explore! Good luck, adventurers!"); + sleep(2000); + enablenpc "#MLWA+"; + + // And now that everything is ready and done, start the timer and set turn 1 + .turn = 1; + initnpctimer; + sc_end SC_STUN, .HERO; + goto OnFirstStage; + +OnInit: + .warpsOnline = true; + .mapMode = 0; + + .ML=0; + .HERO=0; + .maxhp = 1000000; // 1,000,000 HP (used by scripts) + .mana = 0; // More mana = more likely to cast skills + + .memohp = 999; // Memorand HP, controls spawns + .start_time = gettimetick(2); // Controls Death Touch + .tbet = 0; // Internal counter for turn system + .turn = 0; // Actual turn counter + + .dmhp1 = 750000; // The "default" max HP + .dmhp2 = 250000; // The "extra" max HP + + // Platforms Cardinal Sequence is + // Central, Clock, Wind, Fire, Plague, Cold, Blood, Disease, Curse + // XXX: Moubootaur goes from [1] to [8] + setarray $@MLFX, 52, 44, 43, 78, 64, 31, 22, 27, 74, 44, 43, 78, 64, 31, 22, 27, 74; + setarray $@MLFY, 49, 55, 24, 56, 44, 20, 51, 34, 31, 55, 24, 56, 44, 20, 51, 34, 31; + end; +} + + + +001-15,55,47,0 script #ML_NorthWarp NPC_ML_CIRCLE,0,0,{ + end; +OnTouch: + if ($@ML_SHOWDOWN < 2) goto L_InitCheck; + slide 54, 29; + + // Kill any stray timer too in the Central Platform + // It's overkill and not really necessary, BUT better safe than sorry + deltimer("#DungeonCore::OnClocked"); + deltimer("#DungeonCore::OnWindy"); + deltimer("#DungeonCore::OnHeat"); + deltimer("#DungeonCore::OnLeech"); + deltimer("#DungeonCore::OnFrost"); + deltimer("#DungeonCore::OnBleed"); + deltimer("#DungeonCore::OnSick"); + deltimer("#DungeonCore::OnCurse"); + end; + +L_InitCheck: + // First way to trigger: All keys in a single player inventory + if (countitem(MKeyWater) == 1 && + countitem(MKeyEarth) == 1 && + countitem(MKeyDeath) == 1 && + countitem(MKeyFire) == 1 && + countitem(MKeyWind) == 1 && + countitem(MKeyMana) == 1 && + countitem(MKeyEvil) == 1 && + countitem(MKeySacred) == 1) goto L_InitDel; + // Second (prefered) way to trigger: All keys in the magic circle + .@i=0; + .@i+=min(1,getareadropitem("001-15", .x-3, .y-3, .x+3, .y+3, MKeyWater, false)); + .@i+=min(1,getareadropitem("001-15", .x-3, .y-3, .x+3, .y+3, MKeyEarth, false)); + .@i+=min(1,getareadropitem("001-15", .x-3, .y-3, .x+3, .y+3, MKeyDeath, false)); + .@i+=min(1,getareadropitem("001-15", .x-3, .y-3, .x+3, .y+3, MKeyFire, false)); + .@i+=min(1,getareadropitem("001-15", .x-3, .y-3, .x+3, .y+3, MKeyWind, false)); + .@i+=min(1,getareadropitem("001-15", .x-3, .y-3, .x+3, .y+3, MKeyMana, false)); + .@i+=min(1,getareadropitem("001-15", .x-3, .y-3, .x+3, .y+3, MKeyEvil, false)); + .@i+=min(1,getareadropitem("001-15", .x-3, .y-3, .x+3, .y+3, MKeySacred,false)); + if (.@i == 8) goto L_InitOk; + dispbottom l("This circle doesn't work right now. Maybe there's a clue on what is needed?"); + end; + +L_InitDel: + delitem MKeySacred, 1; + delitem MKeyWater, 1; + delitem MKeyEarth, 1; + delitem MKeyDeath, 1; + delitem MKeyFire, 1; + delitem MKeyWind, 1; + delitem MKeyEvil, 1; + delitem MKeyMana, 1; + // FALLTHROUGH +L_InitOk: + $@ML_SHOWDOWN=2; + getareadropitem("001-15", .x-3, .y-3, .x+3, .y+3, MKeyWater, true); + getareadropitem("001-15", .x-3, .y-3, .x+3, .y+3, MKeyEarth, true); + getareadropitem("001-15", .x-3, .y-3, .x+3, .y+3, MKeyDeath, true); + getareadropitem("001-15", .x-3, .y-3, .x+3, .y+3, MKeyFire, true); + getareadropitem("001-15", .x-3, .y-3, .x+3, .y+3, MKeyWind, true); + getareadropitem("001-15", .x-3, .y-3, .x+3, .y+3, MKeyMana, true); + getareadropitem("001-15", .x-3, .y-3, .x+3, .y+3, MKeyEvil, true); + getareadropitem("001-15", .x-3, .y-3, .x+3, .y+3, MKeySacred,true); + // Send the hero to the warp circle + .@hero = getvariableofnpc(.HERO, "#Moubootaur"); + unitwalk(.@hero, 55, 47); + // Mark the activation + sleep2(50); + specialeffect(312, AREA, .name$); + // Enable the warp and NPC dialogue + sleep2(300); + enablenpc "#ML_EastWarp"; + unittalk(getvariableofnpc(.HERO, "#Moubootaur"), "Good job! Chop chop!"); + // Warp NPC and activator to the platform + sleep2(250); + unitwarp(.@hero, "001-15", 55, 29); + sc_start SC_STUN, 86400000, 1, 10000, SCFLAG_NOAVOID|SCFLAG_FIXEDTICK, .@hero; + // TODO: Begin 2nd Stage Cutscene + goto OnTouch; + end; +OnInit: + end; +} + + + +001-15,54,28,0 script #ML_NorthExit NPC_HIDDEN,0,0,{ + end; +OnTouch: + if ($@ML_SHOWDOWN < 2) end; + slide 55, 48; + end; +L_InitCheck: + end; +OnInit: + end; +} + + + +001-15,60,53,0 script #ML_EastWarp NPC_SUMMONING_CIRC,0,0,{ + end; +OnTouch: + // Verify if this portal is active (it should, however, be disabled!) + if (!getvariableofnpc(.turn, "#Moubootaur")) + end; + if ($@ML_SHOWDOWN < 2) goto L_Inactive; + + // Assuming nothing is wrong, then do the warp + slide 85, 57; + end; + +// Report the error to the user & console +L_Inactive: + dispbottom l("There's nothing of interest in this direction... for now."); + consolewarn("ML Showdown: Eastern Portal was visible while disabled."); + end; +OnInit: + end; +} + + +// You can always leave the battleground area, there's no restriction whatsoever +001-15,85,58,0 script #ML_EastExit NPC_SUMMONING_CIRC,0,0,{ + end; +OnTouch: + slide 60, 54; + end; +OnInit: + end; +} + + + +/* Miller system (otherwise, you can't reach the switches & platforms) */ +001-15,51,49,0 script #MLWA+ NPC_FANCY_CIRCLE,0,0,{ + end; +OnTouch: + // TODO: Verify if portalling is active in the Showdown + // Probably via a public function in #Moubootaur + if (false) { + dispbottom l("Oh no! The Moubootaur has disabled this portal!"); + end; + } + if (!$@ML_SHOWDOWN) + end; + if (!getvariableofnpc(.turn, "#Moubootaur")) + end; + + // Dungeon Climate System (stop effect, start next) + // TODO: Disable previous Climate System timer, before @state is changed + switch (miller_rand(@state, getcharid(0), 9)) { + case 1: + deltimer("#DungeonCore::OnClocked"); break; + case 2: + deltimer("#DungeonCore::OnWindy"); break; + case 3: + deltimer("#DungeonCore::OnHeat"); break; + case 4: + deltimer("#DungeonCore::OnLeech"); break; + case 5: + deltimer("#DungeonCore::OnFrost"); break; + case 6: + deltimer("#DungeonCore::OnBleed"); break; + case 7: + deltimer("#DungeonCore::OnSick"); break; + case 8: + deltimer("#DungeonCore::OnCurse"); break; + default: + // Case 0 has no special effects whatsoever + break; + } + + // All portals are the same, anyway + if (compare(strnpcinfo(2), "+")) + @state += 3; + else + @state -= 2; + .@index = miller_rand(@state, getcharid(0), 9); + slide $@MLFX[.@index], $@MLFY[.@index]; + + // Dungeon Climate System (start effect, stop previous) + switch (.@index) { + case 1: + addtimer(10, "#DungeonCore::OnClocked"); break; + case 2: + addtimer(10, "#DungeonCore::OnWindy"); break; + case 3: + addtimer(10, "#DungeonCore::OnHeat"); break; + case 4: + addtimer(10, "#DungeonCore::OnLeech"); break; + case 5: + addtimer(10, "#DungeonCore::OnFrost"); break; + case 6: + addtimer(10, "#DungeonCore::OnBleed"); break; + case 7: + addtimer(10, "#DungeonCore::OnSick"); break; + case 8: + addtimer(10, "#DungeonCore::OnCurse"); break; + default: + // Case 0 has no special effects whatsoever + break; + } + end; +} +//001-15,28,136,0 duplicate(#MLWA+) #MLWA- NPC_FANCY_CIRCLE,0,0 +// Clock, Wind, Fire, Plague, Cold, Blood, Disease, Curse +// B, C, D, E, F, G, H, I +001-15,34,44,0 duplicate(#MLWA+) #MLWB+ NPC_NO_SPRITE,0,0 +001-15,45,55,0 duplicate(#MLWA+) #MLWB- NPC_NO_SPRITE,0,0 +001-15,36,38,0 duplicate(#MLWA+) #MLWC+ NPC_FANCY_CIRCLE,0,0 +001-15,44,24,0 duplicate(#MLWA+) #MLWC- NPC_FANCY_CIRCLE,0,0 +001-15,69,53,0 duplicate(#MLWA+) #MLWD+ NPC_FANCY_CIRCLE,0,0 +001-15,78,55,0 duplicate(#MLWA+) #MLWD- NPC_FANCY_CIRCLE,0,0 +001-15,75,38,0 duplicate(#MLWA+) #MLWE+ NPC_FANCY_CIRCLE,0,0 +001-15,63,44,0 duplicate(#MLWA+) #MLWE- NPC_FANCY_CIRCLE,0,0 +001-15,21,24,0 duplicate(#MLWA+) #MLWF+ NPC_FANCY_CIRCLE,0,0 +001-15,31,22,0 duplicate(#MLWA+) #MLWF- NPC_FANCY_CIRCLE,0,0 +001-15,31,59,0 duplicate(#MLWA+) #MLWG+ NPC_FANCY_CIRCLE,0,0 +001-15,21,51,0 duplicate(#MLWA+) #MLWG- NPC_FANCY_CIRCLE,0,0 +001-15,22,43,0 duplicate(#MLWA+) #MLWH+ NPC_FANCY_CIRCLE,0,0 +001-15,28,34,0 duplicate(#MLWA+) #MLWH- NPC_FANCY_CIRCLE,0,0 +001-15,65,26,0 duplicate(#MLWA+) #MLWI+ NPC_FANCY_CIRCLE,0,0 +001-15,75,31,0 duplicate(#MLWA+) #MLWI- NPC_FANCY_CIRCLE,0,0 + + + + + + + + + + + + + + + + + + +// Main Room Traps, only against players +001-15,0,0,0 script #ML_Trap01 NPC_TRAP_ONLINE,0,0,{ + end; + +OnTouch: +OnTouchNPC: + WorldHeartTrap(); + sleep(500); // Wait 500ms for animation + setnpcdisplay .name$, NPC_TRAP_ONLINE; + // Move the trap away after it disarms (up to 30 attempts) + +OnInit: + .@e=0; + do { + if (.@e >= 30) + break; + .@x = rand2(48, 60); + .@y = rand2(30, 44); + .@e+=1; + } while (!checknpccell("001-15", .@x, .@y, cell_chkpass)); + movenpc .name$, .@x, .@y; + end; +} + +001-15,0,0,0 duplicate(#ML_Trap01) #ML_Trap02 NPC_TRAP_ONLINE,0,0 +001-15,0,0,0 duplicate(#ML_Trap01) #ML_Trap03 NPC_TRAP_ONLINE,0,0 +001-15,0,0,0 duplicate(#ML_Trap01) #ML_Trap04 NPC_TRAP_ONLINE,0,0 +001-15,0,0,0 duplicate(#ML_Trap01) #ML_Trap05 NPC_TRAP_ONLINE,0,0 +001-15,0,0,0 duplicate(#ML_Trap01) #ML_Trap06 NPC_TRAP_ONLINE,0,0 +001-15,0,0,0 duplicate(#ML_Trap01) #ML_Trap07 NPC_TRAP_ONLINE,0,0 + + + + + +// Convenience Shop NPC +// TODO: enablenpc; and disablenpc; depending on state? Move to (58,50)? +001-15,50,47,0 script Tiki NPC_TIKI,{ + mesn; + mes l("Hey hey, my name is Micksha, and I'm Arthur's grandfather!"); + mes l("I retired to my own laboratory and sell strange drinks on the side!"); + mes l("The Mirror Lake here is twisty, so I can do things to you... for a price!"); + next; + // Pricing + .@price = 15; + if (!MOUBOOTAUR_WINNER) .@price += 150; + if (!EPISODE_WINNER) .@price += 150; + if (islegendary()) .@price += 65; + mesc l("Special Price for You! %s GP!", fnum(.@price)), 1; + // Friendly Advise, "free" of charge + if (any(true, false)) + mesc l("* \"Make sure to be well stocked and stashed for the fights! Preparation is the utmost for victory!\" - The Micksha"); + else + mesc l("* \"Prepare, go and destroy! Don't tell your parents I've said that!\" - The Micksha"); + + // Require the money NOW + if (Zeny >= .@price) + Zeny -= .@price; + else if (BankVault >= .@price) + BankVault -= .@price; + else + close; + + // Main Menu + select + l("I don't need anything!"), + l("Withdraw Money"), + rif($@ML_SHOWDOWN < 2, l("Open Storage")), + l("Nursery services"), + l("Acquire goods"); + switch (@menu) { + case 2: + Banking(); + break; + case 3: + Banker("Micksha", "Impregnable Fortress", 999999); + break; + case 4: + Nurse("Micksha", 10, 6); + break; + case 5: + closeclientdialog; + openshop(.name$); + break; + default: + Zeny += .@price; + break; + } + close; + +// x2( Item , Multiplier=2x ) +function x2 { + return getiteminfo(getarg(0), ITEMINFO_BUYPRICE) * getarg(1, 2); +} + +OnInit: + .sex = G_MALE; + .distance = 3; + sellitem InsuranceContract, x2(InsuranceContract, 1); + sellitem ChamomileTea, x2(ChamomileTea, 4); // Mana F + sellitem YerbaMate, x2(YerbaMate, 1); // Mana S + sellitem LemonCake, x2(LemonCake, 3); // Homun F + sellitem WhiteCake, x2(WhiteCake, 5); // Homun A + sellitem PiberriesInfusion, x2(PiberriesInfusion, 3); + sellitem FatesPotion, x2(FatesPotion, 3); + sellitem ClothoLiquor, x2(ClothoLiquor, 3); + sellitem LachesisBrew, x2(LachesisBrew, 3); + sellitem AtroposMixture, x2(AtroposMixture, 3); + sellitem TrainingAmmoBox, x2(TrainingAmmoBox); // Arrow E + sellitem IronAmmoBox, x2(IronAmmoBox); // Arrow C + sellitem BigBulletSack, x2(BigBulletSack, 1); // Bullets MAX + sellitem StatusResetPotion, 4999; + sellitem MercBoxA, 9999; + sellitem BottleOfSewerWater, 9999; + sellitem BlueberryCake, 9999; + sellitem SmokeGrenade, 9999; + sellitem ScentGrenade, 9999; + sellitem HerbalTea, 9999; + sellitem EmptyBox, 9999; + sellitem Coffee, 9999; + sellitem IcedBottle, 9999; + sellitem PurificationPotion, 9999; + sellitem ScrollSCave, 9999; + sellitem CommonCarp, 9999; + sellitem FishingRod, 9999; + sellitem TreasureKey, 9999; + sellitem SaxsoKey, 9999; + sellitem Flour, 9999; + sellitem StrangeCoin, 9999; + sellitem GuildCoin, 9999; + sellitem HeroCoin, 9999; + sellitem Lifestone, 9999; + sellitem Quill, 9999; + sellitem EverburnPowder, 9999; + sellitem EarthPowder, 9999; + sellitem WoodenLog, 9999; + sellitem MinerKnife, 9999; + sellitem ShortBow, 9999; + sellitem Lockpicks, 9999; + sellitem IronShovel, 9999; + sellitem EmptyBottle, 12999; + sellitem ArcmageBoxset, 14999; + sellitem LeatherQuiver, 19999; + sellitem HomunResetPotion, 19999; + sellitem DeathPotion, 19999; + sellitem NymphPoison, 19999; + sellitem BrokenWarpCrystal, 19999; + sellitem SacredImmortalityPotion, 29999; + sellitem GoldenApple, 49999; + sellitem ElixirOfLife, 99999; + sellitem MagicApple, 199999; + sellitem LegendaryTortuga, 1499999; + sellitem PiouEgg, 3499999; + sellitem Skypiercer, 9999999; + sellitem BlackyCatFix, INT_MAX/2; + end; +} + +function script ML_MobKill { + // Moubootaur Showdown Effects + if (getvariableofnpc(.mapMode, "#Moubootaur") == ML_MAPMODE_PAY2KILL) { + // Not a target of the map-wide effect + if (getmap() != "001-15") + return; + // Price is 10 GP per monster level (~3000 gp for Tortuga) + .@price = strmobinfo(3,killedrid) * 10; + .@price += rand2(JobLevel); + .@debit = 0; + // Pay the money or set .@debit + if (Zeny >= .@price) + Zeny -= .@price; + else + .@debit = .@price - Zeny; + // For each unpaid GP, you lose 1% HP + if (.@debit) { + Zeny = 0; + percentheal -(.@debit), -(.@debit); + } + } + return; +} + + |