summaryrefslogtreecommitdiff
path: root/npc
diff options
context:
space:
mode:
authorJesusalva Jesusalva <jesusalva@themanaworld.org>2023-07-17 01:48:54 +0000
committerJesusalva Jesusalva <jesusalva@themanaworld.org>2023-07-17 01:48:54 +0000
commit5b0a9c8ffdbac30c4ff3981167c7206ca75425c7 (patch)
tree5a82418c9f0b725fed8d5e5cf0c1fa1a6fe861bc /npc
parentcac5c770e7bbb169e9516909dfc0d44afceb1446 (diff)
downloadserverdata-5b0a9c8ffdbac30c4ff3981167c7206ca75425c7.tar.gz
serverdata-5b0a9c8ffdbac30c4ff3981167c7206ca75425c7.tar.bz2
serverdata-5b0a9c8ffdbac30c4ff3981167c7206ca75425c7.tar.xz
serverdata-5b0a9c8ffdbac30c4ff3981167c7206ca75425c7.zip
Jesusalva/00610
Diffstat (limited to 'npc')
-rw-r--r--npc/001-3/_import.txt1
-rw-r--r--npc/001-3/_warps.txt (renamed from npc/003-6/_import.txt)6
-rw-r--r--npc/003-6/_warps.txt4
-rw-r--r--npc/003-6/cyndala.txt249
-rw-r--r--npc/003-6/tamiloc.txt83
-rw-r--r--npc/006-10/_config.txt128
-rw-r--r--npc/006-10/_import.txt1
-rw-r--r--npc/006-10/_mobs.txt2
-rw-r--r--npc/006-10/logic.txt485
-rw-r--r--npc/017-3/gambler.txt165
-rw-r--r--npc/026-2/_mobs.txt11
-rw-r--r--npc/026-2/_warps.txt2
-rw-r--r--npc/033-1/_import.txt2
-rw-r--r--npc/033-1/misc.txt111
-rw-r--r--npc/033-1/nico.txt (renamed from npc/017-3/nico.txt)174
-rw-r--r--npc/033-1/trainer.txt (renamed from npc/020-1/trainer.txt)69
-rw-r--r--npc/033-2/magic.txt5
-rw-r--r--npc/config/events.txt105
-rw-r--r--npc/config/traps.txt4
-rw-r--r--npc/craft/price.txt2
-rw-r--r--npc/functions/main.txt28
-rw-r--r--npc/functions/mobpoint.txt2
-rw-r--r--npc/items/grenade.txt8
23 files changed, 988 insertions, 659 deletions
diff --git a/npc/001-3/_import.txt b/npc/001-3/_import.txt
index 2118c10..38587a4 100644
--- a/npc/001-3/_import.txt
+++ b/npc/001-3/_import.txt
@@ -1,3 +1,4 @@
// Map 001-3: Dark Forest
// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/001-3/_warps.txt",
"npc/001-3/ctrl.txt",
diff --git a/npc/003-6/_import.txt b/npc/001-3/_warps.txt
index 95f4096..99c9589 100644
--- a/npc/003-6/_import.txt
+++ b/npc/001-3/_warps.txt
@@ -1,5 +1,3 @@
-// Map 003-6: Laundry
// This file is generated automatically. All manually added changes will be removed when running the Converter.
-"npc/003-6/_warps.txt",
-"npc/003-6/cyndala.txt",
-"npc/003-6/tamiloc.txt",
+// Map 001-3: Dark Forest warps
+001-3,164,32,0 warp #001-3_164_32 0,0,033-1,72,191
diff --git a/npc/003-6/_warps.txt b/npc/003-6/_warps.txt
deleted file mode 100644
index d540cc5..0000000
--- a/npc/003-6/_warps.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-// This file is generated automatically. All manually added changes will be removed when running the Converter.
-// Map 003-6: Laundry warps
-003-6,40,39,0 warp #003-6_40_39 0,0,003-1,112,148
-003-6,32,39,0 warp #003-6_32_39 0,0,003-1,106,148
diff --git a/npc/003-6/cyndala.txt b/npc/003-6/cyndala.txt
deleted file mode 100644
index 9dd039f..0000000
--- a/npc/003-6/cyndala.txt
+++ /dev/null
@@ -1,249 +0,0 @@
-// TMW2 Script.
-// Author:
-// Saulc
-// Jesusalva
-// Dye Quest added by:
-// Povo
-// Description:
-// Will be with dye functions for a while... May be wrong. Only Card2 is available per hercules rules
-
-// Original code from evol
-// Authors:
-// Reid
-
-003-6,33,30,0 script Cyndala NPC_FEMALE_ARGAES,{
- function explain_dyes;
- function item_is_bleachable;
- function remove_cards_from_item;
- function give_yellow_dye;
- function deny_yellow_dye;
- function craft_yellow_dye;
-
- mesn;
- mesq l("Hello, darling!");
- mes "";
-
- do
- {
- .@q = getq(TulimsharQuest_Cyndala);
- select
- l("Excuse me."),
- l("Could you bleach my equipment?"),
- l("What can you say about dyes?"),
- rif(.@q > 0, l("I would like to order some dye.")),
- rif(is_staff(), "Technical problem, gimme info about an item.");
-
- switch (@menu) {
- case 2:
- remove_cards_from_item();
- break;
- case 3:
- explain_dyes();
- break;
- case 4:
- craft_yellow_dye();
- break;
- case 5:
- .@item = requestitemindex();
- mes "Item index selected: " + str(.@item);
- mes "slots=" + str(MAX_SLOTS);
- for (.@i = 0; .@i < MAX_SLOTS; .@i++)
- {
- mes "slot " + str(.@i) + " = " + str(getcardbyindex(.@item, .@i));
- }
- mes str(@inventorylist_card1[.@item]);
- mes str(YellowDye);
- mes "item options:";
- for (.@i = 0; .@i < 5; .@i ++)
- {
- mes sprintf("%d: Option: %d, Value: %d", .@i, getitemoptionidbyindex(.@item, .@i),
- getitemoptionvaluebyindex(.@item, .@i));
- }
- mes "Note named items (Card1 254 and 255) have Card3 and Card4 reserved";
- break;
- default:
- mes "";
- mesn;
- mesq l("I wish you a good time in town.");
- next;
- break;
- }
-
- } while (@menu != 1);
-
-
- closeclientdialog;
- goodbye;
- close;
-
-/////////////////////////////////////////////////////////////////////////////////
-function explain_dyes {
- .@q = getq(TulimsharQuest_Cyndala);
- speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
- l("Dyes are a special kind of ink to make certain objects fancier."),
- l("Once you have the appropriate colorant for the item, ##bdrag the colorant##b to the material."),
- l("Example:"),
- l("Drag and drop a %s in a %s, and you will obtain a %s.", getitemlink(YellowDye),
- getitemlink(ArtisTankTop), getitemlink(ArtisTankTop, YellowDye)),
- l("Dye cards are not the only thing which exist, but they are the coolest!");
- if (.@q < 1) {
- speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
- l("By the way, did you know that the official color of Tulimshar is yellow?"),
- l("In fact, the Tulimshar Noble District is world-renowned for crafting high-quality yellow garments!"),
- l("Normally I would offer to make you some %s, but economic problems in Halinarzo have caused a shortage of supplies...",
- getitemlink(YellowDye));
- if (BaseLevel > 20 &&
- .@q < 1) {
- speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
- l("Wait a minute! I have an idea!"),
- l("You look like you have enough experience to know your way around town..."),
- l("If you can manage to gather the supplies I need, I can surely craft some %s for you!",
- getitemlink(YellowDye)),
- l("Of course, I do charge a nominal fee of for the service. %s GP to be exact.", fnum(50)),
- l("In addition to my fee, I will also need the following items:");
- mesq l("%d/%d %s", countitem(BottleOfSewerWater), 1, getitemlink(BottleOfSewerWater));
- mesq l("%d/%d %s", countitem(PiouFeathers), 50, getitemlink(PiouFeathers));
- next;
- mesq l("I am sure that an adventurer like you can gather everything in no time at all!");
- setq TulimsharQuest_Cyndala, 1;
- }
- }
-}
-
-function item_is_bleachable
-{
- .@item_index = getarg(0);
- if (.@item_index < 0)
- return false;
-
- // Collect the item ID
- delinventorylist();
- getinventorylist();
- .@x=@inventorylist_id[.@id];
-
- // Debug info
- if (is_staff())
- mesf "Item Index %d (%s) - ID %d", .@item_index,
- getitemlink(@inventorylist_id[.@item_index]),
- @inventorylist_id[.@item_index];
-
- // No duplicates
- if (countitem(.@x) > 1) {
- mesc l("You are carrying duplicates of the same item. Sorry, but I have no idea which one you want to tweak."), 1;
- return false;
- }
-
- // Must have a card, d'oh
- if (@inventorylist_card1[.@item_index] == 0)
- return false;
-
- return true;
-}
-
-function remove_cards_from_item
-{
- .@item_index = -1;
-
- speech S_FIRST_BLANK_LINE,
- l("What item would you like to bleach?");
-
- narrator S_FIRST_BLANK_LINE | S_LAST_NEXT,
- l("You can drag and drop an item to the NPC window or select an item through your inventory.");
-
- .@item_index = requestitemindex();
- if (!item_is_bleachable(.@item_index)) {
- speech S_LAST_NEXT,
- l("You should know this, an item like this can't be bleached.");
-
- return;
- }
- .@item_id = @inventorylist_id[.@item_index];
-
- speech S_LAST_NEXT,
- l("Your mind is set? You will probably lose all the dyes and/or cards during on the item during this process. You're bleaching a %s by the way.", getitemlink(.@item_id));
-
- switch (askyesno()) {
- case ASK_YES:
- speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
- l("Ok, let me see..."),
- l("...");
-
- // FIXME: Register this on picklog
- if (rand2(1, 800) > readparam2(bLuk)) {
- failedremovecardsindex .@item_index, 1;
- logmes("Deleted Cards from item: "+.@item_id);
- } else {
- successremovecardsindex(.@item_index);
- logmes("Removed Cards from item: "+.@item_id);
- }
-
- // First option slot of weapon: Raises STR in 5
- // setequipoption(EQI_HAND_R, 1, VAR_STRAMOUNT, 5);
- // This is an option :3
-
- speech S_LAST_NEXT | S_NO_NPC_NAME,
- l("..."),
- l("Here it is, clean like a whistle!");
- break;
- default:
- speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
- l("Is it truly a hard choice to make?");
- break;
- }
- return;
-}
-
-function give_yellow_dye {
- .@q = getq(TulimsharQuest_Cyndala);
-
- inventoryplace YellowDye, 1, EmptyBottle, 1;
- Zeny = Zeny - 50;
- delitem BottleOfSewerWater, 1;
- delitem PiouFeathers, 50;
-
- mesn;
- mesq l("Here you are, you won't find a dye more yellow than this!");
- getitem(YellowDye, 1);
- getitem(EmptyBottle, 1);
-
- if (.@q == 1) {
- setq TulimsharQuest_Cyndala, 2;
- getexp 80, 0;
- }
- return;
-}
-
-function deny_yellow_dye {
- mesn;
- mesc l("I am sorry, but it does not look like you have everything. You will need to bring:");
- next;
- mesc l("%d/%d %s", countitem(BottleOfSewerWater), 1, getitemlink(BottleOfSewerWater));
- mesc l("%d/%d %s", countitem(PiouFeathers), 50, getitemlink(PiouFeathers));
- mesc l("%s/%s GP", fnum(Zeny), fnum(50));
- next;
- return;
-}
-
-function craft_yellow_dye {
- if (countitem(BottleOfSewerWater) < 1 ||
- countitem(PiouFeathers) < 50 ||
- Zeny < 50)
- deny_yellow_dye();
- else
- give_yellow_dye();
- return;
-}
-
-OnInit:
- .@npcId = getnpcid(.name$);
- setunitdata(.@npcId, UDT_HEADTOP, NPCEyesD);
- setunitdata(.@npcId, UDT_HEADMIDDLE, ValentineDress); //TODO
- setunitdata(.@npcId, UDT_HEADBOTTOM, CottonTrousers);
- setunitdata(.@npcId, UDT_WEAPON, DeepBlackBoots); // Boots
- setunitdata(.@npcId, UDT_HAIRSTYLE, 16);
- setunitdata(.@npcId, UDT_HAIRCOLOR, 11);
-
- .sex = G_FEMALE;
- .distance = 5;
- end;
-}
diff --git a/npc/003-6/tamiloc.txt b/npc/003-6/tamiloc.txt
deleted file mode 100644
index 6f88398..0000000
--- a/npc/003-6/tamiloc.txt
+++ /dev/null
@@ -1,83 +0,0 @@
-// TMW2 scripts.
-// Authors:
-// Saulc
-// Jesusalva
-// Reid
-// Travolta
-// Description:
-// Tamiloc is the barber.
-
-003-6,46,30,0 script Tamiloc NPC_ELVEN_FEMALE_ARMOR_SHOP,{
- function setRace {
- clear;
- setnpcdialogtitle l("%s - Modify Race", .name$);
- mes l("Race") + ": " + get_race();
- next;
- mes l("Please select the desired race.");
- select
- l("Kaizei Human"),
- l("Argaes Human"),
- l("Tonori Human"),
- l("Elf"),
- l("Orc"),
- l("Raijin"),
- l("Tritan"),
- l("Ukar"),
- l("Redy"),
- l("Savior");
- switch (@menu)
- {
- default:
- jobchange max(0, @menu-1);
- }
- return;
- }
-
-
- mesn;
- mesq l("Hi! Do you want a hair cut?");
-
- do
- {
- select
- l("What is my current hairstyle and hair color?"),
- l("I'd like to get a different style."),
- l("Can you do something with my color?"),
- rif(is_gm() || REBIRTH >= 5, l("I want to change my Race!")),
- l("I'm fine for now, thank you.");
-
- switch (@menu)
- {
- case 1:
- BarberSayStyle 3;
- break;
- case 2:
- BarberChangeStyle;
- speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
- l("Enjoy your new style.");
- l("Anything else?");
- break;
- case 3:
- BarberChangeColor;
- speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
- l("I hope you like this color.");
- l("Anything else?");
- break;
- case 4:
- setRace;
- break;
- case 5:
- speech S_FIRST_BLANK_LINE | S_LAST_NEXT,
- l("Feel free to come visit me another time.");
-
- goodbye;
- }
- } while (1);
- close;
-
-
-OnInit:
- .sex = G_FEMALE;
- .distance = 5;
- end;
-}
diff --git a/npc/006-10/_config.txt b/npc/006-10/_config.txt
new file mode 100644
index 0000000..333acee
--- /dev/null
+++ b/npc/006-10/_config.txt
@@ -0,0 +1,128 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 006-10: Fefe's Crypt conf
+
+006-10,68,50,0 script #006-10_68_50 NPC_TRAP,0,0,{
+ mesn strcharinfo(0);
+ mesq l("Something seems off with that!");
+ close;
+OnTouch:
+OnTouchNPC:
+ IronTrap(80, 15, 1);
+ end;
+OnTimer15000:
+ stopnpctimer; setnpctimer 0; setnpcdisplay "#006-10_68_50", NPC_TRAP; end;
+}
+
+006-10,70,51,0 script #006-10_70_51 NPC_TRAP,0,0,{
+ mesn strcharinfo(0);
+ mesq l("Something seems off with that!");
+ close;
+OnTouch:
+OnTouchNPC:
+ IronTrap(80, 15, 1);
+ end;
+OnTimer15000:
+ stopnpctimer; setnpctimer 0; setnpcdisplay "#006-10_70_51", NPC_TRAP; end;
+}
+
+006-10,72,49,0 script #006-10_72_49 NPC_TRAP,0,0,{
+ mesn strcharinfo(0);
+ mesq l("Something seems off with that!");
+ close;
+OnTouch:
+OnTouchNPC:
+ IronTrap(80, 15, 1);
+ end;
+OnTimer15000:
+ stopnpctimer; setnpctimer 0; setnpcdisplay "#006-10_72_49", NPC_TRAP; end;
+}
+
+006-10,73,52,0 script #006-10_73_52 NPC_TRAP,0,0,{
+ mesn strcharinfo(0);
+ mesq l("Something seems off with that!");
+ close;
+OnTouch:
+OnTouchNPC:
+ IronTrap(80, 15, 1);
+ end;
+OnTimer15000:
+ stopnpctimer; setnpctimer 0; setnpcdisplay "#006-10_73_52", NPC_TRAP; end;
+}
+
+006-10,75,49,0 script #006-10_75_49 NPC_TRAP,0,0,{
+ mesn strcharinfo(0);
+ mesq l("Something seems off with that!");
+ close;
+OnTouch:
+OnTouchNPC:
+ IronTrap(80, 15, 1);
+ end;
+OnTimer15000:
+ stopnpctimer; setnpctimer 0; setnpcdisplay "#006-10_75_49", NPC_TRAP; end;
+}
+
+006-10,50,27,0 script #006-10_50_27 NPC_TRAP,0,0,{
+ mesn strcharinfo(0);
+ mesq l("Something seems off with that!");
+ close;
+OnTouch:
+ IronTrap(30, 15, 1);
+ end;
+OnTimer15000:
+ stopnpctimer; setnpctimer 0; setnpcdisplay "#006-10_50_27", NPC_TRAP; end;
+}
+
+006-10,50,28,0 script #006-10_50_28 NPC_TRAP,0,0,{
+ mesn strcharinfo(0);
+ mesq l("Something seems off with that!");
+ close;
+OnTouch:
+ IronTrap(30, 15, 1);
+ end;
+OnTimer15000:
+ stopnpctimer; setnpctimer 0; setnpcdisplay "#006-10_50_28", NPC_TRAP; end;
+}
+
+006-10,52,27,0 script #006-10_52_27 NPC_TRAP,0,0,{
+ mesn strcharinfo(0);
+ mesq l("Something seems off with that!");
+ close;
+OnTouch:
+ IronTrap(30, 15, 1);
+ end;
+OnTimer15000:
+ stopnpctimer; setnpctimer 0; setnpcdisplay "#006-10_52_27", NPC_TRAP; end;
+}
+
+006-10,52,28,0 script #006-10_52_28 NPC_TRAP,0,0,{
+ mesn strcharinfo(0);
+ mesq l("Something seems off with that!");
+ close;
+OnTouch:
+ IronTrap(30, 15, 1);
+ end;
+OnTimer15000:
+ stopnpctimer; setnpctimer 0; setnpcdisplay "#006-10_52_28", NPC_TRAP; end;
+}
+
+006-10,54,27,0 script #006-10_54_27 NPC_TRAP,0,0,{
+ mesn strcharinfo(0);
+ mesq l("Something seems off with that!");
+ close;
+OnTouch:
+ IronTrap(30, 15, 1);
+ end;
+OnTimer15000:
+ stopnpctimer; setnpctimer 0; setnpcdisplay "#006-10_54_27", NPC_TRAP; end;
+}
+
+006-10,54,28,0 script #006-10_54_28 NPC_TRAP,0,0,{
+ mesn strcharinfo(0);
+ mesq l("Something seems off with that!");
+ close;
+OnTouch:
+ IronTrap(30, 15, 1);
+ end;
+OnTimer15000:
+ stopnpctimer; setnpctimer 0; setnpcdisplay "#006-10_54_28", NPC_TRAP; end;
+}
diff --git a/npc/006-10/_import.txt b/npc/006-10/_import.txt
index 4c0c28f..72ca523 100644
--- a/npc/006-10/_import.txt
+++ b/npc/006-10/_import.txt
@@ -1,5 +1,6 @@
// Map 006-10: Fefe's Crypt
// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/006-10/_config.txt",
"npc/006-10/_mobs.txt",
"npc/006-10/_warps.txt",
"npc/006-10/logic.txt",
diff --git a/npc/006-10/_mobs.txt b/npc/006-10/_mobs.txt
index 16b27b7..9575b1a 100644
--- a/npc/006-10/_mobs.txt
+++ b/npc/006-10/_mobs.txt
@@ -1,3 +1,5 @@
// This file is generated automatically. All manually added changes will be removed when running the Converter.
// Map 006-10: Fefe's Crypt mobs
006-10,54,44,24,24 monster Vampire Bat 1063,18,300000,30000
+006-10,73,28,3,1 monster Vicious Chest 1148,1,10000,10000
+006-10,71,26,3,1 monster Evil Chest 1149,1,10000,10000
diff --git a/npc/006-10/logic.txt b/npc/006-10/logic.txt
index 601563d..f662b2d 100644
--- a/npc/006-10/logic.txt
+++ b/npc/006-10/logic.txt
@@ -2,129 +2,430 @@
// Author:
// Jesusalva
// Description:
-// Crazyfefe's Shrine
+// Crazyfefe's Shrine (remastered)
006-10 mapflag zone MMO
+026-2 mapflag zone MMO
// We need to refactor this warp system, replace NPC_HIDDEN, and include the boss
+006-10,54,58,0 script Blanc NPC_BLANC,{
+ if (getunittype(.blanc) >= 0) end;
+ mesc l("Isn't that Blanc? Should we attempt to capture him?");
+ mesc l("Advised: 6+ players"), 1;
+ mesc l("Advised: 1+ mage, 1+ tanker, 2+ healers"), 1;
+ mesc l("No Time Limit"), 1;
+ mesc l("Enter/Leave after start: %s", b(l("YES"))), 1;
+ next;
+ select
+ l("Not yet."),
+ l("Bring it on!"),
+ rif(is_gm(), l("Bring me, my worst nightmare."));
+ mes "";
+ if (@menu == 1) {
+ closeclientdialog;
+ close;
+ }
+ if (@menu == 2)
+ .hard = false;
+ else
+ .hard = true;
-006-10,46,45,0 script #00610WA NPC_HIDDEN,0,3,{
- end;
-OnTouch:
- slide 53, 46; end;
-}
+ // Create the boss
+ .blanc = monster("006-10", 54, 61, "Blanc Halifax", Blanc, 1);
+ .@mlt = (.hard ? 15 : 10);
-006-10,58,45,0 script #00610WB NPC_HIDDEN,0,3,{
- end;
-OnTouch:
- slide 54, 38; end;
-}
+ // Basic attributes
+ .maxhp = (750000 * .@mlt / 10); // 750k ~ 1250k
+ setunitdata(.blanc, UDT_MAXHP, .maxhp);
+ setunitdata(.blanc, UDT_HP, .maxhp);
+ setunitdata(.blanc, UDT_ATKRANGE, (.hard ? 7 : 6));
-006-10,49,38,0 script #00610WC NPC_HIDDEN,0,3,{
- end;
-OnTouch:
- slide 42, 40; end;
-}
+ // Reconfigure the AI
+ .@opt=getunitdata(.blanc, UDT_MODE);
+ // Disable looting
+ if (.@opt & MD_LOOTER)
+ .@opt=.@opt^MD_LOOTER;
+ // Add knockback immunity
+ .@opt=.@opt|MD_NOKNOCKBACK;
+ // Mark as boss
+ .@opt=.@opt|MD_BOSS;
+ // Mark as aggressive
+ .@opt=.@opt|MD_AGGRESSIVE;
+ .@opt=.@opt|MD_ANGRY;
+ // 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(.blanc, UDT_MODE, .@opt);
-006-10,55,37,0 script #00610WD NPC_HIDDEN,0,3,{
- end;
-OnTouch:
- slide 45, 46; end;
-}
+ // Nerf the damage, but never miss a hit
+ setunitdata(.blanc, UDT_ATKMIN, 60 * .@mlt / 10); // 60~90 dmg
+ setunitdata(.blanc, UDT_ATKMAX, 60 * .@mlt / 10);
+ setunitdata(.blanc, UDT_ADELAY, 2220 / .@mlt * 10); // 2220 or 1480ms
+ setunitdata(.blanc, UDT_HIT, 2400);
-006-10,44,39,0 script #00610WE NPC_HIDDEN,0,3,{
- end;
-OnTouch:
- slide 50, 38; end;
-}
+ // Boosting the defense is not necessary
+ // It nerfs weapons to 40% (bows to 20%)
+ // Then it resists 50% of Neutral element.
+ // Note it is strong against Water (25% dmg)
+ // And weak against Fire (snow) and Wind (100% dmg)
+ // Otherwise, behave as Ghost element
-006-10,38,39,0 script #00610WF NPC_HIDDEN,0,3,{
- end;
-OnTouch:
- slide 35, 35; end;
-}
+ // Make Blanc damn hard to damage until his reinforcements appear
+ sc_start SC_PRESTIGE, 5000, 120000, 10000, SCFLAG_NOAVOID|SCFLAG_FIXEDTICK|SCFLAG_FIXEDRATE, .blanc;
+ // TODO: Defense and attributes are wrong?
+ disablenpc .name$;
+ initnpctimer;
+ closeclientdialog;
+ close;
-006-10,30,34,0 script #00610WG NPC_HIDDEN,0,3,{
+OnRw:
+ dispbottom l("Mission accomplished. Well played!");
+ // Mark as "done" on Mirror Lake Quest Tracker
+ ##01_CRQUEST = ##01_CRQUEST | MLP_CR_DEBUT;
+ specialeffect(FX_FANFARE, AREA, getcharid(3));
+ sleep2(15000);
+ $@EVENT_08 = PORTHOS_UNUSED;
+ warp("033-1", 72, 191);
end;
-OnTouch:
- slide 33, 25; end;
-}
-006-10,38,24,0 script #00610WH NPC_HIDDEN,0,3,{
+// Fail-safe Mechanism (will never happen)
+OnTimer60000:
+ consolebug("Warning! final fail-safe mechanism triggered to Blanc.");
+ initnpctimer;
end;
-OnTouch:
- slide 45, 22; end;
-}
+OnTimer25000:
+OnTimer15000:
+ consolewarn("Warning, fail-safe mechanism triggered to Blanc.");
+// This is the boss' core
+OnTimer5000:
+ /* Regeneration & Defeat Loop */
+ .@end = false;
+ // FIXME: Don't check the WHOLE map, just the current platform?
+ if (!getmapusers("006-10")) {
+ .@hp = getunitdata(.blanc, UDT_HP);
+ .@mh = .maxhp;
+ .@hp = max(.@mh, .@hp + (.@mh / 500)); // Regenerates 0.2% HP
+ // Fully healed, players lost
+ if (.@hp >= .@mh)
+ .@end = true;
+ // Regeneration
+ setunitdata(.blanc, UDT_HP, .@hp);
+ }
-006-10,50,21,0 script #00610WI NPC_HIDDEN,0,3,{
- end;
-OnTouch:
- slide 57, 29; end;
-}
+ /* Maybe the fight is over */
+ if (!mobcount("006-10", "all") || getunittype(.blanc) < 0) {
+ $@EVENT_08 = PORTHOS_BUSY;
+ maptimer2("006-10", 10, "Blanc::OnRw");
+ }
+ if (!mobcount("006-10", "all") || getunittype(.blanc) < 0 || .@end) {
+ killmonsterall("006-10");
+ enablenpc .name$;
+ kamibroadcast("The battle is over!", "Blanc Showdown");
+ .beats = 0;
+ stopnpctimer;
+ end;
+ }
-006-10,52,28,0 script #00610WJ NPC_HIDDEN,0,3,{
- end;
-OnTouch:
- slide 45, 31; end;
-}
+ /* Move platform according to HP threshold */
+ .@hp = getunitdata(.blanc, UDT_HP) * 10 / .maxhp;
+ .@state = 9 - limit(0, .@hp, 9); // The platform ID they should be on
+ debugmes "HP %d / %d (%d%%) (S %d/%d) [%03d@%d]", getunitdata(.blanc, UDT_HP), .maxhp, .@hp, .@state, .state, .beats, .blanc;
+ if (.state != .@state) {
+ unittalk(.blanc, "Damn, you guys are tough! I must fall back!");
+ sleep(100);
+ unitwarp(.blanc, "006-10", $@BLANC_X[.@state], $@BLANC_Y[.@state]);
+ sleep(100);
+ unittalk(.blanc, "Outta the way!");
+ .state = .@state;
+ }
-006-10,40,30,0 script #00610WK NPC_HIDDEN,0,3,{
- end;
-OnTouch:
- slide 37, 25; end;
-}
+ /* Prepare some combat data */
+ // TODO: Maybe not universal? Maybe we should impose a range?
+ getmapxy(.@m$, .@x, .@y, UNITTYPE_MOB, .blanc);
+ .@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);
+ }
+ }
+ .beats += 1;
-006-10,32,24,0 script #00610WL NPC_HIDDEN,0,3,{
- end;
-OnTouch:
- slide 31, 46; end;
-}
+ /* Everyone is dead, get rid of their corpses */
+ if (!.@mvp || !.@rnd) {
+ mapwarp("006-10", "033-1", 72, 191);
+ initnpctimer;
+ end;
+ }
-006-10,36,45,0 script #00610WM NPC_HIDDEN,0,3,{
- end;
-OnTouch:
- slide 41, 46; end;
-}
+ //debugmes "----------- Skill Loop, beat is %d", .beats % 18;
+ /* Decide the skill to use based on ~5s beats over 3 minutes */
+ switch (.beats % 18) {
+ // (1/6) Summon Reinforcements (every 60s)
+ case 1:
+ case 7:
+ case 13:
+ unittalk(.blanc, "Come forth, ##BHalifax's Crew##b, do not let these fools arrest your captain!");
+ specialeffect(FX_MGWARP, AREA, .blanc); // Maybe 65 would also work
+ sleep(1000);
+ // Default amount: Half players + Half magnifying HP
+ .@max = (getmapusers("006-10")/2) + (max(1, (11 - .@hp) / 10)/2);
+ // Keep boundaries: Never less than 1, never more than 10
+ .@max = limit(1, .@max, 10);
+ for (.@i=0; .@i < .@max; .@i++) {
+ .@mob = any(Thug, Grenadier, Swashbuckler);
+ monster(.@m$, .@x, .@y, strmobinfo(1, .@mob), .@mob, 1);
+ }
+ break;
+ // (2/6) Tanker (~30s)
+ case 0:
+ case 4:
+ case 6:
+ case 10:
+ case 12:
+ case 16:
+ specialeffect(FX_ATTACK, AREA, .blanc);
+ sleep(1000);
+ if (.@hp < 3) {
+ // Third Attack Pattern: Judgment
+ unittalk(.blanc, sprintf("%s cannot stop me! ##BElectric Judgment##b!", strcharinfo(0, "cursed player", .@mvp)));
+ .@PW=240; .@SPW=60; .@RG=3;
+ } else if (.@hp < 7) {
+ // Second Attack Pattern: Holy Light
+ unittalk(.blanc, sprintf("%s, I'll show you no mercy! ##BThunder Bolt##b!", strcharinfo(0, "cursed player", .@mvp)));
+ .@PW=125; .@SPW=25; .@RG=1;
+ } else {
+ // First Attack Pattern: Napalm Beat
+ unittalk(.blanc, sprintf("This battle is over, %s! ##BThunder Neddle##b!", strcharinfo(0, "cursed player", .@mvp)));
+ .@PW=35; .@SPW=5; .@RG=2;
+ }
+ .@mtk = calcdmg(.blanc, .@mvp, HARM_MAGI);
+ .@dmg = .@mtk * .@PW / 100;
+ .@dsb = .@mtk * .@SPW / 100;
+ sleep(1000);
+ specialeffect(FX_LIGHTNING, AREA, .@mvp);
+ areaharm(.@mvp, .@RG, .@dsb, HARM_MAGI, Ele_Wind, "filter_always", BL_PC|BL_MER|BL_HOM);
+ harm(.@mvp, .@dmg, HARM_MAGI, Ele_Holy);
+ break;
+ // (3/6) Random Target (~60s)
+ case 2:
+ case 8:
+ case 14:
+ specialeffect(FX_SMOKE, AREA, .blanc);
+ sleep(1000);
+ .@time=rand2(18000, 36000) + 10000 - (.@hp * 1000);
+ // Switch between curse and disable
+ if (any(true,false)) {
+ unittalk(.blanc, sprintf("I hereby ##Bcurse##b you, %s!", strcharinfo(0, "cursed player", .@rnd)));
+ sc_start(SC_CURSE, .@time, 1, 10000, SCFLAG_FIXEDRATE, .@rnd);
+ } else {
+ unittalk(.blanc, sprintf("I shall ##Bdisable##b you, %s!", strcharinfo(0, "cursed player", .@rnd)));
+ sc_start(SC_BLIND, .@time / 2, 1, 10000, SCFLAG_FIXEDRATE, .@rnd);
+ sc_start(SC_SILENCE, .@time / 2, 1, 10000, SCFLAG_FIXEDRATE, .@rnd);
+ }
+ // Second pattern: Bleeding ON
+ if (.@hp < 7) {
+ sc_start(SC_BLOODING, 10000, 1, 9000-(.@hp*1000), SCFLAG_FIXEDRATE, .@rnd);
+ }
+ specialeffect(FX_LIGHTNING, AREA, .@rnd);
+ break;
+ // (4/6) Traps (~60s)
+ case 3:
+ case 9:
+ case 15:
+ // Determine if there'll be 4 or 2 AoE explosions
+ .@extra = (.@hp < 5 || .hard);
+ // Coordinates are between origin and Blanc
+ // ID 3 and ID 6 were disabled - the platforms are small
+ .@mx=$@BLANC_X[.@state];
+ .@my=$@BLANC_Y[.@state];
+ .@x1=rand2(.@mx, .@x); .@x2=rand2(.@mx, .@x);
+ .@y1=rand2(.@my, .@y); .@y2=rand2(.@my, .@y);
+ // TODO: Maybe replace Dummy/EnergyBall with an invisible monster?
+ .@t1=monster("006-10", .@x1, .@y1, "", EnergyBall, 1);
+ .@t2=monster("006-10", .@x2, .@y2, "", EnergyBall, 1);
+ specialeffect(67, AREA, .@t1);
+ specialeffect(67, AREA, .@t2);
+ immortal(.@t1); immortal(.@t2);
+ if (.@extra) {
+ .@x4=rand2(.@mx, .@x); .@x5=rand2(.@mx, .@x);
+ .@y4=rand2(.@my, .@y); .@y5=rand2(.@my, .@y);
+ .@t4=monster("006-10", .@x1, .@y1, "", EnergyBall, 1);
+ .@t5=monster("006-10", .@x2, .@y2, "", EnergyBall, 1);
+ specialeffect(67, AREA, .@t4);
+ specialeffect(67, AREA, .@t5);
+ immortal(.@t4); immortal(.@t5);
+ }
+ sleep(1500);
+ // This is just a prop
+ specialeffect(FX_LIGHTNING, AREA, .@t1);
+ specialeffect(FX_LIGHTNING, AREA, .@t2);
+ if (.@extra) {
+ specialeffect(FX_LIGHTNING, AREA, .@t4);
+ specialeffect(FX_LIGHTNING, AREA, .@t5);
+ }
+ sleep(500);
+ specialeffect(FX_CRITICAL, AREA, .@t1);
+ specialeffect(FX_CRITICAL, AREA, .@t2);
+ if (.@extra) {
+ specialeffect(FX_CRITICAL, AREA, .@t4);
+ specialeffect(FX_CRITICAL, AREA, .@t5);
+ }
+ areaharm(.@t1, 1, 450, HARM_MISC, Ele_Neutral, "filter_always", BL_PC|BL_MER|BL_HOM);
+ areaharm(.@t2, 1, 450, HARM_MISC, Ele_Neutral, "filter_always", BL_PC|BL_MER|BL_HOM);
+ if (.@extra) {
+ areaharm(.@t4, 1, 450, HARM_MISC, Ele_Neutral, "filter_always", BL_PC|BL_MER|BL_HOM);
+ areaharm(.@t5, 1, 450, HARM_MISC, Ele_Neutral, "filter_always", BL_PC|BL_MER|BL_HOM);
+ }
+ sleep(1000);
+ // FIXME: M+ fails to remove them, need @refresh (maybe @refreshall?)
+ // NOTE: The effect Nº 67 (halo circle) is also not cleaned by M+
+ unitkill(.@t1); unitkill(.@t2);
+ if (.@extra) {
+ unitkill(.@t4); unitkill(.@t5);
+ }
+ break;
+ // (5/6) Weak AOE (~60s)
+ case 5:
+ case 11:
+ case 17:
+ specialeffect(60, AREA, .blanc);
+ sleep(500);
+ switch (rand2(3)) {
+ case 1:
+ unittalk(.blanc, "Cease! I shall ##Bpoison##b all of you!");
+ .@sc = (.@hp < 1 ? SC_DPOISON : SC_POISON);
+ break;
+ case 2:
+ unittalk(.blanc, "Cease! I shall ##Bhurt##b all of you!");
+ .@sc = SC_BLOODING;
+ break;
+ case 3:
+ unittalk(.blanc, "Cease! I shall ##Bsilence##b all of you!");
+ .@sc = SC_SILENCE;
+ break;
+ default:
+ unittalk(.blanc, "Cease! I shall ##Bcripple##b all of you!");
+ .@sc = SC_BLIND;
+ break;
+ }
+ areasc((.hard ? 7 : 5), 30000, .@sc, BL_PC|BL_HOM|BL_MER, 1, "filter_always", .blanc, 95000);
+ areaharm(.blanc, (.hard ? 7 : 5), 100, HARM_MAGI, Ele_Wind, "filter_always", BL_PC|BL_MER|BL_HOM);
+ // Forces everyone to sit, for cosmetic effect
+ areasc(18, 500, SC_BANANA_BOMB_SITDOWN_POSTDELAY, BL_PC|BL_HOM|BL_MER, 1, "filter_always", .blanc);
+ break;
+ }
+ // Strong AOE: Every 3 minutes (case = 0)
+ // Stalls all other skills for a while
+ if (.beats % 18 == 0) {
+ specialeffect(66, AREA, .blanc);
+ unittalk(.blanc, "I am Blanc, Halifax's captain!");
+ sleep((.hard ? 1000 : 1500));
+ specialeffect(700, AREA, .blanc);
+ unittalk(.blanc, "I'll never be caught by your ilk alive!");
+ sleep((.hard ? 1000 : 1500));
+ specialeffect(700, AREA, .blanc);
+ if (.@hp < 3) {
+ unittalk(.blanc, "Perish! ##BRage of Hungry Thunder##b!");
+ .@dmg=rand2(900, 1100);
+ areasc3((.hard ? 5 : 4), 11000, SC_STOMACHACHE, BL_PC|BL_HOM|BL_MER, (.hard ? 20 : 15), "filter_always", .blanc, 6000);
+ areasc(6, 10000, SC_BLIND, BL_PC|BL_HOM|BL_MER, 1, "filter_always", .blanc, 2000);
+ } else if (.@hp < 7) {
+ unittalk(.blanc, "Perish! ##BVoracious Thunder Storm##b!");
+ .@dmg=rand2(650, 900);
+ areasc3((.hard ? 4 : 3), 11000, SC_STOMACHACHE, BL_PC|BL_HOM|BL_MER, (.hard ? 15 : 10), "filter_always", .blanc, 4500);
+ } else {
+ unittalk(.blanc, "Perish! ##BEletric Needles##b!");
+ .@dmg=rand2(400, 650);
+ }
+ /* Three blocks */
+ specialeffect(66, AREA, .blanc);
+ areaharm(.blanc, (.hard ? 7 : 5), .@dmg, HARM_MAGI, Ele_Fire, "filter_always", BL_PC|BL_MER|BL_HOM);
+ sleep(500);
+ specialeffect(66, AREA, .blanc);
+ areaharm(.blanc, (.hard ? 15 : 10), .@dmg, HARM_MAGI, Ele_Holy, "filter_always", BL_PC|BL_MER|BL_HOM);
+ sleep(500);
+ specialeffect(66, AREA, .blanc);
+ specialeffect(FX_LIGHTNING, AREA, .blanc);
+ areaharm(.blanc, (.hard ? 24 : 18), .@dmg, HARM_MAGI, Ele_Wind, "filter_always", BL_PC|BL_MER|BL_HOM);
+ areasc((.hard ? 24 : 18), .@dmg*rand2(50, 100), SC_FROSTMISTY, BL_PC|BL_HOM|BL_MER, 1, "filter_always", .blanc, 10001 - (.@hp * 1000)); // SC_FROSTMISTY - General crippling
+ }
-006-10,30,45,0 script #00610WN NPC_HIDDEN,0,3,{
- end;
-OnTouch:
- slide 57, 46; end;
-}
-// --------------------------------------------------
-006-10,52,45,0 script #00610WO NPC_HIDDEN,0,3,{
+ initnpctimer;
end;
-OnTouch:
- slide 45, 46; end;
-}
-006-10,40,45,0 script #00610WP NPC_HIDDEN,0,3,{
- end;
-OnTouch:
- slide 35, 35; end;
-}
+OnInit:
+ .distance = 4;
+ .beats = 0; // Skill cooldown timer
+ .hard = 0; // Hard mode (for GMs)
+ .blanc = 0; // Boss GID
+ .state = 0; // Current platform ID
+ .maxhp = 0; // Blanc's max HP (getunitdata(.blanc, UDT_MAXHP) is broken)
-006-10,36,34,0 script #00610WQ NPC_HIDDEN,0,3,{
- end;
-OnTouch:
- slide 40, 40; end;
-}
+ // TODO: In general, we have no idea of platforms size
+ setarray $@BLANC_X, 53, 72, 71, 72, 52, 36, 34, 35, 35, 52;
+ setarray $@BLANC_Y, 63, 67, 53, 30, 30, 27, 48, 36, 63, 36;
-006-10,58,28,0 script #00610WR NPC_HIDDEN,0,3,{
+ // .@index = miller_rand(.@state, getcharid(0), 10);
end;
-OnTouch:
- slide 49, 22; end;
}
-006-10,46,30,0 script #00610WS NPC_HIDDEN,0,3,{
+// Below be the warp system. Rightmost forwards, leftmost rewinds.
+
+006-10,51,64,0 script #00610XX NPC_HIDDEN,1,0,{
end;
OnTouch:
- slide 53, 29; end;
+ // Now... WTF are we on miller rand?
+ if (!@miller_fix) {
+ for (.@i=0;.@i<10;.@i++) {
+ if (miller_rand(.@i, getcharid(0), 10) == 0) {
+ @miller_fix = .@i;
+ break;
+ }
+ }
+ }
+ // Set "@state" properly
+ @state = @miller_fix;
+ end;
}
-
-006-10,44,21,0 script #00610WT NPC_HIDDEN,0,3,{
+006-10,57,61,0 script #00610WA+ NPC_FANCY_CIRCLE,0,0,{
end;
OnTouch:
- slide 37, 25; end;
+ // All portals are the same, anyway
+ if (compare(strnpcinfo(2), "+"))
+ @state = ((@state+1) % 10); // Technically, the loop is not needed
+ else
+ @state = ((@state-1) % 10); // Technically, this loop is not needed
+ .@index = miller_rand(@state, getcharid(0), 10);
+ slide $@BLANC_X[.@index], $@BLANC_Y[.@index];
+ end;
}
+// NOTE: Vampire Bats are aggressive, they're tasked in disposing non-fighters
+006-10,49,60,0 duplicate(#00610WA+) #00610WA- NPC_FANCY_CIRCLE,0,0
+006-10,75,65,0 duplicate(#00610WA+) #00610WB+ NPC_FANCY_CIRCLE,0,0
+006-10,68,64,0 duplicate(#00610WA+) #00610WB- NPC_FANCY_CIRCLE,0,0
+006-10,75,50,0 duplicate(#00610WA+) #00610WC+ NPC_FANCY_CIRCLE,0,0
+006-10,67,49,0 duplicate(#00610WA+) #00610WC- NPC_FANCY_CIRCLE,0,0
+006-10,76,27,0 duplicate(#00610WA+) #00610WD+ NPC_FANCY_CIRCLE,0,0
+006-10,68,26,0 duplicate(#00610WA+) #00610WD- NPC_FANCY_CIRCLE,0,0
+006-10,56,27,0 duplicate(#00610WA+) #00610WE+ NPC_FANCY_CIRCLE,0,0
+006-10,48,26,0 duplicate(#00610WA+) #00610WE- NPC_FANCY_CIRCLE,0,0
+006-10,40,24,0 duplicate(#00610WA+) #00610WF+ NPC_FANCY_CIRCLE,0,0
+006-10,32,24,0 duplicate(#00610WA+) #00610WF- NPC_FANCY_CIRCLE,0,0
+006-10,37,51,0 duplicate(#00610WA+) #00610WG+ NPC_FANCY_CIRCLE,0,0
+006-10,30,45,0 duplicate(#00610WA+) #00610WG- NPC_FANCY_CIRCLE,0,0
+006-10,41,33,0 duplicate(#00610WA+) #00610WH+ NPC_FANCY_CIRCLE,0,0
+006-10,30,33,0 duplicate(#00610WA+) #00610WH- NPC_FANCY_CIRCLE,0,0
+006-10,44,63,0 duplicate(#00610WA+) #00610WI+ NPC_FANCY_CIRCLE,0,0
+006-10,35,57,0 duplicate(#00610WA+) #00610WI- NPC_FANCY_CIRCLE,0,0
+006-10,55,37,0 duplicate(#00610WA+) #00610WJ+ NPC_FANCY_CIRCLE,0,0
+006-10,49,37,0 duplicate(#00610WA+) #00610WJ- NPC_FANCY_CIRCLE,0,0
diff --git a/npc/017-3/gambler.txt b/npc/017-3/gambler.txt
deleted file mode 100644
index 7d5c848..0000000
--- a/npc/017-3/gambler.txt
+++ /dev/null
@@ -1,165 +0,0 @@
-// TMW2 Scripts
-// Author:
-// Jesusalva
-// Description:
-// Gambler: Can you remember the sequence?
-
-017-3,23,38,0 script Gambler#017-3 NPC_PLAYER,{
- function colorname {
- switch (getarg(0)) {
- case 1:
- return "Green"; break;
- case 2:
- return "Blue"; break;
- case 3:
- return "Red"; break;
- case 4:
- return "Yellow"; break;
- case 5:
- return "Exit"; break;
- default:
- return l("ERROR: %d", getarg(0));
- }
- }
-
- goto L_Menu;
-
-L_Menu:
- showavatar NPC_FLOPPED_NOBLEMAN;
- mesn;
- mesc l("Gambling is for the weak, I offer you a true game!");
- mesc l("You need %d %s. I'll start showing you sequences of colors.", .price, getitemlink(CasinoCoins));
- mesc l("The farther you go on the sequence, the better the payout!");
- next;
- menu
- rif(countitem(CasinoCoins) >= .price, l("Let's play!")), L_Start,
- l("Information"), L_Info,
- l("Leave"), -;
- close;
-
-L_Info:
- mes "";
- mesc l("Rules:");
- mesc l("A color sequence will be displayed on the avatar frame.");
- mesc l("You must then repeat the sequence at the board which will show.");
- next;
- mesc l("Prizes:");
- mesc l("You'll get %d GP every time you finish the sequence.", .prize);
- next;
- mesc l("Winning Strike Prizes:");
- mesc l("Every %d sequences, you'll get a %s!", 10, getitemlink(StrangeCoin));
- mesc l("If you get %d sequence, you'll get a %s!", 30, getitemlink(BronzeGift));
- mesc l("If you get %d sequence, you'll get a %s!", 50, getitemlink(SilverGift));
- //mesc l("If you get %d sequence, you'll get a %s!", 50, getitemlink(GoldenGift));
- next;
- goto L_Menu;
-
-
-L_Start:
- showavatar AVATAR_SEQBOARD;
- mesc l("Pay attention to the sequence!");
- next;
- delitem CasinoCoins, .price;
- deletearray(@sequence);
- @streak=0;
-
-L_Sequence:
- // Configure
- setnpcdialogtitle l("Memorize the sequence!");
- array_push(@sequence, 1+rand2(4));
- sleep2(1000);
-
- // Display
- freeloop(true);
- for (.@i=0;.@i < getarraysize(@sequence);.@i++) {
- showavatar 1200+@sequence[.@i];
- sleep2(1200-(@streak*20));
- }
- freeloop(false);
-
- // Request
- setnpcdialogtitle l("What was the sequence?");
- showavatar AVATAR_SEQBOARD;
- sleep2(500);
-
- for (.@i=0;.@i < getarraysize(@sequence);.@i++) {
- setskin "seqboard";
- select
- l("Green"),
- l("Blue"),
- l("Red"),
- l("Yellow"),
- l("Exit");
- .@ans=@menu;
- setskin "";
- mes "";
- mes l("%s", colorname(.@ans));
- //next;
- setnpcdialogtitle strnpcinfo(1);
-
- // Exit
- if (.@ans == 5)
- goto L_Close;
-
- // Wrong reply
- if (.@ans != @sequence[.@i])
- goto L_Wrong;
- // Correct!
- }
- mes "";
- showavatar AVATAR_SEQBOARD_WELL;
-
- // Seems like everything is/was correct
- mesn;
- mesq l("Congratulations! Everything was correct!");
- Zeny+=.prize;
- @streak+=1;
-
- // Winning Streak
- if (@streak % 10 == 0)
- getitem StrangeCoin, 1;
- if (@streak == 30)
- getitem BronzeGift, 1;
- if (@streak == 50)
- getitem SilverGift, 1;
- mesc l("Your current win streak is @@!", @streak);
- next;
- // Game over
- if (@streak == 50)
- goto L_Close;
- // Otherwise, go ahead
- mesn;
- mesc l("Continue?"), 1;
- next;
- if (askyesno() == ASK_YES)
- goto L_Sequence;
- goto L_Close;
-
-L_Wrong:
- showavatar AVATAR_SEQBOARD_FAIL;
- mesn;
- mesq l("Oh no... That is wrong! %%3");
- next;
- mesn;
- mesq l("Better luck next time!");
- close;
-
-L_Close:
- mesn;
- mesq l("Thanks for playing!");
- close;
-
-OnInit:
- .@npcId = getnpcid(.name$);
- setunitdata(.@npcId, UDT_HEADTOP, TopHat);
- setunitdata(.@npcId, UDT_HEADMIDDLE, CreasedShirt);
- setunitdata(.@npcId, UDT_HEADBOTTOM, JeansShorts);
-
- .sex = G_MALE;
- .distance = 4;
- .price = 5;
- .prize = 50;
- npcsit;
- end;
-}
-
diff --git a/npc/026-2/_mobs.txt b/npc/026-2/_mobs.txt
index a5b827f..bcaa771 100644
--- a/npc/026-2/_mobs.txt
+++ b/npc/026-2/_mobs.txt
@@ -1,7 +1,8 @@
// This file is generated automatically. All manually added changes will be removed when running the Converter.
// Map 026-2: Count's Fortress mobs
-026-2,61,35,39,17 monster Piou Knight 1434,8,300000,30000
-026-2,62,81,39,17 monster Grenadier 1444,18,300000,30000
-026-2,70,57,39,17 monster Swashbuckler 1443,18,300000,30000
-026-2,57,59,39,27 monster Thug 1442,18,300000,30000
-026-2,61,57,20,45 monster Revolver Shooter 1208,18,300000,30000
+026-2,61,35,39,17 monster Piou Knight 1434,6,300000,30000
+026-2,62,81,39,17 monster Grenadier 1444,10,300000,30000
+026-2,70,57,39,17 monster Swashbuckler 1443,10,300000,30000
+026-2,57,59,39,27 monster Thug 1442,10,300000,30000
+026-2,61,58,20,43 monster Revolver Shooter 1208,11,300000,30000
+026-2,61,23,39,7 monster Grenadier 1444,3,300000,30000
diff --git a/npc/026-2/_warps.txt b/npc/026-2/_warps.txt
index 98b9d22..f15a3bf 100644
--- a/npc/026-2/_warps.txt
+++ b/npc/026-2/_warps.txt
@@ -1,5 +1,5 @@
// This file is generated automatically. All manually added changes will be removed when running the Converter.
// Map 026-2: Count's Fortress warps
-026-2,32,98,0 warp #026-2_32_98 0,0,001-3,118,114
+026-2,32,97,0 warp #026-2_32_97 0,0,001-3,118,114
026-2,86,26,0 warp #026-2_86_26 0,0,006-10,52,64
026-2,29,26,0 warp #026-2_29_26 0,0,006-10,51,64
diff --git a/npc/033-1/_import.txt b/npc/033-1/_import.txt
index 90c62d6..bd2a012 100644
--- a/npc/033-1/_import.txt
+++ b/npc/033-1/_import.txt
@@ -2,3 +2,5 @@
// This file is generated automatically. All manually added changes will be removed when running the Converter.
"npc/033-1/_warps.txt",
"npc/033-1/misc.txt",
+"npc/033-1/nico.txt",
+"npc/033-1/trainer.txt",
diff --git a/npc/033-1/misc.txt b/npc/033-1/misc.txt
index f57cc03..608cc1f 100644
--- a/npc/033-1/misc.txt
+++ b/npc/033-1/misc.txt
@@ -44,21 +44,69 @@ OnTouch:
function script SetPorthosPortal {
.@id = getarg(0);
mesn l("Portal %02d", .@id);
- mes l("Do you want to activate an event?");
+ switch (.@id) {
+ case 6:
+ mesc l("Event: Moubootaur Showdown"), 1; break;
+ case 7:
+ mesc l("Warp: TMW Classic"), 1; close;
+ case 8:
+ mesc l("Event: Blanc's Showdown"), 1; break;
+ case 9:
+ mesc l("Warp: TMW ML"), 1; close;
+ default:
+ mesc l("This portal has not been coded yet."); close;
+ }
next;
- select
- l("Cancel"),
- l("Moubootaur Showdown");
- mes "";
- switch (@menu) {
- case 2:
+ mes l("Do you want to activate the event?");
+ if (askyesno() == ASK_NO) close;
+ switch (.@id) {
+ case 6:
setd(sprintf("$@EVENT_%02d", .@id), PORTHOS_ACTIVE);
setd(sprintf("$@EVENT_%02d_M$", .@id), "001-13-2");
setd(sprintf("$@EVENT_%02d_X", .@id), 47);
setd(sprintf("$@EVENT_%02d_Y", .@id), 52);
break;
+ case 8:
+ // Clean-up 001-3 in case there are already mobs there
+ killmonsterall("001-3");
+ // Environment Monsters, they do not respawn
+ .@m$="001-3";
+ // Thematic mobs
+ areamonster(.@m$, 20, 20, getmapinfo(MAPINFO_SIZE_X, .@m$), getmapinfo(MAPINFO_SIZE_Y, .@m$), strmobinfo(1, Thug), Thug, 150);
+ areamonster(.@m$, 20, 20, getmapinfo(MAPINFO_SIZE_X, .@m$), getmapinfo(MAPINFO_SIZE_Y, .@m$), strmobinfo(1, Swashbuckler), Swashbuckler, 150);
+ areamonster(.@m$, 20, 20, getmapinfo(MAPINFO_SIZE_X, .@m$), getmapinfo(MAPINFO_SIZE_Y, .@m$), strmobinfo(1, Grenadier), Grenadier, 140);
+ areamonster(.@m$, 20, 20, getmapinfo(MAPINFO_SIZE_X, .@m$), getmapinfo(MAPINFO_SIZE_Y, .@m$), strmobinfo(1, OceanPirate), OceanPirate, 100);
+ // There's `Marley` but they're listed as boss
+ // We'll likely use them in the mazes, as your target?
+ // Environment runt
+ areamonster(.@m$, 20, 20, getmapinfo(MAPINFO_SIZE_X, .@m$), getmapinfo(MAPINFO_SIZE_Y, .@m$), strmobinfo(1, DeathCat), DeathCat, 100);
+ areamonster(.@m$, 20, 20, getmapinfo(MAPINFO_SIZE_X, .@m$), getmapinfo(MAPINFO_SIZE_Y, .@m$), strmobinfo(1, BlackSlime), BlackSlime, 90);
+ areamonster(.@m$, 20, 20, getmapinfo(MAPINFO_SIZE_X, .@m$), getmapinfo(MAPINFO_SIZE_Y, .@m$), strmobinfo(1, SmallFrog), SmallFrog, 80);
+ areamonster(.@m$, 20, 20, getmapinfo(MAPINFO_SIZE_X, .@m$), getmapinfo(MAPINFO_SIZE_Y, .@m$), strmobinfo(1, BigFrog), BigFrog, 80);
+ // The lower tier
+ areamonster(.@m$, 20, 20, getmapinfo(MAPINFO_SIZE_X, .@m$), getmapinfo(MAPINFO_SIZE_Y, .@m$), strmobinfo(1, WickedMushroom), WickedMushroom, 50);
+ areamonster(.@m$, 20, 20, getmapinfo(MAPINFO_SIZE_X, .@m$), getmapinfo(MAPINFO_SIZE_Y, .@m$), strmobinfo(1, Forain), Forain, 50);
+ areamonster(.@m$, 20, 20, getmapinfo(MAPINFO_SIZE_X, .@m$), getmapinfo(MAPINFO_SIZE_Y, .@m$), strmobinfo(1, Assassin), Assassin, 50);
+ // The mid tier
+ areamonster(.@m$, 20, 20, getmapinfo(MAPINFO_SIZE_X, .@m$), getmapinfo(MAPINFO_SIZE_Y, .@m$), strmobinfo(1, HoodedNinja), HoodedNinja, 30);
+ // The high tier
+ areamonster(.@m$, 20, 20, getmapinfo(MAPINFO_SIZE_X, .@m$), getmapinfo(MAPINFO_SIZE_Y, .@m$), strmobinfo(1, BlackSlimeMother), BlackSlimeMother, 10);
+ // The boss level spawns
+ areamonster(.@m$, 20, 20, getmapinfo(MAPINFO_SIZE_X, .@m$), getmapinfo(MAPINFO_SIZE_Y, .@m$), strmobinfo(1, Reaper), Reaper, 2);
+ areamonster(.@m$, 20, 20, getmapinfo(MAPINFO_SIZE_X, .@m$), getmapinfo(MAPINFO_SIZE_Y, .@m$), strmobinfo(1, NightmareDragon), NightmareDragon, 2);
+ areamonster(.@m$, 20, 20, getmapinfo(MAPINFO_SIZE_X, .@m$), getmapinfo(MAPINFO_SIZE_Y, .@m$), strmobinfo(1, Mandragora), Mandragora, 1);
+ areamonster(.@m$, 20, 20, getmapinfo(MAPINFO_SIZE_X, .@m$), getmapinfo(MAPINFO_SIZE_Y, .@m$), strmobinfo(1, SiegeTower), SiegeTower, 1);
+ areamonster(.@m$, 20, 20, getmapinfo(MAPINFO_SIZE_X, .@m$), getmapinfo(MAPINFO_SIZE_Y, .@m$), strmobinfo(1, Golem), Golem, 2);
+ areamonster(.@m$, 20, 20, getmapinfo(MAPINFO_SIZE_X, .@m$), getmapinfo(MAPINFO_SIZE_Y, .@m$), strmobinfo(1, ShadowTortuga), ShadowTortuga, 1);
+ // Set everything up
+ setd(sprintf("$@EVENT_%02d", .@id), PORTHOS_ACTIVE);
+ setd(sprintf("$@EVENT_%02d_M$", .@id), "001-3");
+ setd(sprintf("$@EVENT_%02d_X", .@id), 164);
+ setd(sprintf("$@EVENT_%02d_Y", .@id), 33);
+ kamibroadcast("Blanc's Showdown was enabled.");
+ break;
default:
- mes l("Ok.");
+ mes l("Error.");
break;
}
close;
@@ -66,25 +114,40 @@ function script SetPorthosPortal {
}
-033-1,72,190,0 script #Porthos01 NPC_NO_SPRITE,0,0,{
+// Shortcut to TMW Classic?
+033-1,85,227,0 script #Porthos07 NPC_NO_SPRITE,0,0,{
+ end;
+OnTouch:
+ slide 85, 228;
+ mes l("Do you want to visit The Mana World: Classic?");
+ next;
+ if (askyesno() == ASK_YES)
+ MirrorLakeSendTo(MLP_TMW, 0);
+ closeclientdialog;
+ end;
+}
+
+// Event: Blanc's Manhunt
+033-1,72,190,0 script #Porthos08 NPC_NO_SPRITE,0,0,{
end;
OnTouch:
- if ($@EVENT_01 == PORTHOS_BUSY) {
+ if ($@EVENT_06 == PORTHOS_BUSY) {
dispbottom l("This portal is currently busy - an event must be in progress.");
end;
}
- if ($@EVENT_01 == PORTHOS_UNUSED) {
+ // 001-3 portals
+ if ($@EVENT_08 == PORTHOS_UNUSED) {
if (is_admin() || is_master())
- SetPorthosPortal(1);
+ SetPorthosPortal(8);
dispbottom l("This portal is not currently active.");
end;
}
- warp $@EVENT_01_M$, $@EVENT_01_X, $@EVENT_01_Y;
+ warp $@EVENT_08_M$, $@EVENT_08_X, $@EVENT_08_Y;
end;
}
// Shortcut to Moubootaur Legends?
-033-1,31,155,0 script #Porthos02 NPC_NO_SPRITE,0,0,{
+033-1,31,155,0 script #Porthos09 NPC_NO_SPRITE,0,0,{
end;
OnTouch:
slide 31, 156;
@@ -96,3 +159,23 @@ OnTouch:
end;
}
+// TODO: Event: Zax De'Kagen Showdown
+// Event: Moubootaur Showdown
+// This is a draft in npc/config/events.txt
+033-1,154,238,0 script #Porthos06 NPC_NO_SPRITE,0,0,{
+ end;
+OnTouch:
+ if ($@EVENT_06 == PORTHOS_BUSY) {
+ dispbottom l("This portal is currently busy - an event must be in progress.");
+ end;
+ }
+ if ($@EVENT_06 == PORTHOS_UNUSED) {
+ if (is_admin() || is_master())
+ SetPorthosPortal(6);
+ dispbottom l("This portal is not currently active.");
+ end;
+ }
+ warp $@EVENT_06_M$, $@EVENT_06_X, $@EVENT_06_Y;
+ end;
+}
+
diff --git a/npc/017-3/nico.txt b/npc/033-1/nico.txt
index 19dd79e..e656f4b 100644
--- a/npc/017-3/nico.txt
+++ b/npc/033-1/nico.txt
@@ -4,7 +4,9 @@
// Description:
// Arcmage Cards Enhancer
-017-3,37,84,0 script Nico Goethe NPC_PLAYER,{
+033-1,157,89,0 script Nico Goethe NPC_PLAYER,{
+ function colorname;
+ function gameinfo;
mesn;
mesq l("My name is Nico Goethe, an %s card player.", "[@@https://arcmage.org|Arcmage@@]");
next;
@@ -13,6 +15,7 @@
next;
mesn;
mesq l("However, I am still up for trading cards, if you wish.");
+ mesc l("%s discreetly point out that cards only works well in Moubootaur Legends weapons, but this depends on your origin server.", .name$);
next;
goto L_Main;
@@ -20,6 +23,7 @@ L_Main:
select
l("Trade a card"),
l("Evolve a card"),
+ l("Remove a card"),
l("Lets play!"),
l("Bye.");
mes "";
@@ -269,11 +273,49 @@ L_Main:
break;
}
break;
- // TODO: Play minigame
+ // Remove a card
case 3:
+ mesc l("You can drag and drop an item to the NPC window or select an item through your inventory.");
+
+ delinventorylist();
+ getinventorylist();
+ .@item_index = requestitemindex();
+ .@item_id = @inventorylist_id[.@item_index];
+
+ mesn;
+ mesq l("Your mind is set? You will probably lose all the dyes and/or cards during on the item during this process. You're bleaching a %s by the way, and THERE ARE NO REFUNDS even if the item go ablaze.", getitemlink(.@item_id));
+
+ if (askyesno() == ASK_YES) {
+ mesn;
+ mesq l("Sure, I'll be done in a jiff.");
+ next;
+ successremovecardsindex(.@item_index); // *should* return the card
+ mesn;
+ mesq l("Here it is, clean like a whistle!");
+ } else {
+ mesn;
+ mesq l("Is it truly a hard choice to make?");
+ }
+ next;
+ break;
+ // Play minigame
+ case 4:
mesn;
mesq l("...Are you trying to troll me?");
next;
+ mesn;
+ mesq l("Well, I can't offer you an %s match, but do you want to play something else? I would charge %d GP for a match.", "[@@https://arcmage.org|Arcmage@@]", .price);
+ next;
+ if (askyesno() == ASK_NO) {
+ mesn;
+ mesq l("Suit yourself.");
+ next;
+ break;
+ }
+ gameinfo();
+ mesn;
+ mesq l("Ready to begin?");
+ if (askyesno() == ASK_YES) goto L_Start;
break;
// Leave
default:
@@ -284,6 +326,132 @@ L_Main:
}
goto L_Main;
+function colorname {
+ switch (getarg(0)) {
+ case 1:
+ return "Green"; break;
+ case 2:
+ return "Blue"; break;
+ case 3:
+ return "Red"; break;
+ case 4:
+ return "Yellow"; break;
+ case 5:
+ return "Exit"; break;
+ default:
+ return l("ERROR: %d", getarg(0));
+ }
+}
+
+function gameinfo {
+ showavatar NPC_FLOPPED_NOBLEMAN;
+ mes "";
+ mesc l("Rules:");
+ mesc l("A color sequence will be displayed on the avatar frame.");
+ mesc l("You must then repeat the sequence at the board which will show.");
+ next;
+ mesc l("Prizes:");
+ mesc l("You'll get %d GP every time you finish the sequence.", .prize);
+ mesc l("If you finish %d sequences, you'll get a(n) %s!", 10, getitemlink(ArcmageBoxset));
+ next;
+ return;
+}
+
+L_Start:
+ showavatar AVATAR_SEQBOARD;
+ mesc l("Pay attention to the sequence!");
+ next;
+ Zeny -= .price;
+ deletearray(@sequence);
+ @streak=0;
+
+L_Sequence:
+ // Configure
+ setnpcdialogtitle l("Memorize the sequence!");
+ array_push(@sequence, 1+rand2(4));
+ sleep2(1000);
+
+ // Display
+ freeloop(true);
+ for (.@i=0;.@i < getarraysize(@sequence);.@i++) {
+ showavatar 1200+@sequence[.@i];
+ sleep2(1200-(@streak*20));
+ }
+ freeloop(false);
+
+ // Request
+ setnpcdialogtitle l("What was the sequence?");
+ showavatar AVATAR_SEQBOARD;
+ sleep2(500);
+
+ for (.@i=0;.@i < getarraysize(@sequence);.@i++) {
+ setskin "seqboard";
+ select
+ l("Green"),
+ l("Blue"),
+ l("Red"),
+ l("Yellow"),
+ l("Exit");
+ .@ans=@menu;
+ setskin "";
+ mes "";
+ mes l("%s", colorname(.@ans));
+ //next;
+ setnpcdialogtitle strnpcinfo(1);
+
+ // Exit
+ if (.@ans == 5)
+ goto L_Close;
+
+ // Wrong reply
+ if (.@ans != @sequence[.@i])
+ goto L_Wrong;
+ // Correct!
+ }
+ mes "";
+ showavatar AVATAR_SEQBOARD_WELL;
+
+ // Seems like everything is/was correct
+ mesn;
+ mesq l("Congratulations! Everything was correct!");
+ Zeny+=.prize;
+ @streak+=1;
+
+ // Winning Streak
+ if (@streak % 10 == 0)
+ getitem ArcmageBoxset, 1;
+ mesc l("Your current win streak is @@!", @streak);
+ next;
+ // Game over
+ if (@streak == 50)
+ goto L_Close;
+ // Otherwise, go ahead
+ mesn;
+ mesc l("Continue?"), 1;
+ next;
+ if (askyesno() == ASK_YES)
+ goto L_Sequence;
+ goto L_Close;
+
+L_Wrong:
+ showavatar AVATAR_SEQBOARD_FAIL;
+ mesn;
+ mesq l("Oh no... That is wrong! %%3");
+ next;
+ mesn;
+ mesq l("Better luck next time!");
+ next;
+ showavatar;
+ goto L_Main;
+
+L_Close:
+ showavatar;
+ mesn;
+ mesq l("Thanks for the match, it was fun!");
+ next;
+ goto L_Main;
+
+
OnInit:
.@npcId = getnpcid(.name$);
setunitdata(.@npcId, UDT_HEADTOP, TopHat);
@@ -296,6 +464,8 @@ OnInit:
.sex = G_MALE;
.distance = 4;
+ .price = 100;
+ .prize = 25;
end;
}
diff --git a/npc/020-1/trainer.txt b/npc/033-1/trainer.txt
index 1fb4774..c4be75b 100644
--- a/npc/020-1/trainer.txt
+++ b/npc/033-1/trainer.txt
@@ -4,12 +4,13 @@
// Description:
// Mercenary Trainer
-020-1,39,89,0 script Mercenary Trainer NPC_REDY_MALE_SWORD,{
+033-1,180,100,0 script Mercenary Trainer NPC_REDY_MALE_SWORD,{
mesn;
mesq l("Hello, I am a sword to hire, a Mercenary Trainer and Chief.");
next;
mesn;
mesq l("Do you want to hire a mercenary? Or perhaps get a card so you can invoke them later? I can even make them stronger if you wish.");
+ mesc l("With a discrete motion, you notice they also sell scrolls.");
next;
goto L_Main;
@@ -24,15 +25,15 @@ L_Main:
// Hire Card
case 1:
menuint
- l("[%d GP] [Lv 1~25] Hire for one hour", 2500), 1,
- l("[%d GP] [Lv 26~40] Hire for one hour", 7500), 2,
- l("[%d GP] [Lv 41~60] Hire for one hour", 15000), 3,
- l("[%d GP] [Lv 61~79] Hire for one hour", 30000), 4,
- l("[%d GP] [Lv 80~100] Hire for one hour", 50000), 5,
+ l("[%d GP] [Lv 1~25] Hire for one hour", 1000), 1,
+ l("[%d GP] [Lv 26~40] Hire for one hour", 3000), 2,
+ l("[%d GP] [Lv 41~60] Hire for one hour", 7500), 3,
+ l("[%d GP] [Lv 61~79] Hire for one hour", 15000), 4,
+ l("[%d GP] [Lv 80~100] Hire for one hour", 25000), 5,
l("I've changed my mind"), 0;
switch (@menuret) {
case 1:
- .@gp=max(2000, POL_AdjustPrice(2500));
+ .@gp=1000;
if (Zeny < .@gp) {
mesc l("You cannot pay."), 1;
next;
@@ -43,7 +44,7 @@ L_Main:
}
break;
case 2:
- .@gp=max(7000, POL_AdjustPrice(7500));
+ .@gp=3000;
if (Zeny < .@gp) {
mesc l("You cannot pay."), 1;
next;
@@ -54,7 +55,7 @@ L_Main:
}
break;
case 3:
- .@gp=max(14000, POL_AdjustPrice(15000));
+ .@gp=7500;
if (Zeny < .@gp) {
mesc l("You cannot pay."), 1;
next;
@@ -64,7 +65,7 @@ L_Main:
}
break;
case 4:
- .@gp=max(27000, POL_AdjustPrice(30000));
+ .@gp=15000;
if (Zeny < .@gp) {
mesc l("You cannot pay."), 1;
next;
@@ -74,7 +75,7 @@ L_Main:
}
break;
case 5:
- .@gp=max(45000, POL_AdjustPrice(50000));
+ .@gp=25000;
if (Zeny < .@gp) {
mesc l("You cannot pay."), 1;
next;
@@ -132,26 +133,42 @@ L_Main:
goto L_Main;
OnInit:
- tradertype(NST_MARKET);
- sellitem MercBoxEE, 25000, 1;
- sellitem MercBoxDD, 15000, 2;
- sellitem MercBoxCC, 7500, 3;
- sellitem MercBoxBB, 3750, 4;
- sellitem MercBoxAA, 1250, 5;
+ tradertype(NST_ZENY);
+ sellitem MercBoxEE, 25000;
+ sellitem MercBoxDD, 15000;
+ sellitem MercBoxCC, 7500;
+ sellitem MercBoxBB, 3750;
+ sellitem MercBoxAA, 1250;
+
+ sellitem ScrollSMaggot, 1000;
+ sellitem ScrollSCave, 1500;
+ sellitem ScrollSWolvern, 2000;
+ sellitem ScrollSYeti, 2500;
+ sellitem ScrollSTerranite, 3000;
+ sellitem ScrollSDragon, 3500;
+
+ sellitem SacredImmortalityPotion, 25000;
+
+ sellitem ScrollMagnusHealA, 500;
+ sellitem ScrollMagnusHealB,1000;
+ sellitem ScrollMagnusHealC,2000;
+
+ sellitem ScrollBattlePlansA, 400;
+ sellitem ScrollBattlePlansB,1000;
+ //sellitem ScrollBattlePlansC,1500;
+
+ sellitem ScrollDefenseBlessA, 400;
+ sellitem ScrollDefenseBlessB,1000;
+ //sellitem ScrollDefenseBlessC,1500;
+
+ sellitem ScrollCriticalFortuneA, 400;
+ sellitem ScrollCriticalFortuneB,1000;
+ //sellitem ScrollCriticalFortuneC,1500;
.distance=5;
.sex=G_MALE;
end;
-OnClock0001:
-OnClock1201:
- restoreshopitem MercBoxEE, 25000, 1;
- restoreshopitem MercBoxDD, 15000, 2;
- restoreshopitem MercBoxCC, 7500, 3;
- restoreshopitem MercBoxBB, 3750, 4;
- restoreshopitem MercBoxAA, 1250, 5;
- end;
-
// Pay your taxes!
OnBuyItem:
debugmes("Purchase confirmed");
diff --git a/npc/033-2/magic.txt b/npc/033-2/magic.txt
index 35f2145..0ee0dc2 100644
--- a/npc/033-2/magic.txt
+++ b/npc/033-2/magic.txt
@@ -39,6 +39,9 @@ OnInit:
function script Crossroads_Magic {
+ // Respect SC_SILENCE
+ if (getstatus(SC_SILENCE)) return;
+
// Structure: "«Power» «Element», «Action» «Range»!"
.@msg$ = getarg(0);
explode(.@x$, .@msg$, " ");
@@ -207,7 +210,7 @@ function script Crossroads_Magic {
// areaharm()
if (.@TY & 1) {
- .@dmg = AdjustSpellpower(.@PW);
+ .@dmg = AdjustSpellpower(.@PW) * 11 / 10;
areaharm(getcharid(3), .@RG, .@dmg, HARM_MAGI, .@EL, .@F$);
}
diff --git a/npc/config/events.txt b/npc/config/events.txt
index 3dd4311..89e7f37 100644
--- a/npc/config/events.txt
+++ b/npc/config/events.txt
@@ -4,7 +4,11 @@
// Description:
// Some of the event scripts
+001-3 mapflag zone MMO
001-13-2 mapflag zone MMO
+
+/////////////////////////////////////////////////////////////////////////////////
+// Area 06: Moubootaur Showdown
001-13-2,47,26,0 script #FoSCore NPC_NO_SPRITE,{
if (!is_admin() && !is_master()) end;
if ($@FIRESOFSTEAM_BOSS) end;
@@ -22,7 +26,7 @@
l("Portable Apocalypse");
mes "";
$@FIRESOFSTEAM_DIFF=70+(@menu*30);
- $@EVENT_01 = PORTHOS_BUSY;
+ $@EVENT_06 = PORTHOS_BUSY;
switch (@menu) {
case 1: .@d$="##2Easy"; break;
case 2: .@d$="##3Crazy"; break;
@@ -35,7 +39,7 @@
changemusic("001-13-2", "mythica.ogg");
closeclientdialog;
// Dispose of the GM
- warp "033-1", 72, 185;
+ warp "033-1", 49, 193;
sleep(200);
// PC no longer attached
// Start the event
@@ -152,7 +156,7 @@ OnEventEnd:
mapannounce("001-13-2", "Moubootaur : ##1##BI'll come back... Stronger than ever!", 0);
sleep(3000);
maptimer2("001-13-2", 10, "#FoSCore::OnMFSurvive");
- $@EVENT_01 = PORTHOS_UNUSED;
+ $@EVENT_06 = PORTHOS_UNUSED;
end;
@@ -171,7 +175,7 @@ OnMFShake:
end;
OnMFDispose:
- if (ispcdead()) warp("033-1", 72, 191);
+ if (ispcdead()) warp("033-1", 154, 240);
end;
OnMFSurvive:
@@ -180,7 +184,7 @@ OnMFSurvive:
##01_CRQUEST = ##01_CRQUEST | MLP_CR_DEBUT;
specialeffect(FX_FANFARE, AREA, getcharid(3));
sleep2(15000);
- warp("033-1", 72, 191);
+ warp("033-1", 154, 240);
end;
////////////// Heartbeat //////////////
@@ -308,7 +312,7 @@ L_Defeat:
.Support5=0;
killmonsterall("001-13-2");
kamibroadcast("The players were defeated at Fires of Steam Showdown.", "Fires of Steam");
- $@EVENT_01 = PORTHOS_UNUSED;
+ $@EVENT_06 = PORTHOS_UNUSED;
stopnpctimer;
end;
@@ -320,3 +324,92 @@ OnInit:
end;
}
+
+/////////////////////////////////////////////////////////////////////////////////
+// Area 08: Blanc's Showdown
+001-3,147,153,0 script #E08_CF NPC_HIDDEN,2,0,{
+ end;
+OnTouch:
+ if (!(get_byte(EVENT_08, 0) & EV08_KEY)) {
+ dispbottom l("Darn, it is locked. A few keys will be necessary to open this.");
+ end;
+ }
+ warp "026-2", 32, 96;
+ end;
+OnBossDie:
+ .@p=get_nibble(EVENT_08, 2)+1;
+ set_nibble(EVENT_08, 2, .@p);
+ if (.@p >= 3) {
+ set_byte(EVENT_08, 0, get_byte(EVENT_08, 0) | EV08_KEY);
+ dispbottom l("I got all the keys! Time to get out of here!");
+ sleep2(500);
+ warp "001-3", 164, 33;
+ end;
+ }
+ dispbottom l("Keys: %d/%d", .@p, 3);
+ end;
+OnInit:
+ .sex = G_OTHER;
+ end;
+}
+
+001-3,35,32,0 script #E08WP_150 NPC_HIDDEN,0,0,{
+ end;
+OnTouch:
+ if ($@EVENT_08 != PORTHOS_ACTIVE) end;
+ //if (get_byte(EVENT_08, 0) & EV08_P150) end;
+ if (get_byte(EVENT_08, 0) & EV08_KEY) end;
+ setpcblock(PCBLOCK_HARD, true);
+ mesc l("STORY MODE ENABLED. Monsters won't attack you, so you can read without worries."), 1;
+ next;
+ mesc l("Seems like our prey was through. This portal connects to a Level %d Maze.", .lvl);
+ if (BaseLevel > .lvl*2) {
+ mesc l("Meaning I cannot use this one. Dang!");
+ next;
+ goto L_Close;
+ }
+ mesc l("If I can find Elmo or Marley inside, they should be holding the keys for the castle, where we presume Blanc ran off to.");
+ mesc l("I need to defeat at least three of them."), 1;
+ next;
+ mesc l("Will I explore this Maze? Or will I look another?"), 1;
+ next;
+ if (askyesno() == ASK_YES) {
+ set_nibble(EVENT_08, 2, 0);
+ CreateMaze(IOT_CHAR, MAZE_SIZE_G | MAZE_SIZE_X);
+ if (BaseLevel > .lvl)
+ .density=12;
+ else
+ .density=15;
+ MazeMobs(.lvl, false, .density);
+
+ // Spawn & Configure the boss monster
+ .@mx=getmapinfo(MAPINFO_SIZE_X, MAZE_MAP$)-20;
+ .@my=getmapinfo(MAPINFO_SIZE_Y, MAZE_MAP$)-20;
+ .@mob=areamonster(MAZE_MAP$, 20, 20, .@mx, .@my, "Elmo", Marley, 5, "#E08_CF::OnBossDie");
+ InitMaze(7200);
+ dispbottom col(l("Reminder : Defeat 3/5 %s to win. Time limit: %d minutes or death.", b("Elmo"), 120), 2);
+ }
+
+L_Close:
+ closeclientdialog;
+ setpcblock(PCBLOCK_HARD, false);
+ end;
+OnInit:
+ .sex = G_OTHER;
+ .@n$ = strnpcinfo(0, "_0");
+ explode(.@ni$, .@n$, "_");
+ .lvl = atoi(.@ni$[1]);
+ end;
+}
+
+001-3,113,148,0 duplicate(#E08WP_150) #E08WP_100 NPC_HIDDEN,0,0
+001-3,258,39,0 duplicate(#E08WP_150) #E08WP_75 NPC_HIDDEN,0,0
+001-3,38,257,0 duplicate(#E08WP_150) #E08WP_50 NPC_HIDDEN,0,0
+001-3,229,188,0 duplicate(#E08WP_150) #E08WP_25 NPC_HIDDEN,0,0
+
+// 35,32 NW (150) OK
+// 113,148 Central circle (100)
+// 258,39 NE (75)
+// 38,257 SW (50)
+// 229,188 SE (25)
+
diff --git a/npc/config/traps.txt b/npc/config/traps.txt
index 1b43e5c..560abcf 100644
--- a/npc/config/traps.txt
+++ b/npc/config/traps.txt
@@ -65,7 +65,9 @@ function script IronTrap {
// Boom - Hurt and Stun (only works on players and mobs)
.@stun*=1000;
- sc_start SC_STUN, rand2(.@stun,.@stun*3), 0;
+ // Replaced SC_STUN with something else, which is not SC_Start* controlled
+ // But basically, SC_STUN causes lag in M+ because the client is dumb
+ sc_start2 SC_QUAGMIRE, rand2(.@stun,.@stun*3), 20000, 20000;
.@gid=(playerattached() ? playerattached() : mobattached());
// Just to be sure
diff --git a/npc/craft/price.txt b/npc/craft/price.txt
index 4b0ab9c..34ff919 100644
--- a/npc/craft/price.txt
+++ b/npc/craft/price.txt
@@ -58,7 +58,7 @@ function script _fix_cPrice {
// Update the final price
if (.@price > 0) {
- debugmes("Price for %s adjusted from %d (%d) to %d (%d) GP", getitemname(.@item), getiteminfo(.@item, ITEMINFO_BUYPRICE), getiteminfo(.@item, ITEMINFO_SELLPRICE), .@price * .@m / 10, .@price);
+ //debugmes("Price for %s adjusted from %d (%d) to %d (%d) GP", getitemname(.@item), getiteminfo(.@item, ITEMINFO_BUYPRICE), getiteminfo(.@item, ITEMINFO_SELLPRICE), .@price * .@m / 10, .@price);
setiteminfo(.@item, ITEMINFO_BUYPRICE, .@price * .@m / 10);
setiteminfo(.@item, ITEMINFO_SELLPRICE, .@price);
//debugmes("New Price for %s is now %d (%d) GP", getitemname(.@item), getiteminfo(.@item, ITEMINFO_BUYPRICE), getiteminfo(.@item, ITEMINFO_SELLPRICE));
diff --git a/npc/functions/main.txt b/npc/functions/main.txt
index b2a7a78..999d18c 100644
--- a/npc/functions/main.txt
+++ b/npc/functions/main.txt
@@ -299,6 +299,34 @@ function script any_of {
return getelementofarray(getarg(0), getarrayindex(getarg(0)) + rand2(getarraysize(getarg(0)) - getarrayindex(getarg(0))));
}
+// Miller Algorithm implementation for shuffling (PRIG)
+// miller_rand( state, seed, array_size )
+function script miller_rand {
+ .@inx = getarg(0);
+ .@shuffleID = getarg(1);
+ .@listSize = getarg(2);
+
+ .@shuffleID += 131 * (.@inx/.@listSize); // have inx overflow effect the mix
+ .@si = (.@inx + .@shuffleID) % .@listSize; // cut the deck
+
+ .@topEven = .@listSize - (.@listSize & 1); // compute reference value
+ .@r1 = .@shuffleID % 0xFFF; // improved randomizing values
+ .@r2 = .@shuffleID % 0x3FFF ^ .@r1;
+ .@r3 = .@shuffleID / 881 + 3;
+ .@rx = (.@shuffleID / .@listSize) % .@listSize + 1;
+
+ // NOTE: the next line operates only 1/3 the time, the following line 1/2
+ if (.@si % 3 == 0)
+ .@si = (((.@si/3)*3343+.@r1) % ((.@listSize+2)/3)) * 3; // spin multiples of 3
+ if (.@si&1)
+ .@si = (2 * .@r2 + .@topEven - .@si) % .@topEven; // reverse+rotate flow of odd #s
+ if ((.@si ^ .@rx) < .@listSize)
+ .@si ^= .@rx; // flip some bits with Xor
+ .@si = (.@si * 9973 + .@r3) % .@listSize; // turn more prime wheels
+
+ return .@si;
+}
+
function script die {
if ($HARDCORE) {
@grace=true;
diff --git a/npc/functions/mobpoint.txt b/npc/functions/mobpoint.txt
index b49baa9..08b3ff7 100644
--- a/npc/functions/mobpoint.txt
+++ b/npc/functions/mobpoint.txt
@@ -85,8 +85,6 @@ OnNPCKillEvent:
callfunc "CoffeeDay";
callfunc "FSFDay";
callfunc "CraftmasterDay";
- callfunc "CadisQuestCheck";
- callfunc "GeminiKill";
callfunc "SK_drops";
// Other updates
diff --git a/npc/items/grenade.txt b/npc/items/grenade.txt
index 12a314b..a3ddf9f 100644
--- a/npc/items/grenade.txt
+++ b/npc/items/grenade.txt
@@ -78,7 +78,7 @@ function script areasc2 {
return;
}
-// areasc3(range, time, sc, bl, val1, val2, filter)
+// areasc3(range, time, sc, bl, val1, val2, filter, target, chances)
// Defaults to 3x3 square, sleep mob for 500ms. Ignores you.
// Need a player caster. Valid BL: BL_MOB | BL_PC | BL_HOM | BL_MER
function script areasc3 {
@@ -89,14 +89,16 @@ function script areasc3 {
.@v1=getarg(4, 1);
.@v2=getarg(5, 1);
.@f$=getarg(6, "filter_notme");
+ .@t=getarg(7, playerattached());
+ .@sr=getarg(8, 10000);
- getmapxy(.@m$, .@x, .@y, 0);
+ getmapxy(.@m$, .@x, .@y, getunittype(.@t), .@t);
.@c=getunits(.@b, .@mbs, false, .@m$, .@x-.@r, .@y-.@r, .@x+.@r, .@y+.@r);
for (.@i = 0; .@i < .@c; .@i++) {
// Filtering
if (!callfunc(.@f$, .@mbs[.@i]))
continue;
- sc_start2 .@s, .@d, .@v1, .@v2, 10000, SCFLAG_NONE, .@mbs[.@i];
+ sc_start2 .@s, .@d, .@v1, .@v2, .@sr, SCFLAG_NONE, .@mbs[.@i];
specialeffect(FX_BUFF, AREA, .@mbs[.@i]);
}
return;