summaryrefslogtreecommitdiff
path: root/npc/magic/config.txt
diff options
context:
space:
mode:
Diffstat (limited to 'npc/magic/config.txt')
-rw-r--r--npc/magic/config.txt434
1 files changed, 434 insertions, 0 deletions
diff --git a/npc/magic/config.txt b/npc/magic/config.txt
new file mode 100644
index 00000000..f8135b43
--- /dev/null
+++ b/npc/magic/config.txt
@@ -0,0 +1,434 @@
+// TMW2 script
+// Author: Jesusalva <admin@tmw2.org>
+//
+// Magic Script Core Functions
+//
+// Used for our pseudo-magic.
+// These are only helpers, you can add more restrictions and effects freely.
+// Here abizit() goes up to 10 instead of 5
+function script abizit {
+ if (!getskilllv(SKILL_MAGIC)) return 0;
+ switch (getskilllv(SKILL_MAGIC)) {
+ case 1:
+ .@base = 10; break;
+ case 2:
+ .@base = 120; break;
+ case 3:
+ .@base = 1500; break;
+ case 4:
+ .@base = 20000; break;
+ case 5:
+ .@base = 250000; break;
+ default:
+ return 0;
+ }
+ return min(MAGIC_EXP/.@base, 10);
+ return 0;
+}
+
+// AdjustSpellpower(power=100, {target=@skillTarget{, type=HARM_MAGI}})
+function script AdjustSpellpower {
+ .@power=getarg(0, 100);
+ .@target=getarg(1, @skillTarget);
+ .@type=getarg(2, HARM_MAGI);
+ .@src=getcharid(3);
+
+ // Prevents a possible glitch
+ if (.@target < 1 || .@target == getcharid(3))
+ .@target=0;
+
+ // Your magic power permanently increases your damage in 5%
+ if (getskilllv(SKILL_MAGIC) > 1)
+ .@power+=getskilllv(SKILL_MAGIC)*5-5;
+
+ // Calculation FIX
+ if (.@type == HARM_MAGI) {
+ .@power+=(readparam2(UDT_INT)/5);
+ .@dmg=rand2(
+ readbattleparam(getcharid(3), UDT_MATKMIN),
+ readbattleparam(getcharid(3), UDT_MATKMAX));
+ // Apply defense
+ //if (.@target)
+ // .@dmg=max(0, .@dmg-getunitdata(.@target, UDT_MDEF));
+ } else if (.@type == HARM_PHYS) {
+ .@power+=(readparam2(UDT_STR)/5);
+ .@dmg=rand2(
+ readbattleparam(getcharid(3), UDT_ATKMIN),
+ readbattleparam(getcharid(3), UDT_ATKMAX));
+ // Apply defense
+ //if (.@target)
+ // .@dmg=max(0, .@dmg-getunitdata(.@target, UDT_DEF));
+ } else {
+ .@dmg = .@power; .@power = 100;
+ }
+ // Abizit Influence (50%~110% at best, perfect ctrl is 100%~110%)
+ .@dmg = .@dmg * (50 + abizit() * rand2(5,6)) / 100;
+ .@dmg = .@dmg * .@power / 100;
+ return .@dmg;
+}
+
+// An alias for simplification
+// AdjustAttackpower(power=100, {target=@skillTarget{, type=HARM_PHYS}})
+function script AdjustAttackpower {
+ .@power=getarg(0, 100);
+ .@target=getarg(1, @skillTarget);
+ .@type=getarg(2, HARM_PHYS);
+ return AdjustSpellpower(.@power, .@target, .@type);
+}
+
+
+// SkillID, EXP Points
+function script GetManaExp {
+ .@sk=getarg(0);
+ .@pt=getarg(1);
+ if (LAST_SKILL != .@sk) {
+ // Update skill memory
+ LAST_SKILL[4]=LAST_SKILL[3];
+ LAST_SKILL[3]=LAST_SKILL[2];
+ LAST_SKILL[2]=LAST_SKILL[1];
+ LAST_SKILL[1]=LAST_SKILL[0];
+ LAST_SKILL[0]=.@sk;
+ // Magic EXP is gained by switching skills often
+ MAGIC_EXP=MAGIC_EXP+.@pt;
+ }
+ return;
+}
+
+
+// SkillID, MobID{, SkillLevelPerMob=2{, Level Override{, Summon=True}}}
+function script SummonMagic {
+ .@sk=getarg(0);
+ .@id=getarg(1);
+ .@adj=getarg(2,2);
+ .@lv=getarg(3,getskilllv(.@sk));
+ .@sm=getarg(4, true);
+
+ if (.@adj < 1) {
+ debugmes "\033[31mInvalid MobPerSkillLevel for SummonMagic (.@adj): "+.@adj+"\033[0m";
+ dispbottom l("Invalid parameter specified, blame saulc.");
+ end;
+ }
+
+ if (!.@sm)
+ getmapxy(.@m$, .@x, .@y, 0);
+
+ // Cause effect
+ // Summoned monsters live from 45 to 60 seconds, and each skill levels grants 10s extra life
+ // The 35~50 is not a defect, remember skill starts at level 1...
+ // PS. Abizit makes a variation from 80% to 130% of official values
+ for (.@i = 0; .@i < (.@lv+(.@adj-1))/.@adj; .@i++) {
+ .@lifetime=rand2(35,50)+.@lv*10;
+ // Abizit makes lifetime vary (like AdjustSpellpower)
+ .@lifetime = .@lifetime * (50 + abizit() * rand2(5,6)) / 100;
+ // Unfortunately this version does not returns the summoned monster GID
+ if (.@sm)
+ summon("Summoned Monster", .@id, .@lifetime);
+ else
+ monster(.@m$, .@x, .@y, "Invoked Monster", .@id, 1);
+ /*
+ .@mids=summon("Summoned Monster", .@id, .@lifetime);
+ .@bhp=getunitdata(.@mids, UDT_MAXHP);
+ // Each skill level raises HP in 5%
+ .@lvx=.@bhp + max(0, (.@lv-1)*.@bhp/20);
+ // Abizit makes bonus HP vary (like AdjustSpellpower)
+ .@lvx = .@lvx * (50 + abizit() * rand2(5,6)) / 100;
+ setunitdata(.@mids, UDT_MAXHP, .@lvx);
+ setunitdata(.@mids, UDT_HP, .@lvx);
+ // Reconfigure monster modes
+ .@opt=getunitdata(.@mids, UDT_MODE);
+ // Disable looting
+ if (.@opt & MD_LOOTER)
+ .@opt=.@opt^MD_LOOTER;
+ // All summons can suffer knockback
+ if (.@opt & MD_NOKNOCKBACK)
+ .@opt=.@opt^MD_NOKNOCKBACK;
+ // Strip summons from BOSS mode and immunity
+ if (.@opt & MD_BOSS)
+ .@opt=.@opt^MD_BOSS;
+ // Save new options
+ setunitdata(.@mids, UDT_MODE, .@opt);
+ */
+ }
+ dispbottom l("All monsters summoned!");
+ return;
+}
+
+
+// SK_summon(ID, amount, mexp{, summon=True})
+function script SK_summon {
+ .@mob=getarg(0);
+ .@amt=getarg(1);
+ .@mex=getarg(2, 1);
+ .@sum=getarg(3, true);
+ .@lvl=getskilllv(SKILL_MAGIC);
+ if ($@GM_OVERRIDE || debug) debugmes "Skill "+@skillId+" Lv "+@skillLv;
+ if (ispcdead() || !.@lvl || !@skillLv)
+ return;
+
+ if (rand2(10) < abizit()) {
+ // Summon Magic (with magic level bonus)
+ SummonMagic(@skillId, .@mob, .@amt, .@lvl+@skillLv-1, @skillLv, .@sum);
+ } else if (rand2(10) < abizit()) {
+ // Re-roll
+ dispbottom l("You cannot complete the casting correctly!");
+ SummonMagic(@skillId, .@mob, 1, 1, 1, .@sum);
+ } else if (abizit() <= rand2(3)) {
+ // Spell overwhelms you, causing it to be spawned as aggro vs you. (33%)
+ dispbottom l("The spell takes a mind of its own backfires!");
+ getmapxy(.@m$, .@x, .@y, 0);
+ .@opo=monster(.@m$, .@x, .@y, "Failed summon", .@mob, 1);
+ unitattack(.@opo, getcharid(3));
+ } else {
+ dispbottom l("The spell fails!");
+ }
+
+ // Get a single mana experience point (FIXME)
+ GetManaExp(@skillId, .@mex);
+ return;
+}
+
+// areaharm(target, range, DMG, {type, element, filter, bl})
+// Defaults to HARM_MISC, Ele_Neutral, filter filter_hostile and all BLs
+// Valid BL: BL_MOB | BL_PC | BL_HOM | BL_MER
+// Do not use: NPC, PET, ELEM
+// Range centers on caster (player), implement and use areaharm2 elsewhere
+function script areaharm {
+ .@t=getarg(0);
+ .@r=getarg(1);
+ .@d=getarg(2);
+ .@h=getarg(3, HARM_MISC);
+ .@e=getarg(4, Ele_Neutral);
+ .@f$=getarg(5, "filter_hostile");
+ .@b=getarg(6, BL_PC | BL_MOB | BL_MER | BL_HOM);
+
+ getmapxy(.@m$, .@x, .@y, getunittype(.@t), .@t);
+
+ .@c=getunits(.@b, .@mbs, false, .@m$, .@x-.@r, .@y-.@r, .@x+.@r, .@y+.@r);
+ for (.@i = 0; .@i < .@c; .@i++) {
+ // Filtering
+ if (!callfunc(.@f$, .@mbs[.@i]))
+ continue;
+ harm(.@mbs[.@i], .@d, .@t, .@e);
+ specialeffect(FX_ATTACK, AREA, .@mbs[.@i]);
+ // TODO: Handle MobPt to don't overload timer system?
+ }
+ return;
+}
+
+
+// rectharm(target, x, y, DMG, {type, element, filter, bl})
+// Same as areaharm() but causes a rectangle in (x,y) size, instead of a square
+function script rectharm {
+ .@t=getarg(0);
+ .@rx=getarg(1);
+ .@ry=getarg(2);
+ .@d=getarg(3);
+ .@h=getarg(4, HARM_MISC);
+ .@e=getarg(5, Ele_Neutral);
+ .@f$=getarg(6, "filter_hostile");
+ .@b=getarg(7, BL_PC | BL_MOB | BL_MER | BL_HOM);
+
+ getmapxy(.@m$, .@x, .@y, getunittype(.@t), .@t);
+
+ .@c=getunits(.@b, .@mbs, false, .@m$, .@x-.@rx, .@y-.@ry, .@x+.@rx, .@y+.@ry);
+ for (.@i = 0; .@i < .@c; .@i++) {
+ // Filtering
+ if (!callfunc(.@f$, .@mbs[.@i]))
+ continue;
+ harm(.@mbs[.@i], .@d, .@t, .@e);
+ specialeffect(FX_ATTACK, AREA, .@mbs[.@i]);
+ // TODO: Handle MobPt to don't overload timer system?
+ }
+ return;
+}
+
+// areasc(range, time, sc, bl, value, filter, target, chances)
+// Defaults to 3x3 square, sleep mob for 500ms. Ignores you.
+// Centered on player attached, 100% success chance
+// Need a player caster. Valid BL: BL_MOB | BL_PC | BL_HOM | BL_MER
+function script areasc {
+ .@r=getarg(0, 3);
+ .@d=getarg(1, 500);
+ .@s=getarg(2, SC_SLEEP);
+ .@b=getarg(3, BL_MOB);
+ .@val=getarg(4, 1);
+ .@f$=getarg(5, "filter_notme");
+ .@t=getarg(6, playerattached());
+ .@sr=getarg(7, 10000);
+
+ getmapxy(.@m$, .@x, .@y, getunittype(.@t), .@t);
+ .@c=getunits(.@b, .@mbs, false, .@m$, .@x-.@r, .@y-.@r, .@x+.@r, .@y+.@r);
+ for (.@i = 0; .@i < .@c; .@i++) {
+ // Filtering
+ if (!callfunc(.@f$, .@mbs[.@i]))
+ continue;
+ sc_start .@s, .@d, .@val, .@sr, SCFLAG_NONE, .@mbs[.@i];
+ specialeffect(FX_BUFF, AREA, .@mbs[.@i]);
+ }
+ return;
+}
+
+// areasc2(map, x, y, {range, time, sc, bl, value, filter}) - can be used by NPC
+// Valid BL: BL_MOB | BL_PC | BL_HOM | BL_MER
+function script areasc2 {
+ .@m$=getarg(0);
+ .@x=getarg(1);
+ .@y=getarg(2);
+ .@r=getarg(3, 3);
+ .@d=getarg(4, 500);
+ .@s=getarg(5, SC_SLEEP);
+ .@b=getarg(6, BL_MOB);
+ .@val=getarg(7, 1);
+ .@f$=getarg(8, "filter_always");
+
+ .@c=getunits(.@b, .@mbs, false, .@m$, .@x-.@r, .@y-.@r, .@x+.@r, .@y+.@r);
+ for (.@i = 0; .@i < .@c; .@i++) {
+ // Filtering
+ if (!callfunc(.@f$, .@mbs[.@i]))
+ continue;
+ sc_start .@s, .@d, .@val, 10000, SCFLAG_NONE, .@mbs[.@i];
+ specialeffect(FX_BUFF, AREA, .@mbs[.@i]);
+ }
+ return;
+}
+
+// areasc3(range, time, sc, bl, val1, val2, filter)
+// Defaults to 3x3 square, sleep mob for 500ms. Ignores you.
+// Need a player caster. Valid BL: BL_MOB | BL_PC | BL_HOM | BL_MER
+function script areasc3 {
+ .@r=getarg(0, 3);
+ .@d=getarg(1, 500);
+ .@s=getarg(2, SC_SLEEP);
+ .@b=getarg(3, BL_MOB);
+ .@v1=getarg(4, 1);
+ .@v2=getarg(5, 1);
+ .@f$=getarg(6, "filter_notme");
+
+ getmapxy(.@m$, .@x, .@y, 0);
+ .@c=getunits(.@b, .@mbs, false, .@m$, .@x-.@r, .@y-.@r, .@x+.@r, .@y+.@r);
+ for (.@i = 0; .@i < .@c; .@i++) {
+ // Filtering
+ if (!callfunc(.@f$, .@mbs[.@i]))
+ continue;
+ sc_start2 .@s, .@d, .@v1, .@v2, 10000, SCFLAG_NONE, .@mbs[.@i];
+ specialeffect(FX_BUFF, AREA, .@mbs[.@i]);
+ }
+ return;
+}
+
+// massprovoke(range, {map, x, y}) - player only
+function script massprovoke {
+ getmapxy(.@m$, .@x, .@y, 0);
+ .@r=getarg(0, 3);
+ .@m$=getarg(1, .@m$);
+ .@x=getarg(2, .@x);
+ .@y=getarg(3, .@y);
+
+ .@c=getunits(BL_MOB, .@mbs, false, .@m$, .@x-.@r, .@y-.@r, .@x+.@r, .@y+.@r);
+ for (.@i = 0; .@i < .@c; .@i++) {
+ //sc_start .@s, .@d, 1, 10000, SCFLAG_NONE, .@mbs[.@i];
+ aggravate .@mbs[.@i];
+ specialeffect(FX_MAGIC, AREA, .@mbs[.@i]);
+ }
+ return;
+}
+
+
+
+// getactivatedpoolskilllist(?)
+function script getactivatedpoolskilllist {
+ return bitmask_count(FOCUSING);
+}
+
+// getdeactivatedpoolskilllist(?)
+function script getdeactivatedpoolskilllist {
+ return (bitmask_count(FOCUSING)-FSKILL_TOTAL);
+}
+
+// getpoolskillFID(ID)
+function script getpoolskillFID {
+ switch (getarg(0)) {
+ case SKILL_MALLARDS_EYE: return FSKILL_MALLARDS_EYE;
+ case SKILL_BRAWLING: return FSKILL_BRAWLING;
+ case SKILL_SPEED: return FSKILL_SPEED;
+ case SKILL_RESIST_POISON: return FSKILL_RESIST_POISON;
+ case SKILL_ASTRAL_SOUL: return FSKILL_ASTRAL_SOUL;
+ case SKILL_RAGING: return FSKILL_RAGING;
+ }
+ return Exception("Invalid focus skill ID: "+getarg(0), RB_DEFAULT|RB_ISFATAL);
+}
+
+// poolskill(skill)
+function script poolskill {
+ if (bitmask_count(FOCUSING) < getskilllv(SKILL_POOL)) {
+ FOCUSING=FOCUSING | getpoolskillFID(getarg(0));
+ recalcstatus();
+ return true;
+ }
+ return false;
+}
+
+// unpoolskill(skill)
+function script unpoolskill {
+ .@f=getpoolskillFID(getarg(0));
+ if (FOCUSING & .@f)
+ FOCUSING=FOCUSING ^ .@f;
+ recalcstatus();
+ return;
+}
+
+// isfocused(skill)
+function script isfocused {
+ .@f=getpoolskillFID(getarg(0));
+ return (FOCUSING & .@f);
+}
+
+// mcharge(item, school, charges) {inheirs = @skillId}
+function script mcharge {
+ .@it=getarg(0);
+ .@sc=getarg(1);
+ .@cr=getarg(2, 0);
+ if (@MCHARGE[@skillId] < 1) {
+ delitem .@it, 1;
+ @MCHARGE[@skillId] = .@cr+getskilllv(SKILL_MAGIC)+getskilllv(.@cr);
+ // Low supply warning
+ if (countitem(.@it) <= 3)
+ dispbottom col(b(l("Warning, %d remaining: %s",
+ countitem(.@it), getitemname(.@it))), 1);
+ }
+ @MCHARGE[@skillId]-=1;
+ return;
+}
+
+// transcheck( {item 1, amount 1}, {item 2, amount 2}... )
+// returns true upon success
+function script transcheck {
+ if (getargcount() < 2 || getargcount() % 2 != 0)
+ return Exception("Faulty transcheck invoked - error");
+
+ // Count items
+ for (.@i=0;.@i < getargcount(); .@i++) {
+ if (countitem(getarg(.@i)) < getarg(.@i+1))
+ return false;
+ .@i++;
+ }
+
+ // Delete Items
+ for (.@i=0;.@i < getargcount(); .@i++) {
+ delitem getarg(.@i), getarg(.@i+1);
+ .@i++;
+ }
+ return true;
+}
+
+- script Magic Load NPC_HIDDEN,{
+OnInit:
+ end;
+OnSkillInvoke:
+ callfunc("HUB_SkillInvoke");
+ end;
+OnPCBonusEvent:
+ callfunc("HUB_PCBonus");
+ end;
+}
+