summaryrefslogblamecommitdiff
path: root/src/map/atcommand.cpp
blob: 6901437a3c846ad50ad4dca8cfdf651171a2b31d (plain) (tree)
1
                        



















                                                                           
 

                

                    


                               


                                     
                                 
                                 



                                 
                            

                                
                             
                            


                          

                            
                                     
 
                                  
                                    
                                   
                                     
                         
                             
 




                                  

                         
                     
                          
                    
                   
                      


                     
                       

                  
                        
                    
                 
                    
                      
                  
                    
 

                        
 

              

             


               
               





          

                    
                 
                  
                                                                             
                 
 

                                                                                                               
      

  







                                              
                                                       


                                                   
                                                                             

                         
                                                                  

                         
                                                                  

                         
                                                                     




                                            
                               
 
                       
     
                                                                               


               
                                                                     



                                                                    
                                                                                                    





                                                
                               



                                 

 
 








































                                                                                            
      
                             
 

                                                         
 
                                      

               




                                                              

                                    
                                    



                                                                                                               
 
 
                            
 
                         
                       
 
                                   
 


                                         
 
                                                      

                                      
                                
                                 
 
                                                    
                                          
 
                   
                           
 
                                                             
 


                              
                                    
     
                            

 
                                                            
                                       
 
                           
 
                                 
                     
 



                                    



                                                       
                                                                                                              
                                  
                                       

                    


                                                        
     
                                                                  
                                  
                                       

                             
       
                                        
     
                                                                                          
                                   
                                  
                                       

                    
 
     
         
                                              
                        
             


                                             
                                               
                      


                                       
                             

                                                                                                    

                             
                                                                                                         

                             
                                                                               

                            
                                                                              


                        

             
 
                    
     

 
























                                                                      
                                                      
 
                            
     
                                          
                                                                     
                  
     
                

 
      
                                                         
 
                    
 
                                         
             
                                           
        
                       

 
      
                                                                      
 
                                       

 

                                                                       
 
                   
     
                                                                        
                         
         

                                
                                                                                       


                               
                 
                                                                                     


                               
         
                      
     
 
              

 




                                                       


                                  
                                                                    
 

                                               
                                                                                   

                                       
                    
             
                     
             
                                                       


      
                                                           



                        


                                                                                                      





                                          
                                                                                           
                                                                                
                                           


                          
                           
     
                                                                               

                                               
                                                                                                        
                                                    
                                      



                          





                                                                                 
                                







                                                        

                           
                            
                           



                                                                                                                                

                                           
                                                                                                    
                                                
                                                                               
                                      


                      
 
      
                                                               
                        
 
                  
                       
 
                                             
                           
            
 
                
                                              
                                              
 
                                                   
                                              
 
                  
                                             
                                      

                  
                                             
                                      

                  
                                       
                                      
 
                                                   
                                   
 
                      

 
        
                                                                  
                        
 

                       
                     
 
                                                        
                           

               
                                
               
                                
 

                                                              
     
                                                   

                                                        
                                                     
             

                                                                                                        
                                                                                   
                 
                                          
                                                                                     
                                      
                 
                                                          
                                                                                     
                 
                                          
                                                                                                 
                                      
                 
                                                                                  
                 

                                                                                             


                    
                                                               
                                       



                 
                                                                      
                                   



             
                                                                                                            
                              



         
                                                         
                           

     
                      

 
      
                                                              
                        
 
                     
                     
 

                                                                
     
                              
                                                                           
                           
     
 
               
                                
               
                                
 
                                             
     

                                                                                                
                                                                             
         
                                  
                                                                         
                              
         
                                               
                                                                             
         
                                  
                                                                                  
                              
         
                                                                       
                                                

            
                                                       
                               



         
                                                              
                           
     
 
                      

 
      
                                                               
                        
 

                                 
 
                                                                                            
                           
                                        
                                                      
                                                     

                                                
                                                        
                                       
                                                           
                                       


        
                                                         
                           
     
 
                      

 
      
                                                              
                        
 
                       
 
                                     
     
                              
                                                                                             
                           
     
 
                                                              
                                                                                                              
     
                                                    
                                                                             
         
                                  
                                                                                       
                              
         
                                               
                                                                             
         
                                  
                                                                                  
                              
         
                                                                                         
                                                                
                                       


        
                                                         
                           
     
 
                      

 
      






























































                                                                                                                
                                                              
                        
 
                     

                                          
 
               
                                
               
                                
                                             
     
                                                 
                                                                             
         
                                  
                                                                                
                              
         
                                               
                                                                             
         
                                  
                                                                                  
                              
         
                                                                  
                                                              
                                       


        
                                                              
                           
     
 
                            

 
      
                                                             
                        
 
              

                                       

              
                                   
                               
     
                                     
                
                     
                                                                                                                               
                                       
         
                                                 

                                               
                                                             
                                                      

                                                        
                                                                             
                                                         

                                                    
                                   
                                    
                                           

                                                                            
                                                                           
                        
                                           
                                                                    
                                                                        
                                                          
                                                   






                            
                                                     
                        
                                                    

        
                                                                   
                                       

     
                      

 
      
                                                                  
                        
 
              
 

                                       

              
                                   
                               
     
                                     
                
                     
                                                                                                                               
                                       
         
                                                 

                                               
                                                             
                                                        

                                                        
                                                                             
                                                         

                                                    

                                                                                                            
                                   
                                    
                                           

                                                                                                    
                                                   






                            
                                                     
                        
                                                    

        
                                                                   
                                       

     
                      

 
      
                                                                
                        
 
              
 

                                

                                    


                                                      

              
                                   
                               
     
                                     
                
                     
                                                                                                                               
                                       
         
                                                 

                                               
                                                             
                                                        

                                                        
                                          
                 
                                   
                                    
                                           
                                                                            
                                                                    
                                                                           
                        
                                           
                                                                    
                                                                        
                                                          
                                                   





                            
                                                                   
                                  
                                   
 
                      

 
      
                                                                     
                        
 
              
 

                         

                                    


                                                      

              
                                   
                               
     
                                     
                
                     
                                                                                                                               
                                       
         
                                                 

                                               
                                                             
                                                        

                                                        
                                          
                 

                                                                                                            
                                   
                                    

                                                                                                    
                        

                                                                                       
                                                   





                            
                   
                   
                                                                              
                        
                                                                             

        
                                                                                      
     
                                   
 
                      

 
      
                                                               
                        
 
              
 

                                       

              
                                   
                               
     
                                     
                
                     
                                                                                                                               
                                       
         

                                                 


                                                   
                                                                 
                                                            

                                                            
                                                                                 
                                                             

                                                        
                                       
                                           
                                                                            
                                                                    
                                                                           
                                                       
                                           
                                                                          
                                                         
                                                 
                                                         
                                                       

                                                                                                                
                                           

                                                               
                                                       







                                
                                                 
                        
                                                

        
                                                               
                                       

     
                      

 
      
                                                              
                
 
                                                          

                          
                                                                    
 
                      

 
      
                                                              
                
 

                                                                                            
                                                                         
     
                              
                                                                                       
                          
     
                                           
                                                                         
     
                              
                                                                                           
                          
     
 










                                                                          
                                                          
 
                      

 
      
                                                               
                        
 
                 
     
                                   
                                                                           

                                                               
                                       
                           
     
 
                                                                      



                                                           
                                   
                                         
                                                   


        
                                   
                                                                                 

                                                               
                                       
                           
     
 
                      

 
      
                                                                 
                
 
                               
     
                                                   
                           
     
 
                                                                                                       
     
                                                   
                           
     
 
                            
 
                            

 
      
                                                                
                        
 

                             
                             

                                                                     
                           


                      
                               
 
                          
                                                          
                                                 
 
                      

 
      
                                                              
                
 
                                             
     
                                         
                                                    


        
                                        
                                                   
     
                          
 
                      

 
      
                                                             
                
 
                                              
                                                     
 
                      

 
      
                                                              
                        
 
                       
 
                                     
                           
 
                                                              
                         
     
                                                   

                                                    
                                                            
                                                          


            
                                                                                                            
                              



         
                                                         
                           
     
 
                      

 
      
                                                               
                
 

                                      
                    

                                                                        

                                  
                             
                                                                     
 
                      

 
      
                                                          
                        
 
                 
                           
 
                             
 
                      

 
      
                                                              
                        
 
                       
 
                                            
 






                                               

                                                                                           
                                                   

                                                                                 
                                   

                                                                                           
                                                   

                                                                                 

                                   
 

                              
                                                                                                             


                           
                            
                               
                                                          
            
                                                               


        
                                                                               
                           
     
 
                      

 
      















                                                                         
                                                              
                        
 
                      
                   
                     
 
                                                               
     
                              
                                                                                                
                           
     
 


                    

                                                                                                
                                           
 

                           



                                                 




                                               
                             
                                      
                            
                                                             
                                    
                                                          
         
                                                  
     
 
                      

 
      
                                                                   
                
 
                                 

                                          
                                                           
                                                                 
     
                                                                     
 
                      

 
      
                                                                  
                
 
                     
 
                      

 
      
                                                                     
                        
 
                 
 
                                            
     
                              
                                                                                          
                           




                                                                 
         
                                                                        



                                                                                                                 



                                                                            


                                               
                                                              
                                                          
                               
                                                       




                                       
                                                                       
                               
         

                                                                                        



                                              



                                                         
                                                   

                                                  
                                       

                                               
                                                              
                                                        

     
                      
 
 
                                                  
                                              
      
                                                                    
                        
 
                             
 
                                            
                           
 
                   




                                             
                                                                       
                               
         

                                                                          

                                                    

                                              
                                        
                                              
                                                              
                               
                                                      




                                      
                                                                      
                               
         

                                                                    

                                             

                                              

                                       


                                            
                                                  

                                                   
                                                              
                                                       

     
                      

 
      
                                                                
                
 
                              

                                                           
                                                                           
                           
     
 
                                         
     
                                            
                                   
         
                                         
                    
                         
                                                                                                                                   
                                           
             
                                            
                 
                                              
                                        


                 
                                              


        
                                                        
                           
     
 
                      

 

                                                     
      












                                                                                   
                                                                                  




                                   



































                                                                                    


                                                            


                                                                           




                                   
                                                               
                
 
                              

                                                           
                                                                           
                           
     
 
                                                                                 
     
                                            
                                   
         
                                         
                    
                         
                                                                                                                                   
                                           
             
                                                                 
                 
                                                                
                                                                                            


                                           


                 
                                             


        
                                                       
                           
     
 
                      

 
      
                                                               
                        
 
                                                        
 
                                                                                  
                           
 



                                                                         
         


                                                                
                                                            


         
                           
 
                      

 
      
                                                             
                        
 
                        
 
                                        
                           
 

                                                                         
         
                                                                
                                                            


         
                           
 
                      

 
      
                                                                    
                        
 
                       
 
                                       
                           
 

                                                                     
         
                                                      
                                                            


         
                           
 
                      

 
      
                                                                    
                        
 
                       
 
                                       
                           
 

                                                                     
         
                                                            
                                                            


         
                           
 
                      

 
      




                                                                 













                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                                                                                                       



































































                                                                                                                                                                                                                                                                                                                                          
                                                                                                                                                                                  










































































                                                                                              
                                                               
                        
 
                    
                   


                     
                      
 
                                                                     
                           

                                                    
                                                          
                                                                         
                                                                     
 
                            
                           
 



                                                                                                                                                         


                                                                 

                              
                                                                  
                                               

              
                             

                                                     
                                    
     


                             

                                                                       
                       
                                                                    


                       
                                                                   

                       
                                                                                           
         
                           



                            
                                                              

            
                                                                     
                           
                                           


         
                                                                
                           

     
                      

 
      
                                                                         
                                        
 

                         

                                    


                                                      
 




                                                                 
 
                                                     

 
      
                                                                     
                        
 
                                                 
 
                      

 
      
                                                           
 
                    
 
                                            
                                              
                                

 
      
                                                                     
                
 
                                                
                                                              



                                       
 
                      

 
      
                                                                      
                        
 
                                                 
 
                      

 
      
                                                             
                
 
          
 

                             
                                   
                                                                 
                                                            




                                                                   
                                       
     
 
                      

 
      
                                                               
                        
 

                         
 
                                                     
                           
 
                                       
 
                      

 
      
                                                                     
                        
 
                                
 
                                                
                           
 
                                                       

                                                                   
                                  

                                                                    

                             
                                                    
     
                                                   
                                               
                                                                     

        
                           
 
                      

 
      
                                                                    
                        
 
                               
 
                                                
                           
 
                                                     

                                                                  
                                 

                                                                   

                            
                                                  
     
                                                 
                                              
                                                                    

        
                           
 
                      

 
      
                                                              
                        
 
                       
 
                                              
                           
 
                                      

                                                             
                            

                                                            




                                    
                                        
                                                             

        
                           
 
                      

 
                   
                                                               
                        
 
                             
 
                                 
                      
                           
 
                                               

                                                                                                      
                                                

                                                                                  

                      
                                            
     


                                                 
                                                              
                                                  

        
                           
 
                      

 
      
                                                                   
                        
 
                                    
 
                                 



                                            
                           
     
                                                   

                                                                                                          
                                                    

                                                                                      

                          
                                                
         


                                                     
                                                                  


                    
 

                                      
                                                       
        
                           
 
                      

 
      
                                                                
                        
 
                       
 
                                     
                           
 
                                                              
                         
     
                                                   

                                                      
                                                     
                                                                                 
             
                                      
                                                                                         
                                  
             
                                                      
                                                                                 
             
                                      
                                                                                             
                                  
             
                                                                                     
                                                                      
                                           


            
                                                                                                            
                              



         
                                                         
                           

     
                      

 
      
                                                                
                        
 
                       
 
                                     
                           
 
                                                              
                         

                                                
                           

                                                                            

                                         
                                    
                                                       


        
                                                         
                           
     
 
                      

 
      
                                                                      
                        
 
                       
 
                                     
                           
 
                                                              
                         
     
                       
                                                                      
                                       
                                                                            
                                       
                                                                                         
                                       
                                                            
                                       
                                                                   
                                       
                                                            
                                       
                                                                   
                                       
                                                                            
                                       
                                                                            
                                       
                                                                            
                                       
                                                                            
                                       
                                                                            
                                       
                                                                            
                                       
                                                                
                                       


        
                                                         
                           

     















































































































                                                                                                                                                   
                                                




                                           
                                                                                                                        
                                         

                                                             






                                                                                                     













                                                                                                                           

 
      
                                                                          
                
 
              
 
              
                               
     
                                     
                
                     
                                                                                                                               
                                       
         
                            

                                                                     
                
                                
 
                           
                               
                                                                                                    
                                                                     
                                            

                                                            
                                           
                                                                                                             







                                                   
                                           
                                                 


                    
 
                   
                                                     
                        
                                                    

        
                                                                   
                                       
     
 
                      

 
      
                                                                          
                        
 

              
              

                                                          
                           
 
                                                              
                         
     
                                                   

                                                                


                                        
 
                                     
                                                                     
                                                                     


            
                                                                                                            
                              



         
                                                         
                           

     
                      

 
      
                                                                         
                        
 
                       

                      
 



                                                                                             
                           

        
     


















                                                                                                 
                              
                                                                                   
     
 
                      

 
      
                                                                    
                        
 
                       
 
                                     
                           
 
     
                                                                                      
                          
                                                                                   
     
 
                      

 
      
                                                                  
                        
 

                        
 

                                            
                           
 
     
                                                                            
                        
                                                                                   

     
                      

 
      
                                                                      
                        
 
                       
 
                                     
                           
 

                                                      
                                                                                      
                            
                                                                                   
     
 
                      

 
      
                                                                    
                        
 
                       
 
                                     
                           
 

                                                      
                                                                                      
                          
                                                                                   
     
 
                      

 
      
                                                                        
                        
 

                       
                     
 

                                                       
                           
 
                                                              
                         
     
                                                   

                                                                       
                                                                    
             
                                                           
                                   

               
             
                                                  
                                                                                     
                 
                                          
                                                                                       
                                      
                 
                                                       
                                                                               



             
                                                                                                            
                              



         
                                                         
                           

     
                      

 
      
                                                              
                
 
                               
     
                                     
                
                     
                                                                                                                               
                                              
                                           
                                                      

                                                       
                                                            
                                                                                          

         
                                                    
 
                      

 
      
                                                                 
                
 
                               
     
                                     
                
                     
                                                                                                                               
                                              
                                                                      
                                                      

                                                       
                                                            
                                                                                          

         
                                                    
 
                      

 
      
                                                       
 
                                              


                                          
                        

                                      
                                 
                                                                 
     

 
      
                                                            
                
 
                               
     
                                     
                
                     
                                                                                                                               
                                   
     
                                                        
 
                      

 
      
                                                                  
                
 
                               
     
                                     
                
                     
                                                                                                                               
                 
                                                            
                                       
     
                                                        
 
                      

 
        
                                                                             
                        
 
                       
                     
 
                                            
                      
                           
 
                                                              
                         
     
                                                   

                                                                    


                                                                            
                 
                                                                                            



                                                                                                                            






                                                                


                                                          
                                                                         
                                                                           
                                          
                                                                           




                                                  
                                                                                           
                                       
                 

                                                                                                   



                                                         



                                                                    
                                                              

                                                          

                                                  


                                                          
                                                                         
                                                                            
             
                                                                            
                                                                 


            
                                                                                                            
                              



         
                                                         
                           

     
                      

 
      
                                                                            
                        
 
                       
                                  
 
                                            
                      
                           
 
                                                              
                         
     
                                                   


                                                                   




                                                         
                                                                                           
                                       



                                                                

                                                         
                                                   
                                                         
                                                                         
                                          
                                                                          




                                                 
                                                                                          
                                       



                                                        

                                                         

                                                  


                                                       
                                                             

                                                           
                                                                         
                                                                           



             
                                                                                                            
                              



         
                                                         
                           

     
                      

 
      
                                                              
                        
 
                       
 
                                     
                           
 
                                                              
                         
     
                                                   
                                                       
                                       

            
                                                                                                            
                              



         
                                                         
                           
     
 
                      

 
      
                                                                 
                
 
                               
     
                                     
                
                     
                                                                                                                               
                 
                                                                           

                                                       
                                                                          
                                           

         
 
                                                              
 
                      

 
      
                                                                    
                        
 
                     
 
                                     
                           
 
                                                                      
     
                                            
         
                                                 
             
                                             
                                                                        


                
                                                                               
                                   



             
                                                                                                
                               



         
                                                                     
                           
     
 
                      

 
      
                                                                     
                        
 

                       
 
                                                
                           
 
                                                                      
     
                                            
         
                                                                      
                                 
             
                                                        
                 
                                                    
                                                                                   


                    
                                                                                          
                                       



                 
                                                                 
                                   



             
                                                                                                
                               



         
                                                                     
                           

     
                      
 
 
      
                                                                   
                        
 
                     
 
                                     
                           
 
                                                          
     
                                            
         
                                                

                                                  
                                                                    
                                        
                                                                          


                
                                                                             
                                   



             
                                                                                                
                               



         
                                                                     
                           
     
 
                      

 
      
                                                                    
                        
 

                       
 
                                                
                           
 
                                                          
     
                                            
         
                                                                      
                                 
             
                                                       

                                                         
                                                                           
                                               
                                                                                     


                    
                                                                                           
                                       



                 
                                                                 
                                   



             
                                                                                                
                               



         
                                                                     
                           

     
                      

 
      
                                                              
                        
 
                    
 
                                            
                           
 
                            
 
                      

 
      
                                                                
                
 
                               
     
                                     
                
                     
                                                                                                                               
                                       
         
                                                                          
                                           

         
                            
 
                
 
                      

 
      
                                                               
                        
 
                       
              
 
                                                    
                           
 
                                                                                          
                                   
              
                                                                                   
     
                                                                          
                                               

                    
                                                                       
                                           

         
                                                            
                                   
 
                      

 
      
                                                                     
                        
 
                       
 
                                     
                           
 
                                                              
                         
     
                                                   

                                                                     
                                 
                                       
                                                                 
                                           


            
                                                                                                            
                              



         
                                                         
                           
     
 
                      

 
        
                                                                     
                        
 
                       
 
                                     
                           
 
                                                              
                         
     
                                                   

                                                                     
                                 
                                       
                                                     
                               
                                           


            
                                                                                                            
                              



         
                                                         
                           
     
 
                      

 
      
                                                                   
                        
 
                       
 
                                     
                           
 
                                                              
                         
     
                                                   

                                                                        

                                 
                                                                           
                                                 
                                                                         
                                            
                                       
                                                                           
                                           


            
                                                                                                            
                              



         
                                                         
                           
     
 
                      

 
      
                                                                   
                        
 
                       
 
                                     
                           
 
                                                              
                         
     
                                                   

                                                                        



                                         


                                                      



                                        


                                                     


                                    
                                               

                              
                                         


                                                   

                                                                  
                                                                            



                                   
                      
                                                 
                                        
                                                 
                                        

                                     
                                                                     

                                 
                                                                           
                                                 
                                                                         
                                            
 
                                                                     
                                           


            
                                                                                                            
                              



         
                                                         
                           

     
                      

 
      
                                                                
                        
 

                                                             
 
                                                                             
                           
 
                                                              
                         




                                                                             
             


                                                                       
                                                                


             
                               


        
                                                         
                           

     
                      

 
      
                                                                  
                        
 
                       

                        
 
                                            
                      
                           
 
                                                              
                         
     
                                                            

                                                                      
                                     

                                                                       
                                
                                                         

                                                        
                                                     
                                                                                    

            
                               


        
                                                         
                           

     
                      

 
      
                                                                  
                        
 
                       

                         
 
                                            
                      
                           
 
                                                              
                         
     
                                                              

                                                                       
                                      

                                                                        
                                 
                                                           

                                                          
                                                      
                                                                                     

            
                               


        
                                                         
                           

     
                      

 
      
                                                               
                        
 
                       
                           
 
                                                         
                           
 
                                                              
                         

                                             

                                                                 
                                

                                                                



                                           
                                               
                                                                             

            
                               


        
                                                         
                           
     
 
                      

 
      
                                                                   
                
 
              
 
                                             
                                                                         
     
                              
                                                                                 
                          
     
 
              
                               
     
                                     
                
                     
                                                                                                                               
                 
                                
                                                                        
                                                      

                                                      
                                                      
                                                                                 

                        
                                                                                         

         
 
                                                         

              
                                   
                                                                                                                  
                       
                                       
     
 
                      

 
      
                                                                     
                        
 
                         
              
 
                                                      
                           
 
                                             
                                                                         
     
                              
                                                                                 
                          

     



                                                                                       
                     
     
                            
         

                                       
             



                                                                                                                                       
                                                                           



                                                                                
                                                                                         












                                                                                                                          

             
                           
         

                                                                                                  

         
                  
 
                      

 
      
                                                                 
                        
 
                                    
                     
                             
                 
 
                                                    
 

                             
 

                                
 
                                                                                    
 

                                                             
                                   
                                                              
                                   
                                                             
                                   

                                                                 

                                                                           
                                   
                                            
                                                                         
                                   
                                           
                                                                        
                                   
                                         
                                                                      
                                   
                                         
                                                                      
                                   
                                             
                                                                          
                                   
                                                     
                                                                                  
                                   






                                                              
                                                                   
                                       
             
                                             
                        
                             
                                                                                                                                       
                                              
                                                   
                 
                                       
                                                                              
                                                                                  
                                                   



                  
                                                                
                                               
             
                                  

                                            

                                
                                
                                              
                              
                                 
                                                   
                              
                                
                                             
                              
                                 
                                                   
                              
                                
                                              
                              
                                 
                                                   
                              
                                
                                             
                              
                                 
                                                   
                              
     
                           
                                              
                              
      
                            
                                                

                              
                                   
                                                                                         

                                                                           
                                               

                  

                                                 
                                  
                                                                                                   
                               

     
                      

 
      
                                                                  
                        
 
                         
 
                                       
                           
 



                                                                                       
                     
     
                            
         











                                                                                             
         
                           
         

                                                                                                  

         
                  
 
                      

 
      
                                                                     






































                                                                                                  






































                                                                                                       
                                                                
                        
 
                    
 
                                                
                           
 
                                        
     
                               
                                                 


        
                                                            
                           
     
 
                      

 
      
                                                                 
                        
 
                    
 
                                                
                           
 
                                        
     
                               
                                                  


        
                                                            
                           
     
 
                      

 
      
                                                                 
                
 

                                   
                                                           
                                 
 
                      

 
      
                                                                     
                        
 
                       
                      
                      
              
 
                                                                        
                           
 

                                                                                                
                                           
 
     
                                                                  
                             
         
                                                       

                                                        

                                                                          

                              
                                                                      
                     
                                                               
                                

                                                                            
                     
                                               
                                                              
                                   
                                                             
 
                                        
                                                                                             
                        
                                                                                                                            
                                                   


                    
                                                                                  
                                       



                 
                                                                                                                
                                  



             
                                                             
                               

         
 
                      

 
      
                                                                  
                        
 
                 
                           
 
                                                                            
                            
 
                      

 
      
                                                                       
                        
 
                 
                           
 
                                                                            
 
                                  
 
                      

 
      
                                                               
                        
 

                              
 
                                                                  
                           
 
                                    
     
                                                                                                    
                           
     
                                      
     
                                                                                   
                           
     
                                        
     
                                                                     
                           
     
                                       
     
                                                                                      
                           


        
                                                                              
                                                                                        
     
 
                      

 
      
                                                                
                        
 
                           
 
                                                     
                           

                  
                                           
                                                             


        
                                   
         
                                         
                    
                         
                                                                                                                                   
                                                                        
             
                                                      
                                                                               


             
 
                      

 
      
                                                                             
                        
 
                       
                       
 
                                     
                           
 
                                                              
                         
     
                                                   

                                                          

                        
                                         
             



                                                                                                                       




                                                                          
                                                   
                                                                       
                                                        
                                                       
                     


                                                                  
                     
                                                    
                                                       
                                                            
                                                     
                                                             
                                                      
                                                         
                                                                                    
                                                         
                                                                                    
                                                        
                                                                                                     
                                                         
                                                      
                                                   
                                                      
                                                              
                                                                                           
                                                         
                                                                                          
                                                       
                                                                                                         
                                                             
                                                                                            
                                                       
                                                                                                           
                                                             
                                                                                                                       
                                                                 
                                            
                                             

                        
                                             
 
                                   
                             
                                                                   
                                                                  
                                                

                                                                  
                                                   
 
                                 


                           
                                                                          

                
                                           
                                                                       
                                        
                                               



             
                                                                                                            
                              



         
                                                         
                           

     
                      

 
      
                                                                                
                        
 
                       
                       
 
                                     
                           
 
                                                              
                         
     
                                                   

                                                          
                                                                                      
                                
             
                                       
                 


                                                 
                     



                                                                                                                      
                         










                                                                                       
                                                                        
                                                                 
                                                        
                                                                  
                                                           
                         








                                                                                  
                                                       

                     
                                   
                 

                                                                            

                 
                          


            
                                                                                                            
                              



         
                                                         
                           

     
                      

 
      
                                                             
                
 

                                    
                          
 

                                 
                                                                

                                 
                                                                 
     
 


                                                    
                                                      
                      

 
      













                                                              

                                                          




                      
                                                             
                        
 
                      
                     
                                    
 
                                             
                           
 
                                
                      
                           
 
                             
                     

                 
                     
                             
 
                      

 
      
                                                                 
                        
 

                    
 
                                                         
                           
 
                                                                                
                                            





                               

                     




                             

                           
 
                                                             
                                   
 
                      

 
      
                                                                    
                        
 
                    
                 
 
                                         
                           
 
                                                           
                                                                                                              
                           
 
                                       
                                                         
 
                      
 
 
      
                                                                
                
 
                                 


                                           

                                                       
                                                               

         
                      
 
 
      
                                                                  
                        
 
                       
 
                                     
                           
                                                              
                         
                           
                                 


                                              

                                                          
                                                                     

         
 

                                                                    
 
                      
 
 
      
                                                                  
                
 
                                

                       
                                        
         

                           
                                                                     


                                  
                                      
                                                                   
                                   

         
                                 


                                           

                                                       
                                                                      

         
                             
 
                                           
                      
 
 
      
                                                                      
                        
 
                       
 
                                     
                           
                                                              
                         
                           
 
                                        
     

                                                                
                              

                                                                  
                          
     
                                 


                                              

                                                          
                                                                         

         
                                
 
                                    
                                                                        
                                    

                                                               
 
                                           
 
                      
 
 
      
                                                             
                
 
                  
                
                                                       
                           
 
                                         
                                     
                      
 
 
      
                                                             
                
 
                  
                
                                                       
                           
 
                                         
                                     
                      

 
      
                                                               
                
 
                  
                
                                                         
                           
 
                                           
                                     
                      

 
      
                                                            
                
 
                  
                
                                                      
                           
 
                                        
                                     
 
                      

 
      
                                                               
                
 
                  
                
                                                         
                           
 
                                           
                                     
                      
 
 
      
                                                                
                        
 
                   
                
 
                                                      
     
                                                                       
                           

     
                                                              
     
                                   
         
                               
                                                                
                              
         
                      
     
 
                                                    



                       
                                                               
                        
 
                   
                  
 
                                         
     
                                                                   
                           

     
                                                         
                         
                           
 
                                                          

                                                          
 
                      

 
      
                                                              
                        
 
                       
 
                                     
                           


                                                              
     
                                             
                                
     
                       

 

                              

                        
 





                                 




                                                                        
      
                                            
 





                  
  
 
      
                                                                 
                        
 
                       
 
                                     
                           
 

                                                              
     
                                
                                                           
                           
                                    
 
                                                    
         
                                         
                            
                                   

                                               
                                           
                                            
         
 
                          
     
 
                                                     
                       

 
      
                                                                   
 

                                             
                                   

 
      
                                                                
                        
 

                       
              
 
                                                          
     
                              
                                                                                                                                         
                           
     
 
                                            
                              
                                    

        
                                                    
         
                                                   
             
                                              



                      
 
                                         
     
                              
                                                                                                                       
                           

     
                                                              
                         
     


                                            
            
                                                 
 
                                   
                          
     
 
                                                     
                       
 
 
      

































































                                                                                       








                                                              


























                                                                                       
                                                         
                
 
                      
                                       

 
      
                                                            
                        
 
                              
                      
 
 
      
                                                                  
                
 
                           
                      

 
      
                                                                
                
 
                           
                      

 
      
                                                                      

                                                                           
 
                                     
 
                                               
 
              
                                
 
               
                            
 
                                                    
     



                                                                                  
                                
                   
                                













                                                                                    
     
 
                                                
                                                                         
     
                              
                                                                                   
                          
     
                                           
                                                                         
     
                              
                                                                              
                          
     
                                                                                        
                                                                         
                                   
 
                                    
 
                            

 
      
                                                                                               
 
                                                                                      

 
      
                                                                                                 
 
                                                                                     
 
 
      
                                                             
                        
 
                                       
                          
 
                                                                              
                     
                                                  
 
                      
 
 
 
      
                                                                     
                        
 
                       
 
                                     
                           
 
                                                              
                         
     
                                            

                                                            
 
                                
                                                         
                                                                  
                                    

                                            
                                                       
                                               
                                   
                                                        
                                        
         
 

                                                                
                                    
 
                                                      
         
                                                                   
                                                                   
 

                    
                                                         
                                                         
                                            

             
 

        
     
                                                         

                           
 
                      

 
      
                                                                      
                        
 

                       
 
                                             
     
                                                                            
                           
     
 
                                                              
                         
     
                                              
                                                           
            
                                                               

        
                                                         
 
                      

 
      
                                                                        
                        
 

                       
 
                                             
                           
 
                                                              
                         
     
                                                
                                                             
            
                                                                 

        
                                                         
 
                      

 
        
                                                                  
                        
 


                       
 
                                                     
                           
 
                                                              
                         
     

                                       

        
                                                         
 
                      
 
 
      
                                                              
                        
 
                       
 
                                     
                           
 
                                                              
                         
     
                                                         
                           

     
                                    



                                                            
                               
     
                                     
                
                     
                                                                                                    
                                       
         
                                                        
                                      
             
                                           
                                                            
                                                                
                                                  
                                               



             
                                            
                      
 
 
      
                                                                  
                
 
                               
     
                                     
                
                     
                                                                                                                               
                                              
                                                                      
                                                                 
                                                      

                                                       
                                                            
                                                                                          

         
                                                    
 


                      



                                                             



                                                



                      




                                            
                                                      
                          

                                        
                            

                                                                                   
                               

                                                         
                           

                                           
                            

                                                       
                           
                                                 


                                     
                            
                           

                                         
                          

                                                               
                               

                                                            
                             

                                                              
                                  

                                                           
                            

                                                                             
                           

                                                              
                           

                                           
                           

                                           
                            

                            
                              

                                             
                             

                                             
                           

                                                                     
                          

                                             
                           

                                                   
                            

                                       
                           

                                          
                           

                                              
                           

                                           
                                

                                                                                   
                                

                                                                
                                  

                                
                                 
                                    
                       
                             
                                     

                                 
                                        





                                  

                           
                                          
                      
                            

                                           
                            
                                                   





                                                 
                                                      
                            

                                                 
                                  

                                             
                                   

                                           
                          

                                     
                             

                                    
                                  

                                        
                                 

                                         
                           

                                             
                                       

                                   
                                       

                                  
                                       

                                   
                                       

                                                                                       
                                       

                                    
                                       

                                 
                             

                                   
                             

                                              



                                                        

                                                        
                                          

                                                           
                                       

                                                    
                                     

                                                 
                           

                                          
                              

                                        
                            

                                                  
                               

                                                
                                          

                                               
                                         

                                                   
                           

                                                       
                              

                                                          
                                 

                                                    
                                     

                                                    
                                

                                                     
                                    

                                                                 
                            
                                 


                                                                 


                                                       
                        
                              

                                            
                               

                                                     
                           

                                       
                                

                                            
                                     

                                                   
                                

                                                           
                                  

                                            
                                  

                                           
                                

                                                                   
                                

                                                    
                                  

                                                   
                                  

                                                  
                               

                                            
                              

                                                                                   
                          

                            
                          

                                 
                                 

                                    
                                 

                                     
                                
                                                     
                                              
                                      
                                                          
                                
                                 

                                                                   
                                   

                                                               
                               

                                                                        
                                 

                                                           
                               

                                                
                                  

                                                 
                                

                                           
                                 

                                            
                                

                                                                
                                  

                                                     
                                  

                                                
                           

                                           
                             

                                                                     
                                          

                                          
                                             

                                         
                              
                                          


                                   
                                          
                              
                                              


                                                    
                                          
                                 

                                                       
                              

                                      
                                  

                                                        
                               

                                       
                                   

                                            
                           

                                      
                           

                                      
                             

                                        
                          

                                     
                             
                                        
                                           
                               
                                                          
                                           
                                
                                                           
                                
                            

                                                    
                                

                                                    
                                
                                      





                                                            
                                    
                                 

                                            
                          

                                                  
                          

                                                  
                          

                                                             
                          

                                                             
                                

                                                 
                              

                                               
                                                   

                                      
                                                     

                                          
                                     

                                              
                                      

                                                
                                        

                                                         
                                  

                                   
                         

                                           
                              

                                                  
                               

                                                
                            
                                                                               
  
                  
                   
#include "atcommand.hpp"
//    atcommand.cpp - GM commands.
//
//    Copyright © ????-2004 Athena Dev Teams
//    Copyright © 2004-2011 The Mana World Development Team
//    Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
//
//    This file is part of The Mana World (Athena server)
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include <ctime>

#include <algorithm>

#include "../compat/nullpo.hpp"
#include "../compat/fun.hpp"

#include "script-call-internal.hpp"
#include "../generic/intern-pool.hpp"

#include "../strings/mstring.hpp"
#include "../strings/astring.hpp"
#include "../strings/zstring.hpp"
#include "../strings/xstring.hpp"
#include "../strings/vstring.hpp"

#include "../generic/db.hpp"
#include "../generic/random.hpp"

#include "../io/cxxstdio.hpp"
#include "../io/extract.hpp"
#include "../io/read.hpp"
#include "../io/write.hpp"

#include "../net/socket.hpp"
#include "../net/timer.hpp"
#include "../net/timestamp-utils.hpp"

#include "../mmo/config_parse.hpp"
#include "../mmo/cxxstdio_enums.hpp"
#include "../mmo/extract_enums.hpp"
#include "../mmo/human_time_diff.hpp"
#include "../mmo/ids.hpp"
#include "../mmo/version.hpp"

#include "../high/core.hpp"
#include "../high/extract_mmo.hpp"
#include "../high/mmo.hpp"
#include "../high/utils.hpp"

#include "../ast/npc.hpp"

#include "battle.hpp"
#include "battle_conf.hpp"
#include "chrif.hpp"
#include "clif.hpp"
#include "globals.hpp"
#include "intif.hpp"
#include "itemdb.hpp"
#include "map.hpp"
#include "map_conf.hpp"
#include "mob.hpp"
#include "npc.hpp"
#include "npc-parse.hpp"
#include "party.hpp"
#include "pc.hpp"
#include "skill.hpp"
#include "storage.hpp"
#include "tmw.hpp"
#include "trade.hpp"

#include "../poison.hpp"


namespace tmwa
{
namespace map
{
enum class ATCE
{
    OKAY,
    OKAY_NOLOG,
    USAGE,
    EXIST,
    RANGE,
    PERM,
};

struct AtCommandInfo
{
    ZString args;
    GmLevel level;
    ATCE (*proc)(Session *s, dumb_ptr<map_session_data> sd, ZString message);
    ZString help;

    AtCommandInfo(ZString a, uint32_t l, ATCE (*p)(Session *s, dumb_ptr<map_session_data>, ZString), ZString h)
    : args(a), level(GmLevel::from(l)), proc(p), help(h)
    {}
};


// TODO What we really want is an ArrayMap ...
// This is defined at the end of the file.
extern
Map<XString, AtCommandInfo> atcommand_info;


static
Option<Borrowed<AtCommandInfo>> atcommand(XString cmd);

// These @commands are used within other @commands.
static
ATCE atcommand_character_baselevel(Session *s, dumb_ptr<map_session_data> sd,
        ZString message);
static
ATCE atcommand_skill_learn(Session *s, dumb_ptr<map_session_data>,
        ZString message);
static
ATCE atcommand_charwarp(Session *s, dumb_ptr<map_session_data> sd,
        ZString message);
static
ATCE atcommand_charstreset(Session *s, dumb_ptr<map_session_data> sd,
        ZString message);


void atcommand_config_write(ZString cfgName)
{
    io::WriteFile out(cfgName);

    if (!out.is_open())
    {
        FPRINTF(stderr, "Failed to write atcommand config: %s\n"_fmt, cfgName);
        return;
    }

    FPRINTF(out, "// Generated by %s\n"_fmt, CURRENT_VERSION_STRING);
    for (const auto& pair : atcommand_info)
    {
        // This XString is really a ZString, but not declared as one
        // in order to allow non-heterogenous lookup by XString.
        auto cmd = ZString(strings::really_construct_from_a_pointer, &*pair.first.begin(), nullptr);
        const AtCommandInfo& info = pair.second;

        FPRINTF(out,
                "\n"
                "// %s\n"
                "// Usage: @%s %s\n"
                "%s: %d\n"_fmt,
                info.help,
                cmd, info.args,
                cmd, info.level);
    }
}


// If your last arg is not a ZString, you probably wanted extract()
// but not always ...
static
bool asplit(ZString raw, ZString *last)
{
    *last = raw;
    return true;
}

// but this case is just so common and useful. In fact, is the previous ever used otherwise?
static
bool asplit(ZString raw, CharName *last)
{
    if (raw.size() < 4 || raw.size() > 23)
        return false;
    *last = stringish<CharName>(raw);
    return true;
}

// huh.
static
bool asplit(ZString raw, NpcName *last)
{
    if (!raw || raw.size() > 23)
        return false;
    *last = stringish<NpcName>(raw);
    return true;
}

// This differs from extract() in that it does not consume extra spaces.
template<class F, class... R, typename=typename std::enable_if<sizeof...(R) != 0>::type>
bool asplit(ZString raw, F *first_arg, R *... rest_args)
{
    ZString::iterator it = std::find(raw.begin(), raw.end(), ' ');
    XString frist = raw.xislice_h(it);
    while (*it == ' ')
        ++it;
    ZString rest = raw.xislice_t(it);
    return extract(frist, first_arg) && asplit(rest, rest_args...);
}

static
io::AppendFile *get_gm_log();

static
void real_log_atcommand(TimerData *, tick_t, AString cmd)
{
    io::AppendFile *fp = get_gm_log();
    if (!fp)
        return;
    FPRINTF(*fp, "%s\n"_fmt, cmd);
}

void log_atcommand(dumb_ptr<map_session_data> sd, ZString cmd)
{
    timestamp_seconds_buffer tmpstr;
    stamp_time(tmpstr);
    MapName map = (sd->bl_m->name_);
    AString str = STRPRINTF("[%s] %s(%d,%d) %s(%d) : %s"_fmt, tmpstr,
                  map, sd->bl_x, sd->bl_y, sd->status_key.name,
                  sd->status_key.account_id, cmd);
    Timer(gettick() + battle_config.gm_log_delay, std::bind(real_log_atcommand, ph::_1, ph::_2, str)).detach();
}

io::AppendFile *get_gm_log()
{
    if (!map_conf.gm_log)
        return nullptr;

    struct tm ctime = TimeT::now();

    int year = ctime.tm_year + 1900;
    int month = ctime.tm_mon + 1;
    int logfile_nr = (year * 12) + month;

    static std::unique_ptr<io::AppendFile> gm_logfile;
    static int last_logfile_nr = 0;
    if (logfile_nr == last_logfile_nr)
        return gm_logfile.get();
    last_logfile_nr = logfile_nr;

    AString fullname = STRPRINTF("%s.%04d-%02d"_fmt,
            map_conf.gm_log, year, month);

    if (gm_logfile)
        gm_logfile.reset();

    gm_logfile = make_unique<io::AppendFile>(fullname, true);

    if (!gm_logfile)
    {
        perror("GM log file");
        map_conf.gm_log = AString();
    }
    return gm_logfile.get();
}

bool is_atcommand(Session *s, dumb_ptr<map_session_data> sd,
        ZString message, GmLevel gmlvl)
{
    nullpo_retr(false, sd);

    if (!message.startswith('@'))
        return false;

    XString command;
    ZString arg;
    asplit(message, &command, &arg);

    if (!gmlvl)
        gmlvl = pc_isGM(sd);
    if (battle_config.atcommand_gm_only != 0 && !gmlvl)
    {
        AString output = STRPRINTF("GM command is level 0, but this server disables level 0 commands: %s"_fmt,
                AString(command));
        clif_displaymessage(s, output);
        return true;
    }

    Option<P<AtCommandInfo>> info_ = atcommand(command);
    P<AtCommandInfo> info = TRY_UNWRAP(info_,
    {
        AString output = STRPRINTF("GM command not found: %s"_fmt,
                AString(command));
        clif_displaymessage(s, output);
        return true;
        // don't show in chat
    });
    if (!(gmlvl.satisfies(info->level)))
    {
        AString output = STRPRINTF("GM command is level %d, but you are level %d: %s"_fmt,
                info->level, gmlvl,
                AString(command));
        clif_displaymessage(s, output);
        return true;
    }

    {
        {
            ATCE err = info->proc(s, sd, arg);
            switch (err)
            {
            case ATCE::OKAY:
                // Don't log level 0 commands
                if (info->level)
                    log_atcommand(sd, message);
                break;
            case ATCE::OKAY_NOLOG:
                // explicitly don't log
                break;
            case ATCE::USAGE:
                clif_displaymessage(s, "Command failed: usage error"_s);
                clif_displaymessage(s, STRPRINTF("Usage: %s %s"_fmt, AString(command), info->args));
                break;
            case ATCE::EXIST:
                clif_displaymessage(s, "Command failed: something does not exist (or already exists)"_s);
                break;
            case ATCE::RANGE:
                clif_displaymessage(s, "Command failed: value out of range"_s);
                break;
            case ATCE::PERM:
                clif_displaymessage(s, "Command failed: permission denied"_s);
                break;
            default:
                abort();
            }
        }

        return true;
    }
}

bool can_use_atcommand(dumb_ptr<map_session_data> sd, ZString message)
{
    nullpo_retr(false, sd);

    if (!message.startswith('@'))
        return false;

    XString command;
    ZString arg;
    asplit(message, &command, &arg);

    GmLevel gmlvl = pc_isGM(sd);

    if (battle_config.atcommand_gm_only != 0 && !gmlvl)
        return false; // level 0 commands are disabled

    Option<P<AtCommandInfo>> info_ = atcommand(command);
    P<AtCommandInfo> info = TRY_UNWRAP(info_,
    {
        return false; // command not found
    });

    return gmlvl.satisfies(info->level);
}

Option<Borrowed<AtCommandInfo>> atcommand(XString cmd)
{
    if (cmd.startswith('@'))
    {
        XString command = cmd.xslice_t(1);
        Option<P<AtCommandInfo>> it = atcommand_info.search(command);
        return it;
    }
    return None;
}

static
void atkillmonster_sub(dumb_ptr<block_list> bl, int flag)
{
    nullpo_retv(bl);

    dumb_ptr<mob_data> md = bl->is_mob();
    if (flag)
        mob_damage(nullptr, md, md->hp, 2);
    else
        mob_delete(md);
}

static
Option<Borrowed<AtCommandInfo>> get_atcommandinfo_byname(XString name)
{
    return atcommand_info.search(name);
}

static
bool atcommand_config(io::Spanned<XString> w1, io::Spanned<ZString> w2)
{
    bool rv = true;
    {
        Option<P<AtCommandInfo>> p_ = get_atcommandinfo_byname(w1.data);
        OMATCH_BEGIN (p_)
        {
            OMATCH_CASE_SOME (p)
            {
                p->level = GmLevel::from(static_cast<uint32_t>(atoi(w2.data.c_str())));
            }
            OMATCH_CASE_NONE ()
            {
                {
                    w1.span.error("Unknown @command for permission level config."_s);
                    rv = false;
                }
            }
        }
        OMATCH_END ();
    }

    return rv;
}

bool atcommand_config_read(ZString cfgName)
{
    return load_config_file(cfgName, atcommand_config);
}

/// @ command processing functions

static
void atc_do_help(Session *s, ZString cmd, const AtCommandInfo& info)
{
    // TODO convert to hex or something
    uint32_t level = info.level.get_all_bits();
    auto msg = STRPRINTF("\u2007\u2007%d: @%s %s"_fmt, info.level, cmd, info.args);
    // manually padding because *space*
    size_t ll = 1;
    if (level >= 10)
        ++ll;
    if (level >= 100)
        ++ll;
    clif_displaymessage(s, msg.xslice_t((ll - 1) * 3));
}

static
ATCE atcommand_help(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    if (!message)
    {
        clif_displaymessage(s, "There is too much help to display it all at once"_s);
        clif_displaymessage(s, "Try @help <@command> or @help <category> or @help <level[-level]>"_s);
        clif_displaymessage(s, "Right now the only category is 'all'"_s);
        return ATCE::OKAY;
    }

    if (message.startswith('@'))
    {
        ZString cmd = message.xslice_t(1);
        P<AtCommandInfo> info = TRY_UNWRAP(atcommand_info.search(cmd), return ATCE::EXIST);
        clif_displaymessage(s, STRPRINTF("Usage: @%s %s"_fmt, cmd, info->args));
        clif_displaymessage(s, info->help);
        return ATCE::OKAY;
    }

    if (message == "all"_s)
    {
        clif_displaymessage(s, "Synopses of GM commands in category 'all':"_s);
        for (const auto& pair : atcommand_info)
        {
            auto cmd = ZString(strings::really_construct_from_a_pointer, &*pair.first.begin(), nullptr);
            const AtCommandInfo& info = pair.second;
            atc_do_help(s, cmd, info);
        }
        return ATCE::OKAY;
    }

    // previous logic is silly
    //
    // @help N: list all commands available at level N
    // @help M-N: list all commands available at level N that were not at level M
    GmLevel low, high;
    bool pass;
    if (extract(message, &high))
    {
        pass = true;
    }
    else if (extract(message, record<'-'>(&low, &high)))
    {
        pass = false;
    }
    else
        return ATCE::USAGE;

    if (low.obsoletes(high))
        return ATCE::RANGE;
    if (pass)
        clif_displaymessage(s, STRPRINTF("Synopses of GM commands available at level %u:"_fmt, high));
    else
        clif_displaymessage(s, STRPRINTF("Synopses of GM commands available at level %u, but not at level %u:"_fmt, high, low));
    for (const auto& pair : atcommand_info)
    {
        auto cmd = ZString(strings::really_construct_from_a_pointer, &*pair.first.begin(), nullptr);
        const AtCommandInfo& info = pair.second;
        if ((!low.satisfies(info.level) || pass) && high.satisfies(info.level))
            atc_do_help(s, cmd, info);
    }
    return ATCE::OKAY;
}

static
ATCE atcommand_setup(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    int level = 1;
    CharName character;

    if (!asplit(message, &level, &character))
        return ATCE::USAGE;
    level--;

    AString buf;
    buf = STRPRINTF("-255 %s"_fmt, character);
    atcommand_character_baselevel(s, sd, buf);

    buf = STRPRINTF("%d %s"_fmt, level, character);
    atcommand_character_baselevel(s, sd, buf);

    // Emote skill
    buf = STRPRINTF("1 1 %s"_fmt, character);
    atcommand_skill_learn(s, sd, buf);

    // Trade skill
    buf = STRPRINTF("2 1 %s"_fmt, character);
    atcommand_skill_learn(s, sd, buf);

    // Party skill
    STRPRINTF("2 2 %s"_fmt, character);
    atcommand_skill_learn(s, sd, buf);

    STRPRINTF("018-1.gat 24 98 %s"_fmt, character);
    atcommand_charwarp(s, sd, buf);

    return ATCE::OKAY;
}

//static
ATCE atcommand_charwarp(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    MapName map_name;
    CharName character;
    int x = 0, y = 0;

    if (!asplit(message, &map_name, &x, &y, &character))
        return ATCE::USAGE;

    if (x <= 0)
        x = random_::in(1, 399);
    if (y <= 0)
        y = random_::in(1, 399);

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd)
    {
        if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd)))
        {
            // you can rura+ only lower or same GM level
            if (x > 0 && x < 800 && y > 0 && y < 800)
            {
                Option<P<map_local>> m = map_mapname2mapid(map_name);
                if (m.map([](P<map_local> m_){ return m_->flag.get(MapFlag::NOWARPTO); }).copy_or(false)
                    && !pc_isGM(sd).satisfies(battle_config.any_warp_GM_min_level))
                {
                    clif_displaymessage(s,
                            "You are not authorised to warp someone to this map."_s);
                    return ATCE::PERM;
                }
                if (pl_sd->bl_m->flag.get(MapFlag::NOWARP)
                    && !(pc_isGM(sd).satisfies(battle_config.any_warp_GM_min_level)))
                {
                    clif_displaymessage(s,
                            "You are not authorised to warp this player from its actual map."_s);
                    return ATCE::PERM;
                }
                if (pc_setpos(pl_sd, map_name, x, y, BeingRemoveWhy::WARPED) == 0)
                {
                    clif_displaymessage(pl_sd->sess, "Warped."_s);
                    clif_displaymessage(s, "Player warped (message sends to player too)."_s);
                }
                else
                {
                    clif_displaymessage(s, "Map not found."_s);
                    return ATCE::EXIST;
                }
            }
            else
            {
                clif_displaymessage(s, "Coordinates out of range."_s);
                return ATCE::RANGE;
            }
        }
        else
        {
            clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s);
            return ATCE::PERM;
        }
    }
    else
    {
        clif_displaymessage(s, "Character not found."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_warp(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    MapName map_name;
    int x = 0, y = 0;

    if (!message
        || !extract(message, record<' ', 1>(&map_name, &x, &y)))
    {
        clif_displaymessage(s,
                "Please, enter a map (usage: @warp <mapname> <x> <y>)."_s);
        return ATCE::USAGE;
    }

    if (x <= 0)
        x = random_::in(1, 399);
    if (y <= 0)
        y = random_::in(1, 399);

    if (x > 0 && x < 800 && y > 0 && y < 800)
    {
        Option<P<map_local>> m = map_mapname2mapid(map_name);
        if (m.map([](P<map_local> m_){ return m_->flag.get(MapFlag::NOWARPTO); }).copy_or(false)
            && !(pc_isGM(sd).satisfies(battle_config.any_warp_GM_min_level)))
        {
            clif_displaymessage(s,
                    "You are not authorised to warp you to this map."_s);
            return ATCE::PERM;
        }
        if (sd->bl_m->flag.get(MapFlag::NOWARP)
            && !(pc_isGM(sd).satisfies(battle_config.any_warp_GM_min_level)))
        {
            clif_displaymessage(s,
                    "You are not authorised to warp you from your actual map."_s);
            return ATCE::PERM;
        }
        if (pc_setpos(sd, map_name, x, y, BeingRemoveWhy::WARPED) == 0)
            clif_displaymessage(s, "Warped."_s);
        else
        {
            clif_displaymessage(s, "Map not found."_s);
            return ATCE::EXIST;
        }
    }
    else
    {
        clif_displaymessage(s, "Coordinates out of range."_s);
        return ATCE::RANGE;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_where(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    CharName character;
    extract(message, &character);

    dumb_ptr<map_session_data> pl_sd = character.to__actual() ? map_nick2sd(character) : sd;
    if (pl_sd != nullptr &&
        !((battle_config.hide_GM_session
           || bool(pl_sd->status.option & Opt0::HIDE))
          && !(pc_isGM(sd).detects(pc_isGM(pl_sd)))))
    {
        // you can look only lower or same level
        AString output = STRPRINTF("%s: %s (%d,%d)"_fmt,
                pl_sd->status_key.name,
                pl_sd->mapname_, pl_sd->bl_x, pl_sd->bl_y);
        clif_displaymessage(s, output);
    }
    else
    {
        clif_displaymessage(s, "Character not found."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_goto(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    CharName character;

    if (!asplit(message, &character))
    {
        clif_displaymessage(s,
                "Please, enter a player name (usage: @jumpto/@warpto/@goto <char name>)."_s);
        return ATCE::USAGE;
    }

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr && (!bool(pl_sd->status.option & Opt0::HIDE) || pc_isGM(sd).detects(pc_isGM(pl_sd))))
    {
        if (pl_sd->bl_m->flag.get(MapFlag::NOWARPTO)
            && !(pc_isGM(sd).satisfies(battle_config.any_warp_GM_min_level)))
        {
            clif_displaymessage(s,
                    "You are not authorised to warp you to the map of this player."_s);
            return ATCE::PERM;
        }
        if (sd->bl_m->flag.get(MapFlag::NOWARP)
            && !(pc_isGM(sd).satisfies(battle_config.any_warp_GM_min_level)))
        {
            clif_displaymessage(s,
                    "You are not authorised to warp you from your actual map."_s);
            return ATCE::PERM;
        }
        pc_setpos(sd, pl_sd->mapname_, pl_sd->bl_x, pl_sd->bl_y, BeingRemoveWhy::WARPED);
        AString output = STRPRINTF("Jump to %s"_fmt, character);
        clif_displaymessage(s, output);
    }
    else
    {
        clif_displaymessage(s, "Character not found."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_npc(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    NpcName npc;

    if (!asplit(message, &npc))
    {
        clif_displaymessage(s,
                "Please, enter a npc name (usage: @npc/@warptonpc/@gotonpc <npc>)."_s);
        return ATCE::USAGE;
    }

    dumb_ptr<npc_data> nd = npc_name2id(npc);
    if (nd != nullptr)
    {
        if (nd->bl_m->flag.get(MapFlag::NOWARPTO)
            && !(pc_isGM(sd).satisfies(battle_config.any_warp_GM_min_level)))
        {
            clif_displaymessage(s,
                    "You are not authorised to warp you to the map of this npc."_s);
            return ATCE::PERM;
        }
        if (sd->bl_m->flag.get(MapFlag::NOWARP)
            && !(pc_isGM(sd).satisfies(battle_config.any_warp_GM_min_level)))
        {
            clif_displaymessage(s,
                    "You are not authorised to warp you from your actual map."_s);
            return ATCE::PERM;
        }

        int x = nd->bl_x, y = nd->bl_y, x0 = (x >= 5)? (x - 5): 0, j = 0,
            y0 = (y >= 5)? (y - 5): 0, x1 = (x + 5), y1 = (y + 5), max;
        max = (y1 - y0 + 1) * (x1 - x0 + 1) * 3;
        P<map_local> m = TRY_UNWRAP(map_mapname2mapid(nd->bl_m->name_), return ATCE::OKAY);
        if (max > 1000)
            max = 1000;
        if (bool(map_getcell(m, x, y) & MapCell::UNWALKABLE)){
            do
            {
                x = random_::in(x0, x1);
                y = random_::in(y0, y1);
            }
            while (bool(map_getcell(m, x, y) & MapCell::UNWALKABLE)
                 && (++j) < max);
            if (j >= max)
            {
                return ATCE::OKAY;       // Since reference of the place which boils first went wrong, it stops.
            }
        }
        pc_setpos(sd, nd->bl_m->name_, x, y, BeingRemoveWhy::WARPED);
        AString output = STRPRINTF("Jump to %s"_fmt, npc);
        clif_displaymessage(s, output);
    }
    else
    {
        clif_displaymessage(s, "Npc not found."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_jump(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    int x = 0, y = 0;
    // may fail
    extract(message, record<' '>(&x, &y));

    if (x <= 0)
        x = random_::in(1, 399);
    if (y <= 0)
        y = random_::in(1, 399);
    if (x > 0 && x < 800 && y > 0 && y < 800)
    {
        if (sd->bl_m->flag.get(MapFlag::NOWARPTO)
            && !(pc_isGM(sd).satisfies(battle_config.any_warp_GM_min_level)))
        {
            clif_displaymessage(s,
                    "You are not authorised to warp you to your actual map."_s);
            return ATCE::PERM;
        }
        if (sd->bl_m->flag.get(MapFlag::NOWARP)
            && !(pc_isGM(sd).satisfies(battle_config.any_warp_GM_min_level)))
        {
            clif_displaymessage(s,
                    "You are not authorised to warp you from your actual map."_s);
            return ATCE::PERM;
        }
        pc_setpos(sd, sd->mapname_, x, y, BeingRemoveWhy::WARPED);
        AString output = STRPRINTF("Jump to %d %d"_fmt, x, y);
        clif_displaymessage(s, output);
    }
    else
    {
        clif_displaymessage(s, "Coordinates out of range."_s);
        return ATCE::RANGE;
    }

    return ATCE::OKAY_NOLOG;
}

static
ATCE atcommand_who(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    int count;
    VString<23> match_text = message;
    match_text = match_text.to_lower();

    count = 0;
    GmLevel gm_level = pc_isGM(sd);
    for (io::FD i : iter_fds())
    {
        Session *s2 = get_session(i);
        if (!s2)
            continue;
        dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get()));
        if (pl_sd && pl_sd->state.auth)
        {
            GmLevel pl_gm_level = pc_isGM(pl_sd);
            if (!
                ((battle_config.hide_GM_session
                  || bool(pl_sd->status.option & Opt0::HIDE))
                 && !(gm_level.detects(pl_gm_level))))
            {
                // you can look only lower or same level
                VString<23> player_name = pl_sd->status_key.name.to__lower();
                if (player_name.contains_seq(match_text))
                {
                    // search with no case sensitive
                    AString output;
                    if (pl_gm_level)
                        output = STRPRINTF(
                                "Name: %s (GM:%u) | Location: %s %d %d"_fmt,
                                pl_sd->status_key.name, pl_gm_level,
                                pl_sd->mapname_, pl_sd->bl_x, pl_sd->bl_y);
                    else
                        output = STRPRINTF(
                                "Name: %s | Location: %s %d %d"_fmt,
                                pl_sd->status_key.name, pl_sd->mapname_,
                                pl_sd->bl_x, pl_sd->bl_y);
                    clif_displaymessage(s, output);
                    count++;
                }
            }
        }
    }

    if (count == 0)
        clif_displaymessage(s, "No player found."_s);
    else if (count == 1)
        clif_displaymessage(s, "1 player found."_s);
    else
    {
        AString output = STRPRINTF("%d players found."_fmt, count);
        clif_displaymessage(s, output);
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_whogroup(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    int count;

    VString<23> match_text = message;
    match_text = match_text.to_lower();

    count = 0;
    GmLevel gm_level = pc_isGM(sd);
    for (io::FD i : iter_fds())
    {
        Session *s2 = get_session(i);
        if (!s2)
            continue;
        dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get()));
        if (pl_sd && pl_sd->state.auth)
        {
            GmLevel pl_gm_level = pc_isGM(pl_sd);
            if (!
                ((battle_config.hide_GM_session
                  || bool(pl_sd->status.option & Opt0::HIDE))
                 && (!(gm_level.detects(pl_gm_level)))))
            {
                // you can look only lower or same level
                VString<23> player_name = pl_sd->status_key.name.to__lower();
                if (player_name.contains_seq(match_text))
                {
                    // search with no case sensitive
                    Option<PartyPair> p_ = party_search(pl_sd->status.party_id);
                    PartyName temp0 = p_.pmd_pget(&PartyMost::name).move_or(stringish<PartyName>("None"_s));
                    AString output;
                    if (pl_gm_level)
                        output = STRPRINTF(
                                "Name: %s (GM:%d) | Party: '%s' (%i)"_fmt,
                                pl_sd->status_key.name, pl_gm_level, temp0, pl_sd->status.party_id);
                    clif_displaymessage(s, output);
                    count++;
                }
            }
        }
    }

    if (count == 0)
        clif_displaymessage(s, "No player found."_s);
    else if (count == 1)
        clif_displaymessage(s, "1 player found."_s);
    else
    {
        AString output = STRPRINTF("%d players found."_fmt, count);
        clif_displaymessage(s, output);
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_whomap(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    int count;

    Borrowed<map_local> map_id =
    ({
        MapName map_name;
        extract(message, &map_name);

        map_mapname2mapid(map_name).copy_or(sd->bl_m);
    });

    count = 0;
    GmLevel gm_level = pc_isGM(sd);
    for (io::FD i : iter_fds())
    {
        Session *s2 = get_session(i);
        if (!s2)
            continue;
        dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get()));
        if (pl_sd && pl_sd->state.auth)
        {
            GmLevel pl_gm_level = pc_isGM(pl_sd);
            if (!
                ((battle_config.hide_GM_session
                  || bool(pl_sd->status.option & Opt0::HIDE))
                 && (!(gm_level.detects(pl_gm_level)))))
            {
                // you can look only lower or same level
                if (pl_sd->bl_m == map_id)
                {
                    AString output;
                    if (pl_gm_level)
                        output = STRPRINTF(
                                "Name: %s (GM:%d) | Location: %s %d %d"_fmt,
                                pl_sd->status_key.name, pl_gm_level,
                                pl_sd->mapname_, pl_sd->bl_x, pl_sd->bl_y);
                    else
                        output = STRPRINTF(
                                "Name: %s | Location: %s %d %d"_fmt,
                                pl_sd->status_key.name, pl_sd->mapname_,
                                pl_sd->bl_x, pl_sd->bl_y);
                    clif_displaymessage(s, output);
                    count++;
                }
            }
        }
    }

    AString output = STRPRINTF("%d players found in map '%s'."_fmt,
            count, map_id->name_);
    clif_displaymessage(s, output);

    return ATCE::OKAY;
}

static
ATCE atcommand_whomapgroup(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    int count;

    P<map_local> map_id =
    ({
        MapName map_name;
        extract(message, &map_name);

        map_mapname2mapid(map_name).copy_or(sd->bl_m);
    });

    count = 0;
    GmLevel gm_level = pc_isGM(sd);
    for (io::FD i : iter_fds())
    {
        Session *s2 = get_session(i);
        if (!s2)
            continue;
        dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get()));
        if (pl_sd && pl_sd->state.auth)
        {
            GmLevel pl_gm_level = pc_isGM(pl_sd);
            if (!
                ((battle_config.hide_GM_session
                  || bool(pl_sd->status.option & Opt0::HIDE))
                 && (!(gm_level.detects(pl_gm_level)))))
            {
                // you can look only lower or same level
                if (pl_sd->bl_m == map_id)
                {
                    Option<PartyPair> p_ = party_search(pl_sd->status.party_id);
                    PartyName temp0 = p_.pmd_pget(&PartyMost::name).copy_or(stringish<PartyName>("None"_s));
                    AString output;
                    if (pl_gm_level)
                        output = STRPRINTF("Name: %s (GM:%d) | Party: '%s' (%i)"_fmt,
                                pl_sd->status_key.name, pl_gm_level, temp0, pl_sd->status.party_id);
                    else
                        output = STRPRINTF("Name: %s | Party: '%s' (%i)"_fmt,
                                pl_sd->status_key.name, temp0, pl_sd->status.party_id);
                    clif_displaymessage(s, output);
                    count++;
                }
            }
        }
    }

    AString output;
    if (count == 0)
        output = STRPRINTF("No player found in map '%s'."_fmt, map_id->name_);
    else if (count == 1)
        output = STRPRINTF("1 player found in map '%s'."_fmt, map_id->name_);
    else
    {
        output = STRPRINTF("%d players found in map '%s'."_fmt, count, map_id->name_);
    }
    clif_displaymessage(s, output);

    return ATCE::OKAY;
}

static
ATCE atcommand_whogm(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    int count;

    VString<23> match_text = message;
    match_text = match_text.to_lower();

    count = 0;
    GmLevel gm_level = pc_isGM(sd);
    for (io::FD i : iter_fds())
    {
        Session *s2 = get_session(i);
        if (!s2)
            continue;
        dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get()));
        if (pl_sd && pl_sd->state.auth)
        {
            GmLevel pl_gm_level = pc_isGM(pl_sd);
            if (pl_gm_level)
            {
                if (!
                    ((battle_config.hide_GM_session
                      || bool(pl_sd->status.option & Opt0::HIDE))
                     && (!(gm_level.detects(pl_gm_level)))))
                {
                    // you can look only lower or same level
                    VString<23> player_name = pl_sd->status_key.name.to__lower();
                    if (player_name.contains_seq(match_text))
                    {
                        // search with no case sensitive
                        AString output;
                        output = STRPRINTF(
                                "Name: %s (GM:%d) | Location: %s %d %d"_fmt,
                                pl_sd->status_key.name, pl_gm_level,
                                pl_sd->mapname_, pl_sd->bl_x, pl_sd->bl_y);
                        clif_displaymessage(s, output);
                        output = STRPRINTF(
                                "       BLvl: %d | Job: %s (Lvl: %d)"_fmt,
                                pl_sd->status.base_level,
                                "Novice/Human"_s,
                                pl_sd->status.job_level);
                        clif_displaymessage(s, output);
                        Option<PartyPair> p_ = party_search(pl_sd->status.party_id);
                        PartyName temp0 = p_.pmd_pget(&PartyMost::name).copy_or(stringish<PartyName>("None"_s));
                        output = STRPRINTF(
                                "       Party: '%s' (%i)"_fmt,
                                temp0, pl_sd->status.party_id);
                        clif_displaymessage(s, output);
                        count++;
                    }
                }
            }
        }
    }

    if (count == 0)
        clif_displaymessage(s, "No GM found."_s);
    else if (count == 1)
        clif_displaymessage(s, "1 GM found."_s);
    else
    {
        AString output = STRPRINTF("%d GMs found."_fmt, count);
        clif_displaymessage(s, output);
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_save(Session *s, dumb_ptr<map_session_data> sd,
        ZString)
{
    pc_setsavepoint(sd, sd->mapname_, sd->bl_x, sd->bl_y);
    pc_makesavestatus(sd);
    chrif_save(sd);
    clif_displaymessage(s, "Character data respawn point saved."_s);

    return ATCE::OKAY;
}

static
ATCE atcommand_load(Session *s, dumb_ptr<map_session_data> sd,
        ZString)
{
    Option<P<map_local>> m = map_mapname2mapid(sd->status.save_point.map_);
    if (m.map([](P<map_local> m_){ return m_->flag.get(MapFlag::NOWARPTO); }).copy_or(false)
        && !(pc_isGM(sd).satisfies(battle_config.any_warp_GM_min_level)))
    {
        clif_displaymessage(s,
                             "You are not authorised to warp you to your save map."_s);
        return ATCE::PERM;
    }
    if (sd->bl_m->flag.get(MapFlag::NOWARP)
        && !(pc_isGM(sd).satisfies(battle_config.any_warp_GM_min_level)))
    {
        clif_displaymessage(s,
                             "You are not authorised to warp you from your actual map."_s);
        return ATCE::PERM;
    }

    // TODO deduplicate with clif_parse_Restart and pc_make_savestatus
    if (sd->bl_m->flag.get(MapFlag::RESAVE))
    {
        pc_setpos(sd, sd->bl_m->resave.map_, sd->bl_m->resave.x,
                sd->bl_m->resave.y, BeingRemoveWhy::GONE);
    }
    else
    {
        pc_setpos(sd, sd->status.save_point.map_, sd->status.save_point.x,
                sd->status.save_point.y, BeingRemoveWhy::GONE);
    }
    clif_displaymessage(s, "Warping to respawn point."_s);

    return ATCE::OKAY;
}

static
ATCE atcommand_speed(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    if (!message)
    {
        AString output = STRPRINTF(
                "Please, enter a speed value (usage: @speed <%d-%d>)."_fmt,
                static_cast<uint32_t>(MIN_WALK_SPEED.count()),
                static_cast<uint32_t>(MAX_WALK_SPEED.count()));
        clif_displaymessage(s, output);
        return ATCE::USAGE;
    }

    interval_t speed = static_cast<interval_t>(atoi(message.c_str()));
    if (speed >= MIN_WALK_SPEED && speed <= MAX_WALK_SPEED)
    {
        sd->speed = speed;
        //sd->walktimer = x;
        //この文を追加 by れ
        clif_updatestatus(sd, SP::SPEED);
        clif_displaymessage(s, "Speed changed."_s);
    }
    else
    {
        AString output = STRPRINTF(
                "Please, enter a valid speed value (usage: @speed <%d-%d>)."_fmt,
                static_cast<uint32_t>(MIN_WALK_SPEED.count()),
                static_cast<uint32_t>(MAX_WALK_SPEED.count()));
        clif_displaymessage(s, output);
        return ATCE::RANGE;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_storage(Session *s, dumb_ptr<map_session_data> sd,
        ZString)
{
    if (sd->state.storage_open)
    {
        clif_displaymessage(s, "msg_table[250]"_s);
        return ATCE::EXIST;
    }

    if (account2storage2(sd->status_key.account_id).pmd_pget(&Storage::storage_status).copy_or(0) == 1)
    {
        clif_displaymessage(s, "msg_table[250]"_s);
        return ATCE::EXIST;
    }

    storage_storageopen(sd);

    return ATCE::OKAY_NOLOG;
}

static
ATCE atcommand_option(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    Opt1 param1 = Opt1::ZERO;
    Opt2 param2 = Opt2::ZERO;
    Opt0 param3 = Opt0::ZERO;

    if (!extract(message, record<',', 1>(&param1, &param2, &param3)))
        return ATCE::USAGE;

    sd->opt1 = param1;
    sd->opt2 = param2;
    sd->status.option = param3;

    clif_changeoption(sd);
    pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC);
    clif_displaymessage(s, "Options changed."_s);

    return ATCE::OKAY;
}

static
ATCE atcommand_hide(Session *s, dumb_ptr<map_session_data> sd,
        ZString)
{
    if (bool(sd->status.option & Opt0::HIDE))
    {
        sd->status.option &= ~Opt0::HIDE;
        clif_displaymessage(s, "Invisible: Off."_s);
    }
    else
    {
        sd->status.option |= Opt0::HIDE;
        clif_displaymessage(s, "Invisible: On."_s);
    }
    clif_changeoption(sd);

    return ATCE::OKAY;
}

static
ATCE atcommand_die(Session *s, dumb_ptr<map_session_data> sd,
        ZString)
{
    pc_damage(nullptr, sd, sd->status.hp + 1);
    clif_displaymessage(s, "A pity! You've died."_s);

    return ATCE::OKAY;
}

static
ATCE atcommand_kill(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    CharName character;

    if (!asplit(message, &character))
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr)
    {
        if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd)))
        {
            // you can kill only lower or same level
            pc_damage(nullptr, pl_sd, pl_sd->status.hp + 1);
            clif_displaymessage(s, "Character killed."_s);
        }
        else
        {
            clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s);
            return ATCE::PERM;
        }
    }
    else
    {
        clif_displaymessage(s, "Character not found."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_alive(Session *s, dumb_ptr<map_session_data> sd,
        ZString)
{
    sd->status.hp = sd->status.max_hp;
    sd->status.sp = sd->status.max_sp;
    pc_setstand(sd);
    if (battle_config.player_invincible_time > interval_t::zero())
        pc_setinvincibletimer(sd, battle_config.player_invincible_time);
    clif_updatestatus(sd, SP::HP);
    clif_updatestatus(sd, SP::SP);
    clif_resurrection(sd, 1);
    clif_displaymessage(s, "You've been revived! It's a miracle!"_s);

    return ATCE::OKAY;
}

static
ATCE atcommand_kami(Session *, dumb_ptr<map_session_data>,
        ZString message)
{
    if (!message)
        return ATCE::USAGE;

    intif_GMmessage(message);

    return ATCE::OKAY;
}

static
ATCE atcommand_heal(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    int hp = 0, sp = 0;

    extract(message, record<' '>(&hp, &sp));

    if (hp == 0 && sp == 0)
    {
        hp = sd->status.max_hp - sd->status.hp;
        sp = sd->status.max_sp - sd->status.sp;
    }
    else
    {
        if (hp > 0 && (hp > sd->status.max_hp || hp > (sd->status.max_hp - sd->status.hp)))
            // fix positiv overflow
            hp = sd->status.max_hp - sd->status.hp;
        else if (hp < 0 && (hp < -sd->status.max_hp || hp < (1 - sd->status.hp)))
            // fix negativ overflow
            hp = 1 - sd->status.hp;
        if (sp > 0 && (sp > sd->status.max_sp || sp > (sd->status.max_sp - sd->status.sp)))
            // fix positiv overflow
            sp = sd->status.max_sp - sd->status.sp;
        else if (sp < 0 && (sp < -sd->status.max_sp || sp < (1 - sd->status.sp)))
            // fix negativ overflow
            sp = 1 - sd->status.sp;
    }

    if (hp < 0)
        // display like damage
        clif_damage(sd, sd, gettick(), interval_t::zero(), interval_t::zero(), -hp, 0, DamageType::RETURNED);

    if (hp != 0 || sp != 0)
    {
        pc_heal(sd, hp, sp);
        if (hp >= 0 && sp >= 0)
            clif_displaymessage(s, "HP, SP recovered."_s);
        else
            clif_displaymessage(s, "HP or/and SP modified."_s);
    }
    else
    {
        clif_displaymessage(s, "HP and SP are already with the good value."_s);
        return ATCE::RANGE;
    }

    return ATCE::OKAY;
}

static
Option<P<struct item_data>> extract_item_opt(XString item_name)
{
    Option<P<struct item_data>> item_data = itemdb_searchname(item_name);
    if (item_data.is_some())
        return item_data;

    ItemNameId item_id;
    if (extract(item_name, &item_id))
    {
        item_data = itemdb_exists(item_id);
        return item_data;
    }
    return None;
}

static
ATCE atcommand_item(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    XString item_name;
    int number = 0;
    int get_count, i;

    if (!extract(message, record<' ', 1>(&item_name, &number)))
    {
        clif_displaymessage(s,
                "Please, enter an item name/id (usage: @item <item name or ID> [quantity])."_s);
        return ATCE::USAGE;
    }

    if (number <= 0)
        number = 1;

    P<struct item_data> item_data = TRY_UNWRAP(extract_item_opt(item_name), return ATCE::EXIST);
    ItemNameId item_id = item_data->nameid;
    assert(item_id >= wrap<ItemNameId>(0));

    {
        get_count = number;
        if (item_data->type == ItemType::WEAPON
            || item_data->type == ItemType::ARMOR
            || item_data->type == ItemType::_7
            || item_data->type == ItemType::_8)
        {
            get_count = 1;
        }
        for (i = 0; i < number; i += get_count)
        {
            Item item_tmp {};
            item_tmp.nameid = item_id;
            PickupFail flag;
            if ((flag = pc_additem(sd, &item_tmp, get_count))
                != PickupFail::OKAY)
                clif_additem(sd, IOff0::from(0), 0, flag);
        }
        clif_displaymessage(s, "Item created."_s);
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_itemreset(Session *s, dumb_ptr<map_session_data> sd,
        ZString)
{
    for (IOff0 i : IOff0::iter())
    {
        if (sd->status.inventory[i].amount
            && sd->status.inventory[i].equip == EPOS::ZERO)
            pc_delitem(sd, i, sd->status.inventory[i].amount, 0);
    }
    clif_displaymessage(s, "All of your items have been removed."_s);

    return ATCE::OKAY;
}

static
ATCE atcommand_itemcheck(Session *, dumb_ptr<map_session_data> sd,
        ZString)
{
    pc_checkitem(sd);

    return ATCE::OKAY;
}

static
ATCE atcommand_baselevelup(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    int level, i;

    if (!extract(message, &level) || !level)
    {
        clif_displaymessage(s,
                "Please, enter a level adjustement (usage: @blvl <number of levels>)."_s);
        return ATCE::USAGE;
    }

    if (level > 0)
    {
        if (sd->status.base_level == battle_config.maximum_level)
        {
            clif_displaymessage(s, "Base level can't go any higher."_s);
            return ATCE::RANGE;
        }
        if (level > battle_config.maximum_level || level > (battle_config.maximum_level - sd->status.base_level))
            // fix positiv overflow
            level = battle_config.maximum_level - sd->status.base_level;
        for (i = 1; i <= level; i++)
            sd->status.status_point += (sd->status.base_level + i + 14) / 4;
        sd->status.base_level += level;
        clif_updatestatus(sd, SP::BASELEVEL);
        clif_updatestatus(sd, SP::NEXTBASEEXP);
        clif_updatestatus(sd, SP::STATUSPOINT);
        pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC);
        pc_heal(sd, sd->status.max_hp, sd->status.max_sp);
        clif_misceffect(sd, 0);
        clif_displaymessage(s, "Base level raised."_s);
    }
    else
    {
        if (sd->status.base_level == 1)
        {
            clif_displaymessage(s, "Base level can't go any lower."_s);
            return ATCE::USAGE;
        }
        if (level < -battle_config.maximum_level || level < (1 - sd->status.base_level))
            // fix negativ overflow
            level = 1 - sd->status.base_level;
        if (sd->status.status_point > 0)
        {
            for (i = 0; i > level; i--)
                sd->status.status_point -=
                    (sd->status.base_level + i + 14) / 4;
            if (sd->status.status_point < 0)
                sd->status.status_point = 0;
            clif_updatestatus(sd, SP::STATUSPOINT);
        }
        // to add: remove status points from stats
        sd->status.base_level += level;
        clif_updatestatus(sd, SP::BASELEVEL);
        clif_updatestatus(sd, SP::NEXTBASEEXP);
        pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC);
        clif_displaymessage(s, "Base level lowered."_s);
    }

    return ATCE::OKAY;
}

// TODO: merge this with pc_setparam(SP::JOBLEVEL)
// then fix the funny 50 and/or 10 limitation.
static
ATCE atcommand_joblevelup(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    int up_level = 50, level;

    if (!extract(message, &level) || !level)
        return ATCE::USAGE;

    up_level -= 40;

    if (level > 0)
    {
        if (sd->status.job_level == up_level)
        {
            clif_displaymessage(s, "Job level can't go any higher."_s);
            return ATCE::RANGE;
        }
        if (level > up_level || level > (up_level - sd->status.job_level))
            // fix positiv overflow
            level = up_level - sd->status.job_level;
        sd->status.job_level += level;
        clif_updatestatus(sd, SP::JOBLEVEL);
        clif_updatestatus(sd, SP::NEXTJOBEXP);
        sd->status.skill_point += level;
        clif_updatestatus(sd, SP::SKILLPOINT);
        pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC);
        clif_misceffect(sd, 1);
        clif_displaymessage(s, "Job level raised."_s);
    }
    else
    {
        if (sd->status.job_level == 1)
        {
            clif_displaymessage(s, "Job level can't go any lower."_s);
            return ATCE::RANGE;
        }
        if (level < -up_level || level < (1 - sd->status.job_level))
            // fix negativ overflow
            level = 1 - sd->status.job_level;
        sd->status.job_level += level;
        clif_updatestatus(sd, SP::JOBLEVEL);
        clif_updatestatus(sd, SP::NEXTJOBEXP);
        if (sd->status.skill_point > 0)
        {
            sd->status.skill_point += level;
            if (sd->status.skill_point < 0)
                sd->status.skill_point = 0;
            clif_updatestatus(sd, SP::SKILLPOINT);
        }
        // to add: remove status points from skills
        pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC);
        clif_displaymessage(s, "Job level lowered."_s);
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_pvpoff(Session *s, dumb_ptr<map_session_data> sd,
        ZString)
{
    if (battle_config.pk_mode)
    {
        //disable command if server is in PK mode [Valaris]
        clif_displaymessage(s, "This option cannot be used in PK Mode."_s);
        return ATCE::EXIST;
    }

    if (sd->bl_m->flag.get(MapFlag::PVP))
    {
        sd->bl_m->flag.set(MapFlag::PVP, 0);
        for (io::FD i : iter_fds())
        {
            Session *s2 = get_session(i);
            if (!s2)
                continue;
            dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get()));
            if (pl_sd && pl_sd->state.auth)
            {
                if (sd->bl_m == pl_sd->bl_m)
                {
                    pl_sd->pvp_timer.cancel();
                    clif_map_pvp(pl_sd);
                }
            }
        }
        clif_displaymessage(s, "PvP: Off."_s);
    }
    else
    {
        clif_displaymessage(s, "PvP is already Off."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

// Command not removed during bexprate/jexprate split
// because serverdata calls it.
static
ATCE atcommand_exprate(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    int rate;

    if (!extract(message, &rate) || !rate)
    {
        clif_displaymessage(s,
                "Please, enter a rate adjustement (usage: @exprate <percent>)."_s);
        return ATCE::USAGE;
    }
    battle_config.base_exp_rate = rate;
    battle_config.job_exp_rate = rate;
    AString output = STRPRINTF("Base & job XP rates now at %d percent"_fmt, rate);
    clif_displaymessage(s, output);
    return ATCE::OKAY;
}

static
ATCE atcommand_bexprate(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    int rate;

    if (!extract(message, &rate) || !rate)
    {
        clif_displaymessage(s,
                "Please, enter a rate adjustement (usage: @bexprate <percent>)."_s);
        return ATCE::USAGE;
    }
    battle_config.base_exp_rate = rate;
    AString output = STRPRINTF("Base XP rate now at %d percent"_fmt, rate);
    clif_displaymessage(s, output);
    return ATCE::OKAY;
}

static
ATCE atcommand_jexprate(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    int rate;

    if (!extract(message, &rate) || !rate)
    {
        clif_displaymessage(s,
                "Please, enter a rate adjustement (usage: @jexprate <percent>)."_s);
        return ATCE::USAGE;
    }
    battle_config.job_exp_rate = rate;
    AString output = STRPRINTF("Job XP rate now at %d percent"_fmt, rate);
    clif_displaymessage(s, output);
    return ATCE::OKAY;
}

static
ATCE atcommand_rates(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    AString output = STRPRINTF(
            "Experience rates: Base %d%% / Job %d%%. Drop rate: 100%%"_fmt,
            battle_config.base_exp_rate, battle_config.job_exp_rate);
    clif_displaymessage(s, output);
    return ATCE::OKAY;
}

static
ATCE atcommand_pvpon(Session *s, dumb_ptr<map_session_data> sd,
        ZString)
{
    if (battle_config.pk_mode)
    {
        //disable command if server is in PK mode [Valaris]
        clif_displaymessage(s, "This option cannot be used in PK Mode."_s);
        return ATCE::EXIST;
    }

    if (!sd->bl_m->flag.get(MapFlag::PVP) && !sd->bl_m->flag.get(MapFlag::NOPVP))
    {
        sd->bl_m->flag.set(MapFlag::PVP, 1);
        for (io::FD i : iter_fds())
        {
            Session *s2 = get_session(i);
            if (!s2)
                continue;
            dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get()));
            if (pl_sd && pl_sd->state.auth)
            {
                if (sd->bl_m == pl_sd->bl_m && !pl_sd->pvp_timer)
                {
                    pl_sd->pvp_timer = Timer(gettick() + 200_ms,
                            std::bind(pc_calc_pvprank_timer, ph::_1, ph::_2, pl_sd->bl_id));
                    //pl_sd->pvp_rank = 0;
                    //pl_sd->pvp_point = 5;
                    clif_map_pvp(pl_sd);
                }
            }
        }
        clif_displaymessage(s, "PvP: On."_s);
    }
    else
    {
        clif_displaymessage(s, "PvP is already On."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_model(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    int hair_style = 0, hair_color = 0, cloth_color = 0;

    if (!extract(message, record<' ', 1>(&hair_style, &hair_color, &cloth_color)))
        return ATCE::USAGE;

    if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE &&
        hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR &&
        cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR)
    {
        {
            pc_changelook(sd, LOOK::HAIR, hair_style);
            pc_changelook(sd, LOOK::HAIR_COLOR, hair_color);
            pc_changelook(sd, LOOK::CLOTHES_COLOR, cloth_color);
            clif_displaymessage(s, "Appearence changed."_s);
        }
    }
    else
        return ATCE::RANGE;

    return ATCE::OKAY;
}

static
ATCE atcommand_dye(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    int cloth_color = 0;

    if (!extract(message, &cloth_color))
        return ATCE::USAGE;

    if (cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR)
    {
        {
            pc_changelook(sd, LOOK::CLOTHES_COLOR, cloth_color);
            clif_displaymessage(s, "Appearence changed."_s);
        }
    }
    else
        return ATCE::RANGE;

    return ATCE::OKAY;
}

static
ATCE atcommand_hair_style(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    int hair_style = 0;

    if (!extract(message, &hair_style))
        return ATCE::USAGE;

    if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE)
    {
        {
            pc_changelook(sd, LOOK::HAIR, hair_style);
            clif_displaymessage(s, "Appearence changed."_s);
        }
    }
    else
        return ATCE::RANGE;

    return ATCE::OKAY;
}

static
ATCE atcommand_hair_color(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    int hair_color = 0;

    if (!extract(message, &hair_color))
        return ATCE::USAGE;

    if (hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR)
    {
        {
            pc_changelook(sd, LOOK::HAIR_COLOR, hair_color);
            clif_displaymessage(s, "Appearence changed."_s);
        }
    }
    else
        return ATCE::RANGE;

    return ATCE::OKAY;
}

static
ATCE atcommand_mobinfo(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    MobName name;
    Species mob_id;

    if (!extract(message, &name) || !name)
        return ATCE::USAGE;

    if ((mob_id = wrap<Species>(static_cast<uint16_t>(atoi(name.c_str())))) == Species())
        mob_id = mobdb_searchname(name);
    else
        mob_id = mobdb_checkid(mob_id);

    if (mob_id == Species())
        return ATCE::EXIST;

    clif_displaymessage(s, STRPRINTF("Monster ID: %i, English Name: %s, Japanese Name: %s"_fmt, mob_id, get_mob_db(mob_id).name, get_mob_db(mob_id).jname));
    clif_displaymessage(s, STRPRINTF("Level: %i, HP: %i, SP: %i, Base EXP: %i, JEXP: %i"_fmt, get_mob_db(mob_id).lv, get_mob_db(mob_id).max_hp, get_mob_db(mob_id).max_sp, get_mob_db(mob_id).base_exp, get_mob_db(mob_id).job_exp));
    clif_displaymessage(s, STRPRINTF("Range1: %i, ATK1: %i, ATK2: %i, DEF: %i, MDEF: %i, CRITICAL_DEF: %i"_fmt, get_mob_db(mob_id).range, get_mob_db(mob_id).atk1, get_mob_db(mob_id).atk2, get_mob_db(mob_id).def, get_mob_db(mob_id).mdef, get_mob_db(mob_id).critical_def));
    clif_displaymessage(s, STRPRINTF("Stats: STR: %i, AGI: %i, VIT: %i, INT: %i, DEX: %i, LUK: %i"_fmt, get_mob_db(mob_id).attrs[ATTR::STR], get_mob_db(mob_id).attrs[ATTR::AGI], get_mob_db(mob_id).attrs[ATTR::VIT], get_mob_db(mob_id).attrs[ATTR::INT], get_mob_db(mob_id).attrs[ATTR::DEX], get_mob_db(mob_id).attrs[ATTR::LUK]));
    clif_displaymessage(s, STRPRINTF("Range2: %i, Range3: %i, Scale: %i, Race: %i, Element: %i, Element Level: %i, Mode: %i"_fmt, get_mob_db(mob_id).range2, get_mob_db(mob_id).range3, get_mob_db(mob_id).size, get_mob_db(mob_id).race, get_mob_db(mob_id).element.element, get_mob_db(mob_id).element.level, get_mob_db(mob_id).mode));
    clif_displaymessage(s, STRPRINTF("Speed: %i, Adelay: %i, Amotion: %i, Dmotion: %i"_fmt, get_mob_db(mob_id).speed.count(), get_mob_db(mob_id).adelay.count(), get_mob_db(mob_id).amotion.count(), get_mob_db(mob_id).dmotion.count()));
    if (get_mob_db(mob_id).mutations_nr)
        clif_displaymessage(s, STRPRINTF("May mutate %i attribute up to %i%%"_fmt, get_mob_db(mob_id).mutations_nr, get_mob_db(mob_id).mutation_power));

    for (int i = 0; i < MaxDrops; ++i)
        if (get_mob_db(mob_id).dropitem[i].nameid)
        {
            Option<P<struct item_data>> i_data = Some(itemdb_search(get_mob_db(mob_id).dropitem[i].nameid));
            RString item_name = i_data.pmd_pget(&item_data::name).copy_or(stringish<ItemName>(""_s));

            int drop_rate = get_mob_db(mob_id).dropitem[i].p.num;

            char str[6];
            char strpos = 0;

            char min = 0;
            char mod = 0;
            char fraction = drop_rate % 100;
            char integer = drop_rate / 100;

            if (fraction)
            {
                if (fraction < 10)
                    min = 1;
                do
                {
                    mod = fraction % 10;
                    fraction = fraction / 10;
                    if (!(strpos == 0 && mod == 0))
                    {
                        str[strpos] = '0' + mod;
                        ++strpos;
                    }
                } while (fraction > 0);
                if (min)
                {
                    str[strpos] = '0';
                    ++strpos;
                }
                str[strpos] = '.';
                ++strpos;
            }
            if (integer)
            {
                do
                {
                    mod = integer % 10;
                    integer = integer / 10;
                    str[strpos] = '0' + mod;
                    ++strpos;
                } while (integer > 0);
            }
            else
            {
                str[strpos] = '0';
                ++strpos;
            }
            // flip string
            for (char i=0, tmpstrpos=strpos-1; i <= tmpstrpos/2; ++i, --tmpstrpos)
            {
                char tmp = str[tmpstrpos];
                str[tmpstrpos]=str[i];
                str[i]=tmp;
            }
            str[strpos] = '\0';

            int drop_rate2 = 10000/drop_rate;
            clif_displaymessage(s, STRPRINTF("Drop ID %i: %i, Item Name: %s, Drop Chance: %s%% (1:%i)"_fmt,i, get_mob_db(mob_id).dropitem[i].nameid, item_name, str, drop_rate2));
        }
        else
            break;

    clif_displaymessage(s, STRPRINTF("Mob Mode Info:"_fmt));
    if (!bool(get_mob_db(mob_id).mode & MobMode::ZERO))
    {
        if (bool(get_mob_db(mob_id).mode & MobMode::CAN_MOVE))
            clif_displaymessage(s, STRPRINTF("Mobile"_fmt));
        if (bool(get_mob_db(mob_id).mode & MobMode::LOOTER))
            clif_displaymessage(s, STRPRINTF("Picks up loot"_fmt));
        if (bool(get_mob_db(mob_id).mode & MobMode::AGGRESSIVE))
            clif_displaymessage(s, STRPRINTF("Aggro"_fmt));
        if (bool(get_mob_db(mob_id).mode & MobMode::ASSIST))
            clif_displaymessage(s, STRPRINTF("Assists"_fmt));
        if (bool(get_mob_db(mob_id).mode & MobMode::CAST_SENSOR))
            clif_displaymessage(s, STRPRINTF("Cast Sensor"_fmt));
        if (bool(get_mob_db(mob_id).mode & MobMode::BOSS))
            clif_displaymessage(s, STRPRINTF("Boss"_fmt));
        if (bool(get_mob_db(mob_id).mode & MobMode::PLANT))
            clif_displaymessage(s, STRPRINTF("Plant"_fmt));
        if (bool(get_mob_db(mob_id).mode & MobMode::CAN_ATTACK))
            clif_displaymessage(s, STRPRINTF("Can attack"_fmt));
        if (bool(get_mob_db(mob_id).mode & MobMode::DETECTOR))
            clif_displaymessage(s, STRPRINTF("Detector"_fmt));
        if (bool(get_mob_db(mob_id).mode & MobMode::CHANGE_TARGET))
            clif_displaymessage(s, STRPRINTF("Change Target"_fmt));
            /*
            Not needed here i guess
            SUMMONED
            TURNS_AGAINST_BAD_MASTER
            SENSIBLE_MASK
            */
    }
    return ATCE::OKAY;
}

static
ATCE atcommand_summon(Session *, dumb_ptr<map_session_data> sd,
        ZString message)
{
    MobName name;
    Species mob_id;
    int x = 0;
    int y = 0;
    tick_t tick = gettick();

    if (!extract(message, &name) || !name)
        return ATCE::USAGE;

    if ((mob_id = wrap<Species>(static_cast<uint16_t>(atoi(name.c_str())))) == Species())
        mob_id = mobdb_searchname(name);
    if (mob_id == Species())
        return ATCE::EXIST;

    x = sd->bl_x + random_::in(-5, 4);
    y = sd->bl_y + random_::in(-5, 4);

    BlockId id = mob_once_spawn(sd, MOB_THIS_MAP, x, y, JAPANESE_NAME, mob_id, 1, NpcEvent());
    dumb_ptr<mob_data> md = map_id_is_mob(id);
    if (md)
    {
        md->master_id = sd->bl_id;
        md->state.special_mob_ai = 1;
        md->mode = get_mob_db(md->mob_class).mode | MobMode::AGGRESSIVE;
        md->deletetimer = Timer(tick + 1_min,
                std::bind(mob_timer_delete, ph::_1, ph::_2,
                    id));
        clif_misceffect(md, 344);
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_spawn(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    MobName monster;
    Species mob_id;
    int number = 0;
    int x = 0, y = 0;
    int count;
    int mx, my, range;

    if (!extract(message, record<' ', 1>(&monster, &number, &x, &y)))
        return ATCE::USAGE;

    // If monster identifier/name argument is a name
    if ((mob_id = mobdb_searchname(monster)) == Species())
        // check name first (to avoid possible name begining by a number)
        mob_id = mobdb_checkid(wrap<Species>(atoi(monster.c_str())));

    if (mob_id == Species())
        return ATCE::EXIST;

    if (number <= 0)
        number = 1;

    // If value of atcommand_spawn_quantity_limit directive is greater than or equal to 1 and quantity of monsters is greater than value of the directive
    if (battle_config.atcommand_spawn_quantity_limit >= 1
        && number > battle_config.atcommand_spawn_quantity_limit)
        number = battle_config.atcommand_spawn_quantity_limit;

    if (battle_config.etc_log)
        PRINTF("@spawn monster='%s' id=%d count=%d (%d,%d)\n"_fmt,
                monster, mob_id, number, x, y);

    count = 0;
    range = sqrt(number) / 2;
    range = range * 2 + 5;
    // calculation of an odd number (+ 4 area around)
    for (int i = 0; i < number; i++)
    {
        int j = 0;
        BlockId k;
        while (j++ < 8 && !k)
        {
            // try 8 times to spawn the monster (needed for close area)
            if (x <= 0)
                mx = sd->bl_x + random_::in(-range / 2, range / 2 );
            else
                mx = x;
            if (y <= 0)
                my = sd->bl_y + random_::in(-range / 2, range / 2);
            else
                my = y;
            k = mob_once_spawn(sd, MOB_THIS_MAP, mx, my, MobName(), mob_id, 1, NpcEvent());
        }
        count += k ? 1 : 0;
    }

    if (count != 0)
        if (number == count)
            clif_displaymessage(s, "All monster summoned!"_s);
        else
        {
            AString output = STRPRINTF("%d monster(s) summoned!"_fmt,
                    count);
            clif_displaymessage(s, output);
        }
    else
    {
        clif_displaymessage(s, "Invalid monster ID or name."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
void atcommand_killmonster_sub(Session *s, dumb_ptr<map_session_data> sd,
        ZString message, const int drop)
{
    P<map_local> map_id =
    ({
        MapName map_name;
        extract(message, &map_name);

        map_mapname2mapid(map_name).copy_or(sd->bl_m);
    });

    map_foreachinarea(std::bind(atkillmonster_sub, ph::_1, drop),
            map_id,
            0, 0,
            map_id->xs, map_id->ys,
            BL::MOB);

    clif_displaymessage(s, "All monsters killed!"_s);
}

static
ATCE atcommand_killmonster(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    atcommand_killmonster_sub(s, sd, message, 1);

    return ATCE::OKAY;
}

static
void atlist_nearby_sub(dumb_ptr<block_list> bl, Session *s)
{
    nullpo_retv(bl);

    AString buf = STRPRINTF(" - \"%s\""_fmt,
            bl->is_player()->status_key.name);
    clif_displaymessage(s, buf);
}

static
ATCE atcommand_list_nearby(Session *s, dumb_ptr<map_session_data> sd,
        ZString)
{
    clif_displaymessage(s, "Nearby players:"_s);
    map_foreachinarea(std::bind(atlist_nearby_sub, ph::_1, s),
            sd->bl_m,
            sd->bl_x - 1, sd->bl_y - 1,
            sd->bl_x + 1, sd->bl_x + 1,
            BL::PC);

    return ATCE::OKAY;
}

static
ATCE atcommand_killmonster2(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    atcommand_killmonster_sub(s, sd, message, 0);

    return ATCE::OKAY;
}

static
ATCE atcommand_gat(Session *s, dumb_ptr<map_session_data> sd,
        ZString)
{
    int y;

    for (y = 2; y >= -2; y--)
    {
        AString output = STRPRINTF(
                "%s (x= %d, y= %d) %02X %02X %02X %02X %02X"_fmt,
                sd->bl_m->name_, sd->bl_x - 2, sd->bl_y + y,
                map_getcell(sd->bl_m, sd->bl_x - 2, sd->bl_y + y),
                map_getcell(sd->bl_m, sd->bl_x - 1, sd->bl_y + y),
                map_getcell(sd->bl_m, sd->bl_x, sd->bl_y + y),
                map_getcell(sd->bl_m, sd->bl_x + 1, sd->bl_y + y),
                map_getcell(sd->bl_m, sd->bl_x + 2, sd->bl_y + y));
        clif_displaymessage(s, output);
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_packet(Session *, dumb_ptr<map_session_data> sd,
        ZString message)
{
    StatusChange type {};
    int flag = 0;

    if (!extract(message, record<' '>(&type, &flag)))
        return ATCE::USAGE;

    clif_status_change(sd, type, flag);

    return ATCE::OKAY;
}

static
ATCE atcommand_statuspoint(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    int point, new_status_point;

    if (!extract(message, &point) || point == 0)
        return ATCE::USAGE;

    new_status_point = sd->status.status_point + point;
    if (point > 0 && (point > 0x7FFF || new_status_point > 0x7FFF))
        // fix positiv overflow
        new_status_point = 0x7FFF;
    else if (point < 0 && (point < -0x7FFF || new_status_point < 0))
        // fix negativ overflow
        new_status_point = 0;

    if (new_status_point != sd->status.status_point)
    {
        sd->status.status_point = new_status_point;
        clif_updatestatus(sd, SP::STATUSPOINT);
        clif_displaymessage(s, "Number of status points changed!"_s);
    }
    else
        return ATCE::RANGE;

    return ATCE::OKAY;
}

static
ATCE atcommand_skillpoint(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    int point, new_skill_point;

    if (!extract(message, &point) || point == 0)
        return ATCE::USAGE;

    new_skill_point = sd->status.skill_point + point;
    if (point > 0 && (point > 0x7FFF || new_skill_point > 0x7FFF))
        // fix positiv overflow
        new_skill_point = 0x7FFF;
    else if (point < 0 && (point < -0x7FFF || new_skill_point < 0))
        // fix negativ overflow
        new_skill_point = 0;

    if (new_skill_point != sd->status.skill_point)
    {
        sd->status.skill_point = new_skill_point;
        clif_updatestatus(sd, SP::SKILLPOINT);
        clif_displaymessage(s, "Number of skill points changed!"_s);
    }
    else
        return ATCE::RANGE;

    return ATCE::OKAY;
}

static
ATCE atcommand_zeny(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    int zeny, new_zeny;

    if (!extract(message, &zeny) || zeny == 0)
        return ATCE::USAGE;

    new_zeny = sd->status.zeny + zeny;
    if (zeny > 0 && (zeny > MAX_ZENY || new_zeny > MAX_ZENY))
        // fix positiv overflow
        new_zeny = MAX_ZENY;
    else if (zeny < 0 && (zeny < -MAX_ZENY || new_zeny < 0))
        // fix negativ overflow
        new_zeny = 0;

    if (new_zeny != sd->status.zeny)
    {
        sd->status.zeny = new_zeny;
        clif_updatestatus(sd, SP::ZENY);
        clif_displaymessage(s, "Number of zenys changed!"_s);
    }
    else
        return ATCE::RANGE;

    return ATCE::OKAY;
}

template<ATTR attr>
ATCE atcommand_param(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    int value = 0, new_value;

    if (!extract(message, &value)
        || value == 0)
        return ATCE::USAGE;

    new_value = sd->status.attrs[attr] + value;
    if (value > 0 && (value > battle_config.max_parameter || new_value > battle_config.max_parameter))
        // fix positiv overflow
        new_value = battle_config.max_parameter;
    else if (value < 0 && (value < -battle_config.max_parameter || new_value < 1))
        // fix negativ overflow
        new_value = 1;

    if (new_value != sd->status.attrs[attr])
    {
        sd->status.attrs[attr] = new_value;
        clif_updatestatus(sd, attr_to_sp(attr));
        clif_updatestatus(sd, attr_to_usp(attr));
        pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC);
        clif_displaymessage(s, "Stat changed."_s);
    }
    else
        return ATCE::RANGE;

    return ATCE::OKAY;
}

static
ATCE atcommand_all_stats(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    int count, value = 0, new_value;

    if (!extract(message, &value)
        || value == 0)
        value = battle_config.max_parameter;

    count = 0;
    for (ATTR attr : ATTRs)
    {
        new_value = sd->status.attrs[attr] + value;
        if (value > 0 && (value > battle_config.max_parameter || new_value > battle_config.max_parameter))
            // fix positiv overflow
            new_value = battle_config.max_parameter;
        else if (value < 0 && (value < -battle_config.max_parameter || new_value < 1))
            // fix negativ overflow
            new_value = 1;

        if (new_value != sd->status.attrs[attr])
        {
            sd->status.attrs[attr] = new_value;
            clif_updatestatus(sd, attr_to_sp(attr));
            clif_updatestatus(sd, attr_to_usp(attr));
            pc_calcstatus(sd, (int)CalcStatusKind::NORMAL_RECALC);
            count++;
        }
    }

    if (count > 0)
        // if at least 1 stat modified
        clif_displaymessage(s, "All stats changed!"_s);
    else
        return ATCE::RANGE;

    return ATCE::OKAY;
}

static
ATCE atcommand_recall(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    CharName character;

    if (!asplit(message, &character))
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr)
    {
        if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd)))
        {
            // you can recall only lower or same level
            if (sd->bl_m->flag.get(MapFlag::NOWARPTO)
                && !(pc_isGM(sd).satisfies(battle_config.any_warp_GM_min_level)))
            {
                clif_displaymessage(s,
                        "You are not authorised to warp somenone to your actual map."_s);
                return ATCE::PERM;
            }
            if (pl_sd->bl_m->flag.get(MapFlag::NOWARP)
                && !(pc_isGM(sd).satisfies(battle_config.any_warp_GM_min_level)))
            {
                clif_displaymessage(s,
                        "You are not authorised to warp this player from its actual map."_s);
                return ATCE::PERM;
            }
            pc_setpos(pl_sd, sd->mapname_, sd->bl_x, sd->bl_y, BeingRemoveWhy::QUIT);
            AString output = STRPRINTF("%s recalled!"_fmt, character);
            clif_displaymessage(s, output);
        }
        else
        {
            clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s);
            return ATCE::PERM;
        }
    }
    else
    {
        clif_displaymessage(s, "Character not found."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_revive(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    CharName character;

    if (!asplit(message, &character))
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr)
    {
        pl_sd->status.hp = pl_sd->status.max_hp;
        pc_setstand(pl_sd);
        if (battle_config.player_invincible_time > interval_t::zero())
            pc_setinvincibletimer(sd, battle_config.player_invincible_time);
        clif_updatestatus(pl_sd, SP::HP);
        clif_updatestatus(pl_sd, SP::SP);
        clif_resurrection(pl_sd, 1);
        clif_displaymessage(s, "Character revived."_s);
    }
    else
    {
        clif_displaymessage(s, "Character not found."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_character_stats(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    CharName character;

    if (!asplit(message, &character))
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr)
    {
        AString output;
        output = STRPRINTF("'%s' stats:"_fmt, pl_sd->status_key.name);
        clif_displaymessage(s, output);
        output = STRPRINTF("Base Level - %d"_fmt, pl_sd->status.base_level);
        clif_displaymessage(s, output);
        output = STRPRINTF("Job - Novice/Human (level %d)"_fmt, pl_sd->status.job_level);
        clif_displaymessage(s, output);
        output = STRPRINTF("Hp - %d"_fmt, pl_sd->status.hp);
        clif_displaymessage(s, output);
        output = STRPRINTF("MaxHp - %d"_fmt, pl_sd->status.max_hp);
        clif_displaymessage(s, output);
        output = STRPRINTF("Sp - %d"_fmt, pl_sd->status.sp);
        clif_displaymessage(s, output);
        output = STRPRINTF("MaxSp - %d"_fmt, pl_sd->status.max_sp);
        clif_displaymessage(s, output);
        output = STRPRINTF("Str - %3d"_fmt, pl_sd->status.attrs[ATTR::STR]);
        clif_displaymessage(s, output);
        output = STRPRINTF("Agi - %3d"_fmt, pl_sd->status.attrs[ATTR::AGI]);
        clif_displaymessage(s, output);
        output = STRPRINTF("Vit - %3d"_fmt, pl_sd->status.attrs[ATTR::VIT]);
        clif_displaymessage(s, output);
        output = STRPRINTF("Int - %3d"_fmt, pl_sd->status.attrs[ATTR::INT]);
        clif_displaymessage(s, output);
        output = STRPRINTF("Dex - %3d"_fmt, pl_sd->status.attrs[ATTR::DEX]);
        clif_displaymessage(s, output);
        output = STRPRINTF("Luk - %3d"_fmt, pl_sd->status.attrs[ATTR::LUK]);
        clif_displaymessage(s, output);
        output = STRPRINTF("Zeny - %d"_fmt, pl_sd->status.zeny);
        clif_displaymessage(s, output);
    }
    else
    {
        clif_displaymessage(s, "Character not found."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_character_stats_full(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    CharName character;

    if (!asplit(message, &character))
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr)
    {
            AString output;
            output = STRPRINTF("------ Character Status Full ------"_fmt);
            clif_displaymessage(s, output);
            output = STRPRINTF(
                    "Char-Name: %s | BLvl: %d | Job: Novice/Human (Lvl: %d) | HP: %d/%d | SP: %d/%d | Zeny: %d"_fmt,
                    pl_sd->status_key.name, pl_sd->status.base_level,
                    pl_sd->status.job_level,
                    pl_sd->status.hp, pl_sd->status.max_hp,
                    pl_sd->status.sp, pl_sd->status.max_sp,
                    pl_sd->status.zeny);
            clif_displaymessage(s, output);
            output = STRPRINTF("Base-Stats: STR: %d | AGI: %d | VIT: %d | INT: %d | DEX: %d | LUK: %d"_fmt,
                    pl_sd->status.attrs[ATTR::STR],
                    pl_sd->status.attrs[ATTR::AGI],
                    pl_sd->status.attrs[ATTR::VIT],
                    pl_sd->status.attrs[ATTR::INT],
                    pl_sd->status.attrs[ATTR::DEX],
                    pl_sd->status.attrs[ATTR::LUK]);
            clif_displaymessage(s, output);
            output = STRPRINTF("Equipment-Stats (parame): STR: %d | AGI: %d | VIT: %d | INT: %d | DEX: %d | LUK: %d"_fmt,
                    pl_sd->parame[ATTR::STR],
                    pl_sd->parame[ATTR::AGI],
                    pl_sd->parame[ATTR::VIT],
                    pl_sd->parame[ATTR::INT],
                    pl_sd->parame[ATTR::DEX],
                    pl_sd->parame[ATTR::LUK]);
            clif_displaymessage(s, output);
            output = STRPRINTF("Full-Stats (paramc): STR: %d | AGI: %d | VIT: %d | INT: %d | DEX: %d | LUK: %d"_fmt,
                    pl_sd->paramc[ATTR::STR],
                    pl_sd->paramc[ATTR::AGI],
                    pl_sd->paramc[ATTR::VIT],
                    pl_sd->paramc[ATTR::INT],
                    pl_sd->paramc[ATTR::DEX],
                    pl_sd->paramc[ATTR::LUK]);
            clif_displaymessage(s, output);
            // paramb seems to be unused atm
            output = STRPRINTF("paramb: STR: %d | AGI: %d | VIT: %d | INT: %d | DEX: %d | LUK: %d"_fmt,
                    pl_sd->paramb[ATTR::STR],
                    pl_sd->paramb[ATTR::AGI],
                    pl_sd->paramb[ATTR::VIT],
                    pl_sd->paramb[ATTR::INT],
                    pl_sd->paramb[ATTR::DEX],
                    pl_sd->paramb[ATTR::LUK]);
            clif_displaymessage(s, output);
            output = STRPRINTF("paramcard: STR: %d | AGI: %d | VIT: %d | INT: %d | DEX: %d | LUK: %d"_fmt,
                    pl_sd->paramcard[ATTR::STR],
                    pl_sd->paramcard[ATTR::AGI],
                    pl_sd->paramcard[ATTR::VIT],
                    pl_sd->paramcard[ATTR::INT],
                    pl_sd->paramcard[ATTR::DEX],
                    pl_sd->paramcard[ATTR::LUK]);
            clif_displaymessage(s, output);
            output = STRPRINTF("BASE_ATK: %d | ATK1: %d | ATK2: %d | ATK_RATE: %d | MATK1: %d | MATK2: %d | MATK_RATE: %d"_fmt,
                    pl_sd->base_atk,
                    pl_sd->watk,
                    pl_sd->watk2,
                    pl_sd->atk_rate,
                    pl_sd->matk1,
                    pl_sd->matk2,
                    pl_sd->matk_rate);
            clif_displaymessage(s, output);
            output = STRPRINTF("ATTACKRANGE: %d | CRITICAL_DEF: %d | FLEE1: %d | FLEE_RATE: %d | FLEE2: %d | FLEE2_RATE: %d"_fmt,
                    pl_sd->attackrange,
                    pl_sd->critical_def,
                    pl_sd->flee,
                    pl_sd->flee_rate,
                    pl_sd->flee2,
                    pl_sd->flee2_rate);
            clif_displaymessage(s, output);
            output = STRPRINTF("MDEF1: %d | MDEF_RATE: %d | MDEF2: %d | MDEF2_RATE: %d | DEF1: %d | DEF_RATE: %d | DEF2: %d | DEF2_RATE: %d"_fmt,
                    pl_sd->mdef,
                    pl_sd->mdef_rate,
                    pl_sd->mdef2,
                    pl_sd->mdef2_rate,
                    pl_sd->def,
                    pl_sd->def_rate,
                    pl_sd->def2,
                    pl_sd->def2_rate);
            clif_displaymessage(s, output);
            output = STRPRINTF("ADD_SPEED: %d | SPEED_RATE: %d | SPEED_ADDRATE: %d | ASPD: %d | ASPD_RATE: %d | ASPD_ADDRATE: %d"_fmt,
                    pl_sd->speed.count(),
                    pl_sd->speed_rate,
                    pl_sd->speed_add_rate,
                    pl_sd->aspd.count(),
                    pl_sd->aspd_rate,
                    pl_sd->aspd_add_rate);
            clif_displaymessage(s, output);
            output = STRPRINTF("MAXHPRATE: %d | HP_RECOV_RATE: %d | MAXSPRATE: %d | SP_RECOV_RATE: %d | DOUBLE_RATE: %d | DOUBLE_ADD_RATE: %d"_fmt,
                    pl_sd->hprate,
                    pl_sd->hprecov_rate,
                    pl_sd->sprate,
                    pl_sd->sprecov_rate,
                    pl_sd->double_rate,
                    pl_sd->double_add_rate);
            clif_displaymessage(s, output);
            output = STRPRINTF("PERFECT_HIT_RATE: %d | PERFECT_HIT_ADD_RATE: %d | CRITICAL: %d | CRITICAL_RATE: %d | HIT: %d | HIT_RATE: %d"_fmt,
                    pl_sd->perfect_hit,
                    pl_sd->perfect_hit_add_rate,
                    pl_sd->critical,
                    pl_sd->critical_rate,
                    pl_sd->hit,
                    pl_sd->hit_rate);
            clif_displaymessage(s, output);
            output = STRPRINTF("DEADLY_STRIKE_RATE: %d | DEADLY_STRIKE_ADD_RATE: %d | BASE_WEAPON_DELAY_ADJUST: %d"_fmt,
                    pl_sd->deadly_strike,
                    pl_sd->deadly_strike_add_rate,
                    pl_sd->base_weapon_delay_adjust.count());
            clif_displaymessage(s, output);
            output = STRPRINTF("arrow_atk: %d | arrow_cri: %d | arrow_hit: %d | arrow_range: %d"_fmt,
                    pl_sd->arrow_atk,
                    pl_sd->arrow_cri,
                    pl_sd->arrow_hit,
                    pl_sd->arrow_range);
            clif_displaymessage(s, output);
            output = STRPRINTF("HP_DRAIN_RATE: %d | HP_DRAIN_RATE per: %d | SP_DRAIN_RATE: %d | SP_DRAIN_RATE per: %d"_fmt,
                    pl_sd->hp_drain_rate,
                    pl_sd->hp_drain_per,
                    pl_sd->sp_drain_rate,
                    pl_sd->sp_drain_per);
            clif_displaymessage(s, output);
    }
    else
    {
        clif_displaymessage(s, "Character not found."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_character_stats_all(Session *s, dumb_ptr<map_session_data>,
        ZString)
{
    int count;

    count = 0;
    for (io::FD i : iter_fds())
    {
        Session *s2 = get_session(i);
        if (!s2)
            continue;
        dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get()));
        if (pl_sd && pl_sd->state.auth)
        {
            AString gmlevel;
            if (GmLevel pl_gm_level = pc_isGM(pl_sd))
                gmlevel = STRPRINTF("| GM Lvl: %d"_fmt, pl_gm_level);
            else
                gmlevel = " "_s;

            AString output;
            output = STRPRINTF(
                    "Name: %s | BLvl: %d | Job: Novice/Human (Lvl: %d) | HP: %d/%d | SP: %d/%d"_fmt,
                    pl_sd->status_key.name, pl_sd->status.base_level,
                    pl_sd->status.job_level,
                    pl_sd->status.hp, pl_sd->status.max_hp,
                    pl_sd->status.sp, pl_sd->status.max_sp);
            clif_displaymessage(s, output);
            output = STRPRINTF("STR: %d | AGI: %d | VIT: %d | INT: %d | DEX: %d | LUK: %d | Zeny: %d %s"_fmt,
                    pl_sd->status.attrs[ATTR::STR],
                    pl_sd->status.attrs[ATTR::AGI],
                    pl_sd->status.attrs[ATTR::VIT],
                    pl_sd->status.attrs[ATTR::INT],
                    pl_sd->status.attrs[ATTR::DEX],
                    pl_sd->status.attrs[ATTR::LUK],
                    pl_sd->status.zeny,
                    gmlevel);
            clif_displaymessage(s, output);
            clif_displaymessage(s, "--------"_s);
            count++;
        }
    }

    if (count == 0)
        clif_displaymessage(s, "No player found."_s);
    else if (count == 1)
        clif_displaymessage(s, "1 player found."_s);
    else
    {
        AString output = STRPRINTF("%d players found."_fmt, count);
        clif_displaymessage(s, output);
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_character_option(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    Opt1 opt1;
    Opt2 opt2;
    Opt0 opt3;
    CharName character;
    if (!asplit(message, &opt1, &opt2, &opt3, &character))
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr)
    {
        if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd)))
        {
            // you can change option only to lower or same level
            pl_sd->opt1 = opt1;
            pl_sd->opt2 = opt2;
            pl_sd->status.option = opt3;

            clif_changeoption(pl_sd);
            pc_calcstatus(pl_sd, (int)CalcStatusKind::NORMAL_RECALC);
            clif_displaymessage(s, "Character's options changed."_s);
        }
        else
        {
            clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s);
            return ATCE::PERM;
        }
    }
    else
    {
        clif_displaymessage(s, "Character not found."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_char_change_sex(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    CharName character;
    VString<1> gender;
    int operation;

    if (!extract(message, record<' ', 1>(&character, &gender)))
    {
        clif_displaymessage(s,
                "Please, enter a char name (usage: @charchangesex <char name> [Gender])."_s);
        return ATCE::USAGE;
    }
    else
    {
        if (sex_from_char(gender.front()) == SEX::FEMALE)
        {
                operation = 5;
        }
        else if (sex_from_char(gender.front()) == SEX::MALE)
        {
                operation = 6;
        }
        else if (sex_from_char(gender.front()) == SEX::NEUTRAL)
        {
                operation = 7;
        }
        else
        {
            clif_displaymessage(s,
                    "Please, enter a char name (usage: @charchangesex <char name> [Gender])."_s);
            return ATCE::USAGE;
        }
        chrif_char_ask_name(sd->status_key.account_id, character, operation, HumanTimeDiff());
        // type: 5 - changesex
        clif_displaymessage(s, "Character name sends to char-server to ask it."_s);
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_char_block(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    CharName character;

    if (!asplit(message, &character))
        return ATCE::USAGE;

    {
        chrif_char_ask_name(sd->status_key.account_id, character, 1, HumanTimeDiff());
        // type: 1 - block
        clif_displaymessage(s, "Character name sends to char-server to ask it."_s);
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_char_ban(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    HumanTimeDiff modif;
    CharName character;

    if (!asplit(message, &modif, &character)
        || !modif)
        return ATCE::USAGE;

    {
        chrif_char_ask_name(sd->status_key.account_id, character, 2, modif);
        // type: 2 - ban
        clif_displaymessage(s, "Character name sends to char-server to ask it."_s);
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_char_unblock(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    CharName character;

    if (!asplit(message, &character))
        return ATCE::USAGE;

    {
        // send answer to login server via char-server
        chrif_char_ask_name(sd->status_key.account_id, character, 3, HumanTimeDiff());
        // type: 3 - unblock
        clif_displaymessage(s, "Character name sends to char-server to ask it."_s);
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_char_unban(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    CharName character;

    if (!asplit(message, &character))
        return ATCE::USAGE;

    {
        // send answer to login server via char-server
        chrif_char_ask_name(sd->status_key.account_id, character, 4, HumanTimeDiff());
        // type: 4 - unban
        clif_displaymessage(s, "Character name sends to char-server to ask it."_s);
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_character_save(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    MapName map_name;
    CharName character;
    int x = 0, y = 0;

    if (!asplit(message, &map_name, &x, &y, &character)
        || x < 0 || y < 0)
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr)
    {
        if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd)))
        {
            // you can change save point only to lower or same gm level
            P<map_local> m = TRY_UNWRAP(map_mapname2mapid(map_name),
            {
                clif_displaymessage(s, "Map not found."_s);
                return ATCE::EXIST;
            });

            {
                if (m->flag.get(MapFlag::NOWARPTO)
                    && !(pc_isGM(sd).satisfies(battle_config.any_warp_GM_min_level)))
                {
                    clif_displaymessage(s,
                            "You are not authorised to set this map as a save map."_s);
                    return ATCE::PERM;
                }
                pc_setsavepoint(pl_sd, map_name, x, y);
                clif_displaymessage(s, "Character's respawn point changed."_s);
            }
        }
        else
        {
            clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s);
            return ATCE::PERM;
        }
    }
    else
    {
        clif_displaymessage(s, "Character not found."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_doom(Session *s, dumb_ptr<map_session_data> sd,
        ZString)
{
    for (io::FD i : iter_fds())
    {
        Session *s2 = get_session(i);
        if (!s2)
            continue;
        dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get()));
        if (pl_sd && !pl_sd->state.connect_new
            && pl_sd->state.auth && s2 != s
            && pc_isGM(sd).overwhelms(pc_isGM(pl_sd)))
        {
            // you can doom only lower or same gm level
            pc_damage(nullptr, pl_sd, pl_sd->status.hp + 1);
            clif_displaymessage(pl_sd->sess, "The holy messenger has given judgement."_s);
        }
    }
    clif_displaymessage(s, "Judgement was made."_s);

    return ATCE::OKAY;
}

static
ATCE atcommand_doommap(Session *s, dumb_ptr<map_session_data> sd,
        ZString)
{
    for (io::FD i : iter_fds())
    {
        Session *s2 = get_session(i);
        if (!s2)
            continue;
        dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get()));
        if (pl_sd && !pl_sd->state.connect_new
            && pl_sd->state.auth && s2 != s && sd->bl_m == pl_sd->bl_m
            && pc_isGM(sd).overwhelms(pc_isGM(pl_sd)))
        {
            // you can doom only lower or same gm level
            pc_damage(nullptr, pl_sd, pl_sd->status.hp + 1);
            clif_displaymessage(pl_sd->sess, "The holy messenger has given judgement."_s);
        }
    }
    clif_displaymessage(s, "Judgement was made."_s);

    return ATCE::OKAY;
}

static
void atcommand_raise_sub(dumb_ptr<map_session_data> sd)
{
    if (sd && sd->state.auth && pc_isdead(sd))
    {
        sd->status.hp = sd->status.max_hp;
        sd->status.sp = sd->status.max_sp;
        pc_setstand(sd);
        clif_updatestatus(sd, SP::HP);
        clif_updatestatus(sd, SP::SP);
        clif_resurrection(sd, 1);
        clif_displaymessage(sd->sess, "Mercy has been shown."_s);
    }
}

static
ATCE atcommand_raise(Session *s, dumb_ptr<map_session_data>,
        ZString)
{
    for (io::FD i : iter_fds())
    {
        Session *s2 = get_session(i);
        if (!s2)
            continue;
        dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get()));
        atcommand_raise_sub(pl_sd);
    }
    clif_displaymessage(s, "Mercy has been granted."_s);

    return ATCE::OKAY;
}

static
ATCE atcommand_raisemap(Session *s, dumb_ptr<map_session_data> sd,
        ZString)
{
    for (io::FD i : iter_fds())
    {
        Session *s2 = get_session(i);
        if (!s2)
            continue;
        dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get()));
        if (pl_sd
            && pl_sd->state.auth && sd->bl_m == pl_sd->bl_m)
            atcommand_raise_sub(pl_sd);
    }
    clif_displaymessage(s, "Mercy has been granted."_s);

    return ATCE::OKAY;
}

//static
ATCE atcommand_character_baselevel(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    CharName character;
    int level = 0, i;

    if (!asplit(message, &level, &character)
        || level == 0)
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr)
    {
        if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd)))
        {
            // you can change base level only lower or same gm level
            if (level > 0)
            {
                if (pl_sd->status.base_level == battle_config.maximum_level)
                {
                    clif_displaymessage(s, "Character's base level can't go any higher."_s);
                    return ATCE::RANGE;
                }
                if (level > battle_config.maximum_level || level > (battle_config.maximum_level - pl_sd->status.base_level))
                    // fix positiv overflow
                    level =
                        battle_config.maximum_level -
                        pl_sd->status.base_level;
                for (i = 1; i <= level; i++)
                    pl_sd->status.status_point +=
                        (pl_sd->status.base_level + i + 14) / 4;
                pl_sd->status.base_level += level;
                clif_updatestatus(pl_sd, SP::BASELEVEL);
                clif_updatestatus(pl_sd, SP::NEXTBASEEXP);
                clif_updatestatus(pl_sd, SP::STATUSPOINT);
                pc_calcstatus(pl_sd, (int)CalcStatusKind::NORMAL_RECALC);
                pc_heal(pl_sd, pl_sd->status.max_hp, pl_sd->status.max_sp);
                clif_misceffect(pl_sd, 0);
                clif_displaymessage(s, "Character's base level raised."_s);
            }
            else
            {
                if (pl_sd->status.base_level == 1)
                {
                    clif_displaymessage(s, "Character's base level can't go any lower."_s);
                    return ATCE::RANGE;
                }
                if (level < -battle_config.maximum_level || level < (1 - pl_sd->status.base_level))
                    // fix negativ overflow
                    level = 1 - pl_sd->status.base_level;
                if (pl_sd->status.status_point > 0)
                {
                    for (i = 0; i > level; i--)
                        pl_sd->status.status_point -=
                            (pl_sd->status.base_level + i + 14) / 4;
                    if (pl_sd->status.status_point < 0)
                        pl_sd->status.status_point = 0;
                    clif_updatestatus(pl_sd, SP::STATUSPOINT);
                }
                // to add: remove status points from stats
                pl_sd->status.base_level += level;
                pl_sd->status.base_exp = 0;
                clif_updatestatus(pl_sd, SP::BASELEVEL);
                clif_updatestatus(pl_sd, SP::NEXTBASEEXP);
                clif_updatestatus(pl_sd, SP::BASEEXP);
                pc_calcstatus(pl_sd, (int)CalcStatusKind::NORMAL_RECALC);
                clif_displaymessage(s, "Character's base level lowered."_s);
            }
            // Reset their stat points to prevent extra points from stacking
            atcommand_charstreset(s, sd, character.to__actual());
        }
        else
        {
            clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s);
            return ATCE::PERM;
        }
    }
    else
    {
        clif_displaymessage(s, "Character not found."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_character_joblevel(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    CharName character;
    int max_level = 50, level = 0;

    if (!asplit(message, &level, &character)
        || level == 0)
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr)
    {
        if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd)))
        {
            // you can change job level only lower or same gm level
            max_level -= 40;

            if (level > 0)
            {
                if (pl_sd->status.job_level == max_level)
                {
                    clif_displaymessage(s, "Character's job level can't go any higher."_s);
                    return ATCE::RANGE;
                }
                if (pl_sd->status.job_level + level > max_level)
                    level = max_level - pl_sd->status.job_level;
                pl_sd->status.job_level += level;
                clif_updatestatus(pl_sd, SP::JOBLEVEL);
                clif_updatestatus(pl_sd, SP::NEXTJOBEXP);
                pl_sd->status.skill_point += level;
                clif_updatestatus(pl_sd, SP::SKILLPOINT);
                pc_calcstatus(pl_sd, (int)CalcStatusKind::NORMAL_RECALC);
                clif_misceffect(pl_sd, 1);
                clif_displaymessage(s, "character's job level raised."_s);
            }
            else
            {
                if (pl_sd->status.job_level == 1)
                {
                    clif_displaymessage(s, "Character's job level can't go any lower."_s);
                    return ATCE::RANGE;
                }
                if (pl_sd->status.job_level + level < 1)
                    level = 1 - pl_sd->status.job_level;
                pl_sd->status.job_level += level;
                clif_updatestatus(pl_sd, SP::JOBLEVEL);
                clif_updatestatus(pl_sd, SP::NEXTJOBEXP);
                if (pl_sd->status.skill_point > 0)
                {
                    pl_sd->status.skill_point += level;
                    if (pl_sd->status.skill_point < 0)
                        pl_sd->status.skill_point = 0;
                    clif_updatestatus(pl_sd, SP::SKILLPOINT);
                }
                // to add: remove status points from skills
                pc_calcstatus(pl_sd, (int)CalcStatusKind::NORMAL_RECALC);
                clif_displaymessage(s, "Character's job level lowered."_s);
            }
        }
        else
        {
            clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s);
            return ATCE::PERM;
        }
    }
    else
    {
        clif_displaymessage(s, "Character not found."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_kick(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    CharName character;

    if (!asplit(message, &character))
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr)
    {
        if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd)))
            // you can kick only lower or same gm level
            clif_GM_kick(sd, pl_sd, 1);
        else
        {
            clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s);
            return ATCE::PERM;
        }
    }
    else
    {
        clif_displaymessage(s, "Character not found."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_kickall(Session *s, dumb_ptr<map_session_data> sd,
        ZString)
{
    for (io::FD i : iter_fds())
    {
        Session *s2 = get_session(i);
        if (!s2)
            continue;
        dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get()));
        if (pl_sd
            && pl_sd->state.auth && pc_isGM(sd).overwhelms(pc_isGM(pl_sd)))
        {
            // you can kick only lower or same gm level
            if (sd->status_key.account_id != pl_sd->status_key.account_id)
                clif_GM_kick(sd, pl_sd, 0);
        }
    }

    clif_displaymessage(s, "All players have been kicked!"_s);

    return ATCE::OKAY;
}

static
ATCE atcommand_questskill(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    SkillID skill_id;

    if (!extract(message, &skill_id))
        return ATCE::USAGE;

    if (/*skill_id >= SkillID() &&*/ skill_id < SkillID::MAX_SKILL_DB)
    {
        if (skill_get_inf2(skill_id) & 0x01)
        {
            if (pc_checkskill(sd, skill_id) == 0)
            {
                pc_skill(sd, skill_id, 1, 0);
                clif_displaymessage(s, "You have learned the skill."_s);
            }
            else
            {
                clif_displaymessage(s, "You already have this quest skill."_s);
                return ATCE::EXIST;
            }
        }
        else
        {
            clif_displaymessage(s, "This skill number doesn't exist or isn't a quest skill."_s);
            return ATCE::RANGE;
        }
    }
    else
    {
        clif_displaymessage(s, "This skill number doesn't exist."_s);
        return ATCE::RANGE;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_charquestskill(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    CharName character;
    SkillID skill_id;

    if (!asplit(message, &skill_id, &character))
        return ATCE::USAGE;

    if (/*skill_id >= SkillID() &&*/ skill_id < SkillID::MAX_SKILL_DB)
    {
        if (skill_get_inf2(skill_id) & 0x01)
        {
            dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
            if (pl_sd != nullptr)
            {
                if (pc_checkskill(pl_sd, skill_id) == 0)
                {
                    pc_skill(pl_sd, skill_id, 1, 0);
                    clif_displaymessage(s, "This player has learned the skill."_s);
                }
                else
                {
                    clif_displaymessage(s, "This player already has this quest skill."_s);
                    return ATCE::EXIST;
                }
            }
            else
            {
                clif_displaymessage(s, "Character not found."_s);
                return ATCE::EXIST;
            }
        }
        else
        {
            clif_displaymessage(s, "This skill number doesn't exist or isn't a quest skill."_s);
            return ATCE::RANGE;
        }
    }
    else
    {
        clif_displaymessage(s, "This skill number doesn't exist."_s);
        return ATCE::RANGE;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_lostskill(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    SkillID skill_id;

    if (!extract(message, &skill_id))
        return ATCE::USAGE;

    if (/*skill_id >= SkillID() &&*/ skill_id < MAX_SKILL)
    {
        if (skill_get_inf2(skill_id) & 0x01)
        {
            if (pc_checkskill(sd, skill_id) > 0)
            {
                sd->status.skill[skill_id].lv = 0;
                sd->status.skill[skill_id].flags = SkillFlags::ZERO;
                clif_skillinfoblock(sd);
                clif_displaymessage(s, "You have forgotten the skill."_s);
            }
            else
            {
                clif_displaymessage(s, "You don't have this quest skill."_s);
                return ATCE::EXIST;
            }
        }
        else
        {
            clif_displaymessage(s, "This skill number doesn't exist or isn't a quest skill."_s);
            return ATCE::RANGE;
        }
    }
    else
    {
        clif_displaymessage(s, "This skill number doesn't exist."_s);
        return ATCE::RANGE;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_charlostskill(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    CharName character;
    SkillID skill_id;

    if (!asplit(message, &skill_id, &character))
        return ATCE::USAGE;

    if (/*skill_id >= SkillID() &&*/ skill_id < MAX_SKILL)
    {
        if (skill_get_inf2(skill_id) & 0x01)
        {
            dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
            if (pl_sd != nullptr)
            {
                if (pc_checkskill(pl_sd, skill_id) > 0)
                {
                    pl_sd->status.skill[skill_id].lv = 0;
                    pl_sd->status.skill[skill_id].flags = SkillFlags::ZERO;
                    clif_skillinfoblock(pl_sd);
                    clif_displaymessage(s, "This player has forgotten the skill."_s);
                }
                else
                {
                    clif_displaymessage(s, "This player doesn't have this quest skill."_s);
                    return ATCE::EXIST;
                }
            }
            else
            {
                clif_displaymessage(s, "Character not found."_s);
                return ATCE::EXIST;
            }
        }
        else
        {
            clif_displaymessage(s, "This skill number doesn't exist or isn't a quest skill."_s);
            return ATCE::RANGE;
        }
    }
    else
    {
        clif_displaymessage(s, "This skill number doesn't exist."_s);
        return ATCE::RANGE;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_party(Session *, dumb_ptr<map_session_data> sd,
        ZString message)
{
    PartyName party;

    if (!extract(message, &party) || !party)
        return ATCE::USAGE;

    party_create(sd, party);

    return ATCE::OKAY;
}

static
ATCE atcommand_mapexit(Session *, dumb_ptr<map_session_data> sd,
        ZString)
{
    for (io::FD i : iter_fds())
    {
        Session *s2 = get_session(i);
        if (!s2)
            continue;
        dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get()));
        if (pl_sd && pl_sd->state.auth)
        {
            if (sd->status_key.account_id != pl_sd->status_key.account_id)
                clif_GM_kick(sd, pl_sd, 0);
        }
    }
    clif_GM_kick(sd, sd, 0);

    runflag = 0;

    return ATCE::OKAY;
}

static
ATCE atcommand_idsearch(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    ItemName item_name;
    int match;

    if (!extract(message, &item_name) || !item_name)
        return ATCE::USAGE;

    AString output = STRPRINTF("The reference result of '%s' (name: id):"_fmt, item_name);
    clif_displaymessage(s, output);
    match = 0;
    for (ItemNameId i = wrap<ItemNameId>(0); i < wrap<ItemNameId>(-1); i = next(i))
    {
        P<struct item_data> item = TRY_UNWRAP(itemdb_exists(i), continue);
        if (item->name.contains_seq(item_name))
        {
            match++;
            output = STRPRINTF("%s: %d"_fmt, item->name, item->nameid);
            clif_displaymessage(s, output);
        }
    }
    output = STRPRINTF("It is %d affair above."_fmt, match);
    clif_displaymessage(s, output);

    return ATCE::OKAY;
}

static
ATCE atcommand_charskreset(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    CharName character;

    if (!asplit(message, &character))
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr)
    {
        if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd)))
        {
            // you can reset skill points only lower or same gm level
            pc_resetskill(pl_sd);
            AString output = STRPRINTF(
                    "'%s' skill points reseted!"_fmt, character);
            clif_displaymessage(s, output);
        }
        else
        {
            clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s);
            return ATCE::PERM;
        }
    }
    else
    {
        clif_displaymessage(s, "Character not found."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

//static
ATCE atcommand_charstreset(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    CharName character;

    if (!asplit(message, &character))
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr)
    {
        if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd)))
        {
            // you can reset stats points only lower or same gm level
            pc_resetstate(pl_sd);
            AString output = STRPRINTF(
                    "'%s' stats points reseted!"_fmt,
                    character);
            clif_displaymessage(s, output);
        }
        else
        {
            clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s);
            return ATCE::PERM;
        }
    }
    else
    {
        clif_displaymessage(s, "Character not found."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_charreset(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    CharName character;

    if (!asplit(message, &character))
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr)
    {
        if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd)))
        {
            // you can reset a character only for lower or same GM level
            pc_resetstate(pl_sd);
            pc_resetskill(pl_sd);
            pc_setglobalreg(pl_sd, stringish<VarName>("MAGIC_FLAGS"_s), 0);
            // [Fate] Reset magic quest variables
            pc_setglobalreg(pl_sd, stringish<VarName>("MAGIC_EXP"_s), 0);
            // [Fate] Reset magic experience
            AString output = STRPRINTF(
                    "'%s' skill and stats points reseted!"_fmt, character);
            clif_displaymessage(s, output);
        }
        else
        {
            clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s);
            return ATCE::PERM;
        }
    }
    else
    {
        clif_displaymessage(s, "Character not found."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_char_wipe(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    CharName character;

    if (!asplit(message, &character))
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr)
    {
        if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd)))
        {
            // you can reset a character only for lower or same GM level

            // Reset base level
            pl_sd->status.base_level = 1;
            pl_sd->status.base_exp = 0;
            clif_updatestatus(pl_sd, SP::BASELEVEL);
            clif_updatestatus(pl_sd, SP::NEXTBASEEXP);
            clif_updatestatus(pl_sd, SP::BASEEXP);

            // Reset job level
            pl_sd->status.job_level = 1;
            pl_sd->status.job_exp = 0;
            clif_updatestatus(pl_sd, SP::JOBLEVEL);
            clif_updatestatus(pl_sd, SP::NEXTJOBEXP);
            clif_updatestatus(pl_sd, SP::JOBEXP);

            // Zeny to 50
            pl_sd->status.zeny = 50;
            clif_updatestatus(pl_sd, SP::ZENY);

            // Clear inventory
            for (IOff0 i : IOff0::iter())
            {
                if (sd->status.inventory[i].amount)
                {
                    if (bool(sd->status.inventory[i].equip))
                        pc_unequipitem(pl_sd, i, CalcStatus::NOW);
                    pc_delitem(pl_sd, i, sd->status.inventory[i].amount, 0);
                }
            }

            // Give knife and shirt
            Item item;
            item.nameid = wrap<ItemNameId>(1201);
            pc_additem(pl_sd, &item, 1);
            item.nameid = wrap<ItemNameId>(1202);
            pc_additem(pl_sd, &item, 1);

            // Reset stats and skills
            pc_calcstatus(pl_sd, (int)CalcStatusKind::NORMAL_RECALC);
            pc_resetstate(pl_sd);
            pc_resetskill(pl_sd);
            pc_setglobalreg(pl_sd, stringish<VarName>("MAGIC_FLAGS"_s), 0);
            // [Fate] Reset magic quest variables
            pc_setglobalreg(pl_sd, stringish<VarName>("MAGIC_EXP"_s), 0);
            // [Fate] Reset magic experience

            AString output = STRPRINTF("%s:  wiped."_fmt, character);
            clif_displaymessage(s, output);
        }
        else
        {
            clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s);
            return ATCE::PERM;
        }
    }
    else
    {
        clif_displaymessage(s, "Character not found."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_charmodel(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    unsigned hair_style = 0, hair_color = 0, cloth_color = 0;
    CharName character;

    if (!asplit(message, &hair_style, &hair_color, &cloth_color, &character))
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr)
    {
        if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE &&
            hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR &&
            cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR)
        {
            {
                pc_changelook(pl_sd, LOOK::HAIR, hair_style);
                pc_changelook(pl_sd, LOOK::HAIR_COLOR, hair_color);
                pc_changelook(pl_sd, LOOK::CLOTHES_COLOR, cloth_color);
                clif_displaymessage(s, "Appearence changed."_s);
            }
        }
        else
            return ATCE::RANGE;
    }
    else
    {
        clif_displaymessage(s, "Character not found."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_charskpoint(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    CharName character;
    int new_skill_point;
    int point = 0;

    if (!asplit(message, &point, &character)
        || point == 0)
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr)
    {
        new_skill_point = pl_sd->status.skill_point + point;
        if (point > 0 && (point > 0x7FFF || new_skill_point > 0x7FFF))
            // fix positiv overflow
            new_skill_point = 0x7FFF;
        else if (point < 0 && (point < -0x7FFF || new_skill_point < 0))
            // fix negativ overflow
            new_skill_point = 0;
        if (new_skill_point != pl_sd->status.skill_point)
        {
            pl_sd->status.skill_point = new_skill_point;
            clif_updatestatus(pl_sd, SP::SKILLPOINT);
            clif_displaymessage(s, "Character's number of skill points changed!"_s);
        }
        else
            return ATCE::RANGE;
    }
    else
    {
        clif_displaymessage(s, "Character not found."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_charstpoint(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    CharName character;
    int new_status_point;
    int point = 0;

    if (!asplit(message, &point, &character)
        || point == 0)
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr)
    {
        new_status_point = pl_sd->status.status_point + point;
        if (point > 0 && (point > 0x7FFF || new_status_point > 0x7FFF))
            // fix positiv overflow
            new_status_point = 0x7FFF;
        else if (point < 0 && (point < -0x7FFF || new_status_point < 0))
            // fix negativ overflow
            new_status_point = 0;
        if (new_status_point != pl_sd->status.status_point)
        {
            pl_sd->status.status_point = new_status_point;
            clif_updatestatus(pl_sd, SP::STATUSPOINT);
            clif_displaymessage(s, "Character's number of status points changed!"_s);
        }
        else
            return ATCE::RANGE;
    }
    else
    {
        clif_displaymessage(s, "Character not found."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_charzeny(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    CharName character;
    int zeny = 0, new_zeny;

    if (!asplit(message, &zeny, &character) || zeny == 0)
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr)
    {
        new_zeny = pl_sd->status.zeny + zeny;
        if (zeny > 0 && (zeny > MAX_ZENY || new_zeny > MAX_ZENY))
            // fix positiv overflow
            new_zeny = MAX_ZENY;
        else if (zeny < 0 && (zeny < -MAX_ZENY || new_zeny < 0))
            // fix negativ overflow
            new_zeny = 0;
        if (new_zeny != pl_sd->status.zeny)
        {
            pl_sd->status.zeny = new_zeny;
            clif_updatestatus(pl_sd, SP::ZENY);
            clif_displaymessage(s, "Character's number of zenys changed!"_s);
        }
        else
            return ATCE::RANGE;
    }
    else
    {
        clif_displaymessage(s, "Character not found."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_recallall(Session *s, dumb_ptr<map_session_data> sd,
        ZString)
{
    int count;

    if (sd->bl_m->flag.get(MapFlag::NOWARPTO)
        && !(pc_isGM(sd).satisfies(battle_config.any_warp_GM_min_level)))
    {
        clif_displaymessage(s,
                "You are not authorised to warp somenone to your actual map."_s);
        return ATCE::PERM;
    }

    count = 0;
    for (io::FD i : iter_fds())
    {
        Session *s2 = get_session(i);
        if (!s2)
            continue;
        dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get()));
        if (pl_sd
            && pl_sd->state.auth
            && sd->status_key.account_id != pl_sd->status_key.account_id
            && pc_isGM(sd).overwhelms(pc_isGM(pl_sd)))
        {
            // you can recall only lower or same level
            if (pl_sd->bl_m->flag.get(MapFlag::NOWARP)
                && !(pc_isGM(sd).satisfies(battle_config.any_warp_GM_min_level)))
                count++;
            else
                pc_setpos(pl_sd, sd->mapname_, sd->bl_x, sd->bl_y, BeingRemoveWhy::QUIT);
        }
    }

    clif_displaymessage(s, "All characters recalled!"_s);
    if (count)
    {
        AString output = STRPRINTF(
                "Because you are not authorised to warp from some maps, %d player(s) have not been recalled."_fmt,
                count);
        clif_displaymessage(s, output);
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_partyrecall(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    PartyName party_name;
    int count;

    if (!extract(message, &party_name) || !party_name)
        return ATCE::USAGE;

    if (sd->bl_m->flag.get(MapFlag::NOWARPTO)
        && !(pc_isGM(sd).satisfies(battle_config.any_warp_GM_min_level)))
    {
        clif_displaymessage(s,
                "You are not authorised to warp somenone to your actual map."_s);
        return ATCE::PERM;
    }

    // name first to avoid error when name begin with a number
    Option<PartyPair> p_ = party_searchname(party_name);
    if (p_.is_none())
        p_ = party_search(wrap<PartyId>(static_cast<uint32_t>(atoi(message.c_str()))));
    OMATCH_BEGIN (p_)
    {
        OMATCH_CASE_SOME (p)
        {
            count = 0;
            for (io::FD i : iter_fds())
            {
                Session *s2 = get_session(i);
                if (!s2)
                    continue;
                dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get()));
                if (pl_sd && pl_sd->state.auth && !pl_sd->state.connect_new
                    && sd->status_key.account_id != pl_sd->status_key.account_id
                    && pl_sd->status.party_id == p.party_id)
                {
                    if (pl_sd->bl_m->flag.get(MapFlag::NOWARP)
                        && !(pc_isGM(sd).satisfies(battle_config.any_warp_GM_min_level)))
                        count++;
                    else
                        pc_setpos(pl_sd, sd->mapname_, sd->bl_x, sd->bl_y, BeingRemoveWhy::QUIT);
                }
            }
            AString output = STRPRINTF("All online characters of the %s party are near you."_fmt, p->name);
            clif_displaymessage(s, output);
            if (count)
            {
                output = STRPRINTF(
                        "Because you are not authorised to warp from some maps, %d player(s) have not been recalled."_fmt,
                        count);
                clif_displaymessage(s, output);
            }
        }
        OMATCH_CASE_NONE ()
        {
            clif_displaymessage(s, "Incorrect name or ID, or no one from the party is online."_s);
            return ATCE::EXIST;
        }
    }
    OMATCH_END ();

    return ATCE::OKAY;
}

static
ATCE atcommand_mapinfo(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    dumb_ptr<npc_data> nd = nullptr;
    MapName map_name;
    LString direction = ""_s;
    int list = 0;

    extract(message, record<' '>(&list, &map_name));

    if (list < 0 || list > 2)
        return ATCE::USAGE;

    if (!map_name)
        map_name = sd->mapname_;

    P<map_local> m_id = TRY_UNWRAP(map_mapname2mapid(map_name), return ATCE::EXIST);

    clif_displaymessage(s, "------ Map Info ------"_s);
    AString output = STRPRINTF("Map Name: %s"_fmt, map_name);
    clif_displaymessage(s, output);
    output = STRPRINTF("Players In Map: %d"_fmt, m_id->users);
    clif_displaymessage(s, output);
    output = STRPRINTF("NPCs In Map: %d"_fmt, m_id->npc_num);
    clif_displaymessage(s, output);
    clif_displaymessage(s, "------ Map Flags ------"_s);
    output = STRPRINTF("Player vs Player: %s | No Party: %s"_fmt,
            (m_id->flag.get(MapFlag::PVP)) ? "True"_s : "False"_s,
            (m_id->flag.get(MapFlag::PVP_NOPARTY)) ? "True"_s : "False"_s);
    clif_displaymessage(s, output);
    output = STRPRINTF("No Penalty: %s"_fmt,
            (m_id->flag.get(MapFlag::NOPENALTY)) ? "True"_s : "False"_s);
    clif_displaymessage(s, output);
    output = STRPRINTF("No Return: %s"_fmt,
            (m_id->flag.get(MapFlag::NORETURN)) ? "True"_s : "False"_s);
    clif_displaymessage(s, output);
    output = STRPRINTF("No Save: %s"_fmt,
            (m_id->flag.get(MapFlag::NOSAVE)) ? "True"_s : "False"_s);
    clif_displaymessage(s, output);
    output = STRPRINTF("Re Save: %s"_fmt,
            (m_id->flag.get(MapFlag::RESAVE)) ? "True"_s : "False"_s);
    clif_displaymessage(s, output);
    output = STRPRINTF("No Teleport: %s"_fmt,
            (m_id->flag.get(MapFlag::NOTELEPORT)) ? "True"_s : "False"_s);
    clif_displaymessage(s, output);
    output = STRPRINTF("No Monster Teleport: %s"_fmt,
            (m_id->flag.get(MapFlag::MONSTER_NOTELEPORT)) ? "True"_s : "False"_s);
    clif_displaymessage(s, output);

    switch (list)
    {
        case 0:
            // Do nothing. It's list 0, no additional display.
            break;
        case 1:
            clif_displaymessage(s, "----- Players in Map -----"_s);
            for (io::FD i : iter_fds())
            {
                Session *s2 = get_session(i);
                if (!s2)
                    continue;
                dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get()));
                if (pl_sd && pl_sd->state.auth
                    && pl_sd->mapname_ == map_name)
                {
                    output = STRPRINTF(
                            "Player '%s' (session #%d) | Location: %d,%d"_fmt,
                            pl_sd->status_key.name, s2, pl_sd->bl_x, pl_sd->bl_y);
                    clif_displaymessage(s, output);
                }
            }
            break;
        case 2:
            clif_displaymessage(s, "----- NPCs in Map -----"_s);
            for (int i = 0; i < m_id->npc_num;)
            {
                nd = m_id->npc[i];
                if (nd == nullptr) continue;

                switch (nd->dir)
                {
                    case DIR::S:
                        direction = "North"_s;
                        break;
                    case DIR::SW:
                        direction = "North West"_s;
                        break;
                    case DIR::W:
                        direction = "West"_s;
                        break;
                    case DIR::NW:
                        direction = "South West"_s;
                        break;
                    case DIR::N:
                        direction = "South"_s;
                        break;
                    case DIR::NE:
                        direction = "South East"_s;
                        break;
                    case DIR::E:
                        direction = "East"_s;
                        break;
                    case DIR::SE:
                        direction = "North East"_s;
                        break;
#if 0
                    case 9:
                        direction = "North"_s;
                        break;
#endif
                    default:
                        direction = "Unknown"_s;
                        break;
                }
                output = STRPRINTF(
                         "NPC %d: %s | Direction: %s | Sprite: %d | Location: %d %d"_fmt,
                         ++i, nd->name, direction, nd->npc_class, nd->bl_x,
                         nd->bl_y);
                clif_displaymessage(s, output);
            }
            break;
        default:
            // normally impossible to arrive here
            clif_displaymessage(s,
                    "Please, enter at least a valid list number (usage: @mapinfo <0-2> [map])."_s);
            return ATCE::USAGE;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_partyspy(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    PartyName party_name;

    if (!extract(message, &party_name))
        return ATCE::USAGE;

    // name first to avoid error when name begin with a number
    Option<PartyPair> p_ = party_searchname(party_name);
    if (p_.is_none())
        p_ = party_search(wrap<PartyId>(static_cast<uint32_t>(atoi(message.c_str()))));
    OMATCH_BEGIN (p_)
    {
        OMATCH_CASE_SOME (p)
        {
            if (sd->partyspy == p.party_id)
            {
                sd->partyspy = PartyId();
                AString output = STRPRINTF("No longer spying on the %s party."_fmt, p->name);
                clif_displaymessage(s, output);
            }
            else
            {
                sd->partyspy = p.party_id;
                AString output = STRPRINTF("Spying on the %s party."_fmt, p->name);
                clif_displaymessage(s, output);
            }
        }
        OMATCH_CASE_NONE ()
        {
            clif_displaymessage(s, "Incorrect name or ID, or no one from the party is online."_s);
            return ATCE::EXIST;
        }
    }
    OMATCH_END ();

    return ATCE::OKAY;
}

static
ATCE atcommand_setpartyleader(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    CharName character;
    PartyName party_name;
    int value = 0;

    if (!asplit(message, &party_name, &value, &character))
        return ATCE::USAGE;


    // name first to avoid error when name begin with a number
    Option<PartyPair> p_ = party_searchname(party_name);
    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);

    // try with party id
    if (p_.is_none())
        p_ = party_search(wrap<PartyId>(static_cast<uint32_t>(atoi(party_name.c_str()))));

    if (p_.is_none() || pl_sd == nullptr)
        return ATCE::EXIST;

    OMATCH_BEGIN (p_)
    {
        OMATCH_CASE_SOME (p)
        {
            intif_party_changeleader(p.party_id, pl_sd->status_key.account_id, value < 1 ? 0 : 1);
            clif_displaymessage(s, "Party leader changed."_s);
        }
        OMATCH_CASE_NONE ()
        {
            clif_displaymessage(s, "Incorrect party name, or no one from the party is online."_s);
            return ATCE::EXIST;
        }
    }
    OMATCH_END ();
    return ATCE::OKAY;
}

static
ATCE atcommand_setleader(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    CharName character;
    short mask = 0;
    int i = 0;

    if (!asplit(message, &character))
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);

    if (pl_sd == nullptr || pl_sd->status.party_id == PartyId())
        return ATCE::EXIST;

    PartyPair p_ = TRY_UNWRAP(party_search(pl_sd->status.party_id), return ATCE::EXIST);

    for (i = 0; i < MAX_PARTY; i++)
    {
        if (p_->member[i].account_id == sd->status_key.account_id)
            mask |= p_->member[i].leader ? 3 : 1;

        if (p_->member[i].account_id == pl_sd->status_key.account_id)
            mask |= p_->member[i].leader ? 12 : 4;

        if (mask & 5)
            break;
    }

    if (!(mask & 2))
        return ATCE::PERM;

    intif_party_changeleader(pl_sd->status.party_id, pl_sd->status_key.account_id, (mask & 8) ? 0 : 1);
    clif_displaymessage(s, "Party leader changed."_s);

    return ATCE::OKAY;
}

static
ATCE atcommand_enablenpc(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    NpcName NPCname;

    if (!extract(message, &NPCname) || !NPCname)
        return ATCE::USAGE;

    if (npc_name2id(NPCname) != nullptr)
    {
        npc_enable(NPCname, 1);
        clif_displaymessage(s, "Npc Enabled."_s);
    }
    else
    {
        clif_displaymessage(s, "This NPC doesn't exist."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_disablenpc(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    NpcName NPCname;

    if (!extract(message, &NPCname) || !NPCname)
        return ATCE::USAGE;

    if (npc_name2id(NPCname) != nullptr)
    {
        npc_enable(NPCname, 0);
        clif_displaymessage(s, "Npc Disabled."_s);
    }
    else
    {
        clif_displaymessage(s, "This NPC doesn't exist."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_servertime(Session *s, dumb_ptr<map_session_data>,
        ZString)
{
    timestamp_seconds_buffer tsbuf;
    stamp_time(tsbuf);
    AString temp = STRPRINTF("Server time: %s"_fmt, tsbuf);
    clif_displaymessage(s, temp);

    return ATCE::OKAY;
}

static
ATCE atcommand_chardelitem(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    CharName character;
    XString item_name;
    int i, number = 0;
    int count;

    if (!asplit(message, &item_name, &number, &character) || number < 1)
        return ATCE::USAGE;

    P<struct item_data> item_data = TRY_UNWRAP(extract_item_opt(item_name), return ATCE::EXIST);
    ItemNameId item_id = item_data->nameid;
    assert(item_id >= wrap<ItemNameId>(0));

    {
        dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
        if (pl_sd != nullptr)
        {
            if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd)))
            {
                // you can kill only lower or same level
                IOff0 item_position = pc_search_inventory(pl_sd, item_id);
                if (item_position.ok())
                {
                    count = 0;
                    for (i = 0; i < number && item_position.ok(); i++)
                    {
                        pc_delitem(pl_sd, item_position, 1, 0);
                        count++;
                        item_position = pc_search_inventory(pl_sd, item_id);
                        // for next loop
                    }
                    AString output = STRPRINTF(
                            "%d item(s) removed by a GM."_fmt,
                            count);
                    clif_displaymessage(pl_sd->sess, output);

                    if (number == count)
                        output = STRPRINTF("%d item(s) removed from the player."_fmt, count);
                    else
                        output = STRPRINTF("%d item(s) removed. Player had only %d on %d items."_fmt, count, count, number);
                    clif_displaymessage(s, output);
                }
                else
                {
                    clif_displaymessage(s, "Character does not have the item."_s);
                    return ATCE::EXIST;
                }
            }
            else
            {
                clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s);
                return ATCE::PERM;
            }
        }
        else
        {
            clif_displaymessage(s, "Character not found."_s);
            return ATCE::EXIST;
        }
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_broadcast(Session *, dumb_ptr<map_session_data> sd,
        ZString message)
{
    if (!message)
        return ATCE::USAGE;

    AString output = STRPRINTF("%s : %s"_fmt, sd->status_key.name, message);
    intif_GMmessage(output);

    return ATCE::OKAY;
}

static
ATCE atcommand_localbroadcast(Session *, dumb_ptr<map_session_data> sd,
        ZString message)
{
    if (!message)
        return ATCE::USAGE;

    AString output = STRPRINTF("%s : %s"_fmt, sd->status_key.name, message);

    clif_GMmessage(sd, output, 1);

    return ATCE::OKAY;
}

static
ATCE atcommand_email(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    AccountEmail actual_email;
    AccountEmail new_email;

    if (!extract(message, record<' '>(&actual_email, &new_email)))
        return ATCE::USAGE;

    if (!e_mail_check(actual_email))
    {
        clif_displaymessage(s, "Invalid actual email. If you have default e-mail, type a@a.com."_s);
        return ATCE::RANGE;
    }
    else if (!e_mail_check(new_email))
    {
        clif_displaymessage(s, "Invalid new email. Please enter a real e-mail."_s);
        return ATCE::RANGE;
    }
    else if (new_email == DEFAULT_EMAIL)
    {
        clif_displaymessage(s, "New email must be a real e-mail."_s);
        return ATCE::RANGE;
    }
    else if (actual_email == new_email)
    {
        clif_displaymessage(s, "New email must be different of the actual e-mail."_s);
        return ATCE::RANGE;
    }
    else
    {
        chrif_changeemail(sd->status_key.account_id, actual_email, new_email);
        clif_displaymessage(s, "Information sended to login-server via char-server."_s);
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_effect(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    int type = 0, flag = 0;

    if (!extract(message, record<' '>(&type, &flag)))
        return ATCE::USAGE;
    if (flag <= 0)
    {
        clif_specialeffect(sd, type, flag);
        clif_displaymessage(s, "Your Effect Has Changed."_s);
    }
    else
    {
        for (io::FD i : iter_fds())
        {
            Session *s2 = get_session(i);
            if (!s2)
                continue;
            dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get()));
            if (pl_sd && pl_sd->state.auth && !pl_sd->state.connect_new)
            {
                clif_specialeffect(pl_sd, type, flag);
                clif_displaymessage(pl_sd->sess, "Your Effect Has Changed."_s);
            }
        }
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_character_item_list(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    int count, counter;
    CharName character;

    if (!asplit(message, &character))
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr)
    {
        if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd)))
        {
            // you can look items only lower or same level
            counter = 0;
            count = 0;
            for (IOff0 i : IOff0::iter())
            {
                if (!pl_sd->status.inventory[i].nameid)
                    continue;
                P<struct item_data> item_data = TRY_UNWRAP(itemdb_exists(pl_sd->status.inventory[i].nameid), continue);

                {
                    counter = counter + pl_sd->status.inventory[i].amount;
                    count++;
                    if (count == 1)
                    {
                        AString output = STRPRINTF(
                                "------ Items list of '%s' ------"_fmt,
                                pl_sd->status_key.name);
                        clif_displaymessage(s, output);
                    }
                    EPOS equip = pl_sd->status.inventory[i].equip;
                    MString equipstr;
                    if (bool(equip))
                    {
                        equipstr += "| equiped: "_s;
                        if (bool(equip & EPOS::GLOVES))
                            equipstr += "robe/gargment, "_s;
                        if (bool(equip & EPOS::CAPE))
                            equipstr += "left accessory, "_s;
                        if (bool(equip & EPOS::MISC1))
                            equipstr += "body/armor, "_s;
                        if ((equip & (EPOS::WEAPON | EPOS::SHIELD)) == EPOS::WEAPON)
                            equipstr += "right hand, "_s;
                        if ((equip & (EPOS::WEAPON | EPOS::SHIELD)) == EPOS::SHIELD)
                            equipstr += "left hand, "_s;
                        if ((equip & (EPOS::WEAPON | EPOS::SHIELD)) == (EPOS::WEAPON | EPOS::SHIELD))
                            equipstr += "both hands, "_s;
                        if (bool(equip & EPOS::SHOES))
                            equipstr += "feet, "_s;
                        if (bool(equip & EPOS::MISC2))
                            equipstr += "right accessory, "_s;
                        if ((equip & (EPOS::TORSO | EPOS::HAT | EPOS::LEGS)) == EPOS::LEGS)
                            equipstr += "lower head, "_s;
                        if ((equip & (EPOS::TORSO | EPOS::HAT | EPOS::LEGS)) == EPOS::HAT)
                            equipstr += "top head, "_s;
                        if ((equip & (EPOS::TORSO | EPOS::HAT | EPOS::LEGS)) == (EPOS::HAT | EPOS::LEGS))
                            equipstr += "lower/top head, "_s;
                        if ((equip & (EPOS::TORSO | EPOS::HAT | EPOS::LEGS)) == EPOS::TORSO)
                            equipstr += "mid head, "_s;
                        if ((equip & (EPOS::TORSO | EPOS::HAT | EPOS::LEGS)) == (EPOS::TORSO | EPOS::LEGS))
                            equipstr += "lower/mid head, "_s;
                        if ((equip & (EPOS::TORSO | EPOS::HAT | EPOS::LEGS)) == (EPOS::TORSO | EPOS::HAT | EPOS::LEGS))
                            equipstr += "lower/mid/top head, "_s;
                        // remove final ', '
                        equipstr.pop_back(2);
                    }
                    else
                        equipstr = MString();

                    AString output;
                    if (true)
                        output = STRPRINTF("%d %s (id: %d) %s"_fmt,
                                pl_sd->status.inventory[i].amount,
                                item_data->name,
                                pl_sd->status.inventory[i].nameid,
                                AString(equipstr));
                    clif_displaymessage(s, output);

                    // snip cards
                }
            }
            if (count == 0)
                clif_displaymessage(s, "No item found on this player."_s);
            else
            {
                AString output = STRPRINTF(
                        "%d item(s) found in %d kind(s) of items."_fmt,
                        counter, count);
                clif_displaymessage(s, output);
            }
        }
        else
        {
            clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s);
            return ATCE::PERM;
        }
    }
    else
    {
        clif_displaymessage(s, "Character not found."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_character_storage_list(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    int count, counter;
    CharName character;

    if (!asplit(message, &character))
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr)
    {
        if (pc_isGM(sd).overwhelms(pc_isGM(pl_sd)))
        {
            // you can look items only lower or same level
            Option<P<Storage>> stor_ = account2storage2(pl_sd->status_key.account_id);
            OMATCH_BEGIN (stor_)
            {
                OMATCH_CASE_SOME (stor)
                {
                    counter = 0;
                    count = 0;
                    for (SOff0 i : SOff0::iter())
                    {
                        if (!stor->storage_[i].nameid)
                            continue;
                        P<struct item_data> item_data = TRY_UNWRAP(itemdb_exists(stor->storage_[i].nameid), continue);

                        {
                            counter = counter + stor->storage_[i].amount;
                            count++;
                            if (count == 1)
                            {
                                AString output = STRPRINTF(
                                        "------ Storage items list of '%s' ------"_fmt,
                                        pl_sd->status_key.name);
                                clif_displaymessage(s, output);
                            }
                            AString output;
                            if (true)
                                output = STRPRINTF("%d %s (id: %d)"_fmt,
                                        stor->storage_[i].amount,
                                        item_data->name,
                                        stor->storage_[i].nameid);
                            clif_displaymessage(s, output);
                        }
                    }
                    if (count == 0)
                        clif_displaymessage(s,
                                "No item found in the storage of this player."_s);
                    else
                    {
                        AString output = STRPRINTF(
                                "%d item(s) found in %d kind(s) of items."_fmt,
                                counter, count);
                        clif_displaymessage(s, output);
                    }
                }
                OMATCH_CASE_NONE ()
                {
                    clif_displaymessage(s, "This player has no storage."_s);
                    return ATCE::OKAY;
                }
            }
            OMATCH_END ();
        }
        else
        {
            clif_displaymessage(s, "Your GM level don't authorise you to do this action on this player."_s);
            return ATCE::PERM;
        }
    }
    else
    {
        clif_displaymessage(s, "Character not found."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_pvp(Session *s, dumb_ptr<map_session_data> sd,
        ZString)
{
    int chan = sd->state.pvpchannel;
    if (sd->pvp_timer || (chan > 1))
        return ATCE::OKAY;

    if (chan < 1) {
        sd->state.pvpchannel = 1;
        clif_displaymessage(s, "Server : ##3##BPvP ##3##BOn"_s);
    } else {
        sd->state.pvpchannel = 0;
        clif_displaymessage(s, "Server : ##3##BPvP ##3##BOff"_s);
    }

    sd->state.pvp_rank = 0;
    clif_pvpstatus(sd); // send my channel to others

    pc_setpvptimer(sd, battle_config.player_pvp_time);
    return ATCE::OKAY;
}

static
ATCE atcommand_charpvp(Session *, dumb_ptr<map_session_data>,
        ZString message)
{
    CharName character;
    int channel;

    if (!extract(message, record<' '>(&character, &channel)))
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd == nullptr)
        return ATCE::EXIST;

    pl_sd->state.pvpchannel = channel;
    pl_sd->state.pvp_rank = 0;
    clif_pvpstatus(pl_sd); // send their channel to others

    return ATCE::OKAY;
}

static
ATCE atcommand_npcmove(Session *, dumb_ptr<map_session_data>,
        ZString message)
{
    NpcName character;
    int x = 0, y = 0;
    dumb_ptr<npc_data> nd = nullptr;

    if (!asplit(message, &x, &y, &character))
        return ATCE::USAGE;

    nd = npc_name2id(character);
    if (nd == nullptr)
        return ATCE::EXIST;

    npc_enable(character, 0);
    map_delblock(nd);
    nd->bl_x = x;
    nd->bl_y = y;
    map_addblock(nd);
    npc_enable(character, 1);

    return ATCE::OKAY;
}

static
ATCE atcommand_addwarp(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    MapName mapname;
    int x, y;

    if (!extract(message, record<' '>(&mapname, &x, &y)))
        return ATCE::USAGE;

    AString w3 = STRPRINTF("%s%d%d%d%d"_fmt, mapname, sd->bl_x, sd->bl_y, x, y);
    NpcName w3name = stringish<NpcName>(w3);

    ast::npc::Warp warp;
    warp.m.data = sd->mapname_;
    warp.x.data = sd->bl_x;
    warp.y.data = sd->bl_y;
    warp.name.data = w3name;
    warp.xs.data = 1;
    warp.ys.data = 1;
    warp.to_m.data = mapname;
    warp.to_x.data = x;
    warp.to_y.data = y;

    if (!npc_load_warp(warp))
        // warp failed
        return ATCE::RANGE;

    AString output = STRPRINTF("New warp NPC => %s"_fmt, w3);
    clif_displaymessage(s, output);

    return ATCE::OKAY;
}

static
ATCE atcommand_chareffect(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    CharName target;
    int type = 0;

    if (!asplit(message, &type, &target))
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(target);
    if (pl_sd == nullptr || (bool(pl_sd->status.option & Opt0::HIDE) && !pc_isGM(sd).detects(pc_isGM(pl_sd))))
        return ATCE::EXIST;

    clif_specialeffect(pl_sd, type, 0);
    clif_displaymessage(s, "Your Effect Has Changed."_s);

    return ATCE::OKAY;
}

static
ATCE atcommand_dropall(Session *, dumb_ptr<map_session_data> sd,
        ZString)
{
    for (IOff0 i : IOff0::iter())
    {
        if (sd->status.inventory[i].amount)
        {
            if (bool(sd->status.inventory[i].equip))
                pc_unequipitem(sd, i, CalcStatus::NOW);
            pc_dropitem(sd, i, sd->status.inventory[i].amount);
        }
    }
    return ATCE::OKAY;
}

static
ATCE atcommand_chardropall(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    CharName character;

    if (!asplit(message, &character))
        return ATCE::USAGE;
    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd == nullptr)
        return ATCE::EXIST;
    for (IOff0 i : IOff0::iter())
    {
        if (pl_sd->status.inventory[i].amount)
        {
            if (bool(pl_sd->status.inventory[i].equip))
                pc_unequipitem(pl_sd, i, CalcStatus::NOW);
            pc_dropitem(pl_sd, i, pl_sd->status.inventory[i].amount);
        }
    }

    clif_displaymessage(pl_sd->sess, "Ever play 52 card pickup?"_s);
    clif_displaymessage(s, "It is official.. you're a jerk."_s);

    return ATCE::OKAY;
}

static
ATCE atcommand_storeall(Session *s, dumb_ptr<map_session_data> sd,
        ZString)
{
    if (!sd->state.storage_open)
    {
        //Open storage.
        switch (storage_storageopen(sd))
        {
            case 2:
                //Try again
                clif_displaymessage(s, "run this command again.."_s);
                return ATCE::OKAY;
            case 1:
                //Failure
                clif_displaymessage(s,
                        "You can't open the storage currently."_s);
                return ATCE::EXIST;
        }
    }
    for (IOff0 i : IOff0::iter())
    {
        if (sd->status.inventory[i].amount)
        {
            if (bool(sd->status.inventory[i].equip))
                pc_unequipitem(sd, i, CalcStatus::NOW);
            storage_storageadd(sd, i, sd->status.inventory[i].amount);
        }
    }
    storage_storageclose(sd);

    clif_displaymessage(s, "It is done"_s);
    return ATCE::OKAY;
}

static
ATCE atcommand_charstoreall(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    CharName character;

    if (!asplit(message, &character))
        return ATCE::USAGE;
    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd == nullptr)
        return ATCE::EXIST;

    if (storage_storageopen(pl_sd) == 1)
    {
        // TODO figure out what the hell this is talking about,
        // and especially why it's different from the other one.
        clif_displaymessage(s,
                "Had to open the characters storage window..."_s);
        clif_displaymessage(s, "run this command again.."_s);
        return ATCE::OKAY;
    }
    for (IOff0 i : IOff0::iter())
    {
        if (pl_sd->status.inventory[i].amount)
        {
            if (bool(pl_sd->status.inventory[i].equip))
                pc_unequipitem(pl_sd, i, CalcStatus::NOW);
            storage_storageadd(pl_sd, i, sd->status.inventory[i].amount);
        }
    }
    storage_storageclose(pl_sd);

    clif_displaymessage(pl_sd->sess,
            "Everything you own has been put away for safe keeping."_s);
    clif_displaymessage(pl_sd->sess,
            "go to the nearest kafka to retrieve it.."_s);
    clif_displaymessage(pl_sd->sess, "   -- the management"_s);

    clif_displaymessage(s, "It is done"_s);

    return ATCE::OKAY;
}

static
ATCE atcommand_rain(Session *, dumb_ptr<map_session_data> sd,
        ZString)
{
    int effno = 0;
    effno = 161;
    if (effno < 0 || sd->bl_m->flag.get(MapFlag::RAIN))
        return ATCE::EXIST;

    sd->bl_m->flag.set(MapFlag::RAIN, 1);
    clif_specialeffect(sd, effno, 2);
    return ATCE::OKAY;
}

static
ATCE atcommand_snow(Session *, dumb_ptr<map_session_data> sd,
        ZString)
{
    int effno = 0;
    effno = 162;
    if (effno < 0 || sd->bl_m->flag.get(MapFlag::SNOW))
        return ATCE::EXIST;

    sd->bl_m->flag.set(MapFlag::SNOW, 1);
    clif_specialeffect(sd, effno, 2);
    return ATCE::OKAY;
}

static
ATCE atcommand_sakura(Session *, dumb_ptr<map_session_data> sd,
        ZString)
{
    int effno = 0;
    effno = 163;
    if (effno < 0 || sd->bl_m->flag.get(MapFlag::SAKURA))
        return ATCE::EXIST;

    sd->bl_m->flag.set(MapFlag::SAKURA, 1);
    clif_specialeffect(sd, effno, 2);
    return ATCE::OKAY;
}

static
ATCE atcommand_fog(Session *, dumb_ptr<map_session_data> sd,
        ZString)
{
    int effno = 0;
    effno = 233;
    if (effno < 0 || sd->bl_m->flag.get(MapFlag::FOG))
        return ATCE::EXIST;

    sd->bl_m->flag.set(MapFlag::FOG, 1);
    clif_specialeffect(sd, effno, 2);

    return ATCE::OKAY;
}

static
ATCE atcommand_leaves(Session *, dumb_ptr<map_session_data> sd,
        ZString)
{
    int effno = 0;
    effno = 333;
    if (effno < 0 || sd->bl_m->flag.get(MapFlag::LEAVES))
        return ATCE::EXIST;

    sd->bl_m->flag.set(MapFlag::LEAVES, 1);
    clif_specialeffect(sd, effno, 2);
    return ATCE::OKAY;
}

static
ATCE atcommand_adjcmdlvl(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    GmLevel newlev;
    XString cmd;

    if (!extract(message, record<' '>(&newlev, &cmd)))
    {
        clif_displaymessage(s, "usage: @adjcmdlvl <lvl> <command>."_s);
        return ATCE::USAGE;
    }

    Option<P<AtCommandInfo>> it_ = atcommand_info.search(cmd);
    {
        OMATCH_BEGIN_SOME (it, it_)
        {
            it->level = newlev;
            clif_displaymessage(s, "@command level changed."_s);
            return ATCE::OKAY;
        }
        OMATCH_END ();
    }

    clif_displaymessage(s, "@command not found."_s);
    return ATCE::EXIST;
}

static
ATCE atcommand_adjgmlvl(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    GmLevel newlev;
    CharName user;

    if (!asplit(message, &newlev, &user))
    {
        clif_displaymessage(s, "usage: @adjgmlvl <lvl> <user>."_s);
        return ATCE::USAGE;
    }

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(user);
    if (pl_sd == nullptr)
        return ATCE::EXIST;

    pc_set_gm_level(pl_sd->status_key.account_id, newlev);
    clif_updatestatus(pl_sd, SP::GM); // propagate to self
    clif_fixpcpos(pl_sd); // propagate to others

    return ATCE::OKAY;
}

static
ATCE atcommand_trade(Session *, dumb_ptr<map_session_data> sd,
        ZString message)
{
    CharName character;

    if (!asplit(message, &character))
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd)
    {
        trade_traderequest(sd, pl_sd->bl_id);
        return ATCE::OKAY_NOLOG;
    }
    return ATCE::EXIST;
}

/* Magic atcommands by Fate */

static
SkillID magic_skills[] =
{
    SkillID::TMW_MAGIC,
    SkillID::TMW_MAGIC_LIFE,
    SkillID::TMW_MAGIC_WAR,
    SkillID::TMW_MAGIC_TRANSMUTE,
    SkillID::TMW_MAGIC_NATURE,
    SkillID::TMW_MAGIC_ETHER,
};

constexpr
size_t magic_skills_nr = sizeof(magic_skills) / sizeof(magic_skills[0]);

static
LString magic_skill_names[magic_skills_nr] =
{
    "magic"_s,
    "life"_s,
    "war"_s,
    "transmute"_s,
    "nature"_s,
    "astral"_s,
};

static
ATCE atcommand_magic_info(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    CharName character;

    if (!asplit(message, &character))
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd)
    {
        AString buf = STRPRINTF(
                "`%s' has the following magic skills:"_fmt,
                character);
        clif_displaymessage(s, buf);

        for (size_t i = 0; i < magic_skills_nr; i++)
        {
            SkillID sk = magic_skills[i];
            buf = STRPRINTF(
                    "%d in %s"_fmt,
                    pl_sd->status.skill[sk].lv,
                    magic_skill_names[i]);
            if (pl_sd->status.skill[sk].lv)
                clif_displaymessage(s, buf);
        }

        return ATCE::OKAY;
    }

    clif_displaymessage(s, "Character not found."_s);
    return ATCE::EXIST;
}

static
void set_skill(dumb_ptr<map_session_data> sd, SkillID i, int level)
{
    level = std::min(level, MAX_SKILL_LEVEL);
    level = std::max(level, 0);
    sd->status.skill[i].lv = level;
}

static
ATCE atcommand_set_magic(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    CharName character;
    XString magic_type;
    int value;

    if (!asplit(message, &magic_type, &value, &character))
    {
        clif_displaymessage(s,
                "Usage: @setmagic <school> <value> <char-name>, where <school> is either `magic', one of the school names, or `all'."_s);
        return ATCE::USAGE;
    }

    SkillID skill_index = SkillID::NEGATIVE;
    if ("all"_s == magic_type)
        skill_index = SkillID::ZERO;
    else
    {
        for (size_t i = 0; i < magic_skills_nr; i++)
        {
            if (magic_skill_names[i] == magic_type)
            {
                skill_index = magic_skills[i];
                break;
            }
        }
    }

    if (skill_index == SkillID::NEGATIVE)
    {
        clif_displaymessage(s,
                "Incorrect school of magic.  Use `magic', `nature', `life', `war', `transmute', `ether', or `all'."_s);
        return ATCE::RANGE;
    }

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr)
    {
        if (skill_index == SkillID::ZERO)
            for (SkillID sk : magic_skills)
                set_skill(pl_sd, sk, value);
        else
            set_skill(pl_sd, skill_index, value);

        clif_skillinfoblock(pl_sd);
        return ATCE::OKAY;
    }

    clif_displaymessage(s, "Character not found."_s);
    return ATCE::EXIST;
}

static
ATCE atcommand_set_var(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    CharName character;
    XString vname;
    XString value;
    XString vindex;
    char prefix;
    char postfix;

    if (!asplit(message, &vname, &vindex, &value, &character))
    {
        clif_displaymessage(s,
                "Usage: @set <var> <index> <value> <char-name>"_s);
        return ATCE::USAGE;
    }

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    prefix = vname.front();
    postfix = vname.back();
    SIR reg = SIR::from(variable_names.intern(vname), atoi((RString(vindex)).c_str()));

    if (prefix != '.' && prefix != '$')
    {
        if (pl_sd == nullptr)
        {
            clif_displaymessage(s, "Character not found."_s);
            return ATCE::EXIST;
        }
    }

    if (postfix == '$')
    {
        set_reg(pl_sd, VariableCode::VARIABLE, reg, value);
    }
    else
    {
        int val = atoi((RString(value)).c_str());
        set_reg(pl_sd, VariableCode::VARIABLE, reg, val);
    }

    AString output = STRPRINTF("variable %s[%s] = `%s`."_fmt,
            RString(vname), RString(vindex), RString(value));

    if (pl_sd != nullptr)
    {
        output = STRPRINTF("variable %s[%s] = `%s` for player %s."_fmt,
            RString(vname), RString(vindex), RString(value), character);

        if (pl_sd->sess != sd->sess)
        {
            clif_displaymessage(pl_sd->sess, output);
        }
    }

    clif_displaymessage(sd->sess, output);
    return ATCE::OKAY;
}

static
ATCE atcommand_get_var(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    CharName character;
    XString vname;
    XString vindex;

    if (!asplit(message, &vname, &vindex, &character))
    {
        clif_displaymessage(s,
                "Usage: @get <var> <index> <char-name>"_s);
        return ATCE::USAGE;
    }

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    SIR reg = SIR::from(variable_names.intern(vname), atoi((RString(vindex)).c_str()));

    struct script_data dat = ScriptDataVariable{reg};
    get_val(pl_sd, &dat);

    RString rval;
    MATCH_BEGIN (dat)
    {
        MATCH_CASE (const ScriptDataStr&, u)
        {
            rval = u.str;
        }
        MATCH_CASE (const ScriptDataInt&, u)
        {
            rval = STRPRINTF("%i"_fmt, u.numi);
        }
    }
    MATCH_END ();

    AString output = STRPRINTF("variable %s[%s] == `%s` for player %s."_fmt,
            RString(vname), RString(vindex), rval, character);

    clif_displaymessage(sd->sess, output);
    return ATCE::OKAY;
}

static
ATCE atcommand_log(Session *, dumb_ptr<map_session_data>,
        ZString)
{
    return ATCE::OKAY;
    // only used for (implicit) logging
}

static
ATCE atcommand_tee(Session *, dumb_ptr<map_session_data> sd,
        ZString message)
{
    clif_message(sd, message);
    return ATCE::OKAY;
}

static
ATCE atcommand_invisible(Session *, dumb_ptr<map_session_data> sd,
        ZString)
{
    pc_invisibility(sd, 1);
    return ATCE::OKAY;
}

static
ATCE atcommand_visible(Session *, dumb_ptr<map_session_data> sd,
        ZString)
{
    pc_invisibility(sd, 0);
    return ATCE::OKAY;
}

static
ATCE atcommand_jump_iterate(Session *s, dumb_ptr<map_session_data> sd,
        dumb_ptr<map_session_data> (*get_start)(void),
        dumb_ptr<map_session_data> (*get_next)(dumb_ptr<map_session_data>))
{
    dumb_ptr<map_session_data> pl_sd;

    pl_sd = map_id_is_player(sd->followtarget);

    if (pl_sd)
        pl_sd = get_next(pl_sd);

    if (!pl_sd)
        pl_sd = get_start();

    for (int i = 0, e = map_getusers(); i <= e; ++i)
    {
        if (pl_sd != sd && !bool(pl_sd->status.option & Opt0::HIDE))
            break;

        // the target player is either hidden or is ourselves, so find another one
        pl_sd = get_next(pl_sd);
        if (!pl_sd)
            pl_sd = get_start();

        if (i == e)
        {
            // we reached the end of the list, and couldn't find anyone else
            if (e == map_getusers())
            {
                pl_sd = sd; // silently warp to ourselves if no new user came online
                break;
            }

            // or, if number of online players changed, try again
            i = 0;
            e = map_getusers();
        }
    }

    if (pl_sd->bl_m->flag.get(MapFlag::NOWARPTO)
        && !(pc_isGM(sd).satisfies(battle_config.any_warp_GM_min_level)))
    {
        clif_displaymessage(s,
                "You are not authorised to warp you to the map of this player."_s);
        return ATCE::PERM;
    }
    if (sd->bl_m->flag.get(MapFlag::NOWARP)
        && !(pc_isGM(sd).satisfies(battle_config.any_warp_GM_min_level)))
    {
        clif_displaymessage(s,
                "You are not authorised to warp you from your actual map."_s);
        return ATCE::PERM;
    }
    pc_setpos(sd, pl_sd->bl_m->name_, pl_sd->bl_x, pl_sd->bl_y, BeingRemoveWhy::WARPED);
    AString output = STRPRINTF("Jump to %s"_fmt, pl_sd->status_key.name);
    clif_displaymessage(s, output);

    sd->followtarget = pl_sd->bl_id;

    return ATCE::OKAY_NOLOG;
}

static
ATCE atcommand_iterate_forward_over_players(Session *s, dumb_ptr<map_session_data> sd, ZString)
{
    return atcommand_jump_iterate(s, sd, map_get_first_session, map_get_next_session);
}

static
ATCE atcommand_iterate_backwards_over_players(Session *s, dumb_ptr<map_session_data> sd, ZString)
{
    return atcommand_jump_iterate(s, sd, map_get_last_session, map_get_prev_session);
}

static
ATCE atcommand_wgm(Session *s, dumb_ptr<map_session_data> sd,
        ZString message)
{
    if (tmw_CheckChatSpam(sd, message))
        return ATCE::OKAY;

    tmw_GmHackMsg(STRPRINTF("[GM] %s: %s"_fmt, sd->status_key.name, message));
    if (!pc_isGM(sd))
        clif_displaymessage(s, "Message sent."_s);

    return ATCE::OKAY;
}


static
ATCE atcommand_skillpool_info(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    CharName character;

    if (!asplit(message, &character))
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr)
    {
        SkillID pool_skills[MAX_SKILL_POOL];
        int pool_skills_nr = skill_pool(pl_sd, pool_skills);
        int i;

        AString buf = STRPRINTF(
                "Active skills %d out of %d for %s:"_fmt,
                pool_skills_nr, skill_pool_max(pl_sd), character);
        clif_displaymessage(s, buf);
        for (i = 0; i < pool_skills_nr; ++i)
        {
            buf = STRPRINTF(" - %s [%d]: power %d"_fmt,
                    skill_name(pool_skills[i]),
                    pool_skills[i],
                    skill_power(pl_sd, pool_skills[i]));
            clif_displaymessage(s, buf);
        }

        buf = STRPRINTF("Learned skills out of %zu for %s:"_fmt,
                skill_pool_skills.size(), character);
        clif_displaymessage(s, buf);

        for (i = 0; i < skill_pool_skills.size(); ++i)
        {
            const RString& name = skill_name(skill_pool_skills[i]);
            int lvl = pl_sd->status.skill[skill_pool_skills[i]].lv;

            if (lvl)
            {
                buf = STRPRINTF(" - %s [%d]: lvl %d"_fmt,
                        name, skill_pool_skills[i], lvl);
                clif_displaymessage(s, buf);
            }
        }

    }
    else
    {
        clif_displaymessage(s, "Character not found."_s);
        return ATCE::EXIST;
    }

    return ATCE::OKAY;
}

static
ATCE atcommand_skillpool_focus(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    CharName character;
    SkillID skill;

    if (!asplit(message, &skill, &character))
    {
        clif_displaymessage(s, "Usage: @sp-focus <skill-nr> <char_name>"_s);
        return ATCE::USAGE;
    }

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr)
    {
        if (skill_pool_activate(pl_sd, skill))
            clif_displaymessage(s, "Activation failed."_s);
        else
            clif_displaymessage(s, "Activation successful."_s);
    }
    else
        clif_displaymessage(s, "Character not found."_s);

    return ATCE::OKAY;
}

static
ATCE atcommand_skillpool_unfocus(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    CharName character;
    SkillID skill;

    if (!asplit(message, &skill, &character))
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr)
    {
        if (skill_pool_deactivate(pl_sd, skill))
            clif_displaymessage(s, "Deactivation failed."_s);
        else
            clif_displaymessage(s, "Deactivation successful."_s);
    }
    else
        clif_displaymessage(s, "Character not found."_s);

    return ATCE::OKAY;
}

//static
ATCE atcommand_skill_learn(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    CharName character;
    SkillID skill;
    int level;

    if (!asplit(message, &skill, &level, &character))
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd != nullptr)
    {
        set_skill(pl_sd, skill, level);
        clif_skillinfoblock(pl_sd);
    }
    else
        clif_displaymessage(s, "Character not found."_s);

    return ATCE::OKAY;
}

static
ATCE atcommand_ipcheck(Session *s, dumb_ptr<map_session_data>,
        ZString message)
{
    CharName character;

    if (!asplit(message, &character))
        return ATCE::USAGE;

    dumb_ptr<map_session_data> pl_sd = map_nick2sd(character);
    if (pl_sd == nullptr)
    {
        clif_displaymessage(s, "Character not found."_s);
        return ATCE::EXIST;
    }

    IP4Address ip = pl_sd->get_ip();

    // We now have the IP address of a character.
    // Loop over all logged in sessions looking for matches.

    for (io::FD i : iter_fds())
    {
        Session *s2 = get_session(i);
        if (!s2)
            continue;
        pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get()));
        if (pl_sd && pl_sd->state.auth)
        {
            // Is checking GM levels really needed here?
            if (ip == pl_sd->get_ip())
            {
                AString output = STRPRINTF(
                        "Name: %s | Location: %s %d %d"_fmt,
                        pl_sd->status_key.name, pl_sd->mapname_,
                        pl_sd->bl_x, pl_sd->bl_y);
                clif_displaymessage(s, output);
            }
        }
    }

    clif_displaymessage(s, "End of list"_s);
    return ATCE::OKAY;
}

static
ATCE atcommand_doomspot(Session *s, dumb_ptr<map_session_data> sd,
        ZString)
{
    for (io::FD i : iter_fds())
    {
        Session *s2 = get_session(i);
        if (!s2)
            continue;
        dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get()));
        if (pl_sd && !pl_sd->state.connect_new
            && pl_sd->state.auth && s2 != s && sd->bl_m == pl_sd->bl_m
            && sd->bl_x == pl_sd->bl_x && sd->bl_y == pl_sd->bl_y
            && pc_isGM(sd).overwhelms(pc_isGM(pl_sd)))
        {
            // you can doom only lower or same gm level
            pc_damage(nullptr, pl_sd, pl_sd->status.hp + 1);
            clif_displaymessage(pl_sd->sess, "The holy messenger has given judgement."_s);
        }
    }
    clif_displaymessage(s, "Judgement was made."_s);

    return ATCE::OKAY;
}

static
ATCE atcommand_source(Session *s, dumb_ptr<map_session_data>,
        ZString)
{
    clif_displaymessage(s, VERSION_INFO_HEADER);
    clif_displaymessage(s, VERSION_INFO_COMMIT);
    clif_displaymessage(s, VERSION_INFO_NUMBER);
    clif_displaymessage(s, VERSION_INFO_URL);

    return ATCE::OKAY;
}



// declared extern above
Map<XString, AtCommandInfo> atcommand_info =
{
    {"help"_s, {"[level[-level]|category|@command]"_s,
        0, atcommand_help,
        "Show help"_s}},
    {"setup"_s, {"<level> <charname>"_s,
        40, atcommand_setup,
        "Safely set a chars levels and warp them to a special place (for TAW)"_s}},
    {"charwarp"_s, {"<mapname> <x> <y> <charname>"_s,
        60, atcommand_charwarp,
        "Warp a character to a point on another map"_s}},
    {"warp"_s, {"<mapname> [x] [y]"_s,
        40, atcommand_warp,
        "Warp yourself to another map"_s}},
    {"where"_s, {"[charname]"_s,
        40, atcommand_where,
        "Show location of a character or yourself"_s}},
    {"goto"_s, {"<charname>"_s,
        40, atcommand_goto,
        "Warp yourself to another character"_s}},
    {"npc"_s, {"<npc>"_s,
        40, atcommand_npc,
        "Warp yourself to a npc"_s}},
    {"jump"_s, {"[x] [y]"_s,
        40, atcommand_jump,
        "Warp yourself within a map"_s}},
    {"who"_s, {"[subsequence]"_s,
        40, atcommand_who,
        "List matching players online, with location info"_s}},
    {"whogroup"_s, {"[subsequence]"_s,
        40, atcommand_whogroup,
        "List matching players online, with party info"_s}},
    {"whomap"_s, {"[mapname]"_s,
        40, atcommand_whomap,
        "List all players on the map, with location info"_s}},
    {"whomapgroup"_s, {"[mapname]"_s,
        40, atcommand_whomapgroup,
        "List all players on the map, with party info"_s}},
    {"whogm"_s, {"[subsequence]"_s,
        40, atcommand_whogm,
        "List matching GM players, with location, level, and party info"_s}},
    {"save"_s, {""_s,
        40, atcommand_save,
        "Set your respawn point to your current location"_s}},
    {"return"_s, {""_s,
        40, atcommand_load,
        "Return to your respawn point"_s}},
    {"load"_s, {""_s,
        40, atcommand_load,
        "Return to your respawn point"_s}},
    {"speed"_s, {"<rate>"_s,
        60, atcommand_speed,
        "Set walk rate"_s}},
    {"storage"_s, {""_s,
        98, atcommand_storage,
        "Open your storage"_s}},
    {"option"_s, {"<opt1> [opt2] [option]"_s,
        80, atcommand_option,
        "Set your 'option' status flags"_s}},
    {"hide"_s, {""_s,
        40, atcommand_hide,
        "Toggle invisibility from monsters and certain commands"_s}},
    {"die"_s, {""_s,
        40, atcommand_die,
        "Cause fatal damage to yourself"_s}},
    {"kill"_s, {"<charname>"_s,
        60, atcommand_kill,
        "Cause fatal damage to another player"_s}},
    {"alive"_s, {""_s,
        60, atcommand_alive,
        "Restore life to yourself"_s}},
    {"kami"_s, {"<message ...>"_s,
        98, atcommand_kami,
        "Send an anonymous broadcast"_s}},
    {"heal"_s, {"[hp] [sp]"_s,
        40, atcommand_heal,
        "Restore or destroy your health"_s}},
    {"item"_s, {"<item-name-or-id> [count]"_s,
        80, atcommand_item,
        "Summon items out of the void"_s}},
    {"itemreset"_s, {""_s,
        40, atcommand_itemreset,
        "Cast all of your itens into the void (why would you ever want this?)"_s}},
    {"itemcheck"_s, {""_s,
        80, atcommand_itemcheck,
        "Perform an internal integrity check on your items"_s}},
    {"blvl"_s, {"<delta>"_s,
        60, atcommand_baselevelup,
        "Adjust your level"_s}},
    {"jlvl"_s, {"<delta>"_s,
        60, atcommand_joblevelup,
        "Adjust your job level"_s}},
    {"pvpoff"_s, {""_s,
        60, atcommand_pvpoff,
        "Enable PvP on your map"_s}},
    {"exprate"_s, {"<percent>"_s,
        60, atcommand_exprate,
        "Set base and job exp rate"_s}},
    {"bexprate"_s, {"<percent>"_s,
        60, atcommand_bexprate,
        "Set base exp rate"_s}},
    {"jexprate"_s, {"<percent>"_s,
        60, atcommand_jexprate,
        "Set job exp rate"_s}},
    {"rates"_s, {""_s,
        0, atcommand_rates,
        "Show base and job exp rates"_s}},
    {"pvpon"_s, {""_s,
        60, atcommand_pvpon,
        "Disable PvP on your map"_s}},
    {"model"_s, {"<style> [color] [dye]"_s,
        98, atcommand_model,
        "Change your hairstyle and hair color"_s}},
    {"mobinfo"_s, {"<mob-id-or-name>"_s,
        20, atcommand_mobinfo,
        "Show stats of a monster."_s}},
    {"summon"_s, {"<mob-id-or-name>"_s,
        50, atcommand_summon,
        "Summon a slave monster temporarily"_s}},
    {"spawn"_s, {"<mob-name-or-id> [count] [x] [y]"_s,
        50, atcommand_spawn,
        "Spawn normal monsters at location."_s}},
    {"killmonster"_s, {"[map]"_s,
        60, atcommand_killmonster,
        "Kill all monsters (with drops)"_s}},
    {"killmonster2"_s, {"[map]"_s,
        60, atcommand_killmonster2,
        "Kill all monsters (no drops)"_s}},
    {"gat"_s, {""_s,
        98, atcommand_gat,
        "Dump the local walkmap"_s}},
    {"packet"_s, {"<type> <flag>"_s,
        98, atcommand_packet,
        "Force a status change"_s}},
    {"stpoint"_s, {"<amount>"_s,
        60, atcommand_statuspoint,
        "Increase your stat points"_s}},
    {"skpoint"_s, {"<amount>"_s,
        60, atcommand_skillpoint,
        "Increase your skill points"_s}},
    {"zeny"_s, {"<amount>"_s,
        80, atcommand_zeny,
        "Change how much money you have"_s}},
    {"str"_s, {"<delta>"_s,
        60, atcommand_param<ATTR::STR>,
        "Adjust your strength"_s}},
    {"agi"_s, {"<delta>"_s,
        60, atcommand_param<ATTR::AGI>,
        "Adjust your agility"_s}},
    {"vit"_s, {"<delta>"_s,
        60, atcommand_param<ATTR::VIT>,
        "Adjust your vitality"_s}},
    {"int"_s, {"<delta>"_s,
        60, atcommand_param<ATTR::INT>,
        "Adjust your intelligence\0(TODO make this work in real life, I'm lonely)"_s}},
    {"dex"_s, {"<delta>"_s,
        60, atcommand_param<ATTR::DEX>,
        "Adjust your dexterity"_s}},
    {"luk"_s, {"<delta>"_s,
        60, atcommand_param<ATTR::LUK>,
        "Adjust your luck"_s}},
    {"recall"_s, {"<charname>"_s,
        60, atcommand_recall,
        "Warp a player to you"_s}},
    {"revive"_s, {"<charname>"_s,
        60, atcommand_revive,
        "Restore a player to full health"_s}},
    {"charstats"_s, {"<charname>"_s,
        60, atcommand_character_stats,
        "Show a bunch of stats about a single user"_s}},
    {"charstatsfull"_s, {"<charname>"_s,
        60, atcommand_character_stats_full,
        "Show a bunch of stats about a single user"_s}},
    {"charstatsall"_s, {""_s,
        60, atcommand_character_stats_all,
        "Show a bunch of stats about all online users"_s}},
    {"charoption"_s, {"<opt1> <opt2> <opt3> <charname>"_s,
        80, atcommand_character_option,
        "Set option flags on another character"_s}},
    {"charsave"_s, {"<map> <x> <y> <charname>"_s,
        60, atcommand_character_save,
        "Set another character's save point"_s}},
    {"doom"_s, {""_s,
        80, atcommand_doom,
        "Kill everyone on the server"_s}},
    {"doommap"_s, {""_s,
        80, atcommand_doommap,
        "Kill everyone on your map"_s}},
    {"raise"_s, {""_s,
        80, atcommand_raise,
        "Resurrect all players on the server"_s}},
    {"raisemap"_s, {""_s,
        80, atcommand_raisemap,
        "Resurrect all players on your map"_s}},
    {"charbaselvl"_s, {"<delta> <charname>"_s,
        60, atcommand_character_baselevel,
        "Adjust another character's level"_s}},
    {"charjlvl"_s, {"<delta> <charname>"_s,
        60, atcommand_character_joblevel,
        "Adjust another character's job level"_s}},
    {"kick"_s, {"<charname>"_s,
        40, atcommand_kick,
        "Transiently kick a player off the server"_s}},
    {"kickall"_s, {""_s,
        98, atcommand_kickall,
        "Transiently kick all players off the server"_s}},
    {"questskill"_s, {"<skill-id>"_s,
        98, atcommand_questskill,
        "Give yourself a quest (?) skill"_s}},
    {"charquestskill"_s, {"<skill-id> <charname>"_s,
        98, atcommand_charquestskill,
        "Give another player a quest (?) skill"_s}},
    {"lostskill"_s, {"<skill-id>"_s,
        80, atcommand_lostskill,
        "Take away one of your quest (?) skills"_s}},
    {"charlostskill"_s, {"<skill-id> <charname>"_s,
        98, atcommand_charlostskill,
        "Take away one of another player's quest (?) skills"_s}},
    {"party"_s, {"<name>"_s,
        98, atcommand_party,
        "Create a new party"_s}},
    {"setpartyleader"_s, {"<party-name-or-id> <flag> <player>"_s,
        40, atcommand_setpartyleader,
        "Change the leader of a party"_s}},
    {"setleader"_s, {"<player>"_s,
        0, atcommand_setleader,
        "Add/remove a leader to the current party"_s}},
    {"mapexit"_s, {""_s,
        98, atcommand_mapexit,
        "Try to kill the server kindly"_s}},
    {"idsearch"_s, {"<item-subseq>"_s,
        80, atcommand_idsearch,
        "Search for some items that might match"_s}},
    {"mapmove"_s, {"<mapname> [x] [y]"_s,
        40, atcommand_warp,
        "Warp to a different map"_s}},
    {"broadcast"_s, {"<message ...>"_s,
        40, atcommand_broadcast,
        "Broadcast a message from you"_s}},
    {"localbroadcast"_s, {"<message ...>"_s,
        40, atcommand_localbroadcast,
        "Broadcast a message from you locally"_s}},
    {"recallall"_s, {""_s,
        80, atcommand_recallall,
        "Warp every online player to your current map"_s}},
    {"charskreset"_s, {"<charname>"_s,
        60, atcommand_charskreset,
        "Reset a player's skill points"_s}},
    {"charstreset"_s, {"<charname>"_s,
        60, atcommand_charstreset,
        "Reset a player's stat points"_s}},
    {"charreset"_s, {"<charname>"_s,
        60, atcommand_charreset,
        "Reset a player's skills, stats, and magic"_s}},
    {"charmodel"_s, {"<hairstyle> <hair-color> <dye> <charname>"_s,
        98, atcommand_charmodel,
        "Change another character's appearance"_s}},
    {"charskpoint"_s, {"<amount> <charname>"_s,
        60, atcommand_charskpoint,
        "Adjust another player's skill points"_s}},
    {"charstpoint"_s, {"<amount> <charname>"_s,
        60, atcommand_charstpoint,
        "Adjust another player's stat points"_s}},
    {"charzeny"_s, {"<delta> <charname>"_s,
        80, atcommand_charzeny,
        "Adjust another player's money"_s}},
    {"mapinfo"_s, {"<0-2> [map]"_s,
        98, atcommand_mapinfo,
        "Show some stats for the map. 1 also shows players, 2 also shows NPCs"_s}},
    {"dye"_s, {"<dye>"_s,
        40, atcommand_dye,
        "Don't use"_s}},
    {"ccolor"_s, {"<dye>"_s,
        40, atcommand_dye,
        "Don't use"_s}},
    {"hairstyle"_s, {"<style>"_s,
        40, atcommand_hair_style,
        "Change your hairstyle"_s}},
    {"haircolor"_s, {"<color>"_s,
        40, atcommand_hair_color,
        "Change your hair color"_s}},
    {"allstats"_s, {"[value]"_s,
        60, atcommand_all_stats,
        "Adjust all stats by value (or maximum)"_s}},
    {"charchangesex"_s, {"<charname> <sex>"_s,
        60, atcommand_char_change_sex,
        "Change a characters sex and disconnect them"_s}},
    {"block"_s, {"<charname>"_s,
        60, atcommand_char_block,
        "Permanently block a player's account from the server"_s}},
    {"unblock"_s, {"<charname>"_s,
        60, atcommand_char_unblock,
        "Remove a permanent block from a player's account"_s}},
    {"ban"_s, {"<timedelta> <charname>"_s,
        60, atcommand_char_ban,
        "Ban a player's account from the server for a limited time"_s}},
    {"unban"_s, {"<timedelta> <charname>"_s,
        60, atcommand_char_unban,
        "Remove a limited ban from a player's account"_s}},
    {"partyspy"_s, {"<party-name-or-id>"_s,
        98, atcommand_partyspy,
        "Listen to all chat within a party"_s}},
    {"partyrecall"_s, {"<party-name-or-id>"_s,
        98, atcommand_partyrecall,
        "Warp all members of a party to you"_s}},
    {"enablenpc"_s, {"<npc-name>"_s,
        80, atcommand_enablenpc,
        "Enable an NPC for visibility"_s}},
    {"disablenpc"_s, {"<npc-name>"_s,
        80, atcommand_disablenpc,
        "Disable an NPC for visibility"_s}},
    {"servertime"_s, {""_s,
        0, atcommand_servertime,
        "Print the server's idea of the current time"_s}},
    {"chardelitem"_s, {"<item-name-or-id> <count> <charname>"_s,
        60, atcommand_chardelitem,
        "Delete items from a player's inventory"_s}},
    {"listnearby"_s, {""_s,
        40, atcommand_list_nearby,
        "Print name of all nearby players"_s}},
    {"email"_s, {"<actual@email> <new@email>"_s,
        0, atcommand_email,
        "Changed your account's email"_s}},
    {"effect"_s, {"<type> <flag>"_s,
        98, atcommand_effect,
        "Apply a special effect to yourself (or everyone! wtf?)"_s}},
    {"charitemlist"_s, {"<charname>"_s,
        98, atcommand_character_item_list,
        "List a player's items"_s}},
    {"charstoragelist"_s, {"<charname>"_s,
        98, atcommand_character_storage_list,
        "List a player's storage"_s}},
    {"addwarp"_s, {"<mapname> <x> <y>"_s,
        80, atcommand_addwarp,
        "Create a new permanent warp"_s}},
    {"pvp"_s, {""_s,
        0, atcommand_pvp,
        "Toggle your pvp flag"_s}},
    {"npcmove"_s, {"<x> <y> <npc-name>"_s,
        80, atcommand_npcmove,
        "Force an NPC to move on the map"_s}},
    {"charpvp"_s, {"<charname> <channel>"_s,
        40, atcommand_charpvp,
        "Set the pvp channel of another player"_s}},
    {"chareffect"_s, {"<type> <target>"_s,
        40, atcommand_chareffect,
        "Apply effect type with arg 0 to a player"_s}},
    {"dropall"_s, {""_s,
        98, atcommand_dropall,
        "Drop all of your items"_s}},
    {"chardropall"_s, {"<charname>"_s,
        60, atcommand_chardropall,
        "Force a player to drop all of their items"_s}},
    {"storeall"_s, {""_s,
        60, atcommand_storeall,
        "Store all of your items"_s}},
    {"charstoreall"_s, {"<charname>"_s,
        60, atcommand_charstoreall,
        "Store all of a player's items"_s}},
    {"rain"_s, {""_s,
        98, atcommand_rain,
        "Enable the rain mapflag"_s}},
    {"snow"_s, {""_s,
        98, atcommand_snow,
        "Enable the snow mapflag"_s}},
    {"sakura"_s, {""_s,
        98, atcommand_sakura,
        "Enable the sakura mapflag"_s}},
    {"fog"_s, {""_s,
        98, atcommand_fog,
        "Enable the fog mapflag"_s}},
    {"leaves"_s, {""_s,
        98, atcommand_leaves,
        "Enable the leaves mapflag"_s}},
    {"adjgmlvl"_s, {"<level> <charname>"_s,
        98, atcommand_adjgmlvl,
        "Temporarily adjust the GM level of a player"_s}},
    {"adjcmdlvl"_s, {"<level> <command>"_s,
        98, atcommand_adjcmdlvl,
        "Temporarily adjust the GM level of a command"_s}},
    {"trade"_s, {"<charname>"_s,
        60, atcommand_trade,
        "Initiate trade with a player anywhere"_s}},
    {"charwipe"_s, {"<charname>"_s,
        60, atcommand_char_wipe,
        "Reset a character almost completely"_s}},
    {"setmagic"_s, {"<school> <value> <charname>"_s,
        80, atcommand_set_magic,
        "Force magic skill level"_s}},
    {"setvar"_s, {"<variable> <index> <value> <charname>"_s,
        40, atcommand_set_var,
        "Sets an arbitrary variable."_s}},
    {"getvar"_s, {"<variable> <index> <charname>"_s,
        40, atcommand_get_var,
        "Gets the value of an arbitrary variable."_s}},
    {"magicinfo"_s, {"<charname>"_s,
        80, atcommand_magic_info,
        "Show magic skills of a palyer"_s}},
    {"log"_s, {"<message ...>"_s,
        40, atcommand_log,
        "Write something directly to the log"_s}},
    {"l"_s, {"<message ...>"_s,
        40, atcommand_log,
        "Write something directly to the log"_s}},
    {"tee"_s, {"<message ...>"_s,
        40, atcommand_tee,
        "Duplicate a message to the log and public chat"_s}},
    {"t"_s, {"<message ...>"_s,
        40, atcommand_tee,
        "Duplicate a message to the log and public chat"_s}},
    {"invisible"_s, {""_s,
        50, atcommand_invisible,
        "Make yourself invisible to players"_s}},
    {"visible"_s, {""_s,
        50, atcommand_visible,
        "Make yourself visible to players"_s}},
    {"hugo"_s, {""_s,
        60, atcommand_iterate_forward_over_players,
        "Jump to the next player"_s}},
    {"linus"_s, {""_s,
        60, atcommand_iterate_backwards_over_players,
        "Jump to the previous player"_s}},
    {"sp-info"_s, {"<charname>"_s,
        40, atcommand_skillpool_info,
        "Show info about pool skills"_s}},
    {"sp-focus"_s, {"<skill-id> <charname>"_s,
        80, atcommand_skillpool_focus,
        "Focus on a pool skill"_s}},
    {"sp-unfocus"_s, {"<skill-id> <charname>"_s,
        80, atcommand_skillpool_unfocus,
        "Unfocus off of a pool skill"_s}},
    {"skill-learn"_s, {"<skill-id> <level> <charname>"_s,
        80, atcommand_skill_learn,
        "Change a skill level"_s}},
    {"wgm"_s, {"<message ...>"_s,
        0, atcommand_wgm,
        "Send a message to online GMs"_s}},
    {"ipcheck"_s, {"<charname>"_s,
        60, atcommand_ipcheck,
        "List players on the same IP address"_s}},
    {"doomspot"_s, {""_s,
        60, atcommand_doomspot,
        "Kill all players on the same tile"_s}},
    {"source"_s, {""_s,
        0, atcommand_source,
        "Legal information about source code (must be a level 0 command!)"_s}},
};
} // namespace map
} // namespace tmwa