summaryrefslogtreecommitdiff
path: root/npc
diff options
context:
space:
mode:
Diffstat (limited to 'npc')
-rw-r--r--npc/001-4/traps.txt38
-rw-r--r--npc/002-1/_config.txt (renamed from npc/002-1/_savepoints.txt)2
-rw-r--r--npc/002-1/_import.txt2
-rw-r--r--npc/003-1/events.txt6
-rw-r--r--npc/003-1/inar.txt11
-rw-r--r--npc/003-3/malindou.txt42
-rw-r--r--npc/003-6/tamiloc.txt17
-rw-r--r--npc/005-4/tolchi.txt2
-rw-r--r--npc/005-6/morgan.txt10
-rw-r--r--npc/008-2/_config.txt99
-rw-r--r--npc/008-2/_import.txt1
-rw-r--r--npc/017-10/dispatcher.txt4
-rw-r--r--npc/018-5-4/elder.txt137
-rw-r--r--npc/024-11/politics.txt5
-rw-r--r--npc/024-16/craftsman.txt25
-rw-r--r--npc/025-2/phoenix.txt19
-rw-r--r--npc/commands/super-menu.txt36
-rw-r--r--npc/config/hairstyle_config.txt2
-rw-r--r--npc/config/magic.txt32
-rw-r--r--npc/config/traps.txt82
-rw-r--r--npc/craft/options.txt78
-rw-r--r--npc/craft/recipes.txt5
-rw-r--r--npc/craft/tweak.txt3
-rw-r--r--npc/functions/clientversion.txt49
-rw-r--r--npc/functions/filters.txt40
-rw-r--r--npc/functions/hub.txt63
-rw-r--r--npc/functions/mkbot.txt5
-rw-r--r--npc/functions/mobpoint.txt13
-rw-r--r--npc/functions/scoreboards.txt5
-rw-r--r--npc/functions/util.txt42
-rw-r--r--npc/items/alcohol.txt6
-rw-r--r--npc/magic/dragokin.txt8
-rw-r--r--npc/magic/plantkingdom.txt4
-rw-r--r--npc/scripts.conf2
34 files changed, 760 insertions, 135 deletions
diff --git a/npc/001-4/traps.txt b/npc/001-4/traps.txt
index 3d50f34fe..bfee1265e 100644
--- a/npc/001-4/traps.txt
+++ b/npc/001-4/traps.txt
@@ -4,44 +4,6 @@
// Description:
// Traps.
-// SteelTrap( {damage=80%}, {delay=15s}, {stun=3s}, {npcname=auto} )
-function script SteelTrap {
- .@dmg=getarg(0, 80);
- .@delay=getarg(1, 15);
- .@stun=getarg(2, 3);
- .@n$=getarg(3, strnpcinfo(0));
-
- // It was disarmed
- if (getnpctimer(0) == 0)
- {
- initnpctimer;
- setnpcdisplay .@n$, NPC_TRAP_ONLINE;
- return;
- }
-
- // Fire!!
- setnpctimer 9000;
- setnpcdisplay .@n$, NPC_TRAP_TRIGGERED;
-
- // Boom - Hurt players and/or stun monsters
- // This means you can - and SHOULD - lead Forains into these traps
- if (playerattached())
- {
- percentheal -(.@dmg), 0;
- }
- else
- {
- .@stun*=1000;
- sc_start SC_WALKSPEED,(.@delay*1000),60;
- sc_start SC_STUN,rand(.@stun,.@stun*3),0;
- }
-
- // A minor special effect and we're done.
- specialeffect 11;
- return;
-}
-
-
001-4,275,204,0 script #001-4_275x204 NPC_TRAP,0,0,{
mesn strcharinfo(0);
mesq l("Something seems off with that!");
diff --git a/npc/002-1/_savepoints.txt b/npc/002-1/_config.txt
index 2edca8761..f43820b70 100644
--- a/npc/002-1/_savepoints.txt
+++ b/npc/002-1/_config.txt
@@ -1,5 +1,5 @@
// This file is generated automatically. All manually added changes will be removed when running the Converter.
-// Map 002-1: Second Deck saves
+// Map 002-1: Second Deck conf
002-1,55,40,0 script #save_002-1_55_40 NPC_SAVE_POINT,{
savepointparticle .map$, .x, .y, NO_INN;
close;
diff --git a/npc/002-1/_import.txt b/npc/002-1/_import.txt
index ad6b0b697..0e3644fe9 100644
--- a/npc/002-1/_import.txt
+++ b/npc/002-1/_import.txt
@@ -1,7 +1,7 @@
// Map 002-1: Second Deck
// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/002-1/_config.txt",
"npc/002-1/_mobs.txt",
-"npc/002-1/_savepoints.txt",
"npc/002-1/alige.txt",
"npc/002-1/arpan.txt",
"npc/002-1/billybons.txt",
diff --git a/npc/003-1/events.txt b/npc/003-1/events.txt
index 443b601cf..08d817455 100644
--- a/npc/003-1/events.txt
+++ b/npc/003-1/events.txt
@@ -336,7 +336,6 @@ L_Aurora:
l("Event Ranking Rewards"),
rif(FYEventUsesRanking(), l("Current Rankings")),
rif(FYEventUsesRanking(), l("List & Claim rewards")),
- rif(FYEventUsesRanking(), l("Submit to ranking")),
l("That's all, thanks!");
mes "";
switch (@menu) {
@@ -361,11 +360,8 @@ L_Aurora:
break;
case 4:
- auroraListRewards();
- break;
-
- case 5:
auroraSubmit();
+ auroraListRewards();
break;
default:
diff --git a/npc/003-1/inar.txt b/npc/003-1/inar.txt
index 8311c8ad5..f80c8c52d 100644
--- a/npc/003-1/inar.txt
+++ b/npc/003-1/inar.txt
@@ -32,4 +32,15 @@ OnInit:
.sex = G_MALE;
.distance = 5;
end;
+
+// Pay your taxes!
+OnBuyItem:
+ debugmes("Purchase confirmed");
+ PurchaseTaxes();
+ end;
+
+OnSellItem:
+ debugmes("Sale confirmed");
+ SaleTaxes();
+ end;
}
diff --git a/npc/003-3/malindou.txt b/npc/003-3/malindou.txt
index 7ea8ac2f1..7f452be41 100644
--- a/npc/003-3/malindou.txt
+++ b/npc/003-3/malindou.txt
@@ -552,20 +552,42 @@ OnInit:
// Fix Tolchi mess
if ($UPDATE < 1590616575) {
if ($UPDATE < 1587915715) {
- query_sql("UPDATE `inventory` SET `opt_val0` = '15', `opt_val1` = '5' WHERE (`opt_idx0`='189' OR `opt_idx0`='200') AND (`opt_idx1`='189' OR `opt_idx1`='200') AND (`opt_val0` > '15' AND `opt_val1` > '15')");
- query_sql("UPDATE `cart_inventory` SET `opt_val0` = '15', `opt_val1` = '5' WHERE (`opt_idx0`='189' OR `opt_idx0`='200') AND (`opt_idx1`='189' OR `opt_idx1`='200') AND (`opt_val0` > '15' AND `opt_val1` > '15')");
- query_sql("UPDATE `storage` SET `opt_val0` = '15', `opt_val1` = '5' WHERE (`opt_idx0`='189' OR `opt_idx0`='200') AND (`opt_idx1`='189' OR `opt_idx1`='200') AND (`opt_val0` > '15' AND `opt_val1` > '15')");
- query_sql("UPDATE `guild_storage` SET `opt_val0` = '15', `opt_val1` = '5' WHERE (`opt_idx0`='189' OR `opt_idx0`='200') AND (`opt_idx1`='189' OR `opt_idx1`='200') AND (`opt_val0` > '15' AND `opt_val1` > '15')");
- query_sql("UPDATE `rodex_items` SET `opt_val0` = '15', `opt_val1` = '5' WHERE (`opt_idx0`='189' OR `opt_idx0`='200') AND (`opt_idx1`='189' OR `opt_idx1`='200') AND (`opt_val0` > '15' AND `opt_val1` > '15')");
- query_sql("UPDATE `auction` SET `opt_val0` = '15', `opt_val1` = '5' WHERE (`opt_idx0`='189' OR `opt_idx0`='200') AND (`opt_idx1`='189' OR `opt_idx1`='200') AND (`opt_val0` > '15' AND `opt_val1` > '15')");
+ query_sql("UPDATE `inventory` SET `opt_val0` = '15', `opt_val1` = '0', `opt_idx1` = '0' WHERE (`opt_idx0`='189' OR `opt_idx0`='200') AND (`opt_idx1`='189' OR `opt_idx1`='200') AND (`opt_val0` > '15' AND `opt_val1` > '15')");
+ query_sql("UPDATE `cart_inventory` SET `opt_val0` = '15', `opt_val1` = '0', `opt_idx1` = '0' WHERE (`opt_idx0`='189' OR `opt_idx0`='200') AND (`opt_idx1`='189' OR `opt_idx1`='200') AND (`opt_val0` > '15' AND `opt_val1` > '15')");
+ query_sql("UPDATE `storage` SET `opt_val0` = '15', `opt_val1` = '0', `opt_idx1` = '0' WHERE (`opt_idx0`='189' OR `opt_idx0`='200') AND (`opt_idx1`='189' OR `opt_idx1`='200') AND (`opt_val0` > '15' AND `opt_val1` > '15')");
+ query_sql("UPDATE `guild_storage` SET `opt_val0` = '15', `opt_val1` = '0', `opt_idx1` = '0' WHERE (`opt_idx0`='189' OR `opt_idx0`='200') AND (`opt_idx1`='189' OR `opt_idx1`='200') AND (`opt_val0` > '15' AND `opt_val1` > '15')");
+ query_sql("UPDATE `rodex_items` SET `opt_val0` = '15', `opt_val1` = '0', `opt_idx1` = '0' WHERE (`opt_idx0`='189' OR `opt_idx0`='200') AND (`opt_idx1`='189' OR `opt_idx1`='200') AND (`opt_val0` > '15' AND `opt_val1` > '15')");
+ query_sql("UPDATE `auction` SET `opt_val0` = '15', `opt_val1` = '0', `opt_idx1` = '0' WHERE (`opt_idx0`='189' OR `opt_idx0`='200') AND (`opt_idx1`='189' OR `opt_idx1`='200') AND (`opt_val0` > '15' AND `opt_val1` > '15')");
}
- query_sql("UPDATE `inventory` SET `opt_val0` = '15', `opt_val1` = '5' WHERE (`opt_idx1`=`opt_idx2`) AND (`opt_val0` > '15' AND `opt_val1` > '15')");
- query_sql("UPDATE `storage` SET `opt_val0` = '15', `opt_val1` = '5' WHERE (`opt_idx1`=`opt_idx2`) AND (`opt_val0` > '15' AND `opt_val1` > '15')");
- query_sql("UPDATE `guild_storage` SET `opt_val0` = '15', `opt_val1` = '5' WHERE (`opt_idx1`=`opt_idx2`) AND (`opt_val0` > '15' AND `opt_val1` > '15')");
- query_sql("UPDATE `rodex_items` SET `opt_val0` = '15', `opt_val1` = '10' WHERE (`opt_idx1`=`opt_idx2`) AND (`opt_val0` > '15' AND `opt_val1` > '15')");
+ // Destroy duplicates (should not exist)
+ query_sql("UPDATE `inventory` SET `opt_val0` = '15', `opt_val1` = '0', `opt_idx1` = '0' WHERE (`opt_idx1`=`opt_idx0`) AND (`opt_val0` > '15' AND `opt_val1` > '15')");
+ query_sql("UPDATE `storage` SET `opt_val0` = '15', `opt_val1` = '0', `opt_idx1` = '0' WHERE (`opt_idx1`=`opt_idx0`) AND (`opt_val0` > '15' AND `opt_val1` > '15')");
+ query_sql("UPDATE `guild_storage` SET `opt_val0` = '15', `opt_val1` = '0', `opt_idx1` = '0' WHERE (`opt_idx1`=`opt_idx0`) AND (`opt_val0` > '15' AND `opt_val1` > '15')");
+ query_sql("UPDATE `rodex_items` SET `opt_val0` = '15', `opt_val1` = '0', `opt_idx1` = '0' WHERE (`opt_idx1`=`opt_idx0`) AND (`opt_val0` > '15' AND `opt_val1` > '15')");
+
+ // Magic v3
+ $REBIRTH_WINNER$="Crazyfefe";
+ /*
+ ReplaceSkillFromEveryPlayer(MG_FIREBALL, TMW2_FIREARROW); // 1 MSP
+
+ ReplaceSkillFromEveryPlayer(AL_HOLYLIGHT, TMW2_HOLYLIGHT); // 1 MSP??
+ ReplaceSkillFromEveryPlayer(MG_NAPALMBEAT, TMW2_NAPALMBEAT); // 2 MSP??
+
+ ReplaceSkillFromEveryPlayer(MG_SOULSTRIKE, TMW2_MAGICSTRIKE);
+ ReplaceSkillFromEveryPlayer(WZ_EARTHSPIKE, TMW2_METEORSTRIKE);
+
+ ReplaceSkillFromEveryPlayer(MG_COLDBOLT, TMW2_FROSTDIVER);
+ ReplaceSkillFromEveryPlayer(MG_FROSTDIVER, TMW2_FROSTNOVA);
+ ReplaceSkillFromEveryPlayer(WZ_FROSTNOVA, TMW2_NILFHEIM);
+
+ ReplaceSkillFromEveryPlayer(AL_HEAL, TMW2_FIRSTAID);
+ ReplaceSkillFromEveryPlayer(AB_HIGHNESSHEAL, TMW2_HEALING);
+ */
+
debugmes "";
debugmes "* Tolchi mess cleanup";
+ debugmes "* Rebirth Hero";
debugmes "";
$UPDATE=1590616575;
}
diff --git a/npc/003-6/tamiloc.txt b/npc/003-6/tamiloc.txt
index b3924fbc2..912ad250e 100644
--- a/npc/003-6/tamiloc.txt
+++ b/npc/003-6/tamiloc.txt
@@ -10,11 +10,22 @@
003-6,46,30,0 script Tamiloc NPC_ELVEN_FEMALE_ARMOR_SHOP,{
function setRace {
clear;
- setnpcdialogtitle l("Debug - Modify Race");
- mes l("Race") + ": " + $@allraces$[Class];
+ setnpcdialogtitle l("Tamiloc - Modify Race");
+ mes l("Race") + ": " + get_race();
next;
mes l("Please select the desired race.");
- switch (select("Human:MedHuman:DarHuman:Elf:Orc:Raijin:Tritan:Ukar:Redy:Savior"))
+ 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);
diff --git a/npc/005-4/tolchi.txt b/npc/005-4/tolchi.txt
index 5c905c17c..a6608acff 100644
--- a/npc/005-4/tolchi.txt
+++ b/npc/005-4/tolchi.txt
@@ -383,6 +383,6 @@ OnInit:
initnpctimer;
.distance = 5;
- setarray .disallow_equip, 0, SponsorNecklace, Event1HSword, Event2HSword, EventBow, EventWand, Lightbringer, DemureAxe, Tyranny, Runestaff, AegisShield, BlacksmithAxe, Dustynator, SaviorShield, SaviorArmor, SaviorPants, SaviorBoots, CreasedShirt, CreasedShorts;
+ setarray .disallow_equip, 0, SponsorNecklace, Event1HSword, Event2HSword, EventBow, EventWand, Lightbringer, DemureAxe, Tyranny, Runestaff, AegisShield, BlacksmithAxe, Dustynator, SaviorShield, SaviorArmor, SaviorPants, SaviorBoots, Skypiercer, CreasedShirt, CreasedShorts;
end;
}
diff --git a/npc/005-6/morgan.txt b/npc/005-6/morgan.txt
index 692f7e3b0..3647b50eb 100644
--- a/npc/005-6/morgan.txt
+++ b/npc/005-6/morgan.txt
@@ -79,20 +79,20 @@ L_MagicCore:
break;
case 3:
mesn;
- mesq l("Sure! But that is Mana Magic. Just bring me a mug of beer, I'm thristy. And I'll teach you a basic skill.");
+ mesq l("Sure! But that is Summon Magic. Just bring me a mug of beer, I'm thristy. And I'll teach you a basic skill.");
next;
if (askyesno() == ASK_YES) {
if (!countitem(Beer)) goto L_Cheat;
delitem Beer, 1;
skill(TMW2_KALMURK,1,0);
mesn;
- mesq l("You can use @@ to summon some maggots. That depends on your magic level, of course.", b("@sk-kalmurk"));
+ mesq l("You can use @@ to summon some maggots. That depends on your magic level, of course.", b("Kalmurk"));
next;
mesn;
- mesq l("That's a Mana Magic. It is very different from regular magic. For example, it have an experience meter and an alias you can say.");
+ mesq l("That's a Summon Magic. Unlike regular magic, you can increase its levels directly from skill menu (F5).");
next;
mesn;
- mesq l("If you don't have a @@, you can only track progress on Mana Magic using @@, and you won't really gain any mana experience for a while.", getitemlink(JesusalvaGrimorium), b("@sk-abizit"));
+ mesq l("Keep in mind the more power you have, the less control you'll have as well. Until you get a %s to track progress, use %s to check your control. Less control may result in failure to summon!", getitemlink(JesusalvaGrimorium), b("@abizit"));
next;
mesn;
mesq l("By the way, you need a couple of @@ to try the skill. Fail rate is pretty high if you don't know how to control your magic.", getitemlink(MaggotSlime));
@@ -106,7 +106,7 @@ L_MagicCore:
mesq l("This means everytime you get more power, you lose control. Pratice is the key.");
next;
mesn;
- mesq l("Try praticing with different mana magic skills. Anyway, you can use this command to see your magic proeficiency: " + b("@sk-abizit"));
+ mesq l("Try praticing with different mana magic skills. Anyway, you can use this command to see your magic proeficiency: " + b("@abizit"));
break;
default:
close;
diff --git a/npc/008-2/_config.txt b/npc/008-2/_config.txt
new file mode 100644
index 000000000..ce9c7ad2b
--- /dev/null
+++ b/npc/008-2/_config.txt
@@ -0,0 +1,99 @@
+// This file is generated automatically. All manually added changes will be removed when running the Converter.
+// Map 008-2: 2nd Floor - Party Dungeon conf
+
+008-2,80,208,0 script #008-2_80_208 NPC_HIDDEN,{
+ end;
+OnDisable:
+ delcells "008-2_80_208"; end;
+OnEnable:
+OnInit:
+ setcells "008-2", 80, 208, 88, 208, 3, "008-2_80_208";
+}
+
+// FIXME: Either let flip/unflip, or only run once.
+// This could be done with a new attribute and checking NPC display when only run once.
+008-2,106,237,0 script #008-2_106_237 NPC_SWITCH_ONLINE,{
+ callfunc "massprovoke", 12;
+ setnpcdisplay "#008-2_106_237", NPC_SWITCH_OFFLINE;
+ end;
+OnInit:
+ .distance=2;
+}
+
+// FIXME: Either let flip/unflip, or only run once.
+// This could be done with a new attribute and checking NPC display when only run once.
+008-2,66,143,0 script #008-2_66_143 NPC_SWITCH_OFFLINE,{
+ callfunc "grenade", 12, 10000;
+ setnpcdisplay "#008-2_66_143", NPC_SWITCH_ONLINE;
+ end;
+OnInit:
+ .distance=2;
+}
+
+// FIXME: Either let flip/unflip, or only run once.
+// This could be done with a new attribute and checking NPC display when only run once.
+008-2,111,166,0 script #008-2_111_166 NPC_SWITCH_ONLINE,{
+ callfunc "ALCReset";
+ setnpcdisplay "#008-2_111_166", NPC_SWITCH_OFFLINE;
+ end;
+OnInit:
+ .distance=2;
+}
+
+008-2,135,21,0 script #008-2_135_21 NPC_HIDDEN,2,1,{
+ end;
+OnTouch:
+ callfunc "massprovoke", 12;
+ end;
+}
+
+008-2,54,237,0 script #008-2_54_237 NPC_HIDDEN,2,1,{
+ end;
+OnTouch:
+ doevent "#008-2_80_208::OnDisable";
+ end;
+}
+
+008-2,72,247,0 script #008-2_72_247 NPC_TRAP_ONLINE,0,0,{
+ mesn strcharinfo(0);
+ mesq l("Something seems off with that!");
+ close;
+OnTouch:
+OnTouchNPC:
+ IronTrap(200, 0, 1);
+ end;
+}
+
+008-2,87,240,0 script #008-2_87_240 NPC_TRAP_ONLINE,0,0,{
+ mesn strcharinfo(0);
+ mesq l("Something seems off with that!");
+ close;
+OnTouch:
+OnTouchNPC:
+ IronTrap(200, 0, 1);
+ end;
+}
+
+008-2,46,211,0 script #008-2_46_211 NPC_TRAP,0,0,{
+ mesn strcharinfo(0);
+ mesq l("Something seems off with that!");
+ close;
+OnTouch:
+OnTouchNPC:
+ IronTrap(200, 10, 2);
+ end;
+OnTimer10000:
+ stopnpctimer; setnpctimer 0; setnpcdisplay "#008-2_46_211", NPC_TRAP; end;
+}
+
+008-2,85,117,0 script #008-2_85_117 NPC_TRAP,0,0,{
+ mesn strcharinfo(0);
+ mesq l("Something seems off with that!");
+ close;
+OnTouch:
+OnTouchNPC:
+ IronTrap(400, 15, 3);
+ end;
+OnTimer15000:
+ stopnpctimer; setnpctimer 0; setnpcdisplay "#008-2_85_117", NPC_TRAP; end;
+}
diff --git a/npc/008-2/_import.txt b/npc/008-2/_import.txt
index 6e2d0d90a..12a069214 100644
--- a/npc/008-2/_import.txt
+++ b/npc/008-2/_import.txt
@@ -1,5 +1,6 @@
// Map 008-2: 2nd Floor - Party Dungeon
// This file is generated automatically. All manually added changes will be removed when running the Converter.
+"npc/008-2/_config.txt",
"npc/008-2/_mobs.txt",
"npc/008-2/_warps.txt",
"npc/008-2/master.txt",
diff --git a/npc/017-10/dispatcher.txt b/npc/017-10/dispatcher.txt
index f4d880a0f..86a0e4c44 100644
--- a/npc/017-10/dispatcher.txt
+++ b/npc/017-10/dispatcher.txt
@@ -308,8 +308,8 @@ function lootField {
TinOre, max(1, .@lv/5), 350,
LeadOre, max(1, .@lv/6), 300,
TitaniumOre, max(1, .@lv/8), 100,
- IridiumOre, max(1, .@lv/10), 80,
- PlatinumOre, 1, 20);
+ (REBIRTH ? IridiumOre : TitaniumOre), max(1, .@lv/10), 80,
+ (REBIRTH ? PlatinumOre : IridiumOre), 1, 20);
break;
case HCD_RAREMINES:
.@val+=15;
diff --git a/npc/018-5-4/elder.txt b/npc/018-5-4/elder.txt
index 829e0894b..7d148b913 100644
--- a/npc/018-5-4/elder.txt
+++ b/npc/018-5-4/elder.txt
@@ -3,11 +3,17 @@
// dangerDuck
// Description:
// Duck Elder is a friendly npc.
-// May eventually implement a quest that needs Duck Feathers
-// Variable:
-// none
+// The first stage of the Elder's quest consists of a supply restock
+// Second stage of the quest will be a pirate attack (WIP)
+// Third stage will consist of planting mage acorns around the island (WIP)
+// Variables:
+// LilitQuest_PiratesOfSARAH
018-5-4,28,73,0 script Duck Elder NPC_DUCK_ELDER,{
+ function elderQuest;
+ function elderSupplyList;
+ function elderSupplyGive;
+ function elderPirateAttack;
function elderAbout;
function elderAboutSarah;
function elderClose;
@@ -15,19 +21,134 @@
mesq l("Hello %s. What brings you here?", get_race());
next;
select
+ l("I've heard tidings of strange goings-on in this area..."),
l("Oh, I'm just exploring. What can you tell me about this island?"),
l("I came to enjoy a beautiful day with some ducks!");
mes "";
switch (@menu) {
case 1:
+ elderQuest();
+ break;
+ case 2:
elderAbout();
// fallthrough
- case 2:
+ case 3:
elderClose();
break;
}
close;
+function elderQuest {
+ if(BaseLevel < 50) {
+ mesn;
+ mesq l("Unfortunately, a mere fledgling like you is not strong enough to help us.");
+ next;
+ elderClose();
+ return;
+ }
+ .@q = getq(LilitQuest_PiratesOfSARAH);
+ switch (.@q) {
+ case 0:
+ mesn;
+ mesq l("Your information is correct, %s. Pirates have been plaguing our shores and cutting off our supply lines.", get_race());
+ next;
+ mesn;
+ mesq l("We are in desperate need of food and nesting material, as well as our sacred supply of @@.", getitemlink(CrystallizedMaggot));
+ next;
+ setq LilitQuest_PiratesOfSARAH, 1;
+ elderSupplyList();
+ break;
+ case 1:
+ mesn;
+ mesq l("Did you bring the supplies?");
+ next;
+ select
+ l("Yes, I have them right here."),
+ l("What did you want? I've forgotten."),
+ l("Not yet. I've been... delayed.");
+ mes "";
+ switch (@menu) {
+ case 1:
+ elderSupplyGive();
+ break;
+ case 2:
+ elderSupplyList();
+ break;
+ case 3:
+ close;
+ break;
+ }
+ break;
+ case 2:
+ elderPirateAttack();
+ break;
+ case 3:
+ break;
+ }
+ close;
+ return;
+}
+
+function elderSupplyList {
+ mesq "";
+ mesn;
+ mesq l("We need:");
+ mesq l("%d/%d %s", countitem(Moss), 300, getitemlink(Moss));
+ mesq l("%d/%d %s", countitem(RoastedMaggot), 250, getitemlink(RoastedMaggot));
+ mesq l("%d/%d %s", countitem(FishBox), 20, getitemlink(FishBox));
+ mesq l("%d/%d %s", countitem(CrystallizedMaggot), 1, getitemlink(CrystallizedMaggot));
+ next;
+ mesq l("Of course, we'll find a way to reward you for your efforts.");
+ return;
+}
+
+function elderSupplyGive {
+ if (countitem(Moss) < 300 ||
+ countitem(RoastedMaggot) < 250 ||
+ countitem(FishBox) < 20 ||
+ countitem(CrystallizedMaggot) < 1) {
+ mesn;
+ mesq l("This isn't what we requested. Perhaps you should count your items more carefully.");
+ next;
+ mesn;
+ mesq l("If you aren't more careful, we might... accidentally... mistake you for an agent of S.A.R.A.H.");
+ percentheal -99, 0;
+ close;
+ }
+ inventoryplace RubberDucky, 1;
+
+ delitem(Moss, 300);
+ delitem(RoastedMaggot, 250);
+ delitem(FishBox, 20);
+ delitem(CrystallizedMaggot, 1);
+
+ getitem(RubberDucky, 1);
+ getexp(34576, 19226);
+ setq(LilitQuest_PiratesOfSARAH, 2);
+
+ mes "";
+ mesn;
+ mesq l("We appreciate your help. Take this %s as a token of goodwill.", getitemlink(RubberDucky));
+ next;
+ mesn;
+ mesq l("If you're ever in need, you may use it to call upon the aid of the ducks.");
+ next;
+ if(BaseLevel < 75) {
+ mesn;
+ mesq l("Go now, with the blessing of ducks. There may come a time when we require your aid once again, O %s.", get_race());
+ } else {
+ mesn;
+ mesq l("We may require your aid again soon. The tritan pirates are amassing and we fear they are planning a siege of Duck Island. I must speak with the council...");
+ }
+ close;
+}
+
+function elderPirateAttack {
+ mesn;
+ mesq l("The tritan pirates amass for their siege, but they will not attack yet. Return later. King DD is working to find a solution.");
+ close;
+}
+
function elderAbout {
mesn;
mesq l("This is Duck Island, the last safe refuge for birds. Ducks tend to be very peaceful, but our young ruler, King DD, has been taken up with the art of war.");
@@ -49,7 +170,7 @@ function elderAboutSarah {
mesq l("As I said, S.A.R.A.H. is a terrorist organization. They are dedicated to wiping out every single duck, worldwide. No duck has ever survived an encounter with a S.A.R.A.H. agent. You would do best to avoid them.");
next;
mesn;
- mesq l("I suggest you leave now, %s. If you are even suspected of being a S.A.R.A.H. agent . . .", get_race());
+ mesq l("I suggest you leave now, %s. If you are even suspected of being a S.A.R.A.H. agent...", get_race());
close;
return;
}
@@ -59,7 +180,11 @@ function elderClose {
mesq l("Enjoy your time here, %s. And keep your eye out for agents of S.A.R.A.H.", get_race());
next;
mesn;
- mesq l("Perhaps you may be of assistance later . . .");
+ if (BaseLevel < 50) {
+ mesq l("Perhaps you may be of assistance later...");
+ } else {
+ mesq l("I may have a task for you. Return when you tired of exploring...");
+ }
close;
return;
}
diff --git a/npc/024-11/politics.txt b/npc/024-11/politics.txt
index ce83a920a..efb7fcb80 100644
--- a/npc/024-11/politics.txt
+++ b/npc/024-11/politics.txt
@@ -12,7 +12,10 @@ do
{
mesc ".:: "+l("Frostia Townhall")+" ::.", 2;
mesc l("Current Town Administrator: ")+$FROSTIA_MAYOR$, 3;
- mesc l("Only elves may run to Town Admin Office in Frostia!"), 1;
+ if (Class != Elven)
+ mesc l("Only elves may run to Town Admin Office in Frostia!"), 1;
+ else
+ mesc l("Hey, you're an elf, cool! But you still cannot run for office here!"), 1;
close;
POL_TownInfo("FROSTIA");
mesc l("Application fee: @@ GP", .applytax);
diff --git a/npc/024-16/craftsman.txt b/npc/024-16/craftsman.txt
index d934d2b05..00171a42d 100644
--- a/npc/024-16/craftsman.txt
+++ b/npc/024-16/craftsman.txt
@@ -23,19 +23,20 @@
mesq l("...Unless, of course, if you're interested in learning this art. You'll not regret it, I assure you.");
next;
// Main Loop
+ .@score=CRAFTING_SCORE_COMPLETE%40;
mesc l("Crafting Skill Level: @@", getskilllv(TMW2_CRAFT));
- msObjective(CRAFTING_SCORE>=calcRequisites(),
- l("Completed Crafts: @@/@@", CRAFTING_SCORE, calcRequisites()) );
+ msObjective(.@score >= calcRequisites(),
+ l("Completed Crafts: @@/@@", .@score, calcRequisites()) );
msObjective(Zeny >= calcPrices(),
l("Money: @@ GP", format_number(Zeny)) );
// Script end
- if (getskilllv(TMW2_CRAFT) >= 6)
+ if (getskilllv(TMW2_CRAFT) > 6)
close;
mes "";
select
- rif(!CRAFTING_SCORE, l("How can I complete a craft?")),
- rif(CRAFTING_SCORE >= calcRequisites(), l("Learn crafting for @@ GP", format_number(calcPrices())) ),
- rif(CRAFTING_SCORE, l("How can I complete a craft?")),
+ rif(!.@score, l("How can I complete a craft?")),
+ rif(.@score >= calcRequisites(), l("Learn crafting for @@ GP", format_number(calcPrices())) ),
+ rif(.@score, l("How can I complete a craft?")),
l("Nothing for now, thanks.");
mes "";
switch (@menu) {
@@ -85,9 +86,9 @@ function calcRequisites {
case 4:
return 18;
case 5:
- return 24;
- case 6:
return 32;
+ case 6:
+ return 64;
}
return -1;
}
@@ -121,9 +122,9 @@ function calcUpgrade {
.@cf=calcRequisites();
if (Zeny < .@gp)
return false;
- if (CRAFTING_SCORE < .@cf)
+ if (CRAFTING_SCORE_COMPLETE % 40 < .@cf)
return false;
- if (.@cf < 0)
+ if (.@cf < 0 || .@gp < 0)
return false;
// You may get a free blueprint
@@ -155,6 +156,10 @@ function calcUpgrade {
inventoryplace EquipmentBlueprintE, 1;
getitem EquipmentBlueprintE, 1;
break;
+ case 5:
+ inventoryplace AncientBlueprint, 1;
+ getitem AncientBlueprint, 1;
+ break;
default:
getexp 1700, 200;
break;
diff --git a/npc/025-2/phoenix.txt b/npc/025-2/phoenix.txt
index 0989300ca..6e1d64d19 100644
--- a/npc/025-2/phoenix.txt
+++ b/npc/025-2/phoenix.txt
@@ -84,14 +84,22 @@
STATUSUP_INT+=2;
STATUSUP_DEX+=2;
STATUSUP_LUK+=2;
- REBIRTH_OVERLEVEL=max(0, BaseLevel-.@blvl);
+ REBIRTH_OVERLEVEL=max(0, BaseLevel-.@blvl-(REBIRTH_OVERLEVEL/REBIRTH));
resetlvl(3);
NewcomerEXPDROPUP();
getitembound SupremeGift, 1, 4;
warp "005-1", 40, 117;
LOCATION$="Candor";
kamibroadcast(strcharinfo(0)+" has been reborn.");
- //$MOST_HEROIC$=strcharinfo(0);
+ // Maybe you were THE FIRST
+ if ($REBIRTH_WINNER$ == "") {
+ $REBIRTH_WINNER$=strcharinfo(0);
+ channelmes("#world", $REBIRTH_WINNER$+" is the first player to REBIRTH!! They are so OP! %%N");
+ announce "All hail ##B"+$REBIRTH_WINNER$+"##b, first player to REBIRTH and become OP!", bc_all|bc_npc;
+ getitem SupremeGift, 1;
+ next;
+ }
+ // These operations can be delayed or fail
StatusResetReinvest();
// Open a new dialog
clear;
@@ -165,14 +173,17 @@
}
next;
menuint
- l("Human"), 0,
+ l("Kaizei Human"), 0,
rif(REBIRTH >= 1, l("Elven")), 3,
rif(REBIRTH >= 1, l("Tritan")), 6,
rif(REBIRTH >= 2, l("Raijin")), 5,
rif(REBIRTH >= 2, l("Orc")), 4,
rif(REBIRTH >= 3, l("Ukar")), 7,
rif(REBIRTH >= 3, l("Redy")), 8,
- rif(REBIRTH >= 5, l("Savior")), 9;
+ rif(REBIRTH >= 5, l("Savior")), 9,
+ l("Argaes Human"), 1,
+ l("Tonori Human"), 2,
+ l("Don't change race"), Class;
jobchange max(0, @menuret);
close;
diff --git a/npc/commands/super-menu.txt b/npc/commands/super-menu.txt
index 2909ea31b..2ce9c6f5b 100644
--- a/npc/commands/super-menu.txt
+++ b/npc/commands/super-menu.txt
@@ -117,39 +117,47 @@ OnInit:
end;
// Servers with "debug" set are debug servers which must reset on their own
+// Hardcore servers as well
// They restart every sunday, at 03:00 UTC
OnSun0250:
- if (debug) kamibroadcast("WARNING: Test Server will go down for scheduled maintenance in 10 minutes!");
+ .@sv$=(debug ? "Test" : "Hardcore");
+ if (debug || $HARDCORE) kamibroadcast("WARNING: "+.@sv$+" Server will go down for scheduled maintenance in 10 minutes!");
end;
OnSun0255:
- if (debug) kamibroadcast("WARNING: Test Server will go down for scheduled maintenance in 5 minutes!");
+ .@sv$=(debug ? "Test" : "Hardcore");
+ if (debug || $HARDCORE) kamibroadcast("WARNING: "+.@sv$+" Server will go down for scheduled maintenance in 5 minutes!");
end;
OnSun0259:
- if (debug) kamibroadcast("WARNING: Imminent Test Server restart!");
+ .@sv$=(debug ? "Test" : "Hardcore");
+ if (debug || $HARDCORE) kamibroadcast("WARNING: Imminent "+.@sv$+" Server restart!");
end;
OnSun0300:
- if (debug) atcommand("@serverexit 103");
+ if (debug || $HARDCORE) atcommand("@serverexit 103");
end;
-// Hardcore Servers also need to reset, but with less frequency
-// They restart on the first monday of the month, at 03:00 UTC
+// Live Servers also need to reset, but with less frequency
+// They restart on the first wednesday of the month, at 03:00 UTC
// Note: We can use gettimeparam - weeks since epoch - and restart every
// 2 weeks if needed. (weeks % 2 == 1)
-OnMon0250:
- if (!$HARDCORE || gettime(GETTIME_DAYOFMONTH) > 7) end;
- kamibroadcast("WARNING: Hardcore Server will go down for scheduled maintenance in 10 minutes!");
+OnWed0245:
+ if (!$AUTORESTART || gettime(GETTIME_DAYOFMONTH) > 7) end;
+ kamibroadcast("WARNING: Server will go down for scheduled maintenance in 15 minutes!");
+ end;
+OnWed0250:
+ if (!$AUTORESTART || gettime(GETTIME_DAYOFMONTH) > 7) end;
+ kamibroadcast("WARNING: Server will go down for scheduled maintenance in 10 minutes!");
end;
OnMon0255:
- if (!$HARDCORE || gettime(GETTIME_DAYOFMONTH) > 7) end;
- kamibroadcast("WARNING: Hardcore Server will go down for scheduled maintenance in 5 minutes!");
+ if (!$AUTORESTART || gettime(GETTIME_DAYOFMONTH) > 7) end;
+ kamibroadcast("WARNING: Server will go down for scheduled maintenance in 5 minutes!");
end;
OnMon0259:
- if (!$HARDCORE || gettime(GETTIME_DAYOFMONTH) > 7) end;
- kamibroadcast("WARNING: Imminent Hardcore Server restart!");
+ if (!$AUTORESTART || gettime(GETTIME_DAYOFMONTH) > 7) end;
+ kamibroadcast("WARNING: Imminent Server restart!");
end;
OnMon0300:
- if (!$HARDCORE || gettime(GETTIME_DAYOFMONTH) > 7) end;
+ if (!$AUTORESTART || gettime(GETTIME_DAYOFMONTH) > 7) end;
atcommand("@serverexit 103");
end;
diff --git a/npc/config/hairstyle_config.txt b/npc/config/hairstyle_config.txt
index c55585393..0d594e9e5 100644
--- a/npc/config/hairstyle_config.txt
+++ b/npc/config/hairstyle_config.txt
@@ -23,6 +23,6 @@ OnInit:
"Silver Grey", "Imperial Blue";
setarray $@allraces$[0], "Human", "Human", "Human", "Elf", "Orc",
- "Raijin", "Tritan", "Ukar", "Redy";
+ "Raijin", "Tritan", "Ukar", "Redy", "Savior";
end;
}
diff --git a/npc/config/magic.txt b/npc/config/magic.txt
index b627c30ab..da1484ef3 100644
--- a/npc/config/magic.txt
+++ b/npc/config/magic.txt
@@ -112,6 +112,34 @@ function script SummonMagic {
return;
}
+// areaharm(target, range, DMG, {type, element, filter, bl})
+// Defaults to HARM_MISC, Ele_Neutral, filter filter_hostile and all BLs
+// Valid BL: BL_MOB | BL_PC | BL_HOM | BL_MER
+// Do not use: NPC, PET, ELEM
+// Range centers on caster (player), implement and use areaharm2 elsewhere
+function script areaharm {
+ .@t=getarg(0);
+ .@r=getarg(1);
+ .@d=getarg(2);
+ .@h=getarg(3, HARM_MISC);
+ .@e=getarg(4, Ele_Neutral);
+ .@f$=getarg(5, "filter_hostile");
+ .@b=getarg(6, BL_PC | BL_MOB | BL_MER | BL_HOM);
+
+ 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;
+ harm(.@mbs[.@i], .@d, .@t, .@e);
+ specialeffect(FX_ATTACK, AREA, .@mbs[.@i]);
+ // TODO: Handle MobPt to don't overload timer system?
+ }
+ return;
+}
+
// mescordialog(text, color, {dialog=1})
function script mescordialog {
if (getarg(2, true))
@@ -151,6 +179,10 @@ function script SK_summon {
.@mex=getarg(2);
if ($@GM_OVERRIDE || debug) debugmes "Skill "+@skillId+" Lv "+@skillLv;
+ // Blocked from summoning magic
+ if (alignment() < 0 && !isequippedcnt(AegisShield))
+ return;
+
if (rand2(5) < abizit()) {
// Summon Magic (with magic level bonus)
SummonMagic(@skillId, .@mob, .@amt, MAGIC_LVL+@skillLv-1, @skillLv);
diff --git a/npc/config/traps.txt b/npc/config/traps.txt
new file mode 100644
index 000000000..1b43e5cc7
--- /dev/null
+++ b/npc/config/traps.txt
@@ -0,0 +1,82 @@
+// TMW2 Scripts
+// Author:
+// The Mana World Brazil
+// Jesusalva
+// Description:
+// Traps and other functions.
+
+// SteelTrap( {damage=80%}, {delay=15s}, {stun=3s}, {npcname=auto} )
+function script SteelTrap {
+ .@dmg=getarg(0, 80);
+ .@delay=getarg(1, 15);
+ .@stun=getarg(2, 3);
+ .@n$=getarg(3, strnpcinfo(0));
+
+ // It was disarmed
+ if (getnpctimer(0) == 0)
+ {
+ initnpctimer;
+ setnpcdisplay .@n$, NPC_TRAP_ONLINE;
+ return;
+ }
+
+ // Fire!!
+ setnpctimer 9000;
+ setnpcdisplay .@n$, NPC_TRAP_TRIGGERED;
+
+ // Boom - Hurt players and/or stun monsters
+ // This means you can - and SHOULD - lead Forains into these traps
+ if (playerattached())
+ {
+ percentheal -(.@dmg), 0;
+ }
+ else
+ {
+ .@stun*=1000;
+ sc_start SC_WALKSPEED,(.@delay*1000),60;
+ sc_start SC_STUN,rand(.@stun,.@stun*3),0;
+ }
+
+ // A minor special effect and we're done.
+ specialeffect 11;
+ return;
+}
+
+
+// Unlike SteelTrap, presents same behavior and absolute damage
+// IronTrap( {damage=100}, {delay=15s}, {stun=3s}, {npcname=auto} )
+function script IronTrap {
+ .@dmg=getarg(0, 100);
+ .@delay=getarg(1, 15);
+ .@stun=getarg(2, 3);
+ .@n$=getarg(3, strnpcinfo(0));
+
+ // It was disarmed
+ if (getnpctimer(0) == 0 && .@delay)
+ {
+ initnpctimer;
+ setnpcdisplay .@n$, NPC_TRAP_ONLINE;
+ return;
+ }
+
+ // Fire!!
+ setnpctimer 9000;
+ setnpcdisplay .@n$, NPC_TRAP_TRIGGERED;
+
+ // Boom - Hurt and Stun (only works on players and mobs)
+ .@stun*=1000;
+ sc_start SC_STUN, rand2(.@stun,.@stun*3), 0;
+ .@gid=(playerattached() ? playerattached() : mobattached());
+
+ // Just to be sure
+ if (.@gid)
+ harm(.@gid, .@dmg, HARM_MISC);
+ else
+ Exception("IronTrap \""+.@n$+"\" called without GID!", RB_DEBUGMES);
+
+ // A minor special effect and we're done.
+ specialeffect 11;
+ return;
+}
+
+
diff --git a/npc/craft/options.txt b/npc/craft/options.txt
index 947a5c8ca..6d572f5bd 100644
--- a/npc/craft/options.txt
+++ b/npc/craft/options.txt
@@ -387,10 +387,9 @@ function script csys_Multiplier {
case VAR_CRITICALRATE:
case DEC_SP_CONSUMPTION:
case VAR_PLUSASPDPERCENT:
- return 5;
case VAR_MAGICATKPERCENT:
case VAR_ATKPERCENT:
- return 7;
+ return 5;
case IOPT_SCRESIST_POISON:
case IOPT_SCRESIST_SILENCE:
case IOPT_SCRESIST_CURSE:
@@ -409,7 +408,7 @@ function script csys_Multiplier {
// Remove problematic bonuses from armors
// Use getiteminfo before
-// csys_ArmorFix( - )
+// csys_ArmorFix( item )
function script csys_ArmorFix {
// Rare bonus
if (rand2(100) >= 5)
@@ -427,7 +426,43 @@ function script csys_ArmorFix {
array_remove(@csys_penalty, VAR_MDEFPOWER);
// Save for csys_BonusCalc
- @csysArmor=true;
+ @csysArmor=CSYS_ARMOR;
+
+ // Special sets
+ if (compare("savior", strtolower(getitemname(getarg(0)))))
+ @csysArmor=@csysArmor|CSYS_SAVIOR;
+ return;
+}
+
+// Update problematic bonuses for weapons
+// Use getiteminfo before
+// csys_WeaponFix( {item} )
+function script csys_WeaponFix {
+ .@sub=getiteminfo(getarg(0,Acorn), ITEMINFO_SUBTYPE);
+ @csysArmor=0;
+
+ // Weapon Subtype
+ if (.@sub == W_FIST || .@sub == W_KNUCKLE)
+ @csysArmor=@csysArmor|CSYS_BRAWLING;
+ else if (.@sub == W_2HSWORD || .@sub == W_2HSPEAR ||
+ .@sub == W_2HAXE || .@sub == W_2HMACE ||
+ .@sub == W_2HSTAFF)
+ @csysArmor=@csysArmor|CSYS_ZWEIHANDER;
+ else if (.@sub == W_BOW || .@sub == W_REVOLVER ||
+ .@sub == W_RIFLE || .@sub == W_GATLING ||
+ .@sub == W_SHOTGUN || .@sub == W_GRENADE)
+ @csysArmor=@csysArmor|CSYS_RANGED;
+ else if (.@sub == W_STAFF || .@sub == W_BOOK)
+ @csysArmor=@csysArmor|CSYS_MAGICAL;
+ else if (.@sub == W_KATAR)
+ @csysArmor=@csysArmor|CSYS_SPECIAL;
+ else
+ @csysArmor=@csysArmor|CSYS_OTHER;
+
+ // Special sets
+ if (compare("savior", strtolower(getitemname(getarg(0)))))
+ @csysArmor=@csysArmor|CSYS_SAVIOR;
+
return;
}
@@ -449,8 +484,32 @@ function script csys_BonusCalc {
if (.@base >= (.@avg+1)*7/10)
.@base=rand2(1, .@avg+1);
- // Armor? Crap it to 25%
- if (@csysArmor)
+ // Savior Set? Effects +20%
+ if (@csysArmor & CSYS_SAVIOR)
+ .@base=max(1, .@base*6/5);
+
+ // Attack for 2H?
+ if (.@var == VAR_ATKPERCENT || .@var == VAR_MAGICATKPERCENT) {
+ // Two Hands/Bows: x2
+ if ((@csysArmor & CSYS_ZWEIHANDER) || (@csysArmor & CSYS_RANGED))
+ .@base=max(1, .@base*2);
+ // Brawling/Magical: +80%
+ else if ((@csysArmor & CSYS_BRAWLING) || (@csysArmor & CSYS_MAGICAL))
+ .@base=max(1, .@base*18/10);
+ }
+
+ // Normal Attack for 2H?
+ if (.@var == VAR_ATTPOWER || .@var == VAR_ATTMPOWER) {
+ // Two Hands/Bows: +50%
+ if ((@csysArmor & CSYS_ZWEIHANDER) || (@csysArmor & CSYS_RANGED))
+ .@base=max(1, .@base*3/2);
+ // Brawling: +40%
+ else if (@csysArmor & CSYS_BRAWLING)
+ .@base=max(1, .@base*7/5);
+ }
+
+ // Armor? Cap it to 25%
+ if (@csysArmor & CSYS_ARMOR)
.@base=max(1, .@base/4);
return .@base;
@@ -472,10 +531,11 @@ function script csys_Apply {
// Remove weapon-only bonuses if it is armor
delinventorylist();
getinventorylist();
- if (getiteminfo(@inventorylist_id[.@id], ITEMINFO_TYPE) != IT_WEAPON)
- csys_ArmorFix();
+ .@itemid=@inventorylist_id[.@id];
+ if (getiteminfo(.@itemid, ITEMINFO_TYPE) != IT_WEAPON)
+ csys_ArmorFix(.@itemid);
else
- @csysArmor=false;
+ csys_WeaponFix(.@itemid);
// Shuffle the arrays
array_shuffle(@csys_attr);
diff --git a/npc/craft/recipes.txt b/npc/craft/recipes.txt
index 07c8625e1..45bc940f7 100644
--- a/npc/craft/recipes.txt
+++ b/npc/craft/recipes.txt
@@ -482,6 +482,11 @@ function readCrafting {
45, Coal,
32, IronPowder,
1, EarthPowder);
+ showRecipe(CraftSkyPiercer, Skypiercer,
+ 1, SunnyCrystal,
+ 5, PlatinumIngot,
+ 20, IridiumIngot,
+ 10, EverburnPowder);
next;
@scope$="";
return;
diff --git a/npc/craft/tweak.txt b/npc/craft/tweak.txt
index 023873068..131f34872 100644
--- a/npc/craft/tweak.txt
+++ b/npc/craft/tweak.txt
@@ -76,7 +76,8 @@ function script SmithTweakSystem {
// If the item have no bonuses - fail
setarray .@AlwaysTweaks, 65535, BlacksmithAxe, Dustynator, Lightbringer,
DemureAxe, Tyranny, Runestaff, AegisShield,
- SaviorShield, SaviorArmor, SaviorBoots, SaviorPants;
+ SaviorShield, SaviorArmor, SaviorBoots, SaviorPants,
+ Skypiercer;
// Tweaked items
if (getitemoptionidbyindex(.@id, 0) <= 0 && !is_master() && array_find(.@AlwaysTweaks, .@x) < 0) {
diff --git a/npc/functions/clientversion.txt b/npc/functions/clientversion.txt
index 16ea51286..344172d40 100644
--- a/npc/functions/clientversion.txt
+++ b/npc/functions/clientversion.txt
@@ -812,6 +812,55 @@ function script clientupdater {
}
}
+ // Magic v3
+ // dom jun 21 05:55:00 BRT 2020
+ if (UPDATE < 1592729700) {
+ UPDATE=1592729700;
+
+ if (getskilllv(TMW2_CRAFT) > 5) {
+ // Refund part of the money spent
+ Zeny+=35000+(getskilllv(TMW2_CRAFT) > 6 ? 40000 : 0);
+ // Update crafting
+ skill TMW2_CRAFT, 5, 0;
+ dispbottom l("Crafting rules changed! Your crafting skill was lowered to Level 5, talk to Craftmaster to recover it!");
+ }
+
+ // Rebirth Heroics
+ if (strcharinfo(0) == "Crazyfefe") {
+ getitem SupremeGift, 1;
+ channelmes("#world", $REBIRTH_WINNER$+" is the first player to REBIRTH!! They are so OP! %%N");
+ announce "All hail ##B"+$REBIRTH_WINNER$+"##b, first player to REBIRTH and become OP!", bc_all|bc_npc;
+ }
+
+ // Mass Provoke replacement
+ if (getskilllv(EVOL_AREA_PROVOKE)) {
+ getitembound ScholarshipBadge, getskilllv(EVOL_AREA_PROVOKE), 4;
+ MAGIC_PTS-=getskilllv(EVOL_AREA_PROVOKE)+1;
+ skill EVOL_AREA_PROVOKE, 0, 0;
+ dispbottom col(l("MSP for Area Provoke was refunded."), 1);
+ }
+ if (getskilllv(EVOL_MASS_PROVOKE)) {
+ skill EVOL_AREA_PROVOKE, getskilllv(EVOL_MASS_PROVOKE), 0;
+ skill EVOL_MASS_PROVOKE, 0, 0;
+ dispbottom col(l("Mass Provoke replaced with Area Provoke."), 1);
+ }
+
+ // MG_LIGHTNINGBOLT and TMW2_LIGHTNINGBOLT MSP cost differ, refund
+ if (getskilllv(MG_LIGHTNINGBOLT)) {
+ getitembound ScholarshipBadge, getskilllv(MG_LIGHTNINGBOLT), 4;
+ MAGIC_PTS-=getskilllv(MG_LIGHTNINGBOLT);
+ skill MG_LIGHTNINGBOLT, 0, 0;
+ dispbottom col(l("MSP for Lightning Strike was refunded."), 1);
+ }
+
+
+ // Eisten Update
+ if (getq(TulimsharQuest_Eistein) > 3) {
+ getitem GraduationAlbum, 1;
+ dispbottom l("You've got a Graduation Album for Eistein levels!");
+ }
+
+ }
// :// End of Regular Update System
////////////////////////////////////
diff --git a/npc/functions/filters.txt b/npc/functions/filters.txt
index cec7a15af..945ab8bce 100644
--- a/npc/functions/filters.txt
+++ b/npc/functions/filters.txt
@@ -62,6 +62,46 @@ function script filter_sameguildorpartynotyou {
return ((getcharid(1) > 0 && .@party) || (getcharid(2) > 0 && .@guild));
}
+// filter_hostile( id )
+function script filter_hostile {
+ //.@type=getunitdata(getarg(0), UDT_TYPE);
+ .@type=getunittype(getarg(0));
+ .@chkid=getarg(0);
+
+ // Monsters
+ if (.@type == UNITTYPE_MOB)
+ return true;
+
+ // NPCs
+ if (.@type == UNITTYPE_NPC)
+ return false;
+
+ // Homunculus
+ if (.@type == UNITTYPE_HOM)
+ .@chkid=charid2rid(getunitdata(getarg(0), UDT_MASTERCID));
+
+ // Pets
+ if (.@type == UNITTYPE_PET)
+ .@chkid=getunitdata(getarg(0), UDT_MASTERAID);
+
+ // Mercenaries
+ if (.@type == UNITTYPE_MER)
+ .@chkid=charid2rid(getunitdata(getarg(0), UDT_MASTERCID));
+
+ // Elementals
+ if (.@type == UNITTYPE_ELEM)
+ .@chkid=charid2rid(getunitdata(getarg(0), UDT_MASTERCID));
+
+ //debugmes "filter_hostile: Filtering %d (original %d) (BL %d)", .@chkid, getarg(0), .@type;
+ // Players (and slaves)
+ return !(filter_sameguildorparty(.@chkid));
+}
+
+// filter_friendly( id )
+function script filter_friendly {
+ return !(filter_hostile(.@chkid));
+}
+
// filter_notboss( id )
function script filter_notboss {
// 32 = MD_BOSS
diff --git a/npc/functions/hub.txt b/npc/functions/hub.txt
index 1e2711622..b1094faee 100644
--- a/npc/functions/hub.txt
+++ b/npc/functions/hub.txt
@@ -254,7 +254,10 @@ function script HUB_SkillInvoke {
SK_mpregen();
break;
case EVOL_AREA_PROVOKE:
- massprovoke(1+@skillLv);
+ if (@skillTargetX && @skillTargetY)
+ massprovoke(1+@skillLv, getmap(), @skillTargetX, @skillTargetY);
+ else
+ massprovoke(1+@skillLv);
GetManaExp(@skillId, rand2(1,3));
break;
case TMW2_GD_INCALL:
@@ -302,15 +305,28 @@ function script HUB_SkillInvoke {
debugmes "Target: %d (%d,%d)", @skillTarget, @skillTargetX, @skillTargetY;
areasc2(getmap(), @skillTargetX, @skillTargetY, 2, 10000, SC_BLOODING, BL_MOB|BL_PC);
.@dmg=AdjustSpellpower(300);
- harm(@skillTarget, .@dmg, HARM_MAGI, Ele_Holy);
+ //harm(@skillTarget, .@dmg, HARM_MAGI, Ele_Holy);
+ areaharm(@skillTarget, 8, .@dmg, HARM_MAGI, Ele_Holy);
break;
/*
+ case TMW2_MANABOMB:
+ // TODO: areaharm(1x1 or same square?)
+ // This skill takes 100% mana for a 1:1 ratio damage
+ // And is a trick. Each level improves ratio in 1
+ // Has no cooldown, so it is powerful with pots
+ // And is a good starter offensive skill
+ areaharm(@skillTarget, 0, Sp*@skillLv, HARM_MAGI, Ele_Ghost);
+ Sp=0;
+ break;
+
// Weapon Overload attack
case TMW2_OVERLOAD:
- .@PW=100+(50*@skillLv);
- harm(@skillTarget, AdjustAttackpower(.@PW), HARM_MISC);
+ .@PW=67+(33*@skillLv);
+ areaharm(@skillTarget, 0, AdjustAttackpower(.@PW), HARM_MISC);
break;
+ // TODO: Ultimate Skills (T5/0)
+
// Support magic
// TODO: Debuffs
// TODO: Buffs
@@ -325,14 +341,15 @@ function script HUB_SkillInvoke {
harm(@skillTarget, -AdjustSpellpower(.@PW), HARM_MISC);
break;
case TMW2_MAGNUSHEAL:
- // TODO: Area healing
+ // Area healing
.@PW=200+(20*@skillLv);
- harm(@skillTarget, -AdjustSpellpower(.@PW), HARM_MISC);
+ areaharm(@skillTarget, 4, -AdjustSpellpower(.@PW), HARM_MISC, "filter_friendly");
break;
// Provoke: builtin, Mass Provoke: See above
// Mana Wisdom: Passive, Accumulate Power: builtin
// FIXME: Windwalker, Last Standing Man
+ // TODO: Ressurection skill
// Destructive Magic
case TMW2_FIREARROW:
@@ -341,14 +358,12 @@ function script HUB_SkillInvoke {
break;
case TMW2_FIREBALL:
.@PW=140+(10*@skillLv);
- // TODO: areaharm()
- harm(@skillTarget, AdjustSpellpower(.@PW), HARM_MAGI, Ele_Fire);
+ areaharm(@skillTarget, 3, AdjustSpellpower(.@PW), HARM_MAGI, Ele_Fire);
break;
case TMW2_ARMAGEDDON:
.@PW=140+(10*@skillLv);
- // TODO: areaharm()
areasc2(getmap(), @skillTargetX, @skillTargetY, 2, 10000, SC_BLOODING, BL_MOB|BL_PC);
- harm(@skillTarget, AdjustSpellpower(.@PW), HARM_MAGI, Ele_Fire);
+ areaharm(@skillTarget, 8, AdjustSpellpower(.@PW), HARM_MAGI, Ele_Fire);
break;
case TMW2_FROSTDIVER:
@@ -362,17 +377,23 @@ function script HUB_SkillInvoke {
// TODO: All this in area
// 8% chance, 10s
sc_start SC_FREEZE, 10000, 1, 800, flag?, @skillTarget;
- harm(@skillTarget, AdjustSpellpower(.@PW), HARM_MAGI, Ele_Water);
+ areaharm(@skillTarget, 6, AdjustSpellpower(.@PW), HARM_MAGI, Ele_Water);
+ break;
+ case TMW2_NILFHEIM:
+ // FIXME SK_Nilfheim
+ // Nilfheim cast on self?
+ .@PW=80+(10*@skillLv);
+ areasc(8, 10000, SC_FREEZE, BL_PC | BL_MOB | BL_MER | BL_HOM, "filter_hostile"); // Maybe filter_notme() would work better, indeed
+ areaharm(getcharid(3), 8, AdjustSpellpower(.@PW), HARM_MAGI, Ele_Water);
break;
- // FIXME SK_Nilfheim
case TMW2_MAGICSTRIKE:
case TMW2_LIGHTNINGBOLT:
case TMW2_TEMPEST:
break;
- case TMW2_NAPALMBEAT:
case TMW2_HOLYLIGHT:
+ case TMW2_NAPALMBEAT:
case TMW2_JUDGEMENT:
break;
@@ -391,6 +412,9 @@ function script HUB_SkillInvoke {
case TMW2_BRAWLING:
// 75x3 = 225
.@PW=70+(5*@skillLv);
+ // Using a shield, so power is halved
+ if (getequipid(EQI_HAND_L) > 0)
+ .@PW=.@PW/2;
harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Neutral);
harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Neutral);
harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Neutral);
@@ -398,6 +422,9 @@ function script HUB_SkillInvoke {
case TMW2_BEARSTRIKE:
// 60x5 = 300
.@PW=55+(5*@skillLv);
+ // Using a shield, so power is halved
+ if (getequipid(EQI_HAND_L) > 0)
+ .@PW=.@PW/2;
harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Neutral);
harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Neutral);
harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Neutral);
@@ -407,6 +434,9 @@ function script HUB_SkillInvoke {
case TMW2_ALLINONE:
// 45x8 = 360
.@PW=40+(5*@skillLv);
+ // Using a shield, so power is halved
+ if (getequipid(EQI_HAND_L) > 0)
+ .@PW=.@PW/2;
harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Neutral);
harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Fire);
harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Water);
@@ -484,6 +514,12 @@ function script HUB_SkillInvoke {
}
SK_summon(.@mobId, 4, any(4,5));
break;
+ case TMW2_DUCKY:
+ if (alignment() < 0 && !isequippedcnt(AegisShield))
+ break;
+ SummonMagic(@skillId, Duck, 2, @skillLv);
+ GetManaExp(@skillId, 1);
+ break;
// Special exception
case TMW2_TRANSMIGRATION:
@@ -500,7 +536,6 @@ function script HUB_SkillInvoke {
case AL_HEAL:
case HW_MAGICPOWER:
case SM_PROVOKE:
- case EVOL_MASS_PROVOKE:
case AB_HIGHNESSHEAL:
case SN_WINDWALK:
case MG_FIREBALL:
diff --git a/npc/functions/mkbot.txt b/npc/functions/mkbot.txt
index 4304f8f0a..dae226812 100644
--- a/npc/functions/mkbot.txt
+++ b/npc/functions/mkbot.txt
@@ -41,7 +41,10 @@ OnBourneAgain:
channelmes("#world", strcharinfo(0)+" did an act worth of notice.");
dispbottom l("Oh well, this sucks, but that was only an illusion.");
dispbottom l("The real Monster King is probably on his fortress. It'll take more than that to take him down.");
- getexp BaseLevel**3, 0;
+ if ($REBIRTH_WINNER$ == "" && TOP3AVERAGELVL() < 100)
+ getexp min(641500, BaseLevel**3), 0;
+ else
+ Mobpt+=max(13500, rand2(10000, BaseLevel*90));
Mobpt = Mobpt + 165;
//$MOST_HEROIC$=strcharinfo(0);
}
diff --git a/npc/functions/mobpoint.txt b/npc/functions/mobpoint.txt
index 7b29ca155..49d742298 100644
--- a/npc/functions/mobpoint.txt
+++ b/npc/functions/mobpoint.txt
@@ -13,7 +13,8 @@ function script fix_mobkill {
function script mobpoint {
if (!MPQUEST)
return;
- //if (killedrid < 1002) goto L_Return;
+ if (!killedrid) // A bug!
+ return;
.@moblv=strmobinfo(3,killedrid);
// You get MobLv + 20% as MobPoints.
@@ -52,10 +53,6 @@ OnUnlock:
OnNPCKillEvent:
$MONSTERS_KILLED+=1;
- if (killedrid == MonsterKing) {
- announce "An illusionary monster king was killed.", bc_all | bc_pc;
- getexp min(641500, BaseLevel**3), 0;
- }
// Remove undue Job exp
// The check is probably correct, but setparam is not working =/
@@ -66,6 +63,10 @@ OnNPCKillEvent:
JobExp-=1;
}
+ // killedrid was not set, so we skip
+ if (!killedrid)
+ return;
+
// call functions
callfunc "mobpoint";
callfunc "mobhunter";
@@ -75,6 +76,8 @@ OnNPCKillEvent:
callfunc "Guardhouse_RandQuestCheck";
callfunc "AuroraMobkill";
+ // Unset killedrid. This affects multiple calls of this function
+ // But it is in overall more reliable imao
killedrid=0;
end;
diff --git a/npc/functions/scoreboards.txt b/npc/functions/scoreboards.txt
index 462bfcfcf..fb5f76130 100644
--- a/npc/functions/scoreboards.txt
+++ b/npc/functions/scoreboards.txt
@@ -523,6 +523,11 @@ function script HallOf2020 {
mesc l("This schedule is subject to change without prior notice."), 1;
mesc l("Changes include but are not limited to festive events and dates."), 1;
next;
+ if ($REBIRTH_WINNER$ != "") {
+ mes l(".:: FIRST PLAYER TO REBIRTH ::.");
+ mes $REBIRTH_WINNER$;
+ mes "";
+ }
mes l(".:: TMW-2 Anniversary ::.");
//mesc l("Scheduled: January 13rd");
mes l("No victor appliable.");
diff --git a/npc/functions/util.txt b/npc/functions/util.txt
index 624491d9a..45aa5fb7a 100644
--- a/npc/functions/util.txt
+++ b/npc/functions/util.txt
@@ -115,6 +115,17 @@ function script ReplaceItemFromEveryPlayer {
return;
}
+// Replaces a skill with another ID.
+// ReplaceSkillFromEveryPlayer( OldID, NewID )
+function script ReplaceSkillFromEveryPlayer {
+ if (getarg(0, -1) < 0)
+ return;
+ debugmes("* Server update: skill %d was replaced by %d", getarg(0), getarg(1));
+ // If new ID already exists, it will skip
+ query_sql("UPDATE IGNORE `skill` SET `id`='"+getarg(1)+"' WHERE `id`="+getarg(0));
+ return;
+}
+
/////////////////////////////////////////////////////////////////////////////////
// Returns Nard reputation for discounts
@@ -578,6 +589,22 @@ function script nard_time {
return INT_MAX;
}
+// alignment() → 1 if Good, -1 if Evil, 0 if Neutral
+function script alignment {
+ .@m=getq(HurnscaldQuest_InjuriedMouboo);
+
+ // Mouboo was slain: EVIL
+ if (.@m >= 9)
+ return -1;
+
+ // Mouboo was saved and Sagratha rescued: GOOD
+ if (SAGRATHA_FRIENDSHIP >= 2)
+ return 1;
+
+ // N/A: NEUTRAL
+ return 0;
+}
+
// Returns if an event is a ranked Aurora Event or not
// (Had to be moved from functions/aurora.txt)
function script FYEventUsesRanking {
@@ -962,6 +989,12 @@ function script MapToLoc {
return .@locs$[.@lx];
}
+// Returns TOP 3 Average Level
+// TOP3AVERAGELVL( - )
+function script TOP3AVERAGELVL {
+ return ($@hoblvl_value[0]+$@hoblvl_value[1]+$@hoblvl_value[2])/3;
+}
+
// Grants newcomers exp boost. Returns bonus %
// NewcomerEXPDROPUP( - )
function script NewcomerEXPDROPUP {
@@ -1034,3 +1067,12 @@ function script json_encode {
}
+// api_send( code, data )
+// sends to API
+function script api_send {
+ .@cde=getarg(0);
+ .@fm$=getarg(1);
+ query_sql("INSERT INTO `api_export` (`type`, `data`) VALUES ('"+.@cde+"', \""+.@fm$+"\")");
+ return;
+}
+
diff --git a/npc/items/alcohol.txt b/npc/items/alcohol.txt
index b171eedc9..374a4be31 100644
--- a/npc/items/alcohol.txt
+++ b/npc/items/alcohol.txt
@@ -112,7 +112,13 @@ OnUse:
// Sanitization, and nerf the debuff
.@min=(.@min/2)+1;
.@max=(.@max/2)+2;
+ // DEX and VIT may affect a tiny bit (there's caps)
+ .@pam=readparam2(bVit)+readparam2(bDex);
+ .@min=min(0, .@min*limit(50, 500-.@pam, 500)/500);
+ .@max=min(0, .@min*limit(100, 500-.@pam, 500)/500);
SC_Bonus(.@delay, SC_ATTHASTE_INFINITY, .@min, .@max);
+ if (debug || $@GM_OVERRIDE)
+ debugmes "Alcohol penalty: %d ~ %d for %d s", .@min, .@max, .@delay;
close;
}
diff --git a/npc/magic/dragokin.txt b/npc/magic/dragokin.txt
index 544859cce..4acbb0a5b 100644
--- a/npc/magic/dragokin.txt
+++ b/npc/magic/dragokin.txt
@@ -8,10 +8,14 @@
// Cooldown is cast duration
function script SK_Dragokin {
+ // Blocked from summoning magic
+ if (alignment() < 0)
+ return;
+
// Other requeriments: 5x Dragon Scale or Demure Axe
if (!(countitem(DragonScales) >= 4 || countitem(DemureAxe))) {
dispbottom l("You need 4x @@ to cast this skill.", getitemlink(DragonScales));
- end;
+ return;
}
// Setup
@@ -22,7 +26,7 @@ function script SK_Dragokin {
// Check if you have mana to cast
// MagicCheck(SkillID, Mana{, MP per level})
if (!MagicCheck(@sk, @mp, @amp))
- end;
+ return;
// Destroy reagents
if (!countitem(DemureAxe))
diff --git a/npc/magic/plantkingdom.txt b/npc/magic/plantkingdom.txt
index 2ee9e314e..0ed87b3b5 100644
--- a/npc/magic/plantkingdom.txt
+++ b/npc/magic/plantkingdom.txt
@@ -9,6 +9,10 @@
end;
OnCall:
+ // Blocked from summoning magic
+ if (alignment() < 0)
+ return;
+
// Other requeriments: 2x Root
if (countitem(Root) < 2) {
dispbottom l("You need 2x @@ to cast this skill.", getitemlink(Root));
diff --git a/npc/scripts.conf b/npc/scripts.conf
index 3fdf0aada..79e2b0e80 100644
--- a/npc/scripts.conf
+++ b/npc/scripts.conf
@@ -35,6 +35,7 @@
// config script
"npc/config/hairstyle_config.txt",
+"npc/config/traps.txt",
"npc/config/magic.txt",
// Misc functions
@@ -105,7 +106,6 @@
"npc/commands/ipcheck.txt",
"npc/commands/language.txt",
"npc/commands/mobinfo.txt",
-"npc/commands/motd-debug-text.txt",
"npc/commands/motd.txt",
"npc/commands/rate-management.txt",
"npc/commands/resync.txt",