summaryrefslogblamecommitdiff
path: root/npc/026-7/boss.txt
blob: 82c8cbad0a621ef518ea3e1c0528c6ace5be5c44 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11





                                                                           
                                                    



                      
          
                                                       


                                                                          
                                       
                                                         


                                                    

        




                                              
                                                                               

        














                                                                     






                                        



                                                                      







                                                   
                     
                       
        


                                                         


                                                    

                                  
                                                         

                                                
                                     
                                                                  




                                                                              
                             
                                                                     
                                                       


                                                                     
                                                                   
                                       
                                 


                                                                           
















                                      
                                             




                                                                      
                                            


                                                      
     

                                                 



                                                      

                                                        

                                                        
     
                                                                            

                                         
                                   
                                          
     







                                                                               
                       
     




                                                                            

                                                                                 







                                           



                                                 



                                                 





                                                              
                                                                     



                                                                                                                                    
                                                           


                                                                                                                                                           



                                                                            




                                                                      


                 






                                                                              










                                                                                
                                                           
                                                 
 



                                                           




                                          
                                                













                                                                         
                                                                     
                     
                                         
                             




                                                               
                                                                                   
                                                  

                                     
                                                        
                                                                 
                              

                                 
                                                                                      
                                                  

                                                                                  




                                                    
         
            




























                                                                  



                                                                            



                                                                                           

                                                                                          

                                                                     



                                                                                            
                            
                                             







                                                                
                        
                                                                        



                                                                     
         




                                                                                   
                                                        

                                                                               
                                                                   
         


                                                            
                                                                                   













                                                                                        
                                                                              
                                                                
                                                                    






                                                                                        
                                                                         







                                                                        
                                                                    






                                                                                         
                                                                         






                                                                             
                                                                      






                                                                                                 
                                                                      






                                                                                          
                                                                  






                                                                                                                                                          
                                                                        



























































                                                                                                                        
                                                                                                                                                      






























































































                                                                                                                       

        


                                              

                                

                        
                            
        
                            




                                                                       






                                                                       

        
                                       
          
                           


                                             






                                                                   
                   



                                                                              
                                                  

                                               
                                                            

                                                                           
                                                                                        
                

                                                  
                                                                                
                                                                     
                
                   
                                  
                                                                                                                                                                                                                                                                                                                                                             
                                 
                                                                                 
                          

                    


                                                   
                   
                                  


                                                                                                                                                                                                        
                          

                    

                                                                                        
                                                                                                     

                                                                     
                                                                                  
                


                                                                             





                                                                                                                       
                                                                                                                                    
                




                                                         
             
 
                                    


                                                    
                                                   

                                        

                      





                                                      





                                                                            

                                         
                                                                             
                                                                          
                                                          





                                                  

























                                                                                   
                 











                                                                                                             

                                                                                                         
                                                                                                
        


 



















                                                              
                                                             




                             








                                                                                   
 
// TMW2 scripts.
// Author:
//    Jesusalva
// Description:
//   The Impregnable Fortress Control Files - Boss Chamber - Final Showdown

026-7,39,34,0	script	Impregnable#B7F	NPC_HIDDEN,{
    function _moveNpc;
    end;

OnInit:
    .MK=0;
    .maxhp = 1000000; // 1,000,000 HP (used by scripts)
    .mana = 0; // More mana = more likely to cast skills
    .immortal = true; // Set to FALSE when all four guardians are defeated
    .memohp = 999; // Memorand HP, controls spawns
    .mou = 0; // Temporary for Cutscene
    .start_time = gettimetick(2); // Controls Death Touch
    .dmhp1 = 750000; // The "default" max HP
    .dmhp2 = 250000; // The "extra" max HP
    .reward = 0; // Reward modifier ($@MK_CHALLENGE)
    end;

// Maybe not OnTouch, but OnSit?
OnTouch:
    if (strcharinfo(2) == "Monster King") end;
    slide 39, 35;
    percentheal -15,0;
    dispbottom l("The throne is cursed, only the Monster King may sit on it.");
    end;

function _moveNpc {
    // Try to warp randomly, up to 30 attempts
    .@e=0;
    .@mx=getmapinfo(MAPINFO_SIZE_X, getarg(0))-20;
    .@my=getmapinfo(MAPINFO_SIZE_Y, getarg(0))-20;
    do {
        if (.@e >= 30)
            break;
        .npc_x = rand2(20, .@mx);
        .npc_y = rand2(20, .@my);
        .@e+=1;
    } while (!checknpccell(getarg(0), .npc_x, .npc_y, cell_chkpass));
    return;
} // _moveNpc

function _boostMe {
    .@mg = getarg(0);
    .@bat=getunitdata(.@mg, UDT_ATKMAX);
    .@bai=getunitdata(.@mg, UDT_ATKMIN);
    .@bdf=getunitdata(.@mg, UDT_DEF);
    .@bcr=getunitdata(.@mg, UDT_CRIT);
    .@bag=getunitdata(.@mg, UDT_AGI);
    .@bf = $@MK_CHALLENGE + 2; // The booster from selected difficulty
    .@s=.@bf+max(0, (TOP3AVERAGELVL()-100 / 5)); // Over-100 scaling
    .@bat = .@bat * .@bf / 2;
    .@bcr = .@bcr * .@bf / 2;
    setunitdata(.@mg, UDT_ATKMAX,   .@bat+(.@s*5));
    setunitdata(.@mg, UDT_DEF,      .@bdf+(.@s*4));
    setunitdata(.@mg, UDT_CRIT,     .@bcr+(.@s*3));
    setunitdata(.@mg, UDT_ATKMIN,   .@bai+(.@s*2));
    setunitdata(.@mg, UDT_AGI,      .@bag+(.@s*1));
    return;
}

// Controls the Event
// TODO: Intro Cutscene
OnBegin:
    // Monster King is somewhere else, so nothing happens
    if ($@MK_SCENE != MK_NONE)
        end;
    // It is a false positive? Something gone wrong?
    if ($@MK_CHALLENGE < 1)
        end;
    // Lock the MK in the showdown
    $@MK_SCENE=MK_SHOWDOWN;
    .start_time = gettimetick(2); // Controls Death Touch
    // Recalculate Max HP
    .maxhp = .dmhp1 + (.dmhp2 * $@MK_CHALLENGE);
    // Initial assortment of monsters
    //siege_cast("026-7", .name$, 15, TP_TULIM|TP_HURNS|TP_NIVAL);
    .@am = ($@MK_CHALLENGE + 1) / 2;
    areamonster("026-7", 30, 27, 50, 50, "Heart's Curse", EvilWisp, .@am);
    areamonster("026-7", 30, 27, 50, 50, "Heart's Curse", EpiphanyWisp, .@am);
    areamonster("026-7", 30, 27, 50, 50, "Heart's Curse", SacredWisp, .@am);
    areamonster("026-7", 30, 27, 50, 50, "Heart's Curse", PanthomWisp, .@am);
    // Spawn the boss himself
    .MK=monster("026-7", 39, 34, "The Monster King", MonsterKing, 1);
    immortal(.MK); // Immortal until conditions are met
    .immortal = true;
    // Mana is mostly carried over between attempts, but no negatives
    .mana = max(.mana, 0);
    .mana += $@MK_CHALLENGE; // Difficulty mode starting MP booster
    .memohp = 999; // Reset Memorand HP
    // Give MK some extra defense
    setunitdata(.MK, UDT_DEF, getunitdata(.MK, UDT_DEF) * 4 / 3);  // +30%
    setunitdata(.MK, UDT_MDEF, getunitdata(.MK, UDT_DEF) * 5 / 4); // +25%
    setunitdata(.MK, UDT_LUK, getunitdata(.MK, UDT_LUK) * 2);      // +100%
    // Reconfigure the AI
    .@opt=getunitdata(.MK, UDT_MODE);
    // Add knockback immunity
    .@opt=.@opt|MD_NOKNOCKBACK;
    // Mark as boss
    .@opt=.@opt|MD_BOSS;
    // Mark as aggressive
    .@opt=.@opt|MD_AGGRESSIVE;
    .@opt=.@opt|MD_ANGRY;
    // Make it more op
    .@opt=.@opt|MD_DETECTOR;
    .@opt=.@opt|MD_CASTSENSOR_CHASE;
    .@opt=.@opt|MD_CASTSENSOR_IDLE;
    .@opt=.@opt|MD_CHANGECHASE;
    .@opt=.@opt|MD_CHANGETARGET_MELEE;
    .@opt=.@opt|MD_CHANGETARGET_CHASE;
    setunitdata(.MK, UDT_MODE, .@opt);
    setunitdata(.MK, UDT_RACE, RC_Legendary);
    // If the number of players is below the expected, BUFF the damage
    // +20% max damage every missing player
    if (getmapusers("026-7") < 5) {
        .@bat=getunitdata(.MK, UDT_ATKMAX);
        .@bat += .@bat / 5 * (5-getmapusers("026-7"));
        setunitdata(.MK, UDT_ATKMAX, .@bat);
        .@bat=getunitdata(.MK, UDT_ATKMIN);
        .@bat += .@bat / 5 * (5-getmapusers("026-7"));
        setunitdata(.MK, UDT_ATKMIN, .@bat);
    }
    // Some restrictions are based on the players
    .@crc=5; .@leg=5;
    .@c=getunits(BL_PC, .@pcs, MAX_CYCLE_PC, "026-7");
    for (.@i = 0; .@i < .@c; .@i++) {
        if (readparam(BaseLevel, .@pcs[.@i]) >= 109)
            .@crc -= 1;
        if (islegendary(strcharinfo(0, "", .@pcs[.@i])))
            .@leg -= 1;
        // For every player, increase MK's starting mana
        .mana += 1;
    }
    // If the level of the players is below the expected, BUFF the criticals
    if (.@crc > 0) {
        .@bcr=getunitdata(.MK, UDT_CRIT);
        .@bcr += .@bcr / 5 * .@crc;
        setunitdata(.MK, UDT_CRIT, .@bcr);
    }
    // If the legendary players is below the expected, BUFF the speed and range
    if (.@leg > 0) {
        .@bs1=getunitdata(.MK, UDT_SPEED);
        .@bs1 -= .@leg * 10;
        .@bs2=getunitdata(.MK, UDT_ATKRANGE);
        .@bs1 += .@leg;
        setunitdata(.MK, UDT_SPEED, .@bs1);
        setunitdata(.MK, UDT_ATKRANGE, .@bs2);
        .mana += .@leg;
    }
    // The Four Generals which command his immortality
    .GUARD1=monster("026-7", 35, 30, "Air General", MonsterGeneral, 1);
    .GUARD4=monster("026-7", 44, 45, "Fire General", MonsterGeneral, 1);
    .GUARD3=monster("026-7", 35, 45, "Earth General", MonsterGeneral, 1);
    .GUARD2=monster("026-7", 44, 30, "Darkness General", MonsterGeneral, 1);
    // Boost these four generals or they'll become cheese too fast
    // Also, fix their elementals, but they have no elemental skills to speak of.
    setunitdata(.GUARD1, UDT_HP,    90000);
    setunitdata(.GUARD1, UDT_MAXHP, 90000);
    setunitdata(.GUARD2, UDT_HP,    90000);
    setunitdata(.GUARD2, UDT_MAXHP, 90000);
    setunitdata(.GUARD3, UDT_HP,    90000);
    setunitdata(.GUARD3, UDT_MAXHP, 90000);
    setunitdata(.GUARD4, UDT_HP,    90000);
    setunitdata(.GUARD4, UDT_MAXHP, 90000);
    setunitdata(.GUARD1, UDT_ELETYPE, Ele_Wind);
    setunitdata(.GUARD2, UDT_ELETYPE, Ele_Dark);
    setunitdata(.GUARD4, UDT_ELETYPE, Ele_Fire);
    setunitdata(.GUARD3, UDT_ELETYPE, Ele_Earth);
    setunitdata(.GUARD1, UDT_RACE, RC_Legendary);
    setunitdata(.GUARD2, UDT_RACE, RC_Legendary);
    setunitdata(.GUARD3, UDT_RACE, RC_Legendary);
    setunitdata(.GUARD4, UDT_RACE, RC_Legendary);
    // Use the wrapper to make all the guards minimally decent
    // (or at very least, as strong as during town sieges)
    _boostMe(.GUARD1);
    _boostMe(.GUARD2);
    _boostMe(.GUARD3);
    _boostMe(.GUARD4);
    // The remainder of MK army (Centered at the generals / 20 total)
    .@x = 35; .@y = 30; areamonster("026-7", .@x-3, .@y-3, .@x+3, .@y+3, "Air Officer", Reaper, 5); // Air Troops
    .@x = 44; .@y = 45; areamonster("026-7", .@x-3, .@y-3, .@x+3, .@y+3, "Fire Officer", LavaSkullSlime, 6); // Fire Troops
    .@x = 35; .@y = 45; areamonster("026-7", .@x-3, .@y-3, .@x+3, .@y+3, "Earth Officer", Snail, 5); // Earth Troops
    .@x = 44; .@y = 30; areamonster("026-7", .@x-3, .@y-3, .@x+3, .@y+3, "Darkness Officer", NightmareDragon, 5); // Darkness Troops
    // Monster King Personal Bodyguard is special (4 total)
    for (.@i = 0; .@i < 4; ++.@i) {
        areamonster("026-7", 37, 32, 41, 36, "Imperial Officer", any(VanityPixie, HolyPixie, ShadowPixie, NulityPixie, BlackSkullSlime, PinkieSuseran), 1);
    }
    // General ranged troops / Artillery (20 total)
    areamonster("026-7", 30, 30, 45, 45, "Ranged Support", RobinBandit, 12);
    areamonster("026-7", 30, 30, 45, 45, "Ranged Support", DustRevolver, 5);
    areamonster("026-7", 30, 30, 45, 45, "Ranged Support", DustRifle, 3);
    // Some "cutscene" most likely no one will see, taking half second
    sleep(150);
    unittalk(.MK, "You dare to challenge me?!");
    sleep(350);
    unittalk(.MK, "You noobs, you all deserve to die!");
    initnpctimer;
    end;

OnMFDispose:
    if (ispcdead() || getq(General_Fortress) < 6) warp("025-2", 100, 27);
    // Summons, for a whole minute, an allied solider (0.1% per siege won)
    if (rand2(1000) < $MK_TEMPVAR)
        summon("Allied Guard", any(FallenGuard1, FallenGuard2, FallenGuard3));
    end;

// Fail-safe Mechanism (will never happen)
OnTimer60000:
    consolebug("Warning! final fail-safe mechanism triggered to Monster King.");
    initnpctimer;
    end;

// Run every 10 seconds
OnTimer25000:
OnTimer15000:
    consolewarn("Warning, fail-safe mechanism triggered to Monster King.");
OnTimer10000:
    maptimer2("026-7", 10, "Impregnable#B7F::OnMFDispose");
    .mana += (.immortal ? 1 : 2); // Recover mana

    // Bonus MP regeneration from difficulty mode selection
    if ($@MK_CHALLENGE > 1)
        .mana += $@MK_CHALLENGE-1;

    /* Regeneration & Defeat Loop */
    .@end = false;
    if (.immortal)
        setunitdata(.MK, UDT_HP, INT_MAX);
    if (!getmapusers("026-7")) {
        if (.immortal || getunittype(.MK) < 0) {
            .@end = true;
        } else {
            .@hp = getunitdata(.MK, UDT_HP);
            .@mh = .maxhp;
            .@hp = max(.@mh, .@hp + (.@mh / 500)); // Regenerates 0.2% HP
            // Regeneration
            setunitdata(.MK, UDT_HP, .@hp);
            // Fully healed, players lost
            if (.@hp >= .@mh)
                .@end = true;
        }
    }

    /* Maybe the fight is over */
    if (!mobcount("026-7", "all") || getunittype(.MK) < 0 || .@end) {
        stopnpctimer;
        .reward = max(1, $@MK_CHALLENGE);
        $@MK_SCENE = MK_NONE;
        $@MK_CHALLENGE=false;
        killmonsterall("026-7");
        enablenpc .name$;
        if (!.@end) {
            // This is not due to full health! We actually won!
            kamibroadcast("The MONSTER KING has been DEFEATED!", b("WORLD HEART"));
            $@MK_COOLDOWN = gettimetick(2) + 7200;
            if ($GAME_STORYLINE != 5)
                goto L_NextAct;
            // Will not be cast if L_NextAct is summoned
            maptimer2("026-7", 10, "Impregnable#B7F::OnVictory");
            goto OnPrepBlight;
        } else {
            // We actually lost?!
            kamibroadcast("The MONSTER KING has WON the showdown!", b("WORLD HEART"));
            $@MK_COOLDOWN = gettimetick(2) + 1800;
            // Apply some kind of penalty, like lowering EXP rate in 5% for a hour
            // (NLib was 50% for 24 hours...)
            if ($GAME_STORYLINE >= 5) {
                $@EXP_EVENT=-5;
                $@EXP_EVENT_TIME=1;
                donpcevent "@exprate::OnPlayerCall";
            }
        }
        end;
    }

    /* Prepare some combat data */
    getmapxy(.@m$, .@x, .@y, UNITTYPE_MOB, .MK);
    .@c=getunits(BL_PC, .@pcs, MAX_CYCLE_PC, .@m$);
    .@mvp=0;.@rnd=0;.@def=-1;
    for (.@i = 0; .@i < .@c; .@i++) {
        if (!.@rnd || !rand2(.@c))
            .@rnd=.@pcs[.@i];
        if (readbattleparam(.@pcs[.@i], UDT_DEF) > .@def) {
            if (readparam(Hp, .@pcs[.@i]) < 1) continue;
            .@mvp=.@pcs[.@i];
            .@def=readbattleparam(.@pcs[.@i], UDT_DEF);
        }
    }

    /* Everyone is dead, get rid of their corpses and loop over */
    if (!.@mvp || !.@rnd) {
        mapwarp("026-7", "025-2", 100, 27);
        initnpctimer;
        end;
    }

    /* Maybe he lost his immortality */
    if (.immortal) {
        if (getunittype(.GUARD1) < 0 &&
            getunittype(.GUARD2) < 0 &&
            getunittype(.GUARD3) < 0 &&
            getunittype(.GUARD4) < 0) {
                // Secondary throttle (1m), see code copy-pasta below
                if (.start_time < gettimetick(2) + 60) {
                    unittalk(.MK, "Death touch!");
                    maptimer2("026-7", 10, "Impregnable#B7F::OnDeathTouch");
                    areamonster("026-7", 30, 27, 50, 50, "Heart's Curse", EvilWisp, 1);
                    areamonster("026-7", 30, 27, 50, 50, "Heart's Curse", EpiphanyWisp, 1);
                    areamonster("026-7", 30, 27, 50, 50, "Heart's Curse", SacredWisp, 1);
                    areamonster("026-7", 30, 27, 50, 50, "Heart's Curse", PanthomWisp, 1);
                    .@t=areamonster("026-7", 30, 27, 50, 50, "Heart's Curse", Tortuga, 1);
                    set_aggro(.@t);
                }
                // Remove the immortality and reset Death Touch timer
                .immortal = false;
                kamibroadcast("The Monster King has lost his immortality.", "Monster King");
                setunitdata(.MK, UDT_HP,    .maxhp);
                setunitdata(.MK, UDT_MAXHP, .maxhp);
                .mana += 25;
                .start_time = gettimetick(2);
        }
    }

    /* Spawn every 20% HP lost, using siege logic 'cause lazy */
    if (!.immortal) {
        .@hp = getunitdata(.MK, UDT_HP) * 5 / .maxhp;
        if (.@hp < .memohp) {
            .memohp = .@hp;
            .mana += 25;
            siege_cast("026-7", .name$, 35, TP_TULIM|TP_HURNS|TP_NIVAL);
            if (any(true,false,false))
                unitwarp(.MK, "026-7", rand2(38, 40), rand2(35, 37));
            else
                unitwarp(.MK, "026-7", rand2(35, 44), rand2(40, 45));
        }
        // If Monster King is taking too much damage and too fast, throttle players
        // Aegis Shield, however, provides immunity to this
        if (.@hp <= 2 && .start_time < gettimetick(2) + 180) {
            unittalk(.MK, "Death touch!");
            maptimer2("026-7", 10, "Impregnable#B7F::OnDeathTouch");
            .mana += 5; // Replenish the skill mana cost
            // The next touch is in a minute, but in a Judgement Day, every 10s
            .start_time = gettimetick(2) + 180 + 64 - ($@MK_CHALLENGE * 4);
            monster("026-7", 39, 34, "Summoned Reaper", Reaper, 1);
        }
    }

    /* Decide whenever the Monster King will use a skill. */
    // Each Mana point is worth 1% chance. He gains 6 points per minute. (12 later)
    // (While immortal, each mana point is worth 0.5% chance)
    if (rand2(.immortal ? 200 : 100) <= .mana) {
        .mana -= 5; // Mana cost for skill use. It can go negative
        // Give players 500ms to prepare
        specialeffect(FX_SPECIAL, AREA, .MK);
        sleep(500);
        // Initialization
        .@skill = rand2(25); .@mob = .MK; .@msg$ = ""; .@lv = 120; .@t = rand2(15);
        // Skills taken from Blanc, Terogan and Moubootaur (Sealed)
        switch (.@skill) {
        case 1:
		    .@msg$ = sprintf("Witness my sublime rain of death. Regeneration!");
		    .@hp=getunitdata(.@mob, UDT_HP);
		    .@mp=getunitdata(.@mob, UDT_MAXHP);
            .@hp = limit(.@hp, .@hp + (.@mp / 25), .@mp); // Regenerates 4% HP
		    setunitdata(.@mob, UDT_HP, min(.@hp, .@mp));
            .@mobid=(rand2(.@lv) > 50 ? DeathCat : GreenSkullSlime);
            monster(.@m$, .@x, .@y, strmobinfo(1, .@mobid), .@mobid, 1);
            break;
	    case 2:
		    .@msg$ = sprintf("Chaos shall be my founding stone! Falling star!");
            attachrid(.@rnd);
		    percentheal -5, -10;
            detachrid();
            .@mobid=(rand2(.@lv) > 50 ? BlackSkullSlime : RedSkullSlime);
            monster(.@m$, .@x, .@y, strmobinfo(1, .@mobid), .@mobid, 1);
            break;
	    case 3:
		    .@msg$ = sprintf("I demand this world! Tyranny!");
            attachrid(.@rnd);
		    percentheal -1, -1;
		    SC_Bonus(.@t, any(SC_BLIND, SC_POISON), 1);
            detachrid();
            .@mobid=(rand2(.@lv) > 50 ? RedFollowerF : HoodedNinja);
            monster(.@m$, .@x, .@y, strmobinfo(1, .@mobid), .@mobid, 1);
            break;
	    case 4:
		    .@msg$ = sprintf("Stop on your tracks, unfair being! Freeze!");
            attachrid(.@rnd);
		    SC_Bonus((.@t / 2), any(SC_FREEZE, SC_SLEEP, SC_SLEEP, SC_SLEEP), 1);
            detachrid();
            .@mobid=(rand2(.@lv) > 50 ? LavaSkullSlime : AzulSkullSlime);
            monster(.@m$, .@x, .@y, strmobinfo(1, .@mobid), .@mobid, 1);
            break;
	    case 5:
		    .@msg$ = sprintf("There is no free speech. Censorship!");
            attachrid(.@rnd);
		    SC_Bonus(.@t, SC_SILENCE, 1);
            detachrid();
            .@mobid=(rand2(.@lv) > 50 ? RedFollower : RedSlimeMother);
            monster(.@m$, .@x, .@y, strmobinfo(1, .@mobid), .@mobid, 1);
            break;
	    case 6:
		    .@msg$ = sprintf("And then... There was a quake. And all life died. Bleed!");
            attachrid(.@rnd);
		    SC_Bonus(.@t, SC_BLOODING, 1);
            detachrid();
            .@mobid=(rand2(.@lv) > 50 ? BlackSkullSlime : BlackMamba);
            monster(.@m$, .@x, .@y, strmobinfo(1, .@mobid), .@mobid, 1);
            break;
	    case 7:
		    .@msg$ = sprintf("Puny mortal, do your best to entertain me! Curse!");
            attachrid(.@rnd);
		    SC_Bonus(.@t, SC_CURSE, 1);
            detachrid();
            .@mobid=(rand2(.@lv) > 50 ? Reaper : ArmoredSkeleton);
            monster(.@m$, .@x, .@y, strmobinfo(1, .@mobid), .@mobid, 1);
            break;
	    case 8:
		    .@msg$ = sprintf("The problem with typos is - unpredictable side effects.");
            attachrid(.@rnd);
		    SC_Bonus(.@t, any(SC_SILENCE, SC_CURSE, SC_FREEZE, SC_BLOODING, SC_BLIND, SC_POISON, SC_DPOISON, SC_POISON, SC_BURNING, SC_SLEEP), 1);
            detachrid();
            .@mobid=(rand2(.@lv) > 50 ? ShadowTortuga : SuperiorShroom);
            monster(.@m$, .@x, .@y, strmobinfo(1, .@mobid), .@mobid, 1);
            break;
        case 9:
            mapannounce("026-7", "Monster King : ##BAncient Magic: Lag", 0);
            areasc2("026-7", 39, 38, 20, 15000, SC_CONFUSION, BL_PC, 1);
            break;
        case 10:
            mapannounce("026-7", "Monster King : ##BAncient Magic: Sleep", 0);
            areasc2("026-7", 39, 38, 20, 15000, SC_SLEEP, BL_PC, 1);
            break;
        case 11:
            mapannounce("026-7", "Monster King : ##BAncient Magic: Burning", 0);
            areasc2("026-7", 39, 38, 20, 15000, SC_BURNING, BL_PC, 1);
            break;
        case 12:
            mapannounce("026-7", "Monster King : ##BAncient Magic: Fear", 0);
            areasc2("026-7", 39, 38, 20, 15000, SC_FEAR, BL_PC, 1);
            break;
        case 13:
            .@msg$ = sprintf("##BAncient Magic: Obliterate");
            rectharm(.MK, 7, 7, rand2(700, 900), HARM_MISC, Ele_Dark, "filter_always", BL_PC | BL_MER | BL_HOM);
            break;
        case 14:
            .@msg$ = sprintf("##BAncient Magic: Terminate Homunculi");
            rectharm(.MK, 14, 14, rand2(1500, 2500), HARM_MISC, Ele_Dark, "filter_always", BL_MER | BL_HOM);
            break;
        case 15:
            mapannounce("026-7", "Monster King : ##BAncient Magic: Wizcat", 0);
            for (.@i=0;.@i <= 2+rand2(7);.@i++) {
                .@m=monster("026-7", rand2(30,50), rand2(30,45),
                    "Reinforcement", BlackCat, 1);
                setunitdata(.@m, UDT_RACE, RC_Legendary);
            }
            break;
        case 16:
            mapannounce("026-7", "Monster King : ##BAncient Magic: Silencing Nuke", 0);
            rectharm(.MK, 14, 14, rand2(450, 750), HARM_MISC, Ele_Dark, "filter_always", BL_PC | BL_MER | BL_HOM);
            areasc2("026-7", 40, 35, 20, 15000, SC_SILENCE, BL_PC, 1);
            break;
        case 17:
            // Second Attack Pattern: Holy Light (vs Tank)
            .@msg$ = sprintf("%s, I'll show you no mercy! ##BThunder Bolt##b!", strcharinfo(0, "cursed player", .@mvp));
            .@PW=125; .@SPW=25; .@RG=1;
            .@mtk = calcdmg(.@mob, .@mvp, HARM_MAGI);
            .@dmg = .@mtk * .@PW / 100;
            .@dsb = .@mtk * .@SPW / 100;
            sleep(1000);
            specialeffect(FX_LIGHTNING, AREA, .@mvp);
            areaharm(.@mvp, .@RG, .@dsb, HARM_MAGI, Ele_Wind, "filter_always", BL_PC|BL_MER|BL_HOM);
            harm(.@mvp, .@dmg, HARM_MAGI, Ele_Holy);
            break;
        case 18:
            .@msg$ = sprintf("Come forth, my minions! Wreak chaos and havoc!");
            specialeffect(FX_MGWARP, AREA, .MK); // Maybe 65 would also work
            sleep(1000);
            // Default amount: Half players + 3
            .@max = (getmapusers("026-7")/2) + 3;
            // Keep boundaries: Never less than 1, never more than 10
            .@max = limit(1, .@max, 10);
            for (.@i=0; .@i < .@max; .@i++) {
                .@mid = any(GoboBear, Golem, BloodyMouboo, GreenSkullSlime, BlackMamba, JackO, Brainic, TerraniteProtector, Mandragora, Yeti, Reaper);
                .@x = monster(.@m$, .@x, .@y, strmobinfo(1, .@mid), .@mid, 1);
                set_aggro(.@x);
            }
            break;
        case 19:
            .@msg$ = sprintf("I shall ##Bdisable##b you, %s!", strcharinfo(0, "cursed player", .@mvp));
            specialeffect(FX_SMOKE, AREA, .MK);
            attachrid(.@mvp);
		    SC_Bonus(.@t, SC_SILENCE, 1);
		    SC_Bonus(.@t, SC_BLIND, 1);
		    SC_Bonus(.@t/3, SC_CURSE, 1);
            detachrid();
            break;
	    case 20:
            // First Attack Pattern: Napalm Beat (vs MVP)
            .@msg$ = sprintf("This battle is over, %s! ##BThunder Neddle##b!", strcharinfo(0, "cursed player", .@mvp));
            .@PW=35; .@SPW=5; .@RG=2;
            .@mtk = calcdmg(.@mob, .@mvp, HARM_MAGI);
            .@dmg = .@mtk * .@PW / 100;
            .@dsb = .@mtk * .@SPW / 100;
            sleep(1000);
            specialeffect(FX_LIGHTNING, AREA, .@mvp);
            areaharm(.@mvp, .@RG, .@dsb, HARM_MAGI, Ele_Wind, "filter_always", BL_PC|BL_MER|BL_HOM);
            harm(.@mvp, .@dmg, HARM_MAGI, Ele_Holy);
            break;
        case 21:
            .@msg$ = sprintf("##BMagic: Armageddon");
            rectharm(.MK, 6, 6, rand2(300, 500), HARM_MAGI, Ele_Fire, "filter_always", BL_PC | BL_MER | BL_HOM);
            break;
        case 22:
            .mana += 1;
            .@msg$ = sprintf("##BMagic: Tempest");
            rectharm(.MK, 3, 3, rand2(200, 300), HARM_MAGI, Ele_Wind, "filter_always", BL_PC | BL_MER | BL_HOM);
            break;
        case 23:
            .@msg$ = sprintf("##BMagic: Gaia Break");
            sc_start SC_INCDEFRATE, 15000, 10, .MK;
            rectharm(.MK, 2, 5, rand2(250, 350), HARM_MAGI, Ele_Earth, "filter_always", BL_PC | BL_MER | BL_HOM);
            break;
        case 24:
            .@msg$ = sprintf("##BMagic: Ground Strike");
            .@EF=any(SC_STUN, SC_BLIND, SC_BLOODING, SC_BLIND, SC_BLOODING);
            areasc2("026-7", .@x, .@y, 3, 12000, .@EF, BL_PC, 1);
            rectharm(.MK, 3, 3, rand2(250, 350), HARM_PHYS, Ele_Neutral, "filter_always", BL_PC | BL_MER | BL_HOM);
            break;
        // TODO: Skills which manipulate the map or weather
        default:
            .@mx=55; .@my=55; .@x=22; .@y=22;
            .@x1=rand2(.@mx, .@x); .@x2=rand2(.@mx, .@x); .@x3=rand2(.@mx, .@x);
            .@y1=rand2(.@my, .@y); .@y2=rand2(.@my, .@y); .@y3=rand2(.@my, .@y);
            .@x4=rand2(.@mx, .@x); .@x5=rand2(.@mx, .@x);
            .@y4=rand2(.@my, .@y); .@y5=rand2(.@my, .@y);
            // TODO: Maybe replace Dummy/EnergyBall with an invisible monster/FX?
            .@t1=monster("026-7", .@x1, .@y1, "", Dummy, 1);
            .@t2=monster("026-7", .@x2, .@y2, "", Dummy, 1);
            .@t3=monster("026-7", .@x3, .@y3, "", Dummy, 1);
            .@t4=monster("026-7", .@x4, .@y4, "", Dummy, 1);
            .@t5=monster("026-7", .@x5, .@y5, "", Dummy, 1);
            specialeffect(67, AREA, .@t1);
            specialeffect(67, AREA, .@t2);
            specialeffect(67, AREA, .@t3);
            specialeffect(67, AREA, .@t4);
            specialeffect(67, AREA, .@t5);
            immortal(.@t1); immortal(.@t2); immortal(.@t3);
            immortal(.@t4); immortal(.@t5);
            sleep(1500); // Saw a pillar? RUN!
            specialeffect(FX_LIGHTNING, AREA, .@t1);
            specialeffect(FX_LIGHTNING, AREA, .@t2);
            specialeffect(FX_LIGHTNING, AREA, .@t3);
            specialeffect(FX_LIGHTNING, AREA, .@t4);
            specialeffect(FX_LIGHTNING, AREA, .@t5);
            sleep(500);
            specialeffect(FX_CRITICAL, AREA, .@t1);
            specialeffect(FX_CRITICAL, AREA, .@t2);
            specialeffect(FX_CRITICAL, AREA, .@t3);
            specialeffect(FX_CRITICAL, AREA, .@t4);
            specialeffect(FX_CRITICAL, AREA, .@t5);
            areaharm(.@t1, 2, 450, HARM_MISC, Ele_Neutral, "filter_always", BL_PC|BL_MER|BL_HOM);
            areaharm(.@t2, 2, 450, HARM_MISC, Ele_Neutral, "filter_always", BL_PC|BL_MER|BL_HOM);
            areaharm(.@t3, 2, 450, HARM_MISC, Ele_Neutral, "filter_always", BL_PC|BL_MER|BL_HOM);
            areaharm(.@t4, 2, 450, HARM_MISC, Ele_Neutral, "filter_always", BL_PC|BL_MER|BL_HOM);
            areaharm(.@t5, 2, 450, HARM_MISC, Ele_Neutral, "filter_always", BL_PC|BL_MER|BL_HOM);
            sleep(1000);
            // FIXME: M+ fails to remove them, need @refresh (maybe @refreshall?)
            // NOTE: The effect Nº 67 (halo circle) is also not cleaned by M+
            unitkill(.@t1); unitkill(.@t2);
            unitkill(.@t4); unitkill(.@t5);
            break;
        }
        if (.@msg$ != "")
            unittalk(.@mob, .@msg$);
    }

    // Restart the endless loop
    initnpctimer;
    end;

OnDeathTouch:
    if (strcharinfo(0) == $AEGIS_HOLDER$) end;
    SC_Bonus(30, SC_BLIND, 1);
    SC_Bonus(25, SC_SILENCE, 1);
    SC_Bonus(15, SC_CURSE, 1);
    // Consume some mana
    if (islegendary())
        percentheal -2, -15;
    else
        percentheal -2, -25;
    // If you ran out of MP, consume 1/3 HP (Death Touch)
    if (Sp < 10) {
        dispbottom l("Death grazes your soul (-%s HP)", fnum(Hp*3/10));
        percentheal -30, 0;
    }
    // Buff the Monster King slightly (approx. +3.5% damage per player)
    .@bat=getunitdata(.MK, UDT_ATKMAX);
    .@bat += .@bat / 28;
    setunitdata(.MK, UDT_ATKMAX, .@bat);
    .@bat=getunitdata(.MK, UDT_ATKMIN);
    .@bat += .@bat / 28;
    setunitdata(.MK, UDT_ATKMIN, .@bat);
    end;

// Monster King was defeated - game won
L_NextAct:
    $@MK_SCENE=MK_CUTSCENE;
    $GAME_STORYLINE=5;
    $MANA_BLVL-=10; // Set base level to 5~15
    $MANA_BLVL=max(0, $MANA_BLVL);
    // Thanksgiving event no longer happens after Monster King dies
    if ($EVENT$ == "Thanksgiving") {
        kamibroadcast("Thanksgiving ended!");
        sClear();
        $EVENT$="";
    }
    donpcevent "sThankAeros::OnTimer90000";
    // XXX Cutscene
    sleep(3000);
    .mou = monster("026-7", 39, 37, "Moubootaur", MobMoubootaur, 1);
    immortal(.mou);
    sc_start(SC_STUN, 90000, 1, 10000, SCFLAG_NOAVOID|SCFLAG_FIXEDTICK, .mou);
    maptimer2("026-7", 30, "Book#FoS::OnMFShake");
    sleep(3000);
    unittalk(.mou, "##1I'm free... At least!");
    kamibroadcast("##1I'm free... At least!", "Moubootaur");
    sleep(6500);
    unittalk(.mou, "##1The blood in the Heart, as the prophecy foretold!");
    kamibroadcast("##1The blood in the Heart, as the prophecy foretold!", "Moubootaur");
    sleep(4500);
    maptimer2("026-7", 30, "Book#FoS::OnMFShake");
    sleep(30);
    unittalk(.mou, "##1All monsters, heed my command! ##BHostile Takeover!##b");
    kamibroadcast("##1All monsters, heed my command!", "Moubootaur");
    sleep(1500);
    freeloop(true);
    for (.@i=0; .@i < 25; .@i++) {
        .@m = areamonster("026-7", 20, 20, 55, 55, "Subjugated Monster", any(PinkieEmperor, PanthomLord, TerraniteKing, YetiKing, PsiConscience, DemureSecondForm, Luvia, Birb, MonsterGeneral, MonsterColonel, LavaSlimeMother, BlackSlimeMother, WanderingShadow, BanditLord, HoodedAssassin, SpiderQueen, NightScorpion, SaxsoGhost, GiantMutatedBat), 1);
        immortal(.@m); // Broken?
        sc_start(SC_STUN, 90000, 1, 10000, SCFLAG_NOAVOID|SCFLAG_FIXEDTICK, .@m);
        sleep(200); // 5 s
    }
    freeloop(false);
    sleep(3000);
    unittalk(.mou, "##1My children, ##BArise!##b");
    sleep(1500);
    freeloop(true);
    for (.@i=0; .@i < 25; .@i++) {
        .@m = areamonster("026-7", 20, 20, 55, 55, "Subjugated Monster", any(Moubi, Moubi, Moubi, MoubooSlime, GreatMoubooSlime, Mouboo, Mouboo, EasterMouboo, AlphaMouboo, Shrewboo, BloodyMouboo), 1);
        immortal(.@m);
        sc_start(SC_STUN, 90000, 1, 10000, SCFLAG_NOAVOID|SCFLAG_FIXEDTICK, .@m);
        sleep(160); // 4 s
    }
    freeloop(false);
    sleep(3000);
    unittalk(.mou, "##1I have taken over the World Heart... Your chances are forfeit.");
    kamibroadcast("##1I have taken over the World Heart... Your chances are forfeit.", "Moubootaur");
    sleep(6000);
    unittalk(.mou, "##1But first, I'll make a Monster King puppet.");
    kamibroadcast("##1But first, I'll make a Monster King puppet.", "Moubootaur");
    sleep(2000);
    .@m = monster("026-7", 39, 34, "Monster King (puppet)", MonsterKing, 1);
    immortal(.@m);
    sc_start(SC_STUN, 90000, 1, 10000, SCFLAG_NOAVOID|SCFLAG_FIXEDTICK, .@m);
    sleep(3000);
    unittalk(.mou, "##1Now, it would be inconvenient if you were to disturb me while I work...");
    sleep(6000);
    unittalk(.mou, "##1It'll take several days or even months to corrupt the Heart. Can't be bothered.");
    sleep(8000);
    unittalk(.mou, "##1Enjoy your final days while you can. The day on which everything will be a Mouboo is upon us!");
    kamibroadcast("##1Enjoy your final days while you can. The day on which everything will be a Mouboo is upon us!", "Moubootaur");
    sleep(5000);
    maptimer2("026-7", 10, "Impregnable#B7F::OnVictory");
    // Cleanup
    sleep(10000);
    $@MK_SCENE=MK_NONE;
    killmonsterall("026-7");
    .mou = 0;

    // This disables all mosnters :<
    //setbattleflag("monster_ai", 0x209);
    //setbattleflag("monster_active_enable", false);
    //setbattleflag("mob_count_rate", 25);
    //charcommand("@reloadbattleconf"); // Careful!
    //donpcevent("@exprate::OnReload");
    //donpcevent("@droprate::OnReload");
    //end;
    goto OnPrepBlight;

OnVictory:
    // Not killed by a player? It doesn't counts, then
    if (!playerattached())
        end;
    // Prizes
    Mobpt += 150 + (.reward * 15);
    getitem StrangeCoin, 45 + min(55, .reward * 5); // 50 ~ 100 coins reward
    // Give some additional EXP for higher difficulty settings
    if (.reward > 1)
        getexp (.reward/2) * getmonsterinfo(MonsterKing, MOB_BASEEXP),
               (.reward/2) * getmonsterinfo(MonsterKing, MOB_JOBEXP);
    if (!MK_WINNER) {
        MK_WINNER=gettimetick(2); // TODO
        getitem StrangeCoin, 1450; // Total: 1,500 Strange Coins on first win
        getitembound MysteriousFruit, 3, 4; // You get 3 char bound fruits
        getexp 0, 250000; // 250k job exp on first victory
    }
    // Effects
    specialeffect(FX_FANFARE, SELF, getcharid(3));
    // Bailout
    sleep2(5000);
    warp "025-1", 99, 22;
    close;

OnPrepBlight:
    if ($SHADY_HOLDER$ != "") end;
    .@c=getunits(BL_PC, .@pcs, MAX_CYCLE_PC, "026-7");
    .@mvp=0;.@def=-1;
    for (.@i = 0; .@i < .@c; .@i++) {
        .@atk = readbattleparam(.@pcs[.@i], UDT_ATKMAX);
        if (.@atk > .@def) {
            // Lets check if they qualify
            attachrid(.@pcs[.@i]);
            if (islegendary()) .@atk=false; // Already legendary, so nope
            if (ispcdead()) .@atk=false; // Dead, so nope
            if (!checkweight(Blightbringer, 1)) .@atk=false; // Overweight, so nope
            detachrid();
            // They qualify: Remember this, and look for someone worthier
            if (.@atk) {
                .@mvp=.@pcs[.@i];
                .@def=.@atk;
            }
        } // if qualified
    } // for Loop
    if (.@mvp) {
        attachrid(.@mvp);
        addtimer(10, "Impregnable#B7F::OnBlightbringer");
    }
    stopnpctimer;
    end;

OnBlightbringer:
    // Repeat all checks
    if ($SHADY_HOLDER$ != "") end;
    if (islegendary()) end;
    if (ispcdead()) end;
    inventoryplace Blightbringer, 1;

    $SHADY_HOLDER$ = strcharinfo(0);
    getitembound Blightbringer, 1, 1; // Account bound or char bound? (1 or 4)
    dispbottom l("For defeating the Monster King, you've got the Legendary @@.", getitemlink(Blightbringer));
    dispbottom l("This item cannot be traded normally and is a Legendary Item.");
    dispbottom l("You can transfer it with \"@grantpower\" command. Please contact a GM for more info.");
    dispbottom l("Protip: If you plan in selling it, it's adviseable to ask for GM mediation.");
    end;

}


// Room Traps, only against players
026-7,0,0,0	script	#MKBossTrap01	NPC_TRAP_ONLINE,0,0,{
    end;

OnTouch:
OnTouchNPC:
    WorldHeartTrap();
    sleep(500); // Wait 500ms for animation
    setnpcdisplay .name$, NPC_TRAP_ONLINE;
    // Move the trap away after it disarms (up to 30 attempts)

OnInit:
    .@e=0;
    do {
        if (.@e >= 30)
            break;
        .@x = rand2(21, 60);
        .@y = rand2(21, 60);
        .@e+=1;
    } while (!checknpccell("026-7", .@x, .@y, cell_chkpass));
    movenpc .name$, .@x, .@y;
    end;
}

// Create more traps
026-7,0,0,0	duplicate(#MKBossTrap01)	#MKBossTrap02	NPC_TRAP_ONLINE,0,0
026-7,0,0,0	duplicate(#MKBossTrap01)	#MKBossTrap03	NPC_TRAP_ONLINE,0,0
026-7,0,0,0	duplicate(#MKBossTrap01)	#MKBossTrap04	NPC_TRAP_ONLINE,0,0
026-7,0,0,0	duplicate(#MKBossTrap01)	#MKBossTrap05	NPC_TRAP_ONLINE,0,0
026-7,0,0,0	duplicate(#MKBossTrap01)	#MKBossTrap06	NPC_TRAP_ONLINE,0,0
026-7,0,0,0	duplicate(#MKBossTrap01)	#MKBossTrap07	NPC_TRAP_ONLINE,0,0
026-7,0,0,0	duplicate(#MKBossTrap01)	#MKBossTrap08	NPC_TRAP_ONLINE,0,0
026-7,0,0,0	duplicate(#MKBossTrap01)	#MKBossTrap09	NPC_TRAP_ONLINE,0,0
026-7,0,0,0	duplicate(#MKBossTrap01)	#MKBossTrap10	NPC_TRAP_ONLINE,0,0