diff options
Diffstat (limited to 'npc/magic/config.txt')
-rw-r--r-- | npc/magic/config.txt | 434 |
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; +} + |