summaryrefslogblamecommitdiff
path: root/npc/functions/event.txt
blob: a627788de983f8e22971d799fae85b960ed23f5c (plain) (tree)
1
2
3
4
5
6




                                                              
                                                          

























                                                                               
            
            
            





                                                                                     
                                                          






















                                                                                                                                    
                                   


        
















                                                                             
                                                                   




                                                                  
                         

































                                           
                                   
















                                            
                                    

















                                          
                                    













                                              
                                    
















                                       
                                    









                                      
                                    



                                     
                                    












                                          
                                     













                                               
                                     









                                           
                                     











                                          
                                     







                                             
                                      






                                          
                                      














































                                                                                                                 
                                                  

                                                  


                                                                       

                                                        

                                                        
                                                                     






















                                                                                                         





                                            










                                                       











                                                



















                                                                                                                          



























                                                               

                                                             
                          


                                                          











                                     
                             



                                                                            
               
                               





                                     
               




                                      
                      





















                                                      

                                                     

                                                         
                       







                                                               
                                                         























                                                                                                                        




                                                                                                           



                                                 
 





                                                                                                   
            
         




                      







                                         
                        









                                                                            
                                    






                                             













                                                     
                                    






                                            










                                 
                                                   
                                                     
                                   


                                    



                                                                                                                           
                                                                                                                  
                                          



           





                                         

                     











































                                                                     































                                                                                  
 
 











 


                                                    

















                                                                              
                                           
                                                  
       


























                                                                        

                 
                  
                          
                    


                                  




                                

                                    
                                                         
                                                              




                                          



                       
                                                      
 
                                        
                                                   


                                 

                                                                












                                                                                


                                                                               
                                                                        








                                                     


                              
                                  
                                    
                         


                                                          




                                                             
                                                                

                                             
                                       
                                                                              


                                      
                                                  

                              





                                             
                                                  





                       













                                                                                   

                                         










                                                                          






                                                                                          
                                                                  

                                             
                                          
                                                                                

                          
                                         
                                                    

                              
                              

                                             
                                                                     

                                                            

                                      
                                            
                                                    





                                             
 


                                                       
                                                               
                                                         

                                             
                                                                  
                                                                           

                          
                                                                
                                           

                              
                      

                                      
                                                                    
                                           




                       
 


                                                       
                                                               
                                                             

                                             
                                                                  
                                                                               

                          
                                                                
                                               

                              
                             

                                      
                                                                    
                                               





                       






                                                               
                                                                  


                                                                                 
                                                                
                                                 

                              
                                   
                                                    

                                      
                                                                    






                                                 

                                                                               
                                                  
                                                           
                                                            

                                             
                                                              
                                                                              

                          
                                                            
                                              

                              
                                
                                                      


                                      
                                                                
                                              



                       
                                       


        
// TMW2 scripts.
// Authors:
//    Jesusalva
// Description:
//    Controls world events so Saulc and I can take vacations.
//    See also: seasons.txt, command/event.txt, aurora.txt
//    003-1/events.txt, soulmenhir.txt and, of course, the event maps (if any).
//    Schedule, if needed to change, can be found in the OnInit loop.
//    An event, obviously, cannot last more than 7... 15 days at WORST.
//    Therefore, month checks aren't included in day checks.

-	script	sPatrick	NPC_HIDDEN,{
OnInit:
    setarray .maps$,
                    "005-1",
                    "013-1",
                    "014-1",
                    "014-2",
                    "014-3",
                    "014-4",
                    "014-5",
                    "017-1",
                    "018-2",
                    "018-4",
                    "018-5",
                    "soren";
    end;
OnMyMobDeath:
    end;
OnClock0000:
OnClock6000:
OnClock1200:
OnClock1500:
OnClock1800:
OnClock2100:
    .@d=gettime(GETTIME_DAYOFMONTH);
    // Patrick Day should work only in 2 luck days according to Saulc
    // If this is required use $PATRICK_DAYCTRL so the days before $@PATRICK_DAYMAX
    // act with 100% chances (determinism).
    // As it is being spawn 4 times at a day (like TMW-BR events), because it is
    // flatly and outright IMPOSSIBLE to add a permanent spawn, that is not required.
    if ($EVENT$ == "Patrick" && .@d <= $@PATRICK_DAYMAX) {
        for (.@i=0; .@i < getarraysize(.maps$); .@i++) {
            .@m$=.maps$[.@i];
            .@x=getmapinfo(MAPINFO_SIZE_X, .@m$)-20;
            .@y=getmapinfo(MAPINFO_SIZE_Y, .@m$)-20;

            // Remove previously spawned clovers
            killmonster(.@m$, "sPatrick::OnMyMobDeath");
            // It is one clover for each 225 tiles (about a 25x25 square)
            .@maparea=(.@x-20)*(.@y-20);
            .@mobs=max(1, .@maparea/225);
            areamonster .@m$, 20, 20, .@x, .@y, strmobinfo(1, StPatricksClover), StPatricksClover, .@mobs, "sPatrick::OnMyMobDeath";
        }
    }
    end;

// Remove previously spawned clovers for event end
// And then disables the NPC
OnCleanUp:
    for (.@i=0; .@i < getarraysize(.maps$); .@i++) {
        .@m$=.maps$[.@i];
        killmonster(.@m$, "sPatrick::OnMyMobDeath");
    }
    disablenpc "sPatrick";
    donpcevent "Aurora::OnRestore";
    end;
}

-	script	sDreamTower	NPC_HIDDEN,{
OnWarpTo:
    if ($EVENT$ != "Tower") end;
    if (!countitem(EventDreamTicket)) end;

    // Reset progress
    if (DTOWER_DAY != gettimeparam(GETTIME_DAYOFMONTH) || DTOWER_FLOOR < 1) {
        DTOWER_DAY=gettimeparam(GETTIME_DAYOFMONTH);
        DTOWER_FLOOR=1;
        dispbottom l("A new Dream Tower opens its gates before you...");
    }

    // Create maze and populate
    CreateMaze(IOT_CHAR);
    .@mx=getmapinfo(MAPINFO_SIZE_X, MAZE_MAP$)-20;
    .@my=getmapinfo(MAPINFO_SIZE_Y, MAZE_MAP$)-20;
    .@tl=(20-.@mx)*(20-.@my) * 3 / 10; // Total tiles + collision guess
    .@tl=.@tl / rand2(9,14) + 1; // Monster density is a bit random

    /* *** Copied from 006-5/groata.txt & 018-2-2/main.txt! *** */
    /* ********* Spawn monsters based on DTOWER_FLOOR ********* */
    .@lv = (BaseLevel/10) + DTOWER_FLOOR * 5;
    .@mb[0] = MagicGoblin;
    .@mb[1] = CaveMaggot;

    // Artillery & Chests
    if (.@lv > 10)
        array_push(.@mb, BronzeChest);
    if (.@lv > 20)
        array_push(.@mb, SmallMagicBif);
    if (.@lv > 30)
        array_push(.@mb, Bif);
    if (.@lv > 40)
        array_push(.@mb, RobinBandit);
    if (.@lv > 45)
        array_push(.@mb, SilverChest);
    if (.@lv > 50)
        array_push(.@mb, DustGatling);
    if (.@lv > 55)
        array_push(.@mb, MagicBif);
    if (.@lv > 60)
        array_push(.@mb, DustRifle);
    if (.@lv > 70)
        array_push(.@mb, DustRevolver);
    if (.@lv > 75)
        array_push(.@mb, GoldenChest);
    if (.@lv > 80)
        array_push(.@mb, DustBoss);
    if (.@lv > 85)
        array_push(.@mb, BigMagicBif);
    if (.@lv > 90)
        array_push(.@mb, GreatMoubooSlime);
    if (.@lv > 100)
        array_push(.@mb, Jhon);
    if (.@lv > 105)
        array_push(.@mb, PrismChest);

    // Monsters
    if (is_between2(0, .@lv, 30)) {
        array_push(.@mb, Piou);
        array_push(.@mb, Piousse);
        array_push(.@mb, Squirrel);
        array_push(.@mb, ManaPiou);
        array_push(.@mb, ForestPiou);
        array_push(.@mb, RedButterfly);
        array_push(.@mb, Maggot);
        array_push(.@mb, CandorScorpion);
        array_push(.@mb, HouseMaggot);
        array_push(.@mb, LittleYellowSlime);
        array_push(.@mb, Ratto);
        array_push(.@mb, RudolphSlime);
        array_push(.@mb, MoubooSlime);
        array_push(.@mb, Croc);
        array_push(.@mb, Scorpion);
        array_push(.@mb, SmallFrog);
    }
    if (is_between2(10, .@lv, 40)) {
        array_push(.@mb, BigFrog);
        array_push(.@mb, Lavern);
        array_push(.@mb, LittleRedSlime);
        array_push(.@mb, ChocolateSlime);
        array_push(.@mb, Blub);
        array_push(.@mb, Duck);
        array_push(.@mb, Bat);
        array_push(.@mb, CaveMaggot);
        array_push(.@mb, ManaGhost);
        array_push(.@mb, ManaBug);
        array_push(.@mb, Fluffy);
        array_push(.@mb, FireGoblin);
        array_push(.@mb, ViciousSquirrel);
        array_push(.@mb, RedScorpion);
        array_push(.@mb, WhiteSlime);
        array_push(.@mb, AzulSlime);
        array_push(.@mb, DesertLogHead);
    }
    if (is_between2(20, .@lv, 50)) {
        array_push(.@mb, RedSlime);
        array_push(.@mb, PoisonSpikyMushroom);
        array_push(.@mb, DesertBandit);
        array_push(.@mb, OceanCroc);
        array_push(.@mb, ToppyBlub);
        array_push(.@mb, Sarracenus);
        array_push(.@mb, IceMaggot);
        array_push(.@mb, VampireBat);
        array_push(.@mb, Bandit);
        array_push(.@mb, Pinkie);
        array_push(.@mb, LivingPotato);
        array_push(.@mb, Assassin);
        array_push(.@mb, Skeleton);
    }
    if (is_between2(30, .@lv, 60)) {
        array_push(.@mb, CaveSnake);
        array_push(.@mb, GreenSlime);
        array_push(.@mb, CopperSlime);
        array_push(.@mb, YellowSlime);
        array_push(.@mb, SantaSlime);
        array_push(.@mb, LavaSlime);
        array_push(.@mb, Bluepar);
        array_push(.@mb, DeathCat);
        array_push(.@mb, Moggun);
        array_push(.@mb, SeaSlime);
        array_push(.@mb, RedMushroom);
        array_push(.@mb, Mouboo);
        array_push(.@mb, LogHead);
        array_push(.@mb, CandiedSlime);
        array_push(.@mb, OldSnake);
        array_push(.@mb, GrassSnake);
    }
    if (is_between2(40, .@lv, 70)) {
        array_push(.@mb, GiantMaggot);
        array_push(.@mb, IcedFluffy);
        array_push(.@mb, Snake);
        array_push(.@mb, BlackSlime);
        array_push(.@mb, Tipiou);
        array_push(.@mb, AlphaMouboo);
        array_push(.@mb, Pollet);
        array_push(.@mb, PiouKnight);
        array_push(.@mb, Shrewboo);
    }
    if (is_between2(40, .@lv, 80)) {
        array_push(.@mb, Wolvern);
        array_push(.@mb, FireSkull);
        array_push(.@mb, DarkLizard);
    }
    if (is_between2(50, .@lv, 90)) {
        array_push(.@mb, ArmoredSkeleton);
        array_push(.@mb, BlackScorpion);
        array_push(.@mb, ElectroWorm);
        array_push(.@mb, EarthFairy);
        array_push(.@mb, FireFairy);
        array_push(.@mb, WaterFairy);
        array_push(.@mb, WindFairy);
        array_push(.@mb, PoisonFairy);
        array_push(.@mb, MountainSnake);
        array_push(.@mb, HoodedNinja);
        array_push(.@mb, ForestMushroom);
        array_push(.@mb, GoldenScorpion);
    }
    if (is_between2(60, .@lv, 100)) {
        array_push(.@mb, Yeti);
        array_push(.@mb, FallenGuard1);
        array_push(.@mb, GreenSlimeMother);
        array_push(.@mb, SnowFlower);
        array_push(.@mb, BlueSlimeMother);
        array_push(.@mb, WickedMushroom);
        array_push(.@mb, CopperSlimeMother);
        array_push(.@mb, YellowSlimeMother);
        array_push(.@mb, RedSlimeMother);
        array_push(.@mb, ChocolateSlimeMother);
        array_push(.@mb, WhiteSlimeMother);
        array_push(.@mb, Archant);
        array_push(.@mb, Scar);
    }
    if (is_between2(70, .@lv, 110)) {
        array_push(.@mb, AzulSlimeMother);
        array_push(.@mb, SeaSlimeMother);
        array_push(.@mb, LavaSlimeMother);
        array_push(.@mb, BlackSlimeMother);
        array_push(.@mb, Crafty);
        array_push(.@mb, Forain);
        array_push(.@mb, GreenDragon);
        array_push(.@mb, Michel);
        array_push(.@mb, Troll);
    }
    if (is_between2(80, .@lv, 120)) {
        array_push(.@mb, EliteDuck);
        array_push(.@mb, AzulSkullSlime);
        array_push(.@mb, Moonshroom);
        array_push(.@mb, RedSkullSlime);
        array_push(.@mb, Terranite);
        array_push(.@mb, JackO);
        array_push(.@mb, BlackMamba);
        array_push(.@mb, GreenSkullSlime);
        array_push(.@mb, BloodyMouboo);
        array_push(.@mb, Centaur);
        array_push(.@mb, GoboBear);
    }
    if (is_between2(90, .@lv, 130)) {
        array_push(.@mb, CopperSkullSlime);
        array_push(.@mb, LavaSkullSlime);
        array_push(.@mb, BlackSkullSlime);
        array_push(.@mb, GiantCaveMaggot);
        array_push(.@mb, TerraniteProtector);
        array_push(.@mb, VanityPixie);
        array_push(.@mb, HolyPixie);
    }
    if (is_between2(100, .@lv, 140)) {
        array_push(.@mb, ShadowPixie);
        array_push(.@mb, NulityPixie);
        array_push(.@mb, Reaper);
        array_push(.@mb, NightmareDragon);
        array_push(.@mb, Snail);
        array_push(.@mb, WhirlyBird);
    }
    if (is_between2(110, .@lv, 150)) {
        array_push(.@mb, PinkieSuseran);
        array_push(.@mb, Mandragora);
        array_push(.@mb, PinkieMaximus);
    }
    if (.@lv > 120) {
        array_push(.@mb, Junglefowl);
        array_push(.@mb, Tengu);
        array_push(.@mb, Moubi);
    }
    if (.@lv > 130) {
        array_push(.@mb, SuperiorShroom);
        array_push(.@mb, Nutcracker);
        array_push(.@mb, Golem);
    }
    if (.@lv > 140) {
        array_push(.@mb, SiegeTower);
        array_push(.@mb, GreenhornAbomination);
        array_push(.@mb, ShadowTortuga);
        array_push(.@mb, FireElement);
        array_push(.@mb, WaterElement);
        array_push(.@mb, EarthElement);
        array_push(.@mb, WindElement);
    }
    if (.@lv > 150) {
        array_push(.@mb, SacredWisp);
        array_push(.@mb, EvilWisp);
        array_push(.@mb, PanthomWisp);
        array_push(.@mb, EpiphanyWisp);
    }
    if (.@lv > 175)
        array_push(.@mb, Tortuga);

    /* Spawn them and make hostile */
    freeloop(true);
    for (.@i = 0; .@i < 1+(.@tl); .@i++) {
        .@mid = any_of(.@mb);
        .@m=areamonster(MAZE_MAP$, 20, 20, .@mx, .@my, strmobinfo(1, .@mid), .@mid, 1);
        set_aggro(.@m);
    }
    freeloop(false);

    // Spawn & Configure the boss monster
    .@mob=areamonster(MAZE_MAP$, 20, 20, .@mx, .@my, "Gatekeeper", MonsterSergeant, 1, "sDreamTower::OnBossDie");
    setunitdata(.@mob, UDT_LEVEL, DTOWER_FLOOR * 5);
    setunitdata(.@mob, UDT_STR, DTOWER_FLOOR * 2);
    setunitdata(.@mob, UDT_AGI, DTOWER_FLOOR * 2);
    setunitdata(.@mob, UDT_VIT, DTOWER_FLOOR * 3);
    setunitdata(.@mob, UDT_INT, DTOWER_FLOOR * 1);
    setunitdata(.@mob, UDT_DEX, DTOWER_FLOOR * 3);
    setunitdata(.@mob, UDT_LUK, DTOWER_FLOOR * 2);
    setunitdata(.@mob, UDT_ADELAY, max(640, 1672-(DTOWER_FLOOR * 24)));
    setunitdata(.@mob, UDT_MAXHP,    2000+DTOWER_FLOOR*120);
    setunitdata(.@mob, UDT_HP,       2000+DTOWER_FLOOR*120);
    setunitdata(.@mob, UDT_ATKMIN,   20+DTOWER_FLOOR*4);
    setunitdata(.@mob, UDT_ATKMAX,   40+DTOWER_FLOOR*4);
    setunitdata(.@mob, UDT_DEF,      10+DTOWER_FLOOR*3);
    setunitdata(.@mob, UDT_MDEF,     5+DTOWER_FLOOR);
    setunitdata(.@mob, UDT_HIT,      (BaseLevel+DTOWER_FLOOR)*32/10);
    setunitdata(.@mob, UDT_FLEE,     (BaseLevel+DTOWER_FLOOR)*24/10);
    setunitdata(.@mob, UDT_CRIT,     rand2(40, min(120, 40+DTOWER_FLOOR)));
    // TODO: Spawn more treasure chests? (exp, gp, items)

    // Consume the ticket and begin the maze
    delitem EventDreamTicket, 1;
    InitMaze(3600);
    dispbottom col(l("Reminder : Defeat the %s to win.", b("Gatekeeper")), 2);
    dispbottom l("Mana Plane - Dream Tower, %dº floor. Time limit: 60 minutes or death.", DTOWER_FLOOR);
    end;

// Dream Tower cleared
OnBossDie:
    dispbottom l("Mana Plane - Dream Tower, %dº floor %s", DTOWER_FLOOR, b(l("CLEAR!")));
    DTOWER_FLOOR+=1;
    if ($EVENT$ == "Tower")
        getitem BrokenMedal, 1;
    unitskilluseid(getcharid(3), BS_GREED, 1, getcharid(3));
    sleep2(500);
    teleporthome();
    end;
}

-	script	sThankAeros	NPC_HIDDEN,{
OnInit:
    .users=getusers(1);
    .score=0;
    .event=0;
OnTimer90000:
    // Abort event and reset score
    if (.event && .event < gettimetick(2)) {
        .event=0;
        .score=0;
        $@GM_EVENT=0;
        $@MK_SCENE=MK_NONE;
        killmonsterall("001-1");
        mapwarp("001-1", "000-1", 22, 22, 0);
        announce ("The event is over!"), bc_all|bc_npc;
    }

    // Skip processment until current event ends
    if (.event) {
        initnpctimer;
        end;
    }

    // Stop counting or update scores
    if ($EVENT$ != "Thanksgiving")
        end;
    .users=getusers(1);
    .score+=.users;

    // Do event (lasts 30 minutes)
    if (!.event && !$@MK_SCENE && .score > 300 && .users > 3) {
        /* Reserve Aeros */
        $@MK_SCENE=MK_LOCKED;
        /* Setup the event */
        $@AEROS_SPWN=(.users > 6 ? 2 : any(0, 1));
        $@AEROS_AUTOSPAWN=.users+rand2(1, .users);
        donpcevent("Mana Being#001-1::OnAutoSched");
        /* Open the event */
        $@GM_EVENT = 2;
        .event = gettimetick(2) + 1800;
        announce ("The mana bridge to Aeros is open! To participate on event, talk to ##BSoul Menhir##b!"), bc_all|bc_npc;
        announce ("##1THANKSGIVING SPECIAL. TIME LIMIT: ##B30 MINUTES.##b##0"), bc_all|bc_npc;
        channelmes("#world", "An event is happening on Aeros! Hurry up!");
    }

    initnpctimer;
    end;
}

function	script	sThanksgiving	{
    // Variables:
    // #THANKS_DAY
    // #THANKS_STREAK
    // @thanks_card

    // Already spinned
    if (#THANKS_DAY == gettime(5) || $EVENT$ != "Thanksgiving")
        return;

    // Not spinned yet
    showavatar 1102;
    mes l(".:: Thanksgiving ::.");
    mesc l("Spin daily the card to get prizes!");

    select
        l("SPIN!"),
        l("Later");
    mes "";
    if (@menu == 2) {
        setskin "";
        closeclientdialog;
        return;
    }
    // Spin it
    // Your prize is saved in .@luck. Rigged against fruits
    .@luck=rand2(0,11);
    .@luck=(.@luck == 10 ? rand2(0,11) : .@luck);
    // A fruit before 10 days: rig to Arcmage or to blueprint
    if (.@luck == 10 && #THANKS_STREAK < 10)
        .@luck+=any(-1,1);
    // A fruit before 20 days: Lower chances from 4% to 2%
    if (.@luck == 10 && #THANKS_STREAK < 20)
        .@luck=rand2(0,11);
    // Extra spins
    .@extra=rand2(1,3);
    .@spins=.@extra*11+.@luck;
    //.@extra=0;

    // Show the spins
    for (.@i=0;.@i<=.@spins;.@i++) {
        .@cur=(.@i%11);
        showavatar 1103+.@cur;
        sleep2(60);
    }
    mes l(".:: Congratulations ::.");
    #THANKS_DAY = gettime(5);
    #THANKS_STREAK+=1;
    if (debug || $@GM_OVERRIDE) {
        mes l("You got a %d", .@luck);
        mesf "Spins: %d/%d (cur %d extra %d)", .@i, .@spins, .@cur, .@extra;
        mes "";
        //.@luck=$@GM_OVERRIDE;
    }

    // Switch the reward
    switch (.@luck) {
    case 0: // EXP
        .@p=BaseLevel*#THANKS_STREAK;
        .@p*=3;
        getexp .@p, 0;
        mes l("You got %d EXP!", .@p);
        break;
    case 1: // JEXP
        .@p=BaseLevel*#THANKS_STREAK;
        .@p=.@p*15/10;
        getexp 0, .@p;
        mes l("You got %d JEXP!", .@p);
        break;
    case 2: // GP
        .@p=BaseLevel*#THANKS_STREAK;
        Zeny+=.@p;
        mes l("You got %d GP!", .@p);
        break;
    case 3: // MOBPT
        .@p=BaseLevel*#THANKS_STREAK;
        Mobpt+=.@p;
        mes l("You got %d Monster Points!", .@p);
        break;
    case 4: // RES
        .@p=BaseLevel*#THANKS_STREAK;
        .@p*=3;
        REAL_ESTATE_CREDITS+=.@p;
        mes l("You got %d Real Estate Credits!", .@p);
        break;
    case 5: // GIFT
        .@p=BronzeGift;
        .@p=(#THANKS_STREAK > 7 ? SilverGift : .@p);
        .@p=(#THANKS_STREAK > 15 ? GoldenGift : .@p);
        .@p=(#THANKS_STREAK > 22 ? PrismGift : .@p);
        .@p=(#THANKS_STREAK > 27 ? SupremeGift : .@p);
        mes l("You got a(n) %s gift!", getitemlink(.@p));
        getitem .@p, 1;
        break;
    case 6: // STR C
        .@p=#THANKS_STREAK;
        getitem StrangeCoin, .@p;
        mes l("You got %d %s!", .@p, getitemlink(StrangeCoin));
        break;
    case 7: // HERO C
        .@p=#THANKS_STREAK;
        .@p+=getq2(LoFQuest_HH)*max(1,#THANKS_STREAK/10);
        getitem HeroCoin, .@p;
        mes l("You got %d %s!", .@p, getitemlink(HeroCoin));
        break;
    case 8: // MERC
        .@p=any(MercCard_GonzoDark, MercCard_Rosa, MercCard_Soren, MercCard_Apane);
        .@p=(#THANKS_STREAK > 7 ? any(MercCard_EarthWitch, MercCard_Demure, MercCard_Jesusalva, MercCard_Pookie) : .@p);
        .@p=(#THANKS_STREAK > 14 ? any(MercCard_Arthur, MercCard_LawnCable, MercCard_Crazyfefe, MercCard_Saulc) : .@p);
        .@p=(#THANKS_STREAK > 21 ? any(MercCard_Swezanne, MercCard_DragonStar, MercCard_Msawis, MercCard_Aisen) : .@p);
        .@p=(#THANKS_STREAK > 27 ? any(MercCard_Xanthem, MercCard_Woody, MercCard_Lilanna) : .@p);
        getitem .@p, 1;
        mes l("You got a %s!", getitemlink(.@p));
        break;
    case 9: // CARD
        .@p=any(NatureCard, NinjaCard, MageCard, DruidCard, ClericCard, KnightCard, HeroCard, NecromancerCard);
        .@p=(#THANKS_STREAK > 24 ? any(SpeedCard, ReflectCard, PowerCard, WallCard) : .@p);
        getitem .@p, 1;
        mes l("You got a %s!", getitemlink(.@p));
        break;
    case 10: // FRUIT
        .@p=MysteriousFruit;
        getitem .@p, 1;
        mes l("You got a %s!", getitemlink(.@p));
        break;
    case 11: // BLUE
        .@p=any(EquipmentBlueprintA, EquipmentBlueprintA, AlchemyBlueprintA);
        .@p=(#THANKS_STREAK > 7 ? any(EquipmentBlueprintB, EquipmentBlueprintB, AlchemyBlueprintB) : .@p);
        .@p=(#THANKS_STREAK > 14 ? any(EquipmentBlueprintC, EquipmentBlueprintC, AlchemyBlueprintC) : .@p);
        .@p=(#THANKS_STREAK > 21 ? any(EquipmentBlueprintD, EquipmentBlueprintD, AlchemyBlueprintD) : .@p);
        .@p=(#THANKS_STREAK > 27 ? any(EquipmentBlueprintE, EquipmentBlueprintE, AlchemyBlueprintE) : .@p);
        getitem .@p, 1;
        mes l("You got a %s!", getitemlink(.@p));
        break;
    }

    // Special bonus
    if (#THANKS_STREAK % 7 == 0) {
        getitem StrangeCoin, 10;
        mesc l("%d day streak! Gained %d bonus %s!", #THANKS_STREAK, 10, getitemlink(StrangeCoin));
    }

    // Close
    next;
    setskin "";
    closeclientdialog;
    return;
}

// ChocolateDay()
function	script	ChocolateDay	{
    if (!playerattached())
        return;

    // Date check
    if (gettime(6) != JULY)
        return;
    if (gettime(5) != 7)
        return;

    // Max. 80% chances, 0.4% per monster level
    .@lv=min(200, getmonsterinfo(killedrid, MOB_LV));
    if (rand2(10000) < (.@lv*40)) {
        // Chocolate Bar: 73%; Chocolate Dye: 6.7%
        .@choco=any(ChocolateBar, ChocolateBar, ChocolateBar, ChocolateBar,
                    ChocolateMouboo, ChocolateBiscuit, ChocolateBunny,
                    ChocolateBar, ChocolateBar, ChocolateBar, ChocolateBar,
                    ChocolateDye, ChocolateBar, ChocolateBar, ChocolateBar);
        getmapxy(.@m$, .@x, .@y, 0);
        .@x+=rand2(-1,1);
        .@y+=rand2(-1,1);
        makeitem(.@choco, 1, .@m$, .@x, .@y);
    }
    return;
}

// CoffeeDay()
function	script	CoffeeDay	{
    if (!playerattached())
        return;

    // Date check
    if (gettime(6) != OCTOBER)
        return;
    if (gettime(5) != 1)
        return;

    // Max. 22% chances, 0.1% per monster level
    .@lv=min(200, getmonsterinfo(killedrid, MOB_LV));
    if (rand2(10000) < (.@lv*11)) {
        getmapxy(.@m$, .@x, .@y, 0);
        .@x+=rand2(-1,1);
        .@y+=rand2(-1,1);
        makeitem(Coffee, 1, .@m$, .@x, .@y);
    }
    return;
}

// FSFDay()
function	script	FSFDay	{
    if (!playerattached())
        return;

    // Date check
    if (gettime(6) != SEPTEMBER)
        return;
    if (gettime(5) != 9)
        return;

    // Max. 0.16% chances, 0.008% per monster level
    .@lv=min(200, getmonsterinfo(killedrid, MOB_LV));
    if (rand(1000000) < (.@lv*8)) {
        getmapxy(.@m$, .@x, .@y, 0);
        .@x+=rand2(-1,1);
        .@y+=rand2(-1,1);
        // Ancient 50%, Equipment 25%, Alchemy 25%
        .@bp = any(AncientBlueprint, AncientBlueprint, AncientBlueprint, AncientBlueprint, AncientBlueprint,
                   AncientBlueprint, AncientBlueprint, AncientBlueprint, AncientBlueprint, AncientBlueprint,
                   EquipmentBlueprintA, EquipmentBlueprintB, EquipmentBlueprintC, EquipmentBlueprintD, EquipmentBlueprintE,
                   AlchemyBlueprintA, AlchemyBlueprintB, AlchemyBlueprintC, AlchemyBlueprintD, AlchemyBlueprintE);
        makeitem(.@bp, 1, .@m$, .@x, .@y);
    }
    return;
}

// CraftmasterDay()
function	script	CraftmasterDay	{
    if (!playerattached())
        return;

    // Date check
    if (!$BETASERVER)
        return;
    if (gettime(7) != 2021)
        return;
    if (gettime(6) != JUNE)
        return;
    if (gettime(5) != 21)
        return;
    if (getmap() != "018-3")
        return;

    // Scored a Blue Print (2.5%)
    if (rand2(10000) < 250) {
        if (BaseLevel > 80 && REBIRTH)
            getitem any(EquipmentBlueprintE, AlchemyBlueprintE,
                        EquipmentBlueprintD, AlchemyBlueprintD,
                        EquipmentBlueprintC, AlchemyBlueprintC,
                        EquipmentBlueprintB, AlchemyBlueprintB,
                        EquipmentBlueprintA, AlchemyBlueprintA), 1;
        else if (BaseLevel > 70)
            getitem any(EquipmentBlueprintD, AlchemyBlueprintD,
                        EquipmentBlueprintC, AlchemyBlueprintC,
                        EquipmentBlueprintB, AlchemyBlueprintB,
                        EquipmentBlueprintA, AlchemyBlueprintA), 1;
        else if (BaseLevel > 45)
            getitem any(EquipmentBlueprintC, AlchemyBlueprintC,
                        EquipmentBlueprintB, AlchemyBlueprintB,
                        EquipmentBlueprintA, AlchemyBlueprintA), 1;
        else if (BaseLevel > 20)
            getitem any(EquipmentBlueprintB, AlchemyBlueprintB,
                        EquipmentBlueprintA, AlchemyBlueprintA), 1;
        else
            getitem any(EquipmentBlueprintA, AlchemyBlueprintA), 1;
        return;
    }

    // Scored Monster Points (9%)
    if (rand2(10000) < 900) {
        .@mpt=rand2(BaseLevel*10, BaseLevel*100); // 600~6000 usually
        Mobpt+=.@mpt;
        dispbottom l("Acquired: %s Monster Points", fnum(.@mpt));
        return;
    }

    // Autocraft (1%)
    if (rand2(10000) < 100) {
        .@rc=any(rand2(51, 62), 65, 66, rand2(72, 76), rand2(77, 81), 82, 98,
                 99, 100, rand2(93, 97), rand2(88, 91), rand(83, 87), 92, 101,
                 rand2(102,117), any(122, 112), rand2(125, 134), rand2(135, 143));
        // Retrieve ID
        .@it=getcraftcode(.@rc);
        if (.@it <= 0)
            return;
        // Mark the crafting in your score variable
        CRAFTING_SCORE_COMPLETE+=getiteminfo(.@it, ITEMINFO_ELV);
        // Update your score book
        CRAFTING_SCORE=(CRAFTING_SCORE_COMPLETE/40);
        // Receive item
        getitembound(.@it, 1, 1);
        // Apply options if possible
        if (getskilllv(TMW2_CRAFT)) {
            delinventorylist(); // Needed, because we'll rely on rfind()
            getinventorylist();
            .@index=array_rfind(@inventorylist_id, .@it);

            // Just to be sure, if this have an option, get something else
            if (getitemoptionparambyindex(.@index, 0)) {
                .@index=array_find(@inventorylist_id, .@it);
            }

            callfunc("csys_Apply", .@index);
        }
        dispbottom l("Successfully Crafted: %s", getitemname(.@it));
        return;
    }
    return;
}















000-0,0,0,0	script	#EventCore	NPC_HIDDEN,{
    end;

// confEvent(event ID, stday, stmon, endday, endmon)
function confEvent {
    setd("."+getarg(0)+"_stday", getarg(1));
    setd("."+getarg(0)+"_stmon", getarg(2));
    setd("."+getarg(0)+"_endday", getarg(3));
    setd("."+getarg(0)+"_endmon", getarg(4));
    // Save the event key?
    //.@confname=".conf_"+getarg(2)+"$";
    //setd(.@confname+"["+getarraysize(.@confname)+"]", getarg(0));
    // Save only the day? (And use if statement)
    .@confname$=".conf_"+getarg(2);
    .@size=getarraysize(getd(.@confname$));
    setd(.@confname$+"["+.@size+"]", getarg(1));
    //debugmes "CONFIGURE EVENT, %s[%d] = %d", .@confname$, .@size, getarg(1);
    //debugmes "CNAME: %s", getarg(0);
    return;
}

// Event Schedule (all dates are inclusive)
// NEVER, ever, include the last day of the month.
OnInit:
    confEvent("valentine",
              13, FEBRUARY,
              16, FEBRUARY);

    confEvent("tmw2day",
              1, MARCH,
              7, MARCH);

    confEvent("patrick",
              15, MARCH,
              19, MARCH);

    confEvent("easter",
              17, APRIL,
              24, APRIL);

    confEvent("worker",
              27, APRIL,
              3, MAY);

    confEvent("thanks",
              1, NOVEMBER,
              29, NOVEMBER); // NEVER use the last day of the month here

    confEvent("xmas",
              19, DECEMBER,
              2, JANUARY);

    // Some setup
    .@isinit=true;
    disablenpc "sPatrick";
    FYE_Normalize();

// Check for events every midnight
OnClock0000:
    // No events on test server
    if (debug && !$@GM_OVERRIDE)
        end;

    // Prepare variables
    .@d=gettime(GETTIME_DAYOFMONTH);
    .@m=gettime(GETTIME_MONTH);
    .@o=gettime(GETTIME_WEEKDAY); // Resets at 0 (sunday)
    debugmes "A new day begins! Today is %02d/%02d", .@d, .@m;

    // Override the server-wide randomness
    resetrng();

    // Initialize the event core
    if ($@DEBUG_OD)
        .@d=$@DEBUG_OD;
    if ($@DEBUG_OM)
        .@m=$@DEBUG_OM;
    consoleinfo "EVENT CORE, the %02d/%02d", .@d, .@m;

    // Is there another event this week?
    if (!$HARDCORE && .@o == MONDAY && !.@isinit) {
        .@dofy=true;
        .@confname$=".conf_"+.@m;

        // NOTE: Maybe make a single .annuals array and cycle it
        // Gather the ST variable from interest...?
        for (.@i=0;.@i < getarraysize(getd(.@confname$)); .@i++) {
            .@val=getd(.@confname$+"["+.@i+"]");
            //debugmes "Looping, %d = %d", .@i, .@val;

            // Erm.
            if (.@val == 0)
                continue;

            // This script has a weakness: It cannot predict events starting
            // at the start or the end of the month.
            // So they might still overlap.
            // A possible solution is to, eventually, record start and end date.
            // And only inhibit FY event if the MONDAY is within the event...?
            // XXX: Now it inhibits by itself; But it should NOT begin a FYE if
            // another (annual) event is scheduled for the same week.
            // Namely: TMW2 Day and Thanksgiving
            debugmes "%d >= %d && %d <= %d", .@val, .@d-6, .@val, .@d+6;
            // In this case there's already an event!
            // .@d == .@val <= .@d+6 AND
            if ( .@val >= .@d-6 && .@val <= .@d+6 ) {
                .@dofy=false;
                break;
            }
            // continue...
        }

        // Stop previous event
        FYStopEvent();

        // Trigger event framework
        if (.@dofy && $EVENT$ == "")
            FYNewEvent();
        else
            debugmes "\033[1mAnother event is scheduled!";
    }

    // Handle Valentine Day
    if (.@m >=.valentine_stmon && .@m <= .valentine_endmon) {
        // It's tomorrow: Send out an announcement
        if (.@d == .valentine_stday - 1) {
            kamibroadcast("Valentine Day will start tomorrow!");
        }
        // Last Day: Send out an announcement
        if (.@d == .valentine_endday) {
            kamibroadcast("It's the last day for Valentine Event! Hurry up!");
        }
        // Begin the event
        if (.@d == .valentine_stday) {
            kamibroadcast("Valentine Day begun!");
            if ($EVENT$ != "")
                FYStopEvent();
            $EVENT$="Valentine";
            $@VALENTINE_LOVELETTER = htnew();
            $@VALENTINE_GIFTSTACKS = htnew();
        }
        // End the event the day after
        if (.@d == .valentine_endday+1) {
            kamibroadcast("Valentine Day ended!");
            sClear();
            $EVENT$="";
        }
    }



    // Handle TMW2 Day
    if (.@m >=.tmw2day_stmon && .@m <= .tmw2day_endmon) {
        // It's tomorrow: Send out an announcement
        if (.@d == .tmw2day_stday - 1) {
            kamibroadcast("Moubootaur Legends Anniversary will start tomorrow!");
        }
        // Last Day: Send out an announcement
        if (.@d == .tmw2day_endday) {
            kamibroadcast("It's the last day of our Anniversary Event! Hurry up!");
        }
        // Begin the event
        if (.@d == .tmw2day_stday) {
            kamibroadcast("Moubootaur Legends Anniversary Event begun!");
            if ($EVENT$ != "Anniversary")
                $BCONFB_EXPR+=50;
            $EVENT$="Anniversary";
        }
        // End the event the day after
        if (.@d == .tmw2day_endday+1) {
            kamibroadcast("Our Special Anniversary Event ended! Thanks!");
            sClear();
            $EVENT$="";
        }
    }


    // Handle St. Patrick Day
    // During this day, a special four leaf clover is spawned daily, at 4 times in the day
    // in all forests: 6:00, 12:00, 18:00 and 00:00.
    // $PATRICK_DAYMAX
    if (.@m >=.patrick_stmon && .@m <= .patrick_endmon) {
        // It's tomorrow: Send out an announcement
        if (.@d == .patrick_stday - 1) {
            kamibroadcast("St. Patrick Day will start tomorrow!");
        }
        // Last Day: Send out an announcement
        else if (.@d == .patrick_endday) {
            kamibroadcast("It's the last day for St. Patrick Event! Hurry up!");
        }
        // Begin the event
        else if (.@d == .patrick_stday) {
            kamibroadcast("St. Patrick Day begun!");
            if ($EVENT$ != "")
                FYStopEvent();
            $EVENT$="Patrick";
            $@PATRICK_DAYMAX=.patrick_endday;
            enablenpc "sPatrick";
            setnpcdisplay("Aurora", "Patrick Saulc", NPC_WEIRDGREEN);
            enablenpc "St. Patrick Gold Pot";
            donpcevent "St. Patrick Gold Pot::OnForcedMove";
        }
        // End the event the day after
        else if (.@d == .patrick_endday+1) {
            kamibroadcast("St. Patrick Day ended!");
            sClear();
            $EVENT$="";
            donpcevent "sPatrick::OnCleanUp";
        }
    }


    // Handle Easter
    if (.@m >=.easter_stmon && .@m <= .easter_endmon) {
        // It's tomorrow: Send out an announcement
        if (.@d == .easter_stday - 1 && .@m == .easter_stmon) {
            kamibroadcast("Easter will start tomorrow!");
        }
        // Last Day: Send out an announcement
        else if (.@d == .easter_endday && .@m == .easter_endmon) {
            kamibroadcast("It's the last day for Easter Event! Hurry up!");
        }
        // Begin the event
        else if (.@d == .easter_stday && .@m == .easter_stmon) {
            kamibroadcast("Easter begun!");
            if ($EVENT$ != "")
                FYStopEvent();
            sEaster();
        }
        // End the event the day after
        else if (.@d == .easter_endday+1 && .@m == .easter_endmon) {
            kamibroadcast("Easter ended!");
            sClear();
            $EVENT$="";
        }
    }


    // Handle Worker Day
    if (.@m >=.worker_stmon && .@m <= .worker_endmon) {
        // It's tomorrow: Send out an announcement
        if (.@d == .worker_stday - 1 && .@m == .worker_stmon) {
            kamibroadcast("Worker Day will start tomorrow!");
        }
        // Last Day: Send out an announcement
        else if (.@d == .worker_endday && .@m == .worker_endmon) {
            kamibroadcast("It's the last day for Worker Day Event! Hurry up!");
        }
        // Begin the event
        else if (.@d == .worker_stday && .@m == .worker_stmon) {
            kamibroadcast("Worker Day begun!");
            if ($EVENT$ != "")
                FYStopEvent();
            $EVENT$="Worker";
        }
        // End the event the day after
        else if (.@d == .worker_endday+1 && .@m == .worker_endmon) {
            kamibroadcast("Worker Day ended!");
            sClear();
            $EVENT$="";
        }
    }


    // Handle Thanksgiving Day
    if (.@m >=.thanks_stmon && .@m <= .thanks_endmon) {
        // It's tomorrow: Send out an announcement
        if (.@d == .thanks_stday - 1 && .@m == .thanks_stmon) {
            kamibroadcast("Thanksgiving will start tomorrow!");
        }
        // Last Day: Send out an announcement
        else if (.@d == .thanks_endday && .@m == .thanks_endmon) {
            kamibroadcast("It's the last day for Thanksgiving Event! Hurry up!");
        }
        // Begin the event
        else if (.@d == .thanks_stday && .@m == .thanks_stmon) {
            kamibroadcast("Thanksgiving begun!");
            if ($EVENT$ != "")
                FYStopEvent();
            $EVENT$="Thanksgiving";
            donpcevent("sThankAeros::OnTimer90000");
        }
        // End the event the day after
        else if (.@d == .thanks_endday+1 && .@m == .thanks_endmon) {
            kamibroadcast("Thanksgiving ended!");
            sClear();
            $EVENT$="";
        }
    }


    // Handle Christmas. It goes past the year so the rule is different, BEWARE
    if (.@m == .xmas_stmon || .@m == .xmas_endmon) {
        // It's tomorrow: Send out an announcement
        if (.@d == .xmas_stday - 1 && .@m == .xmas_stmon) {
            kamibroadcast("Christmas will start tomorrow!");
        }
        // Last Day: Send out an announcement
        else if (.@d == .xmas_endday && .@m == .xmas_endmon) {
            kamibroadcast("It's the last day for Christmas Event! Hurry up!");
        }
        // Begin the event
        else if (.@d == .xmas_stday && .@m == .xmas_stmon) {
            kamibroadcast("Christmas begun!");
            if ($EVENT$ != "")
                FYStopEvent();
            $EVENT$="Christmas";
            DelQuestFromEveryPlayer(SQuest_Christmas);
            sChristmas();
        }
        // End the event the day after
        else if (.@d == .xmas_endday+1 && .@m == .xmas_endmon) {
            kamibroadcast("Christmas ended!");
            sClear();
            $EVENT$="";
        }
    }
    debugmes "EVENT CORE has finished";
    end;
}