summaryrefslogblamecommitdiffstats
path: root/crawl-ref/source/item_use.cc
blob: 4e345054cbfd8fdb588f4833b600062c85109f82 (plain) (tree)
1
2
3
4
5
6
7
8
9
10



                                                            


                   
 

                     
                  





                    
                     
                     
                 
                
                  
                   
                    
                    
                  
                  

                     
                    
                    
                
                          

                  
                    
                    




                     
                     
                
                  
                    
                 
                     
                     
                      


                      
                      
                  
                    

                   
                   
                     
                     




                    
                    

                     
                    
                     
                  
                  
                  
                     
                      
                  
                     
                 
                  

                     
                
 



                                                                             
 

                                                                
 

                                                                              
                                                 
                                                
 
                                          
 
                                                      

                                         
                       
     
 
                                                             

                                                                   
                       
     
 
                                    

                                                 
                                  

                                                                     
                       
     
 












                                                                   
                                                
                                         








                                                                            
 
                                                                             

                                                                 
                       
     
 
                                              

                                                                            

                                                       
                       
     
 
                                                         
     



                                                                           
                                                             






                                                                    
                       
     
 
                                  
                                                        
                                                         
                                                                
     

                       
                                                                                            
                                                               
                                                             







                                                                    

     





                                                                        
                                      
                  

          

 

                                                    
                                            
                                                                      
                      
 



                                                                     
                      
     
 
                                                   


                                       
                                                    

                                      
                                                           
 
                       

     
                   


                                                
                                                     

     
                            
                                                   
                       









                                                               
                   

 


                                                                     
                                                    
 


                                        
                       

     

                                                                      
                               
                       
 

                                                 

                   
                                              



                                                          

     

                                                         

                                                                       
 

                                                                     
                                       
                                                                         
     
                        
         
                                           
                                                                            
                                                   
                                                                         
         

                                           
     
 
                                 
                       





                                               
                                                               








                                                              
     
                                               
         
                                               
                                                          
             

                                                                        


                                                       
 

                                                  
 

                                             
 
                                                     


                                    
         
            
                                                 

                      

     


                                          
                       
 
                                              


                                                            
                       
     
 
                                                                
                                                

                       

                                                          
                       
 

                                                                
                                     
                                     
 
                                                  
                                                 
 
                                                    
 
                                                       

                           
 
                                                                           

                                                    
                         
                        
 
                             
                                      
                             

                  

 







                                                           



                                             

 

                                                                   
                         
                                                                            
                         




                                                                    
                                 
                                                              
 
                        
         

                                                         
                                                   
                                 
         





                                                                             
                      

               
                                                                    
                                          


                
                                 
                                               
                                             
                                                   

                                                                                
                                             
     

 
                                                                
                                                               
                                                         

                                                   
                              
 
                                           
                                                
                                                      
 
                                                                        


                           
     
                                                     


                                                                   
 
                                    
                                               
                                            
         
                                                      
                                                     
              

     
                    
     
                                         
         
                      

                                                         
                                                         
         
                                             
         

                                                         
                                                     
         












                                                                              
              

     
                     
     
                     
         

                                                                            

                                                                               

                                                                             

                                                                               

                                                                            

         


                                                              
 

                                                          
 
                                                     
 

                               
                     
         

                                                              

                           

                                              

                                                                               




                                                                                   


                                                                          
         
 
                                    



                            
                                
                 












                                                                   
                                             
                     

                                                                   
                     

                                                   







                                                                           

                                                     
                                                                            


                                                                           
 







                                                          



                                             




                                                     

                                                      


                                 
                                                 






                                                   

                                                 



                                                             
                                                  
                     
                                                           

                                                           


                        

                                                                 

                          



                                                
                                





                                                                  

                          
                                 
                                                                           


                                              





                                                                             
                                   


                                                                         





                            
                            

                                  
                                               


                                  
                                                            
 
                               
                 
                                                                             






                                                                         

                      
                    



                      
                          
         
                                           
                               
                                                 










                                                                              
         
 
              
     

              
     


                                

                                                    
 








                                                                   
                                                                              



                            
               


                                        
                           


                                    



                                                                      
                                                                 
                                          
 
                                 






                             
 
















                                                                 
                                               
 
                             




                                                             
                          
 


                                                                           

               



                                                              
                                               
     

 
                                                   
 
                                          
 







                                              

 
                                                                               
 
                                                       
                                
     
                    



                                       
 
                         

                                                      
 

                                            
                                             
                                               
        

                                         
                                                                            
     
 

                  
                    
                                        
 


                       

                               
                                      







                                                                     
                              
     
                                              





                                                         
                                              





                                                    
                                   
         
                        
                                            


                           
                                               
                                         
         
                        





                                                     
                                                              
                                                           
     
                   
                      

                                      
                                               
                                                                
     
                   
                      
     
                               
     
                                                          


                                    
                                             






                                                            
                                            

                        
                                                           


                           
     
 
                                             
     
                    
                                                             



                       
                                  
                                                                  
                                         
     

                                            


                                      
                                                 
                                    
         
                        





                                                            
                  
                                                                    
     






                                                 
                                    
         
                        





                                                            


                  
                                         
 
                                            
                            






                                                  
                                                 
                       
 









                                                         
                           








                                                       

                                    
                    
                                       

                                                           





                                                     
 
                               

                    
                                                              

                                                                  
     
                                           
                                                           
         
                       
             
                                                 

                                                                           
             

                           
                                                   
         
                                        


                                                     
                                 









                                                                       
                         




                                     
                                 
     
                                             


                           
                                                

                       
                            
 
                                                  
              
                                                  
 

                                               

                  
 


                             


                                            

                                        
                       

     
                      

                                    
                       

     

                                                                       
     









                                                  
         

                                                   


         
                                              
                         
     
                                                                               


                       
                                               

                       
                               

                   
                               


                                                                   
                                                       




                                                         
                                     



                                                                         
                               

             


        
                     
         
                       
                      
                       
                       
                      
                                        

                                                
                               

                  


                  


         
                            
 
                                                  
                                               
 

                                               
 
                  
 
 




                                                        


                                                  
                                             

                               

                      

                             
                                                    

                                     
         
                           
                                                                        
                                    
         
     
                         

 
                                                         

       
                           

                                                                         
     
                                                               

     
                               

                                                   
                                       
 
                                                              

       

                                
                                 
                     
                     

  

                                                                            

                                                                   
 


                 
                               
 
                           
                     

                         
     
                                                   

                                                                       
 









                                            

                                                            
                
 



                                                      

        

                                                                           
                                                         
                                     
     
 

                                                                          
                                            

 









                                           




                                                 






                                                        















                                                                            
                            















                                                                
                               



                              
     
 
                                                  

 

                                                                 
 
                              
                                         

                   
     

                                             
         
                              
                           
         

                                              
     
 
                              
 

                                                                                
 
                         

                           
                       
     






                               
                                                                      
                             
                      



                  
                                                             
                                               

                                                  
 
                        
     
                                                              
                                              
                  

     

                                                                            

                                                                           
 
                                                       

                                  
                  



                

                                                           

                                    
                                                 
                                  
     
                                                   
                       
     
                                

                                             
                       
     
                  
 
 
                                    

                                      






                                                         
                             
     
                                     
                      
     
 



                                                 
         
                                                                  
                          
         
                                                 
         

                                                                      
                          
         
                                     
     
                      

                                    
                      
     
                   

 
                                                            


                                   
                                               
                    
     
 

                                                              
 



                                         
                    
     


                  



                                                  

                                           


                   
                                                             
     
                  

                                                  
 
 



































                                                                          








                                                                              
                                                                  




                   

              














                                                          
                                                       































                                                                            
 


                                                           
     
                                                                              


                                                           
                                     


                                                     
















                                                                           
                                                  

                                                               


                                                                   
                                                
                                              


                                                  
                          

 

                                                                              
                                                     








                                

                                                                          
     
                                
















                                                                          
 





                                                                       
                                                            









                                                                              
                                                                               

                                                         
                                                               



                       
                                                                        




















                                                                     


                                                                      
                           


                                                        





                                   

                                                                             


















                                                                
                                
                                                                          
 






                                                        


                                           
                              

                                
                                                              

                                              

                                            






                                                         




                  












                                                                               





                                                                          









                                                                            
 



                            

                                              

                                                                     

                                                               





                                                         


















                                                                    


                                    
                       
















                                                       





























                                                                                 





                                                                      


                                      










                                                                  


                                      










                                                                      


                                      










                                                                 


                                      










                                                                     


                                      










                                                                 


                                      







                                                        


                  
                                                                       




















                                                                
                            





























                                                                   
                                                               


                                                 



















                                                                              




                                                
 










                                                                      
                                     
     
 





















                                                                    


























                                                                        
                                    
                                  



                                                                    
                                                                      

                                 
                                    



                                   
                                                                    


                                                                      
                                    

                             
                                   









                                                               

                    
                                                            
                                          
     

                                                      

                                                        



                                                         
 















                                                                     
 
                                                 










                                                     
                                                  

                                                   














                                                         





                                           






















                                                                        
                                                   














                                                     



                                               

                                       

                   

 


                                                                    
                                                                

                                                              
                       
                                                              
                       
                                                                 
                       

                                                              

                                                                          
                                                                  
                       
 
                  

 


























                                                                         


                                                                         
 

                                     

                                                             

                                                                           
             

 

                                       
                                  





                                       
                                                
                     
 







                                                             
                                                                   





                                                          



                                                                     
                                                               

               















                                                          











                                                  
 










                                                       
                                                              
                                               

                                                                  


                                                                         

                                                                     
 
             
                        
                           
 

                               
 





                                                                                

                                                                                
                         
 


                                                                         

                      
     
                                               
 



                                   
 
                           
         
     

                          
                                        
                              
 


                                                                            




                                                                   


                                                                    




                                                                    
 
                          





                                                                    
 
                                                       
                                                          
 
                                              

                                                        
 
                       


                      



                                     

                                                        
                                            
             

                                                



                                            
                                                              


            
                                           




                                                           
                                                                               

     


                                                
                                                                     
                            
 
                                                                             
                                     
     




                                                                
                                 


                                  
                               
 
                     
 

                                                                        
                                 


                                     

                                                

                           

                                  
     
                            
 


                                 
                           
                                                                
     
                                                                        

                           
                         

     


                             
                                                     
     
                                                                
                                                      



                                            
 
                                                             
                                                              
                  
                              
 

                                                  
                               
        
                                                                    

                                             
                                                               
                                    



                                                 
                                                               
 
                                                


                              


                                   
                                                    

                                                  
 
                                        
                                   
     
                                                 



                                                 
 







                                                                    
                                                  









                                                                              
                                         


                                                             
                                                    
                                          

                                                      
 
                                                                   

                                    
                                                     
                                                  
         
                                                                      
             

                          

                                        
                                                                 

                                                 
                              


                 
 
                                           
                                     
                      
 
                                                                     
                                                                        
                                                                   

                                                                     
 

                                                                       
 

                                                                    
 
                                                 
                                  
 
                                                                       
                                                

                                                      






                                                                             



                                                                      
 





                                                               
                                           
             
                                                                    

                                 

         
                                                                      

                                                                     


                               
         
                                                                  
                                                                        
                                                      



                                                                         
 
                                             
 
                                                             

                                                                      

                  
                                                            
 
                                   
                                                                            
                                                                      
 
                                                  
                                                     
                  
         


                                                                    
                         
                         
                                                       
                                                           
 
                                            
                              
 
                                                             

                                                     

                  


                         
                                                   
                                         
 
                                                           

                                                                      
 
                                                                    
                                                                       
                                                            

                                   
 
                                                                                
                                      
 
                                                                      
 
                                                  
                                                     
                  
         

                                                       
                          
                                                        





                                                                      
                


                  







                                                                     
 

                                              
 

                                                                     
                                                          
         

                                                                    
                                                   
             

                                                                        
                                 
                                                                           

                                                                  

             
                                                              
         
                                             
                                                        
 
                                                                            





                                    
                                              
                                                


                         


                                                                              
                      
                           
                                                                           
                                      
                      

                             
                                                                         
                                      
                      
                             
                                                                             
                                      
                      




                      
                                      
                                 
     
                                           
 

                                                                     
 

                    
                                      


                                        
                                                   
                                   
                                        
                                                                   
                                                                     
         
                                        
                                                    
                                             
             
                          
             
 




                                           




                                        
                                  

                                   
                                  





                                     



                                              


                                     
                                    
                                  




                              
 
                                                     
 
                                                  
 
                                                        



                                                        
             
                          

             
                        
                                                                              
 
                                                                    
                                                                     



                                                                          
                                     
         

                                                                
                             
 

                            
                               
                                                

                                
 
                         


                                                              

                                  
                                                            
                      
 
                            
                                               
                                                      
                                                              







                                                                            
                                                   
                                                      
                      
 
                                 
                                                                      

                               
                                 
 
                                                             
                            
                                                                


                                                                 
                                       
                                         
                      
             

         



                                                                      

                                                           
                                                 
         
 

                         
                                     
 
                   

                                                                
                                                           
         

                                                                    
                                                                       
                             

                                                              
         

     
                                      


                                                         
                                                                       
                  
     
                                                                   
         


                                      
                                     
             
                                                           

                                                                
             
 
                                                        

         
                        
     
                              
                                     

                                 





                                                                             

                                                             
                                                         
                                         
         

     
                                





                                                                  
                                                                      
        
                                                                            
 


                                                             
                                                             
                                             




                                                         
                                                          

                                  
 
                             
 
                                                          


                                                               
 
                      


                                               
                                                         
                              
 
                                                 
                            
                            
 
                                                                           



                                                            
                     


                                                      

                                       
                                
                                                     
                                
     

        

                                         
 
                                                                          
                                      
                     

                                                      
                                                                       
                               

     
                                                              
     
                                                  


                                                                      
                                                                  

                                          
                                                                        
     
 




                                                                     
                   
     
                                
                              
                          
                     
 

                                                                          
 
                                      
                                           





                                                                              
     
        
     
                                           
                                                           
         

                                                                         
         
                                          

                                         
     
 
                                     
 

                                                                         
                            
 


                                          

                            


                                        
                 
 
 
                                                                    
 
                         

                   
 





                                                                  

                                        
                                          
                                                             
                          
 




                                                                           
                                                     
                  
 
                             
















                                                 





                           
 

                                 
                                 


                                 
                                   
                        

     

                                                          

                                                                                



                     

                                           
                                                         
                                                               
                                                 
 


                                                                     
                                                



                                                                   
 












                                    
                       


                               








                                                                          
                         
                                       
                           


                                      
                                   
             
                                                    

                                                           
                                
         


                           
                                     

                                                        
                         
                                          
                
                                      



                      
                                  
                           


                                      
                                   
                                                                                
                                
         


                       




                                                               
                                         

                                      
 

                               


                        




                                                                
                                          

                                      
 

                               


                           


                                                                   
 
                         
                                             




                                      


                            
                                                     
                  
                     
                                          
            
                                  


                         
                                           
         
                               


                                                                  
                         
                                         
                

                                      

              
                            




                                                
              
 
                  
                                          

                                                                    
                         
                                        
                

                                      

              







                                                                   
                          
                                                  

                                       







                                                               





                                                                     

                                                                                 



                                  






                                                                            


                                                                     
                                                           
                 
     

                                       

                                                                
                                                      
 

                                                    





                                                            
     
        
     
                                    
 
                                   
                                                            
     
 
                      
     
                                                 
                                                           
                                              
 









                                                                 
     
 
                                                               
                                             
 
                                                 

 
                                               
 

                                                         
 
                                          





                                                         
                                                                      
 

                                                    

                      
                                                                        

                       

                                                          
 



                                                                


                    

                                                           





                                

                                                                

                                                                             
                    
 


                               

                                                                  


                                                                   



                     


                                                   
 
                                                  
                                       
                                                














                                     


                             




                  
























                                                              
                          
     


                                                                         
 

                                                                                






                                                                            

     

















































                                                                                      

               
                                                             
                                                               
         
                       





                                                                               




                           

                                                               
         
                       





                                                                              
 



                           


                  





                                                                         
                                      
 


                                                         
                                           








                                                         

                                       

                                                        
                            









                                                                   
                       

                           
                       
     
 

                                      
 
                                             

                                                           
 
                           
                                                  
 

                  
 
                              
 

                                        



                                                
                                                             






                                                       




                                             
                       

     
                                        
     
                                              
                       

     


                                                              
 
                                           
     
                                                          
                                       

                                                                    
                           

         
                           
                                          
     
                                                         
     


                                                             
         
                           
         
 

                                                   
                           
 
                                 
                                                      
 

                                        

     

                                             
                       
 
                             

                  
     



                              
                                               
                                 
 
                                                                    

                                      

     

                                                                

                                     
 

                                 
 
                                                                           

                                                    
                                                           
                        




                            
                         
 
                             




                                                               







                                        
                      







                                    
     
                                                                           

                                                                              
     
 
                                 
                       
 
                                 
 
 




















                                                                 
                                                        

                                                                            
 

                                                                             
                                                        
                                  
 
             
                                                                   



                                             








                                    


                            

                                

                            
                               


                         
                                       


                      
                                  


                       
                                                                  


                        
                                                                   


                           
                                                                      

              

                                                                        
                                             

              

                                    
                                        

              
                            
                                                     
                         

              

                                       
              
 



                                     
                             

                                                             

     
                          
                                    
 
                                               
              

 
                                         
 
                             




                                                                       
                                       
                    




                                                                       
                       

     
                      

                                    
                       

     
                                  
                                                  


                                                                   
                       




                                                                       
                                 




                                                                       
                                  




                                                                       
                              

     
                             
     
                          



                                                                                
                               
 
                                  
                           



                                                       
                           


                                              
                                     
                                                    
                                      
                                                
                                  


                                            
                           

         
 
                                                                  
                                                 



                           
 
                                  
                                                  
                                                                     

                                                                   
                       

     
                                   

                                                    
                       

     
                                                
     
                     
         
                                       
                                                                            
         

                                      
 
                                                                          
                       
     
 
                                       
 
                       


                                                            
                              
 
                                                   
 
                        
                            

                  
 
 










                                                             











                                                                     
                                                   






                      
                       
 





                                     

                  
                  
 
                                                                      
                                              
                                            
 
                                






                                        
                      




                                    


                         
     




                                                                     

     
                                 
               
 

                                        

                                        


               
                                                                       


                                          

                                            

                            
     





                                             

     
                                                    
                                                    

                                                                        
 

                                  
        
     
                              
         
                          
                                
                                 

                  
                          






                                             
                               
                                    
                  
 
                
                                     
                  


         
                                                                               
                                                                     
                                                           







                               
                                                     
     










                                                                 

     









                                                    
                       
                                                                              
 
                                             
                                  
 

                                 
                              

                                                    
 
                                                                             

                                                                       
                       
     







                                                                 
     
 


                                                                        



                                                           

                                                                      





                                                                 

                                          










                                                        
                              

                                                                               
                         

                
                                               
                                                                               
                       
                           
                        

                     
                             
                                                                              
     
                                            


                                                                 
                                                     

        
                                            
 
                             
                                                

                                                            
                                                  
         

                                                                   

         
                                               
                                                   
 
                                                  

     
                               

                            
                                                


                                                                   
                               

     
                            
 
 
                           
 

                        

                                                    
     
 
                                                              
                                                             
 
                                 
               
 
                                            

 
                    
 





                                   
                   
     

                                                                      
                                  
                       

     
                         




                                        
                      




                                    
                             



                                    
 
                   
     





                                                                

     
                                     
 
                                        




                                     
                                                      
 
                                                       
                                                                        




                                                





                                                           
                                                           




                                           


                                                                      

                                                         
 


                                                                
     

                                                   


        
                                              
     
 



                                                                     
                               
     
 
                                
     
                                      
                                           
     

                                   
                            
 

                                  
 
 
                      
 
                                                     
 

                                                                
 
                                         

                                                        
                       

     
                      

                                    
                      

     
                                            
                                   
     
                                                          
                           
 

                                                
                                         
     
                                                                   
                           
 

                                    
     
        
     
                                                                    
                           
 
                                              
 







                                                        

                                                       















                                                              

     
                                                                     

                              

                                                                       
                                                                               
 
                          
                                   
     
                              
                            
     
                                         
     

                                                      

                            
                                
     
                              
                            
                                  
         

                                                                       
                                                
                                           
         




                                      
 
                                                               
                                                                        
 
                                       
 
                                        

     
                            

                  
 


                                                                          
 
                      
                       
 




                                                                   
                       
     
 








                                                          
                      



                                            
                       
 



                                                               
 
                                  

                      
                                                   
                                                                         
            
                                                                      

              
                     
                       
                                                                          
                                                                

              
                     
                        



                                                                               



                               
                                                                     



                     
                                                                    


                              
                    
                                                                   
                                                         
 
                                                        
                        
 
                                                            
                                                                          
                                           

                                                                         

              
                          

                                                                             
                                                      

                            

                                                                    
                        



                        
                    





                                           
                 

 
                                                                            
 

                                                 
                                        
                                                  

                   
                                              



                       
                                        
 
                                   
                                      
     
                                    

                          
 

                                             
 
                                                

                                                                               
     
                      


                       
                                                     
                                                      

             
                                 






                                                



                                                                          



                           
                                                     
                                                
 
                                     
     
                   
         
                       


                                                                    
         
            
         
                       


                                                                  

         
                                           
     

                   

                                                              
         
 
                   

     
                  
                             
 


                  

                                                                




                                           

                                        
                       
     









                                                         
                                                              
 
                  
 
                                        
                                          
     

                                              
 
                       
     
 
                                        
 


                                                                          
                                   
     




                                                  
 
                                           
                         
                                                       

                      
                                 
 
                                     
                      

     
                                                
                                          

                                                       
     
                      
         




                                                      

                                 


                          
         
                       
                                                
 



                                                                          
                           
         

     
                                                                   




                                              
 
               
                
 
                  
                             
 


                  
                                                 
 
      
     






                                                                             
 
                                          
 




                                                                           
 


                           
 


                                                                
 







                                           

 
                                           
 
                                       
 
                                          
     
                                
                                                                        

                                     

               
                                          



                                
 
                

                    
                                                            
 
                                                               
         
                         

                   
 
                                                          

                                                                           
         
                         

                   
 




                                                            
     

 




                                                                             
                                                
 







                                                                              


                                                                                 
 

                                 
 
                                        
 


                            
                                    





                                                 
                        
                                                    
         

                                                                             


                                         
         
              
                            

                                              

                                                                     
                                                  


                              
              
            
                                                                    
              
     
 


                                    

 
                                   
 


                                        
                                                            


                                              
                   
                   


                       
                    







                                                           
                                    

                                                             
                                            
         
                                               
                                                                         
                                                                
 
                                                          

                                          
 
                                                                      
                                    
                                                        

         
 
                                                                         
 
 

                          
                      




                                    





                                     





                                        





                                                                               
 
                                 
               
 


                                                                         

                                    
                                       


               
                                        
                                      




                                      
                            

                                                               
                                       


               
                                                         
                            
 
                                                                           
                                                
                                                                      
     
                                                                               




                                                                      
                                                                           
                                                                               









                                                                              
                                 
                                                              




                                                            
                                                         
 
                                                                   
                                  
     
                           
         
                                          
                                                






                                                           

                                                                  
                                                                    
                                                                      
 
                                                                              
                         

                   
                                                                      
                                                
                                                          
                                  


                                
                                      


                      
                           
















                                  

                                                
                                           


                  



                                                                           
              
     

                   
                                                                


                       


                                                                               
                                                                         

                                                         

                                             
                                                  
         




                                            
              
     
 

                                                
                                                                              

              
                           


                                                
                                                         


                                                                
            
                                                       


                     
                                           
 
                                                            
                                                                     
                          



                                                  
 
                                                                              
                                                                         
                          
               

              
                          

                                                     
                                      




                                            
         
                                      
                                                  
                                                  
                              


              
                                                                       
                              
                                                               


                               
                                                               


                                
                         
         
                                          
 
                                                
 











                                                                             


                                                             



                                                             
 




                                                                    
 




                                                                 
 





                                                                         
 

                                     
 
                        


                                                                           




                                                
             








                                            
                                            
                           
                                            

              
                      
                                     
         
                                                        


                                     
            
                         
              
 
                        
                                     
         
                                                        


                                     
            
                              


                            
                                     
         
                                                        


                                     
            
                                       


                          
     
                                                     


                                                        
         
                                                                      

                        
                                         









                                            



                                                             
                          
              
     
 
                       

                      
 




                                                                     
 
                                                                        
                                                                       

                     



                                            
 



                                                                       
              

     



                         

                                

              


                                                        
     
 


                                                             
 
                                                
                                  
     
                          
                                                                   
 


                                              

                                   
                                                                      


                                                                         
     
 
 
                         
 
                                                              
                                                       
                                                                      
                                                       
                                 
               
 
                                              
                    
                 

                                                      
                                                              
 
                                                       

 
                                                               
 

                                                               
                                  
 















                                                                             
                                                    
                                                            
 


                                                   
 
                                                                     
                        
     
                                       
                            
         
                                                     
                                                       
                                                   

         
 
                             
     
                                  
                                 
         
                                                                   
                                             
                                                        

         
 
                                                                 
     


                                                                      

     

                                                                          


                                                                             
 

                                                           
 

                                          
                                                         
 
                                                                   

                                                                   

                                                         
     
                           


                                                              
                                                     
     
 
                                                                   

                                                    
                                                      
     
 

                                                        

                                                                
                                                    
     
 
                                                            
                                               
     
                                     
                                                   

     
                            
                                       
 

                                                                   
 

                                   
                                                                   
                                                 
                               
     



                                               
                     
 



                                               

                                     
 
                   
 
 










































                                                                        
               
                                      

                                 
 


                                                
     
                      
     



                              
                                                












                                                                       
     

                                                                       
     





                                       
                                                                  
     

                                                        
     
                                         
     
                                                          
     
                                      








                                                      


                          
                                 
                                                



                                

                                       



                  

                                                        


                                                      

                                                
     



                                               

                                    
             
                 


                         
                            
                       
                                                       
                         


                                                                              
             
                                        
                       
             
                                                 
                                       
             
                                
                       
             
                                     
                         
                                                                  
                   
 
                          

                                                            


                        




                                                                               
                                             
             
                                                                   
                                        
             
                                                                 
                                 

                   
                         
                                         

                                                   
             
                      
             
                                                    
                      
                                                           
                              

                   
                       
                                            

                                                    
             
                                                                

                                          
                                                                     
                                                                              
                   
 
                         
                                                            
                                 


                           
                                             
             
                                                                  
                                     
             
                                                                  
                                


                         
                                                             
                           






                   
/*
 *  File:       item_use.cc
 *  Summary:    Functions for making use of inventory items.
 *  Written by: Linley Henzell
 */

#include "AppHdr.h"

#include "item_use.h"

#include <sstream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include "externs.h"

#include "abl-show.h"
#include "artefact.h"
#include "beam.h"
#include "cio.h"
#include "cloud.h"
#include "colour.h"
#include "command.h"
#include "coordit.h"
#include "debug.h"
#include "decks.h"
#include "delay.h"
#include "describe.h"
#include "directn.h"
#include "effects.h"
#include "env.h"
#include "map_knowledge.h"
#include "fight.h"
#include "food.h"
#include "godabil.h"
#include "goditem.h"
#include "invent.h"
#include "it_use2.h"
#include "it_use3.h"
#include "items.h"
#include "itemname.h"
#include "itemprop.h"
#include "los.h"
#include "macro.h"
#include "message.h"
#include "misc.h"
#include "mon-behv.h"
#include "mon-util.h"
#include "mon-place.h"
#include "terrain.h"
#include "mgen_data.h"
#include "coord.h"
#include "mon-stuff.h"
#include "notes.h"
#include "options.h"
#include "ouch.h"
#include "player.h"
#include "quiver.h"
#include "religion.h"
#include "shopping.h"
#include "skills.h"
#include "skills2.h"
#include "spells1.h"
#include "spells2.h"
#include "spells3.h"
#include "spells4.h"
#include "spl-book.h"
#include "spl-cast.h"
#include "spl-mis.h"
#include "spl-util.h"
#include "state.h"
#include "stuff.h"
#include "areas.h"
#include "teleport.h"
#include "transform.h"
#include "traps.h"
#include "tutorial.h"
#include "view.h"
#include "shout.h"
#include "viewchar.h"
#include "viewgeom.h"
#include "xom.h"

static bool _drink_fountain();
static bool _handle_enchant_weapon( enchant_stat_type which_stat,
                                    bool quiet = false, int item_slot = -1 );
static bool _handle_enchant_armour( int item_slot = -1 );

static int  _fire_prompt_for_item(std::string& err);
static bool _fire_validate_item(int selected, std::string& err);

// Rather messy - we've gathered all the can't-wield logic from wield_weapon()
// here.
bool can_wield(item_def *weapon, bool say_reason,
               bool ignore_temporary_disability)
{
#define SAY(x) if (say_reason) { x; } else

    if (!ignore_temporary_disability && you.berserk())
    {
        SAY(canned_msg(MSG_TOO_BERSERK));
        return (false);
    }

    if (!can_equip( EQ_WEAPON, ignore_temporary_disability ))
    {
        SAY(mpr("You can't wield anything in your present form."));
        return (false);
    }

    if (!ignore_temporary_disability
        && you.weapon()
        && you.weapon()->base_type == OBJ_WEAPONS
        && you.weapon()->cursed())
    {
        SAY(mpr("You can't unwield your weapon to draw a new one!"));
        return (false);
    }

    // If we don't have an actual weapon to check, return now.
    if (!weapon)
        return (true);

    for (int i = EQ_CLOAK; i <= EQ_AMULET; i++)
    {
        if (you.equip[i] != -1 && &you.inv[you.equip[i]] == weapon)
        {
            SAY(mpr("You are wearing that object!"));
            return (false);
        }
    }

    // All non-weapons only need a shield check.
    if (weapon->base_type != OBJ_WEAPONS)
    {
        if (!ignore_temporary_disability && is_shield_incompatible(*weapon))
        {
            SAY(mpr("You can't wield that with a shield."));
            return (false);
        }
        else
            return (true);
    }

    if (you.body_size(PSIZE_TORSO) < SIZE_LARGE && item_mass(*weapon) >= 300)
    {
        SAY(mpr("That's too large and heavy for you to wield."));
        return (false);
    }

    // Small species wielding large weapons...
    if (you.body_size(PSIZE_BODY) < SIZE_MEDIUM
        && !check_weapon_wieldable_size(*weapon, you.body_size(PSIZE_BODY)))
    {
        SAY(mpr("That's too large for you to wield."));
        return (false);
    }

    if (you.undead_or_demonic() && is_holy_item(*weapon))
    {
        if (say_reason)
        {
            mpr("This weapon is holy and will not allow you to wield it.");
            // If it's a standard weapon, you know its ego now.
            if (!is_artefact(*weapon) && !is_blessed(*weapon)
                && !item_type_known(*weapon))
            {
                set_ident_flags(*weapon, ISFLAG_KNOW_TYPE);
                if (in_inventory(*weapon))
                    mpr(weapon->name(DESC_INVENTORY_EQUIP).c_str());
            }
        }
        return (false);
    }

    if (you.hunger_state < HS_FULL
        && you.hunger < you_max_hunger() - 500 // ghouls
        && get_weapon_brand(*weapon) == SPWPN_VAMPIRICISM
        && you.species != SP_VAMPIRE && you.species != SP_MUMMY)
    {
        if (say_reason)
        {
            mpr("As you grasp it, you feel a great hunger.  Being not satiated, you stop.");
            // If it's a standard weapon, you know its ego now.
            if (!is_artefact(*weapon) && !is_blessed(*weapon)
                && !item_type_known(*weapon))
            {
                set_ident_flags(*weapon, ISFLAG_KNOW_TYPE);
                if (in_inventory(*weapon))
                    mpr(weapon->name(DESC_INVENTORY_EQUIP).c_str());
            }
        }
        return (false);
    }

    if (!ignore_temporary_disability && is_shield_incompatible(*weapon))
    {
        SAY(mpr("You can't wield that with a shield."));
        return (false);
    }

    // We can wield this weapon. Phew!
    return (true);

#undef SAY
}

static bool _valid_weapon_swap(const item_def &item)
{
    // Weapons and staves are valid weapons.
    if (item.base_type == OBJ_WEAPONS || item.base_type == OBJ_STAVES)
        return (true);

    // Some misc. items need to be wielded to be evoked.
    if (is_deck(item) || item.base_type == OBJ_MISCELLANY
                         && item.sub_type == MISC_LANTERN_OF_SHADOWS)
    {
        return (true);
    }

    // Some missiles need to be wielded for spells.
    if (item.base_type == OBJ_MISSILES)
    {
        if (item.sub_type == MI_STONE)
            return (you.has_spell(SPELL_SANDBLAST));

        if (item.sub_type == MI_ARROW)
            return (you.has_spell(SPELL_STICKS_TO_SNAKES));

        return (false);
    }

    // Bone Shards.
    if (item.base_type == OBJ_CORPSES)
    {
        return (item.sub_type == CORPSE_SKELETON
                && you.has_spell(SPELL_BONE_SHARDS));
    }

    // Sublimation of Blood.
    if (!you.has_spell(SPELL_SUBLIMATION_OF_BLOOD))
        return (false);

    if (item.base_type == OBJ_FOOD)
        return (item.sub_type == FOOD_CHUNK);

    if (item.base_type == OBJ_POTIONS && item_type_known(item))
    {
       return (item.sub_type == POT_BLOOD
               || item.sub_type == POT_BLOOD_COAGULATED);
    }

    return (false);
}

// If force is true, don't check weapon inscriptions.
// (Assuming the player was already prompted for that.)
bool wield_weapon(bool auto_wield, int slot, bool show_weff_messages,
                  bool force, bool show_unwield_msg)
{
    if (inv_count() < 1)
    {
        canned_msg(MSG_NOTHING_CARRIED);
        return (false);
    }

    // Look for conditions like berserking that could prevent wielding
    // weapons.
    if (!can_wield(NULL, true))
        return (false);

    int item_slot = 0;          // default is 'a'

    if (auto_wield)
    {
        if (item_slot == you.equip[EQ_WEAPON])
            item_slot = 1;      // backup is 'b'

        if (slot != -1)         // allow external override
            item_slot = slot;
    }

    // If the swap slot has a bad (but valid) item in it,
    // the swap will be to bare hands.
    const bool good_swap = (item_slot == PROMPT_GOT_SPECIAL
                            || _valid_weapon_swap(you.inv[item_slot]));

    // Prompt if not using the auto swap command, or if the swap slot
    // is empty.
    if (item_slot != PROMPT_GOT_SPECIAL
        && (!auto_wield || !you.inv[item_slot].is_valid() || !good_swap))
    {
        if (!auto_wield)
        {
            item_slot = prompt_invent_item(
                            "Wield which item (- for none, * to show all)?",
                            MT_INVLIST, OSEL_WIELD,
                            true, true, true, '-', -1, NULL, OPER_WIELD);
        }
        else
            item_slot = PROMPT_GOT_SPECIAL;
    }

    if (prompt_failed(item_slot))
        return (false);
    else if (item_slot == you.equip[EQ_WEAPON])
    {
        mpr("You are already wielding that!");
        return (true);
    }

    // Now we really change weapons! (Most likely, at least...)
    if (you.duration[DUR_SURE_BLADE])
    {
        mpr("The bond with your blade fades away.");
        you.duration[DUR_SURE_BLADE] = 0;
    }
    // Reset the warning counter.
    you.received_weapon_warning = false;

    if (item_slot == PROMPT_GOT_SPECIAL)  // '-' or bare hands
    {
        if (const item_def* wpn = you.weapon())
        {
            // Can we safely unwield this item?
            if (has_warning_inscription(*wpn, OPER_WIELD))
            {
                const std::string prompt =
                    "Really unwield " + wpn->name(DESC_INVENTORY) + "?";
                if (!yesno(prompt.c_str(), false, 'n'))
                    return (false);
            }

            if (!unwield_item(show_weff_messages))
                return (false);

            if (show_unwield_msg)
                canned_msg(MSG_EMPTY_HANDED);

            // Switching to bare hands is extra fast.
            you.turn_is_over = true;
            you.time_taken *= 3;
            you.time_taken /= 10;
        }
        else
            mpr("You are already empty-handed.");

        return (true);
    }

    item_def& new_wpn(you.inv[item_slot]);

    if (!can_wield(&new_wpn, true))
        return (false);

    // For non-auto_wield cases checked above.
    if (auto_wield && !force
        && !check_warning_inscriptions(new_wpn, OPER_WIELD))
    {
        return (false);
    }

    // Make sure that wielding the weapon won't kill the player.
    if (!safe_to_remove_or_wear(new_wpn, false))
        return (false);

    // Unwield any old weapon.
    if (you.weapon() && !unwield_item(show_weff_messages))
        return (false);

    const unsigned int old_talents = your_talents(false).size();

    // Go ahead and wield the weapon.
    you.equip[EQ_WEAPON] = item_slot;

    // Any oddness on wielding taken care of here.
    wield_effects(item_slot, show_weff_messages);

    mpr(new_wpn.name(DESC_INVENTORY_EQUIP).c_str());

    // Warn player about low str/dex or throwing skill.
    if (show_weff_messages)
        wield_warning();

    if (Tutorial.tutorial_left && your_talents(false).size() > old_talents)
        learned_something_new(TUT_NEW_ABILITY_ITEM);

    // Time calculations.
    you.time_taken /= 2;

    you.wield_change  = true;
    you.m_quiver->on_weapon_changed();
    you.turn_is_over  = true;

    return (true);
}

static const char *shield_base_name(const item_def *shield)
{
    return (shield->sub_type == ARM_BUCKLER? "buckler"
                                           : "shield");
}

static const char *shield_impact_degree(int impact)
{
    return (impact > 160 ? "severely "      :
            impact > 130 ? "significantly " :
            impact > 110 ? ""
                         : NULL);
}

static void warn_launcher_shield_slowdown(const item_def &launcher)
{
    const int slowspeed =
        launcher_final_speed(launcher, you.shield()) * player_speed() / 100;
    const int normspeed =
        launcher_final_speed(launcher, NULL) * player_speed() / 100;

    // Don't warn the player unless the slowdown is real.
    if (slowspeed > normspeed)
    {
        const char *slow_degree =
            shield_impact_degree(slowspeed * 100 / normspeed);

        if (slow_degree)
        {
            mprf(MSGCH_WARN,
                    "Your %s %sslows your rate of fire.",
                    shield_base_name(you.shield()),
                    slow_degree);
        }
    }
}

// Warn if your shield is greatly impacting the effectiveness of your weapon?
void warn_shield_penalties()
{
    if (!you.shield())
        return;

    // Warnings are limited to bows and quarterstaves at the moment.
    const item_def *weapon = you.weapon();
    if (!weapon)
        return;

    if (is_range_weapon(*weapon))
        warn_launcher_shield_slowdown(*weapon);
    else if (weapon->base_type == OBJ_WEAPONS
             && weapon_skill(*weapon) == SK_STAVES)
    {
        mprf(MSGCH_WARN, "Your %s severely limits your weapon's effectiveness.",
             shield_base_name(you.shield()));
    }
}

// Provide a function for handling initial wielding of 'special'
// weapons, or those whose function is annoying to reproduce in
// other places *cough* auto-butchering *cough*.    {gdl}
void wield_effects(int item_wield_2, bool showMsgs)
{
    unsigned char special = 0;

    item_def &item = you.inv[item_wield_2];
    const bool artefact     = is_artefact(item);
    const bool known_cursed = item_known_cursed(item);

    // And here we finally get to the special effects of wielding. {dlb}
    switch (item.base_type)
    {
    case OBJ_MISCELLANY:
    {
        if (item.sub_type == MISC_LANTERN_OF_SHADOWS)
        {
            if (showMsgs)
                mpr("The area is filled with flickering shadows.");

            you.current_vision -= 2;
            set_los_radius(you.current_vision);
            you.attribute[ATTR_SHADOWS] = 1;
        }
        else if (item.sub_type == MISC_HORN_OF_GERYON)
            set_ident_flags(item, ISFLAG_IDENT_MASK);
        break;
    }

    case OBJ_STAVES:
    {
        if (item.sub_type == STAFF_POWER)
        {
            calc_mp();
            set_ident_type(item, ID_KNOWN_TYPE);
            set_ident_flags(item, ISFLAG_EQ_WEAPON_MASK);
            mpr("You feel your mana capacity increase.");
        }
        else if (!maybe_identify_staff(item))
        {
            // Give curse status when wielded.
            // Right now that's always "uncursed". -- bwr
            set_ident_flags(item, ISFLAG_KNOW_CURSE);
        }
        // Automatically identify rods; you can do this by wielding and then
        // evoking them, so do it automatically instead. We don't need to give
        // a message either, as the game will do that automatically. {due}
        if (item_is_rod(item))
        {
            if (!item_type_known(item))
            {
                set_ident_type( OBJ_STAVES, item.sub_type, ID_KNOWN_TYPE );
                set_ident_flags( item, ISFLAG_KNOW_TYPE );
            }
            if (!item_ident( item, ISFLAG_KNOW_PLUSES))
                set_ident_flags( item, ISFLAG_KNOW_PLUSES );
        }
        break;
    }

    case OBJ_WEAPONS:
    {
        if (showMsgs)
        {
            if (is_holy_item(item) && you.religion == GOD_YREDELEMNUL)
                mpr("You really shouldn't be using a holy item like this.");
            else if (is_unholy_item(item) && is_good_god(you.religion))
                mpr("You really shouldn't be using an unholy item like this.");
            else if (is_evil_item(item) && is_good_god(you.religion))
                mpr("You really shouldn't be using an evil item like this.");
            else if (is_chaotic_item(item) && you.religion == GOD_ZIN)
                mpr("You really shouldn't be using a chaotic item like this.");
            else if (is_hasty_item(item) && you.religion == GOD_CHEIBRIADOS)
                mpr("You really shouldn't be using a fast item like this.");
        }

        // Call unrandrt equip func before item is identified.
        if (artefact)
            use_artefact(item_wield_2, &showMsgs);

        const bool was_known      = item_type_known(item);
              bool known_recurser = false;

        set_ident_flags(item, ISFLAG_EQ_WEAPON_MASK);

        special = item.special;

        if (artefact)
        {
            special = artefact_wpn_property(item, ARTP_BRAND);

            if (!was_known)
            {
                item.flags |= ISFLAG_NOTED_ID;

                if (Options.autoinscribe_artefacts)
                    add_autoinscription(item, artefact_auto_inscription(item));

                // Make a note of it.
                take_note(Note(NOTE_ID_ITEM, 0, 0, item.name(DESC_NOCAP_A).c_str(),
                               origin_desc(item).c_str()));
            }
            else
                known_recurser = artefact_known_wpn_property(item,
                                                             ARTP_CURSED);
        }

        if (special != SPWPN_NORMAL)
        {
            // message first
            if (showMsgs)
            {
                switch (special)
                {
                case SPWPN_FLAMING:
                    mpr("It bursts into flame!");
                    break;

                case SPWPN_FREEZING:
                    mpr("It glows with a cold blue light!");
                    break;

                case SPWPN_HOLY_WRATH:
                    mpr("It softly glows with a divine radiance!");
                    break;

                case SPWPN_ELECTROCUTION:
                    if (!silenced(you.pos()))
                    {
                        mpr("You hear the crackle of electricity.",
                            MSGCH_SOUND);
                    }
                    else
                        mpr("You see sparks fly.");
                    break;

                case SPWPN_ORC_SLAYING:
                    mpr((you.species == SP_HILL_ORC)
                            ? "You feel a sudden desire to commit suicide."
                            : "You feel a sudden desire to kill orcs!");
                    break;

                case SPWPN_DRAGON_SLAYING:
                    mpr(player_genus(GENPC_DRACONIAN)
                        || you.attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON
                            ? "You feel a sudden desire to commit suicide."
                            : "You feel a sudden desire to slay dragons!");
                    break;

                case SPWPN_VENOM:
                    mpr("It begins to drip with poison!");
                    break;

                case SPWPN_PROTECTION:
                    mpr("You feel protected!");
                    break;

                case SPWPN_EVASION:
                    mpr("You feel nimbler!");
                    break;

                case SPWPN_DRAINING:
                    mpr("You sense an unholy aura.");
                    break;

                case SPWPN_SPEED:
                    mprf("Your %s tingle!",
                         you.hand_name(true).c_str());
                    break;

                case SPWPN_FLAME:
                    mpr("It bursts into flame!");
                    break;

                case SPWPN_FROST:
                    mpr("It is covered in frost.");
                    break;

                case SPWPN_VAMPIRICISM:
                    if(you.species == SP_VAMPIRE)
                    {
                        mpr("You feel a bloodthirsty glee!");
                        break;
                    }

                    if (you.is_undead == US_ALIVE)
                    {
                        mpr("You feel a dreadful hunger.");
                        // takes player from Full to Hungry
                        make_hungry(4500, false, false);
                    }
                    else
                    {
                        mpr("You feel an empty sense of dread.");
                    }
                    break;

                case SPWPN_RETURNING:
                    mpr("It wiggles slightly.");
                    break;

                case SPWPN_PAIN:
                    if(you.skills[SK_NECROMANCY] == 0)
                        mpr("You have a feeling of ineptitude.");
                    else if(you.skills[SK_NECROMANCY] <= 4)
                        mpr("Pain shudders through your arm!");
                    else
                        mpr("A searing pain shoots up your arm!");
                    break;

                case SPWPN_CHAOS:
                    mpr("It is briefly surrounded by a scintillating aura "
                        "of random colours.");
                    break;

                case SPWPN_PENETRATION:
                    mprf("Your %s briefly pass through it before you manage "
                         "to get a firm grip on it.",
                         you.hand_name(true).c_str());
                    break;

                case SPWPN_REAPING:
                    mpr("It is briefly surrounded by shifting shadows.");
                    break;

                default:
                    break;
                }
            }

            // effect second
            switch (special)
            {
            case SPWPN_PROTECTION:
                you.redraw_armour_class = true;
                break;

            case SPWPN_DISTORTION:
                mpr("Space warps around you for a moment!");

                if (!was_known)
                {
                    // Xom loves it when you ID a distortion weapon this way,
                    // and even more so if he gifted the weapon himself.
                    god_type god;
                    if (origin_is_god_gift(item, &god) && god == GOD_XOM)
                        xom_is_stimulated(255);
                    else
                        xom_is_stimulated(128);
                }
                break;

            default:
                break;
            }
        }

        if (item.cursed())
        {
            mpr("It sticks to your hand!");
            int amusement = 16;
            if (!known_cursed && !known_recurser)
            {
                amusement *= 2;
                god_type god;
                if (origin_is_god_gift(item, &god) && god == GOD_XOM)
                    amusement *= 2;
            }
            const int wpn_skill = weapon_skill(item.base_type, item.sub_type);
            if (wpn_skill != SK_FIGHTING && you.skills[wpn_skill] == 0)
                amusement *= 2;

            xom_is_stimulated(amusement);
        }

        break;
    }
    default:
        break;
    }

    if (showMsgs)
        warn_shield_penalties();

    you.attribute[ATTR_WEAPON_SWAP_INTERRUPTED] = 0;
}

//---------------------------------------------------------------
//
// armour_prompt
//
// Prompt the user for some armour. Returns true if the user picked
// something legit.
//
//---------------------------------------------------------------
bool armour_prompt(const std::string & mesg, int *index, operation_types oper)
{
    ASSERT(index != NULL);

    bool  succeeded = false;
    int   slot;

    if (inv_count() < 1)
        canned_msg(MSG_NOTHING_CARRIED);
    else if (you.berserk())
        canned_msg(MSG_TOO_BERSERK);
    else
    {
        int selector = OBJ_ARMOUR;
        if (oper == OPER_TAKEOFF && !Options.equip_unequip)
            selector = OSEL_WORN_ARMOUR;
        slot = prompt_invent_item( mesg.c_str(), MT_INVLIST, selector,
                                   true, true, true, 0, -1, NULL,
                                   oper );

        if (!prompt_failed(slot))
        {
            *index = slot;
            succeeded = true;
        }
    }

    return (succeeded);
}

static bool cloak_is_being_removed( void )
{
    if (current_delay_action() != DELAY_ARMOUR_OFF)
        return (false);

    if (you.delay_queue.front().parm1 != you.equip[ EQ_CLOAK ])
        return (false);

    return (true);
}

//---------------------------------------------------------------
//
// wear_armour
//
//---------------------------------------------------------------
void wear_armour(int slot) // slot is for tiles
{
    if (player_in_bat_form())
    {
        mpr("You can't wear anything in your present form.");
        return;
    }

    int armour_wear_2 = 0;

    if (slot != -1)
        armour_wear_2 = slot;
    else if (!armour_prompt("Wear which item?", &armour_wear_2, OPER_WEAR))
        return;

    // Wear the armour.
    if (safe_to_remove_or_wear( you.inv[armour_wear_2],
                                wearing_slot(armour_wear_2) ))
    {
        do_wear_armour( armour_wear_2, false );
    }
}

static int armour_equip_delay(const item_def &item)
{
    int delay = property( item, PARM_AC );

    // Shields are comparatively easy to wear.
    if (is_shield( item ))
        delay = delay / 2 + 1;

    if (delay < 1)
        delay = 1;

    return (delay);
}

bool can_wear_armour(const item_def &item, bool verbose, bool ignore_temporary)
{
    const object_class_type base_type = item.base_type;
    if (base_type != OBJ_ARMOUR)
    {
        if (verbose)
           mpr("You can't wear that.");

        return (false);
    }

    bool can_wear = true;
    const int sub_type = item.sub_type;
    const equipment_type slot = get_armour_slot(item);

    if (sub_type == ARM_NAGA_BARDING)
        can_wear = (you.species == SP_NAGA);
    else if (sub_type == ARM_CENTAUR_BARDING)
        can_wear = (you.species == SP_CENTAUR);
    else
    {
        can_wear = (fit_armour_size(item,
                        you.body_size(PSIZE_TORSO, ignore_temporary)) == 0);
    }

    if (!can_wear)
    {
        if (verbose)
            mpr("You can't wear that!");

        return (false);
    }

    if (sub_type == ARM_GLOVES)
    {
        if (you.has_claws(false) >= 3)
        {
            if (verbose)
                mpr( "You can't wear gloves with your huge claws!" );

            return (false);
        }
    }

    if (sub_type == ARM_BOOTS)
    {
        if (player_mutation_level(MUT_HOOVES))
        {
            if (verbose)
                mpr("You can't wear boots with hooves!");
            return (false);
        }

        if (player_mutation_level(MUT_TALONS))
        {
            if (verbose)
                mpr("Boots don't fit your talons!");
           return (false);
        }

        if (you.species == SP_NAGA)
        {
            if (verbose)
                mpr("You can't wear that!");
            return (false);
        }

        if (!ignore_temporary && you.swimming()
            && you.species == SP_MERFOLK)
        {
            if (verbose)
               mpr("You don't currently have feet!");

            return (false);
        }
    }

    if (you.species == SP_NAGA && sub_type == ARM_NAGA_BARDING
        && (ignore_temporary || !player_is_shapechanged()))
    {
        // It fits.
        return (true);
    }
    else if (you.species == SP_CENTAUR
             && sub_type == ARM_CENTAUR_BARDING
             && (ignore_temporary || !player_is_shapechanged()))
    {
        // It fits.
        return (true);
    }
    else if (slot == EQ_HELMET)
    {
        // Soft helmets (caps and wizard hats) always fit.
        if (!is_hard_helmet( item ))
            return (true);

        if (player_mutation_level(MUT_HORNS))
        {
            if (verbose)
                mpr("You can't wear that with your horns!");

            return (false);
        }

        if (player_mutation_level(MUT_BEAK))
        {
            if (verbose)
                mpr("You can't wear that with your beak!");

            return (false);
        }
    }

    if (!can_equip( slot, ignore_temporary ))
    {
        if (verbose)
            mpr("You can't wear that in your present form.");

        return (false);
    }

    // Giant races and draconians.
    if (you.body_size(PSIZE_TORSO, ignore_temporary) >= SIZE_LARGE
        || player_genus(GENPC_DRACONIAN))
    {
        if (sub_type >= ARM_LEATHER_ARMOUR
               && sub_type <= ARM_PLATE_MAIL
            || sub_type == ARM_GLOVES
            || sub_type == ARM_BOOTS
            || sub_type == ARM_BUCKLER
            || sub_type == ARM_CRYSTAL_PLATE_MAIL
            || is_hard_helmet(item))
        {
            if (verbose)
               mpr("This armour doesn't fit on your body.");

            return (false);
        }
    }

    // Tiny races.
    if (you.body_size(PSIZE_TORSO, ignore_temporary) <= SIZE_LITTLE)
    {
        if ((sub_type >= ARM_LEATHER_ARMOUR
                && sub_type <= ARM_PLATE_MAIL)
            || sub_type == ARM_GLOVES
            || sub_type == ARM_BOOTS
            || sub_type == ARM_SHIELD
            || sub_type == ARM_LARGE_SHIELD
            || sub_type == ARM_CRYSTAL_PLATE_MAIL
            || is_hard_helmet(item))
        {
            if (verbose)
               mpr("This armour doesn't fit on your body.");

            return (false);
        }
    }

    return (true);
}

bool do_wear_armour(int item, bool quiet)
{
    const item_def &invitem = you.inv[item];
    if (!invitem.is_valid())
    {
        if (!quiet)
           mpr("You don't have any such object.");

        return (false);
    }

    if (!can_wear_armour(invitem, !quiet, false))
        return (false);

    const equipment_type slot = get_armour_slot(invitem);

    if (item == you.equip[EQ_WEAPON])
    {
        if (!quiet)
           mpr("You are wielding that object!");

        return (false);
    }

    if (wearing_slot(item))
    {
        if (Options.equip_unequip)
            return (!takeoff_armour(item));
        else
        {
            mpr("You're already wearing that object!");
            return (false);
        }
    }

    // if you're wielding something,
    if (you.weapon()
        // attempting to wear a shield,
        && is_shield(invitem)
        && is_shield_incompatible(*you.weapon(), &invitem))
    {
        if (!quiet)
           mpr("You'd need three hands to do that!");

        return (false);
    }

    bool removed_cloak = false;
    int  cloak = -1;

    // Removing body armour requires removing the cloak first.
    if (slot == EQ_BODY_ARMOUR
        && you.equip[EQ_CLOAK] != -1 && !cloak_is_being_removed())
    {
        if (you.equip[EQ_BODY_ARMOUR] != -1
            && you.inv[you.equip[EQ_BODY_ARMOUR]].cursed())
        {
            if (!quiet)
            {
                mprf("%s is stuck to your body!",
                     you.inv[you.equip[EQ_BODY_ARMOUR]].name(DESC_CAP_YOUR)
                                                       .c_str());
            }
            return (false);
        }
        if (!you.inv[you.equip[EQ_CLOAK]].cursed())
        {
            cloak = you.equip[EQ_CLOAK];
            if (!takeoff_armour(you.equip[EQ_CLOAK]))
                return (false);

            removed_cloak = true;
        }
        else
        {
            if (!quiet)
               mpr("Your cloak prevents you from wearing the armour.");

            return (false);
        }
    }

    if ((slot == EQ_CLOAK
           || slot == EQ_HELMET
           || slot == EQ_GLOVES
           || slot == EQ_BOOTS
           || slot == EQ_SHIELD
           || slot == EQ_BODY_ARMOUR)
        && you.equip[slot] != -1)
    {
        if (!takeoff_armour(you.equip[slot]))
            return (false);
    }

    if (!safe_to_remove_or_wear(invitem, false))
        return (false);

    you.turn_is_over = true;

    const int delay = armour_equip_delay(invitem);
    if (delay)
        start_delay(DELAY_ARMOUR_ON, delay, item);

    if (removed_cloak)
        start_delay(DELAY_ARMOUR_ON, 1, cloak);

    return (true);
}

bool takeoff_armour(int item)
{
    const item_def& invitem = you.inv[item];

    if (invitem.base_type != OBJ_ARMOUR)
    {
        mpr("You aren't wearing that!");
        return (false);
    }

    if (you.berserk())
    {
        canned_msg(MSG_TOO_BERSERK);
        return (false);
    }

    const equipment_type slot = get_armour_slot(invitem);
    if (!you_tran_can_wear(invitem) && invitem.link == you.equip[slot])
    {
        mprf("%s is melded into your body!",
             invitem.name(DESC_CAP_YOUR).c_str());
        return (false);
    }

    if (!wearing_slot(item))
    {
        if (Options.equip_unequip)
            return do_wear_armour(item, true);
        else
        {
            mpr("You aren't wearing that object!");
            return (false);
        }
    }

    // If we get here, we're wearing the item.
    if (invitem.cursed())
    {
        mprf("%s is stuck to your body!", invitem.name(DESC_CAP_YOUR).c_str());
        return (false);
    }

    if (!safe_to_remove_or_wear(invitem, true))
        return (false);

    bool removed_cloak = false;
    int cloak = -1;

    if (slot == EQ_BODY_ARMOUR)
    {
        if (you.equip[EQ_CLOAK] != -1 && !cloak_is_being_removed())
        {
            if (!you.inv[you.equip[EQ_CLOAK]].cursed())
            {
                cloak = you.equip[ EQ_CLOAK ];
                if (!takeoff_armour(you.equip[EQ_CLOAK]))
                    return (false);

                removed_cloak = true;
            }
            else
            {
                mpr("Your cloak prevents you from removing the armour.");
                return (false);
            }
        }
    }
    else
    {
        switch (slot)
        {
        case EQ_SHIELD:
        case EQ_CLOAK:
        case EQ_HELMET:
        case EQ_GLOVES:
        case EQ_BOOTS:
            if (item != you.equip[slot])
            {
                mpr("You aren't wearing that!");
                return (false);
            }
            break;

        default:
            break;
        }
    }

    you.turn_is_over = true;

    const int delay = armour_equip_delay(invitem);
    start_delay(DELAY_ARMOUR_OFF, delay, item);

    if (removed_cloak)
        start_delay(DELAY_ARMOUR_ON, 1, cloak);

    return (true);
}

bool item_is_quivered(const item_def &item)
{
    return (item.link == you.m_quiver->get_fire_item());
}

int get_next_fire_item(int current, int direction)
{
    std::vector<int> fire_order;
    you.m_quiver->get_fire_order(fire_order);

    if (fire_order.size() == 0)
        return -1;
    if (current == -1)
        return fire_order[0];

    for (unsigned i = 0; i < fire_order.size(); i++)
    {
        if (fire_order[i] == current)
        {
            unsigned next =
                (i + direction + fire_order.size()) % fire_order.size();
            return fire_order[next];
        }
    }
    return fire_order[0];
}

class fire_target_behaviour : public targetting_behaviour
{
public:
    fire_target_behaviour()
        : m_slot(-1), selected_from_inventory(false), need_prompt(false),
          chosen_ammo(false)
    {
        m_slot = you.m_quiver->get_fire_item(&m_noitem_reason);
    }

    // targetting_behaviour API
    virtual command_type get_command(int key = -1);
    virtual bool should_redraw();
    virtual void mark_ammo_nonchosen();

    void message_ammo_prompt(const std::string* pre_text = 0);

public:
    int m_slot;
    std::string m_noitem_reason;
    bool selected_from_inventory;
    bool need_prompt;
    bool chosen_ammo;
};

void fire_target_behaviour::message_ammo_prompt(const std::string* pre_text)
{
    const int next_item = get_next_fire_item(m_slot, +1);
    bool no_other_items = (next_item == -1 || next_item == m_slot);

    mesclr();

    if (pre_text)
        mpr(pre_text->c_str());

    std::ostringstream msg;
    if (m_slot == -1)
        msg << "Firing ";
    else
    {
        const item_def& item_def = you.inv[m_slot];
        const launch_retval projected = is_launched(&you, you.weapon(),
                                                    item_def);

        if (projected == LRET_FUMBLED)
            msg << "Awkwardly throwing ";
        else if (projected == LRET_LAUNCHED)
            msg << "Firing ";
        else if (projected == LRET_THROWN)
            msg << "Throwing ";
        else
            msg << "Buggy ";
    }

    msg << (no_other_items ? "(i - inventory)"
                           : "(i - inventory. (,) - cycle)")
        << ": ";

    if (m_slot == -1)
    {
        msg << "<red>" << m_noitem_reason << "</red>";
    }
    else
    {
        const char* colour = (selected_from_inventory ? "lightgrey" : "w");
        msg << "<" << colour << ">"
            << you.inv[m_slot].name(DESC_INVENTORY_EQUIP)
            << "</" << colour << ">";
    }

    formatted_message_history(tagged_string_substr(msg.str(),
                                                   0, crawl_view.msgsz.x),
                              MSGCH_PROMPT);
}

bool fire_target_behaviour::should_redraw()
{
    if (need_prompt)
    {
        need_prompt = false;
        return (true);
    }
    return (false);
}

void fire_target_behaviour::mark_ammo_nonchosen()
{
    chosen_ammo = false;
}

command_type fire_target_behaviour::get_command(int key)
{
    if (key == -1)
        key = get_key();

    switch (key)
    {
    case '(':
    case CONTROL('N'):
    case ')':
    case CONTROL('P'):
    {
        const int direction = (key == CONTROL('P') || key == ')') ? -1 : +1;
        const int next = get_next_fire_item(m_slot, direction);
        if (next != m_slot && next != -1)
        {
            m_slot = next;
            selected_from_inventory = false;
            chosen_ammo = true;
        }
        // Do this stuff unconditionally to make the prompt redraw.
        message_ammo_prompt();
        need_prompt = true;
        return (CMD_NO_CMD);
    }
    case 'i':
    {
        std::string err;
        const int selected = _fire_prompt_for_item(err);
        if (selected >= 0 && _fire_validate_item(selected, err))
        {
            m_slot = selected;
            selected_from_inventory = true;
            chosen_ammo = true;
        }
        message_ammo_prompt( err.length() ? &err : NULL );
        need_prompt = true;
        return (CMD_NO_CMD);
    }
    case '?':
        show_targetting_help();
        redraw_screen();
        message_ammo_prompt();
        need_prompt = true;
        return (CMD_NO_CMD);
    }

    return targetting_behaviour::get_command(key);
}

static bool _fire_choose_item_and_target(int& slot, dist& target,
                                         bool teleport = false)
{
    fire_target_behaviour beh;
    const bool was_chosen = (slot != -1);

    if (was_chosen)
    {
        std::string warn;
        if (!_fire_validate_item(slot, warn))
        {
            mpr(warn.c_str());
            return (false);
        }
        // Force item to be the prechosen one.
        beh.m_slot = slot;
    }

    beh.message_ammo_prompt();

    direction(target, DIR_NONE, TARG_HOSTILE, -1, false, !teleport, true, false,
              NULL, &beh);

    if (beh.m_slot == -1)
    {
        canned_msg(MSG_OK);
        return (false);
    }
    if (!target.isValid)
    {
        if (target.isCancel)
            canned_msg(MSG_OK);
        return (false);
    }

    you.m_quiver->on_item_fired(you.inv[beh.m_slot], beh.chosen_ammo);
    you.redraw_quiver = true;
    slot = beh.m_slot;

    return (true);
}

// Bring up an inventory screen and have user choose an item.
// Returns an item slot, or -1 on abort/failure
// On failure, returns error text, if any.
static int _fire_prompt_for_item(std::string& err)
{
    if (inv_count() < 1)
    {
        // canned_msg(MSG_NOTHING_CARRIED);         // Hmmm...
        err = "You aren't carrying anything.";
        return -1;
    }

    int slot = prompt_invent_item( "Fire/throw which item? (* to show all)",
                                   MT_INVLIST,
                                   OSEL_THROWABLE, true, true, true, 0, -1,
                                   NULL, OPER_FIRE );

    if (slot == PROMPT_ABORT || slot == PROMPT_NOTHING)
    {
        err = "Nothing selected.";
        return -1;
    }
    return slot;
}

// Returns false and err text if this item can't be fired.
static bool _fire_validate_item(int slot, std::string &err)
{
    if (slot == you.equip[EQ_WEAPON]
        && you.inv[slot].base_type == OBJ_WEAPONS
        && you.inv[slot].cursed())
    {
        err = "That weapon is stuck to your hand!";
        return (false);
    }
    else if (wearing_slot(slot))
    {
        err = "You are wearing that object!";
        return (false);
    }
    return (true);
}

// Returns true if warning is given.
static bool _fire_warn_if_impossible()
{
    // FIXME: merge this into transform_can_equip_slot()
    const int trans = you.attribute[ATTR_TRANSFORMATION];
    // If you can't wield it, you can't throw it.
    if (trans == TRAN_SPIDER
        || trans == TRAN_BLADE_HANDS
        || trans == TRAN_ICE_BEAST
        || trans == TRAN_DRAGON
        || trans == TRAN_BAT)
    {
        canned_msg(MSG_PRESENT_FORM);
        return (true);
    }

    if (you.attribute[ATTR_HELD])
    {
        const item_def *weapon = you.weapon();
        if (!weapon || !is_range_weapon(*weapon))
        {
            mpr("You cannot throw anything while held in a net!");
            return (true);
        }
        else if (weapon->sub_type != WPN_BLOWGUN)
        {
            mprf("You cannot shoot with your %s while held in a net!",
                 weapon->name(DESC_BASENAME).c_str());
            return (true);
        }
        // Else shooting is possible.
    }
    if (you.berserk())
    {
        canned_msg(MSG_TOO_BERSERK);
        return (true);
    }
    return (false);
}

int get_ammo_to_shoot(int item, dist &target, bool teleport)
{
    if (_fire_warn_if_impossible())
    {
        flush_input_buffer( FLUSH_ON_FAILURE );
        return (-1);
    }

    if (!_fire_choose_item_and_target(item, target, teleport))
        return (-1);

    std::string warn;
    if (!_fire_validate_item(item, warn))
    {
        mpr(warn.c_str());
        return (-1);
    }
    return (item);
}

// If item == -1, prompt the user.
// If item passed, it will be put into the quiver.
void fire_thing(int item)
{
    dist target;
    item = get_ammo_to_shoot(item, target);
    if (item == -1)
        return;

    if (check_warning_inscriptions(you.inv[item], OPER_FIRE))
    {
        bolt beam;
        throw_it( beam, item, false, 0, &target );
    }
}

// Basically does what throwing used to do: throw an item without changing
// the quiver.
void throw_item_no_quiver()
{
    if (_fire_warn_if_impossible())
    {
        flush_input_buffer( FLUSH_ON_FAILURE );
        return;
    }

    if (inv_count() < 1)
    {
        canned_msg(MSG_NOTHING_CARRIED);
        return;
    }

    std::string warn;
    int slot = _fire_prompt_for_item(warn);

    if (slot == -1)
    {
        canned_msg(MSG_OK);
        return;
    }

    if (!_fire_validate_item(slot, warn))
    {
        mpr(warn.c_str());
        return;
    }

    // Okay, item is valid.
    bolt beam;
    throw_it( beam, slot );
}

// Returns delay multiplier numerator (denominator should be 100) for the
// launcher with the currently equipped shield.
int launcher_shield_slowdown(const item_def &launcher, const item_def *shield)
{
    int speed_adjust = 100;
    if (!shield)
        return (speed_adjust);

    const int shield_type = shield->sub_type;
    hands_reqd_type hands = hands_reqd(launcher, you.body_size());

    switch (hands)
    {
    default:
    case HANDS_ONE:
        break;

    case HANDS_HALF:
        speed_adjust = shield_type == ARM_BUCKLER  ? 105 :
                       shield_type == ARM_SHIELD   ? 125 :
                                                     150;
        break;

    case HANDS_TWO:
        speed_adjust = shield_type == ARM_BUCKLER  ? 125 :
                       shield_type == ARM_SHIELD   ? 150 :
                                                     200;
        break;
    }

    // Adjust for shields skill.
    if (speed_adjust > 100)
        speed_adjust -= ((speed_adjust - 100) * 5 / 10)
                            * you.skills[SK_SHIELDS] / 27;

    return (speed_adjust);
}

// Returns the attack cost of using the launcher, taking skill and shields
// into consideration. NOTE: You must pass in the shield; if you send in
// NULL, this function assumes no shield is in use.
int launcher_final_speed(const item_def &launcher, const item_def *shield)
{
    const int  str_weight   = weapon_str_weight( launcher );
    const int  dex_weight   = 10 - str_weight;
    const skill_type launcher_skill = range_skill( launcher );
    const int shoot_skill = you.skills[launcher_skill];
    const int bow_brand = get_weapon_brand( launcher );

    int speed_base = 10 * property( launcher, PWPN_SPEED );
    int speed_min = 70;
    int speed_stat = str_weight * you.strength + dex_weight * you.dex;

    // Reduce runaway bow overpoweredness.
    if (launcher_skill == SK_BOWS)
        speed_min = 60;

    if (shield)
    {
        const int speed_adjust = launcher_shield_slowdown(launcher, shield);

        // Shields also reduce the speed cap.
        speed_base = speed_base * speed_adjust / 100;
        speed_min =  speed_min  * speed_adjust / 100;
    }

    // Do the same when trying to shoot while held in a net
    // (only possible with blowguns).
    if (you.attribute[ATTR_HELD])
    {
        int speed_adjust = 105; // Analogous to buckler and one-handed weapon.
        speed_adjust -= ((speed_adjust - 100) * 5 / 10)
                            * you.skills[SK_THROWING] / 27;

        // Also reduce the speed cap.
        speed_base = speed_base * speed_adjust / 100;
        speed_min =  speed_min  * speed_adjust / 100;
    }

    int speed = speed_base - 4 * shoot_skill * speed_stat / 250;
    if (speed < speed_min)
        speed = speed_min;

    if (bow_brand == SPWPN_SPEED)
    {
        // Speed nerf as per 4.1. Even with the nerf, bows of speed are the
        // best bows, bar none.
        speed = 2 * speed / 3;
    }

    return (speed);
}

// Determines if the end result of the combined launcher + ammo brands a
// fire/frost beam.
// positive: frost, negative: flame, zero: neither
bool elemental_missile_beam(int launcher_brand, int ammo_brand)
{
    if (launcher_brand == SPWPN_CHAOS || ammo_brand == SPMSL_CHAOS)
        return (true);

    int element = (launcher_brand == SPWPN_FROST
                   + ammo_brand == SPMSL_FROST
                   - launcher_brand == SPWPN_FLAME
                   - ammo_brand == SPMSL_FLAME);

    return (element != 0);
}

static bool _poison_hit_victim(bolt& beam, actor* victim, int dmg, int corpse)
{
    if (!victim->alive() || victim->res_poison() > 0)
        return (false);

    if (beam.is_tracer)
        return (true);

    int levels = 0;

    actor* agent = beam.agent();

    if (dmg > 0 || beam.ench_power == AUTOMATIC_HIT
                   && x_chance_in_y(90 - 3 * victim->armour_class(), 100))
    {
        levels = 1 + random2(3);
    }

    if (levels <= 0)
        return (false);

    victim->poison(agent, levels);

    return (true);
}

static bool _item_penetrates_victim(const bolt &beam, const actor *victim,
                                    int &used)
{
    if (beam.aimed_at_feet)
        return (false);

    used = 0;

    return (true);
}

static bool _silver_damages_victim(bolt &beam, actor* victim, int &dmg,
                                   std::string &dmg_msg)
{
    if (victim->undead_or_demonic() || victim->is_chaotic())
    {
        dmg *= 2;

        if (!beam.is_tracer && you.can_see(victim))
           dmg_msg = "The silver sears " + victim->name(DESC_NOCAP_THE) + "!";
    }

    return (false);
}

static bool _reaping_hit_victim(bolt& beam, actor* victim, int dmg, int corpse)
{
    if (beam.is_tracer || victim->alive() || corpse == -1
        || corpse == NON_ITEM || victim->atype() == ACT_PLAYER)
    {
        return (false);
    }

    return (mons_reaped(beam.agent(), dynamic_cast<monsters*>(victim)));
}

static bool _dispersal_hit_victim(bolt& beam, actor* victim, int dmg,
                                  int corpse)
{
    const actor* agent = beam.agent();

    if (!victim->alive() || victim == agent)
        return (false);

    if (beam.is_tracer)
        return (true);

    const bool was_seen = you.can_see(victim);
    const bool no_sanct = victim->kill_alignment() == KC_OTHER;

    coord_def pos, pos2;

    int tries = 0;
    do
    {
        if (!random_near_space(victim->pos(), pos, false, true, false,
                               no_sanct))
        {
            return (false);
        }
    }
    while (!victim->is_habitable(pos) && tries++ < 100);

    if (!victim->is_habitable(pos))
        return (false);

    tries = 0;
    do
        random_near_space(victim->pos(), pos2, false, true, false, no_sanct);
    while (!victim->is_habitable(pos2) && tries++ < 100);

    if (!victim->is_habitable(pos2))
        return (false);

    // Pick the square further away from the agent.
    const coord_def from = agent->pos();
    if (in_bounds(pos2)
        && grid_distance(pos2, from) > grid_distance(pos, from))
    {
        pos = pos2;
    }

    if (pos == victim->pos())
        return (false);

    const coord_def oldpos = victim->pos();

    if (victim->atype() == ACT_PLAYER)
    {
        // Leave a purple cloud.
        place_cloud(CLOUD_TLOC_ENERGY, you.pos(), 1 + random2(3), KC_YOU);

        victim->moveto(pos);
        mpr("You blink!");
    }
    else
    {
        monsters *mon = dynamic_cast<monsters*>(victim);

        if (!(mon->flags & MF_WAS_IN_VIEW))
            mon->seen_context = "thin air";

        mon->move_to_pos(pos);

        // Leave a purple cloud.
        place_cloud(CLOUD_TLOC_ENERGY, oldpos, 1 + random2(3),
                    victim->kill_alignment());

        mon->apply_location_effects(oldpos);
        mon->check_redraw(oldpos);

        const bool        seen = you.can_see(mon);
        const std::string name = mon->name(DESC_CAP_THE);
        if (was_seen && seen)
            mprf("%s blinks!", name.c_str());
        else if (was_seen && !seen)
            mprf("%s vanishes!", name.c_str());
    }

    return (true);
}

static bool _electricity_water_explosion(const bolt &beam, const actor *victim,
                                         int &used)
{
    used = 1000;

    ASSERT(!beam.is_tracer);
    if (you.can_see(victim))
        mpr("Electricity arcs through the water!");
    conduct_electricity(victim->pos(), beam.agent());

    return (true);
}

static bool _charged_hit_victim(bolt &beam, actor* victim, int &dmg,
                                   std::string &dmg_msg)
{
    if (victim->airborne() || victim->res_elec() > 0 || !one_chance_in(3))
        return (false);

    // A hack and code duplication, but that's easier than adding accounting
    // for each of multiple brands.
    if (victim->id() == MONS_SIXFIRHY)
    {
        if (!beam.is_tracer)
            victim->heal(10 + random2(15), false);
        // physical damage is still done
    }
    else
        dmg += 10 + random2(15);

    if (beam.is_tracer)
        return (false);

    if (you.can_see(victim))
        if (victim->atype() == ACT_PLAYER)
            dmg_msg = "You are electrocuted!";
        else if (victim->id() == MONS_SIXFIRHY)
            dmg_msg = victim->name(DESC_CAP_THE) + " is charged up!";
        else
            dmg_msg = "There is a sudden explosion of sparks!";

    if (feat_is_water(grd(victim->pos())))
    {
        beam.range_funcs.insert(beam.range_funcs.begin(),
            _electricity_water_explosion);
    }

    return (false);
}

static bool _blessed_hit_victim(bolt &beam, actor* victim, int &dmg,
                                   std::string &dmg_msg)
{
    if (victim->undead_or_demonic())
    {
        dmg += 1 + (random2(dmg * 15) / 10);

        if (!beam.is_tracer && you.can_see(victim))
           dmg_msg = victim->name(DESC_CAP_THE) + " "
                   + victim->conj_verb("convulse") + "!";
    }

    return (false);
}

int _blowgun_power_roll (bolt &beam)
{
    actor* agent = beam.agent();
    int base_power = 0;
    int blowgun_base = 0;

    if (agent->atype() == ACT_MONSTER)
    {
        monsters* mons = static_cast<monsters*>(agent);
        base_power += mons->hit_dice;
        blowgun_base += (*mons).launcher()->plus;
    }
    else
    {
        base_power += you.skills[SK_THROWING];
        blowgun_base += (you.weapon())->plus;
    }

    return (base_power + blowgun_base);
}

bool _blowgun_check (bolt &beam, actor* victim, bool message = true)
{
    actor* agent = beam.agent();

    if (agent->atype() == ACT_MONSTER)
        return (true);

    monsters* mons = static_cast<monsters*>(victim);

    int skill = you.skills[SK_THROWING];
    int enchantment = (you.weapon())->plus;

    // You have a really minor chance of hitting with no skills or good
    // enchants.
    if (mons->hit_dice < 15 && random2(100) <= 2)
        return (true);

    int resist_roll = 2 + random2(4 + skill + enchantment);

    dprf("Brand rolled %d against monster HD: %d.", resist_roll, mons->hit_dice);

    if (resist_roll < mons->hit_dice)
    {
        simple_monster_message(mons, " resists!");
        return (false);
    }

    return (true);
}

static bool _paralysis_hit_victim (bolt& beam, actor* victim, int dmg,
                                  int corpse)
{
    if (beam.is_tracer)
        return (false);

    if (!_blowgun_check(beam, victim))
        return (false);

    int blowgun_power = _blowgun_power_roll(beam);
    victim->paralyse(beam.agent(), 5 + random2(blowgun_power));
    return (true);
}

static bool _sleep_hit_victim (bolt& beam, actor* victim, int dmg,
                                  int corpse)
{
    if (beam.is_tracer)
        return (false);

    if (!_blowgun_check(beam, victim))
        return (false);

    int blowgun_power = _blowgun_power_roll(beam);
    victim->put_to_sleep(beam.agent(), 5 + random2(blowgun_power));
    return (true);
}

static bool _confusion_hit_victim (bolt &beam, actor* victim, int dmg,
                                   int corpse)
{
    if (beam.is_tracer)
        return (false);

    if (!_blowgun_check(beam, victim))
        return (false);

    int blowgun_power = _blowgun_power_roll(beam);
    victim->confuse(beam.agent(), 5 + random2(blowgun_power));
    return (true);
}

static bool _slow_hit_victim (bolt &beam, actor* victim, int dmg,
                                   int corpse)
{
    if (beam.is_tracer)
        return (false);

    if (!_blowgun_check(beam, victim))
        return (false);

    int blowgun_power = _blowgun_power_roll(beam);
    victim->slow_down(beam.agent(), 5 + random2(blowgun_power));
    return (true);
}

static bool _sickness_hit_victim (bolt &beam, actor* victim, int dmg,
                                   int corpse)
{
    if (beam.is_tracer)
        return (false);

    if (!_blowgun_check(beam, victim))
        return (false);

    int blowgun_power = _blowgun_power_roll(beam);
    victim->sicken(40 + random2(blowgun_power));
    return (true);
}

static bool _rage_hit_victim (bolt &beam, actor* victim, int dmg,
                                   int corpse)
{
    if (beam.is_tracer)
        return (false);

    if (!_blowgun_check(beam, victim))
        return (false);

    if (victim->atype() == ACT_MONSTER)
    {
        monsters* mons = static_cast<monsters*>(victim);
        mons->go_frenzy();
    }
    else
        victim->go_berserk(false);

    return (true);
}

bool setup_missile_beam(const actor *agent, bolt &beam, item_def &item,
                        std::string &ammo_name, bool &returning)
{
    dungeon_char_type zapsym = DCHAR_SPACE;
    switch (item.base_type)
    {
    case OBJ_WEAPONS:    zapsym = DCHAR_FIRED_WEAPON;  break;
    case OBJ_MISSILES:   zapsym = DCHAR_FIRED_MISSILE; break;
    case OBJ_ARMOUR:     zapsym = DCHAR_FIRED_ARMOUR;  break;
    case OBJ_WANDS:      zapsym = DCHAR_FIRED_STICK;   break;
    case OBJ_FOOD:       zapsym = DCHAR_FIRED_CHUNK;   break;
    case OBJ_UNKNOWN_I:  zapsym = DCHAR_FIRED_BURST;   break;
    case OBJ_SCROLLS:    zapsym = DCHAR_FIRED_SCROLL;  break;
    case OBJ_JEWELLERY:  zapsym = DCHAR_FIRED_TRINKET; break;
    case OBJ_POTIONS:    zapsym = DCHAR_FIRED_FLASK;   break;
    case OBJ_UNKNOWN_II: zapsym = DCHAR_FIRED_ZAP;     break;
    case OBJ_BOOKS:      zapsym = DCHAR_FIRED_BOOK;    break;
    case OBJ_STAVES:     zapsym = DCHAR_FIRED_STICK;   break;
    default: break;
    }

    beam.type = dchar_glyph(zapsym);
    beam.was_missile = true;

    returning = get_weapon_brand(item) == SPWPN_RETURNING
                || get_ammo_brand(item) == SPMSL_RETURNING;

    if (agent->atype() == ACT_PLAYER)
    {
        beam.attitude      = ATT_FRIENDLY;
        beam.beam_source   = NON_MONSTER;
        beam.smart_monster = true;
        beam.thrower       = KILL_YOU_MISSILE;
    }
    else
    {
        const monsters *mon = dynamic_cast<const monsters*>(agent);

        beam.attitude      = mons_attitude(mon);
        beam.beam_source   = mon->mindex();
        beam.smart_monster = (mons_intel(mon) >= I_NORMAL);
        beam.thrower       = KILL_MON_MISSILE;
    }

    beam.item     = &item;
    beam.source   = agent->pos();
    beam.colour   = item.colour;
    beam.flavour  = BEAM_MISSILE;
    beam.is_beam  = false;
    beam.aux_source.clear();

    beam.can_see_invis = agent->can_see_invisible();

    item_def *launcher  = const_cast<actor*>(agent)->weapon(0);
    if (launcher && !item.launched_by(*launcher))
        launcher = NULL;

    const unrandart_entry* entry = launcher && is_unrandom_artefact(*launcher)
        ? get_unrand_entry(launcher->special) : NULL;

    if (entry && entry->fight_func.launch)
    {
        setup_missile_type sm =
            entry->fight_func.launch(launcher, &beam, &ammo_name,
                                     &returning);

        switch(sm)
        {
        case SM_CONTINUE:
            break;
        case SM_FINISHED:
            return (false);
        case SM_CANCEL:
            return (true);
        }
    }

    int bow_brand = SPWPN_NORMAL;
    if (launcher != NULL)
        bow_brand = get_weapon_brand(*launcher);

    int  ammo_brand = get_ammo_brand(item);

    // Launcher brand does not affect ammunition.
    if (ammo_brand != SPMSL_NORMAL && bow_brand != SPWPN_NORMAL)
    {
        // But not for Nessos.
        if (agent->atype() == ACT_MONSTER)
        {
            const monsters* mon = static_cast<const monsters*>(agent);
            if (mon->type != MONS_NESSOS)
                bow_brand = SPWPN_NORMAL;
        }
        else
            bow_brand = SPWPN_NORMAL;
    }

    bool poisoned   = (bow_brand == SPWPN_VENOM 
                        || ammo_brand == SPMSL_POISONED);

    const bool exploding    = (ammo_brand == SPMSL_EXPLODING);
    const bool penetrating  = (bow_brand  == SPWPN_PENETRATION
                                || ammo_brand == SPMSL_PENETRATION);
    const bool silver       = (ammo_brand == SPMSL_SILVER);
    const bool disperses    = (ammo_brand == SPMSL_DISPERSAL);
    const bool reaping      = (bow_brand  == SPWPN_REAPING
                               || ammo_brand == SPMSL_REAPING);
    const bool charged      = bow_brand  == SPWPN_ELECTROCUTION;
    const bool blessed      = bow_brand == SPWPN_HOLY_WRATH;

    const bool paralysis    = ammo_brand == SPMSL_PARALYSIS;
    const bool slow         = ammo_brand == SPMSL_SLOW;
    const bool sleep        = ammo_brand == SPMSL_SLEEP;
    const bool confusion    = ammo_brand == SPMSL_CONFUSION;
    const bool sickness     = ammo_brand == SPMSL_SICKNESS;
    const bool rage         = ammo_brand == SPMSL_RAGE;

    ASSERT(!exploding || !is_artefact(item));

    beam.name = item.name(DESC_PLAIN, false, false, false);

    // Print type of item as influenced by launcher.
    item_def ammo = item;

    // The chief advantage here is the extra damage this does
    // against susceptible creatures.

    // Note: weapons & ammo of eg fire are not cumulative
    // ammo of fire and weapons of frost don't work together,
    // and vice versa.

    // Note that bow_brand is known since the bow is equipped.

    // Chaos overides flame and frost/ice.
    if (bow_brand == SPWPN_CHAOS || ammo_brand == SPMSL_CHAOS)
    {
        // Chaos can't be poisoned, since that might conflict with
        // the random healing effect or overlap with the random
        // poisoning effect.
        poisoned = false;
        if (item.special == SPWPN_VENOM || item.special == SPMSL_CURARE)
            item.special = SPMSL_NORMAL;

        beam.effect_known = false;

        beam.flavour = BEAM_CHAOS;
        beam.name    += " of chaos";
        beam.colour  = ETC_RANDOM;

        ammo.special = SPMSL_CHAOS;
    }
    else if ((bow_brand == SPWPN_FLAME || ammo_brand == SPMSL_FLAME)
             && ammo_brand != SPMSL_FROST && bow_brand != SPWPN_FROST)
    {
        beam.flavour = BEAM_FIRE;
        beam.name    += " of flame";
        beam.colour  = RED;

        ammo.special = SPMSL_FLAME;
    }
    else if ((bow_brand == SPWPN_FROST || ammo_brand == SPMSL_FROST)
             && ammo_brand != SPMSL_FLAME && bow_brand != SPWPN_FLAME)
    {
        beam.flavour = BEAM_COLD;
        beam.name    += " of frost";
        beam.colour  = WHITE;

        ammo.special = SPMSL_FROST;
    }

    ASSERT(beam.flavour == BEAM_MISSILE || !is_artefact(item));

    ammo_name = ammo.name(DESC_PLAIN);

    if (silver)
        beam.damage_funcs.push_back(_silver_damages_victim);
    if (poisoned)
        beam.hit_funcs.push_back(_poison_hit_victim);
    if (penetrating)
    {
        beam.range_funcs.push_back(_item_penetrates_victim);
        beam.hit_verb = "pierces through";
    }
    if (reaping)
        beam.hit_funcs.push_back(_reaping_hit_victim);
    if (disperses)
        beam.hit_funcs.push_back(_dispersal_hit_victim);
    if (charged)
        beam.damage_funcs.push_back(_charged_hit_victim);
    if (blessed)
        beam.damage_funcs.push_back(_blessed_hit_victim);

    // New needle brands have no affect when thrown without launcher.
    if (launcher != NULL)
    {
        if (paralysis)
            beam.hit_funcs.push_back(_paralysis_hit_victim);
        if (slow)
            beam.hit_funcs.push_back(_slow_hit_victim);
        if (sleep)
            beam.hit_funcs.push_back(_sleep_hit_victim);
        if (confusion)
            beam.hit_funcs.push_back(_confusion_hit_victim);
        if (sickness)
            beam.hit_funcs.push_back(_sickness_hit_victim);
        if (rage)
            beam.hit_funcs.push_back(_rage_hit_victim);
    }

    if (reaping && ammo.special != SPMSL_REAPING)
    {
        beam.name = "shadowy " + beam.name;
        ammo_name = "shadowy " + ammo_name;
    }

    if (disperses && ammo.special != SPMSL_DISPERSAL)
    {
        beam.name = "dispersing " + beam.name;
        ammo_name = "dispersing " + ammo_name;
    }

    // XXX: This doesn't make sense, but it works.
    if (poisoned && ammo.special != SPMSL_POISONED)
    {
        ammo_name = "poisoned " + ammo_name;
    }

    if (penetrating && ammo.special != SPMSL_PENETRATION)
    {
        beam.name = "penetrating " + beam.name;
        ammo_name = "penetrating " + ammo_name;
    }

    if (silver && ammo.special != SPMSL_SILVER)
    {
        beam.name = "silvery " + beam.name;
        ammo_name = "silvery " + ammo_name;
    }

    if (blessed)
    {
        beam.name = "blessed " + beam.name;
        ammo_name = "blessed " + ammo_name;
    }

    // Do this here so that we get all the name mods except for a
    // redundant "exploding".
    if (exploding)
    {
         bolt *expl = new bolt(beam);

         expl->is_explosion = true;
         expl->damage       = dice_def(2, 5);
         expl->ex_size      = 1;

         if (beam.flavour == BEAM_MISSILE)
         {
             expl->flavour = BEAM_FRAG;
             expl->name   += " fragments";

             const std::string short_name =
                 ammo.name(DESC_PLAIN, false, false, false, false,
                           ISFLAG_IDENT_MASK | ISFLAG_COSMETIC_MASK
                           | ISFLAG_RACIAL_MASK);

             expl->name = replace_all(expl->name, ammo.name(DESC_PLAIN),
                                      short_name);
         }
         expl->name = "explosion of " + expl->name;

         beam.special_explosion = expl;
    }

    if (exploding && ammo.special != SPMSL_EXPLODING)
    {
        beam.name = "exploding " + beam.name;
        ammo_name = "exploding " + ammo_name;
    }

    if (beam.flavour != BEAM_MISSILE)
    {
        returning = false;

        beam.type = dchar_glyph(DCHAR_FIRED_BOLT);
    }

    if (!is_artefact(item))
        ammo_name = article_a(ammo_name, true);
    else
        ammo_name = "the " + ammo_name;

    return (false);
}

// XXX This is a bit too generous, as it lets the player determine
// that the bolt of fire he just shot from a flaming bow is actually
// a poison arrow. Hopefully this isn't too abusable.
static bool determines_ammo_brand(int bow_brand, int ammo_brand)
{
    if (bow_brand == SPWPN_FLAME && ammo_brand == SPMSL_FLAME)
        return (false);
    if (bow_brand == SPWPN_FROST && ammo_brand == SPMSL_FROST)
        return (false);
    if (bow_brand == SPWPN_VENOM && ammo_brand == SPMSL_POISONED)
        return (false);
    if (bow_brand == SPWPN_CHAOS && ammo_brand == SPMSL_CHAOS)
        return (false);
    if (bow_brand == SPWPN_PENETRATION && ammo_brand == SPMSL_PENETRATION)
        return (false);
    if (bow_brand == SPWPN_REAPING && ammo_brand == SPMSL_REAPING)
        return (false);

    return (true);
}

static int stat_adjust(int value, int stat, int statbase,
                       const int maxmult = 160, const int minmult = 40)
{
    int multiplier = (statbase + (stat - statbase) / 2) * 100 / statbase;
    if (multiplier > maxmult)
        multiplier = maxmult;
    else if (multiplier < minmult)
        multiplier = minmult;

    if (multiplier > 100)
        value = value * (100 + random2avg(multiplier - 100, 2)) / 100;
    else if (multiplier < 100)
        value = value * (100 - random2avg(100 - multiplier, 2)) / 100;

    return (value);
}

static int str_adjust_thrown_damage(int dam)
{
    return stat_adjust(dam, you.strength, 15, 160, 90);
}

static int dex_adjust_thrown_tohit(int hit)
{
    return stat_adjust(hit, you.dex, 13, 160, 90);
}

static void identify_floor_missiles_matching(item_def mitem, int idflags)
{
    mitem.flags &= ~idflags;

    for (int y = 0; y < GYM; ++y)
        for (int x = 0; x < GXM; ++x)
            for (stack_iterator si(coord_def(x,y)); si; ++si)
            {
                if ((si->flags & ISFLAG_THROWN) && items_stack(*si, mitem))
                    si->flags |= idflags;
            }
}

void _merge_ammo_in_inventory(int slot)
{
    if (!you.inv[slot].is_valid())
        return;

    bool done_anything = false;

    for (int i = 0; i < ENDOFPACK; ++i)
    {
        if (i == slot || !you.inv[i].is_valid())
            continue;

        // Merge with the thrower slot. This could be a bad
        // thing if you're wielding IDed ammo and firing from
        // an unIDed stack...but that's a pretty remote case.
        if (items_stack(you.inv[i], you.inv[slot]))
        {
            if (!done_anything)
                mpr("You combine your ammunition.");

            inc_inv_item_quantity(slot, you.inv[i].quantity, true);
            dec_inv_item_quantity(i, you.inv[i].quantity);
            done_anything = true;
        }
    }
}

void throw_noise(actor* act, const bolt &pbolt, const item_def &ammo)
{
    const item_def* launcher = act->weapon();

    if (launcher == NULL || launcher->base_type != OBJ_WEAPONS)
        return;

    if (is_launched(act, launcher, ammo) != LRET_LAUNCHED)
        return;

    // Throwing and blowguns are silent...
    int         level = 0;
    const char* msg   = NULL;

    switch(launcher->sub_type)
    {
    case WPN_BLOWGUN:
        return;

    case WPN_SLING:
        level = 1;
        msg   = "You hear a whirring sound.";
        break;
     case WPN_BOW:
        level = 5;
        msg   = "You hear a twanging sound.";
        break;
     case WPN_LONGBOW:
        level = 6;
        msg   = "You hear a loud twanging sound.";
        break;
     case WPN_CROSSBOW:
        level = 7;
        msg   = "You hear a thunk.";
        break;

    default:
        DEBUGSTR("Invalid launcher '%s'",
                 launcher->name(DESC_PLAIN).c_str());
        return;
    }
    if (act->atype() == ACT_PLAYER || you.can_see(act))
        msg = NULL;

    noisy(level, act->pos(), msg, act->mindex());
}

// throw_it - currently handles player throwing only.  Monster
// throwing is handled in mon-act:_mons_throw()
// Note: If teleport is true, assume that pbolt is already set up,
// and teleport the projectile onto the square.
//
// Return value is only relevant if dummy_target is non-NULL, and returns
// true if dummy_target is hit.
bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus,
              dist *target)
{
    dist thr;
    int shoot_skill = 0;
    bool ammo_ided = false;

    // launcher weapon sub-type
    weapon_type lnchType;

    int baseHit      = 0, baseDam = 0;       // from thrown or ammo
    int ammoHitBonus = 0, ammoDamBonus = 0;  // from thrown or ammo
    int lnchHitBonus = 0, lnchDamBonus = 0;  // special add from launcher
    int exHitBonus   = 0, exDamBonus = 0;    // 'extra' bonus from skill/dex/str
    int effSkill     = 0;        // effective launcher skill
    int dice_mult    = 100;
    bool returning   = false;    // Item can return to pack.
    bool did_return  = false;    // Returning item actually does return to pack.
    int slayDam      = 0;

    if (you.confused())
        thr.target = you.pos() + coord_def(random2(13)-6, random2(13)-6);
    else if (target)
        thr = *target;
    else
    {
        direction(thr, DIR_NONE, TARG_HOSTILE);

        if (!thr.isValid)
        {
            if (thr.isCancel)
                canned_msg(MSG_OK);

            return (false);
        }
    }
    pbolt.set_target(thr);

    item_def& thrown = you.inv[throw_2];
    ASSERT(thrown.is_valid());

    // Figure out if we're thrown or launched.
    const launch_retval projected = is_launched(&you, you.weapon(), thrown);

    // Making a copy of the item: changed only for venom launchers.
    item_def item = thrown;
    item.quantity = 1;
    item.slot     = index_to_letter(item.link);

    // Items that get a temporary brand from a player spell lose the
    // brand as soon as the player lets go of the item.  Can't call
    // unwield_item() yet since the beam might get canceled.
    if (you.duration[DUR_WEAPON_BRAND] && projected != LRET_LAUNCHED
        && throw_2 == you.equip[EQ_WEAPON])
    {
        set_item_ego_type(item, OBJ_WEAPONS, SPWPN_NORMAL);
    }

    std::string ammo_name;

    if (setup_missile_beam(&you, pbolt, item, ammo_name, returning))
    {
        you.turn_is_over = false;
        return (false);
    }

    // Did we know the ammo's brand before throwing it?
    const bool ammo_brand_known = item_type_known(thrown);

    // Get the ammo/weapon type.  Convenience.
    const object_class_type wepClass = thrown.base_type;
    const int               wepType  = thrown.sub_type;

    // Determine range.
    int max_range = 0;
    int range = 0;

    if (projected)
    {
        if (wepType == MI_LARGE_ROCK)
        {
            range     = 1 + random2( you.strength / 5 );
            max_range = you.strength / 5;
            if (you.can_throw_large_rocks())
            {
                range     += random_range(4, 7);
                max_range += 7;
            }
        }
        else if (wepType == MI_THROWING_NET)
        {
            max_range = range = 2 + you.body_size(PSIZE_BODY);
        }
        else
        {
            max_range = range = LOS_RADIUS;
        }
    }
    else
    {
        // Range based on mass & strength, between 1 and 9.
        max_range = range = std::max(you.strength-item_mass(thrown)/10 + 3, 1);
    }

    range = std::min(range, LOS_RADIUS);
    max_range = std::min(max_range, LOS_RADIUS);

    // For the tracer, use max_range. For the actual shot, use range.
    pbolt.range = max_range;

    // Don't do the tracing when using Portaled Projectile, or when confused.
    if (!teleport && !you.confused())
    {
        // Set values absurdly high to make sure the tracer will
        // complain if we're attempting to fire through allies.
        pbolt.hit    = 100;
        pbolt.damage = dice_def(1, 100);

        // Init tracer variables.
        pbolt.foe_info.reset();
        pbolt.friend_info.reset();
        pbolt.foe_ratio = 100;
        pbolt.is_tracer = true;

        pbolt.fire();

        // Should only happen if the player answered 'n' to one of those
        // "Fire through friendly?" prompts.
        if (pbolt.beam_cancelled)
        {
            canned_msg(MSG_OK);
            you.turn_is_over = false;
            if (pbolt.special_explosion != NULL)
                delete pbolt.special_explosion;
            return (false);
        }
        pbolt.hit    = 0;
        pbolt.damage = dice_def();
    }
    pbolt.is_tracer = false;

    // Use real range for firing.
    pbolt.range = range;

    bool unwielded = false;
    if (throw_2 == you.equip[EQ_WEAPON] && thrown.quantity == 1)
    {
        if (!wield_weapon(true, PROMPT_GOT_SPECIAL, true, false, false))
            return (false);

        unwielded = true;
    }

    // Now start real firing!
    origin_set_unknown(item);

    if (is_blood_potion(item) && thrown.quantity > 1)
    {
        // Initialise thrown potion with oldest potion in stack.
        long val = remove_oldest_blood_potion(thrown);
        val -= you.num_turns;
        item.props.clear();
        init_stack_blood_potions(item, val);
    }

    // Even though direction is allowed, we're throwing so we
    // want to use tx, ty to make the missile fly to map edge.
    if (!teleport)
        pbolt.set_target(thr);

    // Get the launcher class, type.  Convenience.
    if (!you.weapon())
        lnchType = NUM_WEAPONS;
    else
        lnchType = static_cast<weapon_type>(you.weapon()->sub_type);

    // baseHit and damage for generic objects
    baseHit = std::min(0, you.strength - item_mass(item) / 10);
    baseDam = item_mass(item) / 100;

    // special: might be throwing generic weapon;
    // use base wep. damage, w/ penalty
    if (wepClass == OBJ_WEAPONS)
        baseDam = std::max(0, property(item, PWPN_DAMAGE) - 4);

    // Extract weapon/ammo bonuses due to magic.
    ammoHitBonus = item.plus;
    ammoDamBonus = item.plus2;

    int bow_brand = SPWPN_NORMAL;

    if (projected == LRET_LAUNCHED)
        bow_brand = get_weapon_brand(*you.weapon());

    const int ammo_brand = get_ammo_brand( item );

    // CALCULATIONS FOR LAUNCHED WEAPONS
    if (projected == LRET_LAUNCHED)
    {
        const item_def &launcher = *you.weapon();

        // Extract launcher bonuses due to magic.
        lnchHitBonus = launcher.plus;
        lnchDamBonus = launcher.plus2;

        const int item_base_dam = property( item, PWPN_DAMAGE );
        const int lnch_base_dam = property( launcher, PWPN_DAMAGE );

        const skill_type launcher_skill = range_skill( launcher );

        baseHit = property( launcher, PWPN_HIT );
        baseDam = lnch_base_dam + random2(1 + item_base_dam);

        // Slings are terribly weakened otherwise.
        if (lnch_base_dam == 0)
            baseDam = item_base_dam;

        // If we've a zero base damage + an elemental brand, up the damage
        // slightly so the brand has something to work with. This should
        // only apply to needles.
        if (!baseDam && elemental_missile_beam(bow_brand, ammo_brand))
            baseDam = 4;

        // [dshaligram] This is a horrible hack - we force beam.cc to consider
        // this beam "needle-like". (XXX)
        if (wepClass == OBJ_MISSILES && wepType == MI_NEEDLE)
            pbolt.ench_power = AUTOMATIC_HIT;

        dprf(   "Base hit == %d; Base damage == %d "
                "(item %d + launcher %d)",
                        baseHit, baseDam,
                        item_base_dam, lnch_base_dam);

        // Fix ammo damage bonus, since missiles only use inv_plus.
        ammoDamBonus = ammoHitBonus;

        // Check for matches; dwarven, elven, orcish.
        if (!(get_equip_race(*you.weapon()) == 0))
        {
            if (get_equip_race(*you.weapon()) == get_equip_race(item))
            {
                baseHit++;
                baseDam++;

                // elves with elven bows
                if (get_equip_race(*you.weapon()) == ISFLAG_ELVEN
                    && player_genus(GENPC_ELVEN))
                {
                    baseHit++;
                }
            }
        }

        // Lower accuracy if held in a net.
        if (you.attribute[ATTR_HELD])
            baseHit--;

        // For all launched weapons, maximum effective specific skill
        // is twice throwing skill.  This models the fact that no matter
        // how 'good' you are with a bow, if you know nothing about
        // trajectories you're going to be a damn poor bowman.  Ditto
        // for crossbows and slings.

        // [dshaligram] Throwing now two parts launcher skill, one part
        // ranged combat. Removed the old model which is... silly.

        // [jpeg] Throwing now only affects actual throwing weapons,
        // i.e. not launched ones. (Sep 10, 2007)

        shoot_skill = you.skills[launcher_skill];
        effSkill    = shoot_skill;

        const int speed = launcher_final_speed(launcher, you.shield());
        dprf("Final launcher speed: %d", speed);
        you.time_taken = speed * you.time_taken / 100;

        // [dshaligram] Improving missile weapons:
        //  - Remove the strength/enchantment cap where you need to be strong
        //    to exploit a launcher bonus.
        //  - Add on launcher and missile pluses to extra damage.

        // [dshaligram] This can get large...
        exDamBonus = lnchDamBonus + random2(1 + ammoDamBonus);
        exDamBonus = (exDamBonus > 0   ? random2(exDamBonus + 1)
                                       : -random2(-exDamBonus + 1));
        exHitBonus = (lnchHitBonus > 0 ? random2(lnchHitBonus + 1)
                                       : -random2(-lnchHitBonus + 1));

        // Identify ammo type if the information is there. Note
        // that the bow is always type-identified because it's
        // wielded.
        if (determines_ammo_brand(bow_brand, ammo_brand))
        {
            set_ident_flags(item, ISFLAG_KNOW_TYPE);
            if (ammo_brand != SPMSL_NORMAL)
            {
                set_ident_flags(you.inv[throw_2], ISFLAG_KNOW_TYPE);
                ammo_ided = true;
            }
        }

        // Removed 2 random2(2)s from each of the learning curves, but
        // left slings because they're hard enough to develop without
        // a good source of shot in the dungeon.
        switch (launcher_skill)
        {
        case SK_SLINGS:
        {
            // Slings are really easy to learn because they're not
            // really all that good, and it's harder to get ammo anyway.
            exercise(SK_SLINGS, 1 + random2avg(3, 2));

            // Sling bullets are designed for slinging and easier to aim.
            if (wepType == MI_SLING_BULLET)
                baseHit += 4;

            exHitBonus += (effSkill * 3) / 2;

            // Strength is good if you're using a nice sling.
            int strbonus = (10 * (you.strength - 10)) / 9;
            strbonus = (strbonus * (2 * baseDam + ammoDamBonus)) / 20;

            // cap
            strbonus = std::min(lnchDamBonus + 1, strbonus);

            exDamBonus += strbonus;
            // Add skill for slings... helps to find those vulnerable spots.
            dice_mult = dice_mult * (14 + random2(1 + effSkill)) / 14;

            // Now kill the launcher damage bonus.
            lnchDamBonus = std::min(0, lnchDamBonus);
            break;
        }

        // Blowguns take a _very_ steady hand; a lot of the bonus
        // comes from dexterity.  (Dex bonus here as well as below.)
        case SK_THROWING:
            baseHit -= 2;
            exercise(SK_THROWING, (coinflip()? 2 : 1));
            exHitBonus += (effSkill * 3) / 2 + you.dex / 2;

            // No extra damage for blowguns.
            // exDamBonus = 0;

            // Now kill the launcher damage and ammo bonuses.
            lnchDamBonus = std::min(0, lnchDamBonus);
            ammoDamBonus = std::min(0, ammoDamBonus);
            break;

        case SK_BOWS:
        {
            baseHit -= 3;
            exercise(SK_BOWS, (coinflip()? 2 : 1));
            exHitBonus += (effSkill * 2);

            // Strength is good if you're using a nice bow.
            int strbonus = (10 * (you.strength - 10)) / 4;
            strbonus = (strbonus * (2 * baseDam + ammoDamBonus)) / 20;

            // Cap; reduced this cap, because we don't want to allow
            // the extremely-strong to quadruple the enchantment bonus.
            strbonus = std::min(lnchDamBonus + 1, strbonus);

            exDamBonus += strbonus;

            // Add in skill for bows - helps you to find those vulnerable spots.
            // exDamBonus += effSkill;

            dice_mult = dice_mult * (17 + random2(1 + effSkill)) / 17;

            // Now kill the launcher damage bonus.
            lnchDamBonus = std::min(0, lnchDamBonus);
            break;
        }
            // Crossbows are easy for unskilled people.

        case SK_CROSSBOWS:
            exercise(SK_CROSSBOWS, (coinflip()? 2 : 1));
            baseHit++;
            exHitBonus += (3 * effSkill) / 2 + 6;
            // exDamBonus += effSkill * 2 / 3 + 4;

            dice_mult = dice_mult * (22 + random2(1 + effSkill)) / 22;

        default:
            break;
        }

        if (bow_brand == SPWPN_VORPAL)
        {
            // Vorpal brand adds 30% damage bonus. Increased from 25%
            // because at 25%, vorpal brand is completely inferior to
            // speed. At 30% it's marginally better than speed when
            // fighting monsters with very heavy armour.
            dice_mult = dice_mult * 130 / 100;
        }

        if (ammo_brand == SPMSL_STEEL)
            dice_mult = dice_mult * 150 / 100;

        // ID check. Can't ID off teleported projectiles, uh, because
        // it's too weird. Also it messes up the messages.
        if (item_ident(*you.weapon(), ISFLAG_KNOW_PLUSES))
        {
            if (!teleport
                && !item_ident(you.inv[throw_2], ISFLAG_KNOW_PLUSES)
                && x_chance_in_y(shoot_skill, 100))
            {
                set_ident_flags( item, ISFLAG_KNOW_PLUSES );
                set_ident_flags( you.inv[throw_2], ISFLAG_KNOW_PLUSES );
                ammo_ided = true;
                identify_floor_missiles_matching(item, ISFLAG_KNOW_PLUSES);
                mprf("You are firing %s.",
                     you.inv[throw_2].name(DESC_NOCAP_A).c_str());
            }
        }
        else if (!teleport && x_chance_in_y(shoot_skill, 100))
        {
            item_def& weapon = *you.weapon();
            set_ident_flags(weapon, ISFLAG_KNOW_PLUSES);

            mprf("You are wielding %s.", weapon.name(DESC_NOCAP_A).c_str());

            more();
            you.wield_change = true;
        }
    }

    // check for returning ammo from launchers
    if (returning && projected == LRET_LAUNCHED)
    {
        switch (lnchType)
        {
            case WPN_CROSSBOW:
                if (returning && !one_chance_in(1 + skill_bump(SK_CROSSBOWS)))
                    did_return = true;
                break;
            case WPN_SLING:
                if (returning && !one_chance_in(1 + skill_bump(SK_SLINGS)))
                    did_return = true;
                break;
            case WPN_BOW:
            case WPN_LONGBOW:
                if (returning && !one_chance_in(1 + skill_bump(SK_BOWS)))
                    did_return = true;
                break;
            case WPN_BLOWGUN:
                if (returning && !one_chance_in(1 + skill_bump(SK_THROWING)))
                    did_return = true;
                break;
            default:
                break;
        }
    }

    // CALCULATIONS FOR THROWN WEAPONS
    if (projected == LRET_THROWN)
    {
        returning = returning && !teleport;

        if (returning && !one_chance_in(1 + skill_bump(SK_THROWING)))
            did_return = true;

        baseHit = 0;

        // Missiles only use inv_plus.
        if (wepClass == OBJ_MISSILES)
            ammoDamBonus = ammoHitBonus;

        // All weapons that use 'throwing' go here.
        if (wepClass == OBJ_WEAPONS
            || (wepClass == OBJ_MISSILES
                && (wepType == MI_STONE || wepType == MI_LARGE_ROCK
                    || wepType == MI_DART || wepType == MI_JAVELIN)))
        {
            // Elves with elven weapons.
            if (get_equip_race(item) == ISFLAG_ELVEN
                && player_genus(GENPC_ELVEN))
            {
                baseHit++;
            }

            // Give an appropriate 'tohit':
            // * hand axes and clubs are -5
            // * daggers are +1
            // * spears are -1
            // * rocks are 0
            if (wepClass == OBJ_WEAPONS)
            {
                switch (wepType)
                {
                    case WPN_DAGGER:
                        baseHit++;
                        break;
                    case WPN_SPEAR:
                        baseHit--;
                        break;
                    default:
                        baseHit -= 5;
                        break;
                }
            }
            else if (wepClass == OBJ_MISSILES)
            {
                switch (wepType)
                {
                    case MI_DART:
                        baseHit += 2;
                        break;
                    case MI_JAVELIN:
                        baseHit++;
                        break;
                    default:
                        break;
                }
            }

            exHitBonus = you.skills[SK_THROWING] * 2;

            baseDam = property(item, PWPN_DAMAGE);

            // Dwarves/orcs with dwarven/orcish weapons.
            if (get_equip_race(item) == ISFLAG_DWARVEN
                   && player_genus(GENPC_DWARVEN)
                || get_equip_race(item) == ISFLAG_ORCISH
                   && you.species == SP_HILL_ORC)
            {
                baseDam++;
            }

            exDamBonus =
                (10 * (you.skills[SK_THROWING] / 2 + you.strength - 10)) / 12;

            // Now, exDamBonus is a multiplier.  The full multiplier
            // is applied to base damage, but only a third is applied
            // to the magical modifier.
            exDamBonus = (exDamBonus * (3 * baseDam + ammoDamBonus)) / 30;
        }

        if (wepClass == OBJ_MISSILES)
        {
            // Identify ammo type.
            set_ident_flags(you.inv[throw_2], ISFLAG_KNOW_TYPE);
            ammo_ided = true;

            switch (wepType)
            {
            case MI_LARGE_ROCK:
                if (you.can_throw_large_rocks())
                    baseHit = 1;
                break;

            case MI_DART:
                // Darts also using throwing skills, now.
                exHitBonus += skill_bump(SK_THROWING);
                exDamBonus += you.skills[SK_THROWING] * 3 / 5;

                // exercise skills
                exercise(SK_THROWING, 1 + random2avg(3, 2));
                break;

            case MI_JAVELIN:
                // Javelins use throwing skill.
                exHitBonus += skill_bump(SK_THROWING);
                exDamBonus += you.skills[SK_THROWING] * 3 / 5;

                // Adjust for strength and dex.
                exDamBonus = str_adjust_thrown_damage(exDamBonus);
                exHitBonus = dex_adjust_thrown_tohit(exHitBonus);

                // High dex helps damage a bit, too (aim for weak spots).
                exDamBonus = stat_adjust(exDamBonus, you.dex, 20, 150, 100);

                // Javelins train throwing quickly.
                exercise(SK_THROWING, 1 + coinflip());
                break;

            case MI_THROWING_NET:
                // Nets use throwing skill.  They don't do any damage!
                baseDam = 0;
                exDamBonus = 0;
                ammoDamBonus = 0;

                // ...but accuracy is important for this one.
                baseHit = 1;
                exHitBonus += (skill_bump(SK_THROWING) * 7 / 2);
                // Adjust for strength and dex.
                exHitBonus = dex_adjust_thrown_tohit(exHitBonus);

                // Nets train throwing.
                exercise(SK_THROWING, 1);
                break;
            }
        }

        // [dshaligram] The defined base damage applies only when used
        // for launchers. Hand-thrown stones and darts do only half
        // base damage. Yet another evil 4.0ism.
        if (wepClass == OBJ_MISSILES
            && (wepType == MI_DART || wepType == MI_STONE))
        {
            baseDam = div_rand_round(baseDam, 2);
        }

        // exercise skill
        if (coinflip())
            exercise(SK_THROWING, 1);

        // ID check
        if (!teleport
            && !item_ident(you.inv[throw_2], ISFLAG_KNOW_PLUSES)
            && x_chance_in_y(you.skills[SK_THROWING], 100))
        {
            set_ident_flags( item, ISFLAG_KNOW_PLUSES );
            set_ident_flags( you.inv[throw_2], ISFLAG_KNOW_PLUSES );
            identify_floor_missiles_matching(item, ISFLAG_KNOW_PLUSES);
            ammo_ided = true;
            mprf("You are throwing %s.",
                 you.inv[throw_2].name(DESC_NOCAP_A).c_str());
        }
    }

    if (pbolt.flavour != BEAM_MISSILE)
        // [dshaligram] Branded arrows are much stronger.
        dice_mult = (dice_mult * 150) / 100;

    // Dexterity bonus, and possible skill increase for silly throwing.
    if (projected)
    {
        if (wepType != MI_LARGE_ROCK && wepType != MI_THROWING_NET)
        {
            exHitBonus += you.dex / 2;

            // slaying bonuses
            if (wepType != MI_NEEDLE)
            {
                slayDam = slaying_bonus(PWPN_DAMAGE, true);
                slayDam = (slayDam < 0 ? -random2(1 - slayDam)
                                       :  random2(1 + slayDam));
            }

            exHitBonus += slaying_bonus(PWPN_HIT, true);
        }
    }
    else // LRET_FUMBLED
    {
        if (one_chance_in(20))
            exercise(SK_THROWING, 1);

        exHitBonus = you.dex / 4;

        if (wepClass == OBJ_MISSILES && wepType == MI_NEEDLE)
        {
            // Throwing needles is now seriously frowned upon; it's difficult
            // to grip a fiddly little needle, and not penalising it cheapens
            // blowguns.
            exHitBonus -= (30 - you.skills[SK_THROWING]) / 3;
            baseHit    -= (30 - you.skills[SK_THROWING]) / 3;
            dprf("Needle base hit = %d, exHitBonus = %d",
                    baseHit, exHitBonus);
        }
    }

    // FINALISE tohit and damage
    if (exHitBonus >= 0)
        pbolt.hit = baseHit + random2avg(exHitBonus + 1, 2);
    else
        pbolt.hit = baseHit - random2avg(0 - (exHitBonus - 1), 2);

    if (exDamBonus >= 0)
        pbolt.damage = dice_def(1, baseDam + random2(exDamBonus + 1));
    else
        pbolt.damage = dice_def(1, baseDam - random2(0 - (exDamBonus - 1)));

    pbolt.damage.size  = dice_mult * pbolt.damage.size / 100;
    pbolt.damage.size += slayDam;

    // Only add bonuses if we're throwing something sensible.
    if (projected || wepClass == OBJ_WEAPONS)
    {
        pbolt.hit += ammoHitBonus + lnchHitBonus;
        pbolt.damage.size += ammoDamBonus + lnchDamBonus;
    }

    // Add in bonus (only from Portal Projectile for now).
    if (acc_bonus != DEBUG_COOKIE)
        pbolt.hit += acc_bonus;

    scale_dice(pbolt.damage);

    dprf(   "H:%d+%d;a%dl%d.  D:%d+%d;a%dl%d -> %d,%dd%d",
              baseHit, exHitBonus, ammoHitBonus, lnchHitBonus,
              baseDam, exDamBonus, ammoDamBonus, lnchDamBonus,
              pbolt.hit, pbolt.damage.num, pbolt.damage.size );

    // Create message.
    mprf( "%s %s%s %s.",
          teleport  ? "Magically, you" : "You",
          projected ? "" : "awkwardly ",
          projected == LRET_LAUNCHED ? "shoot" : "throw",
          ammo_name.c_str() );

    // Ensure we're firing a 'missile'-type beam.
    pbolt.is_beam   = false;
    pbolt.is_tracer = false;

    // Mark this item as thrown if it's a missile, so that we'll pick it up
    // when we walk over it.
    if (wepClass == OBJ_MISSILES || wepClass == OBJ_WEAPONS)
        item.flags |= ISFLAG_THROWN;

    bool hit = false;
    if (teleport)
    {
        // Violating encapsulation somewhat...oh well.
        pbolt.use_target_as_pos = true;
        pbolt.affect_cell();
        pbolt.affect_endpoint();
        if (!did_return && acc_bonus != DEBUG_COOKIE)
            pbolt.drop_object();
    }
    else
    {
        if (Tutorial.tutorial_left)
            Tutorial.tut_throw_counter++;

        // Dropping item copy, since the launched item might be different.
        pbolt.drop_item = !did_return;
        pbolt.fire();

        // The item can be destroyed before returning.
        if (did_return && thrown_object_destroyed(&item, pbolt.target))
            did_return = false;
    }

    if (bow_brand == SPWPN_CHAOS || ammo_brand == SPMSL_CHAOS)
    {
        did_god_conduct(DID_CHAOS, 2 + random2(3),
                        bow_brand == SPWPN_CHAOS || ammo_brand_known);
    }

    if (bow_brand == SPWPN_REAPING || ammo_brand == SPMSL_REAPING)
    {
        did_god_conduct(DID_NECROMANCY, 2,
                        bow_brand == SPWPN_REAPING || ammo_brand_known);
    }

    if (ammo_brand == SPMSL_RAGE)
    {
        did_god_conduct(DID_HASTY, 6 + random2(3), ammo_brand_known);
    }

    if (did_return)
    {
        // Fire beam in reverse.
        pbolt.setup_retrace();
        viewwindow(false);
        pbolt.fire();

        msg::stream << item.name(DESC_CAP_THE) << " returns to your pack!"
                    << std::endl;

        // Player saw the item return.
        if (!is_artefact(you.inv[throw_2]))
        {
            // Since this only happens for non-artefacts, also mark properties
            // as known.
            set_ident_flags(you.inv[throw_2],
                            ISFLAG_KNOW_TYPE | ISFLAG_KNOW_PROPERTIES);
        }
    }
    else
    {
        // Should have returned but didn't.
        if (returning && item_type_known(you.inv[throw_2]))
        {
            msg::stream << item.name(DESC_CAP_THE)
                        << " fails to return to your pack!" << std::endl;
        }
        dec_inv_item_quantity(throw_2, 1);
        if (unwielded)
            canned_msg(MSG_EMPTY_HANDED);
    }

    throw_noise(&you, pbolt, thrown);

    // ...any monster nearby can see that something has been thrown, even
    // if it didn't make any noise.
    alert_nearby_monsters();

    if (ammo_ided)
        _merge_ammo_in_inventory(throw_2);

    you.turn_is_over = true;

    if (pbolt.special_explosion != NULL)
        delete pbolt.special_explosion;

    return (hit);
}

bool thrown_object_destroyed(item_def *item, const coord_def& where)
{
    ASSERT(item != NULL);

    int chance = 0;

    std::string name = item->name(DESC_PLAIN, false, true, false);

    // Exploding missiles are always destroyed.
    if (name.find("explod") != std::string::npos)
        return (true);

    if (item->base_type == OBJ_MISSILES)
    {
        int brand = get_ammo_brand(*item);
        if (brand == SPMSL_CHAOS || brand == SPMSL_DISPERSAL)
            return (true);

        // [dshaligram] Removed influence of Throwing on ammo preservation.
        // The effect is nigh impossible to perceive.
        switch (item->sub_type)
        {
        case MI_NEEDLE:
            chance = (brand == SPMSL_CURARE ? 3 : 6);
            break;

        case MI_SLING_BULLET:
        case MI_STONE:
        case MI_ARROW:
        case MI_BOLT:
            chance = 4;
            break;

        case MI_DART:
            chance = 3;
            break;

        case MI_JAVELIN:
            chance = 10;
            break;

        case MI_THROWING_NET:
            // Doesn't get destroyed by throwing.
            break;

        case MI_LARGE_ROCK:
        default:
            chance = 25;
            break;
        }

        if (brand == SPMSL_STEEL)
            chance *= 10;
        if (brand == SPMSL_FLAME)
            chance /= 2;
        if (brand == SPMSL_FROST)
            chance /= 2;
        if (brand == SPMSL_REAPING)
            chance /= 4;
    }

    // Enchanted projectiles get an extra shot at avoiding
    // destruction: plus / (1 + plus) chance of survival.
    bool destroyed = (chance == 0) ? false : (one_chance_in(chance)
                                              && one_chance_in(item->plus + 1));

    return destroyed;
}

void jewellery_wear_effects(item_def &item)
{
    item_type_id_state_type ident        = ID_TRIED_TYPE;
    artefact_prop_type      fake_rap     = ARTP_NUM_PROPERTIES;
    bool                    learn_pluses = false;

    // Randart jewellery shouldn't auto-ID just because the base type
    // is known. Somehow the player should still be told, preferably
    // by message. (jpeg)
    const bool artefact     = is_artefact(item);
    const bool known_pluses = item_ident(item, ISFLAG_KNOW_PLUSES);
    const bool known_cursed = item_known_cursed(item);
    const bool known_bad    = (item_type_known(item)
                               && item_value(item) <= 2);

    switch (item.sub_type)
    {
    case RING_FIRE:
    case RING_HUNGER:
    case RING_ICE:
    case RING_LIFE_PROTECTION:
    case RING_POISON_RESISTANCE:
    case RING_PROTECTION_FROM_COLD:
    case RING_PROTECTION_FROM_FIRE:
    case RING_PROTECTION_FROM_MAGIC:
    case RING_SUSTAIN_ABILITIES:
    case RING_SUSTENANCE:
    case RING_SLAYING:
    case RING_WIZARDRY:
    case RING_TELEPORT_CONTROL:
        break;

    case RING_SEE_INVISIBLE:
        // We might have to turn autopickup back on again.
        // TODO: Check all monsters in LOS. If any of them are invisible
        //       (and thus become visible once the ring is worn), the ring
        //       should be autoidentified.
        if (item_type_known(item))
            autotoggle_autopickup(false);
        break;

    case RING_PROTECTION:
        you.redraw_armour_class = true;
        if (item.plus != 0)
        {
            if (!artefact)
                ident = ID_KNOWN_TYPE;
            else if (!known_pluses)
            {
                mprf("You feel %s.", item.plus > 0 ?
                     "well-protected" : "more vulnerable");
            }
            learn_pluses = true;
        }
        break;

    case RING_INVISIBILITY:
        if (!you.duration[DUR_INVIS])
        {
            mpr("You become transparent for a moment.");
            if (artefact)
                fake_rap = ARTP_INVISIBLE;
            else
                ident = ID_KNOWN_TYPE;
        }
        break;

    case RING_EVASION:
        you.redraw_evasion = true;
        if (item.plus != 0)
        {
            if (!artefact)
                ident = ID_KNOWN_TYPE;
            else if (!known_pluses)
                mprf("You feel %s.", item.plus > 0? "nimbler" : "more awkward");
            learn_pluses = true;
        }
        break;

    case RING_STRENGTH:
        if (item.plus)
        {
            modify_stat(STAT_STRENGTH, item.plus, false, item);

            if (artefact)
                fake_rap = ARTP_STRENGTH;
            else
                ident = ID_KNOWN_TYPE;

           learn_pluses = true;
        }
        break;

    case RING_DEXTERITY:
        if (item.plus)
        {
            modify_stat(STAT_DEXTERITY, item.plus, false, item);

            if (artefact)
                fake_rap = ARTP_DEXTERITY;
            else
                ident = ID_KNOWN_TYPE;

           learn_pluses = true;
        }
        break;

    case RING_INTELLIGENCE:
        if (item.plus)
        {
            modify_stat(STAT_INTELLIGENCE, item.plus, false, item);

            if (artefact)
                fake_rap = ARTP_INTELLIGENCE;
            else
                ident = ID_KNOWN_TYPE;

           learn_pluses = true;
        }
        break;

    case RING_MAGICAL_POWER:
        mpr("You feel your mana capacity increase.");
        calc_mp();
        if (artefact)
            fake_rap = ARTP_MAGICAL_POWER;
        else
            ident = ID_KNOWN_TYPE;
        break;

    case RING_LEVITATION:
        if (!scan_artefacts(ARTP_LEVITATE))
        {
            if (you.airborne())
                mpr("You feel vaguely more buoyant than before.");
            else
                mpr("You feel buoyant.");
            if (artefact)
                fake_rap = ARTP_LEVITATE;
            else
                ident = ID_KNOWN_TYPE;
        }
        break;

    case RING_TELEPORTATION:
        mpr("You feel slightly jumpy.");
        if (artefact)
            fake_rap = ARTP_CAUSE_TELEPORTATION;
        else
            ident = ID_KNOWN_TYPE;
        break;

    case AMU_RAGE:
        if (!scan_artefacts(ARTP_BERSERK))
        {
            mpr("You feel a brief urge to hack something to bits.");
            if (artefact)
                fake_rap = ARTP_BERSERK;
            else
                ident = ID_KNOWN_TYPE;
        }
        break;

    case AMU_FAITH:
        if (you.religion != GOD_NO_GOD)
        {
            mpr("You feel a surge of divine interest.", MSGCH_GOD);
            ident = ID_KNOWN_TYPE;
        }
        break;

    case AMU_THE_GOURMAND:
        // What's this supposed to achieve? (jpeg)
        you.duration[DUR_GOURMAND] = 0;
        break;

    case AMU_CONTROLLED_FLIGHT:
        if (you.duration[DUR_LEVITATION]
            && !extrinsic_amulet_effect(AMU_CONTROLLED_FLIGHT))
        {
            ident = ID_KNOWN_TYPE;
        }
        break;

    case AMU_GUARDIAN_SPIRIT:
        if (player_spirit_shield()<2)
        {
            set_mp(0, false);
            mpr("You feel your power drawn to a protective spirit.");
            if (you.species == SP_DEEP_DWARF)
                mpr("Now linked to your health, your magic stops regenerating.");
            ident = ID_KNOWN_TYPE;
        }
        break;

    case RING_REGENERATION:
        // To be exact, bloodless vampires should get the id only after they
        // drink anything.  Not worth complicating the code, IMHO. [1KB]
        if (player_mutation_level(MUT_SLOW_HEALING) < 3)
            ident = ID_KNOWN_TYPE;
        break;

    }

    // Artefacts have completely different appearance than base types
    // so we don't allow them to make the base types known.
    if (artefact)
    {
        bool show_msgs = true;
        use_artefact(item, &show_msgs);

        if (learn_pluses && (item.plus != 0 || item.plus2 != 0))
            set_ident_flags(item, ISFLAG_KNOW_PLUSES);

        if (fake_rap != ARTP_NUM_PROPERTIES)
            artefact_wpn_learn_prop(item, fake_rap);

        if (!item.props.exists("jewellery_tried")
            || !item.props["jewellery_tried"].get_bool())
        {
            item.props["jewellery_tried"].get_bool() = true;
        }
    }
    else
    {
        set_ident_type(item, ident);

        if (ident == ID_KNOWN_TYPE)
            set_ident_flags(item, ISFLAG_EQ_JEWELLERY_MASK);
    }

    if (item.cursed())
    {
        mprf("Oops, that %s feels deathly cold.",
             jewellery_is_amulet(item)? "amulet" : "ring");
        learned_something_new(TUT_YOU_CURSED);

        int amusement = 32;
        if (!known_cursed && !known_bad)
        {
            amusement *= 2;

            god_type god;
            if (origin_is_god_gift(item, &god) && god == GOD_XOM)
                amusement *= 2;
        }
        xom_is_stimulated(amusement);
    }

    // Cursed or not, we know that since we've put the ring on.
    set_ident_flags(item, ISFLAG_KNOW_CURSE);

    mpr(item.name(DESC_INVENTORY_EQUIP).c_str());
}

static int _prompt_ring_to_remove(int new_ring)
{
    const item_def *left  = you.slot_item(EQ_LEFT_RING);
    const item_def *right = you.slot_item(EQ_RIGHT_RING);

    if (left->cursed() && right->cursed())
    {
        mprf("You're already wearing two cursed rings!");
        return (-1);
    }

    mesclr();
    mprf("Wearing %s.", you.inv[new_ring].name(DESC_NOCAP_A).c_str());

    const char lslot = index_to_letter(left->link);
    const char rslot = index_to_letter(right->link);

    mprf(MSGCH_PROMPT,
         "You're wearing two rings. Remove which one? (%c/%c/<</>/Esc)",
         lslot, rslot);

    mprf(" < or %s", left->name(DESC_INVENTORY).c_str());
    mprf(" > or %s", right->name(DESC_INVENTORY).c_str());

    // Deactivate choice from tile inventory.
    // FIXME: We need to be able to get the choice (item letter)
    //        *without* the choice taking action by itself!
    mouse_control mc(MOUSE_MODE_MORE);
    int c;
    do
        c = getch();
    while (c != lslot && c != rslot && c != '<' && c != '>'
           && c != ESCAPE && c != ' ');

    mesclr();

    if (c == ESCAPE || c == ' ')
        return (-1);

    const int eqslot = (c == lslot || c == '<') ? EQ_LEFT_RING
                                                : EQ_RIGHT_RING;

    if (!check_warning_inscriptions(you.inv[you.equip[eqslot]], OPER_REMOVE))
        return (-1);

    return (you.equip[eqslot]);
}

// Checks whether a to-be-worn or to-be-removed item affects
// character stats and whether wearing/removing it could be fatal.
// If so, warns the player, or just returns false if quiet is true.
bool safe_to_remove_or_wear(const item_def &item, bool remove,
                            bool quiet)
{
    int prop_str = 0;
    int prop_dex = 0;
    int prop_int = 0;
    bool prop_lev = false;
    bool fatal_liquid = false;
    dungeon_feature_type gridhere = grd(you.pos());

    // Don't warn when putting on an unknown item.
    if (item.base_type == OBJ_JEWELLERY
        && item_ident(item, ISFLAG_KNOW_PLUSES))
    {
        switch (item.sub_type)
        {
        case RING_STRENGTH:
            if (item.plus != 0)
                prop_str = item.plus;
            break;
        case RING_DEXTERITY:
            if (item.plus != 0)
                prop_dex = item.plus;
            break;
        case RING_INTELLIGENCE:
            if (item.plus != 0)
                prop_int = item.plus;
            break;
        case RING_LEVITATION:
            prop_lev = true;
            break;
        default:
            break;
        }
    }

    if (item.base_type == OBJ_ARMOUR && item_type_known(item))
    {
        switch (item.special)
        {
        case SPARM_STRENGTH:
            prop_str = 3;
            break;

        case SPARM_INTELLIGENCE:
            prop_int = 3;
            break;

        case SPARM_DEXTERITY:
            prop_dex = 3;
            break;

        case SPARM_LEVITATION:
            prop_lev = true;
            break;

        default:
            break;
        }
    }

    if (is_artefact(item))
    {
        prop_str += artefact_known_wpn_property(item, ARTP_STRENGTH);
        prop_int += artefact_known_wpn_property(item, ARTP_INTELLIGENCE);
        prop_dex += artefact_known_wpn_property(item, ARTP_DEXTERITY);

        prop_lev = prop_lev || artefact_known_wpn_property(item, ARTP_LEVITATE);

        if (!remove && artefact_known_wpn_property(item, ARTP_EYESIGHT))
        {
            // We might have to turn autopickup back on again.
            // This is not optimal, in that it could also happen if we do
            // not know the property (in which case it should become known).
            autotoggle_autopickup(false);
        }
    }

    if (you.species == SP_MERFOLK && feat_is_water(gridhere))
    {
        // Falling into water could lose boots and cause fatal stat loss.
        // There is a complication here.  Suppose you are taking off a
        // randart with +Lev and a stat modification, while wearing boots
        // that modify the same stat.  We have to consider losing both at
        // the same time.

        // This only handles removal, which is OK, because levitating is
        // never fatal.

        you.strength -= prop_str;
        you.intel -= prop_int;
        you.dex -= prop_dex;

        bool safe = merfolk_change_is_safe();

        you.strength += prop_str;
        you.intel += prop_int;
        you.dex += prop_dex;

        if (!safe)
            fatal_liquid = true;
    }

    if (gridhere == DNGN_LAVA || (gridhere == DNGN_DEEP_WATER && !beogh_water_walk()))
    {
        // We'd fall into water!  See if we would drown.
        coord_def empty;

        if (you.attribute[ATTR_TRANSFORMATION] == TRAN_STATUE
               || (carrying_capacity() / 2) <= you.burden
               || !empty_surrounds(you.pos(), DNGN_FLOOR, 1, false, empty))
            fatal_liquid = true;

        if (gridhere == DNGN_LAVA)
        {
            int res = player_res_fire(false);

            if (res <= 0 || (110 / res) >= you.hp)
                fatal_liquid = true;
        }
    }

    if (you.permanent_levitation()
            && (item.base_type != OBJ_ARMOUR || item.sub_type != ARM_BOOTS))
    {
        fatal_liquid = false; // we won't fall!
    }

    if (remove)
    {
        if (prop_str >= you.strength || prop_int >= you.intel
            || prop_dex >= you.dex || prop_lev && fatal_liquid)
        {
            if (!quiet)
            {
                mprf(MSGCH_WARN, "%s this item would be fatal, so you refuse "
                                 "to do that.",
                                 (item.base_type == OBJ_WEAPONS ? "Unwielding"
                                                                : "Removing"));
            }
            return (false);
        }
    }
    else // put on
    {
        if (-prop_str >= you.strength || -prop_int >= you.intel
            || -prop_dex >= you.dex)
        {
            if (!quiet)
            {
                mprf(MSGCH_WARN, "%s this item would be fatal, so you refuse "
                                 "to do that.",
                                 (item.base_type == OBJ_WEAPONS ? "Wielding"
                                                                : "Wearing"));
            }

            return (false);
        }
    }

    return (true);
}

// Assumptions:
// you.inv[ring_slot] is a valid ring.
// EQ_LEFT_RING and EQ_RIGHT_RING are both occupied, and ring_slot is not
// one of the worn rings.
//
// Does not do amulets.
static bool _swap_rings(int ring_slot)
{
    const item_def* lring = you.slot_item(EQ_LEFT_RING);
    const item_def* rring = you.slot_item(EQ_RIGHT_RING);

    if (lring->cursed() && rring->cursed())
    {
        mprf("You're already wearing two cursed rings!");
        return (false);
    }

    int unwanted;

    // Don't prompt if both rings are of the same type.
    if (lring->sub_type == rring->sub_type
        && lring->plus == rring->plus
        && lring->plus2 == rring->plus2
        && !is_artefact(*lring) && !is_artefact(*rring))
    {
        if (lring->cursed())
            unwanted = you.equip[EQ_RIGHT_RING];
        else
            unwanted = you.equip[EQ_LEFT_RING];
    }
    else
    {
        // Ask the player which existing ring is persona non grata.
        unwanted = _prompt_ring_to_remove(ring_slot);
    }

    if (unwanted == -1)
    {
        canned_msg(MSG_OK);
        return (false);
    }

    if (!remove_ring(unwanted, false))
        return (false);

    // Check that the new ring won't kill us.
    if (!safe_to_remove_or_wear(you.inv[ring_slot], false))
        return (false);

    // Put on the new ring.
    start_delay(DELAY_JEWELLERY_ON, 1, ring_slot);

    return (true);
}

bool puton_item(int item_slot)
{
    item_def& item = you.inv[item_slot];

    if (item_slot == you.equip[EQ_LEFT_RING]
        || item_slot == you.equip[EQ_RIGHT_RING]
        || item_slot == you.equip[EQ_AMULET])
    {
        // "Putting on" an equipped item means taking it off.
        if (Options.equip_unequip)
            return (!remove_ring(item_slot));
        else
        {
            mpr("You're already wearing that object!");
            return (false);
        }
    }

    if (item_slot == you.equip[EQ_WEAPON])
    {
        mpr("You are wielding that object.");
        return (false);
    }

    if (item.base_type != OBJ_JEWELLERY)
    {
        mpr("You can only put on jewellery.");
        return (false);
    }

    const bool lring = (you.slot_item(EQ_LEFT_RING)  != NULL);
    const bool rring = (you.slot_item(EQ_RIGHT_RING) != NULL);
    const bool is_amulet = jewellery_is_amulet(item);

    if (!is_amulet)     // i.e. it's a ring
    {
        const item_def* gloves = you.slot_item(EQ_GLOVES);
        if (gloves && gloves->cursed())
        {
            mpr("You can't take your gloves off to put on a ring!");
            return (false);
        }

        if (lring && rring)
            return _swap_rings(item_slot);
    }
    else if (item_def* amulet = you.slot_item(EQ_AMULET))
    {
        // Remove the previous one.
        if (!check_warning_inscriptions(*amulet, OPER_REMOVE)
            || !remove_ring(you.equip[EQ_AMULET], true))
        {
            return (false);
        }

        // Check that the new amulet won't kill us.
        if (!safe_to_remove_or_wear(item, false))
            return (false);

        // Put on the new amulet.
        start_delay(DELAY_JEWELLERY_ON, 1, item_slot);

        // Assume it's going to succeed.
        return (true);
    }

    // Check that it won't kill us.
    if (!safe_to_remove_or_wear(item, false))
        return (false);

    equipment_type hand_used;

    if (is_amulet)
    {
        hand_used = EQ_AMULET;
    }
    else
    {
        // First ring always goes on left hand.
        hand_used = EQ_LEFT_RING;

        // ... unless we're already wearing a ring on the left hand.
        if (lring && !rring)
            hand_used = EQ_RIGHT_RING;
    }

    const unsigned int old_talents = your_talents(false).size();

    // Actually equip the item.
    you.equip[hand_used] = item_slot;

    // And calculate the effects.
    jewellery_wear_effects(item);

    if (Tutorial.tutorial_left && your_talents(false).size() > old_talents)
        learned_something_new(TUT_NEW_ABILITY_ITEM);

    // Putting on jewellery is as fast as wielding weapons.
    you.time_taken /= 2;
    you.turn_is_over = true;

    return (true);
}

bool puton_ring(int slot)
{
    if (player_in_bat_form())
    {
        mpr("You can't put on anything in your present form.");
        return (false);
    }

    int item_slot;

    if (inv_count() < 1)
    {
        canned_msg(MSG_NOTHING_CARRIED);
        return (false);
    }

    if (you.berserk())
    {
        canned_msg(MSG_TOO_BERSERK);
        return (false);
    }

    if (slot != -1)
        item_slot = slot;
    else
    {
        item_slot = prompt_invent_item( "Put on which piece of jewellery?",
                                        MT_INVLIST, OBJ_JEWELLERY, true, true,
                                        true, 0, -1, NULL, OPER_PUTON );
    }

    if (prompt_failed(item_slot))
        return (false);

    return puton_item(item_slot);
}

void remove_amulet_of_faith(item_def &item)
{
    if (you.religion != GOD_NO_GOD
        && you.religion != GOD_XOM)
    {
        simple_god_message(" seems less interested in you.");

        const int piety_loss = div_rand_round(you.piety, 3);
        // Piety penalty for removing the Amulet of Faith.
        if (you.piety - piety_loss > 10)
        {
            mprf(MSGCH_GOD,
                 "%s leaches power out of you as you remove it.",
                 item.name(DESC_CAP_YOUR).c_str());
            dprf("%s: piety leach: %d",
                 item.name(DESC_PLAIN).c_str(), piety_loss);
            lose_piety(piety_loss);
        }
    }
}

void jewellery_remove_effects(item_def &item, bool mesg)
{
    // The ring/amulet must already be removed from you.equip at this point.

    // Turn off show_uncursed before getting the item name, because this item
    // was just removed, and the player knows it's uncursed.
    const bool old_showuncursed = Options.show_uncursed;
    Options.show_uncursed = false;

    if (mesg)
        mprf("You remove %s.", item.name(DESC_NOCAP_YOUR).c_str());

    Options.show_uncursed = old_showuncursed;

    switch (item.sub_type)
    {
    case RING_FIRE:
    case RING_HUNGER:
    case RING_ICE:
    case RING_LIFE_PROTECTION:
    case RING_POISON_RESISTANCE:
    case RING_PROTECTION_FROM_COLD:
    case RING_PROTECTION_FROM_FIRE:
    case RING_PROTECTION_FROM_MAGIC:
    case RING_REGENERATION:
    case RING_SEE_INVISIBLE:
    case RING_SLAYING:
    case RING_SUSTAIN_ABILITIES:
    case RING_SUSTENANCE:
    case RING_TELEPORTATION:
    case RING_WIZARDRY:
    case RING_TELEPORT_CONTROL:
        break;

    case RING_PROTECTION:
        you.redraw_armour_class = true;
        break;

    case RING_EVASION:
        you.redraw_evasion = true;
        break;

    case RING_STRENGTH:
        modify_stat(STAT_STRENGTH, -item.plus, false, item, true);
        break;

    case RING_DEXTERITY:
        modify_stat(STAT_DEXTERITY, -item.plus, false, item, true);
        break;

    case RING_INTELLIGENCE:
        modify_stat(STAT_INTELLIGENCE, -item.plus, false, item, true);
        break;

    case RING_LEVITATION:
        if (you.duration[DUR_LEVITATION] && !you.permanent_levitation())
            you.duration[DUR_LEVITATION] = 1;
        break;

    case RING_INVISIBILITY:
        if (you.duration[DUR_INVIS])
            you.duration[DUR_INVIS] = 1;
        break;

    case RING_MAGICAL_POWER:
        mpr("You feel your mana capacity decrease.");
        // dec_max_mp(9);
        break;

    case AMU_THE_GOURMAND:
        you.duration[DUR_GOURMAND] = 0;
        break;

    case AMU_FAITH:
        remove_amulet_of_faith(item);
        break;

    case AMU_GUARDIAN_SPIRIT:
        if (you.species == SP_DEEP_DWARF)
            mpr("Your magic begins regenerating once more.");
    }

    if (is_artefact(item))
        unuse_artefact(item, &mesg);

    // Must occur after ring is removed. -- bwr
    calc_mp();
}

bool remove_ring(int slot, bool announce)
{
    if (player_in_bat_form())
    {
        mpr("You can't wear or remove anything in your present form.");
        return (false);
    }

    equipment_type hand_used = EQ_NONE;
    int ring_wear_2;

    if (you.equip[EQ_LEFT_RING] == -1 && you.equip[EQ_RIGHT_RING] == -1
        && you.equip[EQ_AMULET] == -1)
    {
        mpr("You aren't wearing any rings or amulets.");
        return (false);
    }

    if (you.berserk())
    {
        canned_msg(MSG_TOO_BERSERK);
        return (false);
    }

    if (you.equip[EQ_GLOVES] != -1
        && you.inv[you.equip[EQ_GLOVES]] .cursed()
        && you.equip[EQ_AMULET] == -1)
    {
        mpr("You can't take your gloves off to remove any rings!");
        return (false);
    }

    if (you.equip[EQ_LEFT_RING] != -1 && you.equip[EQ_RIGHT_RING] == -1
        && you.equip[EQ_AMULET] == -1)
    {
        hand_used = EQ_LEFT_RING;
    }

    if (you.equip[EQ_LEFT_RING] == -1 && you.equip[EQ_RIGHT_RING] != -1
        && you.equip[EQ_AMULET] == -1)
    {
        hand_used = EQ_RIGHT_RING;
    }

    if (you.equip[EQ_LEFT_RING] == -1 && you.equip[EQ_RIGHT_RING] == -1
        && you.equip[EQ_AMULET] != -1)
    {
        hand_used = EQ_AMULET;
    }

    if (hand_used == EQ_NONE)
    {
        const int equipn =
            (slot == -1)? prompt_invent_item("Remove which piece of jewellery?",
                                             MT_INVLIST,
                                             OBJ_JEWELLERY, true, true, true,
                                             0, -1, NULL, OPER_REMOVE)
                        : slot;

        if (prompt_failed(equipn))
            return (false);

        if (you.inv[equipn].base_type != OBJ_JEWELLERY)
        {
            mpr("That isn't a piece of jewellery.");
            return (false);
        }

        if (you.equip[EQ_LEFT_RING] == equipn)
            hand_used = EQ_LEFT_RING;
        else if (you.equip[EQ_RIGHT_RING] == equipn)
            hand_used = EQ_RIGHT_RING;
        else if (you.equip[EQ_AMULET] == equipn)
            hand_used = EQ_AMULET;
        else
        {
            mpr("You aren't wearing that.");
            return (false);
        }
    }

    if (!check_warning_inscriptions(you.inv[you.equip[hand_used]],
                                    OPER_REMOVE))
    {
        canned_msg(MSG_OK);
        return (false);
    }

    if (you.equip[EQ_GLOVES] != -1
        && you.inv[you.equip[EQ_GLOVES]] .cursed()
        && (hand_used == EQ_LEFT_RING || hand_used == EQ_RIGHT_RING))
    {
        mpr("You can't take your gloves off to remove any rings!");
        return (false);
    }

    if (you.equip[hand_used] == -1)
    {
        mpr("I don't think you really meant that.");
        return (false);
    }

    if (you.inv[you.equip[hand_used]] .cursed())
    {
        if (announce)
        {
            mprf("%s is stuck to you!",
                 you.inv[you.equip[hand_used]].name(DESC_CAP_YOUR).c_str());
        }
        else
            mpr("It's stuck to you!");

        set_ident_flags(you.inv[you.equip[hand_used]], ISFLAG_KNOW_CURSE);
        return (false);
    }

    ring_wear_2 = you.equip[hand_used];

    // Remove the ring.
    if (!safe_to_remove_or_wear(you.inv[ring_wear_2], true))
        return (false);

    you.equip[hand_used] = -1;

    jewellery_remove_effects(you.inv[ring_wear_2]);

    you.time_taken /= 2;
    you.turn_is_over = true;

    return (true);
}

int _wand_range(zap_type ztype)
{
    // FIXME: Eventually we should have sensible values here.
    return (8);
}

int _max_wand_range()
{
    return (8);
}

static bool _dont_use_invis()
{
    if (!you.backlit())
        return (false);

    if (you.haloed())
    {
        mpr("You can't turn invisible.");
        return (true);
    }
    else if (get_contamination_level() > 0
             && !yesno("Invisibility will do you no good right now; "
                       "use anyways?", false, 'n'))
    {
        return (true);
    }

    return (false);
}

void zap_wand(int slot)
{
    if (player_in_bat_form())
    {
        canned_msg(MSG_PRESENT_FORM);
        return;
    }

    bolt beam;
    dist zap_wand;
    int item_slot;

    // Unless the character knows the type of the wand, the targetting
    // system will default to enemies. -- [ds]
    targ_mode_type targ_mode = TARG_HOSTILE;

    beam.obvious_effect = false;

    if (inv_count() < 1)
    {
        canned_msg(MSG_NOTHING_CARRIED);
        return;
    }

    if (you.berserk())
    {
        canned_msg(MSG_TOO_BERSERK);
        return;
    }

    if (slot != -1)
        item_slot = slot;
    else
    {
        item_slot = prompt_invent_item("Zap which item?",
                                       MT_INVLIST,
                                       OBJ_WANDS,
                                       true, true, true, 0, -1, NULL,
                                       OPER_ZAP);
    }

    if (prompt_failed(item_slot))
        return;

    item_def& wand = you.inv[item_slot];
    if (wand.base_type != OBJ_WANDS)
    {
        canned_msg(MSG_NOTHING_HAPPENS);
        return;
    }

    // If you happen to be wielding the wand, its display might change.
    if (you.equip[EQ_WEAPON] == item_slot)
        you.wield_change = true;

    const zap_type type_zapped = wand.zap();

    bool has_charges = true;
    if (wand.plus < 1)
    {
        if (wand.plus2 == ZAPCOUNT_EMPTY)
        {
            mpr("This wand has no charges.");
            return;
        }
        has_charges = false;
    }

    const bool alreadyknown = item_type_known(wand);
    const bool alreadytried = item_type_tried(wand);
          bool invis_enemy  = false;
    const bool dangerous    = player_in_a_dangerous_place(&invis_enemy);

    if (!alreadyknown)
        beam.effect_known = false;
    else
    {
        switch (wand.sub_type)
        {
        case WAND_DIGGING:
        case WAND_TELEPORTATION:
            targ_mode = TARG_ANY;
            break;

        case WAND_HEALING:
            if (you.religion == GOD_ELYVILON)
            {
                targ_mode = TARG_ANY;
                break;
            }
            // else intentional fall-through
        case WAND_HASTING:
        case WAND_INVISIBILITY:
            targ_mode = TARG_FRIEND;
            break;

        default:
            targ_mode = TARG_HOSTILE;
            break;
        }
    }

    int tracer_range = (alreadyknown && wand.sub_type != WAND_RANDOM_EFFECTS) ?
                        _wand_range(type_zapped) : _max_wand_range();
    direction(zap_wand, DIR_NONE, targ_mode, tracer_range);

    if (!zap_wand.isValid)
    {
        if (zap_wand.isCancel)
            canned_msg(MSG_OK);
        return;
    }

    if (alreadyknown && zap_wand.target == you.pos())
    {
        if (wand.sub_type == WAND_TELEPORTATION
            && scan_artefacts(ARTP_PREVENT_TELEPORTATION, false))
        {
            mpr("You cannot teleport right now.");
            return;
        }
        else if (wand.sub_type == WAND_INVISIBILITY
                 && _dont_use_invis())
        {
            return;
        }
    }

    if (!has_charges)
    {
        canned_msg(MSG_NOTHING_HAPPENS);
        // It's an empty wand; inscribe it that way.
        wand.plus2 = ZAPCOUNT_EMPTY;
        you.turn_is_over = true;
        return;
    }


    if (you.confused())
        zap_wand.target = you.pos() + coord_def(random2(13)-6, random2(13)-6);

    if (wand.sub_type == WAND_RANDOM_EFFECTS)
        beam.effect_known = false;

    beam.source   = you.pos();
    beam.attitude = ATT_FRIENDLY;
    beam.set_target(zap_wand);

    bool aimed_at_self = (beam.target == you.pos());

    // Check whether we may hit friends, use "safe" values for random effects
    // and unknown wands (highest possible range, and unresistable beam
    // flavour). Don't use the tracer if firing at self.
    if (!aimed_at_self)
    {
        beam.range = tracer_range;
        if (!player_tracer(beam.effect_known ? type_zapped
                                             : ZAP_DEBUGGING_RAY,
                           2 * (you.skills[SK_EVOCATIONS] - 1),
                           beam, beam.effect_known ? 0 : 17))
        {
            return;
        }
    }

    // Zapping the wand isn't risky if you aim it away from all monsters
    // and yourself, unless there's a nearby invisible enemy and you're
    // trying to hit it at random.
    const bool risky = dangerous && (beam.friend_info.count
                                     || beam.foe_info.count
                                     || invis_enemy
                                     || aimed_at_self);

    if (risky && alreadyknown && wand.sub_type == WAND_RANDOM_EFFECTS)
    {
        // Xom loves it when you use a Wand of Random Effects and
        // there is a dangerous monster nearby...
        xom_is_stimulated(255);
    }

    // Reset range.
    beam.range = _wand_range(type_zapped);

#ifdef WIZARD
    if (you.wizard)
    {
        std::string str = wand.inscription;
        int wiz_range = strip_number_tag(str, "range:");
        if (wiz_range != TAG_UNFOUND)
            beam.range = wiz_range;
    }
#endif

    // zapping() updates beam.
    zapping( type_zapped, 30 + roll_dice(2, you.skills[SK_EVOCATIONS]), beam );

    // Take off a charge.
    wand.plus--;

    // Zap counts count from the last recharge.
    if (wand.plus2 == ZAPCOUNT_MAX_CHARGED || wand.plus2 == ZAPCOUNT_RECHARGED)
        wand.plus2 = 0;
    // Increment zap count.
    if (wand.plus2 >= 0)
        wand.plus2++;

    // Identify if necessary.
    if (!alreadyknown && (beam.obvious_effect || type_zapped == ZAP_FIREBALL))
    {
        set_ident_type(wand, ID_KNOWN_TYPE);
        if (wand.sub_type == WAND_RANDOM_EFFECTS)
            mpr("You feel that this wand is rather unreliable.");

        mpr(wand.name(DESC_INVENTORY_EQUIP).c_str());
    }
    else
        set_ident_type(wand, ID_TRIED_TYPE);

    if (item_type_known(wand)
        && (item_ident(wand, ISFLAG_KNOW_PLUSES)
            || you.skills[SK_EVOCATIONS] > 5 + random2(15)))
    {
        if (!item_ident(wand, ISFLAG_KNOW_PLUSES))
        {
            mpr("Your skill with magical items lets you calculate "
                "the power of this device...");
        }

        mprf("This wand has %d charge%s left.",
             wand.plus, wand.plus == 1 ? "" : "s");

        set_ident_flags(wand, ISFLAG_KNOW_PLUSES);
    }

    exercise(SK_EVOCATIONS, 1);
    alert_nearby_monsters();

    if (!alreadyknown && !alreadytried && risky)
    {
        // Xom loves it when you use an unknown wand and there is a
        // dangerous monster nearby...
        xom_is_stimulated(255);
    }

    you.turn_is_over = true;
}

void prompt_inscribe_item()
{
    if (inv_count() < 1)
    {
        mpr("You don't have anything to inscribe.");
        return;
    }

    int item_slot = prompt_invent_item("Inscribe which item?",
                                       MT_INVLIST, OSEL_ANY);

    if (prompt_failed(item_slot))
        return;

    inscribe_item(you.inv[item_slot], true);
}

void drink(int slot)
{
    if (you.is_undead == US_UNDEAD)
    {
        mpr("You can't drink.");
        return;
    }

    if (slot == -1)
    {
        const dungeon_feature_type feat = grd(you.pos());
        if (feat >= DNGN_FOUNTAIN_BLUE && feat <= DNGN_FOUNTAIN_BLOOD)
            if (_drink_fountain())
                return;
    }

    if (inv_count() == 0)
    {
        canned_msg(MSG_NOTHING_CARRIED);
        return;
    }

    if (you.berserk())
    {
        canned_msg(MSG_TOO_BERSERK);
        return;
    }

    if (player_in_bat_form())
    {
       canned_msg(MSG_PRESENT_FORM);
       return;
    }

    if (slot == -1)
    {
        slot = prompt_invent_item("Drink which item?",
                                  MT_INVLIST, OBJ_POTIONS,
                                  true, true, true, 0, -1, NULL,
                                  OPER_QUAFF);
        if (prompt_failed(slot))
            return;
    }

    item_def& potion = you.inv[slot];

    if (potion.base_type != OBJ_POTIONS)
    {
        mpr("You can't drink that!");
        return;
    }

    const bool alreadyknown = item_type_known(potion);

    if (alreadyknown && you.hunger_state == HS_ENGORGED
        && (is_blood_potion(potion) || potion.sub_type == POT_PORRIDGE))
    {
        mpr("You are much too full right now.");
        return;
    }

    if (alreadyknown && potion.sub_type == POT_INVISIBILITY
        && _dont_use_invis())
    {
        return;
    }

    if (alreadyknown && potion.sub_type == POT_BERSERK_RAGE
        && !berserk_check_wielded_weapon())
    {
        return;
    }

    // The "> 1" part is to reduce the amount of times that Xom is
    // stimulated when you are a low-level 1 trying your first unknown
    // potions on monsters.
    const bool dangerous = (player_in_a_dangerous_place()
                            && you.experience_level > 1);

    // Identify item and type.
    if (potion_effect(static_cast<potion_type>(potion.sub_type),
                      40, true, alreadyknown))
    {
        set_ident_flags(potion, ISFLAG_IDENT_MASK);
        set_ident_type(potion, ID_KNOWN_TYPE);
    }
    else
    {
        set_ident_type(potion, ID_TRIED_TYPE);
    }

    if (!alreadyknown && dangerous)
    {
        // Xom loves it when you drink an unknown potion and there is
        // a dangerous monster nearby...
        xom_is_stimulated(255);
    }

    if (is_blood_potion(potion))
    {
        // Always drink oldest potion.
        remove_oldest_blood_potion(potion);
    }

    dec_inv_item_quantity(slot, 1);
    you.turn_is_over = true;

    if (you.species != SP_VAMPIRE)
        lessen_hunger(40, true);
}

bool _drink_fountain()
{
    const dungeon_feature_type feat = grd(you.pos());

    if (feat < DNGN_FOUNTAIN_BLUE || feat > DNGN_FOUNTAIN_BLOOD)
        return (false);

    if (you.flight_mode() == FL_LEVITATE)
    {
        mpr("You're floating high above the fountain.");
        return (false);
    }

    if (you.berserk())
    {
        canned_msg(MSG_TOO_BERSERK);
        return (true);
    }

    potion_type fountain_effect = POT_WATER;
    if (feat == DNGN_FOUNTAIN_BLUE)
    {
        if (!yesno("Drink from the fountain?", true, 'n'))
            return (false);

        mpr("You drink the pure, clear water.");
    }
    else if (feat == DNGN_FOUNTAIN_BLOOD)
    {
        if (!yesno("Drink from the fountain of blood?", true, 'n'))
            return (false);

        mpr("You drink the blood.");
        fountain_effect = POT_BLOOD;
    }
    else
    {
        if (!yesno("Drink from the sparkling fountain?", true, 'n'))
            return (false);

        mpr("You drink the sparkling water.");

        fountain_effect = static_cast<potion_type>(
            random_choose_weighted(467, POT_WATER,
                                   48,  POT_DECAY,
                                   40,  POT_MUTATION,
                                   40,  POT_HEALING,
                                   40,  POT_HEAL_WOUNDS,
                                   40,  POT_SPEED,
                                   40,  POT_MIGHT,
                                   40,  POT_AGILITY,
                                   40,  POT_BRILLIANCE,
                                   32,  POT_DEGENERATION,
                                   27,  POT_LEVITATION,
                                   27,  POT_POISON,
                                   27,  POT_SLOWING,
                                   27,  POT_PARALYSIS,
                                   27,  POT_CONFUSION,
                                   27,  POT_INVISIBILITY,
                                   20,  POT_MAGIC,
                                   20,  POT_RESTORE_ABILITIES,
                                   20,  POT_RESISTANCE,
                                   20,  POT_STRONG_POISON,
                                   20,  POT_BERSERK_RAGE,
                                   4,   POT_GAIN_STRENGTH,
                                   4,   POT_GAIN_INTELLIGENCE,
                                   4,   POT_GAIN_DEXTERITY,
                                   0));
    }

    if (fountain_effect != POT_WATER && fountain_effect != POT_BLOOD)
        xom_is_stimulated(64);

    // Good gods do not punish for bad random effects. However, they do
    // punish drinking from a fountain of blood.
    potion_effect(fountain_effect, 100, true, feat != DNGN_FOUNTAIN_SPARKLING);

    bool gone_dry = false;
    if (feat == DNGN_FOUNTAIN_BLUE)
    {
        if (one_chance_in(20))
            gone_dry = true;
    }
    else if (feat == DNGN_FOUNTAIN_BLOOD)
    {
        // High chance of drying up, to prevent abuse.
        if (one_chance_in(3))
            gone_dry = true;
    }
    else   // sparkling fountain
    {
        if (one_chance_in(10))
            gone_dry = true;
        else if (random2(50) > 40)
        {
            // Turn fountain into a normal fountain without any message
            // but the glyph colour gives it away (lightblue vs. blue).
            grd(you.pos()) = DNGN_FOUNTAIN_BLUE;
            set_terrain_changed(you.pos());
        }
    }

    if (gone_dry)
    {
        mpr("The fountain dries up!");

        grd(you.pos()) = static_cast<dungeon_feature_type>(feat
                         + DNGN_DRY_FOUNTAIN_BLUE - DNGN_FOUNTAIN_BLUE);

        set_terrain_changed(you.pos());

        crawl_state.cancel_cmd_repeat();
    }

    you.turn_is_over = true;
    return (true);
}

// Returns true if a message has already been printed (which will identify
// the scroll.)
static bool _vorpalise_weapon()
{
    if (!you.weapon())
        return (false);

    // Check if you're wielding a brandable weapon.
    item_def& wpn = *you.weapon();
    if (wpn.base_type != OBJ_WEAPONS || wpn.sub_type == WPN_BLOWGUN
        || is_artefact(wpn))
    {
        return (false);
    }

    you.wield_change = true;

    // If there's no brand, make it vorpal.
    if (get_weapon_brand(wpn) == SPWPN_NORMAL)
    {
        alert_nearby_monsters();
        mprf("%s emits a brilliant flash of light!",
             wpn.name(DESC_CAP_YOUR).c_str());
        set_item_ego_type(wpn, OBJ_WEAPONS, SPWPN_VORPAL);
        return (true);
    }

    // If there's a permanent brand, fail.
    if (you.duration[DUR_WEAPON_BRAND] == 0)
        return (false);

    // There's a temporary brand, attempt to make it permanent.
    const std::string itname = wpn.name(DESC_CAP_YOUR);
    bool success = true;
    bool msg = true;

    switch (get_weapon_brand(wpn))
    {
    case SPWPN_VORPAL:
        if (get_vorpal_type(wpn) != DVORP_CRUSHING)
            mprf("%s's sharpness seems more permanent.", itname.c_str());
        else
            mprf("%s's heaviness feels very stable.", itname.c_str());
        break;

    case SPWPN_FLAME:
    case SPWPN_FLAMING:
        mprf("%s is engulfed in an explosion of flames!", itname.c_str());
        immolation(10, IMMOLATION_SPELL, you.pos(), true, &you);
        break;

    case SPWPN_FROST:
    case SPWPN_FREEZING:
        if (get_weapon_brand(wpn) == SPWPN_FROST)
            mprf("%s is covered with a thick layer of frost!", itname.c_str());
        else
            mprf("%s glows brilliantly blue for a moment.", itname.c_str());
        cast_refrigeration(60);
        break;

    case SPWPN_DRAINING:
        mprf("%s thirsts for the lives of mortals!", itname.c_str());
        drain_exp();
        break;

    case SPWPN_VENOM:
        mprf("%s seems more permanently poisoned.", itname.c_str());
        cast_toxic_radiance();
        break;

    case SPWPN_PAIN:
        // Can't fix pain brand (balance)...you just get tormented.
        mprf("%s shrieks out in agony!", itname.c_str());

        torment_monsters(you.pos(), 0, TORMENT_GENERIC);
        success = false;

        // This is only naughty if you know you're doing it.
        // XXX: assumes this can only happen from Vorpalise Weapon scroll.
        did_god_conduct(DID_NECROMANCY, 10,
                        get_ident_type(OBJ_SCROLLS, SCR_VORPALISE_WEAPON)
                        == ID_KNOWN_TYPE);
        break;

    case SPWPN_DISTORTION:
        // [dshaligram] Attempting to fix a distortion brand gets you a free
        // distortion effect, and no permabranding. Sorry, them's the breaks.
        mprf("%s twongs alarmingly.", itname.c_str());

        // from unwield_item
        MiscastEffect(&you, NON_MONSTER, SPTYP_TRANSLOCATION, 9, 90,
                      "distortion affixation");
        success = false;
        break;

    default:
        success = false;
        msg = false;
        break;
    }

    if (success)
        you.duration[DUR_WEAPON_BRAND] = 0;

    return (msg);
}

bool enchant_weapon(enchant_stat_type which_stat, bool quiet, item_def &wpn)
{
    bool to_hit = (which_stat == ENCHANT_TO_HIT);

    // Cannot be enchanted nor uncursed.
    if (!is_enchantable_weapon(wpn, true, to_hit))
    {
        if (!quiet)
            canned_msg( MSG_NOTHING_HAPPENS );

        return (false);
    }

    const bool is_cursed = wpn.cursed();

    // Missiles only have one stat.
    if (wpn.base_type == OBJ_MISSILES)
    {
        which_stat = ENCHANT_TO_HIT;
        to_hit     = true;
    }

    int enchant_level = (to_hit ? wpn.plus
                                : wpn.plus2);

    // Even if not affected, it may be uncursed.
    if (!is_enchantable_weapon(wpn, false, to_hit)
        || enchant_level >= 4 && x_chance_in_y(enchant_level, MAX_WPN_ENCHANT))
    {
        if (is_cursed)
        {
            if (!quiet)
            {
                mprf("%s glows silver for a moment.",
                     wpn.name(DESC_CAP_YOUR).c_str());
            }

            do_uncurse_item(wpn);
            return (true);
        }
        else
        {
            if (!quiet)
                canned_msg(MSG_NOTHING_HAPPENS);

            // Xom thinks it's funny if enchantment is possible but fails.
            if (is_enchantable_weapon(wpn, false, to_hit))
                xom_is_stimulated(32);

            return (false);
        }
    }

    // Get item name now before changing enchantment.
    std::string iname = wpn.name(DESC_CAP_YOUR);

    if (wpn.base_type == OBJ_WEAPONS)
    {
        if (to_hit)
        {
            if (!quiet)
                mprf("%s glows green for a moment.", iname.c_str());

            wpn.plus++;
        }
        else
        {
            if (!quiet)
                mprf("%s glows red for a moment.", iname.c_str());

            wpn.plus2++;
        }
    }
    else if (wpn.base_type == OBJ_MISSILES)
    {
        if (!quiet)
        {
            mprf("%s glow%s red for a moment.", iname.c_str(),
                 wpn.quantity > 1 ? "" : "s");
        }

        wpn.plus++;
    }

    if (is_cursed)
        do_uncurse_item(wpn);

    return (true);
}

static bool _handle_enchant_weapon(enchant_stat_type which_stat,
                                   bool quiet, int item_slot)
{
    if (item_slot == -1)
        item_slot = you.equip[ EQ_WEAPON ];

    if (item_slot == -1)
    {
        canned_msg(MSG_NOTHING_HAPPENS);
        return (false);
    }

    item_def& wpn(you.inv[item_slot]);

    bool result = enchant_weapon(which_stat, quiet, wpn);

    you.wield_change = true;

    return result;
}

bool enchant_armour(int &ac_change, bool quiet, item_def &arm)
{
    ac_change = 0;

    // Cannot be enchanted nor uncursed.
    if (!is_enchantable_armour(arm, true))
    {
        if (!quiet)
            canned_msg( MSG_NOTHING_HAPPENS );

        return (false);
    }

    const bool is_cursed = arm.cursed();

    // Turn hides into mails where applicable.
    // NOTE: It is assumed that armour which changes in this way does
    // not change into a form of armour with a different evasion modifier.
    if (armour_is_hide(arm, false))
    {
        if (!quiet)
        {
            mprf("%s glows purple and changes!",
                 arm.name(DESC_CAP_YOUR).c_str());
        }

        ac_change = property(arm, PARM_AC);
        hide2armour(arm);
        ac_change = property(arm, PARM_AC) - ac_change;

        if (is_cursed)
            do_uncurse_item(arm);

        // No additional enchantment.
        return (true);
    }

    // Even if not affected, it may be uncursed.
    if (!is_enchantable_armour(arm, false)
        || arm.plus > MAX_SEC_ENCHANT
           && x_chance_in_y(arm.plus, MAX_ARM_ENCHANT))
    {
        if (is_cursed)
        {
            if (!quiet)
            {
                mprf("%s glows silver for a moment.",
                     arm.name(DESC_CAP_YOUR).c_str());
            }

            do_uncurse_item(arm);
            return (true);
        }
        else
        {
            if (!quiet)
                canned_msg(MSG_NOTHING_HAPPENS);

            // Xom thinks it's funny if enchantment is possible but fails.
            if (is_enchantable_armour(arm, false))
                xom_is_stimulated(32);

            return (false);
        }
    }

    // Output message before changing enchantment and curse status.
    if (!quiet)
    {
        mprf("%s glows green for a moment.",
             arm.name(DESC_CAP_YOUR).c_str());
    }

    arm.plus++;
    ac_change++;

    if (is_cursed)
        do_uncurse_item(arm);

    return (true);
}

static bool _handle_enchant_armour(int item_slot)
{
    do
    {
        if (item_slot == -1)
        {
            item_slot = prompt_invent_item("Enchant which item?", MT_INVLIST,
                                           OSEL_ENCH_ARM, true, true, false);
        }
        if (prompt_failed(item_slot))
            return (false);

        item_def& arm(you.inv[item_slot]);

        if (!is_enchantable_armour(arm, true, true))
        {
            mpr("Choose some type of armour to enchant, or Esc to abort.");
            if (Options.auto_list)
                more();

            item_slot = -1;
            continue;
        }

        // Okay, we may actually (attempt to) enchant something.
        int ac_change;
        bool result = enchant_armour(ac_change, false, arm);

        if (ac_change)
            you.redraw_armour_class = true;

        return (result);
    }
    while (true);

    return (false);
}

static void handle_read_book(int item_slot)
{
    item_def& book(you.inv[item_slot]);

    if (book.sub_type == BOOK_DESTRUCTION)
    {
        if (silenced(you.pos()))
            mpr("This book does not work if you cannot read it aloud!");
        else
            tome_of_power(item_slot);
        return;
    }
    else if (book.sub_type == BOOK_MANUAL)
    {
        skill_manual(item_slot);
        return;
    }

    while (true)
    {
        // Spellbook
        const int ltr = read_book( book, RBOOK_READ_SPELL );

        if (ltr < 'a' || ltr > 'h')     //jmf: was 'g', but 8=h
        {
            mesclr(true);
            return;
        }

        const spell_type spell = which_spell_in_book(book,
                                                     letter_to_index(ltr));
        if (spell == SPELL_NO_SPELL)
        {
            mesclr(true);
            return;
        }

        describe_spell(spell, &book);

        // Player memorised spell which was being looked at.
        if (you.turn_is_over)
            return;
    }
}

// For unidentified scrolls of recharging, identify and enchant armour
// offer full choice of inventory and only identify the scroll if you chose
// something that is affected by the scroll. Once they're identified, you'll
// get the limited inventory listing.
// Returns true if the scroll had an obvious effect and should be identified.
static bool _scroll_modify_item(item_def scroll)
{
    ASSERT(scroll.base_type == OBJ_SCROLLS);

    // Get the slot of the scroll just read.
    int item_slot = scroll.slot;

    // Get the slot of the item the scroll is to be used on.
    // Ban the scroll's own slot from the prompt to avoid the stupid situation
    // where you use identify on itself.
    item_slot = prompt_invent_item("Use on which item? (\\ to view known items)",
                                   MT_INVLIST, OSEL_ANY, true, true, false, 0,
                                   item_slot, NULL, OPER_ANY, true);

    if (prompt_failed(item_slot))
        return (false);

    item_def &item = you.inv[item_slot];

    switch (scroll.sub_type)
    {
    case SCR_IDENTIFY:
        if (!fully_identified(item))
        {
            mpr("This is a scroll of identify!");
            identify(-1, item_slot);
            return (true);
        }
        break;
    case SCR_RECHARGING:
        if (item_is_rechargeable(item, false, true))
        {
            // Might still fail on highly enchanted weapons of electrocution.
            // (If so, already prints the "Nothing happens" message.)
            if (recharge_wand(item_slot))
                return (true);
            return (false);
        }
        break;
    case SCR_ENCHANT_ARMOUR:
        if (is_enchantable_armour(item, true))
        {
            // Might still fail because of already high enchantment.
            // (If so, already prints the "Nothing happens" message.)
            if (_handle_enchant_armour(item_slot))
                return (true);
            return (false);
        }
        break;
    default:
        mprf("Buggy scroll %d can't modify item!", scroll.sub_type);
        break;
    }

    // Oops, wrong item...
    canned_msg(MSG_NOTHING_HAPPENS);
    return (false);
}

static void _vulnerability_scroll()
{
    // First cast antimagic on yourself.
    antimagic();

    // List of magical enchantments which will be dispelled.
    const enchant_type lost_enchantments[] = {
        ENCH_SLOW,
        ENCH_HASTE,
        ENCH_SWIFT,
        ENCH_MIGHT,
        ENCH_FEAR,
        ENCH_CONFUSION,
        ENCH_INVIS,
        ENCH_CORONA,
        ENCH_CHARM,
        ENCH_PARALYSIS,
        ENCH_PETRIFYING,
        ENCH_PETRIFIED
    };

    mon_enchant lowered_mr(ENCH_LOWERED_MR, 1, KC_YOU, 40);

    // Go over all creatures in LOS.
    for (radius_iterator ri(you.pos(), LOS_RADIUS); ri; ++ri)
    {
        if (monsters* mon = monster_at(*ri))
        {
            // Dispel all magical enchantments.
            for (unsigned int i = 0; i < ARRAYSZ(lost_enchantments); ++i)
                mon->del_ench(lost_enchantments[i], true, true);

            // If relevant, monsters have their MR halved.
            if (!mons_immune_magic(mon))
                mon->add_ench(lowered_mr);

            // Annoying but not enough to turn friendlies against you.
            if (!mon->wont_attack())
                behaviour_event(mon, ME_ANNOY, MHITYOU);
        }
    }

    you.set_duration(DUR_LOWERED_MR, 40, 0, "Magic dampens around you!");
}

void read_scroll(int slot)
{
    if (you.berserk())
    {
        canned_msg(MSG_TOO_BERSERK);
        return;
    }

    if (player_in_bat_form())
    {
        canned_msg(MSG_PRESENT_FORM);
        return;
    }

    if (inv_count() < 1)
    {
        canned_msg(MSG_NOTHING_CARRIED);
        return;
    }

    int item_slot = (slot != -1) ? slot
                                 : prompt_invent_item( "Read which item?",
                                                       MT_INVLIST,
                                                       OBJ_SCROLLS,
                                                       true, true, true, 0, -1,
                                                       NULL, OPER_READ );

    if (prompt_failed(item_slot))
        return;

    item_def& scroll = you.inv[item_slot];

    if (scroll.base_type != OBJ_BOOKS && scroll.base_type != OBJ_SCROLLS)
    {
        mpr("You can't read that!");
        crawl_state.zero_turns_taken();
        return;
    }

    // Here we try to read a book {dlb}:
    if (scroll.base_type == OBJ_BOOKS)
    {
        handle_read_book( item_slot );
        return;
    }

    if (silenced(you.pos()))
    {
        mpr("Magic scrolls do not work when you're silenced!");
        crawl_state.zero_turns_taken();
        return;
    }

    // Ok - now we FINALLY get to read a scroll !!! {dlb}
    you.turn_is_over = true;

    // Imperfect vision prevents players from reading actual content {dlb}:
    if (player_mutation_level(MUT_BLURRY_VISION)
        && x_chance_in_y(player_mutation_level(MUT_BLURRY_VISION), 5))
    {
        mpr((player_mutation_level(MUT_BLURRY_VISION) == 3 && one_chance_in(3))
                        ? "This scroll appears to be blank."
                        : "The writing blurs in front of your eyes.");
        return;
    }

    // Decrement and handle inventory if any scroll other than paper {dlb}:
    const scroll_type which_scroll = static_cast<scroll_type>(scroll.sub_type);
    const bool alreadyknown = item_type_known(scroll);

    if (alreadyknown
        && (which_scroll == SCR_BLINKING || which_scroll == SCR_TELEPORTATION)
        && scan_artefacts(ARTP_PREVENT_TELEPORTATION, false))
    {
        mpr("You cannot teleport right now.");
        return;
    }

    if (which_scroll != SCR_PAPER
        && (which_scroll != SCR_IMMOLATION || you.confused()))
    {
        mpr("As you read the scroll, it crumbles to dust.");
        // Actual removal of scroll done afterwards. -- bwr
    }

    const bool dangerous = player_in_a_dangerous_place();

    // Scrolls of paper are also exempted from this handling {dlb}:
    if (which_scroll != SCR_PAPER)
    {
        if (you.confused())
        {
            random_uselessness(item_slot);
            dec_inv_item_quantity(item_slot, 1);
            return;
        }

        if (!you.skills[SK_SPELLCASTING])
            exercise(SK_SPELLCASTING, (coinflip()? 2 : 1));
    }

    // It is the exception, not the rule, that the scroll will not
    // be identified. {dlb}
    bool id_the_scroll = true;  // to prevent unnecessary repetition
    bool tried_on_item = false; // used to modify item (?EA, ?RC, ?ID)

    bool bad_effect = false; // for Xom: result is bad (or at least dangerous)
    switch (which_scroll)
    {
    case SCR_PAPER:
        // Remember, paper scrolls handled as special case above, too.
        mpr("This scroll appears to be blank.");
        if (player_mutation_level(MUT_BLURRY_VISION) == 3)
            id_the_scroll = false;
        break;

    case SCR_RANDOM_USELESSNESS:
        random_uselessness(item_slot);
        break;

    case SCR_BLINKING:
        blink(1000, false);
        break;

    case SCR_TELEPORTATION:
        you_teleport();
        break;

    case SCR_REMOVE_CURSE:
        if (!remove_curse(false))
            id_the_scroll = false;
        break;

    case SCR_DETECT_CURSE:
        if (!detect_curse(false))
            id_the_scroll = false;
        break;

    case SCR_ACQUIREMENT:
        mpr("This is a scroll of acquirement!");
        more();
        acquirement(OBJ_RANDOM, AQ_SCROLL);
        break;

    case SCR_FEAR:
    {
        int fear_influenced = 0;
        mass_enchantment(ENCH_FEAR, 1000, MHITYOU, NULL, &fear_influenced);
        id_the_scroll = fear_influenced;
        break;
    }

    case SCR_NOISE:
        noisy(25, you.pos(), "You hear a loud clanging noise!");
        break;

    case SCR_SUMMONING:
    {
        const int monster = create_monster(
                                mgen_data(MONS_ABOMINATION_SMALL, BEH_FRIENDLY,
                                          &you, 0, 0, you.pos(), MHITYOU,
                                          MG_FORCE_BEH));
        if (monster != -1)
        {
            mpr("A horrible Thing appears!");
            player_angers_monster(&menv[monster]);
        }
        else
        {
            canned_msg(MSG_NOTHING_HAPPENS);
            id_the_scroll = false;
        }
        break;
    }

    case SCR_FOG:
        mpr("The scroll dissolves into smoke.");
        big_cloud(random_smoke_type(), KC_YOU, you.pos(), 50, 8 + random2(8));
        break;

    case SCR_MAGIC_MAPPING:
        if (you.level_type == LEVEL_PANDEMONIUM)
        {
            if (!item_type_known(scroll))
                mpr("You feel momentarily disoriented.");
            else
                mpr("Your Earth magic cannot map Pandemonium.");
        }
        else
            magic_mapping(50, 90 + random2(11), false);
        break;

    case SCR_TORMENT:
        torment(TORMENT_SCROLL, you.pos());

        // This is only naughty if you know you're doing it.
        did_god_conduct(DID_NECROMANCY, 10, item_type_known(scroll));
        bad_effect = true;
        break;

    case SCR_IMMOLATION:
        mpr("The scroll explodes in your hands!");

        // Doesn't destroy scrolls anymore, so no special check needed. (jpeg)
        immolation(10, IMMOLATION_SCROLL, you.pos(), alreadyknown, &you);
        bad_effect = true;
        more();
        break;

    case SCR_CURSE_WEAPON:
        if (!you.weapon()
            || you.weapon()->base_type != OBJ_WEAPONS
            || you.weapon()->cursed())
        {
            canned_msg(MSG_NOTHING_HAPPENS);
            id_the_scroll = false;
        }
        else
        {
            // Also sets wield_change.
            do_curse_item( *you.weapon(), false );
            learned_something_new(TUT_YOU_CURSED);
            bad_effect = true;
        }
        break;

    // Everything [in the switch] below this line is a nightmare {dlb}:
    case SCR_ENCHANT_WEAPON_I:
        id_the_scroll = _handle_enchant_weapon(ENCHANT_TO_HIT);
        break;

    case SCR_ENCHANT_WEAPON_II:
        id_the_scroll = _handle_enchant_weapon(ENCHANT_TO_DAM);
        break;

    case SCR_ENCHANT_WEAPON_III:
        if (you.weapon())
        {
            item_def& wpn = *you.weapon();

            const bool is_cursed = wpn.cursed();

            if (wpn.base_type != OBJ_WEAPONS && wpn.base_type != OBJ_MISSILES
                || !is_cursed
                   && !is_enchantable_weapon(wpn, true, true)
                   && !is_enchantable_weapon(wpn, true, false))
            {
                canned_msg(MSG_NOTHING_HAPPENS);
                id_the_scroll = false;
                break;
            }
            // It's a weapon or stack of missiles that is not an artefact
            // and not fully enchanted, or at least needs to be uncursed.

            // Get item name now before changing enchantment.
            std::string iname = wpn.name(DESC_CAP_YOUR);

            // Uncursing is always possible.
            bool success = is_cursed;
            if (_handle_enchant_weapon(ENCHANT_TO_HIT, true))
                success = true;

            if (is_enchantable_weapon(wpn, true, true) && coinflip()
                && _handle_enchant_weapon(ENCHANT_TO_HIT, true))
            {
                success = true;
            }

            // Only weapons use the second stat.
            if (wpn.base_type == OBJ_WEAPONS)
            {
                if (_handle_enchant_weapon(ENCHANT_TO_DAM, true))
                    success = true;

                if (is_enchantable_weapon(wpn, true, false) && coinflip()
                    && _handle_enchant_weapon(ENCHANT_TO_DAM, true))
                {
                    success = true;
                }
            }

            if (is_cursed)
                do_uncurse_item(wpn);

            if (success)
            {
                mprf("%s glow%s bright yellow for a while.", iname.c_str(),
                     wpn.quantity > 1 ? "" : "s");
            }
            else
            {
                canned_msg(MSG_NOTHING_HAPPENS);
                id_the_scroll = false;
            }
        }
        else
        {
            canned_msg(MSG_NOTHING_HAPPENS);
            id_the_scroll = false;
        }
        break;

    case SCR_VORPALISE_WEAPON:
        id_the_scroll = _vorpalise_weapon();
        if (!id_the_scroll)
            canned_msg(MSG_NOTHING_HAPPENS);
        break;

    case SCR_IDENTIFY:
        if (!item_type_known(scroll))
        {
            id_the_scroll = _scroll_modify_item(scroll);
            if (!id_the_scroll)
                tried_on_item = true;
        }
        else
            identify(-1);
        break;

    case SCR_RECHARGING:
        if (!item_type_known(scroll))
        {
            id_the_scroll = _scroll_modify_item(scroll);
            if (!id_the_scroll)
                tried_on_item = true;
        }
        else
            recharge_wand(-1);
        break;

    case SCR_ENCHANT_ARMOUR:
        if (!item_type_known(scroll))
        {
            id_the_scroll = _scroll_modify_item(scroll);
            if (!id_the_scroll)
                tried_on_item = true;
        }
        else
            _handle_enchant_armour(-1);
        break;

    case SCR_CURSE_ARMOUR:
    {
        // make sure there's something to curse first
        int count = 0;
        int affected = EQ_WEAPON;
        for (int i = EQ_CLOAK; i <= EQ_BODY_ARMOUR; i++)
        {
            if (you.equip[i] != -1 && !you.inv[you.equip[i]].cursed())
            {
                count++;
                if (one_chance_in(count))
                    affected = i;
            }
        }

        if (affected == EQ_WEAPON)
        {
            canned_msg(MSG_NOTHING_HAPPENS);
            id_the_scroll = false;
            break;
        }

        // Make the name before we curse it.
        do_curse_item( you.inv[you.equip[affected]], false );
        learned_something_new(TUT_YOU_CURSED);
        bad_effect = true;
        break;
    }

    case SCR_HOLY_WORD:
    {
        int pow = 100;

        if (is_good_god(you.religion))
        {
            pow += (you.religion == GOD_SHINING_ONE) ? you.piety :
                                                       you.piety / 2;
        }

        const bool success = holy_word(pow, HOLY_WORD_SCROLL, you.pos(),
                                       !item_type_known(scroll), &you);

        if (!success)
        {
            canned_msg(MSG_NOTHING_HAPPENS);
            id_the_scroll = false;
        }

        // This is only naughty if you know you're doing it, or if it's
        // succeeded, in which case you'll know for next time.
        if (item_type_known(scroll) || success)
            did_god_conduct(DID_HOLY, 10, item_type_known(scroll));
        break;
    }

    case SCR_SILENCE:
        cast_silence(25);
        break;

    case SCR_VULNERABILITY:
        _vulnerability_scroll();
        break;

    default:
        mpr("Read a buggy scroll, please report this.");
        break;
    }

    set_ident_type(scroll, id_the_scroll ? ID_KNOWN_TYPE :
                           tried_on_item ? ID_TRIED_ITEM_TYPE
                                         : ID_TRIED_TYPE);

    // Finally, destroy and identify the scroll.
    if (which_scroll != SCR_PAPER)
    {
        if (id_the_scroll)
            set_ident_flags(scroll, ISFLAG_KNOW_TYPE); // for notes

        dec_inv_item_quantity( item_slot, 1 );
    }

    if (!alreadyknown && dangerous)
    {
        // Xom loves it when you read an unknown scroll and there is a
        // dangerous monster nearby... (though not as much as potions
        // since there are no *really* bad scrolls, merely useless ones).
        xom_is_stimulated(bad_effect ? 128 : 64);
    }
}

void examine_object(void)
{
    int item_slot = prompt_invent_item( "Examine which item?",
                                        MT_INVLIST, -1,
                                        true, true, true, 0, -1, NULL,
                                        OPER_EXAMINE );
    if (prompt_failed(item_slot))
        return;

    describe_item( you.inv[item_slot], true );
    redraw_screen();
    mesclr(true);
}                               // end original_name()

void use_artefact(unsigned char item_wield_2, bool *show_msgs)
{
    use_artefact( you.inv[ item_wield_2 ], show_msgs );
}

void use_artefact(item_def &item, bool *show_msgs, bool unmeld)
{
#define unknown_proprt(prop) (proprt[(prop)] && !known[(prop)])

    ASSERT( is_artefact( item ) );

    // Call unrandart equip function first, so that it can modify the
    // artefact's properties before they're applied.
    if (is_unrandom_artefact( item ))
    {
        const unrandart_entry *entry = get_unrand_entry(item.special);

        if (entry->equip_func)
            entry->equip_func(&item, show_msgs, unmeld);

        if (entry->world_reacts_func)
        {
            equipment_type eq = get_item_slot(item.base_type, item.sub_type);
            you.unrand_reacts |= (1 << eq);
        }
    }

    const bool alreadyknown = item_type_known(item);
    const bool dangerous    = player_in_a_dangerous_place();

    artefact_properties_t  proprt;
    artefact_known_props_t known;
    artefact_wpn_properties( item, proprt, known );

    // Only give property messages for previously unknown properties.
    if (proprt[ARTP_AC])
    {
        you.redraw_armour_class = true;
        if (!known[ARTP_AC])
        {
            mprf("You feel %s.", proprt[ARTP_AC] > 0?
                 "well-protected" : "more vulnerable");
            artefact_wpn_learn_prop(item, ARTP_AC);
        }
    }

    if (proprt[ARTP_EVASION])
    {
        you.redraw_evasion = true;
        if (!known[ARTP_EVASION])
        {
            mprf("You feel somewhat %s.", proprt[ARTP_EVASION] > 0?
                 "nimbler" : "more awkward");
            artefact_wpn_learn_prop(item, ARTP_EVASION);
        }
    }

    if (proprt[ARTP_MAGICAL_POWER] && !known[ARTP_MAGICAL_POWER])
    {
        mprf("You feel your mana capacity %s.",
             proprt[ARTP_MAGICAL_POWER] > 0? "increase" : "decrease");
        artefact_wpn_learn_prop(item, ARTP_MAGICAL_POWER);
    }

    // Modify ability scores.
    // Output result even when identified (because of potential fatality).
    modify_stat( STAT_STRENGTH,     proprt[ARTP_STRENGTH],     false, item );
    modify_stat( STAT_INTELLIGENCE, proprt[ARTP_INTELLIGENCE], false, item );
    modify_stat( STAT_DEXTERITY,    proprt[ARTP_DEXTERITY],    false, item );

    const artefact_prop_type stat_props[3] =
        {ARTP_STRENGTH, ARTP_INTELLIGENCE, ARTP_DEXTERITY};

    for (int i = 0; i < 3; i++)
        if (unknown_proprt(stat_props[i]))
            artefact_wpn_learn_prop(item, stat_props[i]);

    // For evokable stuff, check whether other equipped items yield
    // the same ability.  If not, and if the ability granted hasn't
    // already been discovered, give a message.
    if (unknown_proprt(ARTP_LEVITATE)
        && !items_give_ability(item.link, ARTP_LEVITATE))
    {
        if (you.airborne())
            mpr("You feel vaguely more buoyant than before.");
        else
            mpr("You feel buoyant.");
        artefact_wpn_learn_prop(item, ARTP_LEVITATE);
    }

    if (unknown_proprt(ARTP_INVISIBLE) && !you.duration[DUR_INVIS])
    {
        mpr("You become transparent for a moment.");
        artefact_wpn_learn_prop(item, ARTP_INVISIBLE);
    }

    if (unknown_proprt(ARTP_BERSERK)
        && !items_give_ability(item.link, ARTP_BERSERK))
    {
        mpr("You feel a brief urge to hack something to bits.");
        artefact_wpn_learn_prop(item, ARTP_BERSERK);
    }

    if (!unmeld && !item.cursed() && proprt[ARTP_CURSED] > 0
         && one_chance_in(proprt[ARTP_CURSED]))
    {
        do_curse_item( item, false );
        artefact_wpn_learn_prop(item, ARTP_CURSED);
    }

    if (proprt[ARTP_NOISES])
        you.attribute[ATTR_NOISES] = 1;

    if (!alreadyknown && Options.autoinscribe_artefacts)
        add_autoinscription(item, artefact_auto_inscription(item));

    if (!alreadyknown && dangerous)
    {
        // Xom loves it when you use an unknown random artefact and
        // there is a dangerous monster nearby...
        xom_is_stimulated(128);
    }

    // Let's try this here instead of up there.
    if (proprt[ARTP_MAGICAL_POWER])
        calc_mp();
#undef unknown_proprt
}

bool wearing_slot(int inv_slot)
{
    for (int i = EQ_CLOAK; i <= EQ_AMULET; ++i)
        if (inv_slot == you.equip[i])
            return (true);

    return (false);
}

bool item_blocks_teleport(bool permit_id)
{
    return (scan_artefacts(ARTP_PREVENT_TELEPORTATION)
            || stasis_blocks_effect(permit_id, NULL));
}

bool stasis_blocks_effect(bool identify,
                          const char *msg, int noise,
                          const char *silenced_msg)
{
    if (wearing_amulet(AMU_STASIS))
    {
        item_def *amulet = you.slot_item(EQ_AMULET);

        if (msg)
        {
            const std::string name(amulet? amulet->name(DESC_CAP_YOUR) :
                                   "Something");
            const std::string message =
                make_stringf(msg, name.c_str());

            if (noise)
            {
                if (!noisy(noise, you.pos(), message.c_str())
                    && silenced_msg)
                {
                    mprf(silenced_msg, name.c_str());
                }
            }
            else
            {
                mpr(message.c_str());
            }
        }

        // In all cases, the amulet auto-ids if requested.
        if (amulet && identify)
            set_ident_type(*amulet, ID_KNOWN_TYPE);
        return (true);
    }
    return (false);
}

#ifdef USE_TILE
// Interactive menu for item drop/use.

void tile_item_use_floor(int idx)
{
    if (mitm[idx].base_type == OBJ_CORPSES
        && mitm[idx].sub_type != CORPSE_SKELETON
        && !food_is_rotten(mitm[idx]))
    {
        butchery(idx);
    }
}

void tile_item_pickup(int idx)
{
    pickup_single_item(idx, mitm[idx].quantity);
}

void tile_item_drop(int idx)
{
    drop_item(idx, you.inv[idx].quantity);
}

void tile_item_eat_floor(int idx)
{
    if (mitm[idx].base_type == OBJ_CORPSES
            && you.species == SP_VAMPIRE
        || mitm[idx].base_type == OBJ_FOOD
            && you.is_undead != US_UNDEAD && you.species != SP_VAMPIRE)
    {
        if (can_ingest(mitm[idx].base_type, mitm[idx].sub_type, false))
            eat_floor_item(idx);
    }
}

void tile_item_use_secondary(int idx)
{
    const item_def item = you.inv[idx];

    if (item.base_type == OBJ_WEAPONS && is_throwable(&you, item))
    {
        if (check_warning_inscriptions(item, OPER_FIRE))
            fire_thing(idx); // fire weapons
    }
    else if (you.equip[EQ_WEAPON] == idx)
    {
        wield_weapon(true, PROMPT_GOT_SPECIAL); // unwield
    }
    else if (_valid_weapon_swap(item))
    {
        // secondary wield for several spells and such
        wield_weapon(true, idx); // wield
    }
}

void tile_item_use(int idx)
{
    const item_def item = you.inv[idx];

    // Equipped?
    bool equipped = false;
    bool equipped_weapon = false;
    for (unsigned int i = 0; i < NUM_EQUIP; i++)
    {
        if (you.equip[i] == idx)
        {
            equipped = true;
            if (i == EQ_WEAPON)
                equipped_weapon = true;
            break;
        }
    }

    // Special case for folks who are wielding something
    // that they shouldn't be wielding.
    // Note that this is only a problem for equipables
    // (otherwise it would only waste a turn)
    if (you.equip[EQ_WEAPON] == idx
        && (item.base_type == OBJ_ARMOUR
            || item.base_type == OBJ_JEWELLERY))
    {
        wield_weapon(true, PROMPT_GOT_SPECIAL);
        return;
    }

    const int type = item.base_type;

    // Use it
    switch (type)
    {
        case OBJ_WEAPONS:
        case OBJ_STAVES:
        case OBJ_MISCELLANY:
        case OBJ_WANDS:
            // Wield any unwielded item of these types.
            if (!equipped
                && (type == OBJ_WEAPONS || type == OBJ_STAVES || is_deck(item)
                    || type == OBJ_MISCELLANY
                       && item.sub_type == MISC_LANTERN_OF_SHADOWS))
            {
                wield_weapon(true, idx);
                return;
            }
            // Evoke misc. items, rods, or wands.
            if (item_is_evokable(item))
            {
                evoke_item(idx);
                return;
            }
            // Unwield wielded items.
            if (equipped)
                wield_weapon(true, PROMPT_GOT_SPECIAL); // unwield
            return;

        case OBJ_MISSILES:
            if (check_warning_inscriptions(item, OPER_FIRE))
                fire_thing(idx);
            return;

        case OBJ_ARMOUR:
            if (player_in_bat_form())
            {
                mpr("You can't wear or remove anything in your present form.");
                return;
            }
            if (equipped && !equipped_weapon)
            {
                if (check_warning_inscriptions(item, OPER_TAKEOFF))
                    takeoff_armour(idx);
            }
            else if (check_warning_inscriptions(item, OPER_WEAR))
                wear_armour(idx);
            return;

        case OBJ_CORPSES:
            if (you.species != SP_VAMPIRE
                || item.sub_type == CORPSE_SKELETON
                || food_is_rotten(item))
            {
                break;
            }
            // intentional fall-through for Vampires
        case OBJ_FOOD:
            if (check_warning_inscriptions(item, OPER_EAT))
                eat_food(idx);
            return;

        case OBJ_BOOKS:
            if (item.sub_type == BOOK_MANUAL
                || item.sub_type == BOOK_DESTRUCTION
                || you.skills[SK_SPELLCASTING] == 0)
            {
                if (check_warning_inscriptions(item, OPER_READ))
                    handle_read_book(idx);
            } // else it's a spellbook
            else if (check_warning_inscriptions(item, OPER_MEMORISE))
                learn_spell(); // offers all spells, might not be what we want
            return;

        case OBJ_SCROLLS:
            if (check_warning_inscriptions(item, OPER_READ))
                read_scroll(idx);
            return;

        case OBJ_JEWELLERY:
            if (equipped && !equipped_weapon)
            {
                if (check_warning_inscriptions(item, OPER_REMOVE))
                    remove_ring(idx);
            }
            else if (check_warning_inscriptions(item, OPER_PUTON))
                puton_ring(idx);
            return;

        case OBJ_POTIONS:
            if (check_warning_inscriptions(item, OPER_QUAFF))
                drink(idx);
            return;

        default:
            return;
    }
}
#endif