// 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. // FIXME function script abizit { 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; // Calculation FIX if (.@type == HARM_MAGI) { .@power+=(readparam2(UDT_INT)/2); .@dmg=rand2( getunitdata(getcharid(3), UDT_MATKMIN), getunitdata(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)/2); .@dmg=rand2( getunitdata(getcharid(3), UDT_ATKMIN), getunitdata(getcharid(3), UDT_ATKMAX)); // Apply defense //if (.@target) // .@dmg=max(0, .@dmg-getunitdata(.@target, UDT_DEF)); } else { .@dmg = .@power; .@power = 100; } // 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); 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}} 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=rand2(35,50)+.@lv*10; // Abizit makes lifetime vary (like AdjustSpellpower) .@lifetime = .@lifetime * (80 + abizit() * rand2(5,10)) / 100; // Unfortunately this version does not returns the summoned monster GID summon("Summoned Monster", .@id, .@lifetime); /* .@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; } // 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; 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 (FIXME) GetManaExp(@skillId, .@mex); 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; } // 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"); // FIXME .@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; } // getactivatedpoolskilllist(?) function script getactivatedpoolskilllist { @skilllist_count=bitmask_count(FOCUSING); // FIXME @skilllist_name$ @skilllist_id? Or just rewrite Luca return @skilllist_count; } // getdeactivatedpoolskilllist(?) function script getdeactivatedpoolskilllist { @skilllist_count=bitmask_count(FOCUSING)-FSKILL_TOTAL; return @skilllist_count; } // 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)); return true; } return false; } // unpoolskill(skill) function script unpoolskill { .@f=getpoolskillFID(getarg(0)); if (FOCUSING & .@f) FOCUSING=FOCUSING ^ .@f; return; } // isfocused(skill) function script isfocused { .@f=getpoolskillFID(getarg(0)); return (FOCUSING & .@f); } - script Magic Load NPC_HIDDEN,{ OnInit: end; OnSkillInvoke: callfunc("HUB_SkillInvoke"); end; OnPCBonusEvent: callfunc("HUB_PCBonus"); end; }