summaryrefslogblamecommitdiff
path: root/npc/magic/config.txt
blob: 285fa3793c0b615aa17dc0df01332bdb91000f4c (plain) (tree)
1
2
3
4
5
6
7
8
9






                                                                            
                                           
                                 















                                           













                                                                       



                                                               

                              
                                         
                    

                                                                
                        

                                                                  
                                     
                                         
                    

                                                               
                        

                                                                 


                                       

                                                                     















                                                                        

                   
                             





                                    

                                                        
     



           
                                                                        




                                         
                         






                                                                                              


                                    






                                                                                                
                                                                     
                                                                               



                                                                





                                                             
                                                           




















                                                    






                                             
                                  
                                                                           
                                          
               


                                                
                                                                               


















                                                                                

















































                                                                                  



           


























































































                                                                                 
 


                                                         
                                   



                                                         
                                                  
















                                                                                  
                                                           
                                                       
                       


                    



                                         
                                   
                       
                                
                   


           





                                         










                                                                           
                                                                        




                          




















                                                              



                                            
                                

               
                            


        
// 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]);
    }
    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;
}