summaryrefslogblamecommitdiff
path: root/conf/magic.conf.template
blob: 40105567a0234db6ba7b54b9f74414a598fd49f4 (plain) (tree)
























                           
                                     
                                                                                                                                                 
                                     





                                     



                            
                            


                            



                            
                                
 



                                       




                                    

                                   
               
 

                                      
 





                                             
 


                                                                                                                          



                                                                                                                                      

                                                                                                           
                                                                                                                             
                

                                                 

                                                                                             
           

                                                                                                         
 

















                                                                                                                             
                      



                                                                             
                         



















                                                                                                     

                                                       
                                                                                           
                                                                                        
                                             



                                                                        

                                                     
                                                         
                                                   

                                  
                                
                             
                                        





                                                          
                                
                             
                                        






















                                                                                                                                                                         


                                               



                                                                              
                                

                                                                                    
                                                                           




                                                                              

                                             
                     
                                            



                                                                                                            
 



                                                                                 




















                                                                                                
                                                                                                                                                                                               

                                  
                                                                                       
                                      


                                                                                                    
                                      


                                                                                      
                                      


                                                                                                   
                                      





                                                                                                                         
                 








                                                                                                                                            
 
                                                           



                                               
                                











                                                                                              
 




                                               


                                                   
                                                                                                                                        


                                              

                       
                               

                                                     
                                                                                                                              
                                     
                                                   
                                          
                                         


                                                                                                                  
                                                  



                                                                                                                             
                                           
                                    

 
                           

                      
                                


                                                                              
                                          
                                                  
                                                         
                                                                  

                                                
                                    

                                                                                               
 

                            

                      
                               


                                                               
                                                         
                                                                                            

                                                                                     

                                                               
                                                         
                                                                                            

                                                                                     
              
 
                          

                         
                                
                                               
                                                   
                                          



                                                                                        
 
                           


                                




                                                   
                                                                                                    









                                                   
                                                                                                    









                                                   
                                                                                                    









                                                   
                                                                                                    
 
 
                                     

                         
                                  
                                               
                                             
                                                   














                                                                                       
                                                                                                   



                                                                





                                                                                 
                            

                            
                                



                                                   
                                          
                                                                                                                               
                                    
 
                           

                            
                                 



                                                   
                                          
                                                                           
                                    
 
                             

                            
                                 



                                                   
                                          
                                                                       
                                    
 
                                   

                            
                                 



                                                   
                                          
                                                                            













                                                                                                                                    











                                                                                                                                                

                                                                                       











                                                                          


                                                                                       


                                    





                                                   
                                                





                                                                                                                
                                                 
                                                          
                                         








                                                                                                                  
                                    


                                                                  


                                                                                                       
 




                                                                   
                                                      





                                                                                 

                      
                                 



                                                                           


                                                                  

                                                     
                                    
                                                 



                                                                                              





                                                                     










                                                                                                                                       

                                                                                                           
                                 

                      
                                 

                                                




                                                                              
 

                                                                                       






                                                                                                         


                                                
                                       












                                                                                                                
                                                       
                  
 
                               







                                                                     


                                                                             
 
                                              




                                                
                                                                           

                                                                                      
                                      



                                                                                                                              
                                


                                                                          
                                      

                         
                                 






                                                                                      
                                           
                                                                                                                         
                                                             
                                


                                                            











                                                                                       
 
                           

                         
                                 

                                                
                                                

                                                                              
                                      




                                                                                                 
                                
                                                                                  
                                                     


                                                                    


                                                

                                                                    
                                                         
                                                   

                                                                     
                                                                                            
                     
                                           

                  

                                                         


                                                                                    

                                                                  

                                                                                   
                                                                                       
          

                                                                                

                                                                                   
                                                                                                             

















                                                                                                           
                                                                                                 
                                                                                                 






                                                                                                     

                                                                               



                     
                                      
                   

                                 

                                                
                                                                              

                                                                                      
                                            
                                     
                                           
                                                                                                                     
                                                                             
                                
                                                                    
                                             

 
                                             

                         
                                  

                                                
                                           
                                                   
                                          
                                    
                                                                                                                
 
                                      

                         
                                  

                                                
                                          
                                                   
                                          
                                    
                                                                                                                                   

 
                               

                        
                               


                                                   
                                          

                                                                               

                                                                               









                                                                                












                                                                              
 
                                  
                   

                                 
                                               
                                                

                                                                                     
                                                   
                                          
                                                        
                                    
 


































                                                                                                                       
                     
 













                                                                                       
                                                   
                                                                               
                                                             




                                                                                 


















                                                                  
                          























                                                                                                                                          
                                




                                                

                                                     
                                                 
                                        







                                                                                                    

                                                                                                                         












                                                                                  
                        
                   
                         


                                                
                                        

                                       








                                                 
                                                           



                                                                     
                                                                                 


















                                                                                                           


                                                                                                          



                                                                                                           
                                                                                                                                                           





                                                                                                          
                                                                                                             










                                                                                                 

                                                                                                 
                                                                                               













                                                                                              

                                                                                              



                                                                                          
                                                                                            




                                                                                          
                                                                                              

















                                                  







                                                    






                                                                 
 
                                                                                 




                                                                                 

                                                                           




































                                                                                                                      
                      




                                                                                          










































                                                                                                                                                       
 









                                                                                  
                                                                                    








                                                                                 






                                                      

                                                       


























                                                                                                                               








                                                                                 





                                                                        

 
# Special-purpose globals
obscure_chance = 95
min_casttime = 200

# Schools of magic
CONST MAGIC	= 340
CONST LIFE	= 341
CONST WAR 	= 342
CONST TRANSMUTE	= 343
CONST NATURE	= 344
CONST ASTRAL	= 345

# Elements
CONST ELT_NEUTRAL	= 0
CONST ELT_WATER		= 1
CONST ELT_EARTH		= 2
CONST ELT_FIRE		= 3
CONST ELT_WIND		= 4
CONST ELT_POISON	= 5
CONST ELT_SHADOW	= 6
CONST ELT_HOLY		= 7
CONST ELT_GHOST		= 8
CONST ELT_UNDEAD	= 9

# Schools of magic
CONST SC_POISON			= 132
CONST SC_SHEARED		= 194 # This is the same as SC_HIDE, since mobs can't hide and shearing is only used for mobs.  Feel free to fix!
CONST SC_HIDE			= 194
CONST SC_HALT_REGENERATE	= 195
CONST SC_FLYING_BACKPACK	= 196
CONST SC_MBARRIER		= 197
CONST SC_HASTE			= 198
CONST SC_PHYS_SHIELD		= 199

# Special effects
CONST SFX_DEFAULT	= 10
CONST SFX_SUMMON_START	= 21
CONST SFX_SUMMON_FIRE	= 22
CONST SFX_TELEPORT	= 24
CONST SFX_RAIN		= 25
CONST SFX_HIT		= 25
CONST SFX_ARROW_HAIL	= 27
CONST SFX_BARRIER	= 10
CONST SFX_UNBARRIER	= 10
CONST SFX_HEAL		= 3

CONST MAX_RAIN_SPELL_RADIUS = 15

CONST MAGIC_FLAGS = "MAGIC_FLAGS"
CONST MFLAG_MADE_CONC_POTION = 16384
CONST MFLAG_MADE_CONC_POTION_SHIFT = 14

CONST SCRIPT_XP = "MAGIC_EXPERIENCE"
CONST SCRIPT_XP_MASK  = 0xffff
CONST SCRIPT_XP_SHIFT = 0
CONST SCRIPT_LASTSPELL_MASK  = 0xff
CONST SCRIPT_LASTSPELL_SHIFT = 16
CONST SCRIPT_HEALSPELL_MASK  = 0xff
CONST SCRIPT_HEALSPELL_SHIFT = 24
CONST DEBUG = 0

CONST ATTACK_ICON_GENERIC	= 2000
CONST ATTACK_ICON_SHEARING	= 2001

# Default sfx on caster
PROCEDURE default_effect() =
          sfx(caster, school - MAGIC + 2, 0);

PROCEDURE sfx_generic(target) =
          sfx(target, SFX_DEFAULT, 0);

PROCEDURE set_var(name, mask, shift, value) =
          set_script_variable(caster, name, script_int(caster, name) & (neg (mask << shift)) | ((value & mask) << shift));

PROCEDURE gain_heal_xp(value, # How many HP we healed
                       gain,  # how many life magic experience points we can potentially gain
                       heal_xp_value_divisor,  # 1 for instaheal, 2 for slow heal
                       base_exp_factor) =      # factor for how many base experience points (max) the player should be allowed to gain
          last_heal_xp = (script_int(caster, SCRIPT_XP) >> SCRIPT_HEALSPELL_SHIFT) & SCRIPT_HEALSPELL_MASK;
          IF (target <> caster
              && (value / heal_xp_value_divisor) > (10 + last_heal_xp + random(last_heal_xp + 1) + random(last_heal_xp + 1)))
          THEN (
             heal_xp = last_heal_xp + gain;
             IF (heal_xp > SCRIPT_HEALSPELL_MASK)
             THEN heal_xp = SCRIPT_HEALSPELL_MASK;
             CALL set_var(SCRIPT_XP, SCRIPT_HEALSPELL_MASK, SCRIPT_HEALSPELL_SHIFT, heal_xp);
          )
          IF target <> caster
          THEN gain_experience(caster, base_exp_factor * extract_healer_experience(target, value), 0, 1);

PROCEDURE gain_xp(gain) =
          IF (level + 3 > skill(caster, MAGIC)) # Level 4 and 5 magic users don't gain anything from spell levels 0 resp. 0+1
          THEN (
                index = spell_index(self_spell);
                last_index = (script_int(caster, SCRIPT_XP) >> SCRIPT_LASTSPELL_SHIFT) & SCRIPT_LASTSPELL_MASK;
                last_xp = (script_int(caster, SCRIPT_XP) >> SCRIPT_XP_SHIFT) & SCRIPT_XP_MASK;
                IF (index != last_index)
                THEN ( # Some variation observed
                     xp = last_xp + gain;
                     IF (xp > SCRIPT_XP_MASK)
                     THEN xp = SCRIPT_XP_MASK;
                     CALL set_var(SCRIPT_XP, SCRIPT_XP_MASK, SCRIPT_XP_SHIFT, xp);
                     CALL set_var(SCRIPT_XP, SCRIPT_LASTSPELL_MASK, SCRIPT_LASTSPELL_SHIFT, index);
                     IF DEBUG THEN message(caster, "Spell xp = " + xp);
                ) ELSE IF DEBUG THEN message(caster, "Re-cast same spell, xp remain at " + last_xp);
          )

PROCEDURE create_item(good_item, count, bad_item, difficulty) =
          success = 1;
          score = experience + random(min(spellpower, (experience / 3) + 1));
          IF (score >= difficulty)
          THEN create_item(caster, good_item, count);
          ELSE (
             success = 0;
             score = score + random(luk(caster)) + random(luk(caster));
             IF (score < difficulty / 3)
             THEN (
               message(caster, "Your spell backfires!");
               IF (random(110) < (luk(caster)))
               THEN itemheal(caster, 0 - ((level + 1) * (level + 2) * (3 + random(28))), 0);
               ELSE itemheal(caster, 0 - (level + 1), 0);
             ) ELSE IF (score < (difficulty * 2) / 3)
             THEN (
               IF random(5) = 0
               THEN (message(caster, "Your spell solidifies into the shape of a mysterious object!");
                     create_item(caster, "Iten", 1);)
               ELSE message(caster, "Your spell escapes!");
             ) ELSE (
               message(caster, "Your spell takes on a mind of its own!");
               IF random(3) = 0
               THEN create_item(caster, bad_item, 1);
             )
          )

# Increase spellpower by school and general magic skill
PROCEDURE adjust_spellpower(school) =
          experience = (script_int(caster, SCRIPT_XP) >> SCRIPT_XP_SHIFT) & SCRIPT_XP_MASK;
          spellpower = spellpower + (skill(caster, MAGIC) + skill(caster, school)) * 10;
          # Below, we adjust by special items
          IF (not(failed(target)) && (school = LIFE || school = NATURE))
          THEN IF (target)
          THEN IF (pc(target) = partner(caster))
               THEN (spellpower = spellpower + 200;
                IF is_equipped(caster, "WeddingRing")
                THEN spellpower = spellpower + 50;
                IF is_equipped(pc(target), "WeddingRing")
                THEN spellpower = spellpower + 50;)

PROCEDURE heal(target, max_heal) =
          CALL default_effect();
          IF caster <> target
          THEN sfx(target, SFX_HEAL, 0);
          power = spellpower + vit(caster);
          power = min(max_heal, (max_heal * power) / 250);
          itemheal(target, power, 0);

# Goes through instaheal instead of itemheal
PROCEDURE quickheal(target, power) =
          CALL default_effect();
          IF caster <> target
          THEN sfx(target, SFX_HEAL, 0);
          instaheal(target, power, 0);

# Can attack the target? Imports attack_range from dynamic environment
PROCEDURE attack_check(target) =
          IF (not (line_of_sight(location(caster), location(target))))
            THEN ABORT;
          IF (not (rdistance(location(caster), location(target)) <= attack_range))
            THEN ABORT;

# Cause elemental damage.  bonus_elt grants an attack bonus, malus_elt reduces the attack. `effect' is the sfx ID.
PROCEDURE elt_damage(target, damage, dmgplus, bonus_elt, malus_elt, effect) =
          d = damage + random(dmgplus);
          IF (element(target) = malus_elt)
            THEN d = d / 3;
          IF (element(target) = bonus_elt)
            THEN d = (d * (4 + element_level(target))) / 4;
          #message(caster, "bonus=" + (element(target) = bonus_elt) + " malus=" + (element(target) = malus_elt) + " damage=" + damage + " + r(" + dmgplus + ") -> " + d);
          sfx(target, effect, 0);
          injure(caster, target, d, 0);

PROCEDURE melee_damage(target, damage, dmgplus) =
          CALL attack_check(target);
          d = damage + random(dmgplus);
          evade = level(target) + mdef(target);
          IF (spellpower - random(100) < evade)
          THEN d = 0;
          injure(caster, target, d, 0);


PROCEDURE install_attack_spell(charges, base_delay, range, attack_animation) =
          CALL default_effect();
          attack_range = range;
          override_attack(caster, charges, ((200 - agi(caster)) * base_delay) / 200,
                          range, ATTACK_ICON_GENERIC, attack_animation, 0);

PROCEDURE install_melee_spell(charges, base_delay, attack_animation) =
          CALL install_attack_spell(charges, base_delay, 1, attack_animation);

PROCEDURE summon_spell(mob_id, count, delay, lifetime, control_level) =
          CALL default_effect();
          sfx(location, SFX_SUMMON_START, 0);
          WAIT delay;
          sfx(location, SFX_SUMMON_FIRE, 0);
          spawn(rbox(location, 2), caster, mob_id,
                if_then_else(skill(caster, ASTRAL) >= control_level, 2, 1), # pets when level is high enough
                count, lifetime);


#--------------------------------------------------------------------------------
# Level 0 spells
#--------------------------------------------------------------------------------

SPELL ask-magic-exp : "#G01" =
      LET level = 0
          school = MAGIC
      IN (MANA 1, CASTTIME 1000,
          REQUIRE skill(caster, MAGIC) > level)
      => EFFECT CALL adjust_spellpower(school);
                CALL default_effect();
                level = skill (caster, MAGIC);
                IF level > 4
                THEN message (caster, "You are as proficient as magic as you can possibly be.");
                ELSE (
                    experience = script_int(caster, "MAGIC_EXPERIENCE") & 0xffff;
                    # This duplicates the table in mana-seed.txt
                    IF level >= 4
                    THEN max_experience = 40000;
                    ELSE IF level = 3
                    THEN max_experience = 8000;
                    ELSE IF level = 2
                    THEN max_experience = 1200;
                    ELSE max_experience = 100;

                    ratio = (10 * experience - random(max_experience / 30)) / max_experience; #Randomness:  jitter a bit at the transitions to give more precise information if used frequently

                    IF ratio >= 10
                    THEN message(caster, "You feel in perfect control of your magic.");
                    ELSE IF ratio >= 9
                    THEN message(caster, "You feel in almost perfect control of your magic.");
                    ELSE IF ratio >= 8
                    THEN message(caster, "You feel that you have very good control of your magic.");
                    ELSE IF ratio >= 7
                    THEN message(caster, "You feel quite in control of your magic.");
                    ELSE IF ratio >= 6
                    THEN message(caster, "You feel mostly in control of your magic.");
                    ELSE IF ratio >= 5
                    THEN message(caster, "You feel somewhat in control of your magic.");
                    ELSE IF ratio >= 4
                    THEN message(caster, "You feel somewhat uneasy about controlling your magic.");
                    ELSE IF ratio >= 3
                    THEN message(caster, "Trying to control your magic makes you quite uncomfortable.");
                    ELSE IF ratio >= 2
                    THEN message(caster, "You feel that you have only the bare minimum of control over your magic.");
                    ELSE IF ratio >= 1
                    THEN message(caster, "You feel quite overwhelmed by your magic, but are beginning to see patterns.");
                    ELSE message (caster, "You feel completely overwhelmed by your magic.");
                )

# SPELL ask-life-magic-exp : "#G02" =
#       LET level = 0
#           school = MAGIC
#       IN (MANA 1, CASTTIME 1000,
#           REQUIRE skill(caster, MAGIC) > level)
#       => EFFECT CALL adjust_spellpower(school);
#                 CALL default_effect();
#                 message(caster, "You have " + ((script_int(caster, "MAGIC_EXPERIENCE") >> 24) & 0xff) + " Life Magic Experience points.");

SPELL transmute-wood-to-figurine (name : STRING) : "#T00" =
      LET level = 0
          school = TRANSMUTE
      IN (MANA 5, CASTTIME 4000,
          REQUIRE skill(caster, MAGIC) > level,
          COMPONENTS ["RawLog"])
          => ( REQUIRE name = "boo" =>
                            EFFECT CALL adjust_spellpower(school);
                            CALL default_effect();
                            CALL create_item("MoubooFigurine", 1, "WarpedLog", 40);
                            CALL gain_xp(1);
             | REQUIRE name = "lurk" =>
                            EFFECT CALL adjust_spellpower(school);
                            CALL default_effect();
                            CALL create_item("WarpedLog", 1, "WarpedLog", 40);
                            message (caster, "You have no idea what a Skrytlurk looks like.");
             )


SPELL make-sulphur : "#T01" =
      LET level = 0
          school = TRANSMUTE
      IN (MANA 4, CASTTIME 4000,
          REQUIRE skill(caster, MAGIC) > level,
          COMPONENTS ["PileOfAsh"])
          => EFFECT CALL adjust_spellpower(school);
                    CALL default_effect();
                    CALL create_item("SulphurPowder", 1 + spellpower / 100 + (random(max(1, 800 - spellpower)) / 180), "PileOfAsh", 50);
                    CALL gain_xp(1);

SPELL lesser-heal (target : STRING) : "#L00" =
      LET level = 0
          school = LIFE
      IN (MANA 6, CASTTIME 500,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE if_then_else(failed(pc(target)), 1,
                                                  rdistance(location(caster), location(pc(target))) < 2 + (spellpower / 100)),
          (COMPONENTS ["Lifestone"]))
          => EFFECT CALL adjust_spellpower(school);
                    CALL default_effect();
                    IF failed(pc(target))
                      THEN (IF ((target = "mouboo" || target = "Mouboo")
                                 && rdistance(location(caster), location(npc("Mouboo"))) < 2 + (spellpower / 100))
                            THEN { mes "Your spell seems to have no effect on the mouboo."; next; close; }
                            ELSE target = caster;)
                      ELSE (target = pc(target);
                            IF is_dead(target)
                            THEN ABORT;)
                    CALL gain_heal_xp(min(200, max_hp(target) - hp(target)), 1, 2, 2); # report half values for non-instaheal
                    CALL heal(target, 200);
                    CALL gain_xp(1);


SPELL flare-dart : "#W00" =
      LET level = 0
          school = WAR
      IN (MANA 10, CASTTIME 500,
          REQUIRE skill(caster, MAGIC) > level,
          (REQUIRE skill(caster, school) > 2 OR COMPONENTS ["SulphurPowder"]))
          => EFFECT CALL adjust_spellpower(school);
                    CALL default_effect();
                    damage = 5 * sqrt(spellpower);
                    damage_bonus = 5 + level(caster) / 3;
                    CALL install_attack_spell(3 + spellpower / 50,
                                         1200,
                                         4, 31);
                    CALL gain_xp(1);
             ATTRIGGER CALL attack_check(target);
                       CALL elt_damage (target, damage, damage_bonus, ELT_WATER, ELT_FIRE, 15);


SPELL magic-blade : "#W01" =
      LET level = 0
          school = WAR
      IN (MANA 9, CASTTIME 500,
          REQUIRE skill(caster, MAGIC) > level)
          => (  COMPONENTS ["SharpKnife"] =>
                            EFFECT CALL adjust_spellpower(WAR);
                                   CALL default_effect();
                                   CALL install_melee_spell(10 + spellpower / 15, 1200, 30);
                                   CALL gain_xp(1);
                            ATTRIGGER CALL melee_damage(target, 60, 5 + str(caster));
              | COMPONENTS ["Knife"] =>
                            EFFECT CALL adjust_spellpower(WAR);
                                   CALL default_effect();
                                   CALL install_melee_spell(10 + spellpower / 15, 1200, 30);
                                   CALL gain_xp(1);
                            ATTRIGGER CALL melee_damage(target, 40, 5 + str(caster));
             )

SPELL aggravate : "#N00" =
      LET level = 0
          school = NATURE
      IN (MANA 3, CASTTIME 1000,
          REQUIRE skill(caster, MAGIC) > level)
          => EFFECT CALL adjust_spellpower(school);
                    CALL default_effect();
                    FOREACH MOB target IN rbox(location(caster), 2 + spellpower / 50) DO
                            IF line_of_sight(location(caster), location(target))
			    THEN (CALL sfx_generic(target);
                                  aggravate(target, 0, caster);)

SPELL grow-mauve : "#N01" =
      LET level = 0
          school = NATURE
      IN (MANA 4, CASTTIME 2000,
          REQUIRE skill(caster, MAGIC) > level,
          COMPONENTS ["MauveHerb", "Root"])
          => EFFECT CALL adjust_spellpower(school);
                    CALL default_effect();
                    CALL gain_xp(1);
                    spawn(rbox(location, 2), caster, 1029, 1, skill(caster, school) / 2 + 1, 10000);

SPELL grow-alizarin : "#N02" =
      LET level = 0
          school = NATURE
      IN (MANA 4, CASTTIME 2000,
          REQUIRE skill(caster, MAGIC) > level,
          COMPONENTS ["AlizarinHerb", "Root"])
          => EFFECT CALL adjust_spellpower(school);
                    CALL default_effect();
                    CALL gain_xp(1);
                    spawn(rbox(location, 2), caster, 1032, 1, skill(caster, school) / 2 + 1, 10000);

SPELL grow-gamboge : "#N03" =
      LET level = 0
          school = NATURE
      IN (MANA 4, CASTTIME 2000,
          REQUIRE skill(caster, MAGIC) > level,
          COMPONENTS ["GambogeHerb", "Root"])
          => EFFECT CALL adjust_spellpower(school);
                    CALL default_effect();
                    CALL gain_xp(1);
                    spawn(rbox(location, 2), caster, 1031, 1, skill(caster, school) / 2 + 1, 10000);

SPELL grow-cobalt : "#N04" =
      LET level = 0
          school = NATURE
      IN (MANA 4, CASTTIME 2000,
          REQUIRE skill(caster, MAGIC) > level,
          COMPONENTS ["CobaltHerb", "Root"])
          => EFFECT CALL adjust_spellpower(school);
                    CALL default_effect();
                    CALL gain_xp(1);
                    spawn(rbox(location, 2), caster, 1030, 1, skill(caster, school) / 2 + 1, 10000);


LOCAL SPELL summon-maggots : "#A00" =
      LET level = 0
          school = ASTRAL
      IN (MANA 21, CASTTIME 20000,
          REQUIRE skill(caster, MAGIC) > level,
          COMPONENTS ["MaggotSlime", "Root"])
          => EFFECT CALL adjust_spellpower(school);
                    CALL gain_xp(1);
                    CALL summon_spell(1002,
                                      1 + ((sqrt(spellpower) + (spellpower / 15)) / 5),
                                      5000 - (spellpower * 5),
                                      10000 + (spellpower * 50), 1);

SPELL detect-magic : "#G00" =
      LET level = 0
          school = MAGIC
      IN (MANA 3, CASTTIME 6000,
          REQUIRE skill(caster, MAGIC) > level)
      => EFFECT CALL adjust_spellpower(school);
                CALL default_effect();
                range = 1 + spellpower / 50;
                FOREACH NPC n IN rbox(location(caster), range)
                DO IF (contains_string(name_of(n), "#MAGIC") || contains_string(name_of(n), "#_M"))
                   THEN sfx(n, SFX_DEFAULT, 0);
                FOREACH SPELL s IN rbox(location(caster), range)
                DO IF (s <> self_invocation)
                   THEN sfx(s, SFX_DEFAULT, 0);


#--------------------------------------------------------------------------------
# Level 1 spells
#--------------------------------------------------------------------------------

SPELL make-arrows : "#T10" =
      LET level = 1
          school = TRANSMUTE
      IN (MANA 8, CASTTIME 5000,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level,
          COMPONENTS ["RawLog"])
          => EFFECT CALL adjust_spellpower(school);
                    CALL default_effect();
                    CALL create_item("Arrow", 1 + spellpower / 40 + (random(max(1, 800 - spellpower)) / 80), "WarpedLog", 500);
                    CALL gain_xp(1);

SPELL make-shirt : "#T11" =
      LET level = 1
          school = TRANSMUTE
      IN (MANA 25, CASTTIME 5000,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level,
          COMPONENTS [5 * "CottonCloth"])
          => EFFECT CALL adjust_spellpower(school);
                    CALL default_effect();
                    CALL create_item("CottonShirt", 1, "CottonCloth", 425);
                    CALL gain_xp(2);

SPELL make-tanktop : "#T12" =
      LET level = 1
          school = TRANSMUTE
      IN (MANA 25, CASTTIME 5000,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level,
          COMPONENTS [4 * "CottonCloth"])
          => EFFECT CALL adjust_spellpower(school);
                    CALL default_effect();
                    CALL create_item("TankTop", 1, "CottonCloth", 350);
                    CALL gain_xp(2);

SPELL make-short-tanktop : "#T13" =
      LET level = 1
          school = TRANSMUTE
      IN (MANA 25, CASTTIME 5000,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level,
          COMPONENTS [3 * "CottonCloth"])
          => EFFECT CALL adjust_spellpower(school);
                    CALL default_effect();
                    CALL create_item("ShortTankTop", 1, "CottonCloth", 250);
                    CALL gain_xp(2);

SPELL make-iron-powder : "#T14" =
      LET level = 1
          school = TRANSMUTE
      IN (MANA 8, CASTTIME 5000,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level,
          COMPONENTS ["IronOre"])
          => EFFECT CALL adjust_spellpower(school);
                    CALL default_effect();
                    CALL create_item("IronPowder", 1 + spellpower / 140 + (random(max(1, 900 - spellpower)) / 220), "IronOre", 700);
                    CALL gain_xp(3);

SPELL make-concentration-potion : "#T15" =
      LET level = 1
          school = TRANSMUTE
      IN (MANA 8, CASTTIME 5000,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level,
          COMPONENTS ["BottleOfWater", 2 * "CobaltHerb", 2 * "Petal"])
          => EFFECT CALL adjust_spellpower(school);
                    CALL default_effect();
                    CALL create_item( if_then_else(random(2000 + experience) < experience, "ConcentrationPotion", "DarkConcentrationPotion"), 1,
                                      if_then_else(random(2), 744, "DarkConcentrationPotion"),
                                      2000);
                    IF (success)
                    THEN CALL set_var(MAGIC_FLAGS, 1, MFLAG_MADE_CONC_POTION_SHIFT, 1);
                    CALL gain_xp(4);

SPELL merge-concentration-potions : "#T16" =
      LET level = 1
          school = TRANSMUTE
      IN (MANA 8, CASTTIME 5000,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level,
          COMPONENTS ["DarkConcentrationPotion", 744])
          => EFFECT CALL adjust_spellpower(school);
                    CALL default_effect();
                    CALL create_item("ConcentrationPotion", 1, 744, 1000);
                    message (caster, "success = " + success);
                    IF (success)
                    THEN CALL set_var(MAGIC_FLAGS, 1, MFLAG_MADE_CONC_POTION_SHIFT, 1);
                    CALL gain_xp(4);


SPELL lay-on-hands (target : STRING) : "#L10" =
      LET level = 1
          school = LIFE
      IN (MANA 10, CASTTIME 500,
          REQUIRE hp(caster) > max_hp(caster) / 20,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level,
          REQUIRE if_then_else(failed(pc(target)), 1,
                                                  (rdistance(location(caster),
                                                           location(pc(target))) < 2 + (spellpower / 50))
                                                  && not (running_status_update(pc(target), SC_HALT_REGENERATE))
                                                  ))
          => EFFECT CALL adjust_spellpower(school);
		    IF (not (target)) THEN ABORT;
		    IF (pc (target) == caster) THEN ABORT;
                    IF failed(pc(target))
                      THEN (IF ((target = "mouboo" || target = "Mouboo")
                                 && rdistance(location(caster), location(npc("Mouboo"))) < 2 + (spellpower / 100))
                            THEN (needed = 1000;
                                  {
                                   set @spell, 1;
                                   callfunc "QuestMoubooHeal";
                                  })
                            ELSE (target = caster;
                                  needed = max_hp(target) - hp(target);
                                  ))
                      ELSE (target = pc(target);
                            needed = max_hp(target) - hp(target);)
                    
                    pay_fraction = max(80, 200 - (vit(caster) + (spellpower / 10))); # Pay at least 40%
                    payment = (needed * pay_fraction) / 200;
                    available = hp(caster) - (max_hp(caster) / 20);

                    IF payment < available
                    THEN power = needed;
                    ELSE (payment = available;
                          power = (available * 200) / pay_fraction;
                    )
                    CALL gain_heal_xp(power, 1, 1, 3);
                    CALL quickheal(target, power);
                    status_change(caster, SC_HALT_REGENERATE, 0, 0, 0, 0, 10000);
                    IF ((caster <> target) && (payment >= 100))
                    THEN CALL gain_xp(min(4, payment / 100));

SPELL lightning-strike : "#W10" =
      LET level = 1
          school = WAR
      IN (MANA 20, CASTTIME 1000,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level,
          (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["IronPowder"]))
          => EFFECT CALL adjust_spellpower(school);
                    damage = spellpower;
                    damage_bonus = 1 + spellpower / 2;
                    CALL install_attack_spell(1 + spellpower / 90,
                                              3000,
                                              8, 31);
                    CALL gain_xp(2);
             ATTRIGGER CALL attack_check(target);
                       in_rain = 0;
                       area = location(caster);
                       FOREACH SPELL s IN rbox(location(caster), MAX_RAIN_SPELL_RADIUS + 1) DO
                               IF name_of(s) = "rain" THEN (
                                  IF is_in (location(caster), s.area)
                                  THEN (in_rain = in_rain | 1;
                                        area = area + s.area;);
                                  IF is_in (location(target), s.area)
                                  THEN in_rain = in_rain | 2;
                               );
                       IF in_rain & 1
                       THEN (# caster standing in the rain?  This is going to be fun.
                            used = 0;
                            FOREACH TARGET t IN area DO
                                  IF (random(200) + luk(caster) > 175)
                                  THEN (used = used + 1;
                                        CALL elt_damage (t, damage / 6, 1 + (damage_bonus / 3), ELT_EARTH, ELT_WIND, 17 + random(3)););
                            IF (not(used) || (random(200) + luk(caster) < 150))
                            THEN (sfx(caster, 17 + random(3), 0);
                                  itemheal(caster, 0 - damage - (random(damage_bonus)), 0););
                       ) ELSE
                       CALL elt_damage (target, damage, damage_bonus, ELT_EARTH, ELT_WIND, 17 + random(3));

LOCAL SPELL arrow-hail : "#W11" =
      LET level = 1
          school = WAR
      IN (MANA 25, CASTTIME 5000,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level,
          REQUIRE is_exterior(location(caster)),
          (COMPONENTS [20 * "Arrow"] OR COMPONENTS [20 * "IronArrow"]),
          (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["SulphurPowder"]))
      => EFFECT CALL adjust_spellpower(school);
                CALL default_effect();

                range = 7;
                area = rbox(awayfrom(location(caster), dir(caster), 1 + range), range);

                FOREACH SPELL s IN rbox(awayfrom(location(caster), dir(caster), 1 + range), range * 2) DO
                                IF (s <> self_invocation) && (name_of(s) = "arrow-hail")
                                THEN (message (caster, "A nearby arrow hail spell absorbs your magic!");
                                      ABORT;)

                damage = 125;
                damage_bonus = spellpower / 5;
                CALL gain_xp(2);
                FOR i = 0 TO spellpower / 8 DO (
                    FOR j = 0 TO 2 DO (
                        location = random_location(area);
                        sfx(location, SFX_ARROW_HAIL, 0);
                        done = 0;
                        FOREACH TARGET target IN rbox(location, 0) DO (
                      	        injure(caster, target, damage + random(damage_bonus) + random(damage_bonus), 0);
                                done = 1;
                                BREAK;
                        )
                        IF location(caster) = location && not(done)
                        THEN (itemheal(caster, 0 - (damage + random(damage_bonus) + random(damage_bonus)), 0);
                             sfx(caster, SFX_HIT, 0);
                        )
                    );
                    WAIT 250 + random(50) + random(50);
                );

SPELL magic-knuckles : "#W12" =
      LET level = 1
          school = WAR
      IN (MANA 20, CASTTIME 500,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level,
          (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["Beer"]))
          => 
             EFFECT CALL adjust_spellpower(WAR);
                    str = str(caster);
                    CALL install_melee_spell(10 + spellpower / 10, 1300, 34);
             ATTRIGGER CALL melee_damage(target, 30, 5 + (str * 2));

SPELL flying-backpack (target : PC) : "#N10" =
      LET level = 1
          school = NATURE
      IN (MANA 12, CASTTIME 1000,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level,
          (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["SilkCocoon"]),
          REQUIRE rdistance(location(target), location(caster)) < 2 + spellpower / 30)
      => EFFECT CALL adjust_spellpower(school);
                CALL default_effect();
                IF (caster <> target)
                THEN sfx(caster, 2, 0);
                status_change(target, SC_FLYING_BACKPACK, 0, 0, 0, 0, 5000 + (spellpower * 500));
                message (target, "Your backpack is lifted by a mystical force; you no longer feel it pressing on your back.");
                CALL gain_xp(1);
         ATEND message (target, "Your backpack is no longer levitating.");
               sfx(target, 2, 0);

SPELL protect (target : PC) : "#N11" =
      LET level = 1
          school = NATURE
      IN (MANA 14, CASTTIME 1500,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level,
          (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["HardSpike"]),
          REQUIRE rdistance(location(target), location(caster)) < 2 + spellpower / 30)
      => EFFECT CALL adjust_spellpower(school);
                sfx(target, 11, 0);
                IF (caster <> target)
                THEN CALL default_effect();
                status_change(target, SC_PHYS_SHIELD, 5 + max(15, spellpower / 20), 0, 0, 0, 5000 + (spellpower * 1000));
                message (target, "You feel more protected.");
                CALL gain_xp(2);
         ATEND message (target, "You feel less protected.");
               sfx(target, 111, 0);

SPELL happy-curse (target : PC) : "#N12" =
      LET level = 1
          school = NATURE
      IN (MANA 13, CASTTIME 1000,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level,
          (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["GingerBreadMan"]),
          REQUIRE rdistance(location(target), location(caster)) < 1 + spellpower / 100)
      => EFFECT CALL adjust_spellpower(school);
                CALL default_effect();
                FOR i = 0 TO (spellpower / 10) DO (emote(target, 3); WAIT 500;);
                CALL gain_xp(1);

LOCAL SPELL rain : "#N13" =
      LET level = 1
          school = NATURE
      IN (MANA 17, CASTTIME 3000,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level,
          REQUIRE is_exterior(location(caster)),
          (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["BottleOfWater"]))
      => EFFECT CALL adjust_spellpower(school);
                CALL default_effect();
                FOREACH SPELL s IN rbox(location(caster), MAX_RAIN_SPELL_RADIUS + 1) DO
                                IF (s <> self_invocation) && (name_of(s) = "rain")
                                THEN (message (caster, "A nearby raincloud absorbs your magic.");
                                      ABORT;)

                CALL gain_xp(1);
                range = min(MAX_RAIN_SPELL_RADIUS, 3 + min(spellpower, 200) / 30);
                area = rbox(location(caster), range);
                IF (is_in(location(npc("#DruidTree0#_M")), area)
                    || is_in(location(npc("#DruidTree1#_M")), area))
                THEN {
                    set @flag, 1;
                    callfunc "QuestTreeTrigger";
                };
                FOR i = 0 TO (spellpower / 3) DO (
                    FOR j = 0 TO min(spellpower / 2, 200) / 100 DO (
                        location = random_location(area);
                        sfx(location, SFX_RAIN, 0);
                        FOREACH TARGET target IN rbox(location, 1) DO
                            IF element(target) = ELT_FIRE
                            THEN injure(caster, target, 2 + random(5 + spellpower / 15), 0);
                    )
                    WAIT 400 + random(100);
                );

PROCEDURE shear-drop(target, target2, item, prob) =
                     IF (target = name || target2 = name)
                     THEN (IF (score < prob)
                           THEN drop_item_for(place, item, 1, 60000, caster, 5000);)

PROCEDURE shear-drop2(target, target2, item, prob, item2, prob2) =
                     IF (target = name || target2 = name)
                     THEN (IF (score < prob)
                           THEN drop_item_for(place, item, 1, 60000, caster, 5000);
                           ELSE CALL shear-drop(target, target2, item2, prob2 + prob);)
          
PROCEDURE shear-drop3(target, target2, item, prob, item2, prob2, item3, prob3) =
                     IF (target = name || target2 = name)
                     THEN (IF (score < prob)
                           THEN drop_item_for(place, item, 1, 60000, caster, 5000);
                           ELSE CALL shear-drop2(target, target2, item2, prob2 + prob, item3, prob3 + prob);)
          

SPELL shear : "#N14" =
      LET level = 1
          school = NATURE
      IN (MANA 23, CASTTIME 1000,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level)
      => EFFECT CALL adjust_spellpower(school);
                CALL default_effect();
                override_attack (caster, 1, 2000, 1, ATTACK_ICON_SHEARING, 30, 0);
         ATTRIGGER IF not(is_pc(target))
                   THEN (score = random (1000 - (random (spellpower))); # lower score -> more valuable item
                         name = name_of(target);
                         place = random_location(rbox(location(target), 1));
                         IF running_status_update(target, SC_SHEARED)
                         THEN ABORT;
                         status_change(target, SC_SHEARED, 1, 1, 1, 1, 600000); # 10 minutes
                         CALL shear-drop("Fluffy", "Fluffy",			"WhiteFur", 300);
                         CALL shear-drop("EasterFluffy", "Easter Fluffy",	"WhiteFur", 300);
                         CALL shear-drop("SpikyMushroom", "Spiky Mushroom",	"HardSpike", 250);
                         CALL shear-drop("Mouboo", "Mouboo",			"CottonCloth", 175);
                         CALL shear-drop("Cobalt", "CobaltPlant",		"CobaltHerb", 700);
                         CALL shear-drop("Alizarin", "AlizarinPlant",		"AlizarinHerb", 700);
                         CALL shear-drop("Gamboge", "GambogePlant",		"GambogeHerb", 700);
                         CALL shear-drop("Mauve", "MauvePlant",			"MauveHerb", 700);
                         CALL shear-drop("SilkWorm", "Silkworm",		"SilkCocoon", 300);
                         IF ((name = "Fluffy" || name = "Mouboo") && random(2))
                         THEN { set @value, 1; callfunc "QuestSagathaHappy"; };
                    )

      

SPELL barrier (target : PC) : "#A10" =
      LET level = 1
          school = ASTRAL
      IN (MANA 16, CASTTIME 1000,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level,
          (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["SmallMushroom"]),
          REQUIRE rdistance(location(target), location(caster)) < 2 + spellpower / 30)
      => EFFECT CALL adjust_spellpower(school);
                sfx(target, SFX_BARRIER, 0);
                IF (caster <> target)
                THEN CALL default_effect();
                status_change(target, SC_MBARRIER, 20 + max(30, spellpower / 8), 0, 0, 0, 2000 + (spellpower * 200));
                message (target, "You are surrounded by a magical barrier.");
                CALL gain_xp(3);
         ATEND message (target, "Your magical barrier dissipates.");
               sfx(target, SFX_UNBARRIER, 0);


LOCAL SPELL summon-spiky-mushrooms : "#A11" =
      LET level = 1
          school = ASTRAL
      IN (MANA 33, CASTTIME 20000,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level,
          COMPONENTS ["HardSpike", "Root"])
          => EFFECT CALL adjust_spellpower(school);
                    CALL default_effect();
                    CALL gain_xp(1);
                    CALL summon_spell(1019, 1 + spellpower / 120, 5000 - (spellpower * 9), spellpower * 400, 2);

LOCAL SPELL summon-fluffies : "#A12" =
      LET level = 1
          school = ASTRAL
      IN (MANA 39, CASTTIME 20000,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level,
          COMPONENTS ["WhiteFur", "Root"])
          => EFFECT CALL adjust_spellpower(school);
                    CALL default_effect();
                    CALL gain_xp(1);
                    CALL summon_spell(1020, 1 + spellpower / 170 + spellpower / 430, 5000 - (spellpower * 8), spellpower * 350, 3);


SPELL detect-players : "#G10" =
      LET level = 1
          school = MAGIC
      IN (MANA 7, CASTTIME 300,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level)
          => EFFECT CALL adjust_spellpower(school);
                    CALL default_effect();
                    message = "";
                    FOREACH PC target IN rbox(location(caster), spellpower / 2)
                    DO IF ((target <> caster)
                           && not (running_status_update(pc(target), SC_HIDE)))
                       THEN (IF message <> ""
                             THEN message = message + ", ";
                             message = message + name_of (target);
                             IF spellpower > 99
                             THEN message = message + "(" + level(target) + ")";
                             )
                    IF message = ""
                    THEN message(caster, "You sense no-one else nearby.");
                    ELSE message(caster, "You sense the following: " + message);

SPELL reveal : "#G11" =
      LET level = 1
          school = MAGIC
      IN (MANA 18, CASTTIME 3000,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level)
          => EFFECT CALL adjust_spellpower(school);
                    CALL default_effect();
             FOREACH PC target IN rbox(location(caster), 1 + spellpower / 100)
             DO IF has_shroud(target) && level(caster) * 2 > level(target)
                THEN (unshroud(target);
                      sfx(target, SFX_DEFAULT, 500);)
                      

SPELL enchant-lifestone : "#G12" =
      LET level = 1
          school = MAGIC
      IN (MANA 15, CASTTIME 4000,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level,
          (COMPONENTS ["MaggotSlime"] OR COMPONENTS["BugLeg"]
           OR COMPONENTS ["MauveHerb", "AlizarinHerb", "CobaltHerb", "GambogeHerb"]))
          => EFFECT CALL adjust_spellpower(school);
                    CALL default_effect();
                    create_item(caster, "Lifestone", 1);
                    CALL gain_xp(1);

SPELL sense-spouse : "#G13" =
      LET level = 1
          school = MAGIC
      IN (MANA 7, CASTTIME 400,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level,
          REQUIRE is_married(caster),
          REQUIRE is_equipped(caster, "WeddingRing"))
          => EFFECT CALL adjust_spellpower(school);
                    CALL default_effect();
                    IF (failed(partner(caster)) || not(is_equipped(partner(caster), "WeddingRing")))
                    THEN (message(caster, "You cannot sense your partner.");
                          ABORT;)
                    partner = partner(caster);
                    name = name_of(partner);
                    IF (is_dead(partner) || (map_nr(location(partner)) <> map_nr(location(caster))))
                    THEN (message(caster, "You cannot sense " + name + " nearby.");
                          ABORT;)
                    IF (map_level(location(partner)) > 2 && map_level(location(caster)) < map_level(location(partner)))
                    THEN (message(caster, "You sense " + name + " somewhere below.");
                          ABORT;)
                    IF (map_level(location(caster)) > 2 && map_level(location(partner)) < map_level(location(caster)))
                    THEN (message(caster, "You sense " + name + " somewhere above.");
                          ABORT;)
                    IF (map_level(location(caster)) <> map_level(location(partner)))
                    THEN message(caster, "You sense " + name + " somewhere in the vincinity.");
                    ELSE (distance = rdistance(location(caster), location(partner));
                          dir = dir_towards(location(caster), location(partner), 1);
                          IF (distance < 3)
                          THEN message(caster, "You sense " + name + " right next to you.");
                          ELSE IF (distance < 30)
                          THEN message(caster, "You sense " + name + " close by, towards the " + dir + ".");
                          ELSE IF (distance < 200)
                          THEN message(caster, "You sense " + name + " nearby, towards the " + dir + ".");
                          ELSE message(caster, "You sense " + name + " in the " + dir + ".");
                    )

SPELL hide (target : PC) : "#A13" =
      LET level = 1
          school = ASTRAL
      IN (MANA 11, CASTTIME 1000,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level,
          (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["CottonCloth"]),
          REQUIRE rdistance(location(target), location(caster)) < 2 + spellpower / 30)
      => EFFECT CALL adjust_spellpower(school);
                sfx(target, SFX_DEFAULT, 0);
                IF (caster <> target)
                THEN CALL default_effect();
                status_change(target, SC_HIDE, 0, 0, 0, 0, 5000 + (spellpower * 2500));
                CALL gain_xp(2);
                message(target, "You are hidden!");
                IF (caster <> target) THEN message(caster, "You hid someone!");
          ATEND message(target, "You are no longer hidden.");

#--------------------------------------------------------------------------------
# Level 2 spells
#--------------------------------------------------------------------------------

SPELL cure-poison (target : PC) : "#L20" =
      LET level = 2
          school = LIFE
      IN (MANA 15, CASTTIME 1000,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level,
          REQUIRE (rdistance(location(caster),
                   location(pc(target))) < 1 + (spellpower / 60)),
          COMPONENTS ["GambogeHerb"])
      => EFFECT CALL adjust_spellpower(school);
                CALL default_effect();
                IF (running_status_update (target, SC_POISON))
                THEN (CALL gain_heal_xp(40, 1, 2, 2);
                      stop_status_change (target, SC_POISON);
                      CALL gain_xp(2);
                      IF caster <> target
                      THEN sfx(target, SFX_HEAL, 0););


SPELL fire-ball : "#W22" =
      LET level = 2
          school = WAR
      IN (MANA 30, CASTTIME 1000,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level,
          COMPONENTS ["PileOfAsh"])
          => EFFECT CALL adjust_spellpower(school);
                    damage = min(50 + skill(caster, school) * 40,
                                 30 + ((spellpower * 3) / 2));
                    damage_bonus = level(caster) + spellpower * 2;
                    radius = 2 + spellpower / 50;
                    CALL install_attack_spell(1 + spellpower / 60,
                                              5000,
                                              10, 31);
             ATTRIGGER CALL attack_check(target);
                       loc = location(target);
                       #WAIT 500;
                       sfx(loc, 16, 0);
                       FOREACH TARGET target IN rbox(loc, radius)
                         DO IF line_of_sight(loc, location(target))
                            THEN (divisor = (3 + rdistance(loc, location(target)));
                                  CALL elt_damage (target, (damage * 3) / divisor, (damage_bonus * 3) / divisor, ELT_WATER, ELT_FIRE, 15);
                            )

SPELL summon-partner : "#A23" = 
      LET level = 2
          school = ASTRAL
      IN (MANA 30, CASTTIME 2000,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level,
          REQUIRE is_married(caster),
          REQUIRE is_equipped(caster, "WeddingRing"))
	=> EFFECT CALL adjust_spellpower(school);
                  CALL default_effect();
                  IF (failed (partner (caster)))
                  THEN message (caster, "You call out for your partner, but there is no response.");
                  ELSE (message (caster, "You call out for " + (name_of (partner (caster))) + ".");
                        message (partner(caster), name_of(caster) + " is calling for your aid!");
                        sfx(partner(caster), 2, 0);
                        WAIT (max (5000, 30000 - (spellpower * 60)));
                        IF (failed (partner (caster)))
                        THEN message (caster, "Your partner has abandoned you.");
                        ELSE IF (is_dead (partner (caster)))
                        THEN message (caster, "Something seems to have happened to " + (name_of(partner(caster))) + ".");
                        ELSE (sfx(location(partner(caster)), SFX_TELEPORT, 0);
                              dest = awayfrom(location(caster), random_dir(1), 1);
                              warp(partner(caster), dest);
                              sfx(dest, SFX_TELEPORT, 0);
                             )
                       )



#--------------------------------------------------------------------------------
# Level 4 spells
#--------------------------------------------------------------------------------

SPELL shroud : "#N40" = 
      LET level = 4
          school = NATURE
      IN (MANA 40, CASTTIME 400,
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level)
	=> EFFECT CALL default_effect();
                  shroud(caster, 0x04);

SPELL teleport (destination : STRING) : "#A40" = 
      LET level = 4
          school = ASTRAL
      IN (MANA 80, CASTTIME 400,
          # COMPONENT ["EtherEssence"],
          # CATALYST ["TeleportCrystal"],
          REQUIRE skill(caster, MAGIC) > level,
          REQUIRE skill(caster, school) > level)
	=> EFFECT CALL default_effect();
                  WAIT 1000 + (200000 / (spellpower + 10));
                  sfx(location(caster), SFX_TELEPORT, 1);
                  warp(caster, random_location(anchor(destination)));
                  sfx(location(caster), SFX_TELEPORT, 100);

#--------------------------------------------------------------------------------
# Debug keywords
#--------------------------------------------------------------------------------

SPELL debug : "debug" =
      REQUIRE DEBUG
      => EFFECT message (caster, "FLAGS: "
                                 + "drank=" + ((script_int(caster, "MAGIC_FLAGS") & 1) > 0) + ", "
                                 + "Kmseed=" + ((script_int(caster, "MAGIC_FLAGS") & 2) > 0) + ", "
                                 + "touched-mseed=" + ((script_int(caster, "MAGIC_FLAGS") & 4) > 0) + ", "
                                 + "mseed-max=" + ((script_int(caster, "MAGIC_FLAGS") & 8) > 0) + ", "
                                 + "Kauldsbel=" + ((script_int(caster, "MAGIC_FLAGS") & 16) > 0) + ", "
                                 + "Kwyara=" + ((script_int(caster, "MAGIC_FLAGS") & 32) > 0) + ", "
                                 + "Ksagatha=" + ((script_int(caster, "MAGIC_FLAGS") & 64) > 0) + ", "
                                 + "Kmpotion=" + ((script_int(caster, "MAGIC_FLAGS") & 128) > 0) + ", "
                                 + "mseed-rumour=" + ((script_int(caster, "MAGIC_FLAGS") & 256) > 0) + ", "
                                 + "Kcuttree=" + ((script_int(caster, "MAGIC_FLAGS") & 512) > 0) + ", "
                                 + "cut=" + ((script_int(caster, "MAGIC_FLAGS") & 1024) > 0) + ", "
                                 + "Kdruidtree=" + ((script_int(caster, "MAGIC_FLAGS") & 2048) > 0) + ", "
                                 + "Kimp=" + ((script_int(caster, "MAGIC_FLAGS") & 4096) > 0) + ", "
                                 + "Koldwiz=" + ((script_int(caster, "MAGIC_FLAGS") & 8192) > 0) + ", "
                                 + "made-conc=" + ((script_int(caster, "MAGIC_FLAGS") & 16384) > 0) + ", "
                                 + "elanore-omar=" + ((script_int(caster, "MAGIC_FLAGS") & 32768) > 0));
                message (caster, "EXP: " + (script_int(caster, "MAGIC_EXPERIENCE") & 0xffff)
                                 + ", lastspell=" + ((script_int(caster, "MAGIC_EXPERIENCE") >> 16) & 0xff)
                                 + ", healexp=" + ((script_int(caster, "MAGIC_EXPERIENCE") >> 24) & 0xff));
                message (caster, "STATUS: "
                                 + "auldsbel:" + (script_int(caster, "QUEST_MAGIC") & 0x1f) + "," + ((script_int(caster, "QUEST_MAGIC") >> 5) & 0x7) + ", "
                                 + "dt/mb:" + ((script_int(caster, "QUEST_MAGIC") >> 8) & 0xf) + ", "
                                 + "s-unhappy:" + ((script_int(caster, "QUEST_MAGIC") >> 12) & 0xf) + ", "
                                 + "sagatha:" + ((script_int(caster, "QUEST_MAGIC") >> 16) & 0xff) + ", "
                                 + "swords:" + ((script_int(caster, "QUEST_MAGIC") >> 24) & 0xff) + ", "
                                 + "imp:" + ((script_int(caster, "QUEST_MAGIC2") >> 0) & 0xf) + ", "
                                 + "elanore:" + ((script_int(caster, "QUEST_MAGIC2") >> 4) & 0xf) + ", "
                                 + "elanore-sub:" + ((script_int(caster, "QUEST_MAGIC2") >> 12) & 0xf) + ", "
                                 + "wyara:" + ((script_int(caster, "QUEST_MAGIC2") >> 8) & 0xf));

PROCEDURE debug_xmod(name, mask, shift, gain) =
          value = ((script_int(caster, name) >> shift) & mask) + gain;
          IF (value < 0)
          THEN value = 0;
          IF (value > mask)
          THEN value = mask;
          CALL set_var(name, mask, shift, value);

PROCEDURE debug_mod(name, delta) =
          IF (name = "mexp") THEN CALL debug_xmod("MAGIC_EXPERIENCE", 0xffff, 0, delta);
          ELSE IF (name = "lastspell") THEN CALL debug_xmod("MAGIC_EXPERIENCE", 0xff, 16, delta);
          ELSE IF (name = "healexp") THEN CALL debug_xmod("MAGIC_EXPERIENCE", 0xff, 24, delta);
          ELSE IF (name = "drank") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 0, delta);
          ELSE IF (name = "Kmseed") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 1, delta);
          ELSE IF (name = "touched-mseed") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 2, delta);
          ELSE IF (name = "mseed-max") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 3, delta);
          ELSE IF (name = "Kauldsbel") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 4, delta);
          ELSE IF (name = "Kwyara") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 5, delta);
          ELSE IF (name = "Ksagatha") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 6, delta);
          ELSE IF (name = "Kmpotion") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 7, delta);
          ELSE IF (name = "mseed-rumour") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 8, delta);
          ELSE IF (name = "Kcuttree") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 9, delta);
          ELSE IF (name = "cut") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 10, delta);
          ELSE IF (name = "Kdruidtree") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 11, delta);
          ELSE IF (name = "Kimp") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 12, delta);
          ELSE IF (name = "oldwiz") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 13, delta);
          ELSE IF (name = "made-conc") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 14, delta);
          ELSE IF (name = "elanore-omar") THEN CALL debug_xmod("MAGIC_FLAGS", 0x1, 15, delta);
          ELSE IF (name = "auldsbel") THEN CALL debug_xmod("QUEST_MAGIC", 0x1f, 0, delta);
          ELSE IF (name = "Qauldsbel") THEN CALL debug_xmod("QUEST_MAGIC", 0x7, 5, delta);
          ELSE IF (name = "dt") THEN CALL debug_xmod("QUEST_MAGIC", 0x3, 10, delta);
          ELSE IF (name = "mb") THEN CALL debug_xmod("QUEST_MAGIC", 0x3, 8, delta);
          ELSE IF (name = "s-unhappy") THEN CALL debug_xmod("QUEST_MAGIC", 0xff, 12, delta);
          ELSE IF (name = "sagatha") THEN CALL debug_xmod("QUEST_MAGIC", 0xff, 16, delta);
          ELSE IF (name = "swords") THEN CALL debug_xmod("QUEST_MAGIC", 0xff, 24, delta);
          ELSE IF (name = "imp") THEN CALL debug_xmod("QUEST_MAGIC2", 0xf, 0, delta);
          ELSE IF (name = "elanore") THEN CALL debug_xmod("QUEST_MAGIC2", 0xf, 4, delta);
          ELSE IF (name = "wyara") THEN CALL debug_xmod("QUEST_MAGIC2", 0xf, 8, delta);
          ELSE IF (name = "elanore-sub") THEN CALL debug_xmod("QUEST_MAGIC2", 0xf, 12, delta);
          ELSE message(caster, "Unknown");

SPELL debug-up1 (name : STRING) : "debug+1" = 
	REQUIRE DEBUG
        => EFFECT CALL debug_mod(name, 1);

SPELL debug-down1 (name : STRING) : "debug-1" = 
	REQUIRE DEBUG
        => EFFECT CALL debug_mod(name, 0 - 1);

SPELL debug-up16 (name : STRING) : "debug+16" = 
	REQUIRE DEBUG
        => EFFECT CALL debug_mod(name, 16);

SPELL debug-down16 (name : STRING) : "debug-16" = 
	REQUIRE DEBUG
        => EFFECT CALL debug_mod(name, 0 - 16);

SPELL debug-up256 (name : STRING) : "debug+256" = 
	REQUIRE DEBUG
        => EFFECT CALL debug_mod(name, 256);

SPELL debug-down256 (name : STRING) : "debug-256" = 
	REQUIRE DEBUG
        => EFFECT CALL debug_mod(name, 0 - 256);

SPELL debug-reset : "debug-reset" =
      REQUIRE DEBUG
	=> EFFECT set_script_variable(caster, "QUEST_MAGIC", 0);
                  set_script_variable(caster, "QUEST_MAGIC2", 0);
                  set_script_variable(caster, "MAGIC_FLAGS", 0);
                  set_script_variable(caster, "MAGIC_EXP", 0);


#--------------------------------------------------------------------------------
# Special-purpose quasispells
#--------------------------------------------------------------------------------

CONST MIN_MARRY_LEVEL = 32;

NONMAGIC SILENT SPELL marriage (target : PC) : "marry" =
       (REQUIRE is_in(location(caster), @("014-1.gat", 28,39) @+ (8, 6)))=>
       EFFECT IF target == caster  # no valid target or tried to marry self?
              THEN ABORT;

              IF (level(caster) < MIN_MARRY_LEVEL)
              THEN (message(caster, "You must be level " + MIN_MARRY_LEVEL + " or higher to marry!"); ABORT;)

              IF (level(target) < MIN_MARRY_LEVEL)
              THEN (message(caster, "Your partner must be level " + MIN_MARRY_LEVEL + " or higher to marry!"); ABORT;)

              IF partner(caster) = target
              THEN (message(caster, "You and " + name_of(target) + " are already married."); ABORT;)

              IF is_married(caster)
              THEN (message(caster, "You are already married!"); ABORT;)

              IF is_married(target)
              THEN (message(caster, name_of(target) + " is already married."); ABORT;);

              IF distance(location(caster), location(target)) <> 1
              THEN (message(caster, "You have to stand next to each other."); ABORT;);

              IF (count_item(caster, "WeddingRing") == 0 || count_item(target, "WeddingRing") == 0)
              THEN (message(caster, "You must both be wearing your wedding rings!"); ABORT;)

              script_target = target;
              { 
                announce @caster_name$ + " is asking " + strcharinfo(0) + " for marriage.", 2;
                mes @caster_name$ + " wishes to marry you.";
                mes "Do you accept?";
                next;
                menu "Yes, I do!", L_yes,
                     "No.", -;
                close;

                L_yes:
                if marriage(@caster_name$)
                     announce @caster_name$ + " and " + strcharinfo(0) + " are now married!", 0;
                close;
              }

              IF not (is_married(caster))
              THEN message(caster, name_of(target) + " turned down your marriage offer.");

# SPELL change-hair-colour (colour : STRING) : "trapa" =
#       (MANA 20) => EFFECT IF colour = "nworbl"
#                           THEN x = 0; # light brown
#                           ELSE IF colour = "der"
#                           THEN x = 1; # red
#                           ELSE IF colour = "neerg"
#                           THEN x = 2; # green
#                           ELSE IF colour = "elprup"
#                           THEN x = 3; # purple
#                           ELSE IF colour = "yerg"
#                           THEN x = 4; # grey
#                           ELSE IF colour = "wolley"
#                           THEN x = 5; # yellow
#                           ELSE IF colour = "eulb"
#                           THEN x = 6; # blue
#                           ELSE IF colour = "nwrob"
#                           THEN x = 7; # brown
#                           ELSE IF colour = "elpropl"
#                           THEN x = 8; # light purple
#                           ELSE IF colour = "elpropd"
#                           THEN x = 9; # dark purple
#                           ELSE x = random(10);
#                           sfx(caster, 2, 0);
#                           set_hair_colour(caster, x);


# SPELL trick-or-treat : "trick-or-treat" =
#       (CASTTIME 30000, MANA 20,
#        COMPONENTS [ "BugLeg" ]) => EFFECT              IF (random(2))
#                                                        THEN (sfx(caster, 2, 0);
#                                                              FOR i = 0 TO random(10) DO
#                                                                  drop_item_for (random_location(rbox(location(caster), 5)),
#                                                                                 "Candy", 1, 10000 + random(10000), caster, 3000);
#                                                              FOR i = 0 TO random(10) DO
#                                                                  drop_item_for (random_location(rbox(location(caster), 5)),
#                                                                                 "ChocolateBar", 1, 10000 + random(10000), caster, 3000);
#                                                             )
#                                                        ELSE (sfx(caster, 5, 0);
#                                                              message(caster, "No treat for you!");
#                                                              spawn(rbox(location(caster), 3), caster, 1010, 0, 1 + random(3), 10000 + random(20000));
#                                                              FOREACH MOB target IN rbox(location(caster), 5) DO
#                                                                      (sfx(target, 5, 0);
#                                                                       aggravate(target, 0, caster);))


LOCAL SPELL mouboo-groan : "#g" =
      (MANA 1,
       REQUIRE name_of(caster) = "MOUBOOTAUR") =>
      	EFFECT FOREACH PC p IN rbox(location(caster), 200) DO
               distance = rdistance(location(caster), location(p));
               IF (distance < 15)
               THEN message(p, "The moubootaur's groaning rings in your ears!");
               ELSE IF (distance < 70)
               THEN message(p, "You hear a loud groaning noise, not far away...");
               ELSE message(p, "You hear an odd groaning noise in the distance...");


LOCAL SPELL mouboo-smell : "#s" =
      (MANA 1,
       REQUIRE name_of(caster) = "MOUBOOTAUR") =>
      	EFFECT WAIT 30000;
               FOREACH PC p IN rbox(location(caster), 30) DO
               		message(p, "You notice a strange smell all around you.");



PROCEDURE hug_tree(target) =
          IF (target = ""
              || target = "tree" || target = "tree*"
              || target = "Tree" || target = "Tree*"
              || target = "druid" || target = "druid*"
              || target = "Druid" || target = "Druid*")
          THEN {
                    set @flag, 2;
                    callfunc "QuestTreeTrigger";
                };

NONMAGIC SPELL hug0 (target : STRING) : "hug" = REQUIRE ((rdistance(location(caster), location(npc("#DruidTree0#_M"))) <= 1
                                                         || rdistance(location(caster), location(npc("#DruidTree1#_M"))) <= 1))
                                                => EFFECT CALL hug_tree(target);

NONMAGIC SPELL hug1 (target : STRING) : "*hug*" = REQUIRE ((rdistance(location(caster), location(npc("#DruidTree0#_M"))) <= 1
                                                         || rdistance(location(caster), location(npc("#DruidTree1#_M"))) <= 1))
                                                => EFFECT CALL hug_tree(target);

NONMAGIC SPELL hug2 (target : STRING) : "*hug" = REQUIRE ((rdistance(location(caster), location(npc("#DruidTree0#_M"))) <= 1
                                                         || rdistance(location(caster), location(npc("#DruidTree1#_M"))) <= 1))
                                                => EFFECT CALL hug_tree(target);

NONMAGIC SPELL hug3 (target : STRING) : "hugs" = REQUIRE ((rdistance(location(caster), location(npc("#DruidTree0#_M"))) <= 1
                                                         || rdistance(location(caster), location(npc("#DruidTree1#_M"))) <= 1))
                                                => EFFECT CALL hug_tree(target);

NONMAGIC SPELL hug4 (target : STRING) : "*hugs*" = REQUIRE ((rdistance(location(caster), location(npc("#DruidTree0#_M"))) <= 1
                                                         || rdistance(location(caster), location(npc("#DruidTree1#_M"))) <= 1))
                                                => EFFECT CALL hug_tree(target);

NONMAGIC SPELL hug5 (target : STRING) : "*hugs" = REQUIRE ((rdistance(location(caster), location(npc("#DruidTree0#_M"))) <= 1
                                                         || rdistance(location(caster), location(npc("#DruidTree1#_M"))) <= 1))
                                                => EFFECT CALL hug_tree(target);


#--------------------------------------------------------------------------------
# Teleport anchors
#--------------------------------------------------------------------------------

TELEPORT-ANCHOR tulimshar : "tulimshar" = @("001-1.gat", 43, 66) @+ (3, 3);
TELEPORT-ANCHOR hurnscald : "hurnscald" = @("009-1.gat", 55, 37) @+ (3, 3);
TELEPORT-ANCHOR nivalis : "nivalis" = @("020-1.gat", 75, 63) @+ (19, 12);
TELEPORT-ANCHOR wizardhut : "##00" = @("013-1.gat", 41, 92) @+ (3, 3);
TELEPORT-ANCHOR pachua : "##01" = @("006-1.gat", 22, 101) @+ (3, 3);
TELEPORT-ANCHOR desert : "##02" = @("005-1.gat", 160, 64) @+ (5, 5);
TELEPORT-ANCHOR forest : "##03" = @("015-1.gat", 35, 35) @+ (40, 40);
TELEPORT-ANCHOR snakecave : "##04" = @("011-4.gat", 50, 75) @+ (3, 3);
TELEPORT-ANCHOR dimondscove : "##05" = @("010-2.gat", 23, 79) @+ (3, 3);