summaryrefslogtreecommitdiff
path: root/world/map/npc
diff options
context:
space:
mode:
authormekolat <mekolat@users.noreply.github.com>2015-06-11 11:13:11 -0400
committermekolat <mekolat@users.noreply.github.com>2016-03-30 11:22:47 -0400
commitbc4deaf81d9701261baac6a10d762b0f40e7f65f (patch)
treee539e3a49756626e27d4491fccb7a6862b12a120 /world/map/npc
parent9e7f46ac732851c1359a15837c82ebf67ea2be39 (diff)
downloadserverdata-bc4deaf81d9701261baac6a10d762b0f40e7f65f.tar.gz
serverdata-bc4deaf81d9701261baac6a10d762b0f40e7f65f.tar.bz2
serverdata-bc4deaf81d9701261baac6a10d762b0f40e7f65f.tar.xz
serverdata-bc4deaf81d9701261baac6a10d762b0f40e7f65f.zip
initial commit for magic v3
Fix Druid Tree and add hug to TMW
Diffstat (limited to 'world/map/npc')
-rw-r--r--world/map/npc/001-1/ched.txt4
-rw-r--r--world/map/npc/001-1/children.txt2
-rw-r--r--world/map/npc/001-1/guards.txt2
-rw-r--r--world/map/npc/001-2/government_building.txt8
-rw-r--r--world/map/npc/001-2/pauline.txt10
-rw-r--r--world/map/npc/001-2/tondar.txt2
-rw-r--r--world/map/npc/001-2/wizards.txt99
-rw-r--r--world/map/npc/002-1/elanore.txt14
-rw-r--r--world/map/npc/006-1/spirit.txt4
-rw-r--r--world/map/npc/006-1/tree.txt6
-rw-r--r--world/map/npc/007-2/witch.txt8
-rw-r--r--world/map/npc/008-1/hinnak.txt2
-rw-r--r--world/map/npc/009-2/misc.txt2
-rw-r--r--world/map/npc/009-2/wyara.txt6
-rw-r--r--world/map/npc/009-3/sword.txt4
-rw-r--r--world/map/npc/009-6/brodomir.txt2
-rw-r--r--world/map/npc/009-7/eventHandler.txt2
-rw-r--r--world/map/npc/009-7/rouge.txt4
-rw-r--r--world/map/npc/011-1/auldsbel.txt20
-rw-r--r--world/map/npc/012-3/mana-seed.txt2
-rw-r--r--world/map/npc/013-1/sagatha.txt14
-rw-r--r--world/map/npc/013-2/wizard.txt2
-rw-r--r--world/map/npc/014-1/wedding-officiator.txt12
-rw-r--r--world/map/npc/015-1/sword.txt6
-rw-r--r--world/map/npc/017-4/waric.txt12
-rw-r--r--world/map/npc/017-9/npcs.txt10
-rw-r--r--world/map/npc/027-6/general_krukan.txt4
-rw-r--r--world/map/npc/027-7/general_razha.txt4
-rw-r--r--world/map/npc/027-8/general_terogan.txt4
-rw-r--r--world/map/npc/029-1/barrier.txt2
-rw-r--r--world/map/npc/029-2/morgan.txt8
-rw-r--r--world/map/npc/029-2/tanisha.txt2
-rw-r--r--world/map/npc/029-3/parua.txt6
-rw-r--r--world/map/npc/030-4/mana_battery.txt6
-rw-r--r--world/map/npc/031-4/cindyCave.txt4
-rw-r--r--world/map/npc/033-1/kimarr.txt2
-rw-r--r--world/map/npc/051-3/ambush.txt4
-rw-r--r--world/map/npc/051-3/reinforcements.txt4
-rw-r--r--world/map/npc/052-1/channelling.txt10
-rw-r--r--world/map/npc/052-2/lobby.txt2
-rw-r--r--world/map/npc/052-2/partyroom.txt8
-rw-r--r--world/map/npc/052-2/storage.txt10
-rw-r--r--world/map/npc/commands/_atcommand_local.txt.example12
-rw-r--r--world/map/npc/commands/_import.txt4
-rw-r--r--world/map/npc/commands/_procedures.txt53
-rw-r--r--world/map/npc/commands/marry.txt69
-rw-r--r--world/map/npc/commands/zeny.txt77
-rw-r--r--world/map/npc/doc/magic23
-rwxr-xr-xworld/map/npc/functions/debug.txt40
-rw-r--r--world/map/npc/functions/global_event_handler.txt1
-rw-r--r--world/map/npc/functions/hug.txt24
-rw-r--r--world/map/npc/functions/strangerquiz.txt2
-rw-r--r--world/map/npc/functions/superdebug.txt16
-rw-r--r--world/map/npc/items/check_wand.txt65
-rw-r--r--world/map/npc/items/magic_gm_top_hat.txt16
-rw-r--r--world/map/npc/magic/README.md63
-rw-r--r--world/map/npc/magic/_import.txt38
-rw-r--r--world/map/npc/magic/_procedures.txt135
-rw-r--r--world/map/npc/magic/level0-wand.txt74
-rw-r--r--world/map/npc/magic/level1-aggravate.txt22
-rw-r--r--world/map/npc/magic/level1-detect-magic.txt29
-rw-r--r--world/map/npc/magic/level1-experience.txt41
-rw-r--r--world/map/npc/magic/level1-flare-dart.txt33
-rw-r--r--world/map/npc/magic/level1-grow-alizarin.txt37
-rw-r--r--world/map/npc/magic/level1-grow-cobalt.txt37
-rw-r--r--world/map/npc/magic/level1-grow-gamboge.txt37
-rw-r--r--world/map/npc/magic/level1-grow-mauve.txt37
-rw-r--r--world/map/npc/magic/level1-lesser-heal.txt41
-rw-r--r--world/map/npc/magic/level1-magic-blade.txt34
-rw-r--r--world/map/npc/magic/level1-make-sulphur.txt24
-rw-r--r--world/map/npc/magic/level1-summon-maggots.txt52
-rw-r--r--world/map/npc/magic/level1-transmute-wood.txt36
-rw-r--r--world/map/npc/magic/level2-arrow-hail.txt112
-rw-r--r--world/map/npc/magic/level2-barrier.txt48
-rw-r--r--world/map/npc/magic/level2-detect-players.txt32
-rw-r--r--world/map/npc/magic/level2-enchant-lifestone.txt35
-rw-r--r--world/map/npc/magic/level2-flying-backpack.txt39
-rw-r--r--world/map/npc/magic/level2-happy-curse.txt42
-rw-r--r--world/map/npc/magic/level2-hide.txt43
-rw-r--r--world/map/npc/magic/level2-lay-on-hands.txt57
-rw-r--r--world/map/npc/magic/level2-lightning-strike.txt67
-rw-r--r--world/map/npc/magic/level2-magic-knuckles.txt32
-rw-r--r--world/map/npc/magic/level2-make-arrows.txt26
-rw-r--r--world/map/npc/magic/level2-make-iron-powder.txt26
-rw-r--r--world/map/npc/magic/level2-protect.txt48
-rw-r--r--world/map/npc/magic/level2-rain.txt103
-rw-r--r--world/map/npc/magic/level2-shear.txt49
-rw-r--r--world/map/npc/magic/level2-summon-fluffies.txt53
-rw-r--r--world/map/npc/magic/level2-summon-mouboo.txt53
-rw-r--r--world/map/npc/magic/level2-summon-pinkie.txt53
-rw-r--r--world/map/npc/magic/level2-summon-snakes.txt54
-rw-r--r--world/map/npc/magic/level2-summon-spiky-mushroom.txt53
-rw-r--r--world/map/npc/magic/level2-summon-wickedmushroom.txt54
-rw-r--r--world/map/npc/magic/level2-toxic-dart.txt36
-rw-r--r--world/map/npc/magic/level3-necromancy.txt54
-rw-r--r--world/map/npc/scripts.conf7
96 files changed, 2375 insertions, 312 deletions
diff --git a/world/map/npc/001-1/ched.txt b/world/map/npc/001-1/ched.txt
index ddfddd95..dee6cb77 100644
--- a/world/map/npc/001-1/ched.txt
+++ b/world/map/npc/001-1/ched.txt
@@ -15,9 +15,9 @@ L_Next:
mes "[Ched]";
mes "\"Well, I don't remember what it's called... I took it out of 'Timbleweed's Advanced Transmutations,' but it seems awfully hard to cast.\"";
next;
- mes "\"If you want to try it, the invocation is '" + getspellinvocation("merge-concentration-potions") + ".' I just can't get the hang of it though.\"";
+ mes "\"If you want to try it, the invocation is '" + ("merge-concentration-potions") + ".' I just can't get the hang of it though.\"";
next;
- mes "\"Maybe I should go back to practicing '" + getspellinvocation("detect-magic") + "' until I can cast it properly.\" %%6";
+ mes "\"Maybe I should go back to practicing '" + ("detect-magic") + "' until I can cast it properly.\" %%6";
goto L_Done;
L_Done:
diff --git a/world/map/npc/001-1/children.txt b/world/map/npc/001-1/children.txt
index 5ad738a9..83718566 100644
--- a/world/map/npc/001-1/children.txt
+++ b/world/map/npc/001-1/children.txt
@@ -78,7 +78,7 @@ L_keepword:
L_giveword:
mes "[Aisha]";
mes "Aisha looks around as she leans in and hushes you to silence. After a few seconds, she whispers to you:";
- mes "\"I like you, so I'll tell you the bad word. But you can't tell anyone else about it! The bad word is '" + getspellinvocation("aggravate") + ".'\"";
+ mes "\"I like you, so I'll tell you the bad word. But you can't tell anyone else about it! The bad word is '" + get(.invocation$, "spell-aggravate") + ".'\"";
next;
mes "[Aisha]";
diff --git a/world/map/npc/001-1/guards.txt b/world/map/npc/001-1/guards.txt
index 0167510e..df25a13e 100644
--- a/world/map/npc/001-1/guards.txt
+++ b/world/map/npc/001-1/guards.txt
@@ -91,6 +91,6 @@ L_message:
mes "[Ryan the Town Guard]";
mes "\" Watch out for Black Scorpions. They are extremely dangerous!\"";
next;
- mes "\"Whenever one approaches the town gate, Ekinu has me run around shouting '" + getspellinvocation("aggravate") + ".' Somehow, this distracts it so Ekinu can kill it.\"";
+ mes "\"Whenever one approaches the town gate, Ekinu has me run around shouting '" + $@SPELL_AGGRAVATE$ + ".' Somehow, this distracts it so Ekinu can kill it.\"";
close;
}
diff --git a/world/map/npc/001-2/government_building.txt b/world/map/npc/001-2/government_building.txt
index 51b43a8c..03c3eaf7 100644
--- a/world/map/npc/001-2/government_building.txt
+++ b/world/map/npc/001-2/government_building.txt
@@ -6,7 +6,7 @@
mes "[Estard]";
mes "\"Hello. What can I do for you?\"";
next;
- if (getpartnerid2())
+ if (PARTNER)
goto L_main_married;
menu
@@ -35,7 +35,7 @@ L_marry_do:
callsub S_give_rings;
mes "";
mes "[Estard]";
- mes "\"Here are your rings. In order to marry each other, you both must stand within one of the designated areas (like that small rug over there in the corner), wear your rings, and say 'marry (your partner's name).'\"";
+ mes "\"Here are your rings. In order to marry each other, you both must stand within one of the designated areas (like that small rug over there in the corner), wear your rings, and say '#marry (your partner's name).'\"";
close;
L_marry_too_young:
@@ -93,8 +93,8 @@ L_do_divorce:
if (Zeny < @divorce_cost)
goto L_not_enough_money;
- if (divorce())
- goto L_divorce_done;
+ set PARTNER, 0, PARTNER; // divorce the partner first, which will also divorce the rid if succesful
+ if (PARTNER < 1) goto L_divorce_done;
mes "";
mes "[Estard]";
diff --git a/world/map/npc/001-2/pauline.txt b/world/map/npc/001-2/pauline.txt
index 4fbd5a5f..93608a10 100644
--- a/world/map/npc/001-2/pauline.txt
+++ b/world/map/npc/001-2/pauline.txt
@@ -92,7 +92,7 @@ L_Spells:
L_Next1:
mes "[Pauline]";
mes "\"Well I could only read the invocations. So I don't exactly know what kind of ingredients you are going to need.\"";
- mes "\"The first one for the mouboo was " + getspellinvocation("summon-mouboo") + " and the one for the pinkie was " + getspellinvocation("summon-pinkie") +".\"";
+ mes "\"The first one for the mouboo was " + ("summon-mouboo") + " and the one for the pinkie was " + ("summon-pinkie") +".\"";
next;
mes "\"For the pinkie spell my suggestion is to try similar ingredients to the other Astral spells. Try a root and some item typical for pinkies.\"";
mes "\"The mouboo spell might be more complicated. From what I could translate, one of the spell components is crafted by magic.\"";
@@ -157,7 +157,7 @@ L_Next4:
goto L_DidNotWorkMouboo;
L_DidNotWorkMouboo:
- mes "The Witch takes " + @pauline_ingredient1$ + " and " + @pauline_ingredient2$ + " and puts them together calling " + getspellinvocation("summon-mouboo") + ".";
+ mes "The Witch takes " + @pauline_ingredient1$ + " and " + @pauline_ingredient2$ + " and puts them together calling " + ("summon-mouboo") + ".";
mes "Nothing happens.";
mes "[Pauline]";
mes "\"It seems you did not tell me the correct ingredients. Come back when you find the correct ones.\"";
@@ -174,7 +174,7 @@ L_Pass2Mouboo:
goto L_DidNotWorkMouboo;
L_TrySpellMouboo:
- mes "The Witch takes " + @pauline_ingredient1$ + " and " + @pauline_ingredient2$ + " and puts them together calling " + getspellinvocation("summon-mouboo") + ".";
+ mes "The Witch takes " + @pauline_ingredient1$ + " and " + @pauline_ingredient2$ + " and puts them together calling " + ("summon-mouboo") + ".";
monster "001-1", 55,68, "Good", 1028, 1;
mes "[Pauline]";
mes "\"It worked!\"";
@@ -220,7 +220,7 @@ L_Next5:
goto L_DidNotWorkPinkie;
L_DidNotWorkPinkie:
- mes "The Witch takes " + @pauline_ingredient1$ + " and " + @pauline_ingredient2$ + " and puts them together calling " + getspellinvocation("summon-pinkie") + ".";
+ mes "The Witch takes " + @pauline_ingredient1$ + " and " + @pauline_ingredient2$ + " and puts them together calling " + ("summon-pinkie") + ".";
mes "Nothing happens.";
mes "[Pauline]";
mes "\"It seems you did not tell me the correct ingredients. Come back when you find the correct ones.\"";
@@ -237,7 +237,7 @@ L_Pass2Pinkie:
goto L_DidNotWorkPinkie;
L_TrySpellPinkie:
- mes "The Witch takes " + @pauline_ingredient1$ + " and " + @pauline_ingredient2$ + " and puts them together calling " + getspellinvocation("summon-pinkie") + ".";
+ mes "The Witch takes " + @pauline_ingredient1$ + " and " + @pauline_ingredient2$ + " and puts them together calling " + ("summon-pinkie") + ".";
monster "001-1", 54,68, "Good", 1018, 1;
mes "[Pauline]";
mes "\"It worked!\"";
diff --git a/world/map/npc/001-2/tondar.txt b/world/map/npc/001-2/tondar.txt
index ba4c0fff..d7fd3531 100644
--- a/world/map/npc/001-2/tondar.txt
+++ b/world/map/npc/001-2/tondar.txt
@@ -41,7 +41,7 @@ L_askspell:
L_spell:
mes "[Tondar]";
- mes "\"Well, all right; this one can't do much harm. Press your hands together and say `" + getspellinvocation("ask-magic-exp") + "'.\"";
+ mes "\"Well, all right; this one can't do much harm. Press your hands together and say `" + get(.invocation$, "spell-experience") + "'.\"";
mes "\"This will release a steady flow of magic within you. Focus and try to control it; it is a good meditative practice.\"";
close;
diff --git a/world/map/npc/001-2/wizards.txt b/world/map/npc/001-2/wizards.txt
index 37efa8bd..ef538489 100644
--- a/world/map/npc/001-2/wizards.txt
+++ b/world/map/npc/001-2/wizards.txt
@@ -1,90 +1,25 @@
// Council of Ruling Wizards Room
-// manaseed
-001-2,104,19,0|script|Desert Mana Seed#_M|166
+-|script|Magic Council|32767
{
- mes "Strangely, you feel nothing – as if its membrane is closed to you.";
+ explode .@n, strnpcinfo(0), "#";
+ if (.@n[1] == 9) mes "The arch wizard seems to be busy.";
+ elif (.@n[1]) mes "The wizard seems to ignore you.";
+ else mes "Strangely, you feel nothing – as if its membrane is closed to you.";
next;
mes "Perhaps you should come back later.";
close;
-}
-
-//
-001-2,99,22,0|script|Wizard#1|355
-{
- mes "The wizard seems to ignore you.";
- next;
- mes "Perhaps you should come back later.";
- close;
-}
-
-//
-001-2,92,24,0|script|Wizard#2|356
-{
- mes "The wizard seems to ignore you.";
- next;
- mes "Perhaps you should come back later.";
- close;
-}
-
-//
-001-2,92,30,0|script|Wizard#3|357
-{
- mes "The wizard seems to ignore you.";
- next;
- mes "Perhaps you should come back later.";
- close;
-}
-
-//
-001-2,99,32,0|script|Wizard#4|358
-{
- mes "The wizard seems to ignore you.";
- next;
- mes "Perhaps you should come back later.";
- close;
-}
-
-//
-001-2,110,22,0|script|Wizard#5|359
-{
- mes "The wizard seems to ignore you.";
- next;
- mes "Perhaps you should come back later.";
- close;
-}
-
-//
-001-2,117,24,0|script|Wizard#6|360
-{
- mes "The wizard seems to ignore you.";
- next;
- mes "Perhaps you should come back later.";
- close;
-}
-
-//
-001-2,117,30,0|script|Wizard#7|361
-{
- mes "The wizard seems to ignore you.";
- next;
- mes "Perhaps you should come back later.";
- close;
-}
-//
-001-2,110,32,0|script|Wizard#8|362
-{
- mes "The wizard seems to ignore you.";
- next;
- mes "Perhaps you should come back later.";
- close;
-}
-//
-001-2,104,27,0|script|Arch-Wizard#9|354
-{
- mes "The arch wizard seems to be busy.";
- next;
- mes "Perhaps you should come back later.";
- close;
+OnInit:
+ set .@void, puppet("001-2", 104, 19, "Desert Mana Seed#_M", 166);
+ set .@void, puppet("001-2", 99, 22, "Wizard#1", 355);
+ set .@void, puppet("001-2", 92, 24, "Wizard#2", 356);
+ set .@void, puppet("001-2", 92, 30, "Wizard#3", 357);
+ set .@void, puppet("001-2", 99, 32, "Wizard#4", 358);
+ set .@void, puppet("001-2", 110, 22, "Wizard#5", 359);
+ set .@void, puppet("001-2", 117, 24, "Wizard#6", 360);
+ set .@void, puppet("001-2", 117, 30, "Wizard#7", 361);
+ set .@void, puppet("001-2", 110, 32, "Wizard#8", 362);
+ set .@void, puppet("001-2", 104, 27, "Arch-Wizard#9", 354);
+ end;
}
diff --git a/world/map/npc/002-1/elanore.txt b/world/map/npc/002-1/elanore.txt
index ea3b78bf..fbc8f3c0 100644
--- a/world/map/npc/002-1/elanore.txt
+++ b/world/map/npc/002-1/elanore.txt
@@ -233,7 +233,7 @@ L_MakeSelf:
goto L_MakeSelf_yes;
L_MakeSelf_yes:
- mes "\"Oh, but of course! You are powerful enough to make your own lifestones, using the enchantment '" + getspellinvocation("enchant-lifestone") + "'. This will consume a bug leg or a maggot slime or one of each of the four healing herbs, though.\"";
+ mes "\"Oh, but of course! You are powerful enough to make your own lifestones, using the enchantment '" + ("enchant-lifestone") + "'. This will consume a bug leg or a maggot slime or one of each of the four healing herbs, though.\"";
goto L_Close;
L_MakeSelf_no:
@@ -265,15 +265,15 @@ L_T_Initial:
next;
mes "[Elanore the Healer]";
mes "\"To heal someone, first locate the injury. As a beginner, you have to touch the wound; with practice, it will be enough to think about it. Hold the lifestone in one hand, touching the wound with the other.\"";
- mes "\"Then say, '" + getspellinvocation("lesser-heal") + "', followed by the name of the one you wish to heal.\"";
+ mes "\"Then say, '" + ("lesser-heal") + "', followed by the name of the one you wish to heal.\"";
next;
mes "[Elanore the Healer]";
mes "\"You might want to write that down, actually. In fact, you might want to make sure to keep notes of all spells you hear, for you never know if you will hear them again!\"";
- mes "\"The invocation was '" + getspellinvocation("lesser-heal") + "'.\"";
+ mes "\"The invocation was '" + ("lesser-heal") + "'.\"";
next;
mes "[Elanore the Healer]";
mes "\"This will only cure cuts and bruises, though, and it will take some time to take effect. It will be useless to mend broken bones or more severe injuries!\"";
- mes "\"To heal yourself, it's enough to just say '" + getspellinvocation("lesser-heal") + "' by itself.\"";
+ mes "\"To heal yourself, it's enough to just say '" + ("lesser-heal") + "' by itself.\"";
next;
mes "[Elanore the Healer]";
mes "\"Let me give you a lifestone to get started with.\"";
@@ -344,7 +344,7 @@ L_T_ChkAdvToLOH:
mes "\"I will now teach you how to heal by laying on your hands. The technique is similar to the spell I taught you at the beginning, but this time you transfer your own health instead of drawing health from a lifestone.\"";
next;
mes "[Elanore the Healer]";
- mes "\"First, lay your hand on the person you wish to heal. You needn't touch the injury itself, though you have to touch the skin until you are a little more experienced. Then, medidate on the word '" + getspellinvocation("lay-on-hands") + "'\"";
+ mes "\"First, lay your hand on the person you wish to heal. You needn't touch the injury itself, though you have to touch the skin until you are a little more experienced. Then, medidate on the word '" + ("lay-on-hands") + "'\"";
next;
mes "[Elanore the Healer]";
mes "\"This will let your own life force flow into the person you are healing. If you are badly injured yourself, you will not be able to do this.\"";
@@ -500,11 +500,11 @@ L_T_CurePosion:
next;
mes "[Elanore the Healer]";
mes "\"If you would like to cure someone who is poisoned, first rub a Gamboge leaf between your hands. Your hands must be covered in Gamboge liquid for this to work.\"";
- mes "\"Speak the invocation, `" + getspellinvocation("cure-poison") + "'.\"";
+ mes "\"Speak the invocation, `" + ("cure-poison") + "'.\"";
mes "\"Next, you either touch the poisoned person with your hands, or speak their name. You have to be close for this to work, though.\"";
next;
mes "[Elanore the Healer]";
- mes "\"Once again, the invocation is `" + getspellinvocation("cure-poison") + "'.\"";
+ mes "\"Once again, the invocation is `" + ("cure-poison") + "'.\"";
mes "\"Come back again soon; there is another spell I would like to teach you.\"";
next;
set @Q_status, @STATUS_LEARNED_CURE_POISON;
diff --git a/world/map/npc/006-1/spirit.txt b/world/map/npc/006-1/spirit.txt
index 8c7155fa..9a839a81 100644
--- a/world/map/npc/006-1/spirit.txt
+++ b/world/map/npc/006-1/spirit.txt
@@ -178,7 +178,7 @@ L_Next5:
mes "\"Kekeke... excellent! Yes, here goes your first spell, the flying backpack! If you are overloaded, it will take the load off your shoulders.\"";
next;
mes "[Earth Spirit]";
- mes "\"Take a cocoon, living or dead, and suffuse it in magic. Whisper '" + getspellinvocation("flying-backpack") + "', and feel it float!\"";
+ mes "\"Take a cocoon, living or dead, and suffuse it in magic. Whisper '" + ("flying-backpack") + "', and feel it float!\"";
goto L_Q_magic_finish;
L_Q_magic_3:
@@ -196,7 +196,7 @@ L_Next6:
mes "\"Yeees, good! This one is a protection spell, making your skin harder. You need a hard spike for it, though. Hold that spike in your hands, and focus on it.\"";
next;
mes "[Earth Spirit]";
- mes "\"Next, say '" + getspellinvocation("protect") + "', and feel your skin grow rigid! Very useful against stings and stabs and pokes and pricks and that sort of stuff.\"";
+ mes "\"Next, say '" + ("protect") + "', and feel your skin grow rigid! Very useful against stings and stabs and pokes and pricks and that sort of stuff.\"";
goto L_Q_magic_finish;
L_Q_magic_4:
diff --git a/world/map/npc/006-1/tree.txt b/world/map/npc/006-1/tree.txt
index 6740312e..57209d24 100644
--- a/world/map/npc/006-1/tree.txt
+++ b/world/map/npc/006-1/tree.txt
@@ -160,9 +160,3 @@ L_Close:
callfunc "QuestTreeTouch";
close;
}
-
-006-1,83,59,0|script|#DruidTree1#_M|400
-{
- callfunc "QuestTreeTouch";
- close;
-}
diff --git a/world/map/npc/007-2/witch.txt b/world/map/npc/007-2/witch.txt
index 557b5f62..f5fcda32 100644
--- a/world/map/npc/007-2/witch.txt
+++ b/world/map/npc/007-2/witch.txt
@@ -639,10 +639,10 @@ OnTimer34000:
end;
// Trigger 4 areatimers to show the teleport spell
// This is better looking than a basic areawarp
- areatimer "007-2", 0, 0, 57, 55, 3000, "Valia::OnWarpHero";
- areatimer "007-2", 0, 0, 57, 55, 3500, "Valia::OnWarpHelper1";
- areatimer "007-2", 0, 0, 57, 55, 4000, "Valia::OnWarpHelper2";
- areatimer "007-2", 0, 0, 57, 55, 4500, "Valia::OnWarpHelper3";
+ areatimer 0, "007-2", 0, 0, 57, 55, 3000, "Valia::OnWarpHero";
+ areatimer 0, "007-2", 0, 0, 57, 55, 3500, "Valia::OnWarpHelper1";
+ areatimer 0, "007-2", 0, 0, 57, 55, 4000, "Valia::OnWarpHelper2";
+ areatimer 0, "007-2", 0, 0, 57, 55, 4500, "Valia::OnWarpHelper3";
npctalk strnpcinfo(0), "Spiralis Major!";
misceffect FX_BLUE_MAGIC_CAST;
end;
diff --git a/world/map/npc/008-1/hinnak.txt b/world/map/npc/008-1/hinnak.txt
index c2360141..d3828d74 100644
--- a/world/map/npc/008-1/hinnak.txt
+++ b/world/map/npc/008-1/hinnak.txt
@@ -217,7 +217,7 @@ L_Sagatha_scary:
L_Sagatha_word:
mes "[Farmer Hinnak]";
- mes "\"Oh, I can't be sure... but something like '" + getspellinvocation("summon-maggots") + "', I think.\"";
+ mes "\"Oh, I can't be sure... but something like '" + ("summon-maggots") + "', I think.\"";
goto L_Close;
L_NoBeer:
diff --git a/world/map/npc/009-2/misc.txt b/world/map/npc/009-2/misc.txt
index b28d43b5..139033ec 100644
--- a/world/map/npc/009-2/misc.txt
+++ b/world/map/npc/009-2/misc.txt
@@ -39,7 +39,7 @@ L_magic:
mes "The page after that is once again hastily written, with many crossed out words and sections and side remarks such as 'it almost worked' or 'it worked fine yesterday.'";
next;
mes "[Bookshelf]";
- mes "The last word on that page is '" + getspellinvocation("make-iron-powder") + ",' and it's underlined twice with a comment next to it saying 'finally got it right.'";
+ mes "The last word on that page is '" + ("make-iron-powder") + ",' and it's underlined twice with a comment next to it saying 'finally got it right.'";
next;
mes "[Bookshelf]";
mes "Unfortunately, you can't make out what the transmutation is for or even whether it requires any materials...";
diff --git a/world/map/npc/009-2/wyara.txt b/world/map/npc/009-2/wyara.txt
index ba33d29f..d0bffbea 100644
--- a/world/map/npc/009-2/wyara.txt
+++ b/world/map/npc/009-2/wyara.txt
@@ -242,7 +242,7 @@ L_M_spell:
L_M_spell3:
mes "[Wyara the Witch]";
- mes "\"Now that you know the basics of nature magic, here is one of my favourites: '" + getspellinvocation("rain") + "' will summon rain, whereever you are standing. It will consume a bottle of water, though.\"";
+ mes "\"Now that you know the basics of nature magic, here is one of my favourites: '" + ("rain") + "' will summon rain, whereever you are standing. It will consume a bottle of water, though.\"";
if (getskilllv(SKILL_MAGIC) < 2)
mes "\"You are not powerful enough to use it yet, though; you will first have to absorb more magic from the mana seed.\"";
next;
@@ -250,14 +250,14 @@ L_M_spell3:
L_M_spell2:
mes "[Wyara the Witch]";
- mes "\"Here is another useful one: '" + getspellinvocation("detect-players") + "'. It will tell you the names of everyone nearby, but beware that there are ways to protect against it.\"";
+ mes "\"Here is another useful one: '" + ("detect-players") + "'. It will tell you the names of everyone nearby, but beware that there are ways to protect against it.\"";
if (getskilllv(SKILL_MAGIC) < 2)
mes "\"Hmm. You aren't powerful enough for this one either yet, I think.\"";
next;
if (!(getpartnerid2()))
goto L_M_main;
mes "[Wyara the Witch]";
- mes "\"Married partners can find each other even more easily. Use the '" + getspellinvocation("sense-spouse") + "' spell instead.\"";
+ mes "\"Married partners can find each other even more easily. Use the '" + ("sense-spouse") + "' spell instead.\"";
next;
goto L_M_main;
diff --git a/world/map/npc/009-3/sword.txt b/world/map/npc/009-3/sword.txt
index 91366f9e..dbb177bc 100644
--- a/world/map/npc/009-3/sword.txt
+++ b/world/map/npc/009-3/sword.txt
@@ -103,7 +103,7 @@ L_Next1:
mes "\"So thou art bound to the path of War, as am I, as is my sister...\"";
next;
mes "[Magic Sword]";
- mes "\"So be it, fellow warrior. Hear the incantation for the blade spell: '" + getspellinvocation("magic-blade") + "'\"";
+ mes "\"So be it, fellow warrior. Hear the incantation for the blade spell: '" + ("magic-blade") + "'\"";
mes "\"Hold a knife, sharp or regular, when thou speakest it.\"";
set @Q_status, @STATUS_LEARNED_MAGICBLADE;
callsub S_update_var;
@@ -152,7 +152,7 @@ L_Next3:
mes "\"The spell I shall teach thee is the hail of arrows spell. It will make arrows fall down from the heavens unto thy enemies.\"";
next;
mes "[Magic Sword]";
- mes "\"Take twenty arrows, sprinkle sulphur powder over them, and then speak '" + getspellinvocation("arrow-hail") + "'. Throw them high up in the air, and watch the hail unfold before thy feet.\"";
+ mes "\"Take twenty arrows, sprinkle sulphur powder over them, and then speak '" + get(.invocation$, "arrow-hail") + "'. Throw them high up in the air, and watch the hail unfold before thy feet.\"";
close;
L_L2_almost_done:
diff --git a/world/map/npc/009-6/brodomir.txt b/world/map/npc/009-6/brodomir.txt
index 02704447..ea73ac36 100644
--- a/world/map/npc/009-6/brodomir.txt
+++ b/world/map/npc/009-6/brodomir.txt
@@ -195,7 +195,7 @@ L_SkipItemback:
L_Check:
if (getareausers("009-5", 20, 20, 80, 80, 1) > 1)
end;
- areatimer "009-5", 20, 20, 80, 80, 0, "Brodomir::OnReward";
+ areatimer 0, "009-5", 20, 20, 80, 80, 0, "Brodomir::OnReward";
goto L_End;
OnReward:
diff --git a/world/map/npc/009-7/eventHandler.txt b/world/map/npc/009-7/eventHandler.txt
index d20fff4d..6f6419ca 100644
--- a/world/map/npc/009-7/eventHandler.txt
+++ b/world/map/npc/009-7/eventHandler.txt
@@ -40,7 +40,7 @@ OnBecomeKiller:
end;
OnCommandIntrusion:
- areatimer "009-7", $@fightclub_x1, $@fightclub_y1, $@fightclub_x2, $@fightclub_y2, 0, "#FightClubUtils::OnIntrusion"; // we can not do this directly on #handler because it already have a timer
+ areatimer 0, "009-7", $@fightclub_x1, $@fightclub_y1, $@fightclub_x2, $@fightclub_y2, 0, "#FightClubUtils::OnIntrusion"; // we can not do this directly on #handler because it already have a timer
end;
}
diff --git a/world/map/npc/009-7/rouge.txt b/world/map/npc/009-7/rouge.txt
index 7660683e..b9b8e4cd 100644
--- a/world/map/npc/009-7/rouge.txt
+++ b/world/map/npc/009-7/rouge.txt
@@ -78,13 +78,13 @@ L_Challenge:
next;
mes "[Rouge]";
mes "To challenge a player to a duel, you need to write this command:";
- mes "%%E ##a"+ getspellinvocation("duel") +" (name)##0";
+ mes "%%E ##a"+ ("duel") +" (name)##0";
next;
mes "Your opponent will have to talk to me to accept or decline your offer.";
mes "The request will expire ##2"+ @time$ +"##0 after being sent.";
next;
mes "Keep in mind that you can ignore incoming duel requests with this command:";
- mes "%%E ##a"+ getspellinvocation("dueloff") +"##0";
+ mes "%%E ##a"+ ("dueloff") +"##0";
next;
mes "To un-ignore, simply write the same command again.";
goto L_End;
diff --git a/world/map/npc/011-1/auldsbel.txt b/world/map/npc/011-1/auldsbel.txt
index 094651e9..4a57b75b 100644
--- a/world/map/npc/011-1/auldsbel.txt
+++ b/world/map/npc/011-1/auldsbel.txt
@@ -236,7 +236,7 @@ L_Sul_t_s:
mes "\"Very well, then. You have been quite helpful with my experiments, after all. As you may have noticed, the spell takes a pile of volcanic ashes. Close your hands around it, then whisper the invocation.\"";
next;
mes "[Auldsbel the Wizard]";
- mes "\"That invocation is '" + getspellinvocation("make-sulphur") + "'.\"";
+ mes "\"That invocation is '" + ("make-sulphur") + "'.\"";
next;
mes "[Auldsbel the Wizard]";
mes "\"You may find that you can transmute the powder more effectively after a while; that is perfectly natural.\"";
@@ -332,7 +332,7 @@ L_about_nature:
L_about_other_spells:
mes "[Auldsbel the Wizard]";
- mes "\"A few spells are not claimed by any particular school of magic. In practice, this means that anyone can cast them if they just have sufficient magical power. The most prominent example is the 'detect magic' spell, '" + getspellinvocation("detect-magic") + "'.\"";
+ mes "\"A few spells are not claimed by any particular school of magic. In practice, this means that anyone can cast them if they just have sufficient magical power. The most prominent example is the 'detect magic' spell, '" + ("detect-magic") + "'.\"";
next;
goto L_a_s_minimenu;
@@ -984,10 +984,10 @@ L_learn_spell:
mes "\"This spell is a simple transmutation invocation. All it takes is a clean wooden log. Hold it in your hand, focus your powers, and say the magic invocation.\"";
next;
mes "[Auldsbel the Wizard]";
- mes "\"You can turn the log into a wooden figurine by imagining the creature whose shape you want in your head and saying `" + getspellinvocation("transmute-wood-to-figurine") + ",' followed by the last syllable of the name of the creature you want to shape it into.\"";
+ mes "\"You can turn the log into a wooden figurine by imagining the creature whose shape you want in your head and saying `" + ("transmute-wood-to-figurine") + ",' followed by the last syllable of the name of the creature you want to shape it into.\"";
next;
mes "[Auldsbel the Wizard]";
- mes "\"So `" + getspellinvocation("transmute-wood-to-figurine") + " lurk' for a Skytlurk figurine, for example. If you know what a Skytlurk is, I mean, otherwise you will have a hard time imagining it. You may want to try some others instead, though.\"";
+ mes "\"So `" + ("transmute-wood-to-figurine") + " lurk' for a Skytlurk figurine, for example. If you know what a Skytlurk is, I mean, otherwise you will have a hard time imagining it. You may want to try some others instead, though.\"";
next;
mes "[Auldsbel the Wizard]";
mes "\"Oh... and it has to be the old Tritan name. Most creatures nowadays have very different names, but some old Tritan names have survived. Just try some, until you find one that fits.\"";
@@ -1001,7 +1001,7 @@ L_learn_spell:
L_repeat_spell:
mes "[Auldsbel the Wizard]";
- mes "\"The invocation is `" + getspellinvocation("transmute-wood-to-figurine") + ",' followed by the last syllable of the name of the creature you want to shape the log into. So `" + getspellinvocation("transmute-wood-to-figurine") + " lurk' for a Skytlurk figurine.\"";
+ mes "\"The invocation is `" + ("transmute-wood-to-figurine") + ",' followed by the last syllable of the name of the creature you want to shape the log into. So `" + ("transmute-wood-to-figurine") + " lurk' for a Skytlurk figurine.\"";
next;
mes "[Auldsbel the Wizard]";
mes "\"But keep two things in mind: First, you must KNOW what the creature looks like – so a Skytlurk probably won't work – and second, you must use the old Tritan name of it. `Fluffy' and `Scorpion' are modern names, so those won't work, you should try some others.\"";
@@ -1092,7 +1092,7 @@ L_Next9:
mes "[1000 experience points]";
next;
mes "[Auldsbel the Wizard]";
- mes "\"Now, listen carefully: to make a short tank top out of three pieces of cloth, you must use the invocation '" + getspellinvocation("make-short-tanktop") + "'.\"";
+ mes "\"Now, listen carefully: to make a short tank top out of three pieces of cloth, you must use the invocation '" + ("make-short-tanktop") + "'.\"";
next;
mes "[Auldsbel the Wizard]";
mes "\"But be careful; transmutations can go wrong, and that can injure you. When you have more overall spellcasting practice, come back to me.\"";
@@ -1131,7 +1131,7 @@ L_Next10:
mes "[1000 experience points]";
next;
mes "[Auldsbel the Wizard]";
- mes "\"The next spell I have will make a normal tank top out of four pieces of cloth. The invocation is '" + getspellinvocation("make-tanktop") + "', make sure to write this down.\"";
+ mes "\"The next spell I have will make a normal tank top out of four pieces of cloth. The invocation is '" + ("make-tanktop") + "', make sure to write this down.\"";
next;
goto L_main_menu;
@@ -1161,7 +1161,7 @@ L_Next11:
mes "[1000 experience points]";
next;
mes "[Auldsbel the Wizard]";
- mes "\"To make a shirt, use the invocation '" + getspellinvocation("make-shirt") + "'. This will require five pieces of cloth.\"";
+ mes "\"To make a shirt, use the invocation '" + ("make-shirt") + "'. This will require five pieces of cloth.\"";
next;
goto L_main_menu;
@@ -1191,7 +1191,7 @@ L_Next12:
mes "[1000 experience points]";
next;
mes "[Auldsbel the Wizard]";
- mes "\"This spell makes arrows out of a single wooden log. Its invocation is '" + getspellinvocation("make-arrows") + "'.\"";
+ mes "\"This spell makes arrows out of a single wooden log. Its invocation is '" + ("make-arrows") + "'.\"";
next;
goto L_main_menu;
@@ -1205,7 +1205,7 @@ L_stu_3:
L_stu_3_repeat:
mes "[Auldsbel the Wizard]";
- mes "\"This one has the invocation `" + getspellinvocation("make-concentration-potion") + "'. Put two cobalt leaves and two pink flower petals into a bottle of water, hold it up, and speak that phrase.\"";
+ mes "\"This one has the invocation `" + ("make-concentration-potion") + "'. Put two cobalt leaves and two pink flower petals into a bottle of water, hold it up, and speak that phrase.\"";
next;
mes "[Auldsbel the Wizard]";
mes "\"It is a tricky spell, but if it works out, you will transform the bottle into a concentration potion.\"";
diff --git a/world/map/npc/012-3/mana-seed.txt b/world/map/npc/012-3/mana-seed.txt
index bb479c2b..35d6ea52 100644
--- a/world/map/npc/012-3/mana-seed.txt
+++ b/world/map/npc/012-3/mana-seed.txt
@@ -37,7 +37,7 @@
"You may only be children, but you recognize that it is this man only who can save the world. As the walls rush towards you to crush your small group, you exchange a glance with your twin sister – there is no doubt what you must do...",
"The sacred place is surrounded by nothingness; were it not for your magic, you would have no hope of returning. The old and young man stands nearby; he has been waiting for you, for centuries. He has all the time in the world, after all...",
"Nothing remains behind. The underground castle is empty now, its chambers plundered, its throne destroyed. Shivering, you climb down the stairs, towards the wailing of the underworld that is waiting beneath...",
- "You feel soft, fluffy fur brushing against your skin and are filled with happiness. Somehow, the word `" + getspellinvocation("happy-curse") + "' comes to mind...";
+ "You feel soft, fluffy fur brushing against your skin and are filled with happiness. Somehow, the word `" + ("happy-curse") + "' comes to mind...";
set @max_magic, 2;
diff --git a/world/map/npc/013-1/sagatha.txt b/world/map/npc/013-1/sagatha.txt
index 558e9b70..84336eef 100644
--- a/world/map/npc/013-1/sagatha.txt
+++ b/world/map/npc/013-1/sagatha.txt
@@ -267,7 +267,7 @@ L_teach_N14:
mes "\"Some forest creatures sometimes overgrow their fur or hide. That makes them uncomfortable.\"";
next;
mes "[Sagatha the Witch]";
- mes "\"You can help them with shearing magic. Press your hands together and say '" + getspellinvocation("shear") + "'. Then touch them with your hands, and brush off any excess.\"";
+ mes "\"You can help them with shearing magic. Press your hands together and say '" + ("shear") + "'. Then touch them with your hands, and brush off any excess.\"";
next;
mes "[Sagatha the Witch]";
mes "\"The spell is strong, so you only need to do this once. Be careful not to cut them. Some things they shed are useful. Often they will leave them to you as a thank-you.\"";
@@ -280,7 +280,7 @@ L_teach_N10:
mes "\"Next, a nature spell. Take a cocoon shell. Hold it in your hand. Feel its lightness.\"";
next;
mes "[Sagatha the Witch]";
- mes "\"Now whisper '" + getspellinvocation("flying-backpack") + "', and if your backpack was pressing on you you should no longer feel it now.\"";
+ mes "\"Now whisper '" + ("flying-backpack") + "', and if your backpack was pressing on you you should no longer feel it now.\"";
goto L_practice;
L_teach_A10:
@@ -290,14 +290,14 @@ L_teach_A10:
mes "\"To protect against others' magic, take a small mushroom from a shady place. Mushrooms draw things out of the earth. Rub your mushroom into pieces between your hands.\"";
next;
mes "[Sagatha the Witch]";
- mes "\"Then say '" + getspellinvocation("barrier") + "' and let the mushroom's power take over.\"";
+ mes "\"Then say '" + ("barrier") + "' and let the mushroom's power take over.\"";
goto L_practice;
L_teach_A11:
if (@mexp < 200)
goto L_teach_noexp;
mes "[Sagatha the Witch]";
- mes "\"If you must fight, call allies. You can call spiky mushrooms out of the ground with a mushroom spike and a root. Hold up the spike and call out to them: '" + getspellinvocation("summon-spiky-mushrooms") + "'. Then press the root to the ground.\"";
+ mes "\"If you must fight, call allies. You can call spiky mushrooms out of the ground with a mushroom spike and a root. Hold up the spike and call out to them: '" + ("summon-spiky-mushrooms") + "'. Then press the root to the ground.\"";
next;
mes "[Sagatha the Witch]";
mes "\"Spiky mushrooms often grow too many spikes, so you can shear the spikes off of some.\"";
@@ -308,17 +308,17 @@ L_teach_A12:
if (@mexp < 220)
goto L_teach_noexp;
mes "[Sagatha the Witch]";
- mes "\"You can call fluffies, too. But for them you must call out '" + getspellinvocation("summon-fluffies") + "' instead, with white fluffy fur instead of a spike. And don't forget the root.\"";
+ mes "\"You can call fluffies, too. But for them you must call out '" + ("summon-fluffies") + "' instead, with white fluffy fur instead of a spike. And don't forget the root.\"";
goto L_practice;
L_teach_N11:
if (@mexp < 250)
goto L_teach_noexp;
mes "[Sagatha the Witch]";
- mes "\"You can harden your skin with a hard spike. Hold it in your hands and speak '" + getspellinvocation("protect") + "', then draw its hardness into your skin.\"";
+ mes "\"You can harden your skin with a hard spike. Hold it in your hands and speak '" + ("protect") + "', then draw its hardness into your skin.\"";
next;
mes "[Sagatha the Witch]";
- mes "\"Or call it into someone else's skin, by saying that someone's name right after the '" + getspellinvocation("protect") + "'.\"";
+ mes "\"Or call it into someone else's skin, by saying that someone's name right after the '" + ("protect") + "'.\"";
goto L_practice;
L_teach_noexp:
diff --git a/world/map/npc/013-2/wizard.txt b/world/map/npc/013-2/wizard.txt
index ced2865b..cf8598b0 100644
--- a/world/map/npc/013-2/wizard.txt
+++ b/world/map/npc/013-2/wizard.txt
@@ -75,7 +75,7 @@ L_TeachSpell:
mes "\"This one may not seem too powerful, but it can be quite handy; it's the 'hide' spell. It will shield you from some forms of detection magic.\"";
next;
mes "[Old Wizard]";
- mes "\"Put a piece of cotton cloth on your head, and speak out '" + getspellinvocation("hide") + "', loudly and clearly. The protection lasts quite long, but you may have to renew it on occasion.\"";
+ mes "\"Put a piece of cotton cloth on your head, and speak out '" + ("hide") + "', loudly and clearly. The protection lasts quite long, but you may have to renew it on occasion.\"";
next;
mes "[Old Wizard]";
mes "\"You can also cast it on others, of course. Just speak their name after you pronounce the invocation.\"";
diff --git a/world/map/npc/014-1/wedding-officiator.txt b/world/map/npc/014-1/wedding-officiator.txt
index fc237082..dfdab00b 100644
--- a/world/map/npc/014-1/wedding-officiator.txt
+++ b/world/map/npc/014-1/wedding-officiator.txt
@@ -9,7 +9,7 @@
goto L_main;
L_main:
- if (getpartnerid2())
+ if (PARTNER)
goto L_main_married;
menu
@@ -35,10 +35,10 @@ L_explain_marriage:
mes "\"Both you and your partner must be at least " + WEDDING_MIN_LEVEL + " levels of age, though; the law is very firm on that. But if all of that works out, I will give you two wedding rings for the ceremony.\"";
next;
mes "[Wedding Officiator]";
- mes "\"To complete the marriage, each of you has to put on one of these rings, and you have to stand next to each other in the southern part of this park. Then one of you says `marry' and then the other person's name.\"";
+ mes "\"To complete the marriage, each of you has to put on one of these rings, and you have to stand next to each other in the southern part of this park. Then one of you says `#marry' and then the other person's name.\"";
next;
mes "[Wedding Officiator]";
- mes "\"So if you would want to marry me, for example, you would say `marry Wendy'. Just like that. Your partner then has to decide whether he or she wants that. And if you both agree, then you're married!\"";
+ mes "\"So if you would want to marry me, for example, you would say `#marry Wendy'. Just like that. Your partner then has to decide whether he or she wants that. And if you both agree, then you're married!\"";
mes "She again smiles that broad smile of hers.";
next;
goto L_main;
@@ -135,7 +135,7 @@ L_too_poor:
L_main_married:
mes "[Wedding Officiator]";
- mes "\"I hope that you and your partner are doing well?\"";
+ mes "\"I hope that you and "+ strcharinfo(0, get(BL_ID, PARTNER)) +" are doing well?\"";
next;
menu
"We are very happy, thanks for asking!", L_farewell,
@@ -219,8 +219,8 @@ L_divorce_nomoney:
L_do_divorce:
if (Zeny < @divorce_cost)
goto L_divorce_nomoney;
- if (divorce())
- goto L_DidDivorce;
+ set PARTNER, 0, PARTNER; // divorce the partner first, which will also divorce the rid if succesful
+ if (PARTNER < 1) goto L_DidDivorce;
mes "[Wedding Officiator]";
mes "The officiator searches through her records for your partner.";
diff --git a/world/map/npc/015-1/sword.txt b/world/map/npc/015-1/sword.txt
index 239de752..90c56283 100644
--- a/world/map/npc/015-1/sword.txt
+++ b/world/map/npc/015-1/sword.txt
@@ -109,7 +109,7 @@ L_Initial_ok:
mes "\"Oh, my apologies – that was a little overly dramatic. But I do not get to talk to thy kin anymore all that often.\"";
next;
mes "[Mystic Sword]";
- mes "\"For the flare dart spell throw a handful of sulphur powder up into the air, and say, '" + getspellinvocation("flare-dart") + "'.\"";
+ mes "\"For the flare dart spell throw a handful of sulphur powder up into the air, and say, '" + ("flare-dart") + "'.\"";
set @Q_status, @STATUS_LEARNED_FLAREDART;
callsub S_update_var;
next;
@@ -257,7 +257,7 @@ L_Next3:
callsub S_update_var;
next;
mes "[Mystic Sword]";
- mes "\"Speak '" + getspellinvocation("magic-knuckles") + "' and take a glass of beer and drink it, without ever taking it off thy lips. This will harden and enchant thy fists, turning them into powerful weapons.\"";
+ mes "\"Speak '" + ("magic-knuckles") + "' and take a glass of beer and drink it, without ever taking it off thy lips. This will harden and enchant thy fists, turning them into powerful weapons.\"";
close;
L_L2_almost_done:
@@ -297,7 +297,7 @@ L_Next4:
callsub S_update_var;
next;
mes "[Mystic Sword]";
- mes "\"This powder thou shalst need to cast the lightning spell. Throw it up into the air and shout '" + getspellinvocation("lightning-strike") + "', and smite thine enemies with lightning.\"";
+ mes "\"This powder thou shalst need to cast the lightning spell. Throw it up into the air and shout '" + ("lightning-strike") + "', and smite thine enemies with lightning.\"";
next;
goto L_Farewell;
diff --git a/world/map/npc/017-4/waric.txt b/world/map/npc/017-4/waric.txt
index f98cb0d0..11f836b6 100644
--- a/world/map/npc/017-4/waric.txt
+++ b/world/map/npc/017-4/waric.txt
@@ -234,7 +234,7 @@ L_Mushroom:
mes "\"Now that you are a student of mine, I will teach you some spells.\"";
next;
mes "\"We will start with an easy one. I will teach you how to summon a wicked mushroom.\"";
- mes "\"The spell consumes a Small Mushroom and a Dark Crystal. Shove the Dark Crystal into the Small Mushroom and yell " + getspellinvocation("summon-wickedmushroom") +".\"";
+ mes "\"The spell consumes a Small Mushroom and a Dark Crystal. Shove the Dark Crystal into the Small Mushroom and yell " + ("summon-wickedmushroom") +".\"";
next;
mes "\"A wicked mushroom will appear to fight for you.\"";
set OrumQuest, 37;
@@ -254,7 +254,7 @@ L_Next4:
next;
mes "\"You have to use two roots for this spell. First you have to take one root and break off all the root hair. Shape it into a stick, if you will. Then put it on top of the other root and form an arrow-like structure.\"";
next;
- mes "\"Once this is done you have to throw it in the air and scream " + getspellinvocation("toxic-dart") + " and the two roots will turn into toxic darts, a projectile you can throw.\"";
+ mes "\"Once this is done you have to throw it in the air and scream " + ("toxic-dart") + " and the two roots will turn into toxic darts, a projectile you can throw.\"";
next;
mes "\"If you want to learn more, come back later.\"";
set OrumQuest, 38;
@@ -312,7 +312,7 @@ L_SnakesSpell:
L_Next7:
mes "[Waric]";
- mes "\"I said " + getspellinvocation("summon-snakes") + ".\"";
+ mes "\"I said " + ("summon-snakes") + ".\"";
mes "\"Have fun with those spells and use them to cause hate, anger and death.\"";
set OrumQuest, 41;
goto L_Close;
@@ -341,9 +341,9 @@ L_MoreMagic:
L_Next8:
mes "[Waric]";
mes "\"Yes, of course.\"";
- mes "\"To summon the snakes use " + getspellinvocation("summon-snakes") + ".\"";
- mes "\"Say " + getspellinvocation("toxic-dart") + " to make your roots into toxic darts.\"";
- mes "\"And the first spell, to summon wicked mushrooms, is " + getspellinvocation("summon-wickedmushroom") + ".\"";
+ mes "\"To summon the snakes use " + ("summon-snakes") + ".\"";
+ mes "\"Say " + ("toxic-dart") + " to make your roots into toxic darts.\"";
+ mes "\"And the first spell, to summon wicked mushrooms, is " + ("summon-wickedmushroom") + ".\"";
next;
mes "\"Now leave. Spread chaos with the spells I have taught you!\"";
goto L_Close;
diff --git a/world/map/npc/017-9/npcs.txt b/world/map/npc/017-9/npcs.txt
index b14428c5..e5a2ec04 100644
--- a/world/map/npc/017-9/npcs.txt
+++ b/world/map/npc/017-9/npcs.txt
@@ -44,3 +44,13 @@
callfunc "SuperDebug";
end;
}
+
+-|script|Numa Spell|32767
+{
+ callfunc "SuperDebug";
+ end;
+
+OnInit:
+ registercmd "@numa", "Numa Spell";
+ end;
+}
diff --git a/world/map/npc/027-6/general_krukan.txt b/world/map/npc/027-6/general_krukan.txt
index 6b086cee..1c2ff95f 100644
--- a/world/map/npc/027-6/general_krukan.txt
+++ b/world/map/npc/027-6/general_krukan.txt
@@ -86,7 +86,7 @@ OnTimer5000:
L_Return_1:
set $@CRYPT_FIGHT1_PLAYER_COUNT, 0;
- areatimer "027-6", 0, 0, 79, 84, 10, "General Krukan::OnTick";
+ areatimer 0, "027-6", 0, 0, 79, 84, 10, "General Krukan::OnTick";
end;
L_CryptLogic:
@@ -182,7 +182,7 @@ L_CleanUpLosers:
end;
L_CleanUp:
- areatimer "027-6", 0, 0, 79, 84, 10, "General Krukan::OnReward";
+ areatimer 0, "027-6", 0, 0, 79, 84, 10, "General Krukan::OnReward";
set $@CRYPT_FIGHT1, 0;
set $@CRYPT_FIGHT1_PLAYER_COUNT, 0;
set $@CRYPT_FIGHT1_WAVE, 0;
diff --git a/world/map/npc/027-7/general_razha.txt b/world/map/npc/027-7/general_razha.txt
index e22f6392..f331d95c 100644
--- a/world/map/npc/027-7/general_razha.txt
+++ b/world/map/npc/027-7/general_razha.txt
@@ -86,7 +86,7 @@ OnTimer5000:
L_Return_1:
set $@CRYPT_FIGHT2_PLAYER_COUNT, 0;
- areatimer "027-7", 0, 0, 79, 84, 10, "General Razha::OnTick";
+ areatimer 0, "027-7", 0, 0, 79, 84, 10, "General Razha::OnTick";
end;
L_CryptLogic:
@@ -186,7 +186,7 @@ L_CleanUpLosers:
L_CleanUp:
mapannounce "027-7", "General Razha : How in all hells could that happen? I am lost forever.", 0;
mapannounce "027-4", "General Razha is defeated.", 0;
- areatimer "027-7", 0, 0, 79, 84, 10, "General Razha::OnReward";
+ areatimer 0, "027-7", 0, 0, 79, 84, 10, "General Razha::OnReward";
set $@CRYPT_FIGHT2, 0;
set $@CRYPT_FIGHT2_PLAYER_COUNT, 0;
set $@CRYPT_FIGHT2_WAVE, 0;
diff --git a/world/map/npc/027-8/general_terogan.txt b/world/map/npc/027-8/general_terogan.txt
index ca8691f0..522b1eaa 100644
--- a/world/map/npc/027-8/general_terogan.txt
+++ b/world/map/npc/027-8/general_terogan.txt
@@ -141,7 +141,7 @@ OnTimer5000:
L_Return_1:
set $@CRYPT_FIGHT3_PLAYER_COUNT, 0;
- areatimer "027-8", 0, 0, 79, 84, 10, "General Terogan#Main::OnTick";
+ areatimer 0, "027-8", 0, 0, 79, 84, 10, "General Terogan#Main::OnTick";
end;
L_CryptLogic:
@@ -249,7 +249,7 @@ L_CleanUpLosers:
L_CleanUp:
mapannounce "027-8", "General Terogan : You might have won this battle, but you will never defeat me!", 0;
- areatimer "027-8", 0, 0, 79, 84, 10, "General Terogan#Main::OnReward";
+ areatimer 0, "027-8", 0, 0, 79, 84, 10, "General Terogan#Main::OnReward";
set $@CRYPT_FIGHT3, 0;
set $@CRYPT_FIGHT3_PLAYER_COUNT, 0;
set $@CRYPT_FIGHT3_WAVE, 0;
diff --git a/world/map/npc/029-1/barrier.txt b/world/map/npc/029-1/barrier.txt
index e6c580ad..7414f78b 100644
--- a/world/map/npc/029-1/barrier.txt
+++ b/world/map/npc/029-1/barrier.txt
@@ -18,6 +18,6 @@ OnTalk:
end;
OnCommandTalk:
- areatimer "029-1", 61, 61, 69, 73, 0, "#CandorAnnouncer::OnTalk";
+ areatimer 0, "029-1", 61, 61, 69, 73, 0, "#CandorAnnouncer::OnTalk";
end;
}
diff --git a/world/map/npc/029-2/morgan.txt b/world/map/npc/029-2/morgan.txt
index 1f8f19f4..d5604f93 100644
--- a/world/map/npc/029-2/morgan.txt
+++ b/world/map/npc/029-2/morgan.txt
@@ -78,7 +78,7 @@ L_Start:
mes "\"Various wands and staffs are found throughout the land with many different strengths and weaknesses.\"";
mes "\"To use the wand you need to have it equipped and speak the incantation to let it tap into your mana.\"";
mes "\"As the power of your magic grows so will the spells you can cast.\"";
- mes "\"Lets start with a basic wand attack. " + getspellinvocation("wand") + "\"";
+ mes "\"Lets start with a basic wand attack. " + get(.invocation$, "spell-wand") + "\"";
mes "\"Equip the wand and lets try out that spell.\"";
mes "\"To cast a spell open the chat window, type the invocation and press enter.\"";
mes "\"Speak to me again once you've cast the spell.\"";
@@ -86,7 +86,7 @@ L_Start:
L_Started:
mes "[Morgan]";
- mes "\"Lets start with a basic wand attack. " + getspellinvocation("wand") + "\"";
+ mes "\"Lets start with a basic wand attack. " + get(.invocation$, "spell-wand") + "\"";
mes "\"Equip the wand and lets try out that spell.\"";
mes "\"To cast a spell open the chat window, type the invocation and press enter.\"";
mes "\"Speak to me again once you've cast the spell.\"";
@@ -95,7 +95,7 @@ L_Started:
L_CastOnce:
mes "[Morgan]";
mes "\"Ok, good job! Looks like you have good mana flow.\"";
- mes "\"Onto the next lesson. Now that you have " + getspellinvocation("wand") + " cast,\"";
+ mes "\"Onto the next lesson. Now that you have " + get(.invocation$, "spell-wand") + " cast,\"";
mes "\"Each time you attack the wand will convert a bit of you mana into a magic bolt.\"";
mes "\"After so many attacks, you will need to recast the invocation to stay attuned to the wand.\"";
mes "\"(Logging out will also cancel any spell effects currently active in-game.).\"";
@@ -106,7 +106,7 @@ L_CastOnce:
L_LearningDone:
mes "[Morgan]";
- mes "\"" + getspellinvocation("wand") + " is a basic wand attack.\"";
+ mes "\"" + get(.invocation$, "spell-wand") + " is a basic wand attack.\"";
mes "\"A Wand must be equipped to use the spell.\"";
mes "\"To cast a spell open the chat window, type the invocation and press enter.\"";
mes "\"I've taught you all I can for now. You should visit the Mana Seed north west of Hurnscald.\"";
diff --git a/world/map/npc/029-2/tanisha.txt b/world/map/npc/029-2/tanisha.txt
index 7142721e..025cc499 100644
--- a/world/map/npc/029-2/tanisha.txt
+++ b/world/map/npc/029-2/tanisha.txt
@@ -221,7 +221,7 @@ OnTimer1000:
if (getareausers("029-2", 98, 84, 106, 89) == 0)
goto L_CleanUp;
// This is needed because multiple players can be in the area at once
- areatimer "029-2", 98, 84, 106, 89, 0, "Tanisha::OnTick";
+ areatimer 0, "029-2", 98, 84, 106, 89, 0, "Tanisha::OnTick";
end;
L_CleanUp:
diff --git a/world/map/npc/029-3/parua.txt b/world/map/npc/029-3/parua.txt
index 5ebcc4d7..ef630413 100644
--- a/world/map/npc/029-3/parua.txt
+++ b/world/map/npc/029-3/parua.txt
@@ -187,7 +187,7 @@ OnTimer5000:
L_Return_1:
set $@FIGHT_CAVE_PLAYER_COUNT, 0;
- areatimer "029-3", 20, 20, 70, 60, 10, "Parua::OnTick";
+ areatimer 0, "029-3", 20, 20, 70, 60, 10, "Parua::OnTick";
end;
L_CaveLogic:
@@ -215,7 +215,7 @@ L_NextRound:
goto L_CleanUp;
set $@FIGHT_CAVE_POINTS, $@FIGHT_CAVE_LEVEL;
- areatimer "029-3", 20, 20, 70, 60, 10, "Parua::OnNewRound";
+ areatimer 0, "029-3", 20, 20, 70, 60, 10, "Parua::OnNewRound";
set $@candor_npctalk$, "The next round (level " + $@FIGHT_CAVE_LEVEL + ") is starting with " + $@FIGHT_CAVE_PLAYER_COUNT + " player(s) left alive.";
donpcevent "#CandorAnnouncer::OnCommandTalk";
@@ -360,7 +360,7 @@ L_CleanUp:
npctalk strnpcinfo(0), "Game Over";
set $@candor_npctalk$, "The dungeon is now ready for its next victims.";
donpcevent "#CandorAnnouncer::OnCommandTalk";
- areatimer "029-3", 20, 20, 70, 60, 10, "Parua::OnReward";
+ areatimer 0, "029-3", 20, 20, 70, 60, 10, "Parua::OnReward";
set $@FIGHT_CAVE_STATUS, 0;
set $@ANNOUNCE_TIME, 0;
set $@FIGHT_CAVE_PAID, 0;
diff --git a/world/map/npc/030-4/mana_battery.txt b/world/map/npc/030-4/mana_battery.txt
index aea601c5..15ff40c3 100644
--- a/world/map/npc/030-4/mana_battery.txt
+++ b/world/map/npc/030-4/mana_battery.txt
@@ -197,7 +197,7 @@ OnTimer5000:
L_Return_1:
set $@XmasBossPlayerCount, 0;
- areatimer "030-4", 0, 0, 60, 60, 10, "AniManOMat::OnTick";
+ areatimer 0, "030-4", 0, 0, 60, 60, 10, "AniManOMat::OnTick";
end;
L_CaveLogic:
@@ -294,7 +294,7 @@ L_Finished:
goto L_CleanUp;
L_CleanUp:
- areatimer "030-4", 0, 0, 50, 50, 10, "AniManOMat::OnReward";
+ areatimer 0, "030-4", 0, 0, 50, 50, 10, "AniManOMat::OnReward";
set $@XmasBossPlayerCount, 0;
set $@XmasBossRound, 0;
set $@BombTimer, 0;
@@ -338,7 +338,7 @@ L_EndNice:
end;
OnCommandChamberReset:
- areatimer "030-4", 0, 0, 50, 50, 10, "AniManOMat::OnReward";
+ areatimer 0, "030-4", 0, 0, 50, 50, 10, "AniManOMat::OnReward";
set $@XmasBattleStatus, 0;
set $@XmasBossPlayerCount, 0;
set $@XmasBossRound, 0;
diff --git a/world/map/npc/031-4/cindyCave.txt b/world/map/npc/031-4/cindyCave.txt
index 33c3a16f..c97b166d 100644
--- a/world/map/npc/031-4/cindyCave.txt
+++ b/world/map/npc/031-4/cindyCave.txt
@@ -131,7 +131,7 @@ OnTimer5000:
L_Return_1:
set $@FIGHT_YETI_PLAYER_COUNT, 0;
- areatimer "031-4", 0, 0, 95, 91, 10, "Cindy::OnTick";
+ areatimer 0, "031-4", 0, 0, 95, 91, 10, "Cindy::OnTick";
end;
L_CaveLogic:
@@ -184,7 +184,7 @@ OnPetDeath:
end;
L_CleanUp:
- areatimer "031-4", 0, 0, 95, 91, 10, "Cindy::OnReward";
+ areatimer 0, "031-4", 0, 0, 95, 91, 10, "Cindy::OnReward";
set $@FIGHT_YETI_STATUS, 0;
set $@FIGHT_YETI_PLAYER_COUNT, 0;
set $@FIGHT_YETI_WAVE, 0;
diff --git a/world/map/npc/033-1/kimarr.txt b/world/map/npc/033-1/kimarr.txt
index 6650198f..cbe2b289 100644
--- a/world/map/npc/033-1/kimarr.txt
+++ b/world/map/npc/033-1/kimarr.txt
@@ -196,7 +196,7 @@ L_Action:
goto L_Died;
// Checking if there is more than 1 player in the fight area
if (getareausers("033-1", 79, 28, 88, 42) > 1)
- areatimer "033-1", 79, 28, 88, 42, 10, "Kimarr::OnTooMany";
+ areatimer 0, "033-1", 79, 28, 88, 42, 10, "Kimarr::OnTooMany";
if ($@Fluffy_Time == 180)
npctalk strnpcinfo(0), strcharinfo(0) + ", you have 3 minutes.";
diff --git a/world/map/npc/051-3/ambush.txt b/world/map/npc/051-3/ambush.txt
index da12b306..7d659710 100644
--- a/world/map/npc/051-3/ambush.txt
+++ b/world/map/npc/051-3/ambush.txt
@@ -72,8 +72,8 @@ OnTimer9000:
end;
OnTimer11000:
- areatimer "051-3", 22, 12, 102, 97, 500, "#BndtTl::OnOuch";
- areatimer "051-3", 22, 12, 102, 97, 3000, "#BndtTl::OnA";
+ areatimer 0, "051-3", 22, 12, 102, 97, 500, "#BndtTl::OnOuch";
+ areatimer 0, "051-3", 22, 12, 102, 97, 3000, "#BndtTl::OnA";
stopnpctimer;
setnpctimer 0;
end;
diff --git a/world/map/npc/051-3/reinforcements.txt b/world/map/npc/051-3/reinforcements.txt
index 73236dec..5870671c 100644
--- a/world/map/npc/051-3/reinforcements.txt
+++ b/world/map/npc/051-3/reinforcements.txt
@@ -49,7 +49,7 @@ OnRnfrcmts:
areamonster "051-3", 29, 25, 48, 39, "", 1065, 3, "Door::OnB";
initnpctimer;
mapannounce "051-3", "Bandit Lords : Do not let them escape!!" , 0;
- areatimer "051-3", 25, 20, 80, 85, 10, "Door::OnDRnfrcmts";
+ areatimer 0, "051-3", 25, 20, 80, 85, 10, "Door::OnDRnfrcmts";
end;
OnB:
@@ -72,7 +72,7 @@ L_OpenDoor:
set $@illia_progress, 3;
callfunc "UpdateIlliaProgress";
set $@illia_max_time, $@illia_max_time + 300;
- areatimer "051-3", 25, 20, 80, 85, 10, "Door::OnKeyFound";
+ areatimer 0, "051-3", 25, 20, 80, 85, 10, "Door::OnKeyFound";
stopnpctimer;
setnpctimer 0;
end;
diff --git a/world/map/npc/052-1/channelling.txt b/world/map/npc/052-1/channelling.txt
index 565f96fd..5eb3dfbf 100644
--- a/world/map/npc/052-1/channelling.txt
+++ b/world/map/npc/052-1/channelling.txt
@@ -141,6 +141,10 @@ L_Return:
goto L_Hint;
end;
+OnCast:
+ callfunc "StartChannelling";
+ end;
+
OnCommandSt:
initnpctimer;
end;
@@ -259,7 +263,7 @@ S_CheckChannelling:
set $@illia_channelling_status_msg$, $@illia_char_channelling$ + ": Damn! It faded a little.";
if ($@illia_channelling_status_msg$ != "")
- areatimer "052-1", 1, 1, 100, 80, 0, "#Power Circle::OnMPSC";
+ areatimer 0, "052-1", 1, 1, 100, 80, 0, "#Power Circle::OnMPSC";
return;
@@ -328,4 +332,8 @@ L_ChannellingFail:
L_ShouldNotBeHere:
heal -Hp, 0;
end;
+
+OnInit:
+ registercmd "#catalazuli", strnpcinfo(0)+"::OnCast";
+ end;
}
diff --git a/world/map/npc/052-2/lobby.txt b/world/map/npc/052-2/lobby.txt
index efc0a20a..1b36d929 100644
--- a/world/map/npc/052-2/lobby.txt
+++ b/world/map/npc/052-2/lobby.txt
@@ -337,7 +337,7 @@ L_ChaseLuvia:
set $@illia_progress, 6;
callfunc "UpdateIlliaProgress";
set $@illia_max_time, $@illia_max_time + 360;
- areatimer "052-2", 19, 18, 48, 43, 2000, "#LuviaShadow::OnNN";
+ areatimer 0, "052-2", 19, 18, 48, 43, 2000, "#LuviaShadow::OnNN";
end;
S_GetHeroRect:
diff --git a/world/map/npc/052-2/partyroom.txt b/world/map/npc/052-2/partyroom.txt
index 02d7a7ac..ec6d2a64 100644
--- a/world/map/npc/052-2/partyroom.txt
+++ b/world/map/npc/052-2/partyroom.txt
@@ -182,7 +182,7 @@ S_SpawnWitchGuard:
misceffect FX_GROUND_SPAWN;
monster "052-2", getx(), gety(), "", 1103, 1, "#LuviaDaemon::OnWGD";
detachrid;
- areatimer "052-2", 73, 11, 115, 49, 0, "#LuviaDaemon::OnWGS";
+ areatimer 0, "052-2", 73, 11, 115, 49, 0, "#LuviaDaemon::OnWGS";
return;
OnTimer30000:
@@ -198,7 +198,7 @@ OnTimer30000:
L_TriggerTrance:
set $@illia_level_7_progress, 3;
set $@illia_luvia_trance_delay, 0;
- areatimer "052-2", 73, 11, 115, 49, 0, "#LuviaDaemon::OnTT";
+ areatimer 0, "052-2", 73, 11, 115, 49, 0, "#LuviaDaemon::OnTT";
setnpctimer 0;
end;
@@ -217,9 +217,9 @@ OnDeath:
mapannounce "052-2", "Luvia : How? By mere humans! But we will see again! Enjoy your victory while it lasts, " + $@ILLIA_HERO$ + "!!", 0;
set $@illia_bp, $Illia_Luvia_Harvest * 16 / 10 + 120;
- areatimer "052-2", 73, 11, 115, 49, 0, "#LuviaDaemon::OnBP";
+ areatimer 0, "052-2", 73, 11, 115, 49, 0, "#LuviaDaemon::OnBP";
- areatimer "052-2", 73, 11, 115, 49, 2000, "#LuviaDaemon::OnW00t";
+ areatimer 0, "052-2", 73, 11, 115, 49, 2000, "#LuviaDaemon::OnW00t";
set $@illia_progress, 8;
callfunc "UpdateIlliaProgress";
diff --git a/world/map/npc/052-2/storage.txt b/world/map/npc/052-2/storage.txt
index 8abbb732..a8582408 100644
--- a/world/map/npc/052-2/storage.txt
+++ b/world/map/npc/052-2/storage.txt
@@ -42,7 +42,7 @@ OnCommandStart:
set $@illia_storage_max_items, 20;
set $@illia_storage_deviation, (8 + ($Illia_Luvia_Harvest*70)/100)*3;
initnpctimer;
- areatimer "052-2", 19, 60, 35, 78, 10, "#ItemsInvoker::OnStart";
+ areatimer 0, "052-2", 19, 60, 35, 78, 10, "#ItemsInvoker::OnStart";
end;
OnStart:
@@ -64,7 +64,7 @@ OnTimer1000:
OnTimer1500:
// See the note above.
enablenpc "#ItemsInvoker";
- areatimer "052-2", 19, 60, 35, 78, 10, "#ItemsInvoker::OnItem";
+ areatimer 0, "052-2", 19, 60, 35, 78, 10, "#ItemsInvoker::OnItem";
misceffect FX_GROUND_SPAWN;
end;
@@ -109,7 +109,7 @@ L_ItemSpawn:
L_MakeSpecialMonster:
monster "052-2", $@item_invoke_x, $@item_invoke_y, "", 1103, 1, "#ItemsInvoker::OnDeath";
- areatimer "052-2", 19, 60, 35, 78, 10, "#ItemsInvoker::OnWtf";
+ areatimer 0, "052-2", 19, 60, 35, 78, 10, "#ItemsInvoker::OnWtf";
set $@illia_storage_max_items, $@illia_storage_max_items - 1;
end;
@@ -121,7 +121,7 @@ L_MakeMonster:
L_MakeSpecialItem:
makeitem $@illia_storage_special_items[rand(getarraysize($@illia_storage_special_items))], rand(2, 4), "052-2", $@item_invoke_x, $@item_invoke_y;
- areatimer "052-2", 19, 60, 35, 78, 10, "#ItemsInvoker::OnWow";
+ areatimer 0, "052-2", 19, 60, 35, 78, 10, "#ItemsInvoker::OnWow";
set $@illia_storage_max_items, $@illia_storage_max_items - 1;
set @r, 0;
end;
@@ -152,7 +152,7 @@ L_Stop:
set $@illia_progress, 7;
callfunc "UpdateIlliaProgress";
set $@illia_max_time, $@illia_max_time + 900;
- areatimer "052-2", 19, 60, 35, 78, 10, "#ItemsInvoker::OnStop";
+ areatimer 0, "052-2", 19, 60, 35, 78, 10, "#ItemsInvoker::OnStop";
end;
OnDeath:
diff --git a/world/map/npc/commands/_atcommand_local.txt.example b/world/map/npc/commands/_atcommand_local.txt.example
new file mode 100644
index 00000000..a195d580
--- /dev/null
+++ b/world/map/npc/commands/_atcommand_local.txt.example
@@ -0,0 +1,12 @@
+-|script|GM|32767
+{
+ end;
+
+OnInit:
+ // define permissions here
+ set .zeny, G_ADMIN;
+
+ // permissions for events
+ set .killthegm, G_EVENT;
+ end;
+}
diff --git a/world/map/npc/commands/_import.txt b/world/map/npc/commands/_import.txt
new file mode 100644
index 00000000..7efe4111
--- /dev/null
+++ b/world/map/npc/commands/_import.txt
@@ -0,0 +1,4 @@
+npc: npc/commands/_procedures.txt
+npc: npc/commands/_atcommand_local.txt
+npc: npc/commands/zeny.txt
+npc: npc/commands/marry.txt
diff --git a/world/map/npc/commands/_procedures.txt b/world/map/npc/commands/_procedures.txt
new file mode 100644
index 00000000..77c1c7e9
--- /dev/null
+++ b/world/map/npc/commands/_procedures.txt
@@ -0,0 +1,53 @@
+// ARGV Splitter
+// takes @args$ and splits it properly so that '@cmd "foo bar" baz' is ['foo bar','baz'] instead of ['foo','bar','baz']
+// input: @args$ (string)
+// output: @argv$ (array) and @argv (array)
+function|script|argv_splitter
+{
+ explode .@fragments$, @args$, " ";
+ set .@e, 0;
+ set .@total, getarraysize(.@fragments$);
+ set .@NULL$, chr(3); // HACK: we use .@NULL$ as a workaround because we can't do "\0"
+ goto L_Check;
+
+L_Check:
+ setarray .@check$[0], "", .@NULL$, .@NULL$;
+ explode .@check$, .@fragments$[.@e], "\""; // check if the fragment contains a quote
+ if (.@check$[0] == "" && .@check$[1] != .@NULL$ && .@check$[1] != "" && .@check$[2] == .@NULL$)
+ set .@string$, .@check$[1]; // begin substring
+ elif (.@check$[0] != "" && .@check$[1] == "" && .@check$[2] == .@NULL$)
+ goto L_EndSubString; // end substring
+ elif (.@string$ != "" && .@check$[0] != "" && .@check$[1] == .@NULL$ && .@check$[2] == .@NULL$)
+ set .@string$, .@string$ +" "+ .@check$[0]; // part of the substring
+ elif (.@check$[2] != .@NULL$) goto L_Set2; // the the argument is quoted but there is no space
+ else goto L_Set;
+ goto L_CheckAfter;
+
+L_Set:
+ setarray @argv$[.@t], .@check$[0]; // not in a substring so push right away
+ setarray @argv[.@t], .@check$[0]; // not in a substring so push right away
+ set .@t, .@t + 1;
+ goto L_CheckAfter;
+
+L_Set2:
+ setarray @argv$[.@t], .@check$[1]; // not in a substring so push right away
+ setarray @argv[.@t], .@check$[1]; // not in a substring so push right away
+ set .@t, .@t + 1;
+ goto L_CheckAfter;
+
+L_EndSubString:
+ set .@string$, .@string$ + " " + .@check$[0];
+ setarray @argv$[.@t], .@string$; // push in the array
+ setarray @argv[.@t], .@string$; // push in the array
+ set .@t, .@t + 1;
+ set .@string$, ""; // clean
+ goto L_CheckAfter;
+
+L_CheckAfter:
+ set .@e, .@e + 1;
+ if (.@e > .@total) goto L_Done; // the @argv$ array is built
+ goto L_Check; // not done yet
+
+L_Done:
+ return;
+}
diff --git a/world/map/npc/commands/marry.txt b/world/map/npc/commands/marry.txt
new file mode 100644
index 00000000..39efe6b8
--- /dev/null
+++ b/world/map/npc/commands/marry.txt
@@ -0,0 +1,69 @@
+-|script|special-marry|32767
+{
+ set .@target_id, getcharid(3, @args$);
+ if (.@target_id < 1 || !(isloggedin(.@target_id)) || .@target_id == BL_ID) goto L_NotFound;
+ if (PARTNER || get(PARTNER, .@target_id)) goto L_AlreadyMarried;
+ if (isin("014-1",29,36,34,39) == 0 && isin("001-1",20,27,22,27) == 0) goto L_NotInArea;
+ if (distance(BL_ID, .@target_id) != 1) goto L_AwayFromPartner;
+ if (BaseLevel < WEDDING_MIN_LEVEL || get(BaseLevel, .@target_id) < WEDDING_MIN_LEVEL) goto L_TooYoung;
+ if (getequipid(equip_shield) != 702 || getequipid(equip_shield, @args$) != 702) goto L_NoRing;
+
+ if (get(@marriage[0], .@target_id) == BL_ID) goto L_Proceed;
+
+ setarray @marriage[0], .@target_id, gettimetick(2);
+ addtimer (.timeout * 1000), strnpcinfo(0) + "::OnTimeout";
+ announce strcharinfo(0) + " is asking " + strcharinfo(0, .@target_id) + " for marriage.", 2;
+ message strcharinfo(0, .@target_id), "Marriage : ##3##B" + strcharinfo(0) + " wishes to marry you. To accept, write `##1#marry "+strcharinfo(0)+"##3` within the next "+.timeout+" seconds.";
+ end;
+
+L_NotFound:
+ message strcharinfo(0), "Marriage : ##3##BThe target player is either not found or yourself.";
+ end;
+
+L_TooYoung:
+ message strcharinfo(0), "Marriage : ##3##BYou and your partner need to be at least level "+ WEDDING_MIN_LEVEL +".";
+ end;
+
+L_NoRing:
+ message strcharinfo(0), "Marriage : ##3##BYou and your partner need to have ["+ getitemlink("WeddingRing") +"] equipped.";
+ end;
+
+L_AwayFromPartner:
+ message strcharinfo(0), "Marriage : ##3##BYou and your partner need to be standing next to each other.";
+ end;
+
+L_NotInArea:
+ message strcharinfo(0), "Marriage : ##3##BYou are not standing in a designated marriage area.";
+ end;
+
+L_Proceed:
+ if ((gettimetick(2) - .timeout) > get(@marriage[1], .@target_id)) goto L_TooLate;
+ set PARTNER, CHAR_ID, .@target_id;
+ if (PARTNER == get(CHAR_ID, .@target_id)) goto L_Success;
+ set PARTNER, 0, .@target_id;
+ set PARTNER, 0;
+ end;
+
+L_Success:
+ announce strcharinfo(0) + " and " + strcharinfo(0, .@target_id) + " are now married.", 2;
+ end;
+
+OnTimeout:
+ goto L_TooLate;
+
+L_TooLate:
+ message strcharinfo(0), "Marriage : ##3##BThe proposal expired. Please try again.";
+ message strcharinfo(0, @marriage[0]), "Marriage : ##3##BThe proposal expired. Please try again.";
+ set @marriage[0], 0, @marriage[0];
+ set @marriage[0], 0;
+ end;
+
+L_AlreadyMarried:
+ message strcharinfo(0), "Marriage : ##3##BYou"+ if_then_else(PARTNER, " are", "r partner is") +" already married.";
+ end;
+
+OnInit:
+ set .timeout, 30; // timeout for proposal
+ registercmd "#marry", strnpcinfo(0); // we NEED to use a # before `marry` because otherwise manaplus does not strip colors
+ end;
+}
diff --git a/world/map/npc/commands/zeny.txt b/world/map/npc/commands/zeny.txt
new file mode 100644
index 00000000..9215637a
--- /dev/null
+++ b/world/map/npc/commands/zeny.txt
@@ -0,0 +1,77 @@
+-|script|@zeny|32767
+{
+ if (GM < get(.zeny, "GM") && GM < G_SYSOP) goto L_GM;
+ callfunc "argv_splitter";
+ set .@target_id, BL_ID;
+ if (@argv$[1] != "") set .@target_id, getcharid(3, @argv$[1]);
+ if (@argv$[1] != "" && !(isloggedin(.@target_id))) goto L_Failed; // do NOT fallback to self
+ if (@argv$[0] == "--") goto L_Remove;
+ if (@argv$[0] == "---") goto L_RemoveAll;
+ if (@argv$[0] == "++") goto L_Max;
+ if (@argv$[0] == "+++") goto L_MaxAll;
+ set .@delta, @argv[0]; // ± zeny
+ set .@zeny, get(Zeny, .@target_id); // get the number of zeny in char
+ set .@bank, get(#BankAccount, .@target_id); // get number of zeny in (world) account
+ set .@new_zeny, .@zeny + .@delta; // new balance in char
+ if (.@new_zeny < 0) goto L_MaybeRemoveBank; // zeny would be below 0 so check if we can take from bank
+ if (.@new_zeny > .max_zeny) goto L_MaybeAddBank; // zeny would be over the limit so check if we can store in bank
+ set Zeny, (.@zeny + .@delta), .@target_id;
+ goto L_Success;
+
+L_Remove:
+ set Zeny, 0, .@target_id;
+ goto L_Success;
+
+L_RemoveAll:
+ set Zeny, 0, .@target_id;
+ set #BankAccount, 0, .@target_id;
+ goto L_Success;
+
+L_Max:
+ set Zeny, .max_zeny, .@target_id;
+ goto L_Success;
+
+L_MaxAll:
+ set Zeny, .max_zeny, .@target_id;
+ set #BankAccount, .max_int, .@target_id;
+ goto L_Success;
+
+L_MaybeAddBank:
+ set .@new_bank, (.@bank + (.@new_zeny - .max_zeny));
+ if (.@new_bank > .max_int || .@new_bank < 0) goto L_OutOfBounds;
+ set Zeny, .max_zeny, .@target_id;
+ set #BankAccount, .@new_bank, .@target_id;
+ goto L_Success;
+
+L_MaybeRemoveBank:
+ if ((.@bank + .@new_zeny) < 0) goto L_OutOfBounds;
+ set Zeny, 0, .@target_id;
+ set #BankAccount, (.@bank + .@new_zeny), .@target_id;
+ goto L_Success;
+
+L_OutOfBounds:
+ // XXX: maybe we could also take from other chars from the same accout?
+ message strcharinfo(0), "zeny : Impossible to proceed! This would cause the player to have less than 0 zeny or more than " + .max_int + ".";
+ end;
+
+L_Failed:
+ // XXX: should we allow GMs to change zeny of users that are not logged in?
+ message strcharinfo(0), "zeny : Impossible to attach to the target player.";
+ end;
+
+L_Success:
+ gmlog "@zeny " + @args$;
+ message strcharinfo(0), "zeny : The operation succeeded.";
+ end;
+
+L_GM:
+ message strcharinfo(0), "zeny : GM command is level "+ get(.zeny, "GM") +", but you are level " + GM;
+ end;
+
+OnInit:
+ set .max_zeny, 1000000000; // hardcoded in tmwa
+ set .max_int, 2147483647; // max int32 value
+ registercmd chr(ATCMD_SYMBOL) + "zeny", strnpcinfo(0);
+ registercmd chr(ATCMD_SYMBOL) + "charzeny", strnpcinfo(0);
+ end;
+}
diff --git a/world/map/npc/doc/magic b/world/map/npc/doc/magic
deleted file mode 100644
index 8a2b84e1..00000000
--- a/world/map/npc/doc/magic
+++ /dev/null
@@ -1,23 +0,0 @@
-Nibble use:
----------------
-== QUEST_MAGIC
- N0, N1: Auldsbel
- N2: druid tree quest, mouboo quest (shared)
- N3: Sagatha unhappiness counter
- N4, N5: Sagatha
- N6, N7: Swords
-== QUEST_MAGIC2
- N0: Evil Earth Spirit
- N1: Elanore
- N2: Wyara
- N3: Elanore subquests (Cure Kadiya)
- N4-N7: may be messy at this point
-
-The various magic scripts pack their status into these variables.
-Locally, they use `@Q_status' to maintain the state, and use a function
-`S_update_var' to update it. This is all re-using the same code, setting
-the `@Q_MASK' and `@Q_SHIFT' variables appropriately.
-
- There are a few exceptions (such as the Kadiya quest) wherein
-a separate helper function sets a dedicated local variable, or some hackery
-in Auldsbel wherein we read stati directly, merely to enable certain options.
diff --git a/world/map/npc/functions/debug.txt b/world/map/npc/functions/debug.txt
index 44af4d40..556e501b 100755
--- a/world/map/npc/functions/debug.txt
+++ b/world/map/npc/functions/debug.txt
@@ -5,7 +5,7 @@ function|script|Debug
if(!@debug_npc) goto L_Begin;
mes "The debug NPCs have been deprecated. Please use this magic spell instead:";
mes "";
- mes "%%E ##a"+ getspellinvocation("debug0") +"##0";
+ mes "%%E ##a#debug##0";
set @debug_npc, 0;
goto L_Close;
@@ -831,13 +831,13 @@ S_Update_Mask:
return;
L_GetAllMagic:
- setskill SKILL_MAGIC, 2;
- setskill SKILL_MAGIC_LIFE, 2;
- setskill SKILL_MAGIC_WAR, 2;
- setskill SKILL_MAGIC_TRANSMUTE, 2;
- setskill SKILL_MAGIC_NATURE, 2;
- setskill SKILL_MAGIC_ASTRAL, 2;
- setskill SKILL_MAGIC_DARK, 2;
+ setskill SKILL_MAGIC, 5;
+ setskill SKILL_MAGIC_LIFE, 5;
+ setskill SKILL_MAGIC_WAR, 5;
+ setskill SKILL_MAGIC_TRANSMUTE, 5;
+ setskill SKILL_MAGIC_NATURE, 5;
+ setskill SKILL_MAGIC_ASTRAL, 5;
+ setskill SKILL_MAGIC_DARK, 5;
set @mexp, 8000;
callsub S_Update_Mask;
mes "Magic skills added.";
@@ -869,13 +869,13 @@ L_AddAll:
setskill SKILL_RESIST_POISON, 9;
setskill SKILL_ASTRAL_SOUL, 9;
setskill SKILL_RAGING, 9;
- setskill SKILL_MAGIC, 2;
- setskill SKILL_MAGIC_LIFE, 2;
- setskill SKILL_MAGIC_WAR, 2;
- setskill SKILL_MAGIC_TRANSMUTE, 2;
- setskill SKILL_MAGIC_NATURE, 2;
- setskill SKILL_MAGIC_ASTRAL, 2;
- setskill SKILL_MAGIC_DARK, 2;
+ setskill SKILL_MAGIC, 5;
+ setskill SKILL_MAGIC_LIFE, 5;
+ setskill SKILL_MAGIC_WAR, 5;
+ setskill SKILL_MAGIC_TRANSMUTE, 5;
+ setskill SKILL_MAGIC_NATURE, 5;
+ setskill SKILL_MAGIC_ASTRAL, 5;
+ setskill SKILL_MAGIC_DARK, 5;
set @mexp, 8000;
resetstatus;
set BaseLevel, 99;
@@ -922,6 +922,16 @@ L_Close:
}
+-|script|Debug Spell|32767
+{
+ if(!debug && getgmlevel() < 99) end;
+ callfunc "Debug";
+ end;
+OnInit:
+ registercmd "@debug", "Debug Spell";
+ end;
+}
+
029-2,30,26,0|script|Debug#0|154
{
set @debug_npc, 1;
diff --git a/world/map/npc/functions/global_event_handler.txt b/world/map/npc/functions/global_event_handler.txt
index d5c20b06..e4247d18 100644
--- a/world/map/npc/functions/global_event_handler.txt
+++ b/world/map/npc/functions/global_event_handler.txt
@@ -28,6 +28,7 @@ OnPCKilledEvent:
OnPCDieEvent:
callfunc "fightclub_GoBack"; // this used by the battle master
callfunc "fightclub_event_die"; // this is used by the 1v1 arena
+ set @necromancer, 0;
end;
OnInit:
diff --git a/world/map/npc/functions/hug.txt b/world/map/npc/functions/hug.txt
new file mode 100644
index 00000000..a663ea1d
--- /dev/null
+++ b/world/map/npc/functions/hug.txt
@@ -0,0 +1,24 @@
+-|script|nonmagic-hug|32767
+{
+ explode .@name$[0], @args$, "*"; // strip the trailing *
+ set @target_id, if_then_else(.@name$[0], getcharid(3, .@name$[0]), BL_ID);
+ if (@target_id < 1 || !(isloggedin(@target_id))) set @target_id, BL_ID; // fallback to self
+ if (.@name$[0] == "Tree" || .@name$[0] == "tree") set @target_id, .tree_id;
+ set .@range, 3;
+ if (distance(BL_ID, @target_id) >= .@range) end;
+ misceffect FX_HUG, strcharinfo(0);
+ if (@target_id != BL_ID) misceffect FX_HUG, @target_id;
+ if (@target_id != .tree_id) end;
+ callfunc "QuestTreeTouch";
+ close;
+
+OnInit:
+ set .tree_id, getnpcid("#DruidTree0#_M");
+ registercmd "hug", strnpcinfo(0);
+ registercmd "*hug", strnpcinfo(0);
+ registercmd "*hug*", strnpcinfo(0);
+ registercmd "hugs", strnpcinfo(0);
+ registercmd "*hugs", strnpcinfo(0);
+ registercmd "*hugs*", strnpcinfo(0);
+ end;
+}
diff --git a/world/map/npc/functions/strangerquiz.txt b/world/map/npc/functions/strangerquiz.txt
index 8da3f65a..3427a0ee 100644
--- a/world/map/npc/functions/strangerquiz.txt
+++ b/world/map/npc/functions/strangerquiz.txt
@@ -3,6 +3,6 @@ function|script|StrangerQuiz
{
// param @quizparam$$
// return in @quizanswer$
- set @quizanswer$, getspellinvocation(@quizparam$);
+ set @quizanswer$, (@quizparam$);
return;
}
diff --git a/world/map/npc/functions/superdebug.txt b/world/map/npc/functions/superdebug.txt
index 5654dd4c..140e703a 100644
--- a/world/map/npc/functions/superdebug.txt
+++ b/world/map/npc/functions/superdebug.txt
@@ -34,32 +34,36 @@ L_Holiday:
L_XmasDebug:
gmlog strcharinfo(0) + " accessed the Xmas debug.";
callfunc "XmasDebug";
- end;
+ goto L_Close;
L_HalloweenDebug:
gmlog strcharinfo(0) + " accessed the Halloween debug.";
callfunc "HalloweenDebug";
- end;
+ goto L_Close;
L_Event:
if(getgmlevel() < 60) goto L_GM;
gmlog strcharinfo(0) + " accessed the GM event debug.";
callfunc "GmDebug";
- close;
+ goto L_Close;
L_StoneBoard:
if (getgmlevel() < 30) goto L_GM;
callfunc "SBConfig";
- close;
+ goto L_Close;
L_MOTD:
if (getgmlevel() < 40) goto L_GM;
callfunc "MOTDConfig";
- close;
+ goto L_Close;
L_GM:
mes "[Numa]";
mes "I'm awfully sorry.";
mes "You do not have the required GM level to perform this action.";
- close;
+ goto L_Close;
+
+L_Close:
+ close2; // FIXME: replace with npc action 5
+ return;
}
diff --git a/world/map/npc/items/check_wand.txt b/world/map/npc/items/check_wand.txt
index 5a339049..93993c53 100644
--- a/world/map/npc/items/check_wand.txt
+++ b/world/map/npc/items/check_wand.txt
@@ -1,67 +1,2 @@
// Wands
// Author: Wushin
-function|script|WandMana
-{
- if(isin("009-7", $@fightclub_x1, $@fightclub_y1, $@fightclub_x2, $@fightclub_y2) && ((@Duel_Fighter != 1) || ($@Duel_NoMagic == 1)))
- goto L_Return;
- callfunc "CheckWand";
- set @WandCost, (@Wand * (BaseLevel / 15) + 2);
- set @WandAttack, 0;
- if (!(@Wand))
- goto L_NoWand;
- if (Sp >= @WandCost)
- goto L_Attack;
- goto L_LowSp;
-
-L_Attack:
- set Sp, (Sp - @WandCost);
- set @WandAttack, 1;
- goto L_Return;
-
-L_NoWand:
- message strcharinfo(0), "You need a wand Equipped!";
- set @WandAttack, 0;
- goto L_Return;
-
-L_LowSp:
- message strcharinfo(0), "Out of Mana";
- set @WandAttack, 0;
- goto L_Return;
-
-L_Return:
- return;
-}
-function|script|CheckWand
-{
- setarray $@Wands, 758, 1171;
- setarray $@WandsPwr, 2, 1;
- setarray $@WandsAnim, 35, 33;
- set @Wand, 0;
- set @wand_loop, 0;
- goto L_Loop;
-
-L_Loop:
- if ((getequipid(equip_hand1) == $@Wands[@wand_loop]) || (getequipid(equip_hand2) == $@Wands[@wand_loop]))
- goto L_SetWand;
- goto L_LoopAgain;
-
-L_SetWand:
- set @Wand, $@WandsPwr[@wand_loop];
- set @WandID, $@WandsAnim[@wand_loop];
- if (QL_MORGAN == 2)
- goto L_SetCastOnce;
- goto L_Return;
-
-L_LoopAgain:
- set @wand_loop, (@wand_loop + 1);
- if (@wand_loop >= getarraysize($@Wands))
- goto L_Return;
- goto L_Loop;
-
-L_SetCastOnce:
- set QL_MORGAN, 3;
- goto L_Return;
-
-L_Return:
- return;
-}
diff --git a/world/map/npc/items/magic_gm_top_hat.txt b/world/map/npc/items/magic_gm_top_hat.txt
index 129aa5c0..dfd114d2 100644
--- a/world/map/npc/items/magic_gm_top_hat.txt
+++ b/world/map/npc/items/magic_gm_top_hat.txt
@@ -1,21 +1,25 @@
-function|script|ActivateMagicGMTophat
+-|script|ActivateMagicGMTophat|32767
{
- if (getgmlevel() < 60) goto L_Return;
+ if (GM < get(.killthegm, "GM") && GM < G_SYSOP) end;
+ if (getequipid(equip_head) != 888) end;
getinventorylist;
if ((checkweight("MurdererCrown", 1) == 0) || (@inventorylist_count == 100))
goto L_Inventory;
// Get the current reward of the event. This may be changed later
getitem "MurdererCrown", 1;
+ // Set HP and SP to max
+ heal MaxHp, MaxSp;
// Display an effect
misceffect FX_CHANNELLING_CAST, strcharinfo(0);
// Log the usage of this spell
gmlog strcharinfo(0)+" used the Magic GM Top Hat.";
- return;
+ end;
L_Inventory:
message strcharinfo(0), "You cannot create this item. You're too heavy or you don't have a free slot.";
- return;
+ end;
-L_Return:
- return;
+OnInit:
+ registercmd "#pullrabbit", strnpcinfo(0);
+ end;
}
diff --git a/world/map/npc/magic/README.md b/world/map/npc/magic/README.md
new file mode 100644
index 00000000..a9dedb6e
--- /dev/null
+++ b/world/map/npc/magic/README.md
@@ -0,0 +1,63 @@
+# To-do
+- [ ] finish the missing spells and push them so they can be tested
+
+---
+---
+to see other things that needs to be done do a grep for `TODO`, `FIXME` in this folder.
+To see a list of things that needs further thoughts do a grep for `XXX`.
+
+---
+---
+
+- [ ] check the new builtins and make sure they work as intended
+ - [ ] `puppet`
+ - [ ] check what happens when making a puppet whose name already exist (maybe it replaces?)
+ - [ ] `destroy`
+ - [ ] `registercmd`
+ - [ ] check what happens when registering a command that was already registered
+ - [ ] `target`
+ - [ ] `get`
+ - [ ] the new `set`
+ - [ ] `min`
+ - [ ] `max`
+ - [ ] `pow`
+ - [ ] `sqrt`
+ - [ ] `cbrt`
+ - [ ] `elttype`
+ - [ ] `eltlvl`
+ - [ ] `injure`
+ - [ ] `elif`
+ - [ ] `else`
+ - [ ] `getnpcid`
+ - [ ] `overrideattack`
+ - [ ] `summon`
+ - [ ] `addnpctimer`
+ - [ ] `explode`
+ - [ ] `foreach`
+ - [ ] modified `areatimer`
+ - [ ] `aggravate`
+ - [ ] `getdir`
+ - [ ] `distance`
+ - [ ] `if_then_else`
+
+---
+- [ ] test the spells
+ - [ ] test with no target
+ - [ ] test with a npc target
+ - [ ] random npc not part of any quest
+ - [ ] injured mouboo
+ - [ ] also test on a **player** with the name `Mouboo` or `mouboo`
+ - [ ] druid tree
+ - [ ] test with a mob target
+ - [ ] mob with clear path (walkable)
+ - [ ] mob with no clear path (unwalkable, blocked by collision)
+ - [ ] mob out of attack range
+ - [ ] test with a player target
+ - [ ] both the caster and the target have pvp disabled
+ - [ ] both the caster and the target have pvp enabled
+ - [ ] the caster has pvp enabled and the target has pvp disabled
+ - [ ] the caster has pvp disabled and the target has pvp enabled
+ - [ ] test with the spouse as target
+
+---
+- [ ] Once everything is done, remove this file
diff --git a/world/map/npc/magic/_import.txt b/world/map/npc/magic/_import.txt
new file mode 100644
index 00000000..4118170e
--- /dev/null
+++ b/world/map/npc/magic/_import.txt
@@ -0,0 +1,38 @@
+npc: npc/magic/_procedures.txt
+npc: npc/magic/level0-wand.txt
+npc: npc/magic/level1-aggravate.txt
+npc: npc/magic/level1-experience.txt
+npc: npc/magic/level1-lesser-heal.txt
+npc: npc/magic/level1-transmute-wood.txt
+npc: npc/magic/level1-make-sulphur.txt
+npc: npc/magic/level1-flare-dart.txt
+npc: npc/magic/level1-magic-blade.txt
+npc: npc/magic/level1-grow-mauve.txt
+npc: npc/magic/level1-grow-alizarin.txt
+npc: npc/magic/level1-grow-gamboge.txt
+npc: npc/magic/level1-grow-cobalt.txt
+npc: npc/magic/level1-summon-maggots.txt
+npc: npc/magic/level1-detect-magic.txt
+npc: npc/magic/level2-arrow-hail.txt
+npc: npc/magic/level2-make-arrows.txt
+npc: npc/magic/level2-make-iron-powder.txt
+npc: npc/magic/level2-magic-knuckles.txt
+npc: npc/magic/level2-summon-snakes.txt
+npc: npc/magic/level2-summon-wickedmushroom.txt
+npc: npc/magic/level2-summon-spiky-mushroom.txt
+npc: npc/magic/level2-summon-fluffies.txt
+npc: npc/magic/level2-summon-mouboo.txt
+npc: npc/magic/level2-summon-pinkie.txt
+npc: npc/magic/level2-toxic-dart.txt
+npc: npc/magic/level2-enchant-lifestone.txt
+npc: npc/magic/level2-flying-backpack.txt
+npc: npc/magic/level2-protect.txt
+npc: npc/magic/level2-barrier.txt
+npc: npc/magic/level2-hide.txt
+npc: npc/magic/level2-happy-curse.txt
+npc: npc/magic/level2-detect-players.txt
+npc: npc/magic/level2-shear.txt
+npc: npc/magic/level2-lightning-strike.txt
+npc: npc/magic/level2-rain.txt
+npc: npc/magic/level2-lay-on-hands.txt
+npc: npc/magic/level3-necromancy.txt
diff --git a/world/map/npc/magic/_procedures.txt b/world/map/npc/magic/_procedures.txt
new file mode 100644
index 00000000..71d12605
--- /dev/null
+++ b/world/map/npc/magic/_procedures.txt
@@ -0,0 +1,135 @@
+function|script|magic_register
+{
+ debugmes ">> Register " + .invocation$ + " @ " + strnpcinfo(0);
+ registercmd .invocation$, strnpcinfo(0); // register the spell
+ set .index, $@magic_index;
+ set $@magic_index, $@magic_index + 1;
+ return;
+}
+
+function|script|magic_register2
+{
+ debugmes ">> Register " + .invocation$ + " @ " + strnpcinfo(0);
+ registercmd .invocation$, strnpcinfo(0) + "::OnCast"; // register the spell <= this spell has a puppet
+ set .index, $@magic_index;
+ set $@magic_index, $@magic_index + 1;
+ return;
+}
+
+function|script|magic_checks
+{
+ set @failed, 0;
+ if(getpvpflag(1)) set @failed, 1; // can not cast with @hide enabled
+ if((gettimetick(2) - MAGIC_CAST_TICK) < 0) set @failed, 1; // check if last debuff ended
+ if(isdead()) set @failed, 1; // can not cast when dead
+ return;
+}
+
+function|script|elt_damage
+{
+ // @edmg is damage, dmgplus(mutation), bonus_elt, malus_elt, effect
+ set @edmg[5], @edmg[0] + rand(@edmg[1]);
+ if(elttype(@target_id) == @edmg[3]) // malus
+ set @edmg[5], @edmg[5] / 3;
+ if(elttype(@target_id) == @edmg[2]) // bonus
+ set @edmg[5], ((eltlvl(@target_id) + 4) * @edmg[5]) / 4;
+ set .@source, .caster;
+ if (!.@source) set .@source, getcharid(3);
+
+ injure .@source, @target_id, @edmg[5];
+ misceffect @edmg[4], @target_id;
+ cleararray @edmg, 0, getarraysize(@edmg);
+ return;
+}
+
+function|script|melee_damage
+{
+ if ((@spellpower - rand(100)) < (get(BaseLevel, @target_id) + get(MDEF1, @target_id)))
+ injure BL_ID, @target_id, 0;
+ else injure BL_ID, @target_id, @melee_dmg[0] + rand(@melee_dmg[1]);
+ return;
+}
+
+function|script|magic_create_item
+{
+ set .@exp, (MAGIC_EXPERIENCE & (BYTE_0_MASK | BYTE_1_MASK)) >> BYTE_0_SHIFT;
+ set .@score, (.@exp + rand(min(@spellpower, ((.@exp / 3) + 1))));
+ set @create_params[2], 1; // success flag
+ if (.@score >= @create_params[1]) goto L_Perfect;
+ set @create_params[2], 0; // success flag
+ set .@score, .@score + rand(Luk) + rand(Luk);
+ if (.@score < (@create_params[1] / 3)) goto L_Backfire;
+ if (.@score < ((@create_params[1] * 2) / 3)) goto L_Iten;
+ message strcharinfo(0), "Magic : ##3##BYour spell takes on a mind of its own!";
+ if (rand(3) == 1) getitem @create_items$[1], 1; // bad item
+ return;
+
+L_Iten:
+ if (rand(5) != 2) goto L_Escape;
+ message strcharinfo(0), "Magic : ##3##BYour spell solidifies into the shape of a mysterious object!";
+ getitem "Iten", 1;
+ return;
+
+L_Escape:
+ message strcharinfo(0), "Magic : ##3##BYour spell escapes!";
+ return;
+
+L_Backfire:
+ message strcharinfo(0), "Magic : ##3##BYour spell backfires!";
+ if (rand(110) < Luk) heal 0 - ((BaseLevel+1)*(BaseLevel+2)*(rand(28)+3)), 0;
+ else heal 0 - (BaseLevel + 1), 0;
+ return;
+
+L_Perfect:
+ getitem @create_items$[0], @create_params[0]; // good item
+ return;
+}
+
+function|script|magic_exp
+{
+ set @last_index, (MAGIC_EXPERIENCE & BYTE_2_MASK) >> BYTE_2_SHIFT;
+ set @last_exp, (MAGIC_EXPERIENCE & (BYTE_0_MASK | BYTE_1_MASK)) >> BYTE_0_SHIFT;
+
+ debugmes "old spell index: " + @last_index;
+ debugmes "new spell index: " + .index;
+
+ if(getskilllv(SKILL_MAGIC) < (.level + 3) && .index != @last_index)
+ goto L_Gain;
+ debugmes "same as last spell => don't proceed";
+ goto L_Return;
+
+L_Gain:
+ if(.exp_gain < 1) goto L_Return; // only the spells that have exp register here. If you
+ // remove this line then players can cast a spell with
+ // no cost, then a spell with a reagents, then another
+ // spell with no costs and still get the exp
+ set @new_exp, @last_exp + .exp_gain;
+ if(@new_exp > (BYTE_0_MASK | BYTE_1_MASK)) set @new_exp, (BYTE_0_MASK | BYTE_1_MASK);
+ debugmes "old magic exp: "+ @last_exp;
+ debugmes "new magic exp: "+ @new_exp;
+ set MAGIC_EXPERIENCE, (MAGIC_EXPERIENCE &~ (BYTE_0_MASK | BYTE_1_MASK)) | (@new_exp << BYTE_0_SHIFT);
+ set MAGIC_EXPERIENCE, (MAGIC_EXPERIENCE &~ BYTE_2_MASK) | (.index << BYTE_2_SHIFT);
+ goto L_Return;
+
+L_Return:
+ return;
+}
+
+function|script|adjust_spellpower
+{
+ set @spellpower, MATK1 + getskilllv(SKILL_MAGIC) + getskilllv(.school) + 10;
+ if((.school != SKILL_MAGIC_NATURE) && (.school != SKILL_MAGIC_LIFE)) goto L_Return;
+ if(@args$ == "" || !@args$ || getpartnerid2() == 0) goto L_Return;
+ if(getcharid(3, @args$) < 1 || getpartnerid2() != getcharid(3, @args$) || !(isloggedin(getcharid(3, @args$))))
+ goto L_Return;
+ debugmes "You targeted your spouse!";
+ // XXX: I need a builtin to check if the target is in range of the caster
+ // XXX: the spell power increases when the target is the spouse so one could
+ // just do #modrilax (spouse) right?
+ //
+ // ... let's just forget about spouse for now
+ goto L_Return;
+
+L_Return:
+ return;
+}
diff --git a/world/map/npc/magic/level0-wand.txt b/world/map/npc/magic/level0-wand.txt
new file mode 100644
index 00000000..e38a26c7
--- /dev/null
+++ b/world/map/npc/magic/level0-wand.txt
@@ -0,0 +1,74 @@
+-|script|spell-wand|32767
+{
+ callfunc "magic_checks"; if(@failed) goto L_Failed; // << I wish we had functions that could return >>
+ callsub S_CheckWand;
+ if(@WandAttack != 1) goto L_Failed;
+
+ // here we install
+ set MAGIC_CAST_TICK, gettimetick(2) + 5; // set the new debuff
+ callfunc "adjust_spellpower";
+ misceffect FX_MAGIC_GENERIC, strcharinfo(0);
+ overrideattack (@Wand + (@spellpower / 10)), 1200, 3, ATTACK_ICON_GENERIC, @WandID, strnpcinfo(0)+"::OnAttack";
+ callfunc "magic_exp";
+ end;
+
+OnAttack:
+ callsub S_CheckWand;
+ if(@WandAttack != 1) goto L_Failed;
+ if(target(BL_ID, @target_id, 22) != 22) goto L_Failed; // 0x02 | 0x04 | 0x10
+ set Sp, (Sp - @WandCost);
+ set @damage, (@Wand * (@spellpower / 3));
+ setarray @edmg,@damage,@damage,ELT_NEUTRAL,ELT_NEUTRAL,FX_MAGIC_RED; callfunc "elt_damage";
+ end;
+
+S_CheckWand:
+ set @Wand, 0;
+ set @wand_loop, 0;
+ goto S_Loop;
+
+S_Loop:
+ if ((getequipid(equip_hand1) == .Wands[@wand_loop]) || (getequipid(equip_hand2) == .Wands[@wand_loop]))
+ goto S_SetWand;
+ set @wand_loop, (@wand_loop + 1);
+ if (@wand_loop >= getarraysize(.Wands))
+ goto S_NoWand;
+ goto S_Loop;
+
+S_SetWand:
+ set @Wand, .WandsPwr[@wand_loop];
+ set @WandID, .WandsAnim[@wand_loop];
+ if (QL_MORGAN == 2)
+ set QL_MORGAN, 3;
+ set @WandCost, (@Wand * (BaseLevel / 15) + 2);
+ set @WandAttack, 0;
+ if (Sp < @WandCost)
+ goto S_LowSp;
+ set @WandAttack, 1; // everything is fine
+ return;
+
+S_NoWand:
+ message strcharinfo(0), "Wand : ##3##BYou need a wand Equipped!";
+ set @WandAttack, 0;
+ return;
+
+S_LowSp:
+ message strcharinfo(0), "Wand : ##3##BOut of Mana";
+ set @WandAttack, 0;
+ return;
+
+L_Failed:
+ //misceffect FX_ELECTRICITY_RED, strcharinfo(0); // XXX: do we show an effect on fail?
+ debugmes "cast or attack failed";
+ end;
+
+OnInit:
+ setarray .Wands[0], 758, 1171;
+ setarray .WandsPwr[0], 2, 1;
+ setarray .WandsAnim[0], 35, 33;
+ set .school, SKILL_MAGIC;
+ set .invocation$, chr(MAGIC_SYMBOL) + "confringo"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 0;
+ set .exp_gain, 1;
+ end;
+}
diff --git a/world/map/npc/magic/level1-aggravate.txt b/world/map/npc/magic/level1-aggravate.txt
new file mode 100644
index 00000000..74316b89
--- /dev/null
+++ b/world/map/npc/magic/level1-aggravate.txt
@@ -0,0 +1,22 @@
+-|script|spell-aggravate|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 3) end;
+ if (getskilllv(.school) < .level) end;
+ set MAGIC_CAST_TICK, gettimetick(2) + 1; // set the new debuff
+ set @args$, ""; callfunc "adjust_spellpower"; // we reset @args$ because this spell should not have a target
+ set @distance, (2 + (@spellpower / 50));
+ set Sp, Sp - 3;
+ misceffect FX_MAGIC_GREEN, strcharinfo(0);
+ callfunc "magic_exp";
+ aggravate getmap(), (POS_X - @distance), (POS_Y - @distance), (POS_X + @distance), (POS_Y + @distance), SFX_DEFAULT;
+ end;
+
+OnInit:
+ set .school, SKILL_MAGIC_NATURE;
+ set .invocation$, chr(MAGIC_SYMBOL) + "itenplz"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 1;
+ set .exp_gain, 0;
+ end;
+}
diff --git a/world/map/npc/magic/level1-detect-magic.txt b/world/map/npc/magic/level1-detect-magic.txt
new file mode 100644
index 00000000..c5dff558
--- /dev/null
+++ b/world/map/npc/magic/level1-detect-magic.txt
@@ -0,0 +1,29 @@
+-|script|detect-magic|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 3) end;
+ if (getskilllv(.school) < .level) end;
+ set MAGIC_CAST_TICK, gettimetick(2) + 6; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 3;
+ misceffect FX_MAGIC_GENERIC, strcharinfo(0);
+ set .@range, (@spellpower/50)+1;
+ foreach 1, getmap(), POS_X - .@range, POS_Y - .@range, POS_X + .@range, POS_Y + .@range,
+ strnpcinfo(0) + "::OnNearbyNpc";
+ callfunc "magic_exp";
+ end;
+
+OnNearbyNpc:
+ set .@e$, strnpcinfo(2,@target_id);
+ if(.@e$ == "#_M" || .@e$ == "#MAGIC")
+ misceffect FX_MAGIC_DEFAULT, @target_id;
+ end;
+
+OnInit:
+ set .school, SKILL_MAGIC;
+ set .invocation$, chr(MAGIC_SYMBOL) + "miteyo"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 1;
+ set .exp_gain, 0;
+ end;
+}
diff --git a/world/map/npc/magic/level1-experience.txt b/world/map/npc/magic/level1-experience.txt
new file mode 100644
index 00000000..9492b6f2
--- /dev/null
+++ b/world/map/npc/magic/level1-experience.txt
@@ -0,0 +1,41 @@
+-|script|spell-experience|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 1) end;
+ set MAGIC_CAST_TICK, gettimetick(2) + 1; // set the new debuff
+ set @level, getskilllv(.school);
+ if (@level < .level) end;
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 1;
+ misceffect FX_MAGIC_GENERIC, strcharinfo(0);
+ callfunc "magic_exp"; // no exp for this spell
+ set @ratio, ((@last_exp*10) - rand(.MAX_MAGIC_EXP[@level]/30))/.MAX_MAGIC_EXP[@level];
+
+ set @mes$, "You feel completely overwhelmed by your magic.";
+ if(@ratio == 1) set @mes$, "You feel quite overwhelmed by your magic, but are beginning to see patterns.";
+ if(@ratio == 2) set @mes$, "You feel that you have only the bare minimum of control over your magic.";
+ if(@ratio == 3) set @mes$, "Trying to control your magic is still rather troublesome.";
+ if(@ratio == 4) set @mes$, "You feel you still have a few difficulties in controlling your magic.";
+ if(@ratio == 5) set @mes$, "You feel somewhat in control of your magic.";
+ if(@ratio == 6) set @mes$, "You feel mostly in control of your magic.";
+ if(@ratio == 7) set @mes$, "You feel quite in control of your magic.";
+ if(@ratio == 8) set @mes$, "You feel that you have very good control of your magic.";
+ if(@ratio == 9) set @mes$, "You feel in almost perfect control of your magic.";
+ if(@ratio >= 10) set @mes$, "You feel in perfect control of your magic" + if_then_else(@level >= MAX_MAGIC_LEVEL, ".", ", and seem on the verge of something more... perhaps you should see the Mana Seed to ask for more magic?");
+ if(@ratio >= 20) set @mes$, "You have perfect control of what you understand now, but there is now a distinct sensation of something more, something indescribable. If only the Mana Seed would give more magic to you...";
+ if(@ratio >= 45) set @mes$, "Magic flows naturally from you, readily and with ease. Your understanding of what you can currently control at present is flawless, far beyond your requirements to cast magic at this level.";
+ if(@ratio >= 45 && @level < MAX_MAGIC_LEVEL) set @mes$, @mes$ + " Surely the Mana Seed will more than readily offer more magic for such a proficient user.";
+ if(@level >= 5) set @mes$, "You are as proficient at magic as you can possibly be."; // this is the maximum magic level
+ message strcharinfo(0), "Magic : ##3##B"+@mes$;
+ // TODO put magic_exp somewhere
+ end;
+
+OnInit:
+ set .school, SKILL_MAGIC;
+ set .invocation$, chr(MAGIC_SYMBOL) + "abizit"; // used in npcs that refer to this spell
+ set .level, 1;
+ set .exp_gain, 0;
+ callfunc "magic_register";
+ setarray .MAX_MAGIC_EXP[0], 0, 100, 1200, 8000, 40000, 65535;
+ end;
+}
diff --git a/world/map/npc/magic/level1-flare-dart.txt b/world/map/npc/magic/level1-flare-dart.txt
new file mode 100644
index 00000000..ee08e7f4
--- /dev/null
+++ b/world/map/npc/magic/level1-flare-dart.txt
@@ -0,0 +1,33 @@
+-|script|flare-dart|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 10) end;
+ set @level, getskilllv(.school);
+ if (@level < .level) end;
+ if (@level <= 2 && countitem("SulphurPowder") >= 1) delitem "SulphurPowder", 1;
+ elif (@level <= 2) end;
+ set MAGIC_CAST_TICK, gettimetick(2) + 1; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 10;
+ misceffect FX_MAGIC_BLACK, strcharinfo(0);
+ set @damage, sqrt(@spellpower) * 5;
+ set @dmg_bonus, (BaseLevel/3) + 5;
+ overrideattack (@spellpower/50)+3, 1200, 4, ATTACK_ICON_GENERIC, 34, strnpcinfo(0)+"::OnAttack";
+ callfunc "magic_exp";
+ end;
+
+OnAttack:
+ misceffect FX_MAGIC_BLACK, strcharinfo(0);
+ if (target(BL_ID, @target_id, 50) != 50) end; // 0x20 | 0x02 | 0x10
+ setarray @edmg[0], @damage, @dmg_bonus, ELT_WATER, ELT_FIRE, FX_MAGIC_BLACK;
+ callfunc "elt_damage";
+ end;
+
+OnInit:
+ set .school, SKILL_MAGIC_WAR;
+ set .invocation$, chr(MAGIC_SYMBOL) + "flar"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 1;
+ set .exp_gain, 1;
+ end;
+}
diff --git a/world/map/npc/magic/level1-grow-alizarin.txt b/world/map/npc/magic/level1-grow-alizarin.txt
new file mode 100644
index 00000000..64593975
--- /dev/null
+++ b/world/map/npc/magic/level1-grow-alizarin.txt
@@ -0,0 +1,37 @@
+-|script|grow-alizarin|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 4) end;
+ if (getskilllv(.school) < .level) end;
+ if (countitem("AlizarinHerb") < 1 || countitem("Root") < 1) end;
+ delitem "AlizarinHerb", 1;
+ delitem "Root", 1;
+ set MAGIC_CAST_TICK, gettimetick(2) + 2; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 4;
+ misceffect FX_MAGIC_GREEN, strcharinfo(0);
+ misceffect FX_PENTAGRAM_BUILDUP, strcharinfo(0);
+ setarray @summon[0], 0, (getskilllv(.school)/2)+1;
+ callfunc "magic_exp";
+ addtimer 4000-(@spellpower-9), strnpcinfo(0)+"::OnSummon";
+ end;
+
+OnSummon:
+ misceffect FX_PENTAGRAM_BURST, strcharinfo(0);
+ callsub S_SummonAll;
+ end;
+
+S_SummonAll:
+ summon getmap(), rand(POS_X-2,POS_X+2), rand(POS_Y-2,POS_Y+2), BL_ID, 1032, 1, (@spellpower*50)+10000;
+ set @summon[0], @summon[0] + 1;
+ if (@summon[0] < @summon[1]) goto S_SummonAll;
+ return;
+
+OnInit:
+ set .school, SKILL_MAGIC_NATURE;
+ set .invocation$, chr(MAGIC_SYMBOL) + "modriphoo"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 1;
+ set .exp_gain, 1;
+ end;
+}
diff --git a/world/map/npc/magic/level1-grow-cobalt.txt b/world/map/npc/magic/level1-grow-cobalt.txt
new file mode 100644
index 00000000..c094fe6f
--- /dev/null
+++ b/world/map/npc/magic/level1-grow-cobalt.txt
@@ -0,0 +1,37 @@
+-|script|grow-cobalt|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 4) end;
+ if (getskilllv(.school) < .level) end;
+ if (countitem("CobaltHerb") < 1 || countitem("Root") < 1) end;
+ delitem "CobaltHerb", 1;
+ delitem "Root", 1;
+ set MAGIC_CAST_TICK, gettimetick(2) + 2; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 4;
+ misceffect FX_MAGIC_GREEN, strcharinfo(0);
+ misceffect FX_PENTAGRAM_BUILDUP, strcharinfo(0);
+ setarray @summon[0], 0, (getskilllv(.school)/2)+1;
+ callfunc "magic_exp";
+ addtimer 4000-(@spellpower-9), strnpcinfo(0)+"::OnSummon";
+ end;
+
+OnSummon:
+ misceffect FX_PENTAGRAM_BURST, strcharinfo(0);
+ callsub S_SummonAll;
+ end;
+
+S_SummonAll:
+ summon getmap(), rand(POS_X-2,POS_X+2), rand(POS_Y-2,POS_Y+2), BL_ID, 1030, 1, (@spellpower*50)+10000;
+ set @summon[0], @summon[0] + 1;
+ if (@summon[0] < @summon[1]) goto S_SummonAll;
+ return;
+
+OnInit:
+ set .school, SKILL_MAGIC_NATURE;
+ set .invocation$, chr(MAGIC_SYMBOL) + "modrisump"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 1;
+ set .exp_gain, 1;
+ end;
+}
diff --git a/world/map/npc/magic/level1-grow-gamboge.txt b/world/map/npc/magic/level1-grow-gamboge.txt
new file mode 100644
index 00000000..15bb9906
--- /dev/null
+++ b/world/map/npc/magic/level1-grow-gamboge.txt
@@ -0,0 +1,37 @@
+-|script|grow-gamboge|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 4) end;
+ if (getskilllv(.school) < .level) end;
+ if (countitem("GambogeHerb") < 1 || countitem("Root") < 1) end;
+ delitem "GambogeHerb", 1;
+ delitem "Root", 1;
+ set MAGIC_CAST_TICK, gettimetick(2) + 2; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 4;
+ misceffect FX_MAGIC_GREEN, strcharinfo(0);
+ misceffect FX_PENTAGRAM_BUILDUP, strcharinfo(0);
+ setarray @summon[0], 0, (getskilllv(.school)/2)+1;
+ callfunc "magic_exp";
+ addtimer 4000-(@spellpower-9), strnpcinfo(0)+"::OnSummon";
+ end;
+
+OnSummon:
+ misceffect FX_PENTAGRAM_BURST, strcharinfo(0);
+ callsub S_SummonAll;
+ end;
+
+S_SummonAll:
+ summon getmap(), rand(POS_X-2,POS_X+2), rand(POS_Y-2,POS_Y+2), BL_ID, 1031, 1, (@spellpower*50)+10000;
+ set @summon[0], @summon[0] + 1;
+ if (@summon[0] < @summon[1]) goto S_SummonAll;
+ return;
+
+OnInit:
+ set .school, SKILL_MAGIC_NATURE;
+ set .invocation$, chr(MAGIC_SYMBOL) + "modriyikam"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 1;
+ set .exp_gain, 1;
+ end;
+}
diff --git a/world/map/npc/magic/level1-grow-mauve.txt b/world/map/npc/magic/level1-grow-mauve.txt
new file mode 100644
index 00000000..6cc15955
--- /dev/null
+++ b/world/map/npc/magic/level1-grow-mauve.txt
@@ -0,0 +1,37 @@
+-|script|grow-mauve|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 4) end;
+ if (getskilllv(.school) < .level) end;
+ if (countitem("MauveHerb") < 1 || countitem("Root") < 1) end;
+ delitem "MauveHerb", 1;
+ delitem "Root", 1;
+ set MAGIC_CAST_TICK, gettimetick(2) + 2; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 4;
+ misceffect FX_MAGIC_GREEN, strcharinfo(0);
+ misceffect FX_PENTAGRAM_BUILDUP, strcharinfo(0);
+ setarray @summon[0], 0, (getskilllv(.school)/2)+1;
+ callfunc "magic_exp";
+ addtimer 4000-(@spellpower-9), strnpcinfo(0)+"::OnSummon";
+ end;
+
+OnSummon:
+ misceffect FX_PENTAGRAM_BURST, strcharinfo(0);
+ callsub S_SummonAll;
+ end;
+
+S_SummonAll:
+ summon getmap(), rand(POS_X-2,POS_X+2), rand(POS_Y-2,POS_Y+2), BL_ID, 1029, 1, (@spellpower*50)+10000;
+ set @summon[0], @summon[0] + 1;
+ if (@summon[0] < @summon[1]) goto S_SummonAll;
+ return;
+
+OnInit:
+ set .school, SKILL_MAGIC_NATURE;
+ set .invocation$, chr(MAGIC_SYMBOL) + "modrilax"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 1;
+ set .exp_gain, 1;
+ end;
+}
diff --git a/world/map/npc/magic/level1-lesser-heal.txt b/world/map/npc/magic/level1-lesser-heal.txt
new file mode 100644
index 00000000..ef087525
--- /dev/null
+++ b/world/map/npc/magic/level1-lesser-heal.txt
@@ -0,0 +1,41 @@
+-|script|lesser-heal|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 6) end;
+ set MAGIC_CAST_TICK, gettimetick(2) + 1; // set the new debuff
+ if (getskilllv(.school) < .level) end;
+ set @target_id, getcharid(3, @args$);
+ if (@target_id < 1 || !(isloggedin(@target_id))) set @target_id, BL_ID; // fallback to self
+ if (@args$ == "Mouboo" || @args$ == "mouboo") set @target_id, getnpcid("Mouboo");
+ set .@range, (((MATK1 + getskilllv(SKILL_MAGIC) + getskilllv(.school) + 10) / 100) + 2);
+ if (distance(BL_ID, @target_id) >= .@range) end;
+ if (PVP_CHANNEL != get(PVP_CHANNEL, @target_id) && get(PVP_CHANNEL, @target_id) != 0) end;
+ if (countitem("Lifestone") < 1) end;
+ delitem "Lifestone", 1;
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 6;
+ misceffect FX_MAGIC_WHITE, strcharinfo(0);
+ if (@target_id != BL_ID) misceffect FX_MAGIC_WHITE, @target_id;
+ // TODO gain_heal_exp
+ // TODO magic_exp
+ if (@args$ == "Mouboo" || @args$ == "mouboo") goto L_Mouboo;
+
+ if (getskilllv(SKILL_MAGIC_DARK) >= 1) sc_start SC_HALT_REGENERATE, 2000, 0;
+
+ set @heal_amount, 200, @target_id;
+ if (attachrid(@target_id) != 1) end; // XXX: to avoid the ugly attachrid method we would need some kind of `run_as` builtin
+ if (!(isdead())) heal @heal_amount, 0, 1;
+ end;
+
+L_Mouboo:
+ mes "Mouboo : ##3##BYour spell seems to have no effect on the mouboo.";
+ close;
+
+OnInit:
+ set .school, SKILL_MAGIC_LIFE;
+ set .invocation$, chr(MAGIC_SYMBOL) + "lum"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 1;
+ set .exp_gain, 1;
+ end;
+}
diff --git a/world/map/npc/magic/level1-magic-blade.txt b/world/map/npc/magic/level1-magic-blade.txt
new file mode 100644
index 00000000..7c286678
--- /dev/null
+++ b/world/map/npc/magic/level1-magic-blade.txt
@@ -0,0 +1,34 @@
+-|script|magic-blade|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 9) end;
+ set .@level, getskilllv(.school);
+ if (.@level < .level) end;
+ set @chiza_component$, "";
+ if (.@level <= 2 && countitem("SharpKnife") >= 1) set @chiza_component$, "SharpKnife";
+ elif (.@level <= 2 && countitem("Knife") >= 1) set @chiza_component$, "Knife";
+ elif (.@level <= 2) end;
+ if (@chiza_component$ != "") delitem @chiza_component$, 1;
+ set MAGIC_CAST_TICK, gettimetick(2) + 1; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 9;
+ misceffect FX_MAGIC_BLACK, strcharinfo(0);
+ overrideattack (@spellpower/15)+10, 1200, 1, ATTACK_ICON_GENERIC, 30, strnpcinfo(0)+"::OnAttack";
+ callfunc "magic_exp";
+ set @chiza_str, Str; // do not allow to equip light armor, cast, and then switch to heavy armor to get bonus str
+ end;
+
+OnAttack:
+ if (target(BL_ID, @target_id, 22) != 22) end; // 0x10 | 0x02 | 0x04
+ setarray @melee_dmg[0], if_then_else(@chiza_component$ == "Knife", 40, 60), (@chiza_str + 5);
+ callfunc "melee_damage";
+ end;
+
+OnInit:
+ set .school, SKILL_MAGIC_WAR;
+ set .invocation$, chr(MAGIC_SYMBOL) + "chiza"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 1;
+ set .exp_gain, 1;
+ end;
+}
diff --git a/world/map/npc/magic/level1-make-sulphur.txt b/world/map/npc/magic/level1-make-sulphur.txt
new file mode 100644
index 00000000..2d11e5f6
--- /dev/null
+++ b/world/map/npc/magic/level1-make-sulphur.txt
@@ -0,0 +1,24 @@
+-|script|make-sulphur|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 4) end;
+ if (getskilllv(.school) < .level) end;
+ if (countitem("PileOfAsh") >= 1) delitem "PileOfAsh", 1; else end;
+ set MAGIC_CAST_TICK, gettimetick(2) + 4; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 4;
+ misceffect FX_MAGIC_RED, strcharinfo(0);
+ setarray @create_params[0], (@spellpower/100)+1+(rand(max(1,(800-@spellpower)))/180), 50;
+ setarray @create_items$[0], "SulphurPowder", "PileOfAsh";
+ callfunc "magic_create_item";
+ callfunc "magic_exp";
+ end;
+
+OnInit:
+ set .school, SKILL_MAGIC_TRANSMUTE;
+ set .invocation$, chr(MAGIC_SYMBOL) + "gole"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 1;
+ set .exp_gain, 1;
+ end;
+}
diff --git a/world/map/npc/magic/level1-summon-maggots.txt b/world/map/npc/magic/level1-summon-maggots.txt
new file mode 100644
index 00000000..12d2465c
--- /dev/null
+++ b/world/map/npc/magic/level1-summon-maggots.txt
@@ -0,0 +1,52 @@
+-|script|summon-maggots|32767
+{
+ end;
+
+OnCast:
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 21) end;
+ if (getskilllv(.school) < .level) end;
+ if (countitem("MaggotSlime") < 1 || countitem("Root") < 1) end;
+ delitem "MaggotSlime", 1;
+ delitem "Root", 1;
+ set MAGIC_CAST_TICK, gettimetick(2) + 20; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 21;
+ misceffect FX_MAGIC_BLUE, strcharinfo(0);
+ misceffect FX_PENTAGRAM_BUILDUP, strcharinfo(0);
+ callfunc "magic_exp";
+ set .@puppet$, "#"+strnpcinfo(0)+"#"+BL_ID;
+ set .@puppet, puppet(getmap(), POS_X, POS_Y, .@puppet$, 127);
+ set .count, ((sqrt(@spellpower)+(@spellpower/15))/5)+1, .@puppet;
+ set .master, BL_ID, .@puppet;
+ set .lifetime, (@spellpower*50)+10000, .@puppet;
+ addnpctimer 5000-(@spellpower*5), .@puppet$+"::OnSummon";
+ addnpctimer 6000, .@puppet$+"::OnDestroy";
+ end;
+
+OnSummon:
+ specialeffect FX_PENTAGRAM_BURST;
+ set .@i, 0;
+ set .@x, getnpcx();
+ set .@y, getnpcy();
+ set .@map$, strnpcinfo(3);
+ callsub S_SummonAll;
+ end;
+
+OnDestroy:
+ destroy;
+
+S_SummonAll:
+ summon .@map$, rand(.@x-2,.@x+2), rand(.@y-2,.@y+2), .master, 1002, 2, .lifetime;
+ set .@i, .@i + 1;
+ if (.@i < .count) goto S_SummonAll;
+ return;
+
+OnInit:
+ set .school, SKILL_MAGIC_ASTRAL;
+ set .invocation$, chr(MAGIC_SYMBOL) + "kalmurk"; // used in npcs that refer to this spell
+ callfunc "magic_register2";
+ set .level, 1;
+ set .exp_gain, 1;
+ end;
+}
diff --git a/world/map/npc/magic/level1-transmute-wood.txt b/world/map/npc/magic/level1-transmute-wood.txt
new file mode 100644
index 00000000..9984d2b0
--- /dev/null
+++ b/world/map/npc/magic/level1-transmute-wood.txt
@@ -0,0 +1,36 @@
+-|script|spell-transmute-wood|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 5) end;
+ if (getskilllv(.school) < .level) end;
+ if (countitem("RawLog") >= 1) delitem "RawLog", 1; else end;
+ set MAGIC_CAST_TICK, gettimetick(2) + 4; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 5;
+ misceffect FX_MAGIC_RED, strcharinfo(0);
+ if (@args$ == "boo") goto L_Mouboo;
+ elif (@args$ == "lurk") goto L_Skytlurk;
+ else message strcharinfo(0), "Magic : ##3##BYou do not know how to transmute wood into this kind of animal."; // FIXME: write a better sentence
+ end;
+
+L_Mouboo:
+ setarray @create_params[0], 1, 40;
+ setarray @create_items$[0], "MoubooFigurine", "WarpedLog";
+ callfunc "magic_create_item";
+ callfunc "magic_exp";
+ end;
+
+L_Skytlurk:
+ if (rand(2) == 1) getitem "Iten", 1;
+ else getitem "WarpedLog", 1;
+ message strcharinfo(0), "Magic : ##3##BYou have no idea what a Skrytlurk looks like.";
+ end;
+
+OnInit:
+ set .school, SKILL_MAGIC_TRANSMUTE;
+ set .invocation$, chr(MAGIC_SYMBOL) + "parum"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 1;
+ set .exp_gain, 1;
+ end;
+}
diff --git a/world/map/npc/magic/level2-arrow-hail.txt b/world/map/npc/magic/level2-arrow-hail.txt
new file mode 100644
index 00000000..ecd79317
--- /dev/null
+++ b/world/map/npc/magic/level2-arrow-hail.txt
@@ -0,0 +1,112 @@
+-|script|arrow-hail|32767
+{
+ // we can not start here because for the puppets this is OnClick
+ end;
+
+OnCast:
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (getskilllv(.school) < .level) end;
+ if (getskilllv(SKILL_MAGIC) < .level) end;
+ if (Sp < 25) end;
+ explode .@map_ext[0], getmap(), "-";
+ if (.@map_ext[1] != 1) end; // XXX this is fugly, in the future let's use MF_OUTSIDE to detect if a map is "outside" or "inside"
+ if (getmapflag(getmap(), MF_TOWN)) end;
+ if (countitem("Arrow") >= 20 && countitem("SulphurPowder") >= 1) delitem "Arrow", 20;
+ elif (countitem("IronArrow") >= 20 && countitem("SulphurPowder") >= 1) delitem "IronArrow", 20;
+ else end;
+ delitem "SulphurPowder", 1;
+ set Sp, Sp - 25;
+ set MAGIC_CAST_TICK, gettimetick(2) + 5; // set the new debuff
+
+ setarray @away[0], POS_X, POS_Y, getdir(), (.range + 1), 0;
+ callsub S_AwayFrom;
+
+ set @nearby, 0;
+ foreach 1, getmap(), @away[0] - 14, @away[1] - 14, @away[0] + 14, @away[1] + 14,
+ strnpcinfo(0) + "::OnNearbyNpc";
+ if (@nearby) goto L_Absorb;
+
+ callfunc "adjust_spellpower";
+ set @new_npc_name$, "#" + strnpcinfo(0) + "#" + getcharid(3); // make a unique puppet name for every player
+ callfunc "magic_exp";
+ misceffect FX_MAGIC_BLACK, strcharinfo(0);
+ set @spell_npc, puppet(getmap(), POS_X, POS_Y, @new_npc_name$, 127); // clone npc => get puppet id
+ set .max_hit, (@spellpower / 8), @spell_npc; // set .max_hit in the puppet
+ set .caster, getcharid(3), @spell_npc; // tell the puppet who controls it
+ set .damage, 125, @spell_npc;
+ set .damage_bonus, (@spellpower / 5), @spell_npc;
+ set .area_x, @away[0], @spell_npc; set .area_y, @away[1], @spell_npc;
+ donpcevent @new_npc_name$+"::OnLaunch"; // start the puppet timer and strike
+ initnpctimer @new_npc_name$; // start the destroy timer
+ end;
+
+S_AwayFrom:
+ if(@away[2] == 6 && !(iscollision(getmap(), (@away[0] + 1), @away[1]))) // right
+ set @away[0], @away[0] + 1;
+ if(@away[2] == 4 && !(iscollision(getmap(), @away[0], (@away[1] - 1)))) // up
+ set @away[1], @away[1] - 1;
+ if(@away[2] == 2 && !(iscollision(getmap(), (@away[0] - 1), @away[1]))) // left
+ set @away[0], @away[0] - 1;
+ if(@away[2] == 0 && !(iscollision(getmap(), @away[0], (@away[1] + 1)))) // down
+ set @away[1], @away[1] + 1;
+ set @away[4], @away[4] + 1;
+ if(@away[4] < @away[3]) goto S_AwayFrom;
+ return;
+
+L_Absorb:
+ message strcharinfo(0), "##3Arrow Hail : ##BA nearby arrow hail absorbs your magic!";
+ end;
+
+OnNearbyNpc:
+ explode .@nearby$[0], strnpcinfo(0,@target_id), "#";
+ if(.@nearby$[0] == "arrow-hail" || .@nearby$[1] == "arrow-hail")
+ set @nearby, @nearby + 1;
+ end;
+
+OnLaunch:
+ if(attachrid(.caster) != 1) destroy; // destroy if caster is missing
+ if(getmap() != strnpcinfo(3)) destroy; // destroy if caster left the map
+ set .hit, .hit + 1;
+ if(.hit > .max_hit) destroy;
+ set .launch, 0;
+ callsub S_Launch;
+ addnpctimer 250 + rand(50) + rand(50), strnpcinfo(0)+"::OnLaunch"; // loop until max
+ end;
+
+S_Launch:
+ npcareawarp .area_x - 6, .area_y - 6, .area_x + 6, .area_y + 6, 0, strnpcinfo(0);
+ misceffect FX_ARROW_HAIL;
+ set .done, 0;
+ foreach 3, strnpcinfo(3), getnpcx(), getnpcy(), getnpcx(), getnpcy(), strnpcinfo(0) + "::OnHit";
+ if(!.done && getx() == getnpcx() && gety() == getnpcy())
+ heal 0 - (.damage + rand(.damage_bonus) + rand(.damage_bonus)), 0; // injure caster
+ set .launch, .launch + 1;
+ if(.launch < 3) goto S_Launch;
+ return;
+
+OnTimer30000:
+ debugmes "frillyar timeout! [this shouldn't happen]";
+ destroy;
+
+OnHit:
+ if(attachrid(.caster) != 1) destroy; // destroy if caster is missing
+ if(getmap() != strnpcinfo(3)) destroy; // destroy if caster left the map
+
+ if(target(.caster, @target_id, 16) != 16 && .caster != @target_id) end;
+ if((get(BL_TYPE, @target_id) & 1) == 0) end; // either mob or pc
+ set .@damage, .damage + rand(.damage_bonus) + rand(.damage_bonus);
+ if(.caster != @target_id)
+ set .@damage, (.@damage * (100 - get(MDEF1, @target_id))) / 100;
+ injure .caster, @target_id, .@damage;
+ set .done, 1;
+ end;
+
+OnInit:
+ set .school, SKILL_MAGIC_WAR;
+ set .range, 7;
+ set .invocation$, chr(MAGIC_SYMBOL) + "frillyar"; // used in npcs that refer to this spell
+ callfunc "magic_register2";
+ set .level, 2;
+ set .exp_gain, 2;
+ end;
+}
diff --git a/world/map/npc/magic/level2-barrier.txt b/world/map/npc/magic/level2-barrier.txt
new file mode 100644
index 00000000..89a50044
--- /dev/null
+++ b/world/map/npc/magic/level2-barrier.txt
@@ -0,0 +1,48 @@
+-|script|magic-barrier|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 15) end;
+ set .@level, getskilllv(.school);
+ if (.@level < .level) end;
+ if (getskilllv(SKILL_MAGIC) < .level) end;
+ if (.@level <= 3 && countitem("SmallMushroom") >= 1) delitem "SmallMushroom", 1;
+ elif (.@level <= 3) end;
+ set @target_id, getcharid(3, @args$);
+ if (@target_id < 1 || !(isloggedin(@target_id))) set @target_id, BL_ID; // fallback to self
+
+ set @asorm_caster, BL_ID, @target_id;
+ if (attachrid(@target_id) != 1) end;
+ set @target_hat, getequipid(equip_head), @asorm_caster;
+ if (attachrid(@asorm_caster) != 1) end;
+ if (@target_hat == 888) end; // FIXME: this whole 5 line block could be done with only one line if we modify getequipid
+
+ set MAGIC_CAST_TICK, gettimetick(2) + 1; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 15;
+ misceffect FX_MAGIC_BLUE, strcharinfo(0);
+ callfunc "magic_exp";
+
+ if (distance(BL_ID, @target_id) >= (@spellpower/30)+2) set @target_id, BL_ID;
+ if (BL_ID == @target_id) set @args$, strcharinfo(0);
+ if (BL_ID != @target_id) misceffect FX_MAGIC_DEFAULT, @args$;
+ set .@time, (@spellpower*200)+2000;
+ set @asorm_time, .@time, @target_id;
+ sc_start SC_MBARRIER, .@time, max(30,(@spellpower/8))+20, @target_id;
+ message @args$, "Barrier : You are surrounded by a magical barrier.";
+ if (attachrid(@target_id) != 1) end;
+ addtimer @asorm_time, strnpcinfo(0)+"::OnEnd";
+ end;
+
+OnEnd:
+ message strcharinfo(0), "Barrier : Your magical barrier dissipates.";
+ misceffect FX_MAGIC_DEFAULT, strcharinfo(0);
+ end;
+
+OnInit:
+ set .school, SKILL_MAGIC_ASTRAL;
+ set .invocation$, chr(MAGIC_SYMBOL) + "asorm"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 2;
+ set .exp_gain, 3;
+ end;
+}
diff --git a/world/map/npc/magic/level2-detect-players.txt b/world/map/npc/magic/level2-detect-players.txt
new file mode 100644
index 00000000..3b024d38
--- /dev/null
+++ b/world/map/npc/magic/level2-detect-players.txt
@@ -0,0 +1,32 @@
+-|script|detect-players|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 7) end;
+ if (getskilllv(.school) < .level) end;
+ set MAGIC_CAST_TICK, gettimetick(2) + 1; // XXX the casttime is 300 so should this be 0 ?
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 7;
+ misceffect FX_MAGIC_DARKRED, strcharinfo(0);
+ callfunc "magic_exp";
+ set @inwilt$, "";
+ set .@d, @spellpower/2;
+ foreach 0, getmap(), POS_X - .@d, POS_Y - .@d, POS_X + .@d, POS_Y + .@d, strnpcinfo(0)+"::OnPC";
+ message strcharinfo(0), if_then_else(@inwilt$=="", "You sense no-one else nearby.", "You sense the following: "+@inwilt$);
+ end;
+
+OnPC:
+ if (@target_id == BL_ID) end; // do not count the caster
+ if (sc_check(SC_HIDE, @target_id)) end; // do not count players with anwiltyp
+ if (getpvpflag(1, @target_id)) end; // do not count invisible players
+ if (@inwilt$ != "") set @inwilt$, @inwilt$ + ", ";
+ set @inwilt$, @inwilt$ + strcharinfo(0, @target_id) + if_then_else(@spellpower > 99, "("+get(BaseLevel, @target_id)+")", "");
+ end;
+
+OnInit:
+ set .school, SKILL_MAGIC;
+ set .invocation$, chr(MAGIC_SYMBOL) + "inwilt"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 2;
+ set .exp_gain, 0;
+ end;
+}
diff --git a/world/map/npc/magic/level2-enchant-lifestone.txt b/world/map/npc/magic/level2-enchant-lifestone.txt
new file mode 100644
index 00000000..9d56f84a
--- /dev/null
+++ b/world/map/npc/magic/level2-enchant-lifestone.txt
@@ -0,0 +1,35 @@
+-|script|enchant-lifestone|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 15) end;
+ if (getskilllv(.school) < .level) end;
+ if (countitem("BugLeg") >= 1) delitem "BugLeg", 1;
+ elif (countitem("MaggotSlime") >= 1) delitem "MaggotSlime", 1;
+ elif (countitem("MauveHerb") >= 1 && countitem("AlizarinHerb") >= 1 && countitem("CobaltHerb") >= 1 && countitem("GambogeHerb") >= 1) goto L_Herbs;
+ else end;
+ goto L_Proceed;
+
+L_Herbs:
+ delitem "MauveHerb", 1;
+ delitem "AlizarinHerb", 1;
+ delitem "CobaltHerb", 1;
+ delitem "GambogeHerb", 1;
+ goto L_Proceed;
+
+L_Proceed:
+ set MAGIC_CAST_TICK, gettimetick(2) + 4; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 15;
+ misceffect FX_MAGIC_GENERIC, strcharinfo(0);
+ getitem "Lifestone", 1;
+ callfunc "magic_exp";
+ end;
+
+OnInit:
+ set .school, SKILL_MAGIC;
+ set .invocation$, chr(MAGIC_SYMBOL) + "manpahil"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 2;
+ set .exp_gain, 1;
+ end;
+}
diff --git a/world/map/npc/magic/level2-flying-backpack.txt b/world/map/npc/magic/level2-flying-backpack.txt
new file mode 100644
index 00000000..f2ab0b07
--- /dev/null
+++ b/world/map/npc/magic/level2-flying-backpack.txt
@@ -0,0 +1,39 @@
+-|script|flying-backpack|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 12) end;
+ set .@level, getskilllv(.school);
+ if (.@level < .level) end;
+ if (getskilllv(SKILL_MAGIC) < .level) end;
+ if (.@level <= 3 && countitem("SilkCocoon") >= 1) delitem "SilkCocoon", 1;
+ elif (.@level <= 3) end;
+ set MAGIC_CAST_TICK, gettimetick(2) + 1; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 12;
+ misceffect FX_MAGIC_GREEN, strcharinfo(0);
+ callfunc "magic_exp";
+ set @target_id, getcharid(3, @args$);
+ if (@target_id < 1 || !(isloggedin(@target_id))) set @target_id, BL_ID; // fallback to self
+ if (distance(BL_ID, @target_id) >= (@spellpower/30)+2) set @target_id, BL_ID;
+ if (BL_ID != @target_id) misceffect FX_MAGIC_GENERIC, @args$;
+ if (BL_ID == @target_id) set @args$, strcharinfo(0);
+ set @plugh_time, (@spellpower*500)+5000, @target_id;
+ sc_start SC_FLYING_BACKPACK, @plugh_time, 0, @target_id;
+ message @args$, "Backpack : Your backpack is lifted by a mystical force; you no longer feel it pressing on your back.";
+ if (attachrid(@target_id) != 1) end;
+ addtimer @plugh_time, strnpcinfo(0)+"::OnEnd";
+ end;
+
+OnEnd:
+ message strcharinfo(0), "Backpack : Your backpack is no longer levitating.";
+ misceffect FX_MAGIC_GENERIC, strcharinfo(0);
+ end;
+
+OnInit:
+ set .school, SKILL_MAGIC_NATURE;
+ set .invocation$, chr(MAGIC_SYMBOL) + "plugh"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 2;
+ set .exp_gain, 1;
+ end;
+}
diff --git a/world/map/npc/magic/level2-happy-curse.txt b/world/map/npc/magic/level2-happy-curse.txt
new file mode 100644
index 00000000..0ad2d113
--- /dev/null
+++ b/world/map/npc/magic/level2-happy-curse.txt
@@ -0,0 +1,42 @@
+-|script|happy-curse|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 13) end;
+ set .@level, getskilllv(.school);
+ if (.@level < .level) end;
+ if (getskilllv(SKILL_MAGIC) < .level) end;
+ if (.@level <= 3 && countitem("GingerBreadMan") >= 1) delitem "GingerBreadMan", 1;
+ elif (.@level <= 3) end;
+ set @target_id, getcharid(3, @args$);
+ if (@target_id < 1 || !(isloggedin(@target_id))) set @target_id, BL_ID; // fallback to self
+
+ set MAGIC_CAST_TICK, gettimetick(2) + 1; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 13;
+ misceffect FX_MAGIC_GREEN, strcharinfo(0);
+ callfunc "magic_exp";
+
+ if (distance(BL_ID, @target_id) >= (@spellpower/100)+1) set @target_id, BL_ID;
+ if (BL_ID == @target_id) set @args$, strcharinfo(0);
+ set @joyplim_count, 1, @target_id;
+ set @joyplim_emote, if_then_else(getskilllv(SKILL_MAGIC_DARK) > 1, EMOTE_EVIL, EMOTE_HAPPY), @target_id;
+ set @joyplim_total, (@spellpower/10), @target_id;
+ if (attachrid(@target_id) != 1) end;
+ emotion @joyplim_emote, "self";
+ addtimer 500, strnpcinfo(0)+"::OnEmote";
+ end;
+
+OnEmote:
+ emotion @joyplim_emote, "self";
+ set @joyplim_count, @joyplim_count + 1;
+ if (@joyplim_count < @joyplim_total) addtimer 500, strnpcinfo(0)+"::OnEmote";
+ end;
+
+OnInit:
+ set .school, SKILL_MAGIC_NATURE;
+ set .invocation$, chr(MAGIC_SYMBOL) + "joyplim"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 2;
+ set .exp_gain, 1;
+ end;
+}
diff --git a/world/map/npc/magic/level2-hide.txt b/world/map/npc/magic/level2-hide.txt
new file mode 100644
index 00000000..42de7f6a
--- /dev/null
+++ b/world/map/npc/magic/level2-hide.txt
@@ -0,0 +1,43 @@
+-|script|spell-hide|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 11) end;
+ set .@level, getskilllv(.school);
+ if (.@level < .level) end;
+ if (getskilllv(SKILL_MAGIC) < .level) end;
+ if (.@level <= 3 && countitem("CottonCloth") >= 1) delitem "CottonCloth", 1;
+ elif (.@level <= 3) end;
+ set @target_id, getcharid(3, @args$);
+ if (@target_id < 1 || !(isloggedin(@target_id))) set @target_id, BL_ID; // fallback to self
+
+ set MAGIC_CAST_TICK, gettimetick(2) + 1; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 11;
+ misceffect FX_MAGIC_BLUE, strcharinfo(0);
+ callfunc "magic_exp";
+
+ if (distance(BL_ID, @target_id) >= (@spellpower/30)+2) set @target_id, BL_ID;
+ if (BL_ID == @target_id) set @args$, strcharinfo(0);
+ if (BL_ID != @target_id) misceffect FX_MAGIC_DEFAULT, @args$;
+ set .@time, (@spellpower*2500)+5000;
+ set @anwiltyp_time, .@time, @target_id;
+ sc_start SC_HIDE, .@time, 0, @target_id;
+ message @args$, "Magic : You are hidden!";
+ if (BL_ID != @target_id) message strcharinfo(0), "Magic : You hid someone!";
+ if (attachrid(@target_id) != 1) end;
+ addtimer @anwiltyp_time, strnpcinfo(0)+"::OnEnd";
+ end;
+
+OnEnd:
+ message strcharinfo(0), "Magic : You are no longer hidden.";
+ misceffect FX_MAGIC_GENERIC, strcharinfo(0);
+ end;
+
+OnInit:
+ set .school, SKILL_MAGIC_ASTRAL;
+ set .invocation$, chr(MAGIC_SYMBOL) + "anwiltyp"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 2;
+ set .exp_gain, 2;
+ end;
+}
diff --git a/world/map/npc/magic/level2-lay-on-hands.txt b/world/map/npc/magic/level2-lay-on-hands.txt
new file mode 100644
index 00000000..d106ac54
--- /dev/null
+++ b/world/map/npc/magic/level2-lay-on-hands.txt
@@ -0,0 +1,57 @@
+-|script|lay-on-hands|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 10) end;
+ if (getskilllv(.school) < .level) end;
+ if (getskilllv(SKILL_MAGIC) < .level) end;
+ if (@args$ == "Mouboo" || @args$ == "mouboo") goto L_Mouboo;
+ set @target_id, getcharid(3, @args$);
+ if (@target_id < 1 || !(isloggedin(@target_id))) end;
+ if (Hp <= get(MaxHp, @target_id) / 20) end; // hp needs to be > 1/20 * target hp
+ callfunc "adjust_spellpower";
+ if (distance(BL_ID, @target_id) >= (((sqrt(@spellpower)*12)+@spellpower)/100)+2) end;
+ if (sc_check(SC_HALT_REGENERATE,@target_id)) end;
+ if (getequipid(equip_head, @args$) == 888) end; // magic gm top hat
+ set .@needed, get(MaxHp, @target_id) - get(Hp, @target_id);
+ goto L_Pay;
+
+L_Pay:
+ set MAGIC_CAST_TICK, gettimetick(2) + 1; // XXX should this be 0 ?
+ set Sp, Sp - 10;
+ misceffect FX_MAGIC_WHITE, strcharinfo(0); // on caster
+ misceffect FX_MAGIC_WHITE, @args$; // on target
+
+ set .@fraction, max(80, 200 - (Vit + (@spellpower/10))); // pay at least 40%
+ set .@payment, (.@needed * .@fraction) / 200;
+ set .@available, Hp - (MaxHp / 20);
+ set .@power, if_then_else(.@payment < .@available, .@needed+1-1, (.@available * 200) / .@fraction); // FIXME / XXX why the f do I need to do +1-1 ?
+ if (.@payment > .@available) set .@payment, .@available;
+
+ set @inma_power, .@power, @target_id;
+
+ set @mexp, min(.exp_gain, .@payment/100); // TODO pass this to gain_heal_exp so it can be passed to gain_exp
+ // TODO gain_heal_exp(.@power, 1, 1, 3) => gain_exp
+
+ set .@dark, getskilllv(SKILL_MAGIC_DARK) >= 2; // true if dark magic user
+ set .@bad, (MaxHp/20)*(0-1);
+ if (.@dark) heal .@bad, 0;
+ sc_start SC_HALT_REGENERATE, if_then_else(.@dark, 5000, 10000), 0;
+
+ if (attachrid(@target_id) != 1) end;
+ if (!(isdead())) heal @inma_power, 0;
+ end;
+
+L_Mouboo:
+ set @spell, 1;
+ callfunc "QuestMoubooHeal";
+ set .@needed, 1000;
+ goto L_Pay;
+
+OnInit:
+ set .school, SKILL_MAGIC_LIFE;
+ set .invocation$, chr(MAGIC_SYMBOL) + "inma"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 2;
+ set .exp_gain, 4; // this is MAX possible exp
+ end;
+}
diff --git a/world/map/npc/magic/level2-lightning-strike.txt b/world/map/npc/magic/level2-lightning-strike.txt
new file mode 100644
index 00000000..d27d88df
--- /dev/null
+++ b/world/map/npc/magic/level2-lightning-strike.txt
@@ -0,0 +1,67 @@
+-|script|lightning-strike|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 20) end;
+ if (getskilllv(SKILL_MAGIC) < .level) end;
+ set .@level, getskilllv(.school);
+ if (.@level < .level) end;
+ if (.@level <= 3 && countitem("IronPowder") >= 1) delitem "IronPowder", 1;
+ elif (.@level <= 3) end;
+ set MAGIC_CAST_TICK, gettimetick(2) + 1; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 20;
+ misceffect FX_MAGIC_BLACK, strcharinfo(0);
+ set @ingrav_sp, @spellpower;
+ set @ingrav_luk, Luk;
+ overrideattack (@spellpower/90)+1, 3000, 8, ATTACK_ICON_GENERIC, 31, strnpcinfo(0)+"::OnAttack";
+ callfunc "magic_exp";
+ end;
+
+OnAttack:
+ if (target(BL_ID, @target_id, 22) != 22) end; // 0x10 | 0x02 | 0x04
+
+ set @ingrav_rain, 0;
+ set .@p, get(.max_radius, "rain") + 1;
+ set @ingrav_target, @target_id; // store it because foreach overwrites it
+ foreach 1, getmap(), POS_X-.@p, POS_Y-.@p, POS_X+.@p, POS_Y+.@p, strnpcinfo(0)+"::OnNpc";
+ set @target_id, @ingrav_target; // now restore it
+
+ if (@ingrav_rain & 1) goto L_InRain;
+ setarray @edmg[0], @ingrav_sp, (@ingrav_sp/2)+1, ELT_EARTH, ELT_WIND, FX_LIGHTNING1 + rand(3);
+ callfunc "elt_damage";
+ end;
+
+OnNpc:
+ set .@name$, strnpcinfo(0,@target_id);
+ explode .@nearby$[0], .@name$, "#";
+ if (.@nearby$[0] != "rain" && .@nearby$[1] != "rain") end;
+ setarray .@l[0], getnpcx(.@name$), getnpcy(.@name$), get(.radius, @target_id); // kaflosh x, y, radius
+ setarray @ar[0], .@l[0]-.@l[2], .@l[1]-.@l[2], .@l[0]+.@l[2], .@l[1]+.@l[2]; // kaflosh x1, y1, x2, y2 <= this is "area"
+ if (POS_X >= @ar[0] && POS_Y >= @ar[1] && POS_X <= @ar[2] && POS_Y <= @ar[3])
+ set @ingrav_rain, @ingrav_rain | 1;
+ end;
+
+L_InRain:
+ set @used, 0;
+ foreach 3, getmap(), @ar[0], @ar[1], @ar[2], @ar[3], strnpcinfo(0)+"::OnEntityInRain";
+ if (@used >= 1 && (@ingrav_luk + rand(200)) >= 150) end;
+ misceffect FX_LIGHTNING1 + rand(3), strcharinfo(0);
+ heal 0 - @ingrav_sp, 0;
+ end;
+
+OnEntityInRain:
+ if (target(BL_ID, @target_id, 16) != 16) end; // 0x10
+ if (@ingrav_luk + rand(200) <= 175) end;
+ set @used, @used + 1;
+ setarray @edmg[0], @ingrav_sp/6, (((@ingrav_sp/2)+1)/3)+1, ELT_EARTH, ELT_WIND, FX_LIGHTNING1 + rand(3);
+ callfunc "elt_damage";
+ end;
+
+OnInit:
+ set .school, SKILL_MAGIC_WAR;
+ set .invocation$, chr(MAGIC_SYMBOL) + "ingrav"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 2;
+ set .exp_gain, 2;
+ end;
+}
diff --git a/world/map/npc/magic/level2-magic-knuckles.txt b/world/map/npc/magic/level2-magic-knuckles.txt
new file mode 100644
index 00000000..76ff3215
--- /dev/null
+++ b/world/map/npc/magic/level2-magic-knuckles.txt
@@ -0,0 +1,32 @@
+-|script|magic-knuckles|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 20) end;
+ if (getskilllv(SKILL_MAGIC) < .level) end;
+ set .@level, getskilllv(.school);
+ if (.@level < .level) end;
+ if (.@level <= 3 && countitem("Beer") >= 1) delitem "Beer", 1;
+ elif (.@level <= 3) end;
+ set MAGIC_CAST_TICK, gettimetick(2) + 1; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 20;
+ misceffect FX_MAGIC_BLACK, strcharinfo(0);
+ overrideattack (@spellpower/10)+10, 1300, 1, ATTACK_ICON_GENERIC, 34, strnpcinfo(0)+"::OnAttack";
+ callfunc "magic_exp";
+ set @upmaru_str, Str; // do not allow to equip light armor, cast, and then switch to heavy armor to get bonus str
+ end;
+
+OnAttack:
+ if (target(BL_ID, @target_id, 22) != 22) end; // 0x10 | 0x02 | 0x04
+ setarray @melee_dmg[0], 30, ((@upmaru_str*2) + 5);
+ callfunc "melee_damage";
+ end;
+
+OnInit:
+ set .school, SKILL_MAGIC_WAR;
+ set .invocation$, chr(MAGIC_SYMBOL) + "upmaru"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 2;
+ set .exp_gain, 1;
+ end;
+}
diff --git a/world/map/npc/magic/level2-make-arrows.txt b/world/map/npc/magic/level2-make-arrows.txt
new file mode 100644
index 00000000..897598f9
--- /dev/null
+++ b/world/map/npc/magic/level2-make-arrows.txt
@@ -0,0 +1,26 @@
+-|script|make-arrows|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 8) end;
+ if (getskilllv(SKILL_MAGIC) < .level) end;
+ if (getskilllv(.school) < .level) end;
+ if (countitem("RawLog") < 1) end;
+ delitem "RawLog", 1;
+ set MAGIC_CAST_TICK, gettimetick(2) + 5; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 8;
+ misceffect FX_MAGIC_RED, strcharinfo(0);
+ setarray @create_params[0], (@spellpower/40)+1+(rand(max(1,(800-@spellpower)))/80), 500;
+ setarray @create_items$[0], "Arrow", "WarpedLog";
+ callfunc "magic_create_item";
+ callfunc "magic_exp";
+ end;
+
+OnInit:
+ set .school, SKILL_MAGIC_TRANSMUTE;
+ set .invocation$, chr(MAGIC_SYMBOL) + "kularzufrill"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 2;
+ set .exp_gain, 1;
+ end;
+}
diff --git a/world/map/npc/magic/level2-make-iron-powder.txt b/world/map/npc/magic/level2-make-iron-powder.txt
new file mode 100644
index 00000000..089150ac
--- /dev/null
+++ b/world/map/npc/magic/level2-make-iron-powder.txt
@@ -0,0 +1,26 @@
+-|script|make-iron-powder|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 8) end;
+ if (getskilllv(SKILL_MAGIC) < .level) end;
+ if (getskilllv(.school) < .level) end;
+ if (countitem("IronOre") < 1) end;
+ delitem "IronOre", 1;
+ set MAGIC_CAST_TICK, gettimetick(2) + 5; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 8;
+ misceffect FX_MAGIC_RED, strcharinfo(0);
+ setarray @create_params[0], (@spellpower/140)+1+(rand(max(1,(900-@spellpower)))/220), 700;
+ setarray @create_items$[0], "IronPowder", "IronOre";
+ callfunc "magic_create_item";
+ callfunc "magic_exp";
+ end;
+
+OnInit:
+ set .school, SKILL_MAGIC_TRANSMUTE;
+ set .invocation$, chr(MAGIC_SYMBOL) + "zukminbirf"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 2;
+ set .exp_gain, 3;
+ end;
+}
diff --git a/world/map/npc/magic/level2-protect.txt b/world/map/npc/magic/level2-protect.txt
new file mode 100644
index 00000000..e4ca8d76
--- /dev/null
+++ b/world/map/npc/magic/level2-protect.txt
@@ -0,0 +1,48 @@
+-|script|protect|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 14) end;
+ set .@level, getskilllv(.school);
+ if (.@level < .level) end;
+ if (getskilllv(SKILL_MAGIC) < .level) end;
+ if (.@level <= 3 && countitem("HardSpike") >= 1) delitem "HardSpike", 1;
+ elif (.@level <= 3) end;
+ set @target_id, getcharid(3, @args$);
+ if (@target_id < 1 || !(isloggedin(@target_id))) set @target_id, BL_ID; // fallback to self
+
+ set @betsanc_caster, BL_ID, @target_id;
+ if (attachrid(@target_id) != 1) end;
+ set @target_hat, getequipid(equip_head), @betsanc_caster;
+ if (attachrid(@betsanc_caster) != 1) end;
+ if (@target_hat == 888) end; // FIXME: this whole 5 line block could be done with only one line if we modify getequipid
+
+ set MAGIC_CAST_TICK, gettimetick(2) + 2; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 14;
+ misceffect FX_MAGIC_GREEN, strcharinfo(0);
+ callfunc "magic_exp";
+
+ if (distance(BL_ID, @target_id) >= (@spellpower/30)+2) set @target_id, BL_ID;
+ if (BL_ID == @target_id) set @args$, strcharinfo(0);
+ misceffect FX_MAGIC_SHIELD, @args$;
+ set .@time, (@spellpower*1000)+5000;
+ set @betsanc_time, .@time, @target_id;
+ sc_start SC_PHYS_SHIELD, .@time, max(15,(@spellpower/20))+5, @target_id;
+ message @args$, "Shield : You feel more protected.";
+ if (attachrid(@target_id) != 1) end;
+ addtimer @betsanc_time, strnpcinfo(0)+"::OnEnd";
+ end;
+
+OnEnd:
+ message strcharinfo(0), "Shield : You feel less protected.";
+ misceffect FX_MAGIC_SHIELD_ENDS, strcharinfo(0);
+ end;
+
+OnInit:
+ set .school, SKILL_MAGIC_NATURE;
+ set .invocation$, chr(MAGIC_SYMBOL) + "betsanc"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 2;
+ set .exp_gain, 2;
+ end;
+}
diff --git a/world/map/npc/magic/level2-rain.txt b/world/map/npc/magic/level2-rain.txt
new file mode 100644
index 00000000..f12c9072
--- /dev/null
+++ b/world/map/npc/magic/level2-rain.txt
@@ -0,0 +1,103 @@
+-|script|rain|32767
+{
+ // we can not start here because for the puppets this is OnClick
+ end;
+
+OnCast:
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (getskilllv(.school) < .level) end;
+ if (getskilllv(SKILL_MAGIC) < .level) end;
+ if (Sp < 17) end;
+ explode .@map_ext[0], getmap(), "-";
+ if (.@map_ext[1] != 1) end; // XXX this is fugly, in the future let's use MF_OUTSIDE to detect if a map is "outside" or "inside"
+ if (getmapflag(getmap(), MF_TOWN)) end;
+ if (getskilllv(.school) < 4 && countitem("BottleOfWater") >= 1) delitem "BottleOfWater", 1;
+ elif (getskilllv(.school) < 4) end;
+ set Sp, Sp - 17;
+ set MAGIC_CAST_TICK, gettimetick(2) + 3; // set the new debuff
+
+ callfunc "adjust_spellpower";
+ set @krad, min(.max_radius,(min(@spellpower,200)/30)+3); // kaflosh radius
+
+ set @nearby, 0;
+ foreach 1, getmap(), POS_X - .max_radius, POS_Y - .max_radius, POS_X + .max_radius, POS_Y + .max_radius,
+ strnpcinfo(0) + "::OnNearbyNpc";
+ if (@nearby) goto L_Absorb;
+
+ set @new_npc_name$, "#" + strnpcinfo(0) + "#" + getcharid(3); // make a unique puppet name for every player
+ callfunc "magic_exp";
+ misceffect FX_MAGIC_GREEN, strcharinfo(0);
+ set @spell_npc, puppet(getmap(), POS_X, POS_Y, @new_npc_name$, 127); // clone npc => get puppet id
+ set .caster, getcharid(3), @spell_npc; // tell the puppet who controls it
+ set .radius, @krad, @spell_npc; // this is also used by ingrav, don't rename
+ set .initial_x, POS_X, @spell_npc;
+ set .initial_y, POS_Y, @spell_npc;
+ set .max, @spellpower/3, @spell_npc;
+ set .max_launch, min(200,@spellpower/2)/100, @spell_npc;
+ donpcevent @new_npc_name$+"::OnLaunch"; // start
+ addnpctimer 30000, @new_npc_name$+"::OnDestroy"; // this is just a failsafe in case the npc is not properly destroyed
+ if(isin("011-1", 85, 31, 103, 45)) goto L_Pumpkins;
+ end;
+
+L_Absorb:
+ message strcharinfo(0), "##3Rain : ##BA nearby raincloud absorbs your magic.";
+ end;
+
+OnNearbyNpc:
+ explode .@nearby$[0], strnpcinfo(0,@target_id), "#";
+ if(.@nearby$[1] == "DruidTree0" || .@nearby$[1] == "DruidTree0") goto L_Tree;
+ if(.@nearby$[0] == "rain" || .@nearby$[1] == "rain")
+ set @nearby, @nearby + 1;
+ end;
+
+L_Pumpkins:
+ callfunc "HalloweenQuestWaterPumpkins";
+ end;
+
+L_Tree:
+ set .@x, get(POS_X, @target_id); set .@y, get(POS_Y, @target_id);
+ if (.@x < POS_X-@krad || .@y < POS_Y-@krad || .@x > POS_X+@krad || .@y > POS_Y+@krad) end; // in max radius but not in puppet area
+ set @flag, 1;
+ callfunc "QuestTreeTrigger";
+ close;
+
+OnLaunch:
+ if(attachrid(.caster) != 1) destroy; // destroy if caster is missing
+ if(getmap() != strnpcinfo(3)) destroy; // destroy if caster left the map
+ set .count, .count + 1;
+ if(.count > .max) destroy;
+ set .launch, 0;
+ callsub S_Launch;
+ addnpctimer 400 + rand(100), strnpcinfo(0)+"::OnLaunch"; // loop until max
+ end;
+
+S_Launch:
+ npcareawarp .initial_x - .radius, .initial_y - .radius, .initial_x + .radius, .initial_y + .radius, 0, strnpcinfo(0);
+ misceffect FX_RAIN;
+ foreach 3, strnpcinfo(3), getnpcx()-1, getnpcy()-1, getnpcx()+1, getnpcy()+1, strnpcinfo(0) + "::OnHit";
+ set .launch, .launch + 1;
+ if(.launch < .max_launch) goto S_Launch;
+ return;
+
+OnHit:
+ if(attachrid(.caster) != 1) destroy; // destroy if caster is missing
+ if(getmap() != strnpcinfo(3)) destroy; // destroy if caster left the map
+ if(target(.caster, @target_id, 16) != 16 && .caster != @target_id) end;
+ if((get(BL_TYPE, @target_id) & 1) == 0) end; // either mob or pc
+ if(elttype(@target_id) == ELT_FIRE)
+ injure .caster, @target_id, rand((@spellpower/15)+5)+2;
+ end;
+
+OnDestroy:
+ debugmes "kaflosh timeout! [this shouldn't happen]";
+ destroy;
+
+OnInit:
+ set .school, SKILL_MAGIC_NATURE;
+ set .invocation$, chr(MAGIC_SYMBOL) + "kaflosh"; // used in npcs that refer to this spell
+ callfunc "magic_register2";
+ set .level, 2;
+ set .exp_gain, 1;
+ set .max_radius, 15;
+ end;
+}
diff --git a/world/map/npc/magic/level2-shear.txt b/world/map/npc/magic/level2-shear.txt
new file mode 100644
index 00000000..5af782e1
--- /dev/null
+++ b/world/map/npc/magic/level2-shear.txt
@@ -0,0 +1,49 @@
+-|script|shear|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 23) end;
+ if (getskilllv(SKILL_MAGIC) < .level) end;
+ if (getskilllv(.school) < .level) end;
+ set MAGIC_CAST_TICK, gettimetick(2) + 1; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 23;
+ misceffect FX_MAGIC_GREEN, strcharinfo(0);
+ overrideattack 1, 2000, 1, ATTACK_ICON_SHEARING, 30, strnpcinfo(0)+"::OnAttack";
+ callfunc "magic_exp";
+ set @chipchip_sp, @spellpower;
+ end;
+
+OnAttack:
+ if (isloggedin(@target_id)) end; // can not shear a player
+ if (sc_check(SC_SHEARED, @target_id)) end; // mob already sheared
+ if (target(BL_ID, @target_id, 22) != 22) end; // 0x10 | 0x02 | 0x04
+ sc_start SC_SHEARED, 600000, 0, @target_id;
+ set .@score, rand(1000 - rand(@chipchip_sp));
+ set .@id, get(Class, @target_id); // get the mob ID
+
+ if (.@id == 1020 && .@score < 300) set .@item$, "WhiteFur"; // Fluffy
+ elif (.@id == 1027 && .@score < 300) set .@item$, "WhiteFur"; // EasterFluffy
+ elif (.@id == 1019 && .@score < 250) set .@item$, "HardSpike"; // SpikyMushroom
+ elif (.@id == 1028 && .@score < 175) set .@item$, "CottonCloth"; // Mouboo
+ elif (.@id == 1029 && .@score < 700) set .@item$, "MauveHerb"; // MauvePlant
+ elif (.@id == 1030 && .@score < 700) set .@item$, "CobaltHerb"; // CobaltPlant
+ elif (.@id == 1031 && .@score < 700) set .@item$, "GambogeHerb"; // GambogePlant
+ elif (.@id == 1032 && .@score < 700) set .@item$, "AlizarinHerb"; // AlizarinPlant
+ elif (.@id == 1035 && .@score < 300) set .@item$, "SilkCocoon"; // SilkWorm
+ elif (.@id == 1018 && .@score < 180) set .@item$, "PinkAntenna"; // Pinkie
+ else end;
+ makeitem .@item$, 1, getmap(), rand(POS_X - 1, POS_X + 1), rand(POS_Y - 1, POS_Y + 1);
+
+ if (.@id != 1020 && .@id != 1028 && .@id != 1018 && rand(2) != 1) end;
+ set @value, 1;
+ callfunc "QuestSagathaHappy";
+ end;
+
+OnInit:
+ set .school, SKILL_MAGIC_NATURE;
+ set .invocation$, chr(MAGIC_SYMBOL) + "chipchip"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 2;
+ set .exp_gain, 0;
+ end;
+}
diff --git a/world/map/npc/magic/level2-summon-fluffies.txt b/world/map/npc/magic/level2-summon-fluffies.txt
new file mode 100644
index 00000000..9590b468
--- /dev/null
+++ b/world/map/npc/magic/level2-summon-fluffies.txt
@@ -0,0 +1,53 @@
+-|script|fluffies|32767
+{
+ end;
+
+OnCast:
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 39) end;
+ if (getskilllv(SKILL_MAGIC) < .level) end;
+ if (getskilllv(.school) < .level) end;
+ if (countitem("WhiteFur") < 1 || countitem("Root") < 1) end;
+ delitem "WhiteFur", 1;
+ delitem "Root", 1;
+ set MAGIC_CAST_TICK, gettimetick(2) + 20; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 39;
+ misceffect FX_MAGIC_BLUE, strcharinfo(0);
+ misceffect FX_PENTAGRAM_BUILDUP, strcharinfo(0);
+ callfunc "magic_exp";
+ set .@puppet$, "#"+strnpcinfo(0)+"#"+BL_ID;
+ set .@puppet, puppet(getmap(), POS_X, POS_Y, .@puppet$, 127);
+ set .count, (@spellpower/170)+1+(@spellpower/430), .@puppet;
+ set .master, BL_ID, .@puppet;
+ set .lifetime, @spellpower*350, .@puppet;
+ addnpctimer 5000-(@spellpower*8), .@puppet$+"::OnSummon";
+ addnpctimer 6000, .@puppet$+"::OnDestroy";
+ end;
+
+OnSummon:
+ specialeffect FX_PENTAGRAM_BURST;
+ set .@i, 0;
+ set .@x, getnpcx();
+ set .@y, getnpcy();
+ set .@map$, strnpcinfo(3);
+ callsub S_SummonAll;
+ end;
+
+OnDestroy:
+ destroy;
+
+S_SummonAll:
+ summon .@map$, rand(.@x-2,.@x+2), rand(.@y-2,.@y+2), .master, 1020, 2, .lifetime;
+ set .@i, .@i + 1;
+ if (.@i < .count) goto S_SummonAll;
+ return;
+
+OnInit:
+ set .school, SKILL_MAGIC_ASTRAL;
+ set .invocation$, chr(MAGIC_SYMBOL) + "kalakarenk"; // used in npcs that refer to this spell
+ callfunc "magic_register2";
+ set .level, 2;
+ set .exp_gain, 1;
+ end;
+}
diff --git a/world/map/npc/magic/level2-summon-mouboo.txt b/world/map/npc/magic/level2-summon-mouboo.txt
new file mode 100644
index 00000000..6b82b8c9
--- /dev/null
+++ b/world/map/npc/magic/level2-summon-mouboo.txt
@@ -0,0 +1,53 @@
+-|script|mouboos|32767
+{
+ end;
+
+OnCast:
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 35) end;
+ if (getskilllv(SKILL_MAGIC) < .level) end;
+ if (getskilllv(.school) < .level) end;
+ if (countitem("MoubooFigurine") < 1 || countitem("Root") < 1) end;
+ delitem "MoubooFigurine", 1;
+ delitem "Root", 1;
+ set MAGIC_CAST_TICK, gettimetick(2) + 20; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 35;
+ misceffect FX_MAGIC_BLUE, strcharinfo(0);
+ misceffect FX_PENTAGRAM_BUILDUP, strcharinfo(0);
+ callfunc "magic_exp";
+ set .@puppet$, "#"+strnpcinfo(0)+"#"+BL_ID;
+ set .@puppet, puppet(getmap(), POS_X, POS_Y, .@puppet$, 127);
+ set .count, (@spellpower/270)+1, .@puppet;
+ set .master, BL_ID, .@puppet;
+ set .lifetime, @spellpower*100, .@puppet;
+ addnpctimer 4000-(@spellpower*9), .@puppet$+"::OnSummon";
+ addnpctimer 6000, .@puppet$+"::OnDestroy";
+ end;
+
+OnSummon:
+ specialeffect FX_PENTAGRAM_BURST;
+ set .@i, 0;
+ set .@x, getnpcx();
+ set .@y, getnpcy();
+ set .@map$, strnpcinfo(3);
+ callsub S_SummonAll;
+ end;
+
+OnDestroy:
+ destroy;
+
+S_SummonAll:
+ summon .@map$, rand(.@x-2,.@x+2), rand(.@y-2,.@y+2), .master, 1028, 2, .lifetime;
+ set .@i, .@i + 1;
+ if (.@i < .count) goto S_SummonAll;
+ return;
+
+OnInit:
+ set .school, SKILL_MAGIC_ASTRAL;
+ set .invocation$, chr(MAGIC_SYMBOL) + "kalboo"; // used in npcs that refer to this spell
+ callfunc "magic_register2";
+ set .level, 2;
+ set .exp_gain, 2;
+ end;
+}
diff --git a/world/map/npc/magic/level2-summon-pinkie.txt b/world/map/npc/magic/level2-summon-pinkie.txt
new file mode 100644
index 00000000..2c8d235e
--- /dev/null
+++ b/world/map/npc/magic/level2-summon-pinkie.txt
@@ -0,0 +1,53 @@
+-|script|pinkies|32767
+{
+ end;
+
+OnCast:
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 35) end;
+ if (getskilllv(SKILL_MAGIC) < .level) end;
+ if (getskilllv(.school) < .level) end;
+ if (countitem("PinkAntenna") < 1 || countitem("Root") < 1) end;
+ delitem "PinkAntenna", 1;
+ delitem "Root", 1;
+ set MAGIC_CAST_TICK, gettimetick(2) + 20; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 35;
+ misceffect FX_MAGIC_BLUE, strcharinfo(0);
+ misceffect FX_PENTAGRAM_BUILDUP, strcharinfo(0);
+ callfunc "magic_exp";
+ set .@puppet$, "#"+strnpcinfo(0)+"#"+BL_ID;
+ set .@puppet, puppet(getmap(), POS_X, POS_Y, .@puppet$, 127);
+ set .count, (@spellpower/120)+1, .@puppet;
+ set .master, BL_ID, .@puppet;
+ set .lifetime, @spellpower*150, .@puppet;
+ addnpctimer 5000-(@spellpower*9), .@puppet$+"::OnSummon";
+ addnpctimer 6000, .@puppet$+"::OnDestroy";
+ end;
+
+OnSummon:
+ specialeffect FX_PENTAGRAM_BURST;
+ set .@i, 0;
+ set .@x, getnpcx();
+ set .@y, getnpcy();
+ set .@map$, strnpcinfo(3);
+ callsub S_SummonAll;
+ end;
+
+OnDestroy:
+ destroy;
+
+S_SummonAll:
+ summon .@map$, rand(.@x-2,.@x+2), rand(.@y-2,.@y+2), .master, 1018, 2, .lifetime;
+ set .@i, .@i + 1;
+ if (.@i < .count) goto S_SummonAll;
+ return;
+
+OnInit:
+ set .school, SKILL_MAGIC_ASTRAL;
+ set .invocation$, chr(MAGIC_SYMBOL) + "kalgina"; // used in npcs that refer to this spell
+ callfunc "magic_register2";
+ set .level, 2;
+ set .exp_gain, 2;
+ end;
+}
diff --git a/world/map/npc/magic/level2-summon-snakes.txt b/world/map/npc/magic/level2-summon-snakes.txt
new file mode 100644
index 00000000..2bce0f96
--- /dev/null
+++ b/world/map/npc/magic/level2-summon-snakes.txt
@@ -0,0 +1,54 @@
+-|script|summon-snakes|32767
+{
+ end;
+
+OnCast:
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 40) end;
+ if (getskilllv(SKILL_MAGIC) < .level) end;
+ if (getskilllv(.school) < .level) end;
+ if (countitem("DarkCrystal") < 1 || countitem("SnakeEgg") < 1) end;
+ if (OrumQuest <= 40) end;
+ delitem "DarkCrystal", 1;
+ delitem "SnakeEgg", 1;
+ set MAGIC_CAST_TICK, gettimetick(2) + 15; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 40;
+ misceffect FX_MAGIC_DARKRED, strcharinfo(0);
+ misceffect FX_PENTAGRAM_BUILDUP, strcharinfo(0);
+ callfunc "magic_exp";
+ set .@puppet$, "#"+strnpcinfo(0)+"#"+BL_ID;
+ set .@puppet, puppet(getmap(), POS_X, POS_Y, .@puppet$, 127);
+ set .count, (@spellpower/300)+1, .@puppet;
+ set .master, BL_ID, .@puppet;
+ set .lifetime, @spellpower*80, .@puppet;
+ addnpctimer 4000-(@spellpower*9), .@puppet$+"::OnSummon";
+ addnpctimer 6000, .@puppet$+"::OnDestroy";
+ end;
+
+OnSummon:
+ specialeffect FX_PENTAGRAM_BURST;
+ set .@i, 0;
+ set .@x, getnpcx();
+ set .@y, getnpcy();
+ set .@map$, strnpcinfo(3);
+ callsub S_SummonAll;
+ end;
+
+OnDestroy:
+ destroy;
+
+S_SummonAll:
+ summon .@map$, rand(.@x-2,.@x+2), rand(.@y-2,.@y+2), .master, 1010, 2, .lifetime;
+ set .@i, .@i + 1;
+ if (.@i < .count) goto S_SummonAll;
+ return;
+
+OnInit:
+ set .school, SKILL_MAGIC_DARK;
+ set .invocation$, chr(MAGIC_SYMBOL) + "halhiss"; // used in npcs that refer to this spell
+ callfunc "magic_register2";
+ set .level, 2;
+ set .exp_gain, 3;
+ end;
+}
diff --git a/world/map/npc/magic/level2-summon-spiky-mushroom.txt b/world/map/npc/magic/level2-summon-spiky-mushroom.txt
new file mode 100644
index 00000000..182bbda5
--- /dev/null
+++ b/world/map/npc/magic/level2-summon-spiky-mushroom.txt
@@ -0,0 +1,53 @@
+-|script|spikymushroom|32767
+{
+ end;
+
+OnCast:
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 33) end;
+ if (getskilllv(SKILL_MAGIC) < .level) end;
+ if (getskilllv(.school) < .level) end;
+ if (countitem("HardSpike") < 1 || countitem("Root") < 1) end;
+ delitem "HardSpike", 1;
+ delitem "Root", 1;
+ set MAGIC_CAST_TICK, gettimetick(2) + 20; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 33;
+ misceffect FX_MAGIC_BLUE, strcharinfo(0);
+ misceffect FX_PENTAGRAM_BUILDUP, strcharinfo(0);
+ callfunc "magic_exp";
+ set .@puppet$, "#"+strnpcinfo(0)+"#"+BL_ID;
+ set .@puppet, puppet(getmap(), POS_X, POS_Y, .@puppet$, 127);
+ set .count, (@spellpower/120)+1, .@puppet;
+ set .master, BL_ID, .@puppet;
+ set .lifetime, @spellpower*400, .@puppet;
+ addnpctimer 5000-(@spellpower*9), .@puppet$+"::OnSummon";
+ addnpctimer 6000, .@puppet$+"::OnDestroy";
+ end;
+
+OnSummon:
+ specialeffect FX_PENTAGRAM_BURST;
+ set .@i, 0;
+ set .@x, getnpcx();
+ set .@y, getnpcy();
+ set .@map$, strnpcinfo(3);
+ callsub S_SummonAll;
+ end;
+
+OnDestroy:
+ destroy;
+
+S_SummonAll:
+ summon .@map$, rand(.@x-2,.@x+2), rand(.@y-2,.@y+2), .master, 1019, 2, .lifetime;
+ set .@i, .@i + 1;
+ if (.@i < .count) goto S_SummonAll;
+ return;
+
+OnInit:
+ set .school, SKILL_MAGIC_ASTRAL;
+ set .invocation$, chr(MAGIC_SYMBOL) + "kalrenk"; // used in npcs that refer to this spell
+ callfunc "magic_register2";
+ set .level, 2;
+ set .exp_gain, 1;
+ end;
+}
diff --git a/world/map/npc/magic/level2-summon-wickedmushroom.txt b/world/map/npc/magic/level2-summon-wickedmushroom.txt
new file mode 100644
index 00000000..bceef8b6
--- /dev/null
+++ b/world/map/npc/magic/level2-summon-wickedmushroom.txt
@@ -0,0 +1,54 @@
+-|script|wickedmushroom|32767
+{
+ end;
+
+OnCast:
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 35) end;
+ if (getskilllv(SKILL_MAGIC) < .level) end;
+ if (getskilllv(.school) < .level) end;
+ if (countitem("DarkCrystal") < 1 || countitem("SmallMushroom") < 1) end;
+ if (OrumQuest <= 36) end;
+ delitem "DarkCrystal", 1;
+ delitem "SmallMushroom", 1;
+ set MAGIC_CAST_TICK, gettimetick(2) + 15; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 35;
+ misceffect FX_MAGIC_DARKRED, strcharinfo(0);
+ misceffect FX_PENTAGRAM_BUILDUP, strcharinfo(0);
+ callfunc "magic_exp";
+ set .@puppet$, "#"+strnpcinfo(0)+"#"+BL_ID;
+ set .@puppet, puppet(getmap(), POS_X, POS_Y, .@puppet$, 127);
+ set .count, (@spellpower/250)+1, .@puppet;
+ set .master, BL_ID, .@puppet;
+ set .lifetime, @spellpower*80, .@puppet;
+ addnpctimer 4000-(@spellpower*9), .@puppet$+"::OnSummon";
+ addnpctimer 6000, .@puppet$+"::OnDestroy";
+ end;
+
+OnSummon:
+ specialeffect FX_PENTAGRAM_BURST;
+ set .@i, 0;
+ set .@x, getnpcx();
+ set .@y, getnpcy();
+ set .@map$, strnpcinfo(3);
+ callsub S_SummonAll;
+ end;
+
+OnDestroy:
+ destroy;
+
+S_SummonAll:
+ summon .@map$, rand(.@x-2,.@x+2), rand(.@y-2,.@y+2), .master, 1106, 2, .lifetime;
+ set .@i, .@i + 1;
+ if (.@i < .count) goto S_SummonAll;
+ return;
+
+OnInit:
+ set .school, SKILL_MAGIC_DARK;
+ set .invocation$, chr(MAGIC_SYMBOL) + "helorp"; // used in npcs that refer to this spell
+ callfunc "magic_register2";
+ set .level, 2;
+ set .exp_gain, 3;
+ end;
+}
diff --git a/world/map/npc/magic/level2-toxic-dart.txt b/world/map/npc/magic/level2-toxic-dart.txt
new file mode 100644
index 00000000..91522a58
--- /dev/null
+++ b/world/map/npc/magic/level2-toxic-dart.txt
@@ -0,0 +1,36 @@
+-|script|toxic-dart|32767
+{
+ callfunc "magic_checks"; if(@failed) end; // << I wish we had functions that could return >>
+ if (Sp < 15) end;
+ set .@level, getskilllv(.school);
+ if (.@level < .level) end;
+ if (OrumQuest <= 37) end;
+ if (.@level <= 2 && countitem("Root") >= 2) delitem "Root", 2;
+ elif (.@level <= 2) end;
+ set MAGIC_CAST_TICK, gettimetick(2) + 1; // set the new debuff
+ callfunc "adjust_spellpower";
+ set Sp, Sp - 15;
+ misceffect FX_MAGIC_DARKRED, strcharinfo(0);
+ set @damage, sqrt(@spellpower) * 5;
+ set @dmg_bonus, (BaseLevel/3) + 5;
+ overrideattack (@spellpower/75)+3, 1200, 4, ATTACK_ICON_GENERIC, 31, strnpcinfo(0)+"::OnAttack";
+ callfunc "magic_exp";
+ end;
+
+OnAttack:
+ misceffect FX_MAGIC_DARKRED, strcharinfo(0);
+ if (target(BL_ID, @target_id, 50) != 50) end; // 0x20 | 0x02 | 0x10
+ setarray @edmg[0], @damage, @dmg_bonus, ELT_NEUTRAL, ELT_POISON, FX_FIRE_BURST;
+ callfunc "elt_damage";
+ if(@target_id != BL_ID && isloggedin(@target_id)) // this is a dirty trick to check if the target is a player
+ sc_start sc_poison, 5000+(@spellpower*1200), max(15,@spellpower/15)+5, @target_id;
+ end;
+
+OnInit:
+ set .school, SKILL_MAGIC_DARK;
+ set .invocation$, chr(MAGIC_SYMBOL) + "phlex"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 2;
+ set .exp_gain, 3;
+ end;
+}
diff --git a/world/map/npc/magic/level3-necromancy.txt b/world/map/npc/magic/level3-necromancy.txt
new file mode 100644
index 00000000..bd1f611c
--- /dev/null
+++ b/world/map/npc/magic/level3-necromancy.txt
@@ -0,0 +1,54 @@
+// see https://tmworld.uservoice.com/forums/255809-general/suggestions/6051818-sacrifice
+// author: gumi
+-|script|necromancy|32767
+{
+ callfunc "magic_checks"; if(@failed) end;
+ if (Sp < 50) end;
+ if (getskilllv(.school) < .level) end;
+ if (getskilllv(SKILL_MAGIC) < .level) end;
+ set @target_id, getcharid(3, @args$);
+ if (@target_id < 1 || !(isloggedin(@target_id))) end;
+ if (get(Hp, @target_id) > 0) end;
+ if (Hp < (get(MaxHp, @target_id) / 3)) end; // hp must be at least a third of the max hp of the target
+ callfunc "adjust_spellpower";
+ if (distance(BL_ID, @target_id) >= (((sqrt(@spellpower)*12)+@spellpower)/100)+2) end;
+ if (get(@necromancer, @target_id) > 0) end; // someone else is already trying to resurrect this player
+ if (getmapflag(getmap(), MF_NOSAVE)) end; // do not allow for maps like illia or candor
+ if (countitem("Soul") >= 1) delitem "Soul", 1; else end;
+
+ set MAGIC_CAST_TICK, gettimetick(2) + 20;
+ set Sp, Sp - 50;
+ misceffect FX_MAGIC_DARKRED, strcharinfo(0); // on caster
+ misceffect FX_PENTAGRAM_BUILDUP, @args$; // on target
+
+ set @necromancer, CHAR_ID, @target_id; // tell the target who is reviving them
+
+ if (attachrid(@target_id) != 1) end;
+ addtimer 6000, strnpcinfo(0)+"::OnRevive"; // TODO: make it take more or less time depending on the spell power
+ end;
+
+OnRevive:
+ set .@necro, get(BL_ID, @necromancer);
+ if (.@necro < 1) goto L_Clean;
+ if (get(Hp, .@necro) < 1) end;
+ misceffect FX_PENTAGRAM_BURST, strcharinfo(0);
+ misceffect FX_CRITICAL, strcharinfo(0, .@necro);
+ heal 1, 0; // revive
+ set Hp, 1;
+ set Sp, 0;
+ set Hp, 1, .@necro;
+ set Sp, 0, .@necro;
+ goto L_Clean;
+
+L_Clean:
+ set @necromancer, 0;
+ end;
+
+OnInit:
+ set .school, SKILL_MAGIC_DARK;
+ set .invocation$, chr(MAGIC_SYMBOL) + "nevela"; // used in npcs that refer to this spell
+ callfunc "magic_register";
+ set .level, 3;
+ set .exp_gain, 1;
+ end;
+}
diff --git a/world/map/npc/scripts.conf b/world/map/npc/scripts.conf
index e9bceb20..68a348e1 100644
--- a/world/map/npc/scripts.conf
+++ b/world/map/npc/scripts.conf
@@ -32,6 +32,7 @@ npc: npc/functions/dynamic_menu.txt
npc: npc/functions/DyeConfig.txt
npc: npc/functions/motd.txt
npc: npc/functions/motdconfig.txt
+npc: npc/functions/hug.txt
// Item Functions
npc: npc/items/magic_gm_top_hat.txt
@@ -50,6 +51,12 @@ npc: npc/items/mirror.txt
npc: npc/items/rubber_bat.txt
import: npc/_import.txt
+// magic
+import: npc/magic/_import.txt
+
+// GM commands
+import: npc/commands/_import.txt
+
// GM Events
npc: npc/functions/gm_island.txt
// Annuals Framework