diff options
Diffstat (limited to 'npc/magic')
-rw-r--r-- | npc/magic/config.txt | 434 | ||||
-rw-r--r-- | npc/magic/final.txt | 259 | ||||
-rw-r--r-- | npc/magic/level0-monsterinfo.txt | 38 | ||||
-rw-r--r-- | npc/magic/level0-reapercry.txt | 228 | ||||
-rw-r--r-- | npc/magic/level0-wand.txt | 25 | ||||
-rw-r--r-- | npc/magic/level1-aggravate.txt | 16 | ||||
-rw-r--r-- | npc/magic/level1-experience.txt | 55 | ||||
-rw-r--r-- | npc/magic/level1-flare-dart.txt | 23 | ||||
-rw-r--r-- | npc/magic/level1-grow-plants.txt | 29 | ||||
-rw-r--r-- | npc/magic/level1-lesser-heal.txt | 63 | ||||
-rw-r--r-- | npc/magic/level1-magic-blade.txt | 27 | ||||
-rw-r--r-- | npc/magic/level1-summon-maggots.txt | 15 | ||||
-rw-r--r-- | npc/magic/level1-transmutations.txt | 95 | ||||
-rw-r--r-- | npc/magic/level2-arrow-hail.txt | 44 | ||||
-rw-r--r-- | npc/magic/level2-happy-curse.txt | 32 | ||||
-rw-r--r-- | npc/magic/level2-lay-on-hands.txt | 71 | ||||
-rw-r--r-- | npc/magic/level2-lightning-strike.txt | 24 | ||||
-rw-r--r-- | npc/magic/level2-magic-knuckles.txt | 19 | ||||
-rw-r--r-- | npc/magic/level2-protect.txt | 51 | ||||
-rw-r--r-- | npc/magic/level2-rain.txt | 55 | ||||
-rw-r--r-- | npc/magic/level2-shear.txt | 54 | ||||
-rw-r--r-- | npc/magic/level2-summon-monsters.txt | 53 | ||||
-rw-r--r-- | npc/magic/level2-toxic-dart.txt | 23 |
23 files changed, 1733 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; +} + diff --git a/npc/magic/final.txt b/npc/magic/final.txt new file mode 100644 index 00000000..30dce5e9 --- /dev/null +++ b/npc/magic/final.txt @@ -0,0 +1,259 @@ +// TMW2 scripts. +// Authors: +// Jesusalva +// TMW Org. +// Description: +// HUB functions (Magic) +// HUB_SkillInvoke ( ) +function script HUB_SkillInvoke { + // Something is... wrong + if (!@skillId) { + Exception("ILLEGAL SKILL PASSED TO HUB. It has been compromised, Jim.", RB_DEBUGMES|RB_IRCBROADCAST); + debugmes "Legal Caster: %s", strcharinfo(0); + debugmes "Effective Caster: %d", @skillCaster; + return; + } + + /* *********************************************************************** */ + // TODO: Detect what was script-cast and what was player-case. Then, readd RB_IRCBROADCAST + // If you can't do this: You can't do this + if (getskilllv(@skillId) < @skillLv && @skillId != BS_GREED) + Exception("System ERROR, HSI."+@skillId+" INVALID CAST (got "+@skillLv+" expected "+getskilllv(@skillId)+", sub-LC."+(getcharid(3)-2000000)+")", RB_DEBUGMES|RB_ISFATAL); + // You are AFK for over 3 minutes, that's crazy, disregard + if (checkidle() > 180) + return; + + // Record to database + skillInvoke[@skillId] = skillInvoke[@skillId] + 1; + + // Script-based skills + /* *********************************************************************** */ + switch (@skillId) { + case TMW2_FAKESKILL: + charcommand("@refresh"); // Possibly broken on too up-to-date Herc + break; + // Level 0 + case SKILL_CONFRINGO: + SK_Confringo(); break; + case SKILL_REAPERCRY: + Reapercry(); break; + // Level 1 + case SKILL_ABIZIT: + SK_Abizit(); break; + case SKILL_MONSTERINFO: + SK_Miteyo(); break; + case EVOL_AREA_PROVOKE: + SK_Itenplz(); break; + case SKILL_FLAR: + SK_Flar(); break; + case SKILL_MODRIPHOO: + case SKILL_MODRISUMP: + case SKILL_MODRIYIKAM: + case SKILL_MODRILAX: + SK_GrowPlants(); break; // FIXME: Unreleased/cannot be learned + case SKILL_LUM: + SK_Lum(); break; + case SKILL_CHIZA: + SK_Chiza(); break; + case SKILL_PARUM: + case SKILL_GOLE: + SK_Transmute(); break; + // Level 2 + case SKILL_INMA: + SK_Inma(); break; + case SKILL_JOYPLIM: + SK_Joyplim(); break; + case SKILL_CHIPCHIP: + SK_Shear(); break; + case SKILL_KALAKARENK: + case SKILL_KALBOO: + case SKILL_KALGINA: + case SKILL_KALRENK: + SK_SummonLv2(); break; + case SKILL_HALHISS: + case SKILL_HELORP: + SK_SummonLv2(); break; + case SKILL_KAFLOSH: + SK_Kaflosh(); break; + case SKILL_BETSANC: + SK_Betsanc(); break; + case SKILL_ASORM: + SK_Asorm(); break; + case SKILL_INGRAV: + SK_Ingrav(); break; + case SKILL_UPMARMU: + SK_Uparmu(); break; + case SKILL_FRILLYAR: + SK_Frillyar(); break; + case SKILL_PHLEX: + SK_Phlex(); break; + case SKILL_KULARZUFRILL: + case SKILL_ZUKMINBIRF: + case SKILL_PATMUPLOO: + case SKILL_PATVILOREE: + case SKILL_PATLOREE: + case SKILL_MANPAHIL: + SK_Transmute(); break; + // Level 3 + // Level 4 + // Level 5 + //////////////////////////////// + /* XXX: Fire Class + // (May burn targets for damage over time) + case TMW2_ARMAGEDDON: + .@PW=140+(10*@skillLv); + .@RG=5+(@skillLv/5); + // 18% chance, 3s, 3x3 radius + areaharm(@skillTarget, .@RG, AdjustSpellpower(.@PW), HARM_MAGI, Ele_Fire); + areasc(.@RG, 6000, SC_BLOODING, BL_MOB|BL_PC|BL_HOM|BL_MER, 1, "filter_hostile", @skillTarget, 1800); + GetManaExp(TMW2_FIREBALL, 3); + break; + //////////////////////////////// + // XXX: Earth Class + case TMW2_GAIABREAK: + .@PWA=170+(30*@skillLv); + .@PWB=110+(10*@skillLv); + .@dmg=AdjustSpellpower(.@PWA); + .@dsub=AdjustSpellpower(.@PWB); + harm(@skillTarget, .@dmg, HARM_MAGI, Ele_Earth); + rectharm(@skillTarget, 2, 5, .@dsub, HARM_MAGI, Ele_Earth); + areasc(2, 5000, SC_INCDEFRATE, BL_PC, 10, "filter_friendly"); + GetManaExp(TMW2_METEORSTRIKE, 3); + break; + //////////////////////////////// + // XXX: Physical Class (Regular) + case TMW2_FALKONSTRIKE: + .@PW=100+(25*@skillLv); + .@ST=0+(10*@skillLv); + .@TM=100+(90*@skillLv); + harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Neutral); + sc_start SC_STUN, .@TM, 1, .@ST, SCFLAG_NONE, @skillTarget; + GetManaExp(@skillId, 1); + break; + case TMW2_GROUNDSTRIKE: + .@PW=50+(40*@skillLv); + .@dmg=AdjustAttackpower(.@PW); + .@RG=2+(@skillLv/5); + .@TM=100+(@skillLv*200); + .@ST=500+(100*@skillLv); + .@EF=any(SC_STUN, SC_BLIND, SC_BLOODING, SC_BLIND, SC_BLOODING); + areaharm(@skillTarget, .@RG, .@dmg, HARM_PHYS, Ele_Neutral); + areasc(.@RG, .@TM, .@EF, BL_MOB | BL_PC | BL_HOM | BL_MER, 1, "filter_hostile", @skillTarget, .@ST); + GetManaExp(@skillId, 1); + break; + case TMW2_SUPREMEATTACK: + .@PW=100+(50*@skillLv); + harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Neutral); + GetManaExp(@skillId, 1); + break; + //////////////////////////////// + // Summons which never fail + case TMW2_ZARKOR: + SummonMagic(@skillId, CaveMaggot, 2, @skillLv); + GetManaExp(@skillId, 1); + break; + // Summons which may fail + case TMW2_KALWULF: + SK_summon(Wolvern, 4, any(3,4)); + break; + // More complex summons + case TMW2_FROZENHEART: + .@mobId=Moggun; + if (rand2(6,12) < abizit()+1) + { + .@mobId=Yeti; + } + SK_summon(.@mobId, 4, any(3,4)); + break; + case TMW2_STONEHEART: + .@mobId=Terranite; + if (rand2(9,12) < abizit()+1 && + BaseLevel > 80) + { + .@mobId=TerraniteProtector; + } + SK_summon(.@mobId, 4, any(4,5)); + break; + */ + + // Experience only + default: + GetManaExp(@skillId, 1); + break; + } + + // Debug + if ($@GM_OVERRIDE) + debugmes "Cast skill %d on level %d - Target %d", + @skillId, @skillLv, @skillTarget; + + // Cleanup (double-safe) + @skillTarget = 0; + return; + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// HUB_PCBonus () +function script HUB_PCBonus { + /* Passive Skills */ + if (FOCUSING & FSKILL_ASTRAL_SOUL) { + bonus bMatkRate, 3*getskilllv(SKILL_ASTRAL_SOUL); + } + if (FOCUSING & FSKILL_RAGING) { + bonus bCritical, 2*getskilllv(SKILL_RAGING); + } + if (FOCUSING & FSKILL_SPEED) { + bonus bSpeedAddRate, 1*getskilllv(SKILL_SPEED); + bonus bAspd, 2*getskilllv(SKILL_SPEED); + } + if (FOCUSING & FSKILL_RESIST_POISON) { + .@l=5*getskilllv(SKILL_RESIST_POISON); + bonus2(bResEff, Eff_Silence, .@l); + bonus2(bResEff, Eff_Poison, .@l); + bonus2(bResEff, Eff_DPoison, .@l); + bonus2(bResEff, Eff_Curse, .@l); + bonus2(bResEff, Eff_Blind, .@l); + } + if (FOCUSING & FSKILL_BRAWLING) { + if (getequipid(EQI_HAND_R) < 1) { + bonus bAtk, 10*getskilllv(SKILL_BRAWLING); + } else if (getiteminfo( + getequipid(EQI_HAND_R), ITEMINFO_SUBTYPE) == W_FIST) { + bonus bAtk, 10*getskilllv(SKILL_BRAWLING); + } + } + if (FOCUSING & FSKILL_MALLARDS_EYE) { + bonus bAtkRange, (2+getskilllv(SKILL_MALLARDS_EYE))/3; + bonus bHit, 5*getskilllv(SKILL_MALLARDS_EYE); + } + return; +} + diff --git a/npc/magic/level0-monsterinfo.txt b/npc/magic/level0-monsterinfo.txt new file mode 100644 index 00000000..0a891055 --- /dev/null +++ b/npc/magic/level0-monsterinfo.txt @@ -0,0 +1,38 @@ +// The Mana World script +// Author: Jesusalva <jesusalva@themanaworld.org> +// +// Magic Script: SKILL_MONSTERINFO (Level 1) +// School: General 1 + +function script SK_Miteyo { + .@mobId=getunitdata(@skillTarget, UDT_CLASS); + if (.@mobId > 1000) { + // Decide how much detail you get based on how much magic you have + if (getskilllv(SKILL_MAGIC) > 2) { + charcommand("@mi "+.@mobId); + } else { + .@mhp = getmonsterinfo(.@mobId, MOB_MAXHP); + // Truncate HP + if (.@mhp > 1000) + .@mhp -= .@mhp % 1000; + else if (.@mhp > 100) + .@mhp -= .@mhp % 100; + else + .@mhp -= .@mhp % 10; + // Randomize atk + .@atk = rand2(getmonsterinfo(.@mobId, MOB_ATK1), + getmonsterinfo(.@mobId, MOB_ATK2)); + // Send the obfuscated information + dispbottom l("%s - Level %d (~%s HP, ~%s ATK)", + getmonsterinfo(.@mobId, MOB_NAME), + getmonsterinfo(.@mobId, MOB_LV), + fnum(.@mhp), + fnum(.@atk)); + } + } else { + // Not a valid monster + dispbottom l("This is not a monster; I cannot use monsterinfo on it."); + } + return; +} + diff --git a/npc/magic/level0-reapercry.txt b/npc/magic/level0-reapercry.txt new file mode 100644 index 00000000..1b6f07d5 --- /dev/null +++ b/npc/magic/level0-reapercry.txt @@ -0,0 +1,228 @@ +// #reapercry +// Spell to warp to Keshlam Outskirts +// Variable: @reapercry -> Holds summon state +// +// If this was Evol2 engine, I would be able to easily use bitmasks, +// Having a custom password sequence unique per character. +// But alas, on TMWA, I can't really abuse player variables. +// So I allow you to cheat. Or not. Lemme think. Account variable... +// This is actually an old script and I'm too lazy to redo. + +// Returns true if player inside candle area +// call("alacriuspos", bitwise) + +function script alacriuspos { + @alacriusp = 0; + + // Left side + if (1 == getarg(0) && #CRYPT_PASSWORD & getarg(0)) + goto L_25_53_29_56; + if (2 == getarg(0) && #CRYPT_PASSWORD & getarg(0)) + goto L_20_47_22_51; + if (4 == getarg(0) && #CRYPT_PASSWORD & getarg(0)) + goto L_22_40_25_43; + if (8 == getarg(0) && #CRYPT_PASSWORD & getarg(0)) + goto L_29_40_32_43; + if (16 == getarg(0) && #CRYPT_PASSWORD & getarg(0)) + goto L_32_47_35_50; + if (32 == getarg(0) && #CRYPT_PASSWORD & getarg(0)) + goto L_25_53_29_56; + // Left not set + if (1 == getarg(0)) + goto L_29_40_32_43; + if (2 == getarg(0)) + goto L_32_47_35_50; + if (4 == getarg(0)) + goto L_25_53_29_56; + if (8 == getarg(0)) + goto L_20_47_22_51; + if (16 == getarg(0)) + goto L_22_40_25_43; + if (32 == getarg(0)) + goto L_29_40_32_43; + // Right side + if (64 == getarg(0) && #CRYPT_PASSWORD & getarg(0)) + goto L_49_53_53_56; + if (128 == getarg(0) && #CRYPT_PASSWORD & getarg(0)) + goto L_43_47_46_51; + if (256 == getarg(0) && #CRYPT_PASSWORD & getarg(0)) + goto L_46_40_49_43; + if (512 == getarg(0) && #CRYPT_PASSWORD & getarg(0)) + goto L_53_40_56_43; + if (1024 == getarg(0) && #CRYPT_PASSWORD & getarg(0)) + goto L_56_47_58_50; + if (2048 == getarg(0) && #CRYPT_PASSWORD & getarg(0)) + goto L_49_53_53_56; + // Right side not set + if (64 == getarg(0)) + goto L_53_40_56_43; + if (128 == getarg(0)) + goto L_56_47_58_50; + if (256 == getarg(0)) + goto L_49_53_53_56; + if (512 == getarg(0)) + goto L_43_47_46_51; + if (1024 == getarg(0)) + goto L_46_40_49_43; + if (2048 == getarg(0)) + goto L_53_40_56_43; + + // Nope, all wrong + @alacriusp = 0; + return; + +L_29_40_32_43: + @alacriusp = isin("027-8", 29, 40, 32, 43); + return; +L_22_40_25_43: + @alacriusp = isin("027-8", 22, 40, 25, 43); + return; +L_20_47_22_51: + @alacriusp = isin("027-8", 20, 47, 22, 51); + return; +L_25_53_29_56: + @alacriusp = isin("027-8", 25, 53, 29, 56); + return; +L_32_47_35_50: + @alacriusp = isin("027-8", 32, 47, 35, 50); + return; + +L_53_40_56_43: + @alacriusp = isin("027-8", 53, 40, 56, 43); + return; +L_46_40_49_43: + @alacriusp = isin("027-8", 46, 40, 49, 43); + return; +L_43_47_46_51: + @alacriusp = isin("027-8", 43, 47, 46, 51); + return; +L_49_53_53_56: + @alacriusp = isin("027-8", 49, 53, 53, 56); + return; +L_56_47_58_50: + @alacriusp = isin("027-8", 56, 47, 58, 50); + return; + +} + +function script Reapercry { + // Not in Terogan's Room + if (getmapname() != "027-8") end; + + // Terogan is asleep + if (!$@CRYPT_FIGHT3) end; + + // No password is set o.o + if (!#CRYPT_PASSWORD) end; + + // Switch the quest state + if (@reapercry == 0) + goto L_Check0; + if (@reapercry == 1) + goto L_Check1; + if (@reapercry == 2) + goto L_Check2; + if (@reapercry == 3) + goto L_Check3; + if (@reapercry == 4) + goto L_Check4; + if (@reapercry == 5) + goto L_Check5; + + // Something went wrong!! + end; + +L_Check0: + callfunc("alacriuspos", 1); + if (@alacriusp) goto L_Exec0; + callfunc("alacriuspos", 64); + if (@alacriusp) goto L_Exec0; + + @reapercry = 0; + misceffect FX_MAGIC_DARK_EXPLOSION, strcharinfo(0); + end; + +L_Exec0: + misceffect FX_FIRE_EXPLOSION, strcharinfo(0); // Hmm FIXME + @reapercry = 1; + end; + +L_Check1: + callfunc("alacriuspos", 2); + if (@alacriusp) goto L_Exec1; + callfunc("alacriuspos", 128); + if (@alacriusp) goto L_Exec1; + + @reapercry = 0; + misceffect FX_MAGIC_DARK_EXPLOSION, strcharinfo(0); + end; + +L_Exec1: + misceffect FX_FIRE_EXPLOSION, strcharinfo(0); // Hmm FIXME + @reapercry = 2; + end; + +L_Check2: + callfunc("alacriuspos", 4); + if (@alacriusp) goto L_Exec2; + callfunc("alacriuspos", 256); + if (@alacriusp) goto L_Exec2; + + @reapercry = 0; + misceffect FX_MAGIC_DARK_EXPLOSION, strcharinfo(0); + end; + +L_Exec2: + misceffect FX_FIRE_EXPLOSION, strcharinfo(0); // Hmm FIXME + @reapercry = 3; + end; + +L_Check3: + callfunc("alacriuspos", 8); + if (@alacriusp) goto L_Exec3; + callfunc("alacriuspos", 512); + if (@alacriusp) goto L_Exec3; + + @reapercry = 0; + misceffect FX_MAGIC_DARK_EXPLOSION, strcharinfo(0); + end; + +L_Exec3: + misceffect FX_FIRE_EXPLOSION, strcharinfo(0); // Hmm FIXME + @reapercry = 4; + end; + +L_Check4: + callfunc("alacriuspos", 16); + if (@alacriusp) goto L_Exec4; + callfunc("alacriuspos", 1024); + if (@alacriusp) goto L_Exec4; + + @reapercry = 0; + misceffect FX_MAGIC_DARK_EXPLOSION, strcharinfo(0); + end; + +L_Exec4: + misceffect FX_FIRE_EXPLOSION, strcharinfo(0); // Hmm FIXME + @reapercry = 5; + end; + +L_Check5: + callfunc("alacriuspos", 32); + if (@alacriusp) goto L_Exec5; + callfunc("alacriuspos", 2048); + if (@alacriusp) goto L_Exec5; + + @reapercry = 0; + misceffect FX_MAGIC_DARK_EXPLOSION, strcharinfo(0); + end; + +L_Exec5: + // This means cast sequence complete + // Maybe FX_MAGIC_BLUE_TELEPORT? (iilia's effect) + @reapercry = 0; + getexp 100000, 0; + misceffect FX_MAGIC_TELEPORT, strcharinfo(0); + warp "099-7", 75, 36; + end; +} diff --git a/npc/magic/level0-wand.txt b/npc/magic/level0-wand.txt new file mode 100644 index 00000000..1c3d7b2b --- /dev/null +++ b/npc/magic/level0-wand.txt @@ -0,0 +1,25 @@ +// The Mana World script +// Author: Jesusalva <jesusalva@themanaworld.org> +// +// Magic Script: SKILL_CONFRINGO (Level 1) +// School: General 0 + +function script SK_Confringo { + // Additional checks + if (QL_MORGAN == 2) + set QL_MORGAN, 3; + // Effective magic code + .@PW=90+(7*@skillLv); + .@dmg=AdjustSpellpower(.@PW); + .@max=(1+getskilllv(SKILL_MAGIC))*100; + // Noobs adjustment + if (.@dmg < readparam(bInt)) + .@dmg=rand2(.@dmg, readparam(bInt)); + // Pro adjustment + if (.@dmg > .@max) + .@dmg = .@max + ((.@dmg - .@max) * 30 / 100); + harm(@skillTarget, .@dmg, HARM_MAGI, Ele_Neutral); + return; +} + + diff --git a/npc/magic/level1-aggravate.txt b/npc/magic/level1-aggravate.txt new file mode 100644 index 00000000..c97d8b47 --- /dev/null +++ b/npc/magic/level1-aggravate.txt @@ -0,0 +1,16 @@ +// The Mana World script +// Author: Jesusalva <jesusalva@themanaworld.org> +// +// Magic Script: EVOL_AREA_PROVOKE (Level 1) +// School: Nature 1 + +function script SK_Itenplz { + /* + if (@skillTargetX && @skillTargetY) + massprovoke(1+@skillLv, getmap(), @skillTargetX, @skillTargetY); + else + */ + massprovoke(1+@skillLv); + return; +} + diff --git a/npc/magic/level1-experience.txt b/npc/magic/level1-experience.txt new file mode 100644 index 00000000..7435fb71 --- /dev/null +++ b/npc/magic/level1-experience.txt @@ -0,0 +1,55 @@ +// The Mana World script +// Author: Jesusalva <jesusalva@themanaworld.org> +// +// Magic Script: SKILL_ABIZIT (Level 1) +// School: General 1 + +// ShowAbizit({dialog=true}) +function script ShowAbizit { + .@dial=getarg(0, true); + if (.@dial) + mesn l("Current Magic Control"); + + switch (abizit()) { + case 10: + mescordialog l("Magic flows naturally from you, readily and with ease. You feel in perfect control of your magic."), 3, .@dial; + break; + case 9: + mescordialog l("You feel in almost perfect control of your magic."), 2, .@dial; + break; + case 8: + mescordialog l("You feel that you have very good control of your magic."), 2, .@dial; + break; + case 7: + mescordialog l("You feel quite in control of your magic."), 4, .@dial; + break; + case 6: + mescordialog l("You feel mostly in control of your magic."), 4, .@dial; + break; + case 5: + mescordialog l("You feel somewhat in control of your magic."), 7, .@dial; + break; + case 4: + mescordialog l("You feel you still have a few difficulties in controlling your magic."), 7, .@dial; + break; + case 3: + mescordialog l("Trying to control your magic is still rather troublesome."), 6, .@dial; + break; + case 2: + mescordialog l("You feel that you have only the bare minimum of control over your magic."), 6, .@dial; + break; + case 1: + mescordialog l("You feel quite overwhelmed by your magic, but are beginning to see patterns."), 1, .@dial; + break; + case 0: + mescordialog l("You feel completely overwhelmed by your magic."), 1, .@dial; + break; + } + return; +} + +function script SK_Abizit { + ShowAbizit(false); + return; +} + diff --git a/npc/magic/level1-flare-dart.txt b/npc/magic/level1-flare-dart.txt new file mode 100644 index 00000000..2446fa9c --- /dev/null +++ b/npc/magic/level1-flare-dart.txt @@ -0,0 +1,23 @@ +// The Mana World script +// Author: Jesusalva <jesusalva@themanaworld.org> +// +// Magic Script: SKILL_FLAR (Level 1) +// School: War 1 + +function script SK_Flar { + // Charge code, item check is in skill_db.conf (FIXME) + mcharge(SulphurPowder, SKILL_MAGIC_WAR, 1); + // Effective magic code + .@PW=70+(5*@skillLv); + // Weather modifiers + if ("#WeatherCore"::weather(MASK_RAIN)) + .@PW-=10; + if ("#WeatherCore"::weather(MASK_SANDSTORM)) + .@PW+=10; + // Calculate real damage + .@dmg=AdjustSpellpower(.@PW); + harm(@skillTarget, .@dmg, HARM_MAGI, Ele_Fire); + GetManaExp(@skillId, 1); + return; +} + diff --git a/npc/magic/level1-grow-plants.txt b/npc/magic/level1-grow-plants.txt new file mode 100644 index 00000000..66e105b4 --- /dev/null +++ b/npc/magic/level1-grow-plants.txt @@ -0,0 +1,29 @@ +// The Mana World script +// Author: Jesusalva <jesusalva@themanaworld.org> +// +// Magic Script: Multiple (Level 1) +// School: Nature 1 + +function script SK_GrowPlants { + // Setup + switch (@skillId) { + case SKILL_MODRIPHOO: + .@it = AlizarinHerb; .@mobId = AlizarinPlant; break; + case SKILL_MODRISUMP: + .@it = CobaltHerb; .@mobId = CobaltPlant; break; + case SKILL_MODRIYIKAM: + .@it = GambogeHerb; .@mobId = GambogePlant; break; + case SKILL_MODRILAX: + .@it = MauveHerb; .@mobId = MauvePlant; break; + default: return; + } + if (getarg(0, true)) { + // Consume reagents + delitem Root, 1; + delitem .@it, 1; + } + // Continue but with a special flag + SK_summon(.@mobId, 2, 1, false); + return; +} + diff --git a/npc/magic/level1-lesser-heal.txt b/npc/magic/level1-lesser-heal.txt new file mode 100644 index 00000000..b65f9625 --- /dev/null +++ b/npc/magic/level1-lesser-heal.txt @@ -0,0 +1,63 @@ +// The Mana World script +// Author: Jesusalva <jesusalva@themanaworld.org> +// +// Magic Script: SKILL_LUM (Level 1) +// School: Life 1 + +function script SK_Lum { + // In some cases it is... aborted + if (getunittype(@skillTarget) == UNITTYPE_PC) { + .@me=getcharid(3); + .@ok=true; + attachrid(@skillTarget); + // Kill the GM Event + if (isequipped(MagicGMTopHat)) + .@ok=false; + // Ailments cannot be bypassed nor healed until Lv 3 Life Magic + if (getstatus(SC_BLOODING) || + getstatus(SC_HALT_REGENERATION) || + getstatus(SC_CURSE)) + .@ok=false; + if (getstatus(SC_POISON) && !getstatus(SC_SLOWPOISON)) + .@ok=false; + if (getstatus(SC_DPOISON) && !getstatus(SC_SLOWPOISON)) + .@ok=false; + // Already dead + if (Hp < 1) + .@ok=false; + // Finished + .@limit=MaxHp-Hp; + detachrid(); + attachrid(.@me); + if (!.@ok) return; + } else { + if (getunitdata(@skillTarget, UDT_HP) < 1) return; + .@limit=getunitdata(@skillTarget, UDT_MAXHP)- + getunitdata(@skillTarget, UDT_HP); + } + + // No need for healing? Otherwise, take reagent + if (.@limit <= 0) return; + delitem Lifestone, 1; + + // Real healing happens here + .@PW=60+(10*@skillLv); + .@dmg=AdjustSpellpower(.@PW); + sc_start(SC_M_LIFEPOTION, 5000, 1+max(0, .@dmg/5), 10000, + SCFLAG_NOAVOID|SCFLAG_FIXEDTICK|SCFLAG_FIXEDRATE, @skillTarget); + specialeffect(FX_MAGIC_WHITE, AREA, @skillTarget); + if (@skillTarget != getcharid(3)) + specialeffect(FX_MAGIC_WHITE, AREA, getcharid(3)); + + // Specifics + if (getskilllv(SKILL_MAGIC_DARK) >= 1) + SC_Bonus(2, SC_HALT_REGENERATION, 1); + + // Gives EXP according to how much you healed + if (@skillTarget != getcharid(3)) + setq2(MagicQuest_Healing, getq2(MagicQuest_Healing)+1); + getexp min(.@dmg, .@limit)*getskilllv(SKILL_MAGIC_LIFE), .@PW/10; + GetManaExp(@skillId, 1); + return; +} + diff --git a/npc/magic/level1-magic-blade.txt b/npc/magic/level1-magic-blade.txt new file mode 100644 index 00000000..ae98d4c4 --- /dev/null +++ b/npc/magic/level1-magic-blade.txt @@ -0,0 +1,27 @@ +// The Mana World script +// Author: Jesusalva <jesusalva@themanaworld.org> +// +// Magic Script: SKILL_CHIZA (Level 1) +// School: War 1 + +function script SK_Chiza { + // Charge code, item check is here =( FIXME + if (countitem(Dagger)) { + mcharge(Dagger, SKILL_MAGIC_WAR, 8); .@PW=100; + } else if (countitem(SharpKnife)) { + mcharge(SharpKnife, SKILL_MAGIC_WAR, 6); .@PW=95; + } else if (countitem(Knife)) { + mcharge(Knife, SKILL_MAGIC_WAR, 4); .@PW=90; + } else { + dispbottom b("Chiza: ")+l("You need a Dagger, Sharp Knife or Knife to use!"); + return; + } + .@PW+=(10*@skillLv); + // Effective magic code + .@dmg=(AdjustSpellpower(.@PW)+AdjustAttackpower(.@PW))/2; + harm(@skillTarget, .@dmg, HARM_PHYS, Ele_Neutral); + GetManaExp(@skillId, 1); + return; +} + + diff --git a/npc/magic/level1-summon-maggots.txt b/npc/magic/level1-summon-maggots.txt new file mode 100644 index 00000000..7ca9f74d --- /dev/null +++ b/npc/magic/level1-summon-maggots.txt @@ -0,0 +1,15 @@ +// The Mana World script +// Author: Jesusalva <jesusalva@themanaworld.org> +// +// Magic Script: SKILL_KALMURK (Level 1) +// School: Astral 1 + +function script SK_Kalmurk { + delitem Root, 1; + delitem .@it, 1; + specialeffect(FX_MAGIC_MAGGOT_CAST, AREA, getcharid(3)); + sleep2(cap_value(5400-AdjustSpellpower(100)-@skillLv*400, 500, 5000)); + SK_summon(Maggot, 2, 1); + return; +} + diff --git a/npc/magic/level1-transmutations.txt b/npc/magic/level1-transmutations.txt new file mode 100644 index 00000000..88e916fc --- /dev/null +++ b/npc/magic/level1-transmutations.txt @@ -0,0 +1,95 @@ +// The Mana World script +// Author: Jesusalva <jesusalva@themanaworld.org> +// +// Magic Script: MULTIPLE (Level 1) +// School: Transmutation * + +function script SK_Transmute { + // Setup + switch (@skillId) { + case SKILL_PARUM: + .@prize = MoubooFigurine; .@pc = 1; + .@mexp = 1; .@fx = FX_MAGIC_WOOD_CAST; + setarray .@component, RawLog; + setarray .@co_amount, 1; + setarray .@failure, Iten, WarpedLog, WarpedLog; + break; + case SKILL_KULARZUFRILL: + .@prize = Arrow; .@pc = AdjustSpellpower(40+@skillLv*2); + .@mexp = 2; .@fx = FX_MAGIC_ARROW_CAST; + setarray .@component, RawLog; + setarray .@co_amount, 1; + setarray .@failure, WarpedLog, WarpedLog; + break; + case SKILL_ZUKMINBIRF: + .@prize = IronPowder; .@pc = 1+AdjustSpellpower(@skillLv*5); + .@mexp = 2; .@fx = FX_MAGIC_IRON_CAST; + setarray .@component, IronOre; + setarray .@co_amount, 1; + setarray .@failure, Iten, IronOre, IronOre; + break; + case SKILL_PATMUPLOO: + .@prize = CottonShirt; .@pc = 1; + .@mexp = 2; .@fx = FX_MAGIC_SHIRT_CAST; + setarray .@component, CottonCloth; + setarray .@co_amount, 5; + setarray .@failure, CottonCloth, CottonCloth; + break; + case SKILL_PATVILOREE: + .@prize = ShortTankTop; .@pc = 1; + .@mexp = 2; .@fx = FX_MAGIC_SHIRT_CAST; + setarray .@component, CottonCloth; + setarray .@co_amount, 3; + setarray .@failure, CottonCloth, CottonCloth; + break; + case SKILL_PATLOREE: + .@prize = TankTop; .@pc = 1; + .@mexp = 2; .@fx = FX_MAGIC_SHIRT_CAST; + setarray .@component, CottonCloth; + setarray .@co_amount, 4; + setarray .@failure, CottonCloth, CottonCloth; + break; + case SKILL_GOLE: + .@prize = SulphurPowder; .@pc = 1+AdjustSpellpower(@skillLv*20); + .@mexp = 1; .@fx = FX_MAGIC_SULPHUR_CAST; + setarray .@component, PileOfAsh; + setarray .@co_amount, 1; + setarray .@failure, PileOfAsh, PileOfAsh; + break; + case SKILL_MANPAHIL: + .@prize = Lifestone; .@pc = 10; + .@mexp = 2; .@fx = FX_MAGIC_STONE_CAST; + setarray .@component, BugLeg, MaggotSlime, MauveHerb, AlizarinHerb, CobaltHerb, GambogeHerb; + setarray .@co_amount, 1, 1, 1, 1, 1, 1; + setarray .@failure, Lifestone, Lifestone; + break; + default: return; + } + // Check for items + for (.@i=0; .@i < getarraysize(.@component); .@i++) { + if (countitem(.@component[.@i]) < .@co_amount[.@i]) { + dispbottom l("You do not have enough %s (min %d)", + getitemname(.@component[.@i]), .@co_amount[.@i]); + return; + } + } + // Delete reagents + inventoryplace Iten, 1, .@prize, .@pc; + for (.@i=0; .@i < getarraysize(.@component); .@i++) { + delitem(.@component[.@i], .@co_amount[.@i]); + } + // Effect and EXP + specialeffect(.@fx, AREA, getcharid(3)); + GetManaExp(@skillId, .@mexp); + // The chances of success are based on magic exp, abizit and skill level + .@rand100 = abizit()*10 + cap_value(MAGIC_EXP/100, 0, 50) + (@skillLv*5); + if (.@rand100 > rand2(100)) { + getitem .@prize, .@pc; + } else { + dispbottom l("Your magic takes a mind of its own!"); + getitem any_of(.@failure), 1; + } + return; +} + + diff --git a/npc/magic/level2-arrow-hail.txt b/npc/magic/level2-arrow-hail.txt new file mode 100644 index 00000000..217f7fb0 --- /dev/null +++ b/npc/magic/level2-arrow-hail.txt @@ -0,0 +1,44 @@ +// The Mana World script +// Author: Jesusalva <jesusalva@themanaworld.org> +// +// Magic Script: SKILL_FRILLYAR (Level 1) +// School: War 2 + +function script SK_Frillyar { + // Additional check for ammo + .@it=getequipid(EQI_AMMO); + if (.@it < 1) { + dispbottom l("Please equip your ammo first!"); + return; + } + if (countitem(.@it) < 15) { + dispbottom l("You need at least %d %s to use this spell!", + 15, getitemname(.@it)); + return; + } + // Delete items + delitem(SulphurPowder, 1); + delitem(.@it, 15); + // Proccess attack power + .@RG=4+(@skillLv/2); + .@PW=90+(10*@skillLv); + .@PW+=getiteminfo(.@it, ITEMINFO_ATK); + // Weather modifiers + if ("#WeatherCore"::weather(MASK_RAIN)) + .@PW-=10; + if ("#WeatherCore"::weather(MASK_SANDSTORM)) + .@PW-=10; + if ("#WeatherCore"::weather(MASK_SNOW)) + .@PW-=10; + // Effective magic code + .@dmg=AdjustSpellpower(.@PW); + .@dmg+=getiteminfo(.@it, ITEMINFO_ATK); + specialeffect(FX_MAGIC_AHAIL_CAST, AREA, @skillTarget); + areaharm(@skillTarget, .@RG, .@dmg, HARM_PHYS, Ele_Neutral); + harm(@skillTarget, .@dmg/20, HARM_MAGI, Ele_Holy); + specialeffect(FX_ARROW_HAIL, AREA, @skillTarget); + GetManaExp(@skillId, 2); + return; +} + + diff --git a/npc/magic/level2-happy-curse.txt b/npc/magic/level2-happy-curse.txt new file mode 100644 index 00000000..1e1096a1 --- /dev/null +++ b/npc/magic/level2-happy-curse.txt @@ -0,0 +1,32 @@ +// The Mana World script +// Author: Jesusalva <jesusalva@themanaworld.org> +// +// Magic Script: SKILL_JOYPLIM (Level 1) +// School: General 2 + +function script SK_Joyplim { + if (getarg(0, true)) + delitem GingerBreadMan, 1; + + .@b=(BL_PC | BL_PET | BL_MER | BL_HOM); // | BL_MOB + .@r=3+cap_value(getskilllv(SKILL_MAGIC)+(@skillLv/2), 1, 12); // Your radius + .@s=AdjustSpellpower(100); // Your magical stamina + .@c=cap_value(11-@skillLv, 1, 10)*2; // MATK stamina cost per char + .@e=(getskilllv(SKILL_MAGIC_DARK) ? E_EVIL : E_HAPPY); // Emote + + getmapxy(.@m$, .@x, .@y, 0); + + // TODO: Maybe put this loop in a timer, etc? But... Do we want to? + .@c=getunits(.@b, .@mbs, false, .@m$, .@x-.@r, .@y-.@r, .@x+.@r, .@y+.@r); + for (.@i = 0; .@i < .@c; .@i++) { + unitemote(.@mbs[.@i], E_HAPPY); + // Stamina cost + .@s-=.@c; + if (.@s < 0) + break; + } + specialeffect(FX_MAGIC_JOY_CAST, AREA, getcharid(3)); + GetManaExp(@skillId, 2); + return; +} + diff --git a/npc/magic/level2-lay-on-hands.txt b/npc/magic/level2-lay-on-hands.txt new file mode 100644 index 00000000..1d515324 --- /dev/null +++ b/npc/magic/level2-lay-on-hands.txt @@ -0,0 +1,71 @@ +// The Mana World script +// Author: Jesusalva <jesusalva@themanaworld.org> +// +// Magic Script: SKILL_INMA (Level 1) +// School: Life 2 + +function script SK_Inma { + // FIXME: #inma Mouboo + // In some cases it is... aborted + if (getunittype(@skillTarget) == UNITTYPE_PC) { + .@me=getcharid(3); + .@ok=true; + attachrid(@skillTarget); + // TODO: detect if is a bot... + // FIXME: 099-4 and 099-5 special rules + // Kill the GM Event + if (isequipped(MagicGMTopHat)) + .@ok=false; + // Ailments which prevent inma from working + if (getstatus(SC_BLOODING) || + getstatus(SC_HALT_REGENERATION) || + getstatus(SC_CURSE)) + .@ok=false; + if (getstatus(SC_POISON) && !getstatus(SC_SLOWPOISON)) + .@ok=false; + if (getstatus(SC_DPOISON) && !getstatus(SC_SLOWPOISON)) + .@ok=false; + // Already dead + if (Hp < 1) + .@ok=false; + // Finished + .@limit=MaxHp-Hp; + detachrid(); + attachrid(.@me); + if (!.@ok) return; + } else { + if (getunitdata(@skillTarget, UDT_HP) < 1) return; + .@limit=getunitdata(@skillTarget, UDT_MAXHP)- + getunitdata(@skillTarget, UDT_HP); + } + if (@skillTarget == getcharid(3)) return; // No self casting + if (isequipped(MagicGMTopHat)) return; // Kill the GM event + if (.@limit <= 0) return; // No need for healing + // Apply effects + .@PW=60+(20*@skillLv); + .@dmg=AdjustSpellpower(.@PW); + + // Capped to what you need or your own health - the smallest of them + .@dmg = min(.@dmg, .@limit, Hp); + + // Pay with 20% of your healing total + heal -(.@dmg/5), 0; + + // Heal the target instantly + harm(@skillTarget, -(.@dmg), HARM_MISC); + specialeffect(FX_MAGIC_WHITE, AREA, @skillTarget); + specialeffect(FX_MAGIC_WHITE, AREA, getcharid(3)); + + // Specifics + if (getskilllv(SKILL_MAGIC_DARK) >= 2) + SC_Bonus(10, SC_HALT_REGENERATION, 1); + else + SC_Bonus(5, SC_HALT_REGENERATION, 1); + + // Gives EXP according to how much you healed + setq2(MagicQuest_Healing, getq2(MagicQuest_Healing)+1); + getexp .@dmg*getskilllv(SKILL_MAGIC_LIFE), .@PW/10; + GetManaExp(@skillId, 2); + return; +} + diff --git a/npc/magic/level2-lightning-strike.txt b/npc/magic/level2-lightning-strike.txt new file mode 100644 index 00000000..97692d3e --- /dev/null +++ b/npc/magic/level2-lightning-strike.txt @@ -0,0 +1,24 @@ +// The Mana World script +// Author: Jesusalva <jesusalva@themanaworld.org> +// +// Magic Script: SKILL_INGRAV (Level 1) +// School: War 2 + +function script SK_Ingrav { + // This one time, effects will come before + specialeffect(FX_MAGIC_BOLT_CAST, AREA, getcharid(3)); + specialeffect(FX_LIGHTNING1+rand2(3), AREA, @skillTarget); + // Charge code, item check is in skill_db.conf (FIXME) + mcharge(IronPowder, SKILL_MAGIC_WAR, 1); + .@PW=110+(20*@skillLv); + // Weather modifiers + .@dmg=AdjustSpellpower(.@PW); + if ("#WeatherCore"::weather(MASK_RAIN)) + harm(getcharid(3), .@dmg*2/3, HARM_MAGI, Ele_Nature); + // Effective magic code + harm(@skillTarget, .@dmg, HARM_MAGI, Ele_Nature); + GetManaExp(@skillId, 2); + return; +} + + diff --git a/npc/magic/level2-magic-knuckles.txt b/npc/magic/level2-magic-knuckles.txt new file mode 100644 index 00000000..d14c8981 --- /dev/null +++ b/npc/magic/level2-magic-knuckles.txt @@ -0,0 +1,19 @@ +// The Mana World script +// Author: Jesusalva <jesusalva@themanaworld.org> +// +// Magic Script: SKILL_UPMARMU (Level 1) +// School: War 2 + +function script SK_Uparmu { + // Charge code, item check is in skill_db.conf (FIXME) + mcharge(Beer, SKILL_MAGIC_WAR, 5); + .@PW=100+(10*@skillLv); + // TODO: What's the diff from Chiza? + // Effective magic code + .@dmg=AdjustSpellpower(.@PW); + harm(@skillTarget, .@dmg, HARM_PHYS, Ele_Neutral); + GetManaExp(@skillId, 2); + return; +} + + diff --git a/npc/magic/level2-protect.txt b/npc/magic/level2-protect.txt new file mode 100644 index 00000000..36e25b45 --- /dev/null +++ b/npc/magic/level2-protect.txt @@ -0,0 +1,51 @@ +// The Mana World script +// Author: Jesusalva <jesusalva@themanaworld.org> +// +// Magic Script: Betsanc and Asorm (Level 1) +// School: Nature/Astral 2 + +function script SK_Betsanc { + // party-guild filter + if (!filter_sameguildorparty(@skillTarget)) { + dispbottom b("Betsanc: ")+l("Skill can only be cast on party or guild members!"); + return; + } + // no GM Hat/Bots? Not needed due filter? + delitem HardSpike, 1; + // Same duration as Kaflosh + .@PW=80+(20*@skillLv); + .@dmg=AdjustSpellpower(.@PW); + .@time=5+.@dmg/11; + .@PX=10+cap_value(.@dmg/33, 0, 20); + // SC, Time, DEF+, ASPD- + sc_start2(SC_PHYSICAL_SHIELD, .@time*1000, .@PX*2, .@PX, 10000, + SCFLAG_NOAVOID|SCFLAG_FIXEDTICK|SCFLAG_FIXEDRATE, @skillTarget); + specialeffect FX_MAGIC_SHIELD_CAST, AREA, @skillTarget; + GetManaExp(@skillId, 2); + return; +} + +function script SK_Asorm { + // party-guild filter + if (!filter_sameguildorparty(@skillTarget)) { + dispbottom b("Betsanc: ")+l("Skill can only be cast on party or guild members!"); + return; + } + // no GM Hat/Bots? Not needed due filter? + delitem SmallMushroom, 1; + // Same duration as Kaflosh + .@PW=80+(20*@skillLv); + .@dmg=AdjustSpellpower(.@PW); + .@time=5+.@dmg/11; + .@PX=10+cap_value(.@dmg/33, 0, 20); + // SC_STONESKIN(??, def, mdef); Usually for mobs. Skill NPC_ANTIMAGIC + // SC_FREYJASCROLL(MDEF, PerfectFlee) + // SC_MDEFSET(MDEF) + // SC, Time, MDEF+ + sc_start(SC_MDEFSET, .@time*1000, .@PX*2, 10000, + SCFLAG_NOAVOID|SCFLAG_FIXEDTICK|SCFLAG_FIXEDRATE, @skillTarget); + specialeffect FX_MAGIC_BARRIER_CAST, AREA, @skillTarget; + GetManaExp(@skillId, 2); + return; +} + diff --git a/npc/magic/level2-rain.txt b/npc/magic/level2-rain.txt new file mode 100644 index 00000000..30171c06 --- /dev/null +++ b/npc/magic/level2-rain.txt @@ -0,0 +1,55 @@ +// The Mana World script +// Author: Jesusalva <jesusalva@themanaworld.org> +// +// Magic Script: SKILL_KAFLOSH (Level 1) +// School: Nature 2 + +function script SK_Kaflosh { + .@m$=getmap(); + .@cl="#WeatherCore"::climate(.@m$); + + // Bad Climate + if (.@cl == CLIMATE_NONE) { + dispbottom l("It was impossible to conjure rain clouds on this map."); + return; + } + + // Techinically not needed + .@rain="#WeatherCore"::weather(MASK_RAIN); + if (.@rain) { + dispbottom l("It is already raining!"); + return; + } + + // From now on, you'll have the cost paid and the MEXP deposited + delitem BottleOfWater, 1; + GetManaExp(@skillId, 2); + + // Adjusted MATK will determine rain duration (11 ATK = 1s) + .@PW=80+(20*@skillLv); + .@dmg=AdjustSpellpower(.@PW); + .@time=.@dmg/11; + //debugmes "KAFLOSH: Damage %d Time %d Climate %d", .@dmg, .@time, .@cl; + .@time+=getskilllv(SKILL_MAGIC_NATURE)-2; // +1 second per nature magic lv + + // Adverse climate (eg. desert and icelands) will cut this to 1/3 + if (.@cl != CLIMATE_MODERATE) + .@time=.@time/3; + + // Rain must last at least 5 seconds or the clouds won't even gather + if (.@time < 5) { + dispbottom l("You do not have suffice magic power to make rain."); + return; + } + + // Invoke the rain clouds; Everything else should work out of the box + // The builtin checks are not necessary in this case =D + // But would be for a sandstorm or snowstorm. + "#WeatherCore"::weather_override(MASK_RAIN, .@time, .@m$, true); + + // Eventually, a quest or another will depend on Kaflosh, so + if (isin("006-1", 82, 59, 14)) + callfunc "QuestTreeTrigger", 1; + return; +} + diff --git a/npc/magic/level2-shear.txt b/npc/magic/level2-shear.txt new file mode 100644 index 00000000..f848b36d --- /dev/null +++ b/npc/magic/level2-shear.txt @@ -0,0 +1,54 @@ +// The Mana World script +// Author: Jesusalva <jesusalva@themanaworld.org> +// +// Magic Script: SKILL_CHIPCHIP (Level 1) +// School: Nature 2 + +function script SK_Shear { + .@mobGD=getarg(0, @skillTarget); + if (.@mobGD <= 0) + return; + + // We only want monsters + if (getunittype(.@mobGD) != UNITTYPE_MOB) { + dispbottom l("This skill can only be used on monsters!"); + return; + } + + // Global data + setarray .@valid, Fluffy, EasterFluffy, SpikyMushroom, Mouboo, MauvePlant, CobaltPlant, GambogePlant, AlizarinPlant, Silkworm, Pinkie; + setarray .@prize, WhiteFur, WhiteFur, HardSpike, CottonCloth, MauveHerb, CoblatHerb, GambogeHerb, AlizarinHerb, SilkCocoon, PinkAntenna; + setarray .@score, 300, 300, 250, 175, 700, 700, 700, 700, 300, 180; + + // Specific data + .@mobID=getunitdata(.@mobGD, UDT_CLASS); + .@matk=AdjustSpellpower(40+(10*@skillLv)); + .@idx=array_find(.@valid, .@mobID); + + // Invalid target + if (.@idx < 0) return; + + // Not yet sheared + if (array_rfind(@shear, .@mobGD) < 0) { + array_push(@shear, @mobGD); + if (.@matk > .@score[.@idx]) + getitem .@prize[.@idx], 1; + } + + // Sagratha bonus + if (.@mobId == Fluffy || .@mobId == Mouboo || .@mobId == Pinkie) + QuestSagathaHappy(any(true, true, false)); + + // Special effect + specialeffect(FX_MAGIC_SHEAR_CAST, AREA, getcharid(3)); + specialeffect(FX_MAGIC_SHEAR_CAST, AREA, .@mobGD); + + // Truncate. + // We're saving the GID so it must be "big enough" + // But not too big so rfind() is not expensive + if (getarraysize(@study) > 99) { + deletearray(@study, 30); + } + return; +} + diff --git a/npc/magic/level2-summon-monsters.txt b/npc/magic/level2-summon-monsters.txt new file mode 100644 index 00000000..9c28e639 --- /dev/null +++ b/npc/magic/level2-summon-monsters.txt @@ -0,0 +1,53 @@ +// The Mana World script +// Author: Jesusalva <jesusalva@themanaworld.org> +// +// Magic Script: Multiple (Level 1) +// School: Astral/Dark 2 + +// SK_SummonLv2() +function script SK_SummonLv2 { + // Setup + switch (@skillId) { + case SKILL_KALAKARENK: + .@it = WhiteFur; .@mobId = Fluffy; .@am = 3; .@cl = Root; + .@fx1 = FX_MAGIC_FLUFFY_CAST; .@fx2 = FX_MAGIC_FLUFFY_SPAWN; break; + case SKILL_KALBOO: + .@it = MoubooFigurine; .@mobId = Mouboo; .@am = 4; .@cl = Root; + .@fx1 = FX_MAGIC_MOUBOO_CAST; .@fx2 = FX_MAGIC_MOUBOO_SPAWN; break; + case SKILL_KALGINA: + .@it = PinkAntenna; .@mobId = Pinkie; .@am = 2; .@cl = Root; + .@fx1 = FX_MAGIC_PINKY_CAST; .@fx2 = FX_MAGIC_PINKY_SPAWN; break; + case SKILL_KALRENK: + .@it = HardSpike; .@mobId = SpikyMushroom; .@am = 2; .@cl = Root; + .@fx1 = FX_MAGIC_SPIKY_CAST; .@fx2 = FX_MAGIC_SPIKY_SPAWN; break; + + // Should non-astral magic be here? + case SKILL_HALHISS: + .@it = SnakeEgg; .@mobId = Snake; .@am = 4; .@cl = DarkCrystal; + .@fx1 = FX_MAGIC_SNAKE_CAST; .@fx2 = FX_MAGIC_SNAKE_SPAWN; break; + case SKILL_HELORP: + .@it = SmallMushroom; .@am = 3; .@cl = DarkCrystal; + .@mobId = any(WickedMushroom, WickedMushroom, WickedMushroom, + WickedMushroom, WickedMushroom, WickedMushroom, + EvilMushroom, Moonshroom, Moonshroom, Moonshroom); + .@fx1 = FX_MAGIC_WICKED_CAST; .@fx2 = FX_MAGIC_WICKED_SPAWN; break; + + default: return; + } + // Consume reagents + delitem .@cl, 1; + delitem .@it, 1; + // Estimate the cast time + if (.@cl == Root) + .@ct = 400+rand2(1001-getskilllv(MAGIC_SKILL_ASTRAL)*100); + else if (.@cl == DarkCrystal) + .@ct = 400+rand2(1001-getskilllv(MAGIC_SKILL_DARK)*100); + // Summon the monsters (or fail trying to) + specialeffect(.@fx1, AREA, getcharid(3)); + sleep2(.@ct); + SK_summon(.@mobId, .@am, 2); + specialeffect(.@fx2, AREA, getcharid(3)); + return; +} + + diff --git a/npc/magic/level2-toxic-dart.txt b/npc/magic/level2-toxic-dart.txt new file mode 100644 index 00000000..df21b89c --- /dev/null +++ b/npc/magic/level2-toxic-dart.txt @@ -0,0 +1,23 @@ +// The Mana World script +// Author: Jesusalva <jesusalva@themanaworld.org> +// +// Magic Script: SKILL_PHLEX (Level 1) +// School: Dark 2 + +function script SK_Phlex { + // Charge code, item check is in skill_db.conf (FIXME) + mcharge(Root, SKILL_MAGIC_DARK, 1); + .@PW=100+(10*@skillLv); + // Effective magic code + .@dmg=AdjustSpellpower(.@PW); + harm(@skillTarget, .@dmg, HARM_MAGI, Ele_Dark); + // May inflict poison + .@sc=(getskilllv(SKILL_MAGIC_DARK) > 3 ? SC_DPOISON : SC_POISON); + .@time=(1+.@dmg/33)*1000; + .@cth=1+rand2(.@time)/15; + sc_start .@sc, .@time, 1, .@cth, SCFLAG_NONE, @skillTarget; + GetManaExp(@skillId, 2); + return; +} + + |