// TMW2 script // Author: Jesusalva // // Magic Script Core Functions // // Used for our pseudo-magic. // These are only helpers, you can add more restrictions and effects freely. // Important Variables: // MAGIC_EXP // Current mana magic experience // LAST_SKILL // Last Mana Skill used // MAGIC_LVL // Maximum tier of usable magic, capped by Mana Stone // 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; .@dmg=calcdmg(.@src, .@target, .@type); // Calculation FIX if (.@type == HARM_MAGI) { .@dmg*=2; .@power+=(readparam2(bInt)/2); } // Abizit Influence (80%~130% at best, worst shot at perfect ctrl is 105%) .@dmg = .@dmg * (80 + abizit() * rand2(5,10)) / 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); .@bonus=rand2(0,getskilllv(TMW2_SAGE)*3/2); if (LAST_SKILL == .@sk) { .@pt=limit(0, (.@pt+.@bonus)/3, 1); .@bonus=0; } else { // 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_RP+=1; // Magic RP is gained by switching skills often } // Update Magic EXP MAGIC_EXP=MAGIC_EXP+.@pt+.@bonus; return; } // DEPRECATED: Please do not use in newer scripts. // It is for Transmigration skill only (@sk-trans needs it) // SkillID, Mana{, MP per level} function script MagicCheck { // PRE EXECUTION // Load Variables .@sk=getarg(0); .@mp=getarg(1); .@amp=getarg(2,0); // Check Skill if (getskilllv(.@sk) < 1) return 0; // Load mana cost .@mp=.@mp+getskilllv(.@sk)*.@amp-.@amp; // Check mana if (readparam(Sp) < .@mp) { dispbottom l("Insufficient mana: @@/@@.", readparam(Sp), .@mp); return 0; } // Apply mana cost heal 0, 0-.@mp; return 1; } // SkillID, MobID{, SkillLevelPerMob=2{, Level Override}} function script SummonMagic { .@sk=getarg(0); .@id=getarg(1); .@adj=getarg(2,2); .@lv=getarg(3,getskilllv(.@sk)); if (.@adj < 1) { debugmes "\033[31mInvalid MobPerSkillLevel for SummonMagic (.@adj): "+.@adj+"\033[0m"; dispbottom l("Invalid parameter specified, blame saulc."); end; } // 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=rand(35,50)+.@lv*10; // Abizit makes lifetime vary (like AdjustSpellpower) .@lifetime = .@lifetime * (80 + abizit() * rand2(5,10)) / 100; if (isequippedcnt(AegisShield)) .@lifetime = .@lifetime * 5 / 2; .@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 * (80 + abizit() * rand2(5,10)) / 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; } // 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; } // mescordialog(text, color, {dialog=1}) function script mescordialog { if (getarg(2, true)) mesc getarg(0), getarg(1); else dispbottom col(getarg(0), getarg(1)); return; } // ShowAbizit({dialog=1}) function script ShowAbizit { .@dial=getarg(0, true); if (.@dial) mesn l("Current Magic Control"); .@val=MAGIC_EXP+rand(-MAGIC_LVL*5, MAGIC_LVL*5); .@base=((MAGIC_LVL*2)**3); if (.@val > .@base*5) mescordialog l("You are perfectly in control of your magic."), 3, .@dial; else if (.@val > .@base*4) mescordialog l("You are mostly in control of your magic."), 2, .@dial; else if (.@val > .@base*3) mescordialog l("You are somewhat in control of your magic."), 4, .@dial; else if (.@val > .@base*2) mescordialog l("Your magic is more powerful than you, but you can control."), 7, .@dial; else if (.@val > .@base) mescordialog l("You still are overwhelmed by your magic."), 6, .@dial; else mescordialog l("You are completly overwhelmed by your magic."), 1, .@dial; return; } // alignment_cansummon() function script alignment_cansummon { if (alignment() < 0 && !isequippedcnt(AegisShield)) { if (!@hatesummon) { dispbottom l("Nature itself express hate against you!"); getmapxy(.@m$, .@x, .@y, 0); .@opo=monster(.@m$, .@x, .@y, "Failed summon", .@mob, 1); unitattack(.@opo, getcharid(3)); @hatesummon=true; } return false; } return true; } // SK_summon(ID, amount, mexp) function script SK_summon { .@mob=getarg(0); .@amt=getarg(1); .@mex=getarg(2); if ($@GM_OVERRIDE || debug) debugmes "Skill "+@skillId+" Lv "+@skillLv; // Blocked from summoning magic if (!alignment_cansummon()) return; if (rand2(5) < abizit()) { // Summon Magic (with magic level bonus) SummonMagic(@skillId, .@mob, .@amt, MAGIC_LVL+@skillLv-1, @skillLv); } else if (rand2(5) < abizit()) { // Re-roll dispbottom l("You cannot complete the casting correctly!"); SummonMagic(@skillId, .@mob, 1, 1, 1); } else if (abizit() <= 1 && any(true, false, false)) { // 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 (this is NOT used by Mana Stone) GetManaExp(@skillId, .@mex); return; } ///////////////////////////////////////// // RegisterMagic(MSP, Skill, MaxLv, Item, Amount, Class, Cost, {PreReq, PostReq}) function script RegisterMagic { .@msp=getarg(0); .@ski=getarg(1); .@max=getarg(2); .@ite=getarg(3); .@amo=getarg(4); .@cla=getarg(5); .@cos=getarg(6); .@pre=getarg(7, false); .@pos=getarg(8, false); $@MSK_MSPCOST[.@ski]=.@msp; $@MSK_MAXLV[.@ski]=.@max; $@MSK_ITEM[.@ski]=.@ite; $@MSK_AMOUNT[.@ski]=.@amo; $@MSK_COST[.@ski]=.@cos; $@MSK_CLASS[.@ski]=.@cla; $@MSK_PREREQ[.@ski]=.@pre; $@MSK_POSTREQ[.@ski]=.@pos; //array_push($@MSK_CLASS[.@cla], .@ski); // 3D Arrays are not supported array_push($@MSK_MAGIC, .@ski); return; } - script Magic Load NPC_HIDDEN,{ OnInit: // Cleanup in case of reload deletearray($@MSK_MSPCOST); deletearray($@MSK_MAXLV); deletearray($@MSK_ITEM); deletearray($@MSK_AMOUNT); deletearray($@MSK_COST); deletearray($@MSK_CLASS); deletearray($@MSK_PREREQ); deletearray($@MSK_POSTREQ); /* RegisterMagic(MSP, Skill, MaxLv, Item, Amount, Class, Cost, {PreReq, PostReq}) */ // Research Points (RP) range: 100~1000 [10k ~ 1M points] //////////////////////// Scholarship // Mana Wisdom RegisterMagic(1, TMW2_SAGE, 5, SpellBookPage, 1, CLASS_SCHOLARSHIP, 50); // Accumulate Power RegisterMagic(1, HW_MAGICPOWER, 5, SpellBookPage, 1, CLASS_SCHOLARSHIP, 50); // Windwalker RegisterMagic(2, SN_WINDWALK, 3, SpellBookPage, 1, CLASS_SCHOLARSHIP, 50); // Last Standing Man RegisterMagic(2, CR_TRUST, 3, SpellBookPage, 1, CLASS_SCHOLARSHIP, 50); /* Skillchain */ // First Aid RegisterMagic(1, TMW2_FIRSTAID, 10, SpellBookPage, 1, CLASS_SCHOLARSHIP, 100, false, TMW2_HEALING); // Healing RegisterMagic(2, TMW2_HEALING, 10, SpellBookPage, 1, CLASS_SCHOLARSHIP, 150, TMW2_FIRSTAID, TMW2_MAGNUSHEAL); // Magnus Healing RegisterMagic(3, TMW2_MAGNUSHEAL, 10, SpellBookPage, 1, CLASS_SCHOLARSHIP, 250, TMW2_HEALING, false); /* Skillchain */ // Provoke RegisterMagic(1, SM_PROVOKE, 1, SpellBookPage, 1, CLASS_SCHOLARSHIP, 50, false, EVOL_AREA_PROVOKE); // Mass Provoke RegisterMagic(2, EVOL_AREA_PROVOKE, 10, SpellBookPage, 1, CLASS_SCHOLARSHIP, 50, SM_PROVOKE, false); //////////////////////// Physical Sciences // Ground Strike RegisterMagic(2, ASC_METEORASSAULT, 3, FluoPowder, 3, CLASS_PHYSICAL, 50); /* Skillchain */ // Falkon Punch RegisterMagic(1, SM_BASH, 10, FluoPowder, 3, CLASS_PHYSICAL, 50, false, MC_MAMMONITE); // Supreme Attack RegisterMagic(1, MC_MAMMONITE, 10, FluoPowder, 3, CLASS_PHYSICAL, 50, SM_BASH, KN_AUTOCOUNTER); // Counter Attack RegisterMagic(2, KN_AUTOCOUNTER, 5, FluoPowder, 3, CLASS_PHYSICAL, 150, MC_MAMMONITE, false); /* Skillchain */ // Arrow Shower RegisterMagic(3, AC_SHOWER, 10, FluoPowder, 3, CLASS_PHYSICAL, 100, false, SN_SHARPSHOOTING); // Sharpshooter RegisterMagic(3, SN_SHARPSHOOTING, 1, FluoPowder, 3, CLASS_PHYSICAL, 100, AC_SHOWER, false); //////////////////////// Destructive Magic // Fire Walk RegisterMagic(2, SO_FIREWALK, 2, Quill, 1, CLASS_DESTRUCTION, 75); /* Skillchain */ // Fire Arrow RegisterMagic(1, TMW2_FIREARROW, 10, Quill, 1, CLASS_DESTRUCTION, 50, false, TMW2_FIREBALL); // Fire Ball RegisterMagic(2, TMW2_FIREBALL, 10, Quill, 2, CLASS_DESTRUCTION, 100, TMW2_FIREARROW, TMW2_ARMAGEDDON); // Armageddon RegisterMagic(3, TMW2_ARMAGEDDON, 5, Quill, 3, CLASS_DESTRUCTION, 150, TMW2_FIREBALL, false); /* Skillchain */ // Napalm Beat RegisterMagic(1, TMW2_NAPALMBEAT, 10, Quill, 1, CLASS_DESTRUCTION, 50, false, TMW2_HOLYLIGHT); // Holy Light RegisterMagic(2, TMW2_HOLYLIGHT, 10, Quill, 2, CLASS_DESTRUCTION, 100, TMW2_NAPALMBEAT, TMW2_JUDGMENT); // Judgement RegisterMagic(3, TMW2_JUDGMENT, 5, Quill, 3, CLASS_DESTRUCTION, 150, TMW2_HOLYLIGHT, false); /* Skillchain */ // Frost Diver RegisterMagic(1, TMW2_FROSTDIVER, 10, Quill, 1, CLASS_DESTRUCTION, 50, false, TMW2_FROSTNOVA); // Frost Nova RegisterMagic(2, TMW2_FROSTNOVA, 10, Quill, 2, CLASS_DESTRUCTION, 100, TMW2_FROSTDIVER, TMW2_NILFHEIM); // Nilfheim RegisterMagic(3, TMW2_NILFHEIM, 5, Quill, 3, CLASS_DESTRUCTION, 150, TMW2_FROSTNOVA, false); /* Skillchain */ // Magic Strike RegisterMagic(1, TMW2_MAGICSTRIKE, 10, Quill, 1, CLASS_DESTRUCTION, 45, false, TMW2_LIGHTNINGBOLT); // Lightning Bolt RegisterMagic(2, TMW2_LIGHTNINGBOLT, 10, Quill, 2, CLASS_DESTRUCTION, 90, TMW2_MAGICSTRIKE, TMW2_TEMPEST); // Tempest RegisterMagic(3, TMW2_TEMPEST, 5, Quill, 3, CLASS_DESTRUCTION, 125, TMW2_LIGHTNINGBOLT, false); /* Skillchain */ // Meteor Strike RegisterMagic(1, TMW2_METEORSTRIKE, 10, Quill, 1, CLASS_DESTRUCTION, 50, false, TMW2_METEORSHOWER); // Meteor Shower RegisterMagic(2, TMW2_METEORSHOWER, 10, Quill, 2, CLASS_DESTRUCTION, 100, TMW2_METEORSTRIKE, TMW2_GAIABREAK); // Gaia Break RegisterMagic(3, TMW2_GAIABREAK, 5, Quill, 3, CLASS_DESTRUCTION, 150, TMW2_METEORSHOWER, false); //////////////////////// Trickmaster /* RegisterMagic(MSP, Skill, MaxLv, Item, Amount, Class, Cost, {PreReq, PostReq}) */ RegisterMagic(1, TMW2_MANABOMB, 10, SulfurPowder, 1, CLASS_TRICKS, 40); RegisterMagic(1, TF_BACKSLIDING, 1, Lockpicks, 1, CLASS_TRICKS, 50); RegisterMagic(1, MG_FIREWALL, 10, Lockpicks, 1, CLASS_TRICKS, 50); RegisterMagic(1, AC_VULTURE, 2, Lockpicks, 1, CLASS_TRICKS, 300); RegisterMagic(1, SA_FREECAST, 1, Lockpicks, 1, CLASS_TRICKS, 50); RegisterMagic(1, ALL_FULL_THROTTLE, 1, Lockpicks, 1, CLASS_TRICKS, 50); RegisterMagic(2, GC_DARKILLUSION, 3, Lockpicks, 1, CLASS_TRICKS, 50); RegisterMagic(2, NV_TRICKDEAD, 1, Lockpicks, 1, CLASS_TRICKS, 50); //////////////////////// Other: Summonning //////////////////////// Other: Misc // Charged Shot RegisterMagic(0, AC_CHARGEARROW, 1, NPCEyes, 1, CLASS_OTHER, 100); // Study RegisterMagic(0, TMW2_STUDY, 1, Manapple, 1, CLASS_OTHER, 400); end; }