summaryrefslogtreecommitdiff
path: root/npc/034-4
diff options
context:
space:
mode:
authorJesusaves <cpntb1@ymail.com>2022-10-23 21:44:22 -0300
committerJesusaves <cpntb1@ymail.com>2022-10-23 21:44:22 -0300
commita7c45a192268da2601cef47a4cdba987ae2327ca (patch)
treec5fb5b97db109fe7106496dd96498c475881046b /npc/034-4
downloadserverdata-a7c45a192268da2601cef47a4cdba987ae2327ca.tar.gz
serverdata-a7c45a192268da2601cef47a4cdba987ae2327ca.tar.bz2
serverdata-a7c45a192268da2601cef47a4cdba987ae2327ca.tar.xz
serverdata-a7c45a192268da2601cef47a4cdba987ae2327ca.zip
Initial commit (Moubootaur Legends fork)
Diffstat (limited to 'npc/034-4')
-rw-r--r--npc/034-4/_import.txt6
-rw-r--r--npc/034-4/exit.txt276
-rw-r--r--npc/034-4/intro.txt211
-rw-r--r--npc/034-4/lobby.txt263
-rw-r--r--npc/034-4/storage.txt186
5 files changed, 942 insertions, 0 deletions
diff --git a/npc/034-4/_import.txt b/npc/034-4/_import.txt
new file mode 100644
index 0000000..4e1f47c
--- /dev/null
+++ b/npc/034-4/_import.txt
@@ -0,0 +1,6 @@
+// Map 034-4: Forsaken Inn
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/034-4/exit.txt",
+"npc/034-4/intro.txt",
+"npc/034-4/lobby.txt",
+"npc/034-4/storage.txt",
diff --git a/npc/034-4/exit.txt b/npc/034-4/exit.txt
new file mode 100644
index 0000000..07d96ea
--- /dev/null
+++ b/npc/034-4/exit.txt
@@ -0,0 +1,276 @@
+// TMW2 scripts.
+// Authors:
+// Jesusalva
+// Description:
+// Gemini Sisters Quest - Part D: Final Chamber
+
+034-4,144,82,0 script #GeminiFExit NPC_HIDDEN,0,0,{
+
+OnWumpus:
+ GeminiCheck(15);
+ .@q = getq2(HurnscaldQuest_Gemini);
+ // TODO: Maybe exchange an Wumpus Egg for a Sunny Crystal or Mylarin Dust?
+ // Have a NPC do so only once, for the Savior set.
+ if (.@q == 0 || .@q == 2 || (.@q > 5 && !(.@q % 3)))
+ getitem WumpusEgg, 1;
+ else
+ getitem LightGreenDiamond, 1;
+ getexp 0, rand2(7500, 9999);
+ setq2 HurnscaldQuest_Gemini, .@q + 1;
+ @forced_sick$ = "";
+ end;
+
+OnRw:
+ getitem StrangeCoin, 1;
+ if (!GEMINI_WINNER)
+ GEMINI_WINNER = gettimetick(2);
+ end;
+
+OnExit:
+ .@p=getcharid(1);
+ partytimer(MAZE_MAP$, 10, "#GeminiFExit::OnRw", getcharid(1));
+ if ($GEMINI_WINNER$ == "") {
+ $GEMINI_WINNER$=strcharinfo(0);
+ channelmes("#world", $GEMINI_WINNER$+" is the first player to finish Gemini Sisters Quest!! GG, dude! %%N");
+ announce "All hail ##B"+$GEMINI_WINNER$+"##b, first to complete the ##3Gemini Sisters Quest!", bc_all|bc_npc;
+ getitem PrismGift, 1;
+ mesc l("CONGRATULATIONS! You are the first player to finish Gemini Sisters quest!!"), 2;
+ mesc l("You just gained a Prism Gift for your bravery!"), 2;
+ next;
+ }
+ sleep2(400);
+ warp "014-2-2", 35, 20;
+ warpparty("014-2-2", 35, 20, getcharid(1), MAZE_MAP$, true);
+ end;
+
+OnTouch:
+ if (instance_id() < 0 || getcharid(1) < 1) end;
+ GeminiCheck(15);
+ // Only the party leader go ahead
+ if (strcharinfo(0) != getpartyleader(getcharid(1))) {
+ mes l("Only %s has the key.", getpartyleader(getcharid(1)));
+ close;
+ }
+
+ mesc l("Are you sure you want to leave?"), 1;
+ mesc l("You, and everyone on the party, won't be able to return."), 1;
+ if (askyesno() == ASK_NO) close;
+ closeclientdialog;
+
+ // Create maze and populate (From 45x45 to 60x60)
+ CreateMaze(IOT_CHAR, MAZE_SIZE_M | MAZE_SIZE_G);
+ .@mx=getmapinfo(MAPINFO_SIZE_X, MAZE_MAP$)-20;
+ .@my=getmapinfo(MAPINFO_SIZE_Y, MAZE_MAP$)-20;
+ .@tl=(20-.@mx)*(20-.@my) * 3 / 10; // Total tiles + collision guess
+ .@tl=(.@tl / 10) + 1; // Monster density is a bit random
+
+ /* *** Copied from 006-5/groata.txt & 018-2-2/main.txt! *** */
+ .@mb[0] = MagicGoblin;
+ .@mb[1] = CaveMaggot;
+ array_push(.@mb, BronzeChest);
+ array_push(.@mb, SmallMagicBif);
+ array_push(.@mb, Bif);
+ array_push(.@mb, RobinBandit);
+ array_push(.@mb, SilverChest);
+ array_push(.@mb, DustGatling);
+ array_push(.@mb, MagicBif);
+ array_push(.@mb, DustRifle);
+ array_push(.@mb, DustRevolver);
+ array_push(.@mb, GoldenChest);
+ array_push(.@mb, GreatMoubooSlime);
+ array_push(.@mb, Piousse);
+ array_push(.@mb, ManaPiou);
+ array_push(.@mb, ForestPiou);
+ array_push(.@mb, HouseMaggot);
+ array_push(.@mb, LittleYellowSlime);
+ array_push(.@mb, MoubooSlime);
+ array_push(.@mb, SmallFrog);
+ array_push(.@mb, BigFrog);
+ array_push(.@mb, Lavern);
+ array_push(.@mb, LittleRedSlime);
+ array_push(.@mb, ChocolateSlime);
+ array_push(.@mb, Duck);
+ array_push(.@mb, Bat);
+ array_push(.@mb, CaveMaggot);
+ array_push(.@mb, ManaGhost);
+ array_push(.@mb, ManaBug);
+ array_push(.@mb, FireGoblin);
+ array_push(.@mb, ViciousSquirrel);
+ array_push(.@mb, RedScorpion);
+ array_push(.@mb, WhiteSlime);
+ array_push(.@mb, AzulSlime);
+ array_push(.@mb, DesertLogHead);
+ array_push(.@mb, RedSlime);
+ array_push(.@mb, DesertBandit);
+ array_push(.@mb, Sarracenus);
+ array_push(.@mb, IceMaggot);
+ array_push(.@mb, VampireBat);
+ array_push(.@mb, Bandit);
+ array_push(.@mb, Assassin);
+ array_push(.@mb, Skeleton);
+ array_push(.@mb, CaveSnake);
+ array_push(.@mb, GreenSlime);
+ array_push(.@mb, CopperSlime);
+ array_push(.@mb, YellowSlime);
+ array_push(.@mb, SantaSlime);
+ array_push(.@mb, LavaSlime);
+ array_push(.@mb, Bluepar);
+ array_push(.@mb, DeathCat);
+ array_push(.@mb, Moggun);
+ array_push(.@mb, RedMushroom);
+ array_push(.@mb, CandiedSlime);
+ array_push(.@mb, OldSnake);
+ array_push(.@mb, GrassSnake);
+ array_push(.@mb, Snake);
+ array_push(.@mb, BlackSlime);
+ array_push(.@mb, Pollet);
+ array_push(.@mb, PiouKnight);
+ array_push(.@mb, Shrewboo);
+ array_push(.@mb, Wolvern);
+ array_push(.@mb, FireSkull);
+ array_push(.@mb, DarkLizard);
+ array_push(.@mb, ArmoredSkeleton);
+ array_push(.@mb, BlackScorpion);
+ array_push(.@mb, ElectroWorm);
+ array_push(.@mb, EarthFairy);
+ array_push(.@mb, FireFairy);
+ array_push(.@mb, WaterFairy);
+ array_push(.@mb, WindFairy);
+ array_push(.@mb, PoisonFairy);
+ array_push(.@mb, MountainSnake);
+ array_push(.@mb, HoodedNinja);
+ array_push(.@mb, ForestMushroom);
+ array_push(.@mb, GoldenScorpion);
+ array_push(.@mb, FallenGuard2);
+ array_push(.@mb, WickedMushroom);
+ array_push(.@mb, Archant);
+ array_push(.@mb, Scar);
+ array_push(.@mb, Crafty);
+ array_push(.@mb, Forain);
+ array_push(.@mb, GreenDragon);
+ array_push(.@mb, Michel);
+ array_push(.@mb, Troll);
+ array_push(.@mb, EliteDuck);
+ array_push(.@mb, AzulSkullSlime);
+ array_push(.@mb, Moonshroom);
+ array_push(.@mb, RedSkullSlime);
+ array_push(.@mb, Terranite);
+ array_push(.@mb, JackO);
+ array_push(.@mb, BlackMamba);
+ array_push(.@mb, GreenSkullSlime);
+ array_push(.@mb, BloodyMouboo);
+ array_push(.@mb, GoboBear);
+ array_push(.@mb, TerraniteProtector);
+ array_push(.@mb, WhirlyBird);
+
+ /* Spawn them and make hostile */
+ freeloop(true);
+ for (.@i = 0; .@i < 1+(.@tl); .@i++) {
+ .@mid = any_of(.@mb);
+ .@m=areamonster(MAZE_MAP$, 20, 20, .@mx, .@my, strmobinfo(1, .@mid), .@mid, 1);
+ set_aggro(.@m);
+ }
+ freeloop(false);
+
+ // Spawn & Configure the boss monster
+ // Defeating the boss yields a bonus
+ .@mob=areamonster(MAZE_MAP$, 60, 60, .@mx-40, .@my-40, "Wumpus?", PanthomLord, 1, "#GeminiFExit::OnWumpus");
+ setunitdata(.@mob, UDT_MAXHP, 250000);
+ setunitdata(.@mob, UDT_HP, 250000);
+ setunitdata(.@mob, UDT_SPEED, 275);
+ setunitdata(.@mob, UDT_HIT, 3500);
+ setunitdata(.@mob, UDT_DMOTION, 50);
+
+ // NOTE: Once you exit, put the quest in cooldown for 4 hours as well.
+ .@mx = getmapinfo(MAPINFO_SIZE_X, MAZE_MAP$); .@my = getmapinfo(MAPINFO_SIZE_Y, MAZE_MAP$);
+ .@mob=monster(MAZE_MAP$, .@mx-25, .@my-25, "Exit", FortressGate, 1, "#GeminiFExit::OnExit");
+ setunitdata(.@mob, UDT_MAXHP, 50000);
+ setunitdata(.@mob, UDT_HP, 50000);
+
+ // Miscellaneous data
+ .@old$=getmap();
+ .@p=getcharid(1);
+ InitMaze(7200, false);
+ $@VALIA_STATUS[.@p]=16;
+ sleep2(500);
+ changeplayermusic "Arabesque.ogg";
+ dispbottom l("It was a trap! We must escape!");
+ $@VALIA_MAP$[.@p]=getmap();
+ partytimer(.@old$, 2000, "#GeminiFExit::OnSick", .@p);
+ sleep2(2000);
+ @forced_sick$ = getmap();
+ doevent "#DungeonCore::OnSick";
+ end;
+
+OnSick:
+ .@p=getcharid(1);
+ MAZE_MAP$ = $@VALIA_MAP$[.@p];
+ // Find random, warpable coordinates
+ .@e=0; .@x=0; .@y=0;
+ .@mx=40; .@my=40;
+ do {
+ .@x = rand2(20, .@mx);
+ .@y = rand2(20, .@my);
+ .@e += 1;
+ if (.@e > 30) {
+ consolebug("Too many failures at Maze \"%s\"! Trying anyway!", MAZE_MAP$);
+ break;
+ }
+ } while (!checknpccell(MAZE_MAP$, .@x, .@y, cell_chkpass));
+
+ warp MAZE_MAP$, .@x, .@y;
+ sleep2(500);
+ changeplayermusic "Arabesque.ogg";
+ dispbottom l("It was a trap! We must escape!");
+ sleep2(2000);
+ @forced_sick$ = getmap();
+ doevent "#DungeonCore::OnSick";
+ end;
+}
+
+034-4,146,83,0 script Chest#gemini NPC_CHEST,{
+ if (instance_id() < 0 || getcharid(1) < 1) end;
+ GeminiCheck(15);
+ // Already taken
+ if (@mystatus > 20) {
+ dispbottom l("I already took my share from this chest.");
+ end;
+ }
+ // One prize per person
+ inventoryplace Iten, 1;
+ @mystatus = 99;
+ // Non party leaders receive "less"
+ if (strcharinfo(0) != getpartyleader(getcharid(1))) {
+ Mobpt+=7500;
+ getexp 96000, 900;
+ dispbottom l("I found %s and %s!", "7,500 "+l("monster points"), "96,000 "+l("experience points"));
+ end;
+ }
+ // Party leaders receive "more"
+ .@q = getq(HurnscaldQuest_Gemini);
+ setq HurnscaldQuest_Gemini, .@q + 1;
+ //getitem RentCart, 1; // Not rented
+ switch (.@q) {
+ case 1:
+ getitem SarabArmlet, 1;
+ dispbottom l("I found %s!", l("a(n) ")+getitemlink(SarabArmlet));
+ break;
+ case 2:
+ getitem StrangeCoin, 150;
+ getitem MysteriousFruit, 1;
+ dispbottom l("I found %s and %s!", "150 "+getitemlink(StrangeCoin), ("a(n) ")+getitemlink(MysteriousFruit));
+ break;
+ default:
+ Mobpt+=7500;
+ getexp 96000, 900;
+ dispbottom l("I found %s and %s!", "7,500 "+l("monster points"), "96,000 "+l("experience points"));
+ end;
+ }
+ end;
+
+OnInit:
+ .distance=2;
+ end;
+}
+
+
diff --git a/npc/034-4/intro.txt b/npc/034-4/intro.txt
new file mode 100644
index 0000000..43692a3
--- /dev/null
+++ b/npc/034-4/intro.txt
@@ -0,0 +1,211 @@
+// TMW2 scripts.
+// Authors:
+// Jesusalva
+// Description:
+// Gemini Sisters Quest - Part A: Party Room
+
+034-4,43,52,0 script #GeminiNoBack NPC_HIDDEN,0,0,{
+ end;
+OnTouch:
+ if (instance_id() < 0 || getcharid(1) < 1) end;
+ GeminiCheck(8);
+ npctalkonce l("Oh noes ─ the door is sealed! We can only press forward and failure is final!");
+ end;
+}
+
+034-4,43,51,0 script #GeminiIntro NPC_HIDDEN,2,2,{
+ end;
+OnTouch:
+ if (instance_id() < 0 || getcharid(1) < 1) end;
+ GeminiCheck(8);
+ .@p=getcharid(1);
+ if (strcharinfo(0) != getpartyleader(.@p)) end;
+
+ if (!.state) {
+ .mp$ = getmap();
+ .pn$ = getpartyname(getcharid(1));
+ .pid = getcharid(1);
+ .state = true;
+ initnpctimer;
+ killmonsterall(.mp$); // Cancel everything done thus far, incl. showdown
+ }
+ end;
+
+OnTimer1000:
+ .luvia = monster(.mp$, 48, 45, "Luvia Gemini", Luvia, 1);
+ immortal(.luvia);
+ setunitdata(.luvia, UDT_MODE, MD_BOSS|MD_PLANT|MD_NOKNOCKBACK);
+ end;
+
+OnTimer2500:
+ unittalk(.luvia, "Well, well, well, look at what we have here!");
+ end;
+
+OnTimer6000:
+ unittalk(.luvia, sprintf("If it isn't the so-called \"%s\"!", .pn$));
+ end;
+
+OnTimer9500:
+ unittalk(.luvia, "I'm sure it was a long journey to reach here, and well, this IS an Inn.");
+ end;
+
+
+OnTimer13000:
+ unittalk(.luvia, "Where are my manners, of course I'll offer you room to sleep...");
+ end;
+
+
+OnTimer16500:
+ unittalk(.luvia, "...Yes, I'll put all of you to sleep... PERMANENTLY! Hahahaha!");
+ .@pi = getmapusers(.mp$) + 2;
+ areamonster(.mp$, 45, 40, 54, 45, strmobinfo(1, Scar), Scar, .@pi / 2);
+ setunitdata(.luvia, UDT_MODE, MD_BOSS|MD_PLANT|MD_NOKNOCKBACK|MD_CANMOVE);
+ unitwalk(.luvia, 51, 45);
+ end;
+
+OnTimer18000:
+ unitwalk(.luvia, 51, 38);
+ end;
+
+OnTimer20000:
+ .@pi = getmapusers(.mp$) + 1;
+ areamonster(.mp$, 45, 40, 54, 45, strmobinfo(1, Scar), Scar, .@pi);
+ unittalk(.luvia, "HAHAHahahaha!");
+ unitwalk(.luvia, 50, 34);
+ end;
+
+OnTimer24000:
+ .@pi = getmapusers(.mp$) + 1;
+ monster(.mp$, 37, 33, strmobinfo(1, Scar), Scar, .@pi);
+ monster(.mp$, 43, 52, strmobinfo(1, Scar), Scar, .@pi);
+ unitwalk(.luvia, 50, 29);
+ end;
+
+OnTimer28000:
+ .@pi = getmapusers(.mp$) + 1;
+ monster(.mp$, 50, 29, strmobinfo(1, Scar), Scar, .@pi);
+ unitwarp(.luvia, "034-4", 45, 45);
+ end;
+
+OnTimer25000:
+ unitkill(.luvia);
+ end;
+
+OnTimer50000:
+ .@pi = getmapusers(.mp$) + 1;
+ monster(.mp$, 50, 29, strmobinfo(1, Scar), Scar, .@pi);
+ monster(.mp$, 43, 52, strmobinfo(1, Scar), Scar, .@pi);
+ monster(.mp$, 37, 33, strmobinfo(1, Scar), Scar, .@pi * 3 / 2);
+ end;
+
+// 1 minute
+
+OnTimer110000:
+ monster(.mp$, 50, 29, strmobinfo(1, Scar), Scar, 1);
+ monster(.mp$, 43, 52, strmobinfo(1, Scar), Scar, 1);
+ monster(.mp$, 37, 33, strmobinfo(1, Scar), Scar, 1);
+ end;
+
+// 40 seconds
+
+OnTimer150000:
+ .@pi = getmapusers(.mp$) + 1;
+ monster(.mp$, 50, 29, strmobinfo(1, Scar), Scar, .@pi * 3 / 2);
+ monster(.mp$, 43, 52, strmobinfo(1, Scar), Scar, .@pi);
+ monster(.mp$, 37, 33, strmobinfo(1, Scar), Scar, .@pi);
+ monster(.mp$, 43, 52, strmobinfo(1, BlackMamba), BlackMamba, 1);
+ end;
+
+// 1 minute
+
+OnTimer210000:
+ monster(.mp$, 50, 29, strmobinfo(1, Scar), Scar, 1);
+ monster(.mp$, 43, 52, strmobinfo(1, Scar), Scar, 1);
+ monster(.mp$, 37, 33, strmobinfo(1, Scar), Scar, 1);
+ end;
+
+// 1 minute
+
+OnTimer270000:
+ .@pi = getmapusers(.mp$) + 1;
+ monster(.mp$, 50, 29, strmobinfo(1, Scar), Scar, .@pi * 3 / 2);
+ monster(.mp$, 43, 52, strmobinfo(1, Scar), Scar, .@pi);
+ monster(.mp$, 37, 33, strmobinfo(1, Scar), Scar, .@pi);
+ monster(.mp$, 43, 52, strmobinfo(1, Terranite), Terranite, 1+(.@pi/2));
+ end;
+
+// 1.5 minutes
+
+OnTimer360000:
+ .@pi = getmapusers(.mp$) + 1;
+ monster(.mp$, 50, 29, strmobinfo(1, Scar), Scar, 1+(.@pi/2));
+ monster(.mp$, 43, 52, strmobinfo(1, Scar), Scar, 1+(.@pi/2));
+ monster(.mp$, 37, 33, strmobinfo(1, Scar), Scar, 1+(.@pi/2));
+ monster(.mp$, 50, 29, strmobinfo(1, Terranite), Terranite, .@pi);
+ monster(.mp$, 43, 52, strmobinfo(1, Forain), Forain, .@pi);
+ monster(.mp$, 37, 33, strmobinfo(1, AzulSkullSlime), AzulSkullSlime, 1+(.@pi/2));
+ end;
+
+// 1 minute
+
+OnTimer420000:
+ monster(.mp$, 50, 29, strmobinfo(1, Scar), Scar, 1);
+ monster(.mp$, 43, 52, strmobinfo(1, Scar), Scar, 1);
+ monster(.mp$, 37, 33, strmobinfo(1, Scar), Scar, 1);
+ end;
+
+// 1 minute
+
+OnTimer480000:
+ .@pi = getmapusers(.mp$) + 1;
+ monster(.mp$, 50, 29, strmobinfo(1, Terranite), Terranite, .@pi);
+ monster(.mp$, 43, 52, strmobinfo(1, BlackSlimeMother), BlackSlimeMother, 1);
+ monster(.mp$, 37, 33, strmobinfo(1, BlackMamba), BlackMamba, .@pi + 4);
+ end;
+
+// +1 minute
+
+// Bypass, or it'll take... a while
+OnTimer40000:
+ if (!$@GM_OVERRIDE) end;
+OnTimer540000:
+ .@pi = getmapusers(.mp$) + 1;
+ monster(.mp$, 50, 29, strmobinfo(1, GoboBear), GoboBear, 1+(.@pi/2));
+ $@VALIA_STATUS[.pid] = 10;
+ stopnpctimer;
+ end;
+
+OnInit:
+OnInstanceInit:
+ .state = false;
+ .mp$ = "";
+ .pn$ = "";
+ .pid = 0;
+ .luvia = 0;
+ end;
+}
+
+
+034-4,50,29,0 script #GeminiPartB NPC_HIDDEN,0,0,{
+ end;
+OnTouch:
+ if (instance_id() < 0 || getcharid(1) < 1) end;
+ GeminiCheck(8);
+ .@p=getcharid(1);
+ if ($@VALIA_STATUS[.@p] < 10) {
+ dispbottom l("Uh? I can't pass. I wonder why, maybe I need to wait?");
+ end;
+ }
+ if (mobcount(getmap(), "all") > 0) {
+ dispbottom l("I should defeat all mobs before passing.");
+ end;
+ }
+ if (mobcount(getmap(), "all") <= 0 && $@VALIA_STATUS[.@p] == 10) {
+ $@VALIA_STATUS[.@p]=11;
+ }
+ if ($@VALIA_STATUS[.@p] >= 11) {
+ slide 33, 81;
+ }
+ end;
+}
+
diff --git a/npc/034-4/lobby.txt b/npc/034-4/lobby.txt
new file mode 100644
index 0000000..dd9a267
--- /dev/null
+++ b/npc/034-4/lobby.txt
@@ -0,0 +1,263 @@
+// TMW2 scripts.
+// Authors:
+// Jesusalva
+// Description:
+// Gemini Sisters Quest - Part C: Showdown
+
+034-4,98,22,0 script #GeminiPartD NPC_HIDDEN,0,0,{
+ end;
+OnTouch:
+ if (instance_id() < 0 || getcharid(1) < 1) end;
+ GeminiCheck(13);
+ .@p=getcharid(1);
+ if ($@VALIA_STATUS[.@p] < 14 || mobcount(getmap(), "#GeminiShowdown::OnABC")) {
+ dispbottom l("Luvia is too dangerous to be left alone.");
+ end;
+ }
+ if (mobcount(getmap(), "all") > 0) {
+ dispbottom l("I cannot leave until Luvia and her allies are dead.");
+ end;
+ }
+ if (mobcount(getmap(), "all") <= 0 && $@VALIA_STATUS[.@p] == 14) {
+ $@VALIA_STATUS[.@p]=15;
+ }
+ if ($@VALIA_STATUS[.@p] >= 15) {
+ if (!@v_fanfare)
+ specialeffect(FX_FANFARE, SELF, getcharid(3));
+ slide 143, 96;
+ }
+ end;
+}
+
+// 98 36 with radius 12?
+034-4,98,28,0 script #GeminiShowdown NPC_HIDDEN,2,1,{
+ end;
+OnTouch:
+ if (instance_id() < 0 || getcharid(1) < 1) end;
+ GeminiCheck(13);
+ .@p=getcharid(1);
+ if (strcharinfo(0) != getpartyleader(.@p)) end;
+
+ if (!.state) {
+ .mp$ = getmap();
+ .beats = 0;
+ .pid = getcharid(1);
+ .state = true;
+ initnpctimer;
+ killmonsterall(.mp$); // Cancel everything done thus far, incl. showdown
+ }
+ end;
+
+OnABC:
+ // Extra drop chance (20% chance)
+ getmapxy(.@m$, .@x, .@y, 0);
+ if (!rand2(5))
+ makeitem BronzeBossGift, 1, .@m$, .@x, .@y;
+ end;
+
+OnTimer1000:
+ .luvia = monster(.mp$, 98, 32, "Luvia Gemini", Luvia, 1);
+ immortal(.luvia);
+ setunitdata(.luvia, UDT_MODE, MD_BOSS|MD_PLANT|MD_NOKNOCKBACK);
+ end;
+
+OnTimer2500:
+ unittalk(.luvia, "Ara! Look at who is trying to sneak past me!");
+ end;
+
+OnTimer6000:
+ unittalk(.luvia, "How silly. I prepared this party for ya, you know.");
+ end;
+
+OnTimer9500:
+ unittalk(.luvia, "Isbamuth wants all of you dead ─ And I'll carry out his orders.");
+ end;
+
+OnTimer13000:
+ unittalk(.luvia, "Long live Isbamuth... And death to traitors! Now begone!!");
+ end;
+
+OnTimer15000:
+ // Create a new Luvia Gemini
+ unitwarp(.luvia, "034-4", 98, 32);
+ unitkill(.luvia);
+ .luvia = monster(.mp$, 98, 38, "Luvia Gemini", Luvia, 1, "#GeminiShowdown::OnABC");
+
+ // Grant her more HP if more players came to attack her
+ .@hp = getunitdata(.luvia, UDT_MAXHP) + (getmapusers(.mp$) * 12000);
+ setunitdata(.luvia, UDT_MAXHP, .@hp);
+ setunitdata(.luvia, UDT_HP, .@hp);
+
+ // Reconfigure the AI
+ .@opt=getunitdata(.luvia, UDT_MODE);
+ // Add knockback immunity
+ .@opt=.@opt|MD_NOKNOCKBACK;
+ // Make it more op
+ .@opt=.@opt|MD_DETECTOR;
+ .@opt=.@opt|MD_CASTSENSOR_CHASE;
+ .@opt=.@opt|MD_CASTSENSOR_IDLE;
+ .@opt=.@opt|MD_CHANGECHASE;
+ .@opt=.@opt|MD_CHANGETARGET_MELEE;
+ .@opt=.@opt|MD_CHANGETARGET_CHASE;
+ setunitdata(.luvia, UDT_MODE, .@opt);
+
+
+ // Prepare the party, lalala!
+ .@pi = getmapusers(.mp$) * 2 + 1;
+ monster(.mp$, 117, 51, strmobinfo(1, Scar), Scar, .@pi);
+ monster(.mp$, 83, 58, strmobinfo(1, Scar), Scar, .@pi);
+ monster(.mp$, 83, 51, strmobinfo(1, Scar), Scar, .@pi);
+ monster(.mp$, 114, 29, strmobinfo(1, Scar), Scar, .@pi);
+ monster(.mp$, 98, 22, strmobinfo(1, Scar), Scar, .@pi);
+ $@VALIA_STATUS[.pid] = 14;
+ end;
+
+// The fight loops from 20k (the restart point)
+// So this cycle happens every 10 seconds
+OnTimer60000:
+OnTimer45000:
+ consolewarn("Warning, fail-safe mechanism triggered to Luvia.");
+OnTimer30000:
+ if (mobcount(.mp$, "#GeminiShowdown::OnABC") < 1) {
+ stopnpctimer;
+ end;
+ }
+ .beats+=1;
+
+ /* Prepare some data */
+ .@hp = getunitdata(.luvia, UDT_HP) * 10 / getunitdata(.luvia, UDT_MAXHP);
+ .@pi = getmapusers(.mp$);
+ getmapxy(.@m$, .@x, .@y, UNITTYPE_MOB, .luvia);
+ .@c=getunits(BL_PC, .@pcs, MAX_CYCLE_PC, .@m$);
+ /*.@mvp=0;.@rnd=0;.@def=-1;
+ for (.@i = 0; .@i < .@c; .@i++) {
+ if (!.@rnd || !rand2(.@c))
+ .@rnd=.@pcs[.@i];
+ if (readbattleparam(.@pcs[.@i], UDT_DEF) > .@def) {
+ if (readparam(Hp, .@pcs[.@i]) < 1) continue;
+ .@mvp=.@pcs[.@i];
+ .@def=readbattleparam(.@pcs[.@i], UDT_DEF);
+ }
+ }*/
+
+ // Luvia's spell casting
+ // She casts every ~30 seconds
+ switch (.beats % 18) {
+ case 0:
+ case 6:
+ case 12:
+ unittalk(.luvia, "Hahahah, die, die!");
+ specialeffect(64, AREA, .luvia);
+ sleep(1000);
+ monster(.mp$, .@x, .@y, strmobinfo(1, Scar), Scar, .@pi + max(1, (11 - .@hp) / 10));
+ monster(.mp$, .@x, .@y, strmobinfo(1, MagicGoblin), MagicGoblin, .@pi + max(1, (11 - .@hp) / 10));
+ // Doors reinforcements
+ // As time passes, they get stronger
+ // But after 7 minutes, it resets
+ switch ((.beats / 6) % 14) {
+ case 0:
+ .@mob = Skeleton; break; // Shouldn't trigger
+ case 1:
+ .@mob = LavaSlime; break;
+ case 2:
+ .@mob = ArmoredSkeleton; break;
+ case 3:
+ .@mob = DustRifle; break;
+ case 4:
+ .@mob = DarkLizard; break;
+ case 5:
+ .@mob = HoodedNinja; break;
+ case 6:
+ .@mob = Archant; break;
+ case 7:
+ .@mob = Scar; break;
+ case 8:
+ .@mob = Terranite; break;
+ case 9:
+ .@mob = EliteDuck; break;
+ case 10:
+ .@mob = Troll; break;
+ case 11:
+ .@mob = YellowSkullSlime; break;
+ case 12:
+ .@mob = Michel; break;
+ case 13:
+ .@mob = JackO; break;
+ }
+
+ monster(.mp$, 114, 29, strmobinfo(1, .@mob), .@mob, 1);
+ // If you can't deal enough damage, less support comes
+ if (.@hp <= 7) // Up to 79% HP
+ monster(.mp$, 117, 51, strmobinfo(1, .@mob), .@mob, 1);
+ if (.@hp <= 6) // Up to 69% HP
+ monster(.mp$, 98, 22, strmobinfo(1, .@mob), .@mob, 1);
+ if (.@hp <= 4) // Up to 39% HP
+ monster(.mp$, 83, 58, strmobinfo(1, .@mob), .@mob, 1);
+ if (.@hp <= 3) // Up to 29% HP
+ monster(.mp$, 83, 51, strmobinfo(1, .@mob), .@mob, 1);
+ break;
+ case 3:
+ case 9:
+ case 15:
+ specialeffect(60, AREA, .luvia);
+ sleep(500);
+ .@r = (10-.@hp) / 5 + rand2(4); // From 0 to 5
+ // Blind has extra chance until her HP falls below 60%
+ // Curse won't happen if her HP is equal or above 60%
+ // Once her HP falls below 10%, she no longer silences
+ // And her poison is strengthened.
+ switch (.@r) {
+ case 1:
+ unittalk(.luvia, "The dead are ##Bsilent##b, just like you!");
+ .@sc = SC_SILENCE;
+ break;
+ case 2:
+ unittalk(.luvia, "I am your doom, and ##Bpoison##b is my tool!");
+ .@sc = (.@hp < 1 ? SC_DPOISON : SC_POISON);
+ break;
+ case 3:
+ unittalk(.luvia, "You shall ##Bbleed##b, and cease!");
+ .@sc = SC_BLOODING;
+ break;
+ case 4:
+ unittalk(.luvia, "You dare to underestimate me?! ##BCurse##b you!");
+ .@sc = SC_CURSE;
+ break;
+ default:
+ unittalk(.luvia, "You won't see what killed you when ##Bblind##b!");
+ .@sc = SC_BLIND;
+ break;
+ }
+ areasc(9, 45000, .@sc, BL_PC|BL_HOM|BL_MER, 1, "filter_always", .luvia, 95000);
+ .@dmg=100 + (max(1, (11 - .@hp) / 10) * 40);
+ areaharm(.luvia, 9, .@dmg, HARM_MAGI, any(Ele_Water,Ele_Fire,Ele_Wind,Ele_Earth), "filter_always", BL_PC|BL_MER|BL_HOM);
+ break;
+ default:
+ specialeffect(60, AREA, .luvia);
+ unittalk(.luvia, any("I am getting tired of you!",
+ "That's all you can muster?",
+ "Long live Isbamuth!",
+ "Hahahahah!",
+ "Incompetent! Simply incompetent!",
+ "You shall not resist!",
+ "I'm not afraid of you!"));
+ sleep(500);
+ .@dmg=40 + (max(1, (11 - .@hp) / 10) * 20);
+ areaharm(.luvia, 9, .@dmg, HARM_MAGI, any(Ele_Water,Ele_Fire,Ele_Wind,Ele_Earth), "filter_always", BL_PC|BL_MER|BL_HOM);
+ break;
+ }
+
+ // And we're done! Wait 10 seconds before next casting
+ setnpctimer 20000;
+ end;
+
+OnInit:
+OnInstanceInit:
+ .state = false;
+ .mp$ = "";
+ .pid = 0;
+ .luvia = 0;
+ .beats = 0;
+ end;
+}
+
diff --git a/npc/034-4/storage.txt b/npc/034-4/storage.txt
new file mode 100644
index 0000000..893971f
--- /dev/null
+++ b/npc/034-4/storage.txt
@@ -0,0 +1,186 @@
+// TMW2 scripts.
+// Authors:
+// Jesusalva
+// Description:
+// Gemini Sisters Quest - Part B: Storage Room
+
+034-4,45,78,0 script #GeminiPartC NPC_HIDDEN,0,0,{
+ end;
+OnTouch:
+ if (instance_id() < 0 || getcharid(1) < 1) end;
+ GeminiCheck(11);
+ .@p=getcharid(1);
+ if ($@VALIA_STATUS[.@p] < 12) {
+ dispbottom l("Uh? I can't pass. I wonder why, maybe I need to wait?");
+ end;
+ }
+ if (mobcount(getmap(), "all") > 0) {
+ dispbottom l("I should defeat all mobs before passing.");
+ end;
+ }
+ if (mobcount(getmap(), "all") <= 0 && $@VALIA_STATUS[.@p] == 12) {
+ $@VALIA_STATUS[.@p]=13;
+ }
+ if ($@VALIA_STATUS[.@p] >= 13) {
+ slide 83, 58;
+ }
+ end;
+}
+
+034-4,33,77,0 script #GeminiStorei NPC_HIDDEN,2,2,{
+function storageutil;
+ end;
+OnTouch:
+ if (instance_id() < 0 || getcharid(1) < 1) end;
+ GeminiCheck(11);
+ .@p=getcharid(1);
+ if (strcharinfo(0) != getpartyleader(.@p)) end;
+
+ if (!.state) {
+ .mp$ = getmap();
+ .pn$ = getpartyname(getcharid(1));
+ .pid = getcharid(1);
+ .state = true;
+ /* We now must calculate amount of waves */
+ /* It is a hack for now, though */
+ .mto = 5 + (BaseLevel / 30) + getmapusers(.mp$);
+ initnpctimer;
+ killmonsterall(.mp$); // Cancel everything done thus far, incl. showdown
+ }
+ end;
+
+OnTimer1000:
+ .luvia = monster(.mp$, 37, 76, "Luvia Gemini", Luvia, 1);
+ immortal(.luvia);
+ setunitdata(.luvia, UDT_MODE, MD_BOSS|MD_PLANT|MD_NOKNOCKBACK);
+ end;
+
+OnTimer2500:
+ unittalk(.luvia, "So you aren't made of sugar!");
+ end;
+
+OnTimer6000:
+ unittalk(.luvia, "I was worried you would all have melted on the lobby!");
+ end;
+
+OnTimer9500:
+ unittalk(.luvia, "Hahaha, but this is just the beginning of your journey...");
+ end;
+
+
+OnTimer13000:
+ unittalk(.luvia, "I am Luvia Gemini, and this is my trial for you!");
+ end;
+
+
+OnTimer16500:
+ unittalk(.luvia, sprintf("Show me of what you are made of, %s!", .pn$));
+ .@pi = getmapusers(.mp$) + 2;
+ monster(.mp$, 44, 78, strmobinfo(1, Scar), Scar, .@pi);
+ end;
+
+OnTimer19000:
+ unittalk(.luvia, "HAHAHahahaha!");
+ end;
+
+OnTimer20000:
+ unitwarp(.luvia, "034-4", 45, 45);
+ end;
+
+OnTimer21000:
+ unitkill(.luvia);
+ end;
+
+OnTimer30000:
+ storageutil();
+ .sto += 1;
+ end;
+
+OnTimer45000:
+ if (.sto < .mto)
+ setnpctimer 22000;
+ monster(.mp$, 44, 78, strmobinfo(1, BlackMamba), BlackMamba, 1);
+ end;
+
+OnTimer60000:
+ .@pi = getmapusers(.mp$) + 1;
+ monster(.mp$, 44, 78, strmobinfo(1, GoboBear), GoboBear, .@pi);
+ $@VALIA_STATUS[.pid] = 12;
+ stopnpctimer;
+ end;
+
+
+function storageutil {
+ // Decide if we'll spawn or add items. Previous failures are NOT considerated.
+ .@r=rand2(10000)+(.sto * 100);
+
+ // Super rare drop?! (~1.5%)
+ if (.@r < 120 || .@r > 10000) {
+ makeitem(any(DeathPotion, PoisonAmmoBox, AncientBlueprint, ThornAmmoBox, MercBoxD, ScholarshipBadge, DarkDesertMushroom), 1, .mp$, rand2(30, 35), rand2(83, 86));
+ }
+
+ // Super strong monster?! (4%)
+ if ((.@r > 6000 && .@r < 6400) || .sto == 15 || .sto == 17 || .sto >= 20) {
+ .@mob=any(WanderingShadow, SeaSlimeMother, NightDragon, GiantMutatedBat, Reaper, Mandragora);
+ monster(.mp$, 44, 78, strmobinfo(1, .@mob), .@mob, 1);
+ // Warn players?
+ }
+
+ // Compulsory monster spawn
+ switch (.sto) {
+ case 0:
+ .@mob = ArmoredSkeleton; break;
+ case 1:
+ .@mob = DustRifle; break;
+ case 2:
+ .@mob = HoodedNinja; break;
+ case 3:
+ .@mob = WickedMushroom; break;
+ case 4:
+ .@mob = any(Archant, Scar); break;
+ case 5:
+ .@mob = Scar; break;
+ case 6:
+ .@mob = AzulSkullSlime; break;
+ case 7:
+ .@mob = Forain; break;
+ case 8:
+ .@mob = GreenDragon; break;
+ case 9:
+ .@mob = Michel; break;
+ case 10:
+ .@mob = EliteDuck; break;
+ case 11:
+ .@mob = Terranite; break;
+ case 12:
+ .@mob = JackO; break;
+ case 13:
+ .@mob = BloodyMouboo; break;
+ default:
+ .@mob = GoboBear;
+ }
+ monster(.mp$, 44, 78, strmobinfo(1, .@mob), .@mob, 1+getmapusers(.mp$));
+
+ // Compulsory item drop
+ // If it falls on a collision, the item won't be created at all
+ freeloop(true);
+ for (.@i=0; .@i <= ((.sto/2)+getmapusers(.mp$)); .@i++) {
+ makeitem(any(Wurtzite, ShadowHerb, AlizarinHerb, DiamondPowder, RubyPowder, EmeraldPowder, SapphirePowder, TopazPowder, AmethystPowder, CopperOre, IronOre, Coal, LeadOre, Lifestone, ScorpionClaw, WhiteFur, SquirrelPelt, TinOre, PileOfAsh, EmptyBottle, FluoPowder, TerraniteOre, SulfurPowder, LeatherPatch, LazuriteShard, Root, ReedBundle, GambogeHerb, MauveHerb, CobaltHerb, MaggotSlime, BugLeg, RawLog, BanditHood, BatWing, IronPowder, ArtichokeHerb, LeftCraftyWing, RightCraftyWing, Coral, BlueCoral, Pearl, Moss, RattoTail, RattoTeeth, Knife, SharpKnife, StrangeCoin, PurificationPotion, IcedBottle, Grenade, SmokeGrenade, TreasureMap, AgiPotionA, VitPotionA, IntPotionA, DexPotionA, LukPotionA, EmptyBox, HastePotion, StrengthPotion, Croconut, ChocolateBar, ChocolateBiscuit, PinkieLeg, Potatoz, Coffee, SnakeEgg, Plushroom, Chagashroom, Honey, MoubooSteak, Milk, Orange, CherryCake, Piberries, Aquada, Cheese, Bread, Acorn, Manana), 1, .mp$, rand2(30, 71), rand2(44, 87));
+ }
+ freeloop(false);
+ return;
+}
+
+OnInit:
+OnInstanceInit:
+ .state = false;
+ .mp$ = "";
+ .pn$ = "";
+ .pid = 0;
+ .luvia = 0;
+ .sto = 0;
+ .mto = 0;
+ end;
+}
+
+