summaryrefslogtreecommitdiff
path: root/npc/soren
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/soren
downloadserverdata-a7c45a192268da2601cef47a4cdba987ae2327ca.tar.gz
serverdata-a7c45a192268da2601cef47a4cdba987ae2327ca.tar.bz2
serverdata-a7c45a192268da2601cef47a4cdba987ae2327ca.tar.xz
serverdata-a7c45a192268da2601cef47a4cdba987ae2327ca.zip
Initial commit (Moubootaur Legends fork)
Diffstat (limited to 'npc/soren')
-rw-r--r--npc/soren/_import.txt5
-rw-r--r--npc/soren/_mobs.txt8
-rw-r--r--npc/soren/main.txt531
-rw-r--r--npc/soren/mapflags.txt1
4 files changed, 545 insertions, 0 deletions
diff --git a/npc/soren/_import.txt b/npc/soren/_import.txt
new file mode 100644
index 0000000..7721a7c
--- /dev/null
+++ b/npc/soren/_import.txt
@@ -0,0 +1,5 @@
+// Map soren: Soren's Village
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/soren/_mobs.txt",
+"npc/soren/main.txt",
+"npc/soren/mapflags.txt",
diff --git a/npc/soren/_mobs.txt b/npc/soren/_mobs.txt
new file mode 100644
index 0000000..79e4d5d
--- /dev/null
+++ b/npc/soren/_mobs.txt
@@ -0,0 +1,8 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map soren: Soren's Village mobs
+soren,122,104,102,81 monster Moonshroom 1069,14,60000,60000
+soren,102,84,102,81 monster Forain 1061,5,60000,60000
+soren,103,91,64,40 monster 4144's Tortuga 1004,1,6600000,600000
+soren,105,87,30,23 monster Snake 1122,4,15000,15000
+soren,109,57,12,5 monster Guardians Of Soren 1130,4,5000,10000
+soren,110,97,103,81 monster Angry Red Scorpion 1130,18,5000,10000
diff --git a/npc/soren/main.txt b/npc/soren/main.txt
new file mode 100644
index 0000000..845c662
--- /dev/null
+++ b/npc/soren/main.txt
@@ -0,0 +1,531 @@
+// 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(<variable>, "<npc name>")
+// This way, each summon point would have .caster and .lifetime
+// getvariableofpc(<variable>, <account id>{, <default value>})
+// 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
+
diff --git a/npc/soren/mapflags.txt b/npc/soren/mapflags.txt
new file mode 100644
index 0000000..f38cb43
--- /dev/null
+++ b/npc/soren/mapflags.txt
@@ -0,0 +1 @@
+soren mapflag zone MMO