summaryrefslogblamecommitdiff
path: root/src/map/skill.cpp
blob: 3050012bf77cf276eaa9a29d7529f8ad723df08b (plain) (tree)
1
2
3
4
5
6
7
8
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
                    
 



                  
 
                                


                               
 



                     
                    




                     
 
                                   
 
                                 
                                                                        








                                                                    
                                                     



                            
                                               



                            

                                                              







                            
                                               



                            
                                                  
          
                                                  
                            


                                                              










                            
                                                     





                            
                                                        








                            

                                         



                            



                                                                    

                            
                  
                            



                                                                 
                            
                                                                 














                            
                                                        



















                            



                                                                          





















                            

                                                           
                            

                                                                    
           

                                                                    
                            
                                                     











                            
                                                        
                            
                                                           
















                            
                       





























                            
               

                            
               

                            
                     







                            



                   
















                            



                 











                            
                 


                            
                     

                            



                     









                            

                      
           

                        



                            
                



                            



                       
                            



                     


















                            



                    
           



                  


                            
                  
                            
               
           


                 

                            
                 
                            


                    
           

                       
























                            




                     
           


                 


                            
                  

                            
              











                            
                 

                            

                

                            
                 
                            
                 
           
                   




                            
                  
                            

                 


                            



                   














                            

  

                                    



































































































































































































































































































































































































































































                                                                          
                                     

  



                                                  
 

            
 
                                                        
 



                                                                  
                                                
      
                                                        
                                                       
                                                                   























                                                                          
 
                             



                            
                             



                            
                            



                           
                            



                           
                             



                            
                                   



                                  
                                       



                                                      
      
                                    



                                                   
                                    



                                                   
      
                                      



                                                     
                                     



                                                    
                                      



                                                     
                                       



                                                      
                                      



                                                            
                                       



                                                             
                                 



                                      
                                    



                               
                              



                             
                                  



                                 
                                           



                                                          
      
                                     



                                                    
      
                                           


                                                          
 
                        
      
                                                                  


                                                                         
                                                                 
      

                                                                                  
      

                                                                      
      
                                                      
      
                                                                             
      

                                                            
      

                                              

                                            

                                                            


                 
                          









                                                                            

 

                                            
 
               
 

                      
                             

 
                                                                                         
      
                                           

 


                           
                                                                 
                         
                                                                 
                     
                                                                           
                           
                                                  
                          
                                                           
                       
                                                                    
                       
                                                  
                             
                                                              
                            
                                                              
                            
                                                              
                       
                                                           
                          
                                                                          
                          
                                                           
                          
                                                                                                 
                           
                                                           
                           
                                                                              
                          
                                                              
                        
                                                           
                         
                                                        
                          
                                                           
                         
                                                              
                           
                                                           
                          
                                                        
                         
                                                        
                          
                                                                          
                        
                                                     
                        
                                                        
                             
                                                                    
                             
                                                                    
                        
                                                     
                       
                                                     
                            
                                                                 
                              
                                                                 
                        
                                               
                           
                                                        
                             
                                                     
                                
                                                        
                               
                                                                 
                          
                                                     
                          
                                                     
                          
                                                                       
                           
                                                  
                        
                                            
                              
                                                                    
                          
                                                     
                          
                                                           
                          
                                                              
                        
                                                  
                             
                                                              
                            
                                                     
                              
                                                                 
                         
                                                        
                              
                                                                    
                            
                                                              
                       
                                                  
                         
                                                  
                        
                                                           
                          
                                                                 


             




                                                         









                                      


                                            
                        

                                            
                                                                          
                                                                          
                                               
 


                                          
 

                      
 


                                                            
 

                    


                    
 

                           
                                                         


                                 
                                                                 


                                 
                                                           
                                  
                                                        
 
                     



                                                            
                                 
                     



                                                              




                                               

















                             
                                                             
                           

                                                                
                                                                     
             

                                                              
                                                                         
                                                      
             
                                 
                                             
                                                                

                                       
                                                                     
                 
                                              
                      
                        
                                                           

                  
 
                                                                   
                                                                    
             


                                                                            


                                                                             
 

                                                                   


                                                                             



                                               
                                                       

                  
 
                                                          


                                                                             


                                              
                                                                   
                                    


                                                                             


                                              

                                                             

                                                        
                                                               
                                        


                                                                             

                                              
                                                   

                  
                                                          
         
                                                                                      



                                                 

                                                                           





                                                                            
                                                       


                                                                             


                                              
                                                                         



                                                                
                                        

                  
                                                    


                                                                             

                                              
                                              


                                                                             


                                              
                                              


                                                                             


                                              
                                                          


                                                                             


                                              
                                                          
         



                                                                                                                                                                             



                                              
                                                             


                                                                             


                                              
                                                                


                                                                             
                                              


                                                                             


                                              


                                                                             



                                              


                                                                             


                                              
                                              


                                                                             


                                              
                                                   

                               
                                         
                                                       
                                                            
                                                                             


                                              





                                                                         
                               





                                                                         
                            
                            

                                                                     
                                                      


                                                                         
                                        
                                                       
                                                            
                                                                             


                                              





                                                                             
                             
                                        
                                                       
                                                            
                                                                             




                                              
                                                                     

                           
                                       

                  


                                                                                             
                       


                                                                             


                                              


                                                                             

                                              


                                                             
                          


                                                                             

                                              
 
                             


                                                                             

                                              
                                                                   


                                                                            

                                                                            
                                                          


                                                                             

                                              

                                                                               
                                           
                 
                                                                    
                              


                                                                             


                                              

                                                             


                                                                             

                                              
                                                                
         
                                                        
                                                                        
                              

                                                                         


                                               
                                                              


                                                                                                                               
                                              


                                                                             

                                              

                                                                              
                                                                           
                                                        
                                                                             


                  


                                              























                                                       
 




















                                                     
         


                                                                               
 





                                                                  
 












                                                                               


             


                                                                           
                                     
                                                                           
      
                                                                             
 

                                     

                            
                  



                                       

                       


                              
                                                            


                                    
                                                    


                                      
                                                      


                 
 
                                               
                                                                                            






                                                
                                         






                                
                                                                 






                                                       
                                      




                              

                              






                                         
                               


         
                                      



                
                                                                    


                                                                     
                                
                



                                                                      


           
                                                                 


        
                                                                                    
                      
                                 


                       
                                 
                                                           




                                                                                                                       
  


           
                                                                             


                                                                    
                                  




                               



                                                                     



                                         
                                                                                                  

             

 

                                                                            

                                       


                                                                  
                                    
                                                   


                                                                           


                                                                  
 
                      
                                                     
                         
 
                


                     
 
                                     
 

                                                                                           
                 
                                                                                                      
                 
                                                                                                                                        
                 
                                                                                                                                            
                 
                                                                                                                                     
                 
                                                            

                                                  
                                                             
                                                                                                         

                     
                                                                                              

                                

                                                                                           

                     
                                                                                                                                                                        
                 
                                                                                                                                
                 
                                                                                                                                
                 
 
                                   
 

                            
                                                                                                       
 
                                         


                                           
                       

                                                                                             
                              
                                                      
                                                                                              


                                                                                           
                            
                                                                        
                            
                                                      

                                                                  


                                                                                                                                                
             
                                                                                                     
                                                                  
                                                                                                                                                    
         
     
                                         
 
                                      
 

                 
 

                                    
 
                                                                         
                          
 
                                 
                                                       
                                      
                                                                 
                      
                                                                             
     
 
                                              


                                                                      
                       
                                      

                                     

                                                                                                                  
                                                                                 
                                                                                                                                               
                                                                                                                      
 


                                                              

                                                                 
         

                                       

                                           


                                                                        
             

                                                                                                                                     
                                                            

                                                                     
                                                           
                                              
                                                            
                                               
                                                                                                                      
 


                                                             

                                                                 
         

                                       

                                         


                                                                         
             
                                                                                                          
                                                                                                                      
 


                                                               

                                                                 
         

                                         

                                          


                                                                         
             
                                                                                                                                     
                                                           

                                                                    
                                                                                                                      
 


                                                                   

                                                                 
         
                                         
     

                                              
                        



                                    












                                                                          



                                     
                                                                                                                  
                                      
                                                          
                                  
                                                   
                                                                              
                                
                                                        
                                                                   





                                                                              

                                                                                                



                                
                                          
                                                          
                                  
                                                   
                                                                              
                                
                                                       
                                                                   






                                                                             
                                                                          
     
                                
 


                            
                                                                      



                                                            
                                                                       





                                                                 
                                                                       

                                                         
                                                                      
     
                          
                                                                                
                                      
                                                
            
                                                 
                               
                                                   
            
                            

     
                         
                                              
                                          
                                          
                                              
                                         
     

                                                                
                                    

                                                                       


                                                                    
     
  

                                                                                                                              
                                
















                                                                                                                        
  
                                                       


                                                                     
                       
                                                        

                           
                                                                  
                                                            
                                                                                              

                                                             
                               

                                                                
                               


                                                
                                                                   


                                           
                                                                   


             
 



                                     


                                                                      
                           
                       
                                               
                                              

                                                        
         
                                                 
                                               

                                                          
         
                                                   
                                              

                                                        
         
                                                     
                                               

                                                          

                     
                                


                                                           
                                           
 

                                     



                                                     
                                                
                                                                      
                                                        

     
                           
 
                                                                

 

                                                                 

                           


                                                               
                                                    
 
                    

                                                                        
               
 

                                                      

 
      
                                                                                                        
 
                            
                     
                              
                  
 
                    
                                    

                                                 
               

                     
               
 


                                                                         
                   




                                                                        
                   





                                                                        
                   



                                         
                   

        
               

























                                                                    

 
                                                                           
 
              
 


                                                                                              
 
             

 
      
                                                               
 
                    
                   
 
                                                                      
               
 
                                                                       
               
 
           

 
                                                           
 
              
 

                                                                         
                                          
 
             


                                                                           
                                                   
   

                            
      
                                                                  
                                        
 




                                               
             





                                            

                                                                           
 

                                       
                                                    
                                        
              
 
                     
 
                          
               
 

                           
                                                          



                                         
                                                  



                                         
               
 
                     




                              
                                           



                                           
                                                                                                          





                                                   
                   
                                                                   
                   
                                
                   
                                
                   
                                 
                                                            
                                              
                   



                                



                                                       

                                         

                                            
                                     

                                               
                                                                             









                                                 
                                                                     
                                                   
                                                                         

                                                                    
                                                                          




                                                                    

                                                

                                            
                                     

                                               
                                                                             









                                                 
                                                                     
                                                   
                                                                         

                                                                    
                                                                          




                                         


                                                       

                                                                                                                     

                                                       


                      
                                                                           






                                                              
                   


                              
                                     
                 
                                                                        
                                                                      
                                          

                    
                                                                        



                                                          





                                            
                                                                  

                                                        
                                                                
 
          
 
                        



                                                                      
                           




                                                   
                                                             

















                                                           
                           




                                                    
                                                             








                                                           
 






                         





                                            
                                                 
 
          
 
                    
 


                                                                      
                       



                                                   
                                                                        






                                                      
                       



                                                    
                                                                        



                                                  
 
             

 
                                                   


                                                                            




                                                                                        
                                            

                                                                 

                                            
                                                                          

                                     
 
                                       
 

                        


                                             
                            





                                                                             
                                                                       
                 
                         

                    
















                                                                      


                                

                                                                                                     




                               
                                                                                          




                               
                                                                                    



                               
                                                                                       



                              
                                                                                                        



                                   









                                                                      
                                                                         


                                

                                                                       

                                
                                           
         
                                                                                       
                                                                         

                                                  
                                                               

                  
                                                                
                                                                       

                                
                                                                      

                                                         

                                                                         


                                
                                                                            
                                       
                                                           
                    
                                    


                  
                                                       
         



                                                              

                                        
                                                                                           
                                                              

                                                                                              
                                    
                                                                            

                                        
                                                       

                  
 
                                                          
                                                                         

                                 
                                                                
                                                    
                                                              
                  
                                               
         
                                                                                       

                                                     
                                                                             


                                    
                                                                             


                                    
                                                                
                                                                           

                                                                                         




                                                                             
                                                               

                  
                                              
         
                                                                                       
                                                                         

                                                             
                                                               

                  



                                                    
                                                                         

                                
                                                       
         
                                                                                       



                                         
                           












                                       
                                                                                



                                             
                                                                                    

                                                 
                                                               




                                         
                                                                             
                                    

                                  







                                                                   

                                                               

                
                                                                             
                                    
                                                                  
                                                             
                                                               

                  






                                                                             
                                              

                                  
             
                                                       
                                                 
                 
                                        
                                             




                                                                                          
                     
                                                                           
                                                            



                 

                                         




                                         
                                                                                                                                            
                           
                                                                                                 
                           
                                                                                                        
                           


                                            
                                                                
                                                                             
                                        
                                                                                              

                                                                                                                                                         
                                                         
                                                           
             
         
                  
 
                                                                

                         
                                                       
                                                 
                                                                           
                                                     


                

                                     
                        
                                                                           
                                                  

                               

                                                                                                                                  

                                           
                                                
                                               
                                                                   
                            
                                            
                                                           
                                                                                                                                                 
                                                                       

                                                                         

                                  


                                                
                                                                                                  
                                                                                                                                                             
                                                        
                                                          
                                                      
                                    
                                                           
                 
                                       

                  
 

                                                             
                                 


                                                                            


                                    
                                       



                         











                                                                
                                                                        


                                
                                                             
                                                                        

                                
                                                                             


                                                       
                                                 

                                                                            


                                    


                                                             

                         
                                                       
                                                 
                 
                                        
                                               
                                                                                                  


                                                                
                     
                                                                          
                                                            



                 
                                                            

                                                   
                                             

                                                           

                                                                                                                                             
                                                          


                    

                                              
                 


                                                           
                                                                
                                                                            
                                       
                                                                                              
                                                                                                                                                         
                                                      
                                                        





                                                     
                                                 
                 
                                                                          
                                                                          



                 
                                                              

                                                   

                                               

                                                                                                                                             
                                                          


                    

                                              
                 
                                                                            

                                                                                                                                                         
                                                      
                                                        


                  
                                                          
                                                                                    
                                                                        



                                
                                                                                    
                                                       

                  

                                                          

                         
                                                       
                                                 
                                                                         
                                       
                                                                                  


                


                                                   

                                                                                                                                             
                                                          
                                                                
                                                                           
                                                                              
                                                                                              
                                                                                                                                                         
                                                    
                                                      


                  

                                                          
                                                                                    


                                               
                                                                         

                  

                                                       
                                                                                  
                  
 

                                                

                         
                                                       


                                                                  
                                       

                                                     
                                                           









                                                                         


                                                                                                                                                             
                                                        
                                                          
                                                       



                  
                                         


                             
                     
                  
                                        


                                                                           
                                                   

                  
                           



                             
                                                     
                                                                      
                                                                  


                    
                                              

                                                                                                                                                             
                                                          
                                                            




                  
                                   

                     
                           

             


                                            
                                                        

                                            
                                                                            

                                     
 



                                          
                                                                  
                                                     
                       


                                                                           
                                 
 

                        





                                             



                                                                           


                          
                                                               


                                
                                                       













                                       
                            
                 
                                                                 
                 
                                     
                 
                                                                             
                 
 
                         

                    
                                              
         


                                                     


                                                              
                                                                             

                   

                                                                                              
                                                     

                                                                                                                                                                                                                                       

             
                                                                
 
                                 






                                                                   
                                                              



                                             
 
                                                          

                                  
                            
                                                                              
                                    
                                                                
                                                                 
 
                                   
                                                  


















                                                                    
                                                           


                                                            
                                     
                                                             
                                                  
                                                                                 

                                                   

                                                                              

                                              





                                                                           
                                                                     








                                                                              
                                                                    






                                                                              
                                                      



                     
 
                                                 



                                                     
                            
                                   
                                                                 

                              
                                             

                                                                           
                                                                            


                                              
 


                         



                                                                     
                 

                                                       
                                                        

                                                     

                                                                         



                 
                               
                                                                                                                                                           
                                                               
                                                                

                  
 
                                                                
         
                                                                                      




                                                          

                                                           
             
                                             

                                                                           
                                                                            






                                              







                                                     

                                                




                              




                                                     
                                                                           
                      
                                                          

                              
                   
                                                                          


                                                     

                                                                 
                  
 
                             
                   
                                                       
                  
 

                         

                            
                      
                                                     

                         
                      
                                                     

                      
                      
                                                             
                      
                                                      

                              
                      
                                                                             

                        
                   
                                                        
                  

                                                       
                           





                                                                         



                                                     


                
                                             

                                                                           
                                                                            
                                              

                  
 







                                                                                                        











                                                                              
                                                       


                          
                                                                  
             
                                                   




                                                                          
                                                   
                                                                          
                                        




                      
                                             

                                                                           
                                                                            
                                              

                  
 
                                                       





                                                     
                                                                          
                                                        
                                                                            
                  
                                                             



                                                     
                                                                          
                                                        
                                                                            
                  


                                                                       
                              











                                                                   
                                     





                                                             
                                                                          
                                                        
                                                                            










                                                                              
                                                       


                          
                                                                          
                                                        
                                                                            
                  
                                                                   


                                                                          
                                                        
                                                                            

                           
                  
                                                    
         
                          
                                                                          
                                                        
                                                                            

                                                                                                                           
                                                            

                  
                                                    
         
                                                                                      
 
                                                   
                                                                                                                                                                      
             
                                       


                         
                                                                          
                                                        
                                                                            
 
                                                                                                   
                                        
                                                

                                                      
                                                        
                                        



                                                   
                                                               

                                                   
                                                              
                                                  
                                                              



                                   
                                                              
                              

                                                                


                  
 
                                                          

                            
                                                                        
 
                                                                          
                                         


                                                                                   


                                                                                                     


                                                                                    
                                                  

                                                       

                             
                                                 

                                         
                                                                 




                                                 
                                                        

                                                           


                                 
                                             




                                                                           
                                                   
                  
                                        

                   
                                                                      


                                           
                                           

                   
                                           
                                                                          


                                         
                                              
                                                                           
                                                        
                                                                            
                  
                                        

                      

                            
                                                          


                                              
                                                  
                                                                      







                                                                  

                                                                                                                                     
                                    
                 
                                                        
                                              


                  
                                   
                  
         
 
                                              
                  
 
                                                          
                  
                                                             
                  
                                              
                  
                                                             



                                                     
                                                                    
             

                                                                             


                                              
 
                                                                
             
                                         



                                                                                                                                                         
                                                       
                                                         
             
                                                                                      
                  
 
                                                                     
         


                             
                                                      
                             
                                     

                                                      
                         



                                       

                                                                                                                                                    
                                                            

                 
                          

                            
                                                      
                       


                
                                                      
                          





                                       

                                                                                                                                                    

                                                            
                     
                                                              
                               



                               
                         


                                     
                                                          
                                                                                                                                                         
                                                              
                                                                


                  
 




                                                             

                                                                     



                                                         
                                             

                                                                           
                                                                            



                                              
                                                    
                                                                                                                                                              
                                             

                  


                                                                         

                                                                     
                                             

                                                                              
                                                                            



                                              
                                                    
                                                                                                                                                              
                               

                  
 




                                                                
         

                                                                                       


                                             
                                      

                                                                       

                                                                            
                                      
                                                        



                  
                                                       
         

                                                                                       


                                             
                                      

                                                                       

                                                                            
                                      
                                                        



                  
                                                       
         

                                                                                       


                                             
                                      

                                                                       

                                                                            
                                      
                                                        

             
                                     


                  
                                                       
         

                                                                                       


                                             
                                      

                                                                       

                                                                            
                                      
                                                        



                  



















                                                                         
                                                                        

                  

                                                 
                                       
                                                                        

                  
                                                 
         
                                                                                       
                                                           
                                           


                  

                                                       
                                                                        
                                                                                    

                  
                                                 

                  
                                                          

                   
                                          
                 
                                                                  
                                  
                                                                    
                                                                   
                 


                  
                                                          
                                                                 
             
                                                       

                      



                                                     




                                                                             

                                              
                                                   

                  
                                                 
                                           
                  
 
                                                 



                                                     



                                                                                   
                                                                   
                                                                             


                                              
 
                                           
                                                       

                  
                                                    
         



                                                     




                                                                                   
                                                                   
                               


                                                                        


                                                          
                          


                                                                       





                                                              
                                                
                                                   
                                                                 



                  
                                                          

                  
                                                       

                  
                                                 
                  
 
                                                    
                                   
                                                                
                  
 
                                                                

                   
                                     
                                                       





                                                       
                                                                                             
                 

                                                                
                 

                                                                      






                                                                     

                                      

                                                            


                                       
                                             

                                                                
                 

                                                                      



                                                                     
 
                                                                
         
                                                                                       



                                                               

                                                                          
             
                                             



                                                                            
                                                           
                     

                                                                                     
                         
                                                                      






                                  
 
                                                                
         
                                                                                       



                                                               

                                                                          
             
                                             



                                                                            
                                                           
                     

                                                                                     
                         
                                                                      






                                  
 
                                                                
         
                                                                                       



                                                              

                                                                          
             
                                             



                                                                            
                                                           
                     

                                                                                    
                         
                                                                      






                                  
                                                             
         
                                                                                       



                                                             

                                                                          
             
                                             



                                                                            
                                                           
                     

                                                                                  
                         
                                                                      







                                  
                                                                   
         
                                     



                                                        
                                           


                                     
                                                                         

                                                              

                                                       





                                                       

                                                       





                                                                   
                                                                           
                               
                                                                  


                                                                   
                                                                         
                                    
                                                
                                                                      
                                                




                                                                            
                                                    
                                                                     
                                                    








                                                                           
                                                               
                                                                              
                                                                      

                                                                                      
                                                                          

                                            
                                                           





                                                                          
                                                               
                                                                              
                                                                 

                                                                                 
                                                                          

                                            
                                                           






                                                                           

                                                                   

                                    
                                                                             
             
                                            



                          
                                                                                       
                                                                 

                                                                          
                                                        
                                                                            



                          
                                                                                       
                                                                 

                                                                          
                                                        
                                                                            



                         
                                                                                       
                                                                

                                                                          
                                                        
                                                                            



                        
                                                                                       
                                                               

                                                                          
                                                        
                                                                            

                  
                                                    
         



                                                     

                                                                             







                                                                             
                                                   


                  
 
                                                          


                                                                          
                                    
                                                        
                                        

                                                                        
                                                                                    
                  
 
                           
                                     

                   
                                                                        


                                                          
                                    

                  
                                                          
         
                                                                                      
                   



                                                            
                                                        











                                                                     
                 




                                               
                                        



                 

                                                   















                                                         

                                                      

                                                                   

                                                              
                              
                                               















                                                                   


                            
                                                       







                                                     
                                                                          
                                                        
                                                                            
                  
                                                       
                   
              

                





                                                               
















                                            
                                     







                                            
                                             
                                                                         
                                                                           
                                                                           


                                                                            
 
                                                                              




                              
                                       





                                   
                                                    
                                                                               

                                                                                           

                  
 
                               



                                                     
                                                                          
                                                        
                                                                            
                  
 


                         
                                                              
                                                                          
                                                                        
                                                                           

                  
 

                              
                                                   



                                                     
                                                                          
                      
                                                               


                          

                                                   





                                  
 

                                                
                                                                          
                                                                        
                                                                            

                      




                                                     



                                                                             

                                              
 
                                           
                                
                                                
                  
 

                                                  

                                     
                                   
                                                                               



                                                                       
 


                                
                                    
                                                                                 
                  
 
                                                       
                   
                                     
                                                                                
                  
 
                          
                  
 
                                                          

                            
                             

                                                                     
                                                                            
                                                     

                  
                                                                            

                            
                             

                                                                     
                                                                            
                                                     

                  
 
                                                             



                                              

                             
                                                         
                 
                                                       

                             
                                                                            



                                      
                                                          

                   
                                             

                                                                   




                                                             
                                                            
                                               

                  
                                                             


                                             

                                                      


                                                                         
                                                    
                                                    



                                                                     
                                                        



                                                                             
                                                                           



                                                                     
                                                         
                                                       
                                                       
                                                                     

                                                                                         
                                     

                                                                          











                                                                                          
                                                                   

                                                   
                                                 
                                               

                                                                             
                             

                                                                        








                                                                           
                                                       


                                                           
                                                                          
                     
                                      


                  
                                                                






                                                                             








                                                                             
                                                      
                                                          

                                                                 
                                                                        
                                       
                                                                        



                     
                                                    
                   
                                                            

                                                 
                                                                   
                                                                                                                      
                         
                                                                          
                                                                              
                                                                            
                  
                                                    
         
                                                                                      
 
                                                   
                                                                                                                                                                      
             
                                       


                         
                                                                          
                                                        
                                                                            
 
                                                                                                   
                                        
                                                

                                                      
                                                        
                                        



                                                   
                                                               

                                                   
                                                              
                                                  
                                                              



                                   
                                                              
                              

                                                                




                                          



                                                      

                                                                         
                                                    
                           
                                          



                  
                                                                 
                                   


                     
                           
             


                                            
                                               

                                            
      
                                                                               
 
                                                                       
                          
                    
 
                     
 
                                                                    
               
 
                                                                                          
               
                                                            
                                              

                                   
                                        



                                     
                                                                      


                                

                                          
               
     
                                           
                                                                               

                                

                                          
               



                                     
                                                                                  




                                                     
                                                   

                                    

                                              
                   



                                        



                                                                             
         
                                                   

                                    

                                              
                   


         


                                                                                            


                                

                                          
               


                                            

                                                                            
                          

                      
                                                   

                                    

                                              
                   


         
                                                      
                  
                                                        

                                                                             
                                                                     
                                                                            
                                                                     
                                                                             
                                                                     
                                                                             
                                                                    
                
                                                                            
                                              

                                                                            
                                                               
         
                                                   

                                    

                                              
                   

         
                                      
                                                              

                                

                                          
               
     

                                      

                                              
                                                               
         
                                                   

                                    
                   



                                   

                                                  
                           
 
                                      
     
                                              

               
                                                                          
                                                     
                  
                                              


                                                                          


                                                                  
                                                                      
                
                                                                   
                                                                        

                  
 
 
                                            
                                                                     

                                            
                                                            
                                                                  

                                       
                                              
 
                    
 

                           
                                                         
     
 
                                                 



                    
                                                 



                                                                                                                                                         
                                         
                                          

                  
                                                             




                                                                                                                                                       
                  
 
                                                             

                                

                                                                                                    
                                                            


                  





                                                                
                            





















                                                                         
                                                              


                                                       

                                                              

                  



                                                                

                                                                                                       

                  
                                                      
         
                                 

                                                    
                             

                  

                                              









                                                    
                                                                             


                                   

                                       
                          
                                                                            
                                                                                                                        
                                                


                          
                                                                             
                                                                                      


                  
                                                          



                               
                                     

                                         
                                                               
                  
                                                       

                   
                                   



                                                     
                                                                          
                                         
                                                                     




                                                  

                                                                    

                                                            

                  
                                                          

                   
                                   



                                                     
                                                                          
                                         
                                                                     




                                                  

                                                                    

                                                            




                  


                                            
                                                

                                            
                                                                     
                                           
 
                     
 
                   
                                             
                 
 

                                                   
                 







                                                  
 
                                                                     
                 
 
                      
 
                                   

                                                         
                           
 
                                       



                      
                                                    

                                               
                
                                                        



                                                                            
                                                          





                                                                     

                             
 
                                                                 
             
                      







                                                                    


                                                           

                                                      





                                             
                                                    





                                
                                                               

                         
                                              

                         
                                                                     

                                                                        

                                            








                                            
                                    

                                            
                                                                  

                                     

                                   
                                                           

                                    
                                                                                                     
 
                    

                    
                                            
 
                                                                
                                                      
                                



                                                                         
                                                                


                                           
                                              



                          
                                                      
                                


                         
                                                 
                                                      




                                                                         
                                                          
                             
                                
                          
                              
                
                                                          

                  
                                                          
                       
                                                      

                                                        
                             
                       

                  
                                                                   
                       
                                                      


                            
                                                             
                          
                                                          
                
                              
                            

                                

                  
                                                             

                         
                  
 
                                                          

                         
                  
                                                             

                         
                  
 
                                                          

                         
                  
 
                            
                         

                       
 
                                                                         
                          
                            
                       
                  
 
                                                          
                                                      

                      
 
                                                          
                          
                           
                       
                  
 
                                                       
                                                      


                           
 








                                                                   
                                                      
                       
                  
 
                                                             
                                                      
                       

                             
 
                                                                         
                                                      

                                      
                  
 
                                                       
                                                      


                            
 
                                                          
                       
                          

                           
 


                                                                
                                                      


                                                                 
 
                                                          
                                                                                                          
                                      



                                                                                                            
 


                                                             
                       
                                                      
                       


                             



                                                                      
                       
                                                      
                       

                               
 
                                           
                       
                                                      
                       

                                   
                       
                                                                   
                                                  

                                                                
                  
                                                 
                       
                                                      
                       

                                   
                       
                                                                   
                                                  
                                             
                  
 

                                                             
                       
                                                      
                       

                               
 
                                                             
                       
                                                      
                       

                                   
                       
                                                                   
                                                  

                                                                
                  
                                                    
                       
                                                      
                       

                                   
                       
                                                                  
                                                     

                                                                
                  
                                                          
                       
                                                      
                       

                                   
                       
                                                                    

                                                          
                          
                                                    
                                                                                    
                  
                                                                
                       
                                                      
                       

                                   
                       
                                                                   
                                                  
                                             
                  
                                                                   
                       
                                                      
                       

                                   
                       
                                                                   
                                                  
                                             
                  
                                                    
                       
                                                      
                       

                                   
                       
                                                                   
                                                  
                                             
                  
                                                                   
                                                      
                            
                       

                               
                                                             
                                                      
                        
                  
 
                                                 
                                                      
                             
                       
                                                                          

                                                                              

                                          
                                                 

                               
                                                      
                  
                                                          
                       
                                                      


                                                            
                                                         


                  


                                                                             


                          

                                
                          

                                                          

                                              



                                
                                                             
                                    
                                 
                        

                                                 






                                                                          
                                                                

                            
                                                  











                                                            

                                                    
                                    
                                            





                                    
                                                          













                                                                              
                                                                   































                                                                              
                                                          
             






                                               
                                                  




                                          
                                                       








                                  
                                                       







                                                           
                                                              












                                                                             


                                                                    
             
                                             


















                                                        
                                                                                          
                    
                                                                      

                      
                                                                    
             
                                














                                                        








                                                                        


                                  
                                                                                          
                    
                                                                                                    
                      









                                                                       


                                  
                                                                                          
                    
                                                                                                    
                      
                                                 


                                  
                                                          







                                                       
                                                                                                       
                       


                                                                                      


                                           
                                               



                                       
                                               




                  
                                                                       






                                


                                            
                                             

                                            
      
                                                                     
                                          
 



                                          
                                       
 

                    
 
                                       
                                                                            
                 
 

                                           
 
                          
                                                           




                                                
                                                                     
                                     
                                               
                                                                                                         
                                                                             

                               
                                            


                                                                                     







                                
                                                          
         


                                                                    

                                       
                                                                           



                                  
                                       



                             
                                    


                                                         
                                                                             
                                                  

                
                                                                      
                                                            


                  
                                                                   
         


                                                                    



                                       
                                                                  
                                                        


                  
                                                 

                                     

                                                                                      
                                                     
                                                                            



                                                                       

                                                                     




                                                                      
                                                                

                                     

                                                                                      
                                                     
                                                                            




                                                                       
                                                                     





                                                                      
                                                                                                                            
                                                                  
                                                        
                  
 
                                                                
                                  
                                                        
                                                                          
                               
                                   
                  
 
                                                                        

                                                                        

                                             
 
                                                                        

                                                                      
                                                            
                  
 
                                                             
         
                                                                       
                                   
                                                       
                               

                                                              

                  
 
                                                       
                                                                 
                                                        
                               

                                                         
                  
 





                                                                         

                                                                                              
                                                                            

                                                                                                 
                                                                            
                               

                                                              

                  
                                                          
         
                                                                                      

                                                                          
                                                                             

                                                          
                                                       
                                                           

                                                      
                                  

                                                                           


                                                      
                                     


                                  
                                     
                                       
                                                           
                    
                                    
                                                            




                                  
                                                                     










                                                                             
                                                                     

                                                             
                                                                           

                                                                         
                                                       

                            
                                                   




                                                                        
                                                      
                                                                   



                                                
                                                       
         
                                                                     



                                                     

                                                                            
                                                
                                                                        


                                                                              
                                                       
         

                                                                                      
                                                     
                                                                            
                                                
                                                                        


                                                                              


                                                                

                                     

                                                                                      
                                                     
                                                                            
                                                
                                                                        



                                                                              

                                                                     
                                                               
                                                                            





                                                                              
















                                                                      


                                     

                                                                                      


                                                     
                                                                           
                                                               
                                                                        




                                                                              

                                                                     
                                                                             
                                                                            





                                                                              
                                                          

                                     

                                                                                      


                                                     
                                                                 

                                                                          
                                                                        



                                                                              

                                                                     

                                                                              
                                                                            





                                                                              
                                                                   
                                                                   
                                                        
                                                              
                                                    
                                                               
                  

                                                                              


                              
                                   

                                                                  
                                           

                  



                                                                    

                  
                                                                

                              
                                                                             

                                                          
                                                                           

                                                        
                                     


                                      
                                     
                                       
                                                           
                    
                                    
                           

                                                                        



                                                                          
 



                                                                                                             
     
                                                                                  


                                                        
                                                             

                                                             
                                                      
                                                       


                                                         
                                                      
                                                       
     
 
             
 
 
                                            
                                                                          

                                            
      
                                                                   
                                        
 

                                


                                








                                                


                                                                
         

                                                                                      





                                                                      
                                                      


                
                                                          
         
                                                            

                                       

                                                             





                  
                                                            
                             

                                                              



                  
                                                            
                             

                                                            

                  


                                                                
         
                                                                                      
                                  
                                                                     



                                                                    
                                                      



                  

















                                                                      

                  
                                                                                      
                                  
                                                                     



                                                                    
                                                      


                  
                                                                
         
                                                            
                                       

                                                              

                  
 



                                                                                                           
     
                                                    
             
 
 
                                            
                                             

                                            
      
                                                                      
                                           
 

                                


                                








                                                























                                                                      
                  
                                                   
 



                                                                                                              
     
                                                    
             
 
 
                                            
                                             

                                            
      
                                                            
 

                                

                                


                        
                                                                     

                                            
                                                                      



                                                            

                                                  



                                   
                                                          
                                                                    
                  
                                                             



                                                 
                                                                       

                         
                                                    

                         
                                                                          



                  
 
 
                                            
                                                   

                                            
                                                                       
                                                   
 

                                

                                
 

                        
                                                          

                                

                                                                   
                                                                     






                       



                                                                                 
                                                   

                                            
      
                                                                                
 

                                                                       
 
                    
 
                            
               
                                                          
               
                                                                   

                                   
                                        

                        
                      


                                

                                          
               



















                                                

                                                                







                           
                                                                                                 
             
                                                       

                                        

                                                  
                       


















                                         
                                                                








                            
                                                                                     
             
                                                       

                                        

                                                  
                       





                                          
                                                   

                         
                     







                                                                
                                                       

                                        

                                                  
                       



             
                                                      
                  
                                                        


                                                                                                    
                                                                         
         
                                                   

                                    

                                              
                   

         
                                      
                                                              

                                

                                          
               
     

                                      

                                              
                                                                         
         
                                                   

                                    
                   

         
 
                                   

                                                  
                           
 
                                                                    
                                                     


                                            
                                                            


                                            
      
                                                                                          
 




                                 
                    



                                          
 
                                                    
                                                                                           
                                                  
                                                                                                                                
                  
               


     
                                                      


                         
                                                 
                         


                                                                                  



                                                                           









                                                                         
                            





                                                                                 
                                                      

                                                              

                                                                     

                  
           
 
 
                                            
                                                                              


                                            
      
                                                                                         
 



                                 
                
 
                    



                                          
 
                                                    
 
                                                                                           
                                                  
                                                                                                                                
                  
               

     
                                                      
                                   


                           
                                                 
                         


                                                                                  



                                                                           
                                     


                       










                                                                         





                                                                                                                         
                                                                                

                                                                                             
                                                    
                                                                              


                                                       
                                                                            
                                                                            
                                                                           







                                                                              
 
 
                                            
                                                                                                      


                                            
      
                                                                                                   
 

                        
                    
                                
 
                
               
                   
               
                   
 
                                                              
               


                                            
                                                

                                            
                                                                
 
                                                           
                
                                          
 
                   

                                        
                                                       
     

                                          


                 
                       
     
                                               

                                          

                 
                              
     
                                               

                                          

                 
 

                                                                        

                                          

                 
                                                                       




                                            
                                                                          
                     



                                              

                 
                       
     
                                               

                 





                                                
     

                                                             
     
                                
                     

                                                 
                                                                     
                                                                        

                                                              
                                     
                                    
                                             
                                                                    
                                                     
                                








                                              
                                                       


                                              
                                                       
                           
                                                            





                                     
                                                 


                         





                                                                

                                                                       
                                                                            



                                              
                         
                  
                                           

                                     
                                                 


                         
                                              

                                    
                                                 


                         
                                           







                                                                  
                                          


                                                      
                                                                              


                             
                                          
                                                 
                                                                        

                         
                                          
                                                 
                                                                         

                         
                                             

                                                  

                                                                       

                         
                                                    
                                                  

                                                                              


                                                         
                                                 






                                                                           
                                                                       
                                                                             
                                             
                                                                             
                                                 



                         
                                                 
         

                          

                            


                                                                                                 

                          
                                                     




                             


                                                                                                


                  
                                                             

                                       
                                                 


                         

                                                             

                         


                                                                        

                                                                      



                                                                                                                        

                                      
                                                         




                                 

                                                                

                                                  
                                                         

                                 
                             







                                                                  
                                                         









                                         
                                                    
                                                                            


                                         
                                                    
                                                                            



                                               
                                             



                                                 
                                             



                                                          
                                                              






                       
                                                         
             
                                                 



                         
                                                         
             
                                                 



                         
                                 
             
                                                 



                         
                                 
             
                                                 



                         
                                 
             
                                                 



                         
                                 
             
                                                 





                                       
                                                 





                                                              
                                                 





                                                             
                                                 







                                                             
                                                 





                                     
                                                                                       

                          
                                                 




                         
                                                              
                                                        
                                              
                                                 




                         
                                
     
                            











                                                                         
                                                      


                                                                              
                                                                       
                
                                                 










                                            
                                    

                              
                                                                                

         
 

                 
 
                                                                               
 







                                                                      
                                             
                             
                                               
                                            
 
             


                                            
                     

                                            
                                                  
 

                                            
                                                     

                       

                      
 
                   














                                                      

                                     
 
                                                      
                 
 
                                               
 













                                                                         
                            


                                                                     
                                                       
     
                         







                                                                
 
 
                                            
                     

                                            
                                                   
 
                                                     
 
                   
 
                                     

                  
 

                          
                                                                                 

                                                          
                                             



                                                     
                         







                                                                   


                                            
                                

                                            
                                                            
                                        
 
                      
                                               
                                              
                      
                          
                                                     
                     
 
                   
 
                                            
     

                                                                           

                 
                                           
                 
 
                                                 
                 
 


                                                                 
                                               


                          
 
                                                                            
                       
                 



                                          
     
                                    
                     














                                                             
 


















                                                                         
     
 

                                               
                 



                                               

                                
 
                             



                                                   
                                                                                                          






                                                                       
 
                                                                    
                 
                                                                  



                                         
                                                                                  



                                              
                                                    
                                                   
                                                                            
                                                     












                                            










                                                                                     
         

                          


                                                                                             

                      
                                                     


                             
                                                             








                                                 
 
                                      
                 
 
                                        
                                                  
                   

                                                          
                 
 



                                                      
                                     







                                                                
                          
 
                                                                           

                                 
                                                                          


                                                               

                                                                    
                                                                             
                                                                                        
              
                                                          
                                 

                                                                  

                                                                                   
                          

                                                                            

                  
                                               



                                                                          
                                             



                                                             
                                                                                                                        



                                    


                                                 

                                         
 

                                                                                     
                                                      
                                                        

                                                                         













                                                 
                                                    

                                    
                                      
                                                          
                           

                                                                  




                         
                                                                   
         
                                                                                        

                                                              
                                                      



                         
                                                    

                             
 

     
                                                            



                                                                    
                                                              


                                   
                                                                       
                                                                               




                                  
                                                     
                            
 
                                         
                                                               
                                                                                


                                          
                                        


                               
 
                                                                                         
                                      
 
                                
                                        





                                                                          
                                                          


                        

                                                                       


                                                            
                                            

            
                                   




                                       
                                                             

     
                                          

                                                     
                                                            

             


                                            
                                    

                                            
                                              

                                        
 
                         
                                                     
                      
                                              
 
                   
 
                      
                 
 
                                                
                 
 
                          
 
                       








                                                  
                                                                 

     
                                                

                 



                            
                                      
                 
 
                                        



                     
                                                 
                  

                                                        
                 
 
                      
 

                                                                           
                                                               
 
                                   
                                                                              

                                                         


                                  
                                                            



                                                                    
                                                              

     
                                                                                         


                                      

                                          



                                                           
                                                          


                        

                                                                        


                                                            
                                            

            
                                   



                            
                                                              
     
                                          

                                                     
                                                            

             


                                            
                                 

                                            
                                                     
 
            
 
                   



                                                                     
                                       
                       



                                 
                                                   

                                           
                                                


                      

                                                                         
                    
                                                                   


                

                                                                             
                    
                                                                   

                                
                                     






                                                     
                       

                                 

                                                                     
                
                                                                  
                                
                                     
         


                 
 
 
                                           
                                                       

                                          
                                                                        

 
                    




























































































                                                                          



                                           
                                                              

                                           
                                                                 

 
          
 
                    







































                               


                                            
                                     

                                            
                                                     
 
                
          
 
                    




                            
                                                                     
                                                                                                                          
                          
                                                               
                                                             
             
                                              


             
 
 
                                                         
 
                                                                   
                                                      
 
                    
 
           
                                         
 
 
                                                      
 
                                                    

                                
                 
 
                       

                                                     
                                            

                 
                                                       
 
                                               
                                                              

                                          
                                                                               


                 

 
                                                    
                                                                 
 
                                                       

                    

                                                    
           



                                                           
                                                    
     
 
 
                                            
                                                                  


                                            
      
                                                        
 
                                
 
                    
                   
 
                                        
 
                                                           
               

 
      
                                             
 
                                
 
                    
 
                                        

                                                           
                                       

 
      
                                              
 
                                
 
                    
 
                                        

                                   
                                       

 
                                                                 
 

                  
 
                   
 
                                            


                  
                                                           


                                                                      
                  
                                                                                                                      
                                                          






                                                                          
                                                                       


                                                                      
                  
                                                           





                                                                          
 
 
                                            
                                                                  

                                            

                                                                                 
 
                    
                     
 
                                                          
               
 


                                                                           
     

                                                                                           

                                           


                                            


                                            
                                                     
 

                                       
          
 
                    









                                               
                                                        

                                                                            
                                                      


                    
                                                        

                                                                            
                                                      

         
 
 
                                            
                                                         

                                            
                                                                            
 

                            
                    
 
                                    


                                    
                            





                                                               
 
 
                                            
                                                      

                                            
      
                                                                    
 
                                
             
 
                    
                      
                                  
 


                                                        
 
                                                     
               
 

                                                
                                          
     


                                            
                                                                                                  

                                            

                                              
 
                    
 
                    
               
                  
               
                                                    
               
 
 
                                            
                                          

                                            

                                                           
 


                                
          
 
                    

                                     

                                            
 
                                                    


                            


                                                                         
                                                                           

                                                        

                                                                   

                                                  
                                                                    
                                                     
                                                                       
                 
                                                                   
                                                                  
                                                                                       




                      
 
 
                                                                              
                        



                                                                              
                                                

                                            

                                                                     
 
                    
                     

                                                
               


                 
                                              
                            
                                                                                 
             

                                                             

                  
                                              
                                                                                 
             


                                                                
                 
                                                                                              
                                                                   
                                                                      



                  


                                            
                              

                                            
                                                                        
 
                                                     
 
                   


                                                
                                                                         

                 
 


                                     
 
                                     

 
                                                                              
 
                                                     
                                    




                    
 
                   


                                                
                                                                      

                 


                                     




                                                   




                                                     
                                                                                                     
                                                                         
 
                                               



                                 







                                                                    

                                                







                                                                       


                                











                                                                      
                             
                                                              

                                 
                                                          

                                   








                                                                       


                                                                  

                                                                                            



                                
                                                    
                              
                                                                                   
                      
                                                          
             
                                                                            
                                                            
                                           




                              
                                                                    
                                                            
                                                            
                                                                                                
                                                                     
                                                                 


                                                                              




                                             
                                                                   
                                      
                                                             

                                             
                                                                              







                                                                 
                                                                                                                                      
                       
                                           

                      
                                                         
                      
                                                                   
             
                                                                       

                                     
                                                                      

                                                                            
                                                 


                      
                                                   
             
                                                    

                                                                        

                                                                            
                                                







                                       

                                           



                              
 
                                                   
                                                                       

                     
                                                                                   



                           
                                   



                             
                                        


                             
                          
                                       


                             
                            
                                         


                             
                          
                                      




                                                   

                                            



                                 
                                              



                                 
                                              



                             
                                        



                             



                                          
                             
                                          



                              
                                              



                             
                                          

                             
                                                                                            
                                             


                             
                                            




                                                

                                                                       
                                               
                      
                                                                 
                                            
                      
                                                              
                                            
                      
                                                      
                                                  
                      
                                        
                                           
                      
                                                 
                                           
                      
                                                    
                                         
                      
                                                                             
                                            
                      
                                                          
                                           

                      
 

                                         

                                           
                                 

                         
 
                                                                 
                                  
 
                                           
                                                                                             
     
 
             
 
 
                                                            
 
                                  
 
                   

                                                          
 
                                
                                            
 



                          
 
                                      

 
                                            
                                          

                                            
                                                                                             
 
                                           

                                       
                                                     
                                           
 
                                     




                                                                                                                 



                                            
                                                            



                                    
                                                               




                                                          
                                                                       




                                                          


                                                                    



                                      
                                                             
                                    

                                                                                  



                                                                                  
                           


                  
 
                                                       
                   
                                                                                  




                                                                           
                                                     
                     
                                                                                  


                                                                                  
                           


                  
 
                                              

                                

                                                                                               
                                                          


                                           
                                                                              


                                                                              
                       


                  
                                              

                                

                                                                                               
                                                          


                                           
                                                                              


                                                                              
                       


                  
 
                                                             
         
                                           
                         
                                                                       

                                     
                                                                           
                                             
                       


                  
 
                                                                             
                                        

                                                                                                 

                                     
                                                                             
                                     
                       

                  
 
                                                             
         
                                                                      

                                                       
                                                                
                                                              


                                           
                                                                            
                                     
                       


                  
 
                                                    


                                                        
                                                                           

                                             
                       

                  
 
                                                 







                                                             
                                                     

                          
                                                         
                                                                              
                                        
                                     
                                                                    

                                                                        
                       

                  
 
                                              





                                                                           
                                                                      


                                                                             
                                                                   

                                                                        
                       

                  
 


                                        
                                                 

                                       
                                          

                         
                                          
                                          

                                     
                                                                             
                                     
                       


                                                
                                               
                                                   
                                                   




                                          
                                                                        








                                                                    
                                                                             
                                     
                       





                                                   
                                                               
                                  
                                                                   



                                               

                                                    



                                                  
                                                                            










                                                                        
                                                                         




                                                 
                                                                             

                                     
 
                                                                   
                   
                                                                                          




                                                                            
                                                     
                     
                                                                                  


                                                                                  
                           

                                                       
                                                                          


                  
                                          





                          


                                                             



                                           
                                                                           
                                             
                   
 
                                                                    
         
                      



                                                                    
                                                        
                     






                                                                                               

                                  



                                                                               

                                  




                                                                                           

                                  
                                                                                 

                                  

                                                                                                    





                                                             
                                                     
                     
                                                                                  


                                                                                  
                           



                  
                                                    
                   
                                                                


                                                                

                                                                                  


                                                                                  
                           


                  
                                                                                            


                             
                                                                 
                                                                       
                                                                                  


                                                                                  
                           


                  
                                                         



                                                   
                                     
                                                                          
                                                                                         
                                                                                         


                                                                                  
                           


                  
                                               








                                                                       
                                                                              


                                                                              
                       

                  

                                
                                             

                  
     
 
                                           


                                            
                              

                                            
                                                                          
 
                                                     
 
                   


                                     
 
                                                                                                              
                                                      
                                                                                                  
                                                     
                                                                                                                
                                                          
                                                                                                            
                                                        
                                                                                                                          
                                                            
                                                                                                                      
                                                          

             
 
 
                                            
                              

                                            


                                                                       
 
                                                                            
                                   

 


                                                                 
 
                                       
                                                     




                    


                                      
                  
 
                   

                             


                                     




                                                   




                                                  



                                                                             
 



                       
                                                                     



                        
                                                                    


                      
                                                                    

                      
                                           
                  
 









                                            
                                                      



                                                 




                                                  

                                             
                                                                                     










                                       
                                                                        

                 
 

                                                        
 



                                                               
 








                                                                            
                                                                                           


                                                                 
                                  

                                  
                                                                                                  


                                                                                                                                                                                                                                                                           
                                                                                                                       
                                
                                                                                                                         
                                                  



                          
                                                                         




                                     

                                                                    

                          
                                                                
                  
                                                    


                                 
                                                    

                          
                                                       



                                                                 
                                                              

                                                   
                                                              



                          
                                                    

                          
                                                 

                                                    
                                                                
                                                                                  
                                                             
                  
                                                 

                                                    
                                                                
                  
                                                             



                                 
                                





                                               
                                          

                          
                                                                   

                          
                                                                             


                                                          
                                                             
                                       


                                                          
                                                                                               




                                   
                                                                   
                          
                                                                         
                                                           
                  
                                                             
                  
                                                                   

                          
                                                       
                                                          
                  



                                                             
                  
                                                          
                                       



                             
                                                             
                                                                                  
                                                
                                                                
                                                  
                                                              



                            

                                                                

                          
                                                       

                          
                                                    
                  
                                                       
                          
                                                                                   
                                                                
                                                                                
                                                                
                                                       
                                                                   
                                                      
                                                                  
                                                   
                                                               
                                             
                                                         
                                                                               
                                                              
                                                                                  
                                                             
                                                                               
                                                              
                  
                                                                
                                                               
                  
                                                             
                                                             
                  
                                                                       
                                                                 
                  
                                                                   
                                                               
                  
                                                          

                          
                                                          














                                 
 
                                                       

                                
 


























                                                                             
 
                                                             

                             
                                          


                      
                                                             
                  
                                                 
                                      
                  
 
                                              



                           
                                                             

                          
                                                       



                                   
                                                                



                                   
                                                    
                  
                                                    
                  
                                                                      



                                 
                                                 

                      
                                           

                          
                                                                   

                          
                                                    
                  
                                                          

                          
                                                             

                      
                                                 

                          
                                                          
                          
                                                                                
                                                                
                                                       
                                                                   
                                                      
                                                                  
                                                   
                                                               
                                                 
                                                             
                                                                               
                                                              
                                                                                  
                                                             
                                                                               
                                                              
                  
                                                    

                          
                                                                

                          
                                                        



                               
 
                                                  

                                  
                                             
                  
                                        
                          
                                      
                  
                                                       



                            
 
                                                          
                                         





                                              
 

                                              
                                   



                               
                                                                                            





                          
                                    

                  
                                                         

                         
 

                                              
 

                         
                                    
                                      

                  
                                           


                               
 
                         
                                           

                            
                                                       







                                     
                                           




                                                                               
                                                                                    

                  
                                           

                            
                                                       


                                           
                                                                             

                            

                                                                        


                                           
 
                         
                                        


                            

                                                                        






                                           
                                                                         

                            
                                                      


                                           
                                           


                            

                                                                     






                                      
                                                      


                                           
 
                        
                                                       


                                  
                                                      



                            
                                                       




                                   
                                                        



                              
 
                                                            



                                                              
 
                              


                      
                                          

                          
                                                                                                                        



                                                   
 
                                                                










                              
 

                          
                     






                                             
 








                                 
                                                                   
                                          

                          
                                                                   





                                  

                                                          
                                      


                                                                          
 
                                      
                  
 
                                                                  
  





















                                                                        
  
                                                             
                          
                                               
                  
                                                    


                                  

                                                                                   
             
                                    


                          
                                                          
                                      
                  
                                                                         
                                       
                  




                                                                

                          

                                                             
                  

                                                           
                  
                                                       

                                         
                                                                        





                                
                                                                   









                                        
                                                                     



                                               
                                                                   
 
                         





                       

                                                                      



                                                                        
                 



                                                             

                 

                         



                                                         
             




                                                   
                                       


                             
 
                      
                                  

                         
                        
                                    

                         
                      
                                 

                         
 
                           

                                       


                             
                                         


                         



                                                     
                         
                                                     
                                     


                          
                                                     
                                                         


                         
                                     


                         
                                       


                         
                                        

                         
 
                                                     
                              
 
                                                                 
 




                                                                  
                                                                       
                                                          
 
                                                      
 
                            
                         
                                                                      
                                        
 
                                       
                                                             
 
                                                    
                                                                                              
 
             
 
 
                                            
                                 

                                            
                                                              
 
                                                     




                    
 
                   


                                     




                                                   


                       
                                                                   

                                   
                                                                                      
  

                                                                                  
 

                                                             

  
                                               


                  



                            
 
                                                   
                             
 
                              
                              
 
             

 
                                                                              
                                               
 


                                                    
                   
 
                   
 
                                           




                                                                         
                                                    
     
                                                                 




                             
                                                     
                                                                              

               



                                                                              
                        



                                                                              


                                                                     

                                            
      
                                   
 

               









                                                                         
                     











                                                                   
                     
                
                     
     


                                            

                                                            


                                            
                                                         
 
                                                     

                                   
                     
 
                                      

                                                   
                                                                                                                               
                                                                           
                                              
                                                                                                  
                 
                                                                                                    
                                                





                                                                                                                             

                                                        





                                                                                                                                   
                                                                                                       
                                                                                                              




                                                
                                                                           
                                                                                                                                   

                                                   
                                                                                                                                   
                                                                                                           



                                                
                                                                                        
                                                                      
                                                                          


                                                           
                              
                           
                                                          


                                            
                                 

                                            
                                                                          
                                                
 

                            

                                                



                             
                                           







                                
                            
                

 

                                                         
                                            
                              

                                            
                                          
 
                                   
              
 
                     

                     
                                    
 
                                         
                                        
 
                                          
                         

                                                                                              
                                                            
 

                       
                                               
                                                              
                                  
 
             
 
 
                                            
                                             

                                            

                                
                                                                    
                                                             
 
          
                                                        
                   
 
                           












                                                            
                                                                         






                                      
                                                                             

                                                      
                                        
                                                                  



                                
                                         





                             

                                                            


                            
                                               


                                               
                                                  








                                  
                            

                         
                                     






                                                                         


                                                            
                        










                                                                                     
             

                              

                       


                                                                                                    




                 


                                            
                                          

                                            
                                                      
 
                           
          
 
                      

                               
 

                                             
                                                                                     
                
                                                         






                                               
                                               


                              
                                     


                             
                                                           




                          


                                            
                                             

                                            
                                                 
 
                                          
                   
 
                    












                                                             
              

                                                                    
                                              

             


                                            
                                                          

                                            

                                                               
 
                                                              

                                                
                   


















                                                                      


                                            
                                                          

                                            
                                                                      
 
                                                    

                                                     
                   




















                                                                        


                                            
                                                                  

                                            
      

                                                        
 
                          
 
                    
 





                                    

                                                                    
     


                                            
                                                                  

                                            

                                                         
 
                          
 
                    
 





                                    

                                                                    
     


                                            
                                                            

                                            
      
                                                                   
 

                                   
              
 
                    
                                    
                                     

                     
               
 

                                                            
                                         

                                        

                                                                                    
                                                      
                                  
                                                                  
         

                                                                       
                                                          


                          
                            
                      

                                                         



                               
                                                          
                                      


                                                                   
                      








                                                                         
             
                                                                  





                                                           
                                                               

                                               
                                                                                                               



                     
                                    

         
 



                                                                      
                                                             
     
 
 
                                            
                                          

                                            
      
                                                                        
 
                         
 
                                                                               
 
                           


                                            
                                                         

                                            
      

                                                  
 

                                   
              
 
                    

                                    
                                     
 
                                          
               
 
                                                            
 
                                                                           
               
 

                                                             
                                          

 
                                            
                                       

                                            
                                                                           
 
                   
 

                         
 

                  


                                                                          
 
             


                                            
                                                         

                                            
      

                                                  
 

                                   
              
 
                    
                                                 
                     
 
                                          
               
 
                                      
               
                                                            
 
                                                                           
               
 

                                                             
                                            
        
                                          


                                            
                                       

                                            
                                                                        
 
                   
 

                         
 

                  


                                                                       
 
             


                                            
                                                               

                                            
      

                                                          
 

                                   
              
 
                    

                                     
                                     
 
                                         
               


                                                            
                                                                           
               

                                                             
                                           
        
                                         


                                            

                                                

                                            
                                                                             
                                       
 
                      
 






                                              
                  




                                                                            

                                            


                                     
                                            



                                      

                                                                                                                  
                                                                                





                     
                                                

                                     





                                                                                    
 
                                               

                                                   
                                                            






                                                                           



                                                                                                   


                              

                                                                                            

             
                                                        



                                                   
                                                          
                                   

                                                                     

                                                 


                                          
                                                 



                                          


                                                                                                                       
                                                                                      


                         

                                                                                               




                                                               
                                                                  

                                                         



                                                               
                                                         



                                                  


                                                                                                                               
                                                                                              
                                 
                                                                              





                                      


                         


             


                                                                              
                     


                                                                              
                                                                              
               

   
      
                            
 
                                     
                      
                                     
                      
                                     
                      
                                     
                      
                                     
                      
                                     
                      
                                      
                        
 

                                                     

 
                                            


                                                                     

                                            
      
                      
 
                



                                 
                                           
                                        

                   
                                               

                 
                                 








                                                  
                               




                                        
                                                                             


                        
 
                                            
                                                  

                     
                                          


                                                                
                               




                                             








                                                                


                                                                
                               




                                             
                                                                
 
                                             


                                       



                                                   
                                               
                                                     
                                              
                                                    

                                             
                                              
                                          


                                                                 
                               




                                             
                                                                
 
                                              
         
                                   

                                                    
                                                  
         
                                   


                                                                        
                                                     
 
                                                
 
                                      

                                 
                          
                                        
                         


                                           

                            
                                         
     

                                          
 
                                                

                   
                                                       

                 
                                 








                                                  
                               





                                        
                                            
                                                  

                     
                                          


                                                                
                               




                                             
                                                                
 
                                          


                                                                
                               




                                             
                                                                
 
                                          


                                                                
                               




                                             
                                                                
 
                                          


                                                                
                               




                                             
                                                                
 
                                          


                                                                
                               




                                             
                                                                
 
                                          


                                                                
                               




                                             
                                                                
 
                                          


                                                   
                               




                                             
                                







                                                
 
                                                
                                          
                                                       
                                            
                                                     
                                          
                                                     
                                          
                                                     
                                          
                                                   
                                        
                                                     
                                          
                                                    
                                         
                                                               
                                                    
                                                                  
                                                     
                                                          
                                               
                                                    



                                         
                                          


                                                                
                               




                                             























                                                                

           
                                             

                   
                                                    

                 
                                 

                                                  
                                                                    






                                              
                               





                                      
                                            
                                                  

                     
                                          


                                                                
                               




                                             
                                                                
 
                                          


                                                                
                               




                                             
                                                                
 
                                          


                                                                
                               




                                             
                                                                
 
                                          


                                                                
                               




                                             
                                                                
     

                                               
 
                                                  

                   
                                                         

                 
                                 

                                                  
                                        






                                              
                               


                         
 
                                            
                                                  

                     
                                          


                                                                
                               




                                             
                                                                
     

                                                    

             

 
                       
 
      
      

                             
      

       
                    


                                            
                                 

                                            
                       
 
                   
 
                                                           


                                                                         
 

















                                                                          
#include "skill.hpp"

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>

#include "../common/mt_rand.hpp"
#include "../common/nullpo.hpp"
#include "../common/socket.hpp"
#include "../common/timer.hpp"

#include "battle.hpp"
#include "clif.hpp"
#include "intif.hpp"
#include "itemdb.hpp"
#include "magic.hpp"
#include "map.hpp"
#include "mob.hpp"
#include "party.hpp"
#include "pc.hpp"
#include "script.hpp"

#define SKILLUNITTIMER_INVERVAL 100

// This table appears to be wrong
/* スキル番号=>ステータス異常番号変換テーブル */
earray<StatusChange, SkillID, MAX_SKILL_DB> SkillStatusChangeTable =
{
    // 0-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_PROVOKE,                 /* プロボック */
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    // 10-
    SC_SIGHT,                   /* サイト */
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_FREEZE,                  /* フロストダイバー */
    SC_STONE,                   /* ストーンカース */
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    // 20-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_RUWACH,                  /* ルアフ */
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_INCREASEAGI,             /* 速度増加 */
    // 30-
    SC_DECREASEAGI,             /* 速度減少 */
    StatusChange::NEGATIVE1,
    SC_SIGNUMCRUCIS,            /* シグナムクルシス */
    SC_ANGELUS,                 /* エンジェラス */
    SC_BLESSING,                /* ブレッシング */
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    // 40-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_CONCENTRATE,             /* 集中力向上 */
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    // 50-
    StatusChange::NEGATIVE1,
    SC_HIDING,                  /* ハイディング */
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    // 60-
    SC_TWOHANDQUICKEN,          /* 2HQ */
    SC_AUTOCOUNTER,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_IMPOSITIO,               /* インポシティオマヌス */
    SC_SUFFRAGIUM,              /* サフラギウム */
    SC_ASPERSIO,                /* アスペルシオ */
    SC_BENEDICTIO,              /* 聖体降福 */
    // 70-
    StatusChange::NEGATIVE1,
    SC_SLOWPOISON,
    StatusChange::NEGATIVE1,
    SC_KYRIE,                   /* キリエエレイソン */
    SC_MAGNIFICAT,              /* マグニフィカート */
    SC_GLORIA,                  /* グロリア */
    SC_DIVINA,                  /* レックスディビーナ */
    StatusChange::NEGATIVE1,
    SC_AETERNA,                 /* レックスエーテルナ */
    StatusChange::NEGATIVE1,
    // 80-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    // 90-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_QUAGMIRE,                /* クァグマイア */
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    // 100-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    // 110-
    StatusChange::NEGATIVE1,
    SC_ADRENALINE,              /* アドレナリンラッシュ */
    SC_WEAPONPERFECTION,        /* ウェポンパーフェクション */
    SC_OVERTHRUST,              /* オーバートラスト */
    SC_MAXIMIZEPOWER,           /* マキシマイズパワー */
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    // 120-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    // 130-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_CLOAKING,                /* クローキング */
    SC_STAN,                    /* ソニックブロー */
    StatusChange::NEGATIVE1,
    SC_ENCPOISON,               /* エンチャントポイズン */
    SC_POISONREACT,             /* ポイズンリアクト */
    // 140-
    SC_POISON,                  /* ベノムダスト */
    SC_SPLASHER,                /* ベナムスプラッシャー */
    StatusChange::NEGATIVE1,
    SC_TRICKDEAD,               /* 死んだふり */
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    // 150-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_LOUD,                    /* ラウドボイス */
    StatusChange::NEGATIVE1,
    SC_ENERGYCOAT,              /* エナジーコート */
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    // 160-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    // 170-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_SELFDESTRUCTION,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    // 180-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    // 190-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    // 200-
    StatusChange::NEGATIVE1,
    SC_KEEPING,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_BARRIER,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_HALLUCINATION,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    // 210-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_STRIPWEAPON,
    SC_STRIPSHIELD,
    SC_STRIPARMOR,
    SC_STRIPHELM,
    StatusChange::NEGATIVE1,
    // 220-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    // 230-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_CP_WEAPON,
    SC_CP_SHIELD,
    SC_CP_ARMOR,
    SC_CP_HELM,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    // 240-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_AUTOGUARD,
    // 250-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_REFLECTSHIELD,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_DEVOTION,
    SC_PROVIDENCE,
    SC_DEFENDER,
    SC_SPEARSQUICKEN,
    StatusChange::NEGATIVE1,
    // 260-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_STEELBODY,
    SC_BLADESTOP_WAIT,
    // 270-
    SC_EXPLOSIONSPIRITS,
    SC_EXTREMITYFIST,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_MAGICROD,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    // 280-
    SC_FLAMELAUNCHER,
    SC_FROSTWEAPON,
    SC_LIGHTNINGLOADER,
    SC_SEISMICWEAPON,
    StatusChange::NEGATIVE1,
    SC_VOLCANO,
    SC_DELUGE,
    SC_VIOLENTGALE,
    SC_LANDPROTECTOR,
    StatusChange::NEGATIVE1,
    // 290-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    // 300-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_LULLABY,
    SC_RICHMANKIM,
    SC_ETERNALCHAOS,
    SC_DRUMBATTLE,
    // 310-
    SC_NIBELUNGEN,
    SC_ROKISWEIL,
    SC_INTOABYSS,
    SC_SIEGFRIED,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_DISSONANCE,
    StatusChange::NEGATIVE1,
    SC_WHISTLE,
    // 320-
    SC_ASSNCROS,
    SC_POEMBRAGI,
    SC_APPLEIDUN,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_UGLYDANCE,
    StatusChange::NEGATIVE1,
    SC_HUMMING,
    SC_DONTFORGETME,
    SC_FORTUNE,
    // 330-
    SC_SERVICE4U,
    SC_SELFDESTRUCTION,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    // 340-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    // 350-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_AURABLADE,
    SC_PARRYING,
    SC_CONCENTRATION,
    SC_TENSIONRELAX,
    SC_BERSERK,
    // 360-
    SC_BERSERK,
    SC_ASSUMPTIO,
    SC_BASILICA,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_MAGICPOWER,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_GOSPEL,
    // 370-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    // 380-
    SC_TRUESIGHT,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_WINDWALK,
    SC_MELTDOWN,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_CARTBOOST,
    StatusChange::NEGATIVE1,
    SC_CHASEWALK,
    // 390-
    SC_REJECTSWORD,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_MARIONETTE,
    StatusChange::NEGATIVE1,
    SC_HEADCRUSH,
    SC_JOINTBEAT,
    // 400-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    SC_MINDBREAKER,
    SC_MEMORIZE,
    SC_FOGWALL,
    SC_SPIDERWEB,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    // 410-
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
    StatusChange::NEGATIVE1,
};

struct skill_name_db skill_names[] =
{
    {AC_CHARGEARROW, "CHARGEARROW", "Charge_Arrow"},
    {AC_CONCENTRATION, "CONCENTRATION", "Improve_Concentration"},
    {AC_DOUBLE, "DOUBLE", "Double_Strafe"},
    {AC_MAKINGARROW, "MAKINGARROW", "Arrow_Creation"},
    {AC_OWL, "OWL", "Owl's_Eye"},
    {AC_SHOWER, "SHOWER", "Arrow_Shower"},
    {AC_VULTURE, "VULTURE", "Vulture's_Eye"},
    {ALL_RESURRECTION, "RESURRECTION", "Resurrection"},
    {AL_ANGELUS, "ANGELUS", "Angelus"},
    {AL_BLESSING, "BLESSING", "Blessing"},
    {AL_CRUCIS, "CRUCIS", "Signum_Crusis"},
    {AL_CURE, "CURE", "Cure"},
    {AL_DECAGI, "DECAGI", "Decrease_AGI"},
    {AL_DEMONBANE, "DEMONBANE", "Demon_Bane"},
    {AL_DP, "DP", "Divine_Protection"},
    {AL_HEAL, "HEAL", "Heal"},
    {AL_HOLYLIGHT, "HOLYLIGHT", "Holy_Light"},
    {AL_HOLYWATER, "HOLYWATER", "Aqua_Benedicta"},
    {AL_INCAGI, "INCAGI", "Increase_AGI"},
    {AL_PNEUMA, "PNEUMA", "Pneuma"},
    {AL_RUWACH, "RUWACH", "Ruwach"},
    {AL_TELEPORT, "TELEPORT", "Teleport"},
    {AL_WARP, "WARP", "Warp_Portal"},
    {AM_ACIDTERROR, "ACIDTERROR", "Acid_Terror"},
    {AM_AXEMASTERY, "AXEMASTERY", "Axe_Mastery"},
    {AM_BERSERKPITCHER, "BERSERKPITCHER", "Berserk Pitcher"},
    {AM_BIOETHICS, "BIOETHICS", "Bioethics"},
    {AM_BIOTECHNOLOGY, "BIOTECHNOLOGY", "Biotechnology"},
    {AM_CALLHOMUN, "CALLHOMUN", "Call_Homunculus"},
    {AM_CANNIBALIZE, "CANNIBALIZE", "Bio_Cannibalize"},
    {AM_CP_ARMOR, "ARMOR", "Chemical_Protection_Armor"},
    {AM_CP_HELM, "HELM", "Chemical_Protection_Helm"},
    {AM_CP_SHIELD, "SHIELD", "Chemical_Protection_Shield"},
    {AM_CP_WEAPON, "WEAPON", "Chemical_Protection_Weapon"},
    {AM_CREATECREATURE, "CREATECREATURE", "Life_Creation"},
    {AM_CULTIVATION, "CULTIVATION", "Cultivation"},
    {AM_DEMONSTRATION, "DEMONSTRATION", "Demonstration"},
    {AM_DRILLMASTER, "DRILLMASTER", "Drillmaster"},
    {AM_FLAMECONTROL, "FLAMECONTROL", "Flame_Control"},
    {AM_HEALHOMUN, "HEALHOMUN", "Heal_Homunculus"},
    {AM_LEARNINGPOTION, "LEARNINGPOTION", "AM_LEARNINGPOTION"},
    {AM_PHARMACY, "PHARMACY", "Pharmacy"},
    {AM_POTIONPITCHER, "POTIONPITCHER", "Potion_Pitcher"},
    {AM_REST, "REST", "Sabbath"},
    {AM_RESURRECTHOMUN, "RESURRECTHOMUN", "Ressurect_Homunculus"},
    {AM_SPHEREMINE, "SPHEREMINE", "Sphere_Mine"},
    {ASC_BREAKER, "BREAKER", "Breaker"},
    {ASC_CDP, "CDP", "Create_Deadly_Poison"},
    {ASC_EDP, "EDP", "Deadly_Poison_Enchantment"},
    {ASC_HALLUCINATION, "HALLUCINATION", "Hallucination_Walk"},
    {ASC_KATAR, "KATAR", "Advanced_Katar_Mastery"},
    {ASC_METEORASSAULT, "METEORASSAULT", "Meteor_Assault"},
    {AS_CLOAKING, "CLOAKING", "Cloaking"},
    {AS_ENCHANTPOISON, "ENCHANTPOISON", "Enchant_Poison"},
    {AS_GRIMTOOTH, "GRIMTOOTH", "Grimtooth"},
    {AS_KATAR, "KATAR", "Katar_Mastery"},
    {AS_LEFT, "LEFT", "Lefthand_Mastery"},
    {AS_POISONREACT, "POISONREACT", "Poison_React"},
    {AS_RIGHT, "RIGHT", "Righthand_Mastery"},
    {AS_SONICBLOW, "SONICBLOW", "Sonic_Blow"},
    {AS_SPLASHER, "SPLASHER", "Venom_Splasher"},
    {AS_VENOMDUST, "VENOMDUST", "Venom_Dust"},
    {BA_APPLEIDUN, "APPLEIDUN", "Apple_of_Idun"},
    {BA_ASSASSINCROSS, "ASSASSINCROSS", "Assassin_Cross"},
    {BA_DISSONANCE, "DISSONANCE", "Dissonance"},
    {BA_FROSTJOKE, "FROSTJOKE", "Dumb_Joke"},
    {BA_MUSICALLESSON, "MUSICALLESSON", "Musical_Lesson"},
    {BA_MUSICALSTRIKE, "MUSICALSTRIKE", "Musical_Strike"},
    {BA_POEMBRAGI, "POEMBRAGI", "Poem_of_Bragi"},
    {BA_WHISTLE, "WHISTLE", "Whistle"},
    {BD_ADAPTATION, "ADAPTATION", "Adaption"},
    {BD_DRUMBATTLEFIELD, "DRUMBATTLEFIELD", "Drumb_BattleField"},
    {BD_ENCORE, "ENCORE", "Encore"},
    {BD_ETERNALCHAOS, "ETERNALCHAOS", "Eternal_Chaos"},
    {BD_INTOABYSS, "INTOABYSS", "Into_the_Abyss"},
    {BD_LULLABY, "LULLABY", "Lullaby"},
    {BD_RAGNAROK, "RAGNAROK", "Ragnarok"},
    {BD_RICHMANKIM, "RICHMANKIM", "Rich_Mankim"},
    {BD_RINGNIBELUNGEN, "RINGNIBELUNGEN", "Ring_of_Nibelugen"},
    {BD_ROKISWEIL, "ROKISWEIL", "Loki's_Wail"},
    {BD_SIEGFRIED, "SIEGFRIED", "Invulnerable_Siegfried"},
    {BS_ADRENALINE, "ADRENALINE", "Adrenaline_Rush"},
    {BS_ADRENALINE2, "ADRENALINE2", "Adrenaline Rush 2"},
    {BS_AXE, "AXE", "Smith_Axe"},
    {BS_DAGGER, "DAGGER", "Smith_Dagger"},
    {BS_ENCHANTEDSTONE, "ENCHANTEDSTONE", "Enchantedstone_Craft"},
    {BS_FINDINGORE, "FINDINGORE", "Ore_Discovery"},
    {BS_HAMMERFALL, "HAMMERFALL", "Hammer_Fall"},
    {BS_HILTBINDING, "HILTBINDING", "Hilt_Binding"},
    {BS_IRON, "IRON", "Iron_Tempering"},
    {BS_KNUCKLE, "KNUCKLE", "Smith_Knucklebrace"},
    {BS_MACE, "MACE", "Smith_Mace"},
    {BS_MAXIMIZE, "MAXIMIZE", "Power_Maximize"},
    {BS_ORIDEOCON, "ORIDEOCON", "Orideocon_Research"},
    {BS_OVERTHRUST, "OVERTHRUST", "Power-Thrust"},
    {BS_REPAIRWEAPON, "REPAIRWEAPON", "Weapon_Repair"},
    {BS_SKINTEMPER, "SKINTEMPER", "Skin_Tempering"},
    {BS_SPEAR, "SPEAR", "Smith_Spear"},
    {BS_STEEL, "STEEL", "Steel_Tempering"},
    {BS_SWORD, "SWORD", "Smith_Sword"},
    {BS_TWOHANDSWORD, "TWOHANDSWORD", "Smith_Two-handed_Sword"},
    {BS_WEAPONPERFECT, "WEAPONPERFECT", "Weapon_Perfection"},
    {BS_WEAPONRESEARCH, "WEAPONRESEARCH", "Weaponry_Research"},
    {CG_ARROWVULCAN, "ARROWVULCAN", "Vulcan_Arrow"},
    {CG_MARIONETTE, "MARIONETTE", "Marionette_Control"},
    {CG_MOONLIT, "MOONLIT", "Moonlight_Petals"},
    {CH_CHAINCRUSH, "CHAINCRUSH", "Chain_Crush_Combo"},
    {CH_PALMSTRIKE, "PALMSTRIKE", "Palm_Push_Strike"},
    {CH_SOULCOLLECT, "SOULCOLLECT", "Collect_Soul"},
    {CH_TIGERFIST, "TIGERFIST", "Tiger_Knuckle_Fist"},
    {CR_ALCHEMY, "ALCHEMY", "Alchemy"},
    {CR_AUTOGUARD, "AUTOGUARD", "Guard"},
    {CR_DEFENDER, "DEFENDER", "Defender"},
    {CR_DEVOTION, "DEVOTION", "Sacrifice"},
    {CR_GRANDCROSS, "GRANDCROSS", "Grand_Cross"},
    {CR_HOLYCROSS, "HOLYCROSS", "Holy_Cross"},
    {CR_PROVIDENCE, "PROVIDENCE", "Providence"},
    {CR_REFLECTSHIELD, "REFLECTSHIELD", "Shield_Reflect"},
    {CR_SHIELDBOOMERANG, "SHIELDBOOMERANG", "Shield_Boomerang"},
    {CR_SHIELDCHARGE, "SHIELDCHARGE", "Shield_Charge"},
    {CR_SPEARQUICKEN, "SPEARQUICKEN", "Spear_Quicken"},
    {CR_SYNTHESISPOTION, "SYNTHESISPOTION", "Potion_Synthesis"},
    {CR_TRUST, "TRUST", "Faith"},
    {DC_DANCINGLESSON, "DANCINGLESSON", "Dancing_Lesson"},
    {DC_DONTFORGETME, "DONTFORGETME", "Don't_Forget_Me"},
    {DC_FORTUNEKISS, "FORTUNEKISS", "Fortune_Kiss"},
    {DC_HUMMING, "HUMMING", "Humming"},
    {DC_SCREAM, "SCREAM", "Scream"},
    {DC_SERVICEFORYOU, "SERVICEFORYOU", "Prostitute"},
    {DC_THROWARROW, "THROWARROW", "Throw_Arrow"},
    {DC_UGLYDANCE, "UGLYDANCE", "Ugly_Dance"},
    {HP_ASSUMPTIO, "ASSUMPTIO", "Assumptio"},
    {HP_BASILICA, "BASILICA", "Basilica"},
    {HP_MEDITATIO, "MEDITATIO", "Meditation"},
    {HT_ANKLESNARE, "ANKLESNARE", "Ankle_Snare"},
    {HT_BEASTBANE, "BEASTBANE", "Beast_Bane"},
    {HT_BLASTMINE, "BLASTMINE", "Blast_Mine"},
    {HT_BLITZBEAT, "BLITZBEAT", "Blitz_Beat"},
    {HT_CLAYMORETRAP, "CLAYMORETRAP", "Claymore_Trap"},
    {HT_DETECTING, "DETECTING", "Detect"},
    {HT_FALCON, "FALCON", "Falconry_Mastery"},
    {HT_FLASHER, "FLASHER", "Flasher"},
    {HT_FREEZINGTRAP, "FREEZINGTRAP", "Freezing_Trap"},
    {HT_LANDMINE, "LANDMINE", "Land_Mine"},
    {HT_REMOVETRAP, "REMOVETRAP", "Remove_Trap"},
    {HT_SANDMAN, "SANDMAN", "Sandman"},
    {HT_SHOCKWAVE, "SHOCKWAVE", "Shockwave_Trap"},
    {HT_SKIDTRAP, "SKIDTRAP", "Skid_Trap"},
    {HT_SPRINGTRAP, "SPRINGTRAP", "Spring_Trap"},
    {HT_STEELCROW, "STEELCROW", "Steel_Crow"},
    {HT_TALKIEBOX, "TALKIEBOX", "Talkie_Box"},
    {HW_MAGICCRASHER, "MAGICCRASHER", "Magic_Crasher"},
    {HW_MAGICPOWER, "MAGICPOWER", "Magic_Power"},
    {HW_NAPALMVULCAN, "NAPALMVULCAN", "Napalm_Vulcan"},
    {HW_SOULDRAIN, "SOULDRAIN", "Soul_Drain"},
    {KN_AUTOCOUNTER, "AUTOCOUNTER", "Counter_Attack"},
    {KN_BOWLINGBASH, "BOWLINGBASH", "Bowling_Bash"},
    {KN_BRANDISHSPEAR, "BRANDISHSPEAR", "Brandish_Spear"},
    {KN_CAVALIERMASTERY, "CAVALIERMASTERY", "Cavalier_Mastery"},
    {KN_PIERCE, "PIERCE", "Pierce"},
    {KN_RIDING, "RIDING", "Peco_Peco_Ride"},
    {KN_SPEARBOOMERANG, "SPEARBOOMERANG", "Spear_Boomerang"},
    {KN_SPEARMASTERY, "SPEARMASTERY", "Spear_Mastery"},
    {KN_SPEARSTAB, "SPEARSTAB", "Spear_Stab"},
    {KN_TWOHANDQUICKEN, "TWOHANDQUICKEN", "Twohand_Quicken"},
    {LK_AURABLADE, "AURABLADE", "Aura_Blade"},
    {LK_BERSERK, "BERSERK", "Berserk"},
    {LK_CONCENTRATION, "CONCENTRATION", "Concentration"},
    {LK_FURY, "FURY", "LK_FURY"},
    {LK_HEADCRUSH, "HEADCRUSH", "Head_Crusher"},
    {LK_JOINTBEAT, "JOINTBEAT", "Joint_Beat"},
    {LK_PARRYING, "PARRYING", "Parrying"},
    {LK_SPIRALPIERCE, "SPIRALPIERCE", "Spiral_Pierce"},
    {LK_TENSIONRELAX, "TENSIONRELAX", "Tension_Relax"},
    {MC_CARTREVOLUTION, "CARTREVOLUTION", "Cart_Revolution"},
    {MC_CHANGECART, "CHANGECART", "Change_Cart"},
    {MC_DISCOUNT, "DISCOUNT", "Discount"},
    {MC_IDENTIFY, "IDENTIFY", "Item_Appraisal"},
    {MC_INCCARRY, "INCCARRY", "Enlarge_Weight_Limit"},
    {MC_LOUD, "LOUD", "Lord_Exclamation"},
    {MC_MAMMONITE, "MAMMONITE", "Mammonite"},
    {MC_OVERCHARGE, "OVERCHARGE", "Overcharge"},
    {MC_PUSHCART, "PUSHCART", "Pushcart"},
    {MG_COLDBOLT, "COLDBOLT", "Cold_Bolt"},
    {MG_ENERGYCOAT, "ENERGYCOAT", "Energy_Coat"},
    {MG_FIREBALL, "FIREBALL", "Fire_Ball"},
    {MG_FIREBOLT, "FIREBOLT", "Fire_Bolt"},
    {MG_FIREWALL, "FIREWALL", "Fire_Wall"},
    {MG_FROSTDIVER, "FROSTDIVER", "Frost_Diver"},
    {MG_LIGHTNINGBOLT, "LIGHTNINGBOLT", "Lightening_Bolt"},
    {MG_NAPALMBEAT, "NAPALMBEAT", "Napalm_Beat"},
    {MG_SAFETYWALL, "SAFETYWALL", "Safety_Wall"},
    {MG_SIGHT, "SIGHT", "Sight"},
    {MG_SOULSTRIKE, "SOULSTRIKE", "Soul_Strike"},
    {MG_SRECOVERY, "SRECOVERY", "Increase_SP_Recovery"},
    {MG_STONECURSE, "STONECURSE", "Stone_Curse"},
    {MG_THUNDERSTORM, "THUNDERSTORM", "Thunderstorm"},
    {MO_ABSORBSPIRITS, "ABSORBSPIRITS", "Absorb_Spirits"},
    {MO_BLADESTOP, "BLADESTOP", "Blade_Stop"},
    {MO_BODYRELOCATION, "BODYRELOCATION", "Body_Relocation"},
    {MO_CALLSPIRITS, "CALLSPIRITS", "Call_Spirits"},
    {MO_CHAINCOMBO, "CHAINCOMBO", "Chain_Combo"},
    {MO_COMBOFINISH, "COMBOFINISH", "Combo_Finish"},
    {MO_DODGE, "DODGE", "Dodge"},
    {MO_EXPLOSIONSPIRITS, "EXPLOSIONSPIRITS", "Explosion_Spirits"},
    {MO_EXTREMITYFIST, "EXTREMITYFIST", "Extremity_Fist"},
    {MO_FINGEROFFENSIVE, "FINGEROFFENSIVE", "Finger_Offensive"},
    {MO_INVESTIGATE, "INVESTIGATE", "Investigate"},
    {MO_IRONHAND, "IRONHAND", "Iron_Hand"},
    {MO_SPIRITSRECOVERY, "SPIRITSRECOVERY", "Spirit_Recovery"},
    {MO_STEELBODY, "STEELBODY", "Steel_Body"},
    {MO_TRIPLEATTACK, "TRIPLEATTACK", "Triple_Blows"},
    {NPC_ATTRICHANGE, "ATTRICHANGE", "NPC_ATTRICHANGE"},
    {NPC_BARRIER, "BARRIER", "NPC_BARRIER"},
    {NPC_BLINDATTACK, "BLINDATTACK", "NPC_BLINDATTACK"},
    {NPC_BLOODDRAIN, "BLOODDRAIN", "NPC_BLOODDRAIN"},
    {NPC_CHANGEDARKNESS, "CHANGEDARKNESS", "NPC_CHANGEDARKNESS"},
    {NPC_CHANGEFIRE, "CHANGEFIRE", "NPC_CHANGEFIRE"},
    {NPC_CHANGEGROUND, "CHANGEGROUND", "NPC_CHANGEGROUND"},
    {NPC_CHANGEHOLY, "CHANGEHOLY", "NPC_CHANGEHOLY"},
    {NPC_CHANGEPOISON, "CHANGEPOISON", "NPC_CHANGEPOISON"},
    {NPC_CHANGETELEKINESIS, "CHANGETELEKINESIS", "NPC_CHANGETELEKINESIS"},
    {NPC_CHANGEWATER, "CHANGEWATER", "NPC_CHANGEWATER"},
    {NPC_CHANGEWIND, "CHANGEWIND", "NPC_CHANGEWIND"},
    {NPC_COMBOATTACK, "COMBOATTACK", "NPC_COMBOATTACK"},
    {NPC_CRITICALSLASH, "CRITICALSLASH", "NPC_CRITICALSLASH"},
    {NPC_CURSEATTACK, "CURSEATTACK", "NPC_CURSEATTACK"},
    {NPC_DARKBLESSING, "DARKBLESSING", "NPC_DARKBLESSING"},
    {NPC_DARKBREATH, "DARKBREATH", "NPC_DARKBREATH"},
    {NPC_DARKCROSS, "DARKCROSS", "NPC_DARKCROSS"},
    {NPC_DARKNESSATTACK, "DARKNESSATTACK", "NPC_DARKNESSATTACK"},
    {NPC_DEFENDER, "DEFENDER", "NPC_DEFENDER"},
    {NPC_EMOTION, "EMOTION", "NPC_EMOTION"},
    {NPC_ENERGYDRAIN, "ENERGYDRAIN", "NPC_ENERGYDRAIN"},
    {NPC_FIREATTACK, "FIREATTACK", "NPC_FIREATTACK"},
    {NPC_GROUNDATTACK, "GROUNDATTACK", "NPC_GROUNDATTACK"},
    {NPC_GUIDEDATTACK, "GUIDEDATTACK", "NPC_GUIDEDATTACK"},
    {NPC_HALLUCINATION, "HALLUCINATION", "NPC_HALLUCINATION"},
    {NPC_HOLYATTACK, "HOLYATTACK", "NPC_HOLYATTACK"},
    {NPC_KEEPING, "KEEPING", "NPC_KEEPING"},
    {NPC_LICK, "LICK", "NPC_LICK"},
    {NPC_MAGICALATTACK, "MAGICALATTACK", "NPC_MAGICALATTACK"},
    {NPC_MENTALBREAKER, "MENTALBREAKER", "NPC_MENTALBREAKER"},
    {NPC_METAMORPHOSIS, "METAMORPHOSIS", "NPC_METAMORPHOSIS"},
    {NPC_PETRIFYATTACK, "PETRIFYATTACK", "NPC_PETRIFYATTACK"},
    {NPC_PIERCINGATT, "PIERCINGATT", "NPC_PIERCINGATT"},
    {NPC_POISON, "POISON", "NPC_POISON"},
    {NPC_POISONATTACK, "POISONATTACK", "NPC_POISONATTACK"},
    {NPC_RANDOMATTACK, "RANDOMATTACK", "NPC_RANDOMATTACK"},
    {NPC_RANGEATTACK, "RANGEATTACK", "NPC_RANGEATTACK"},
    {NPC_REBIRTH, "REBIRTH", "NPC_REBIRTH"},
    {NPC_SELFDESTRUCTION, "SELFDESTRUCTION", "Kabooooom!"},
    {NPC_SELFDESTRUCTION2, "SELFDESTRUCTION2", "NPC_SELFDESTRUCTION2"},
    {NPC_SILENCEATTACK, "SILENCEATTACK", "NPC_SILENCEATTACK"},
    {NPC_SLEEPATTACK, "SLEEPATTACK", "NPC_SLEEPATTACK"},
    {NPC_SMOKING, "SMOKING", "NPC_SMOKING"},
    {NPC_SPLASHATTACK, "SPLASHATTACK", "NPC_SPLASHATTACK"},
    {NPC_STUNATTACK, "STUNATTACK", "NPC_STUNATTACK"},
    {NPC_SUICIDE, "SUICIDE", "NPC_SUICIDE"},
    {NPC_SUMMONMONSTER, "SUMMONMONSTER", "NPC_SUMMONMONSTER"},
    {NPC_SUMMONSLAVE, "SUMMONSLAVE", "NPC_SUMMONSLAVE"},
    {NPC_TELEKINESISATTACK, "TELEKINESISATTACK", "NPC_TELEKINESISATTACK"},
    {NPC_TRANSFORMATION, "TRANSFORMATION", "NPC_TRANSFORMATION"},
    {NPC_WATERATTACK, "WATERATTACK", "NPC_WATERATTACK"},
    {NPC_WINDATTACK, "WINDATTACK", "NPC_WINDATTACK"},
    {NV_EMOTE, "EMOTE", "Emote_Skill"},
    {NV_TRADE, "TRADE", "Trade_Skill"},
    {NV_PARTY, "PARTY", "Party_Skill"},
    {NV_FIRSTAID, "FIRSTAID", "First Aid"},
    {NV_TRICKDEAD, "TRICKDEAD", "Play_Dead"},
    {PA_GOSPEL, "GOSPEL", "Gospel"},
    {PA_PRESSURE, "PRESSURE", "Pressure"},
    {PA_SACRIFICE, "SACRIFICE", "Sacrificial_Ritual"},
    {PF_FOGWALL, "FOGWALL", "Wall_of_Fog"},
    {PF_HPCONVERSION, "HPCONVERSION", "Health_Conversion"},
    {PF_MEMORIZE, "MEMORIZE", "Memorize"},
    {PF_MINDBREAKER, "MINDBREAKER", "Mind_Breaker"},
    {PF_SOULBURN, "SOULBURN", "Soul_Burn"},
    {PF_SOULCHANGE, "SOULCHANGE", "Soul_Change"},
    {PF_SPIDERWEB, "SPIDERWEB", "Spider_Web"},
    {PR_ASPERSIO, "ASPERSIO", "Aspersio"},
    {PR_BENEDICTIO, "BENEDICTIO", "B.S_Sacramenti"},
    {PR_GLORIA, "GLORIA", "Gloria"},
    {PR_IMPOSITIO, "IMPOSITIO", "Impositio_Manus"},
    {PR_KYRIE, "KYRIE", "Kyrie_Eleison"},
    {PR_LEXAETERNA, "LEXAETERNA", "Lex_Aeterna"},
    {PR_LEXDIVINA, "LEXDIVINA", "Lex_Divina"},
    {PR_MACEMASTERY, "MACEMASTERY", "Mace_Mastery"},
    {PR_MAGNIFICAT, "MAGNIFICAT", "Magnificat"},
    {PR_MAGNUS, "MAGNUS", "Magnus_Exorcismus"},
    {PR_SANCTUARY, "SANCTUARY", "Santuary"},
    {PR_SLOWPOISON, "SLOWPOISON", "Slow_Poison"},
    {PR_STRECOVERY, "STRECOVERY", "Status_Recovery"},
    {PR_SUFFRAGIUM, "SUFFRAGIUM", "Suffragium"},
    {PR_TURNUNDEAD, "TURNUNDEAD", "Turn_Undead"},
    {RG_BACKSTAP, "BACKSTAP", "Back_Stab"},
    {RG_CLEANER, "CLEANER", "Remover"},
    {RG_COMPULSION, "COMPULSION", "Compulsion_Discount"},
    {RG_FLAGGRAFFITI, "FLAGGRAFFITI", "Flag_Graffity"},
    {RG_GANGSTER, "GANGSTER", "Gangster's_Paradise"},
    {RG_GRAFFITI, "GRAFFITI", "Graffiti"},
    {RG_INTIMIDATE, "INTIMIDATE", "Intimidate"},
    {RG_PLAGIARISM, "PLAGIARISM", "Plagiarism"},
    {RG_RAID, "RAID", "Raid"},
    {RG_SNATCHER, "SNATCHER", "Snatcher"},
    {RG_STEALCOIN, "STEALCOIN", "Steal_Coin"},
    {RG_STRIPARMOR, "STRIPARMOR", "Strip_Armor"},
    {RG_STRIPHELM, "STRIPHELM", "Strip_Helm"},
    {RG_STRIPSHIELD, "STRIPSHIELD", "Strip_Shield"},
    {RG_STRIPWEAPON, "STRIPWEAPON", "Strip_Weapon"},
    {RG_TUNNELDRIVE, "TUNNELDRIVE", "Tunnel_Drive"},
    {SA_ABRACADABRA, "ABRACADABRA", "Hocus-pocus"},
    {SA_ADVANCEDBOOK, "ADVANCEDBOOK", "Advanced_Book"},
    {SA_AUTOSPELL, "AUTOSPELL", "Auto_Cast"},
    {SA_CASTCANCEL, "CASTCANCEL", "Cast_Cancel"},
    {SA_CLASSCHANGE, "CLASSCHANGE", "Class_Change"},
    {SA_COMA, "COMA", "Coma"},
    {SA_DEATH, "DEATH", "Death"},
    {SA_DELUGE, "DELUGE", "Deluge"},
    {SA_DISPELL, "DISPELL", "Dispel"},
    {SA_DRAGONOLOGY, "DRAGONOLOGY", "Dragonology"},
    {SA_FLAMELAUNCHER, "FLAMELAUNCHER", "Flame_Launcher"},
    {SA_FORTUNE, "FORTUNE", "Fortune"},
    {SA_FREECAST, "FREECAST", "Cast_Freedom"},
    {SA_FROSTWEAPON, "FROSTWEAPON", "Frost_Weapon"},
    {SA_FULLRECOVERY, "FULLRECOVERY", "Full_Recovery"},
    {SA_GRAVITY, "GRAVITY", "Gravity"},
    {SA_INSTANTDEATH, "INSTANTDEATH", "Instant_Death"},
    {SA_LANDPROTECTOR, "LANDPROTECTOR", "Land_Protector"},
    {SA_LEVELUP, "LEVELUP", "Level_Up"},
    {SA_LIGHTNINGLOADER, "LIGHTNINGLOADER", "Lightning_Loader"},
    {SA_MAGICROD, "MAGICROD", "Magic_Rod"},
    {SA_MONOCELL, "MONOCELL", "Monocell"},
    {SA_QUESTION, "QUESTION", "Question?"},
    {SA_REVERSEORCISH, "REVERSEORCISH", "Reverse_Orcish"},
    {SA_SEISMICWEAPON, "SEISMICWEAPON", "Seismic_Weapon"},
    {SA_SPELLBREAKER, "SPELLBREAKER", "Break_Spell"},
    {SA_SUMMONMONSTER, "SUMMONMONSTER", "Summon_Monster"},
    {SA_VIOLENTGALE, "VIOLENTGALE", "Violent_Gale"},
    {SA_VOLCANO, "VOLCANO", "Volcano"},
    {SG_DEVIL, "DEVIL", "Devil"},
    {SG_FEEL, "FEEL", "Feel"},
    {SG_FRIEND, "FRIEND", "Friend"},
    {SG_FUSION, "FUSION", "Fusion"},
    {SG_HATE, "HATE", "Hate"},
    {SG_KNOWLEDGE, "KNOWLEDGE", "Knowledge"},
    {SG_MOON_ANGER, "ANGER", "Moon Anger"},
    {SG_MOON_BLESS, "BLESS", "Moon Bless"},
    {SG_MOON_COMFORT, "COMFORT", "Moon Comfort"},
    {SG_MOON_WARM, "WARM", "Moon Warm"},
    {SG_STAR_ANGER, "ANGER", "Star Anger"},
    {SG_STAR_BLESS, "BLESS", "Star Bless"},
    {SG_STAR_COMFORT, "COMFORT", "Star Comfort"},
    {SG_STAR_WARM, "WARM", "Star Warm"},
    {SG_SUN_ANGER, "ANGER", "Sun Anger"},
    {SG_SUN_BLESS, "BLESS", "Sun Bless"},
    {SG_SUN_COMFORT, "COMFORT", "Sun Comfort"},
    {SG_SUN_WARM, "WARM", "Sun Warm"},
    {SL_ALCHEMIST, "ALCHEMIST", "Alchemist"},
    {SL_ASSASIN, "ASSASIN", "Assasin"},
    {SL_BARDDANCER, "BARDDANCER", "Bard Dancer"},
    {SL_BLACKSMITH, "BLACKSMITH", "Black Smith"},
    {SL_CRUSADER, "CRUSADER", "Crusader"},
    {SL_HUNTER, "HUNTER", "Hunter"},
    {SL_KAAHI, "KAAHI", "Kaahi"},
    {SL_KAINA, "KAINA", "Kaina"},
    {SL_KAITE, "KAITE", "Kaite"},
    {SL_KAIZEL, "KAIZEL", "Kaizel"},
    {SL_KAUPE, "KAUPE", "Kaupe"},
    {SL_KNIGHT, "KNIGHT", "Knight"},
    {SL_MONK, "MONK", "Monk"},
    {SL_PRIEST, "PRIEST", "Priest"},
    {SL_ROGUE, "ROGUE", "Rogue"},
    {SL_SAGE, "SAGE", "Sage"},
    {SL_SKA, "SKA", "SKA"},
    {SL_SKE, "SKE", "SKE"},
    {SL_SMA, "SMA", "SMA"},
    {SL_SOULLINKER, "SOULLINKER", "Soul Linker"},
    {SL_STAR, "STAR", "Star"},
    {SL_STIN, "STIN", "Stin"},
    {SL_STUN, "STUN", "Stun"},
    {SL_SUPERNOVICE, "SUPERNOVICE", "Super Novice"},
    {SL_SWOO, "SWOO", "Swoo"},
    {SL_WIZARD, "WIZARD", "Wizard"},
    {SM_AUTOBERSERK, "AUTOBERSERK", "Auto_Berserk"},
    {SM_BASH, "BASH", "Bash"},
    {SM_ENDURE, "ENDURE", "Endure"},
    {SM_FATALBLOW, "FATALBLOW", "Attack_Weak_Point"},
    {SM_MAGNUM, "MAGNUM", "Magnum_Break"},
    {SM_MOVINGRECOVERY, "MOVINGRECOVERY", "Moving_HP_Recovery"},
    {SM_PROVOKE, "PROVOKE", "Provoke"},
    {SM_RECOVERY, "RECOVERY", "Increase_HP_Recovery"},
    {SM_SWORD, "SWORD", "Sword_Mastery"},
    {SM_TWOHAND, "TWOHAND", "Two-Handed_Sword_Mastery"},
    {SN_FALCONASSAULT, "FALCONASSAULT", "Falcon_Assault"},
    {SN_SHARPSHOOTING, "SHARPSHOOTING", "Sharpshooting"},
    {SN_SIGHT, "SIGHT", "True_Sight"},
    {SN_WINDWALK, "WINDWALK", "Wind_Walk"},
    {ST_CHASEWALK, "CHASEWALK", "Chase_Walk"},
    {ST_REJECTSWORD, "REJECTSWORD", "Reject_Sword"},
    {ST_STEALBACKPACK, "STEALBACKPACK", "Steal_Backpack"},
    {TF_BACKSLIDING, "BACKSLIDING", "Back_Sliding"},
    {TF_DETOXIFY, "DETOXIFY", "Detoxify"},
    {TF_DOUBLE, "DOUBLE", "Double_Attack"},
    {TF_HIDING, "HIDING", "Hiding"},
    {TF_MISS, "MISS", "Improve_Dodge"},
    {TF_PICKSTONE, "PICKSTONE", "Take_Stone"},
    {TF_POISON, "POISON", "Envenom"},
    {TF_SPRINKLESAND, "SPRINKLESAND", "Throw_Sand"},
    {TF_STEAL, "STEAL", "Steal"},
    {TF_THROWSTONE, "THROWSTONE", "Throw_Stone"},
    {TK_COUNTER, "COUNTER", "Counter"},
    {TK_DODGE, "DODGE", "Dodge"},
    {TK_DOWNKICK, "DOWNKICK", "Down Kick"},
    {TK_HIGHJUMP, "HIGHJUMP", "High Jump"},
    {TK_HPTIME, "HPTIME", "HP Time"},
    {TK_JUMPKICK, "JUMPKICK", "Jump Kick"},
    {TK_POWER, "POWER", "Power"},
    {TK_READYCOUNTER, "READYCOUNTER", "Ready Counter"},
    {TK_READYDOWN, "READYDOWN", "Ready Down"},
    {TK_READYSTORM, "READYSTORM", "Ready Storm"},
    {TK_READYTURN, "READYTURN", "Ready Turn"},
    {TK_RUN, "RUN", "TK_RUN"},
    {TK_SEVENWIND, "SEVENWIND", "Seven Wind"},
    {TK_SPTIME, "SPTIME", "SP Time"},
    {TK_STORMKICK, "STORMKICK", "Storm Kick"},
    {TK_TURNKICK, "TURNKICK", "Turn Kick"},
    {WE_BABY, "BABY", "Adopt_Baby"},
    {WE_CALLBABY, "CALLBABY", "Call_Baby"},
    {WE_CALLPARENT, "CALLPARENT", "Call_Parent"},
    {WE_CALLPARTNER, "CALLPARTNER", "I Want to See You"},
    {WE_FEMALE, "FEMALE", "I Only Look Up to You"},
    {WE_MALE, "MALE", "I Will Protect You"},
    {WS_CARTBOOST, "CARTBOOST", "Cart_Boost"},
    {WS_CREATECOIN, "CREATECOIN", "Create_Coins"},
    {WS_CREATENUGGET, "CREATENUGGET", "Create_Nuggets"},
    {WS_MELTDOWN, "MELTDOWN", "Meltdown"},
    {WS_SYSTEMCREATE, "SYSTEMCREATE", "Create_System_tower"},
    {WZ_EARTHSPIKE, "EARTHSPIKE", "Earth_Spike"},
    {WZ_ESTIMATION, "ESTIMATION", "Sense"},
    {WZ_FIREIVY, "FIREIVY", "Fire_Ivy"},
    {WZ_FIREPILLAR, "FIREPILLAR", "Fire_Pillar"},
    {WZ_FROSTNOVA, "FROSTNOVA", "Frost_Nova"},
    {WZ_HEAVENDRIVE, "HEAVENDRIVE", "Heaven's_Drive"},
    {WZ_ICEWALL, "ICEWALL", "Ice_Wall"},
    {WZ_JUPITEL, "JUPITEL", "Jupitel_Thunder"},
    {WZ_METEOR, "METEOR", "Meteor_Storm"},
    {WZ_QUAGMIRE, "QUAGMIRE", "Quagmire"},
    {WZ_SIGHTRASHER, "SIGHTRASHER", "Sightrasher"},
    {WZ_STORMGUST, "STORMGUST", "Storm_Gust"},
    {WZ_VERMILION, "VERMILION", "Lord_of_Vermilion"},
    {WZ_WATERBALL, "WATERBALL", "Water_Ball"},
    {SkillID::ZERO, nullptr, nullptr}
};

static
const int dirx[8] = { 0, -1, -1, -1, 0, 1, 1, 1 };
static
const int diry[8] = { 1, 1, 0, -1, -1, -1, 0, 1 };

static
int rdamage;

earray<struct skill_db, SkillID, MAX_SKILL_DB> skill_db;


static
int skill_addtimerskill(struct block_list *src, unsigned int tick,
        int target, int x, int y, SkillID skill_id, int skill_lv,
        skill_timerskill::sktst type, BCT flag);
static
int skill_attack(BF attack_type, struct block_list *src,
        struct block_list *dsrc, struct block_list *bl,
        SkillID skillid, int skilllv, unsigned int tick, BCT flag);
static
void skill_brandishspear_dir(struct square *tc, int dir, int are);
static
void skill_brandishspear_first(struct square *tc, int dir, int x, int y);
static
int skill_delunitgroup(struct skill_unit_group *group);
static
void skill_devotion_end(struct map_session_data *md,
        struct map_session_data *sd, int target);
static
struct skill_unit *skill_initunit(struct skill_unit_group *group, int idx,
        int x, int y);
static
struct skill_unit_group *skill_initunitgroup(struct block_list *src,
        int count, SkillID skillid, int skilllv, int unit_id);
static
void skill_status_change_timer(timer_id tid, tick_t tick,
        custom_id_t id, custom_data_t data);
static
int skill_unitgrouptickset_delete(struct block_list *bl, int group_id);
static
struct skill_unit_group_tickset *skill_unitgrouptickset_search(
        struct block_list *bl, int group_id);


int skill_get_hit(SkillID id)
{
    return skill_db[id].hit;
}

int skill_get_inf(SkillID id)
{
    return skill_db[id].inf;
}

int skill_get_pl(SkillID id)
{
    return skill_db[id].pl;
}

int skill_get_nk(SkillID id)
{
    return skill_db[id].nk;
}

int skill_get_max(SkillID id)
{
    return skill_db[id].max;
}

int skill_get_max_raise(SkillID id)
{
    return skill_db[id].max_raise;
}

int skill_get_range(SkillID id, int lv)
{
    return (lv <= 0) ? 0 : skill_db[id].range[lv - 1];
}

static
int skill_get_hp(SkillID id, int lv)
{
    return (lv <= 0) ? 0 : skill_db[id].hp[lv - 1];
}

int skill_get_sp(SkillID id, int lv)
{
    return (lv <= 0) ? 0 : skill_db[id].sp[lv - 1];
}

static
int skill_get_zeny(SkillID id, int lv)
{
    return (lv <= 0) ? 0 : skill_db[id].zeny[lv - 1];
}

int skill_get_num(SkillID id, int lv)
{
    return (lv <= 0) ? 0 : skill_db[id].num[lv - 1];
}

int skill_get_cast(SkillID id, int lv)
{
    return (lv <= 0) ? 0 : skill_db[id].cast[lv - 1];
}

int skill_get_delay(SkillID id, int lv)
{
    return (lv <= 0) ? 0 : skill_db[id].delay[lv - 1];
}

int skill_get_time(SkillID id, int lv)
{
    return (lv <= 0) ? 0 : skill_db[id].upkeep_time[lv - 1];
}

int skill_get_time2(SkillID id, int lv)
{
    return (lv <= 0) ? 0 : skill_db[id].upkeep_time2[lv - 1];
}

int skill_get_castdef(SkillID id)
{
    return skill_db[id].cast_def_rate;
}

int skill_get_weapontype(SkillID id)
{
    return skill_db[id].weapon;
}

int skill_get_inf2(SkillID id)
{
    return skill_db[id].inf2;
}

int skill_get_maxcount(SkillID id)
{
    return skill_db[id].maxcount;
}

int skill_get_blewcount(SkillID id, int lv)
{
    return (lv <= 0) ? 0 : skill_db[id].blewcount[lv - 1];
}

static
int skill_get_mhp(SkillID id, int lv)
{
    return (lv <= 0) ? 0 : skill_db[id].mhp[lv - 1];
}

static
int skill_get_castnodex(SkillID id, int lv)
{
    return (lv <= 0) ? 0 : skill_db[id].castnodex[lv - 1];
}

/* プロトタイプ */
static
struct skill_unit_group *skill_unitsetting(struct block_list *src,
                                            SkillID skillid, int skilllv,
                                            int x, int y, int flag);
static
int skill_check_condition(struct map_session_data *sd, int type);
static
void skill_frostjoke_scream(struct block_list *bl,
        struct block_list *src, SkillID skillnum, int skilllv, unsigned int tick);
static
void skill_status_change_timer_sub(struct block_list *bl,
        struct block_list *src, StatusChange type, unsigned int tick);
static
void skill_clear_element_field(struct block_list *bl);
static
void skill_landprotector(struct block_list *bl, SkillID skillid, int *alive);
static
void skill_trap_splash(struct block_list *bl,
        struct block_list *src, int tick, int splash_count);
static
void skill_count_target(struct block_list *bl,
        struct block_list *src, int *c);

// [MouseJstr] - skill ok to cast? and when?
static
int skillnotok(SkillID skillid, struct map_session_data *sd)
{
    if (sd == 0)
        return 0;
    if (pc_isGM(sd) >= 20)
        return 0;               // gm's can do anything damn thing they want
    switch (skillid)
    {
        case AL_WARP:
        case AL_TELEPORT:
        case MC_IDENTIFY:
            return 0;           // always allowed
        default:
            return (map[sd->bl.m].flag.noskill);
    }
}

static
int distance(int x0, int y0, int x1, int y1)
{
    int dx, dy;

    dx = abs(x0 - x1);
    dy = abs(y0 - y1);
    return dx > dy ? dx : dy;
}

/* スキルユニットIDを返す(これもデータベースに入れたいな) */
static
int skill_get_unit_id(SkillID id, int flag)
{

    switch (id)
    {
        case MG_SAFETYWALL:
            return 0x7e;        /* セイフティウォール */
        case MG_FIREWALL:
            return 0x7f;        /* ファイアーウォール */
        case AL_WARP:
            return (flag == 0) ? 0x81 : 0x80;   /* ワープポータル */
        case PR_BENEDICTIO:
            return 0x82;        /* 聖体降福 */
        case PR_SANCTUARY:
            return 0x83;        /* サンクチュアリ */
        case PR_MAGNUS:
            return 0x84;        /* マグヌスエクソシズム */
        case AL_PNEUMA:
            return 0x85;        /* ニューマ */
        case MG_THUNDERSTORM:
            return 0x86;        /* サンダーストーム */
        case WZ_HEAVENDRIVE:
            return 0x86;        /* ヘヴンズドライブ */
        case WZ_SIGHTRASHER:
            return 0x86;        /* サイトラッシャー */
        case WZ_METEOR:
            return 0x86;        /* メテオストーム */
        case WZ_VERMILION:
            return 0x86;        /* ロードオブヴァーミリオン */
        case WZ_FROSTNOVA:
            return 0x86;        /* フロストノヴァ */
        case WZ_STORMGUST:
            return 0x86;        /* ストームガスト(とりあえずLoVと同じで処理) */
        case CR_GRANDCROSS:
            return 0x86;        /* グランドクロス */
        case WZ_FIREPILLAR:
            return (flag == 0) ? 0x87 : 0x88;   /* ファイアーピラー */
        case HT_TALKIEBOX:
            return 0x99;        /* トーキーボックス */
        case WZ_ICEWALL:
            return 0x8d;        /* アイスウォール */
        case WZ_QUAGMIRE:
            return 0x8e;        /* クァグマイア */
        case HT_BLASTMINE:
            return 0x8f;        /* ブラストマイン */
        case HT_SKIDTRAP:
            return 0x90;        /* スキッドトラップ */
        case HT_ANKLESNARE:
            return 0x91;        /* アンクルスネア */
        case AS_VENOMDUST:
            return 0x92;        /* ベノムダスト */
        case HT_LANDMINE:
            return 0x93;        /* ランドマイン */
        case HT_SHOCKWAVE:
            return 0x94;        /* ショックウェーブトラップ */
        case HT_SANDMAN:
            return 0x95;        /* サンドマン */
        case HT_FLASHER:
            return 0x96;        /* フラッシャー */
        case HT_FREEZINGTRAP:
            return 0x97;        /* フリージングトラップ */
        case HT_CLAYMORETRAP:
            return 0x98;        /* クレイモアートラップ */
        case SA_VOLCANO:
            return 0x9a;        /* ボルケーノ */
        case SA_DELUGE:
            return 0x9b;        /* デリュージ */
        case SA_VIOLENTGALE:
            return 0x9c;        /* バイオレントゲイル */
        case SA_LANDPROTECTOR:
            return 0x9d;        /* ランドプロテクター */
        case BD_LULLABY:
            return 0x9e;        /* 子守歌 */
        case BD_RICHMANKIM:
            return 0x9f;        /* ニヨルドの宴 */
        case BD_ETERNALCHAOS:
            return 0xa0;        /* 永遠の混沌 */
        case BD_DRUMBATTLEFIELD:
            return 0xa1;        /* 戦太鼓の響き */
        case BD_RINGNIBELUNGEN:
            return 0xa2;        /* ニーベルングの指輪 */
        case BD_ROKISWEIL:
            return 0xa3;        /* ロキの叫び */
        case BD_INTOABYSS:
            return 0xa4;        /* 深淵の中に */
        case BD_SIEGFRIED:
            return 0xa5;        /* 不死身のジークフリード */
        case BA_DISSONANCE:
            return 0xa6;        /* 不協和音 */
        case BA_WHISTLE:
            return 0xa7;        /* 口笛 */
        case BA_ASSASSINCROSS:
            return 0xa8;        /* 夕陽のアサシンクロス */
        case BA_POEMBRAGI:
            return 0xa9;        /* ブラギの詩 */
        case BA_APPLEIDUN:
            return 0xaa;        /* イドゥンの林檎 */
        case DC_UGLYDANCE:
            return 0xab;        /* 自分勝手なダンス */
        case DC_HUMMING:
            return 0xac;        /* ハミング */
        case DC_DONTFORGETME:
            return 0xad;        /* 私を忘れないで… */
        case DC_FORTUNEKISS:
            return 0xae;        /* 幸運のキス */
        case DC_SERVICEFORYOU:
            return 0xaf;        /* サービスフォーユー */
        case RG_GRAFFITI:
            return 0xb0;        /* グラフィティ */
        case AM_DEMONSTRATION:
            return 0xb1;        /* デモンストレーション */
        case WE_CALLPARTNER:
            return 0xb2;        /* あなたに逢いたい */
        case PA_GOSPEL:
            return 0xb3;        /* ゴスペル */
        case HP_BASILICA:
            return 0xb4;        /* バジリカ */
        case PF_FOGWALL:
            return 0xb6;        /* フォグウォール */
        case PF_SPIDERWEB:
            return 0xb7;        /* スパイダーウェッブ */
    }
    return 0;
    /*
     * 0x89,0x8a,0x8b 表示無し
     * 0x9a 炎属性の詠唱みたいなエフェクト
     * 0x9b 水属性の詠唱みたいなエフェクト
     * 0x9c 風属性の詠唱みたいなエフェクト
     * 0x9d 白い小さなエフェクト
     * 0xb1 Alchemist Demonstration
     * 0xb2 = Pink Warp Portal
     * 0xb3 = Gospel For Paladin
     * 0xb4 = Basilica
     * 0xb5 = Empty
     * 0xb6 = Fog Wall for Professor
     * 0xb7 = Spider Web for Professor
     * 0xb8 = Empty
     * 0xb9 =
     */
}

/*==========================================
 * スキル追加効果
 *------------------------------------------
 */
int skill_additional_effect(struct block_list *src, struct block_list *bl,
                             SkillID skillid, int skilllv, BF attack_type,
                             unsigned int tick)
{
    struct map_session_data *sd = NULL;
    struct map_session_data *dstsd = NULL;
    struct mob_data *md = NULL;

    int skill, skill2;
    int rate, luk;

    int sc_def_mdef, sc_def_vit, sc_def_int, sc_def_luk;
    int sc_def_mdef2, sc_def_vit2, sc_def_int2, sc_def_luk2;
    int sc_def_phys_shield_spell;

    nullpo_ret(src);
    nullpo_ret(bl);

    if (skilllv < 0)
        return 0;

    if (src->type == BL_PC)
    {
        nullpo_ret(sd = (struct map_session_data *) src);
    }
    else if (src->type == BL_MOB)
    {
        nullpo_ret(md = (struct mob_data *) src);  //未使用?
    }

    sc_def_phys_shield_spell = 0;
    if (battle_get_sc_data(bl)[SC_PHYS_SHIELD].timer != -1)
        sc_def_phys_shield_spell =
            battle_get_sc_data(bl)[SC_PHYS_SHIELD].val1;

    //対象の耐性
    luk = battle_get_luk(bl);
    sc_def_mdef = 100 - (3 + battle_get_mdef(bl) + luk / 3);
    sc_def_vit = 100 - (3 + battle_get_vit(bl) + luk / 3);
    sc_def_int = 100 - (3 + battle_get_int(bl) + luk / 3);
    sc_def_luk = 100 - (3 + luk);
    //自分の耐性
    luk = battle_get_luk(src);
    sc_def_mdef2 = 100 - (3 + battle_get_mdef(src) + luk / 3);
    sc_def_vit2 = 100 - (3 + battle_get_vit(src) + luk / 3);
    sc_def_int2 = 100 - (3 + battle_get_int(src) + luk / 3);
    sc_def_luk2 = 100 - (3 + luk);
    if (bl->type == BL_PC)
        dstsd = (struct map_session_data *) bl;
    else if (bl->type == BL_MOB)
    {
        if (sc_def_mdef > 50)
            sc_def_mdef = 50;
        if (sc_def_vit > 50)
            sc_def_vit = 50;
        if (sc_def_int > 50)
            sc_def_int = 50;
        if (sc_def_luk > 50)
            sc_def_luk = 50;
    }
    if (sc_def_mdef < 0)
        sc_def_mdef = 0;
    if (sc_def_vit < 0)
        sc_def_vit = 0;
    if (sc_def_int < 0)
        sc_def_int = 0;

    switch (skillid)
    {
        case SkillID::ZERO:                /* 通常攻撃 */
            /* 自動鷹 */
            if (sd && pc_isfalcon(sd) && sd->status.weapon == 11
                && (skill = pc_checkskill(sd, HT_BLITZBEAT)) > 0
                && MRAND(1000) <= sd->paramc[ATTR::LUK] * 10 / 3 + 1)
            {
                int lv = (sd->status.job_level + 9) / 10;
                skill_castend_damage_id(src, bl, HT_BLITZBEAT,
                                         (skill < lv) ? skill : lv, tick,
                                         BCT_highnib);
            }
            // スナッチャー
            if (sd && sd->status.weapon != 11
                && (skill = pc_checkskill(sd, RG_SNATCHER)) > 0)
                if ((skill * 15 + 55) +
                    (skill2 =
                     pc_checkskill(sd, TF_STEAL)) * 10 > MRAND(1000))
                {
                    if (pc_steal_item(sd, bl))
                    {}
                    else
                        clif_skill_fail(sd, skillid, 0, 0);
                }
            break;

        case SM_BASH:          /* バッシュ(急所攻撃) */
            if (sd && (skill = pc_checkskill(sd, SM_FATALBLOW)) > 0)
            {
                if (MRAND(100) < 6 * (skilllv - 5) * sc_def_vit / 100)
                    skill_status_change_start(bl, SC_STAN, skilllv, 0, 0, 0,
                                               skill_get_time2(SM_FATALBLOW,
                                                                skilllv), 0);
            }
            break;

        case TF_POISON:        /* インベナム */
        case AS_SPLASHER:      /* ベナムスプラッシャー */
            if (MRAND(100) < (2 * skilllv + 10) * sc_def_vit / 100)
                skill_status_change_start(bl, SC_POISON, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            else
            {
                if (sd && skillid == TF_POISON)
                    clif_skill_fail(sd, skillid, 0, 0);
            }
            break;

        case AS_SONICBLOW:     /* ソニックブロー */
            if (MRAND(100) < (2 * skilllv + 10) * sc_def_vit / 100)
                skill_status_change_start(bl, SC_STAN, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            break;

        case HT_FREEZINGTRAP:  /* フリージングトラップ */
            rate = skilllv * 3 + 35;
            if (MRAND(100) < rate * sc_def_mdef / 100)
                skill_status_change_start(bl, SC_FREEZE, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            break;

        case MG_FROSTDIVER:    /* フロストダイバー */
        case WZ_FROSTNOVA:     /* フロストノヴァ */
            rate =
                (skilllv * 3 + 35) * sc_def_mdef / 100 -
                (battle_get_int(bl) + battle_get_luk(bl)) / 15;
            rate = rate <= 5 ? 5 : rate;
            if (MRAND(100) < rate)
                skill_status_change_start(bl, SC_FREEZE, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            else if (sd)
                clif_skill_fail(sd, skillid, 0, 0);
            break;

        case WZ_STORMGUST:     /* ストームガスト */
        {
            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);
            if (sc_data)
            {
                sc_data[SC_FREEZE].val3++;
                if (sc_data[SC_FREEZE].val3 >= 3)
                    skill_status_change_start(bl, SC_FREEZE, skilllv, 0, 0,
                                               0, skill_get_time2(skillid,
                                                                   skilllv),
                                               0);
            }
        }
            break;

        case HT_LANDMINE:      /* ランドマイン */
            if (MRAND(100) < (5 * skilllv + 30) * sc_def_vit / 100)
                skill_status_change_start(bl, SC_STAN, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            break;

        case HT_SHOCKWAVE:     /* ショックウェーブトラップ */
            if (map[bl->m].flag.pvp && dstsd)
            {
                dstsd->status.sp -=
                    dstsd->status.sp * (5 + 15 * skilllv) / 100;
                pc_calcstatus(dstsd, 0);
            }
            break;
        case HT_SANDMAN:       /* サンドマン */
            if (MRAND(100) < (5 * skilllv + 30) * sc_def_int / 100)
                skill_status_change_start(bl, SC_SLEEP, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            break;
        case TF_SPRINKLESAND:  /* 砂まき */
            if (MRAND(100) < 15 * sc_def_int / 100)
                skill_status_change_start(bl, SC_BLIND, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            break;

        case TF_THROWSTONE:    /* 石投げ */
            if (MRAND(100) < 5 * sc_def_vit / 100)
                skill_status_change_start(bl, SC_STAN, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            break;

        case CR_HOLYCROSS:     /* ホーリークロス */
            if (MRAND(100) < 3 * skilllv * sc_def_int / 100)
                skill_status_change_start(bl, SC_BLIND, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            break;

        case CR_GRANDCROSS:    /* グランドクロス */
        {
            int race = battle_get_race(bl);
            if ((battle_check_undead(race, battle_get_elem_type(bl)) || race == 6) && MRAND(100) < 100000 * sc_def_int / 100)    //強制付与だが完全耐性には無効
                skill_status_change_start(bl, SC_BLIND, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
        }
            break;

        case CR_SHIELDCHARGE:  /* シールドチャージ */
            if (MRAND(100) < (15 + skilllv * 5) * sc_def_vit / 100)
                skill_status_change_start(bl, SC_STAN, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            break;

        case RG_RAID:          /* サプライズアタック */
            if (MRAND(100) < (10 + 3 * skilllv) * sc_def_vit / 100)
                skill_status_change_start(bl, SC_STAN, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            if (MRAND(100) < (10 + 3 * skilllv) * sc_def_int / 100)
                skill_status_change_start(bl, SC_BLIND, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            break;
        case BA_FROSTJOKE:
            if (MRAND(100) < (15 + 5 * skilllv) * sc_def_mdef / 100)
                skill_status_change_start(bl, SC_FREEZE, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            break;

        case DC_SCREAM:
            if (MRAND(100) < (25 + 5 * skilllv) * sc_def_vit / 100)
                skill_status_change_start(bl, SC_STAN, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            break;

        case BD_LULLABY:       /* 子守唄 */
            if (MRAND(100) < 15 * sc_def_int / 100)
                skill_status_change_start(bl, SC_SLEEP, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            break;

            /* MOBの追加効果付きスキル */

        case NPC_PETRIFYATTACK:
            if (MRAND(100) < sc_def_mdef)
                skill_status_change_start(bl, SC_STONE,
                                           skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            break;
        case NPC_POISON:
            if (MRAND(100) <
                50 - (sc_def_vit >> 2) - (sc_def_phys_shield_spell) +
                (skilllv >> 2))
                skill_status_change_start(bl, SC_POISON,
                                           skilllv, 0, 0, 0, skilllv, 0);
            break;
        case NPC_SILENCEATTACK:
            if (MRAND(100) <
                50 - (sc_def_vit >> 2) - (sc_def_phys_shield_spell) +
                (skilllv >> 2))
                skill_status_change_start(bl, SC_SILENCE,
                                           skilllv, 0, 0, 0, skilllv, 0);
            break;
        case NPC_STUNATTACK:
            if (MRAND(100) <
                50 - (sc_def_vit >> 2) - (sc_def_phys_shield_spell) +
                (skilllv >> 2))
                skill_status_change_start(bl, SC_STAN,
                                           skilllv, 0, 0, 0, skilllv, 0);
            break;
        case NPC_CURSEATTACK:
            if (MRAND(100) < sc_def_luk)
                skill_status_change_start(bl, SC_CURSE,
                                           skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            break;
        case NPC_SLEEPATTACK:
            if (MRAND(100) < sc_def_int)
                skill_status_change_start(bl, SC_SLEEP,
                                           skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            break;
        case NPC_BLINDATTACK:
            if (MRAND(100) < sc_def_int)
                skill_status_change_start(bl, SC_BLIND,
                                           skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            break;
        case NPC_MENTALBREAKER:
            if (dstsd)
            {
                int sp = dstsd->status.max_sp * (10 + skilllv) / 100;
                if (sp < 1)
                    sp = 1;
                pc_heal(dstsd, 0, -sp);
            }
            break;

// -- moonsoul (adding status effect chance given to wizard aoe skills meteor and vermillion)
//
        case WZ_METEOR:
            if (MRAND(100) < sc_def_vit)
                skill_status_change_start(bl, SC_STAN, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            break;
        case WZ_VERMILION:
            if (MRAND(100) < sc_def_int)
                skill_status_change_start(bl, SC_BLIND, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            break;

// -- moonsoul (stun ability of new champion skill tigerfist)
//
        case CH_TIGERFIST:
            if (MRAND(100) < (5 + skilllv * 5) * sc_def_vit / 100)
                skill_status_change_start(bl, SC_STAN, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            break;

        case LK_SPIRALPIERCE:
            if (MRAND(100) < (15 + skilllv * 5) * sc_def_vit / 100)
                skill_status_change_start(bl, SC_STAN, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            break;
        case ST_REJECTSWORD:   /* フリージングトラップ */
            if (MRAND(100) < (10 + skilllv * 5))
                skill_status_change_start(bl, SC_AUTOCOUNTER, skilllv, 0, 0,
                                           0, skill_get_time2(skillid,
                                                               skilllv), 0);
            break;
        case PF_FOGWALL:       /* ホーリークロス */
            if (MRAND(100) < 3 * skilllv * sc_def_int / 100)
                skill_status_change_start(bl, SC_BLIND, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            break;
        case LK_HEADCRUSH:     /* ヘッドクラッシュ */
        {                       //条件が良く分からないので適当に
            int race = battle_get_race(bl);
            if (!
                (battle_check_undead(race, battle_get_elem_type(bl))
                 || race == 6)
                && MRAND(100) < (2 * skilllv + 10) * sc_def_vit / 100)
                skill_status_change_start(bl, SC_HEADCRUSH, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
        }
            break;
        case LK_JOINTBEAT:     /* ジョイントビート */
            //条件が良く分からないので適当に
            if (MRAND(100) < (2 * skilllv + 10) * sc_def_vit / 100)
                skill_status_change_start(bl, SC_JOINTBEAT, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            break;
        case PF_SPIDERWEB:     /* スパイダーウェッブ */
        {
            int sec = skill_get_time2(skillid, skilllv);
            if (map[src->m].flag.pvp)   //PvPでは拘束時間半減?
                sec = sec / 2;
            battle_stopwalking(bl, 1);
            skill_status_change_start(bl, SC_SPIDERWEB, skilllv, 0, 0, 0,
                                       sec, 0);
        }
            break;
        case ASC_METEORASSAULT:    /* メテオアサルト */
            if (MRAND(100) < (15 + skilllv * 5) * sc_def_vit / 100)    //状態異常は詳細が分からないので適当に
                skill_status_change_start(bl, SC_STAN, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            if (MRAND(100) < (10 + 3 * skilllv) * sc_def_int / 100)
                skill_status_change_start(bl, SC_BLIND, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            break;
        case MO_EXTREMITYFIST: /* 阿修羅覇凰拳 */
            //阿修羅を使うと5分間自然回復しないようになる
            skill_status_change_start(src, SkillStatusChangeTable[skillid],
                                       skilllv, 0, 0, 0,
                                       skill_get_time2(skillid, skilllv), 0);
            break;
    }

    if (not (sd
            && skillid != MC_CARTREVOLUTION
            && bool(attack_type & BF_WEAPON)))
        return 0;
    earray<int, BadSC, BadSC::COUNT> arr_sc_def_card1 =
    {
        sc_def_mdef,    // stone
        sc_def_mdef,    // freeze
        sc_def_vit,     // stan
        sc_def_int,     // sleep
        sc_def_vit,     // poison
        sc_def_luk,     // curse
        sc_def_vit,     // silence
        sc_def_int,     // confusion
        sc_def_int,     // blind
    }, arr_sc_def_card2 =
    {
        sc_def_mdef2,   // stone
        sc_def_mdef2,   // freeze
        sc_def_vit2,    // stan
        sc_def_int2,    // sleep
        sc_def_vit2,    // poison
        sc_def_luk2,    // curse
        sc_def_vit2,    // silence
        sc_def_int2,    // confusion
        sc_def_int2,    // blind
    };

    earray<SkillID, BadSC, BadSC::COUNT> sc2 =
    {
        MG_STONECURSE,      // stone
        MG_FROSTDIVER,      // freeze
        NPC_STUNATTACK,     // stan
        NPC_SLEEPATTACK,    // sleep
        TF_POISON,          // poison
        NPC_CURSEATTACK,    // curse
        NPC_SILENCEATTACK,  // silence
        SkillID::ZERO,      // confusion
        NPC_BLINDATTACK,    // blind
    };

    for (BadSC bi : erange(BadSC(), BadSC::COUNT))
    {
        StatusChange si = BadSC_to_SC(bi);
        int sc_def_card1 = arr_sc_def_card1[bi];
        int eff1 = sd->addeff[bi];
        if (sd->state.arrow_atk)
            eff1 += sd->arrow_addeff[bi];
        if (MRAND(10000) < eff1 * sc_def_card1 / 100)
        {
            if (battle_config.battle_log)
                printf("PC %d skill_addeff: cardによる異常発動 %d %d\n",
                     sd->bl.id, uint16_t(si), eff1);

            skill_status_change_start(bl, si, 7, 0, 0, 0,
                                    (bi == BadSC::CONFUSION)
                                    ? 10000 + 7000
                                    : skill_get_time2(sc2[bi], 7),
                                    0);
        }

        int sc_def_card2 = arr_sc_def_card2[bi];
        int eff2 = sd->addeff2[bi];

        if (MRAND(10000) < eff2 * sc_def_card2 / 100)
        {
            if (battle_config.battle_log)
                printf("PC %d skill_addeff: cardによる異常発動 %d %d\n",
                     src->id, uint16_t(si), eff2);
            skill_status_change_start(src, si, 7, 0, 0, 0,
                                   (bi == BadSC::CONFUSION)
                                   ? 10000 + 7000
                                   : skill_get_time2(sc2[bi], 7),
                                   0);
        }
    }
    return 0;
}

/*=========================================================================
 スキル攻撃吹き飛ばし処理
-------------------------------------------------------------------------*/
static
int skill_blown(struct block_list *src, struct block_list *target, int count)
{
    int dx = 0, dy = 0, nx, ny;
    int x = target->x, y = target->y;
    int ret;
    MS prev_state = MS_IDLE;
    int moveblock;
    struct map_session_data *sd = NULL;
    struct mob_data *md = NULL;
    struct skill_unit *su = NULL;

    nullpo_ret(src);
    nullpo_ret(target);

    if (target->type == BL_PC)
    {
        nullpo_ret(sd = (struct map_session_data *) target);
    }
    else if (target->type == BL_MOB)
    {
        nullpo_ret(md = (struct mob_data *) target);
    }
    else if (target->type == BL_SKILL)
    {
        nullpo_ret(su = (struct skill_unit *) target);
    }
    else
        return 0;

    if (!(count & 0x10000 && (sd || md || su)))
    {                           /* 指定なしなら位置関係から方向を求める */
        dx = target->x - src->x;
        dx = (dx > 0) ? 1 : ((dx < 0) ? -1 : 0);
        dy = target->y - src->y;
        dy = (dy > 0) ? 1 : ((dy < 0) ? -1 : 0);
    }
    if (dx == 0 && dy == 0)
    {
        int dir = battle_get_dir(target);
        if (dir >= 0 && dir < 8)
        {
            dx = -dirx[dir];
            dy = -diry[dir];
        }
    }

    ret = path_blownpos(target->m, x, y, dx, dy, count & 0xffff);
    nx = ret >> 16;
    ny = ret & 0xffff;
    moveblock = (x / BLOCK_SIZE != nx / BLOCK_SIZE
                 || y / BLOCK_SIZE != ny / BLOCK_SIZE);

    if (count & 0x20000)
    {
        battle_stopwalking(target, 1);
        if (sd)
        {
            sd->to_x = nx;
            sd->to_y = ny;
            sd->walktimer = 1;
            clif_walkok(sd);
            clif_movechar(sd);
        }
        else if (md)
        {
            md->to_x = nx;
            md->to_y = ny;
            prev_state = md->state.state;
            md->state.state = MS_WALK;
            clif_fixmobpos(md);
        }
    }
    else
        battle_stopwalking(target, 2);

    dx = nx - x;
    dy = ny - y;

    if (sd)                     /* 画面外に出たので消去 */
        map_foreachinmovearea(std::bind(clif_pcoutsight, ph::_1, sd),
                target->m, x - AREA_SIZE, y - AREA_SIZE,
                x + AREA_SIZE, y + AREA_SIZE,
                dx, dy, BL_NUL);
    else if (md)
        map_foreachinmovearea(std::bind(clif_moboutsight, ph::_1, md),
                target->m, x - AREA_SIZE, y - AREA_SIZE,
                x + AREA_SIZE, y + AREA_SIZE,
                dx, dy, BL_PC);

    if (su)
    {
        skill_unit_move_unit_group(su->group, target->m, dx, dy);
    }
    else
    {
//      eptr<struct status_change, StatusChange> sc_data=battle_get_sc_data(target);
        if (moveblock)
            map_delblock(target);
        target->x = nx;
        target->y = ny;
        if (moveblock)
            map_addblock(target);
/*ダンス中にエフェクトは移動しないらしい
                if (sc_data && sc_data[SC_DANCING].timer!=-1){ //対象がダンス中なのでエフェクトも移動
                        struct skill_unit_group *sg= (struct skill_unit_group *)sc_data[SC_DANCING].val2;
                        if (sg)
                                skill_unit_move_unit_group(sg,target->m,dx,dy);
                }
*/
    }

    if (sd)
    {                           /* 画面内に入ってきたので表示 */
        map_foreachinmovearea(std::bind(clif_pcinsight, ph::_1, sd),
                target->m, nx - AREA_SIZE, ny - AREA_SIZE,
                nx + AREA_SIZE, ny + AREA_SIZE,
                -dx, -dy, BL_NUL);
        if (count & 0x20000)
            sd->walktimer = -1;
    }
    else if (md)
    {
        map_foreachinmovearea(std::bind(clif_mobinsight, ph::_1, md),
                target->m, nx - AREA_SIZE, ny - AREA_SIZE,
                nx + AREA_SIZE, ny + AREA_SIZE,
                -dx, -dy, BL_PC);
        if (count & 0x20000)
            md->state.state = prev_state;
    }

    skill_unit_move(target, gettick(), (count & 0xffff) + 7); /* スキルユニットの判定 */

    return 0;
}

/*
 * =========================================================================
 * スキル攻撃効果処理まとめ
 * flagの説明。16進図
 *      00XRTTff
 *  ff  = magicで計算に渡される)
 *      TT      = パケットのtype部分(0でデフォルト)
 *  X   = パケットのスキルLv
 *  R   = 予約(skill_area_subで使用する)
 *-------------------------------------------------------------------------
 */

int skill_attack(BF attack_type, struct block_list *src,
        struct block_list *dsrc, struct block_list *bl,
        SkillID skillid, int skilllv, unsigned int tick, BCT flag)
{
    struct Damage dmg;
    eptr<struct status_change, StatusChange> sc_data;
    int type, lv, damage;

    rdamage = 0;
    nullpo_ret(src);
    nullpo_ret(dsrc);
    nullpo_ret(bl);

    sc_data = battle_get_sc_data(bl);

//何もしない判定ここから
    if (dsrc->m != bl->m)       //対象が同じマップにいなければ何もしない
        return 0;
    if (src->prev == NULL || dsrc->prev == NULL || bl->prev == NULL)    //prevよくわからない※
        return 0;
    if (src->type == BL_PC && pc_isdead((struct map_session_data *) src))  //術者?がPCですでに死んでいたら何もしない
        return 0;
    if (dsrc->type == BL_PC && pc_isdead((struct map_session_data *) dsrc))    //術者?がPCですでに死んでいたら何もしない
        return 0;
    if (bl->type == BL_PC && pc_isdead((struct map_session_data *) bl))    //対象がPCですでに死んでいたら何もしない
        return 0;
    if (skillnotok(skillid, (struct map_session_data *) bl))
        return 0;               // [MouseJstr]
    if (sc_data && sc_data[SC_HIDING].timer != -1)
    {                           //ハイディング状態で
        if (skill_get_pl(skillid) != 2)    //スキルの属性が地属性でなければ何もしない
            return 0;
    }
    if (sc_data && sc_data[SC_TRICKDEAD].timer != -1)   //死んだふり中は何もしない
        return 0;
    if (skillid == WZ_STORMGUST)
    {                           //使用スキルがストームガストで
        if (sc_data && sc_data[SC_FREEZE].timer != -1)  //凍結状態なら何もしない
            return 0;
    }
    if (skillid == WZ_FROSTNOVA && dsrc->x == bl->x && dsrc->y == bl->y)    //使用スキルがフロストノヴァで、dsrcとblが同じ場所なら何もしない
        return 0;
    if (src->type == BL_PC && ((struct map_session_data *) src)->chatID)    //術者がPCでチャット中なら何もしない
        return 0;
    if (dsrc->type == BL_PC && ((struct map_session_data *) dsrc)->chatID)  //術者がPCでチャット中なら何もしない
        return 0;

//何もしない判定ここまで

    type = -1;
    lv = (flag >> 20) & 0xf;
    dmg = battle_calc_attack(attack_type, src, bl, skillid, skilllv, flag & 0xff); //ダメージ計算

//マジックロッド処理ここから
    if (bool(attack_type & BF_MAGIC)
        && sc_data
        && sc_data[SC_MAGICROD].timer != -1
        && src == dsrc)
    {                           //魔法攻撃でマジックロッド状態でsrc=dsrcなら
        dmg.damage = dmg.damage2 = 0;   //ダメージ0
        if (bl->type == BL_PC)
        {                       //対象がPCの場合
            int sp = skill_get_sp(skillid, skilllv);  //使用されたスキルのSPを吸収
            sp = sp * sc_data[SC_MAGICROD].val2 / 100;  //吸収率計算
            if (skillid == WZ_WATERBALL && skilllv > 1) //ウォーターボールLv1以上
                sp = sp / ((skilllv | 1) * (skilllv | 1));  //さらに計算?
            if (sp > 0x7fff)
                sp = 0x7fff;    //SP多すぎの場合は理論最大値
            else if (sp < 1)
                sp = 1;         //1以下の場合は1
            if (((struct map_session_data *) bl)->status.sp + sp >
                ((struct map_session_data *) bl)->status.max_sp)
            {                   //回復SP+現在のSPがMSPより大きい場合
                sp = ((struct map_session_data *) bl)->status.max_sp - ((struct map_session_data *) bl)->status.sp; //SPをMSP-現在SPにする
                ((struct map_session_data *) bl)->status.sp = ((struct map_session_data *) bl)->status.max_sp;  //現在のSPにMSPを代入
            }
            else                //回復SP+現在のSPがMSPより小さい場合は回復SPを加算
                ((struct map_session_data *) bl)->status.sp += sp;
            ((struct map_session_data *) bl)->canact_tick = tick + skill_delayfix(bl, skill_get_delay(SA_MAGICROD, sc_data[SC_MAGICROD].val1));   //
        }
    }
//マジックロッド処理ここまで

    damage = dmg.damage + dmg.damage2;

    if (lv == 15)
        lv = -1;

    if (flag & 0xff00)
        type = (flag & 0xff00) >> 8;

    if (damage <= 0 || damage < dmg.div_)   //吹き飛ばし判定?※
        dmg.blewcount = 0;

    if (skillid == CR_GRANDCROSS)
    {                           //グランドクロス
        if (battle_config.gx_disptype)
            dsrc = src;         // 敵ダメージ白文字表示
        if (src == bl)
            type = 4;           // 反動はダメージモーションなし
    }

//使用者がPCの場合の処理ここから
    if (src->type == BL_PC)
    {
        struct map_session_data *sd = (struct map_session_data *) src;
        nullpo_ret(sd);
//連打掌(MO_CHAINCOMBO)ここから
        if (skillid == MO_CHAINCOMBO)
        {
            int delay = 1000 - 4 * battle_get_agi(src) - 2 * battle_get_dex(src);    //基本ディレイの計算
            if (damage < battle_get_hp(bl))
            {                   //ダメージが対象のHPより小さい場合
                if (pc_checkskill(sd, MO_COMBOFINISH) > 0 && sd->spiritball > 0)   //猛龍拳(MO_COMBOFINISH)取得&気球保持時は+300ms
                    delay += 300 * battle_config.combo_delay_rate / 100;    //追加ディレイをconfにより調整

                skill_status_change_start(src, SC_COMBO,
                        uint16_t(MO_CHAINCOMBO), skilllv,
                        0, 0, delay, 0);  //コンボ状態に
            }
            sd->attackabletime = sd->canmove_tick = tick + delay;
        }
//連打掌(MO_CHAINCOMBO)ここまで
//猛龍拳(MO_COMBOFINISH)ここから
        else if (skillid == MO_COMBOFINISH)
        {
            int delay =
                700 - 4 * battle_get_agi(src) - 2 * battle_get_dex(src);
            if (damage < battle_get_hp(bl))
            {
                //阿修羅覇凰拳(MO_EXTREMITYFIST)取得&気球4個保持&爆裂波動(MO_EXPLOSIONSPIRITS)状態時は+300ms
                //伏虎拳(CH_TIGERFIST)取得時も+300ms
                if ((pc_checkskill(sd, MO_EXTREMITYFIST) > 0
                     && sd->spiritball >= 4
                     && sd->sc_data[SC_EXPLOSIONSPIRITS].timer != -1)
                    || (pc_checkskill(sd, CH_TIGERFIST) > 0
                        && sd->spiritball > 0)
                    || (pc_checkskill(sd, CH_CHAINCRUSH) > 0
                        && sd->spiritball > 1))
                    delay += 300 * battle_config.combo_delay_rate / 100;    //追加ディレイをconfにより調整

                skill_status_change_start(src, SC_COMBO,
                        uint16_t(MO_COMBOFINISH), skilllv,
                        0, 0, delay, 0); //コンボ状態に
            }
            sd->attackabletime = sd->canmove_tick = tick + delay;
        }
//猛龍拳(MO_COMBOFINISH)ここまで
//伏虎拳(CH_TIGERFIST)ここから
        else if (skillid == CH_TIGERFIST)
        {
            int delay =
                1000 - 4 * battle_get_agi(src) - 2 * battle_get_dex(src);
            if (damage < battle_get_hp(bl))
            {
                if (pc_checkskill(sd, CH_CHAINCRUSH) > 0)  //連柱崩撃(CH_CHAINCRUSH)取得時は+300ms
                    delay += 300 * battle_config.combo_delay_rate / 100;    //追加ディレイをconfにより調整

                skill_status_change_start(src, SC_COMBO,
                        uint16_t(CH_TIGERFIST), skilllv,
                        0, 0, delay, 0);   //コンボ状態に
            }
            sd->attackabletime = sd->canmove_tick = tick + delay;
        }
//伏虎拳(CH_TIGERFIST)ここまで
//連柱崩撃(CH_CHAINCRUSH)ここから
        else if (skillid == CH_CHAINCRUSH)
        {
            int delay =
                1000 - 4 * battle_get_agi(src) - 2 * battle_get_dex(src);
            if (damage < battle_get_hp(bl))
            {
                //阿修羅覇凰拳(MO_EXTREMITYFIST)取得&気球4個保持&爆裂波動(MO_EXPLOSIONSPIRITS)状態時は+300ms
                if (pc_checkskill(sd, MO_EXTREMITYFIST) > 0
                    && sd->spiritball >= 4
                    && sd->sc_data[SC_EXPLOSIONSPIRITS].timer != -1)
                    delay += 300 * battle_config.combo_delay_rate / 100;    //追加ディレイをconfにより調整

                skill_status_change_start(src,
                        SC_COMBO, uint16_t(CH_CHAINCRUSH), skilllv,
                        0, 0, delay, 0);  //コンボ状態に
            }
            sd->attackabletime = sd->canmove_tick = tick + delay;
        }
//連柱崩撃(CH_CHAINCRUSH)ここまで
    }
//使用者がPCの場合の処理ここまで
//武器スキル?ここから
    //AppleGirl Was Here
    if (bool(attack_type & BF_MAGIC)
        && damage > 0
        && src != bl
        && src == dsrc)
    {                           //Blah Blah
        if (bl->type == BL_PC)
        {                       //Blah Blah
            struct map_session_data *tsd = (struct map_session_data *) bl;
            if (tsd->magic_damage_return > 0)
            {                   //More Blah
                rdamage += damage * tsd->magic_damage_return / 100;
                if (rdamage < 1)
                    rdamage = 1;
            }
        }
    }
    //Stop Here
    if (bool(attack_type & BF_WEAPON)
        && damage > 0
        && src != bl
        && src == dsrc)
    {                           //武器スキル&ダメージあり&使用者と対象者が違う&src=dsrc
        if (bool(dmg.flag & BF_SHORT))
        {                       //近距離攻撃時?※
            if (bl->type == BL_PC)
            {                   //対象がPCの時
                struct map_session_data *tsd = (struct map_session_data *) bl;
                nullpo_ret(tsd);
                if (tsd->short_weapon_damage_return > 0)
                {               //近距離攻撃跳ね返し?※
                    rdamage += damage * tsd->short_weapon_damage_return / 100;
                    if (rdamage < 1)
                        rdamage = 1;
                }
            }
            if (sc_data && sc_data[SC_REFLECTSHIELD].timer != -1)
            {                   //リフレクトシールド時
                rdamage += damage * sc_data[SC_REFLECTSHIELD].val2 / 100;   //跳ね返し計算
                if (rdamage < 1)
                    rdamage = 1;
            }
        }
        else if (bool(dmg.flag & BF_LONG))
        {                       //遠距離攻撃時?※
            if (bl->type == BL_PC)
            {                   //対象がPCの時
                struct map_session_data *tsd = (struct map_session_data *) bl;
                nullpo_ret(tsd);
                if (tsd->long_weapon_damage_return > 0)
                {               //遠距離攻撃跳ね返し?※
                    rdamage += damage * tsd->long_weapon_damage_return / 100;
                    if (rdamage < 1)
                        rdamage = 1;
                }
            }
        }
        if (rdamage > 0)
            clif_damage(src, src, tick, dmg.amotion, 0, rdamage, 1, 4, 0);
    }
//武器スキル?ここまで

    switch (skillid)
    {
        case WZ_SIGHTRASHER:
            clif_skill_damage(src, bl, tick, dmg.amotion, dmg.dmotion,
                               damage, dmg.div_, skillid,
                               (lv != 0) ? lv : skilllv, 5);
            break;
        case AS_SPLASHER:
            clif_skill_damage(dsrc, bl, tick, dmg.amotion, dmg.dmotion,
                               damage, dmg.div_, skillid, -1, 5);
            break;
        case NPC_SELFDESTRUCTION:
        case NPC_SELFDESTRUCTION2:
            break;
        default:
            clif_skill_damage(dsrc, bl, tick, dmg.amotion, dmg.dmotion,
                               damage, dmg.div_, skillid,
                               (lv != 0) ? lv : skilllv,
                               (skillid == SkillID::ZERO) ? 5 : type);
    }
    if (dmg.blewcount > 0)
    {                           /* 吹き飛ばし処理とそのパケット */
        if (skillid == WZ_SIGHTRASHER)
            skill_blown(src, bl, dmg.blewcount);
        else
            skill_blown(dsrc, bl, dmg.blewcount);
        if (bl->type == BL_MOB)
            clif_fixmobpos((struct mob_data *) bl);
        else
            clif_fixpos(bl);
    }

    map_freeblock_lock();
    /* 実際にダメージ処理を行う */
    if (skillid != KN_BOWLINGBASH || flag)
        battle_damage(src, bl, damage, 0);
    if (skillid == RG_INTIMIDATE && damage > 0
        && !(battle_get_mode(bl) & 0x20))
    {
        int s_lv = battle_get_lv(src), t_lv = battle_get_lv(bl);
        int rate = 50 + skilllv * 5;
        rate = rate + (s_lv - t_lv);
        if (MRAND(100) < rate)
            skill_addtimerskill(src, tick + 800, bl->id, 0, 0, skillid,
                                 skilllv,
                                 skill_timerskill::sktst::from_n(0),
                                 flag);
    }
/*
        if (damage > 0 && dmg.flag&BF_SKILL && bl->type==BL_PC && pc_checkskill((struct map_session_data *)bl,RG_PLAGIARISM)){
                struct map_session_data *tsd = (struct map_session_data *)bl;
                nullpo_ret(tsd);
                if (!tsd->status.skill[skillid].id && !tsd->status.skill[skillid].id
                        && !(skillid > NPC_PIERCINGATT && skillid < NPC_SUMMONMONSTER) ){
                        //既に盗んでいるスキルがあれば該当スキルを消す
                        if (tsd->cloneskill_id && tsd->cloneskill_lv && tsd->status.skill[tsd->cloneskill_id].flag==13){
                                tsd->status.skill[tsd->cloneskill_id].id=0;
                                tsd->status.skill[tsd->cloneskill_id].lv=0;
                                tsd->status.skill[tsd->cloneskill_id].flag=0;
                        }
                        tsd->cloneskill_id=skillid;
                        tsd->cloneskill_lv=skilllv;
                        tsd->status.skill[skillid].id=skillid;
                        tsd->status.skill[skillid].lv= (pc_checkskill(tsd,RG_PLAGIARISM) > skill_get_max(skillid))?
                                                        skill_get_max(skillid):pc_checkskill(tsd,RG_PLAGIARISM);
                        tsd->status.skill[skillid].flag=13;//cloneskill flag
                        clif_skillinfoblock(tsd);
                }
        }
*/
    /* ダメージがあるなら追加効果判定 */
    if (bl->prev != NULL)
    {
        struct map_session_data *sd = (struct map_session_data *) bl;
        nullpo_ret(sd);
        if (bl->type != BL_PC || (sd && !pc_isdead(sd)))
        {
            if (damage > 0)
                skill_additional_effect(src, bl, skillid, skilllv,
                                         attack_type, tick);
            if (bl->type == BL_MOB && src != bl)    /* スキル使用条件のMOBスキル */
            {
                struct mob_data *md = (struct mob_data *) bl;
                nullpo_ret(md);
                if (battle_config.mob_changetarget_byskill == 1)
                {
                    int target;
                    target = md->target_id;
                    if (src->type == BL_PC)
                        md->target_id = src->id;
                    mobskill_use(md, tick, MSC_SKILLUSED, skillid);
                    md->target_id = target;
                }
                else
                    mobskill_use(md, tick, MSC_SKILLUSED, skillid);
            }
        }
    }

    if (src->type == BL_PC
        && bool(dmg.flag & BF_WEAPON)
        && src != bl
        && src == dsrc
        && damage > 0)
    {
        struct map_session_data *sd = (struct map_session_data *) src;
        int hp = 0, sp = 0;
        nullpo_ret(sd);
        if (sd->hp_drain_rate && dmg.damage > 0
            && MRAND(100) < sd->hp_drain_rate)
        {
            hp += (dmg.damage * sd->hp_drain_per) / 100;
        }
        if (sd->hp_drain_rate_ && dmg.damage2 > 0
            && MRAND(100) < sd->hp_drain_rate_)
        {
            hp += (dmg.damage2 * sd->hp_drain_per_) / 100;
        }
        if (sd->sp_drain_rate > 0 && dmg.damage > 0
            && MRAND(100) < sd->sp_drain_rate)
        {
            sp += (dmg.damage * sd->sp_drain_per) / 100;
        }
        if (sd->sp_drain_rate_ > 0 && dmg.damage2 > 0
            && MRAND(100) < sd->sp_drain_rate_)
        {
            sp += (dmg.damage2 * sd->sp_drain_per_) / 100;
        }
        if (hp || sp)
            pc_heal(sd, hp, sp);
    }

    if ((skillid != KN_BOWLINGBASH || flag) && rdamage > 0)
        battle_damage(bl, src, rdamage, 0);

    if (bool(attack_type & BF_WEAPON)
        && sc_data
        && sc_data[SC_AUTOCOUNTER].timer != -1
        && sc_data[SC_AUTOCOUNTER].val4 > 0)
    {
        if (sc_data[SC_AUTOCOUNTER].val3 == dsrc->id)
            battle_weapon_attack(bl, dsrc, tick,
                    BCT_mid_x80 | sc_data[SC_AUTOCOUNTER].val1_bct());
        skill_status_change_end(bl, SC_AUTOCOUNTER, -1);
    }

    map_freeblock_unlock();

    return (dmg.damage + dmg.damage2);  /* 与ダメを返す */
}

typedef int(*SkillFunc)(struct block_list *, struct block_list *,
        SkillID, int,
        unsigned int, BCT);

static
void skill_area_sub(struct block_list *bl,
        struct block_list *src, SkillID skill_id, int skill_lv,
        unsigned int tick, BCT flag, SkillFunc func)
{
    nullpo_retv(bl);

    if (bl->type != BL_PC && bl->type != BL_MOB && bl->type != BL_SKILL)
        return;

    if (battle_check_target(src, bl, flag) > 0)
        func(src, bl, skill_id, skill_lv, tick, flag);
}

static
void skill_check_unit_range_sub(struct block_list *bl, int *c, int x, int y, int range, SkillID skillid)
{
    struct skill_unit *unit;
    int sx[4], sy[4];
    int t_range, tx[4], ty[4];
    int i, r_flag;

    nullpo_retv(bl);
    unit = (struct skill_unit *) bl;

    if (bl->prev == NULL || bl->type != BL_SKILL)
        return;

    if (!unit->alive)
        return;

    if (skillid == MG_SAFETYWALL || skillid == AL_PNEUMA)
    {
        if (unit->group->unit_id != 0x7e && unit->group->unit_id != 0x85)
            return;
    }
    else if (skillid == AL_WARP)
    {
        if ((unit->group->unit_id < 0x8f || unit->group->unit_id > 0x99)
            && unit->group->unit_id != 0x92)
            return;
    }
    else if ((skillid >= HT_SKIDTRAP && skillid <= HT_CLAYMORETRAP)
             || skillid == HT_TALKIEBOX)
    {
        if ((unit->group->unit_id < 0x8f || unit->group->unit_id > 0x99)
            && unit->group->unit_id != 0x92)
            return;
    }
    else if (skillid == WZ_FIREPILLAR)
    {
        if (unit->group->unit_id != 0x87)
            return;
    }
    else
        return;
    t_range = (unit->range != 0) ? unit->range : unit->group->range;
    tx[0] = tx[3] = unit->bl.x - t_range;
    tx[1] = tx[2] = unit->bl.x + t_range;
    ty[0] = ty[1] = unit->bl.y - t_range;
    ty[2] = ty[3] = unit->bl.y + t_range;
    sx[0] = sx[3] = x - range;
    sx[1] = sx[2] = x + range;
    sy[0] = sy[1] = y - range;
    sy[2] = sy[3] = y + range;
    for (i = r_flag = 0; i < 4; i++)
    {
        if (sx[i] >= tx[0] && sx[i] <= tx[1] && sy[i] >= ty[0]
            && sy[i] <= ty[2])
        {
            r_flag = 1;
            break;
        }
        if (tx[i] >= sx[0] && tx[i] <= sx[1] && ty[i] >= sy[0]
            && ty[i] <= sy[2])
        {
            r_flag = 1;
            break;
        }
    }
    if (r_flag)
        (*c)++;
}

int skill_check_unit_range(int m, int x, int y, int range, SkillID skillid)
{
    int c = 0;

    map_foreachinarea(std::bind(skill_check_unit_range_sub, ph::_1, &c, x, y, range, skillid),
            m, x - 10, y - 10,
            x + 10, y + 10, BL_SKILL);

    return c;
}

static
void skill_check_unit_range2_sub(struct block_list *bl, int *c)
{
    nullpo_retv(bl);
    nullpo_retv(c);

    if (bl->prev == NULL || (bl->type != BL_PC && bl->type != BL_MOB))
        return;

    if (bl->type == BL_PC && pc_isdead((struct map_session_data *) bl))
        return;

    (*c)++;
}

int skill_check_unit_range2(int m, int x, int y, int range)
{
    int c = 0;

    map_foreachinarea(std::bind(skill_check_unit_range2_sub, ph::_1, &c),
            m, x - range, y - range,
            x + range, y + range, BL_NUL);

    return c;
}

/*=========================================================================
 * 範囲スキル使用処理小分けここから
 */
static
BCT skill_area_temp_counter;
static
int skill_area_sub_count(struct block_list *, struct block_list *,
        SkillID, int, unsigned int, BCT)
{
    if (skill_area_temp_counter.lo == 0xff
        && skill_area_temp_counter.mid == 0xff)
        return 0;
    if (!++skill_area_temp_counter.lo)
        ++skill_area_temp_counter.mid;
    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
static
void skill_timer(timer_id, tick_t tick, custom_id_t id, custom_data_t data)
{
    struct map_session_data *sd = NULL;
    struct mob_data *md = NULL;
    struct block_list *src = map_id2bl(id), *target;
    struct skill_timerskill *skl = NULL;
    int range;

    nullpo_retv(src);

    if (src->prev == NULL)
        return;

    if (src->type == BL_PC)
    {
        nullpo_retv(sd = (struct map_session_data *) src);
        skl = &sd->skilltimerskill[data];
    }
    else if (src->type == BL_MOB)
    {
        nullpo_retv(md = (struct mob_data *) src);
        skl = &md->skilltimerskill[data];
    }

    else
        return;

    nullpo_retv(skl);

    skl->timer = -1;
    if (skl->target_id)
    {
        struct block_list tbl;
        target = map_id2bl(skl->target_id);
        if (skl->skill_id == RG_INTIMIDATE)
        {
            if (target == NULL)
            {
                target = &tbl;  //初期化してないのにアドレス突っ込んでいいのかな?
                target->type = BL_NUL;
                target->m = src->m;
                target->prev = target->next = NULL;
            }
        }
        if (target == NULL)
            return;
        if (target->prev == NULL && skl->skill_id != RG_INTIMIDATE)
            return;
        if (src->m != target->m)
            return;
        if (sd && pc_isdead(sd))
            return;
        if (target->type == BL_PC
            && pc_isdead((struct map_session_data *) target)
            && skl->skill_id != RG_INTIMIDATE)
            return;

        switch (skl->skill_id)
        {
            case TF_BACKSLIDING:
                break;
            case RG_INTIMIDATE:
                if (sd && !map[src->m].flag.noteleport)
                {
                    int x, y, i, j, c;
                    pc_randomwarp(sd, 3);
                    for (i = 0; i < 16; i++)
                    {
                        j = MRAND(8);
                        x = sd->bl.x + dirx[j];
                        y = sd->bl.y + diry[j];
                        if ((c = map_getcell(sd->bl.m, x, y)) != 1 && c != 5)
                            break;
                    }
                    if (i >= 16)
                    {
                        x = sd->bl.x;
                        y = sd->bl.y;
                    }
                    if (target->prev != NULL)
                    {
                        if (target->type == BL_PC
                            && !pc_isdead((struct map_session_data *)
                                           target))
                            pc_setpos((struct map_session_data *) target,
                                       map[sd->bl.m].name, x, y, 3);
                        else if (target->type == BL_MOB)
                            mob_warp((struct mob_data *) target, -1, x, y,
                                      3);
                    }
                }
                else if (md && !map[src->m].flag.monster_noteleport)
                {
                    int x, y, i, j, c;
                    mob_warp(md, -1, -1, -1, 3);
                    for (i = 0; i < 16; i++)
                    {
                        j = MRAND(8);
                        x = md->bl.x + dirx[j];
                        y = md->bl.y + diry[j];
                        if ((c = map_getcell(md->bl.m, x, y)) != 1 && c != 5)
                            break;
                    }
                    if (i >= 16)
                    {
                        x = md->bl.x;
                        y = md->bl.y;
                    }
                    if (target->prev != NULL)
                    {
                        if (target->type == BL_PC
                            && !pc_isdead((struct map_session_data *)
                                           target))
                            pc_setpos((struct map_session_data *) target,
                                       map[md->bl.m].name, x, y, 3);
                        else if (target->type == BL_MOB)
                            mob_warp((struct mob_data *) target, -1, x, y,
                                      3);
                    }
                }
                break;

            case BA_FROSTJOKE: /* 寒いジョーク */
            case DC_SCREAM:    /* スクリーム */
                range = 15;     //視界全体
                map_foreachinarea(std::bind(skill_frostjoke_scream, ph::_1, src, skl->skill_id, skl->skill_lv, tick),
                        src->m, src->x - range, src->y - range,
                        src->x + range, src->y + range,
                        BL_NUL);
                break;

            default:
                skill_attack(skl->type.bf, src, src, target, skl->skill_id,
                              skl->skill_lv, tick, skl->flag);
                break;
        }
    }
    else
    {
        if (src->m != skl->map)
            return;
        switch (skl->skill_id)
        {
            case WZ_METEOR:
                if (skl->type.n >= 0)
                {
                    skill_unitsetting(src, skl->skill_id, skl->skill_lv,
                                       skl->type.xy.x, skl->type.xy.y,
                                       0);
                }
                else
                    skill_unitsetting(src, skl->skill_id, skl->skill_lv,
                                       skl->x, skl->y, 0);
                break;
        }
    }
}

/*==========================================
 *
 *------------------------------------------
 */
int skill_addtimerskill(struct block_list *src, unsigned int tick,
                         int target, int x, int y,
                         SkillID skill_id, int skill_lv,
                         skill_timerskill::sktst type, BCT flag)
{
    int i;

    nullpo_retr(1, src);

    if (src->type == BL_PC)
    {
        struct map_session_data *sd = (struct map_session_data *) src;
        nullpo_retr(1, sd);
        for (i = 0; i < MAX_SKILLTIMERSKILL; i++)
        {
            if (sd->skilltimerskill[i].timer == -1)
            {
                sd->skilltimerskill[i].timer =
                    add_timer(tick, skill_timer, src->id, i);
                sd->skilltimerskill[i].src_id = src->id;
                sd->skilltimerskill[i].target_id = target;
                sd->skilltimerskill[i].skill_id = skill_id;
                sd->skilltimerskill[i].skill_lv = skill_lv;
                sd->skilltimerskill[i].map = src->m;
                sd->skilltimerskill[i].x = x;
                sd->skilltimerskill[i].y = y;
                sd->skilltimerskill[i].type = type;
                sd->skilltimerskill[i].flag = flag;

                return 0;
            }
        }
        return 1;
    }
    else if (src->type == BL_MOB)
    {
        struct mob_data *md = (struct mob_data *) src;
        nullpo_retr(1, md);
        for (i = 0; i < MAX_MOBSKILLTIMERSKILL; i++)
        {
            if (md->skilltimerskill[i].timer == -1)
            {
                md->skilltimerskill[i].timer =
                    add_timer(tick, skill_timer, src->id, i);
                md->skilltimerskill[i].src_id = src->id;
                md->skilltimerskill[i].target_id = target;
                md->skilltimerskill[i].skill_id = skill_id;
                md->skilltimerskill[i].skill_lv = skill_lv;
                md->skilltimerskill[i].map = src->m;
                md->skilltimerskill[i].x = x;
                md->skilltimerskill[i].y = y;
                md->skilltimerskill[i].type = type;
                md->skilltimerskill[i].flag = flag;

                return 0;
            }
        }
        return 1;
    }

    return 1;
}

/*==========================================
 *
 *------------------------------------------
 */
int skill_cleartimerskill(struct block_list *src)
{
    int i;

    nullpo_ret(src);

    if (src->type == BL_PC)
    {
        struct map_session_data *sd = (struct map_session_data *) src;
        nullpo_ret(sd);
        for (i = 0; i < MAX_SKILLTIMERSKILL; i++)
        {
            if (sd->skilltimerskill[i].timer != -1)
            {
                delete_timer(sd->skilltimerskill[i].timer, skill_timer);
                sd->skilltimerskill[i].timer = -1;
            }
        }
    }
    else if (src->type == BL_MOB)
    {
        struct mob_data *md = (struct mob_data *) src;
        nullpo_ret(md);
        for (i = 0; i < MAX_MOBSKILLTIMERSKILL; i++)
        {
            if (md->skilltimerskill[i].timer != -1)
            {
                delete_timer(md->skilltimerskill[i].timer, skill_timer);
                md->skilltimerskill[i].timer = -1;
            }
        }
    }

    return 0;
}

/* 範囲スキル使用処理小分けここまで
 * -------------------------------------------------------------------------
 */

// these variables are set in the 'else' branches,
// and used in the (recursive) 'if' branch
static int skill_area_temp_id, skill_area_temp_x, skill_area_temp_y, skill_area_temp_hp;


/*==========================================
 * スキル使用(詠唱完了、ID指定攻撃系)
 * (スパゲッティに向けて1歩前進!(ダメポ))
 *------------------------------------------
 */
int skill_castend_damage_id(struct block_list *src, struct block_list *bl,
        SkillID skillid, int skilllv,
        unsigned int tick, BCT flag)
{
    struct map_session_data *sd = NULL;

    nullpo_retr(1, src);
    nullpo_retr(1, bl);

    if (src->type == BL_PC)
        sd = (struct map_session_data *) src;
    if (sd && pc_isdead(sd))
        return 1;

    if ((skillid == WZ_SIGHTRASHER || skillid == CR_GRANDCROSS) && src != bl)
        bl = src;
    if (bl->prev == NULL)
        return 1;
    if (bl->type == BL_PC && pc_isdead((struct map_session_data *) bl))
        return 1;
    map_freeblock_lock();
    switch (skillid)
    {
            /* 武器攻撃系スキル */
        case SM_BASH:          /* バッシュ */
        case MC_MAMMONITE:     /* メマーナイト */
        case AC_DOUBLE:        /* ダブルストレイフィング */
        case AS_SONICBLOW:     /* ソニックブロー */
        case KN_PIERCE:        /* ピアース */
        case KN_SPEARBOOMERANG:    /* スピアブーメラン */
        case TF_POISON:        /* インベナム */
        case TF_SPRINKLESAND:  /* 砂まき */
        case AC_CHARGEARROW:   /* チャージアロー */
        case KN_SPEARSTAB:     /* スピアスタブ */
        case RG_RAID:          /* サプライズアタック */
        case RG_INTIMIDATE:    /* インティミデイト */
        case BA_MUSICALSTRIKE: /* ミュージカルストライク */
        case DC_THROWARROW:    /* 矢撃ち */
        case BA_DISSONANCE:    /* 不協和音 */
        case CR_HOLYCROSS:     /* ホーリークロス */
        case CR_SHIELDCHARGE:
        case CR_SHIELDBOOMERANG:

            /* 以下MOB専用 */
            /* 単体攻撃、SP減少攻撃、遠距離攻撃、防御無視攻撃、多段攻撃 */
        case NPC_PIERCINGATT:
        case NPC_MENTALBREAKER:
        case NPC_RANGEATTACK:
        case NPC_CRITICALSLASH:
        case NPC_COMBOATTACK:
            /* 必中攻撃、毒攻撃、暗黒攻撃、沈黙攻撃、スタン攻撃 */
        case NPC_GUIDEDATTACK:
        case NPC_POISON:
        case NPC_BLINDATTACK:
        case NPC_SILENCEATTACK:
        case NPC_STUNATTACK:
            /* 石化攻撃、呪い攻撃、睡眠攻撃、ランダムATK攻撃 */
        case NPC_PETRIFYATTACK:
        case NPC_CURSEATTACK:
        case NPC_SLEEPATTACK:
        case NPC_RANDOMATTACK:
            /* 水属性攻撃、地属性攻撃、火属性攻撃、風属性攻撃 */
        case NPC_WATERATTACK:
        case NPC_GROUNDATTACK:
        case NPC_FIREATTACK:
        case NPC_WINDATTACK:
            /* 毒属性攻撃、聖属性攻撃、闇属性攻撃、念属性攻撃、SP減少攻撃 */
        case NPC_POISONATTACK:
        case NPC_HOLYATTACK:
        case NPC_DARKNESSATTACK:
        case NPC_TELEKINESISATTACK:
        case LK_AURABLADE:     /* オーラブレード */
        case LK_SPIRALPIERCE:  /* スパイラルピアース */
        case LK_HEADCRUSH:     /* ヘッドクラッシュ */
        case LK_JOINTBEAT:     /* ジョイントビート */
        case PA_PRESSURE:      /* プレッシャー */
        case PA_SACRIFICE:     /* サクリファイス */
        case SN_SHARPSHOOTING: /* シャープシューティング */
        case CG_ARROWVULCAN:   /* アローバルカン */
        case ASC_BREAKER:      /* ソウルブレーカー */
        case HW_MAGICCRASHER:  /* マジッククラッシャー */
            skill_attack(BF_WEAPON, src, src, bl, skillid, skilllv, tick,
                          flag);
            break;
        case NPC_DARKBREATH:
            clif_emotion(src, 7);
            skill_attack(BF_MISC, src, src, bl, skillid, skilllv, tick,
                          flag);
            break;
        case MO_INVESTIGATE:   /* 発勁 */
        {
            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(src);
            skill_attack(BF_WEAPON, src, src, bl, skillid, skilllv, tick,
                          flag);
            if (sc_data[SC_BLADESTOP].timer != -1)
                skill_status_change_end(src, SC_BLADESTOP, -1);
        }
            break;
        case SN_FALCONASSAULT: /* ファルコンアサルト */
            skill_attack(BF_MISC, src, src, bl, skillid, skilllv, tick,
                          flag);
            break;
        case KN_BRANDISHSPEAR: /* ブランディッシュスピア */
        {
            struct mob_data *md = (struct mob_data *) bl;
            nullpo_retr(1, md);
            skill_attack(BF_WEAPON, src, src, bl, skillid, skilllv, tick,
                          flag);
            if (md->hp > 0)
            {
                skill_blown(src, bl, skill_get_blewcount(skillid, skilllv));
                if (bl->type == BL_MOB)
                    clif_fixmobpos((struct mob_data *) bl);
                else
                    clif_fixpos(bl);
            }
        }
            break;
        case RG_BACKSTAP:      /* バックスタブ */
        {
            int dir = map_calc_dir(src, bl->x, bl->y), t_dir =
                battle_get_dir(bl);
            int dist = distance(src->x, src->y, bl->x, bl->y);
            if ((dist > 0 && !map_check_dir(dir, t_dir))
                || bl->type == BL_SKILL)
            {
                eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(src);
                if (sc_data && sc_data[SC_HIDING].timer != -1)
                    skill_status_change_end(src, SC_HIDING, -1);   // ハイディング解除
                skill_attack(BF_WEAPON, src, src, bl, skillid, skilllv, tick,
                              flag);
                skill_blown(src, bl, skill_get_blewcount(skillid, skilllv));
            }
            else if (src->type == BL_PC)
                clif_skill_fail(sd, sd->skillid, 0, 0);
        }
            break;

        case AM_ACIDTERROR:    /* アシッドテラー */
            skill_attack(BF_WEAPON, src, src, bl, skillid, skilllv, tick,
                          flag);
            if (bl->type == BL_PC
                && MRAND(100) < skill_get_time(skillid, skilllv)
                && battle_config.equipment_breaking)
                pc_breakarmor((struct map_session_data *) bl);
            break;
        case MO_FINGEROFFENSIVE:   /* 指弾 */
        {
            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(src);

            if (!battle_config.finger_offensive_type)
                skill_attack(BF_WEAPON, src, src, bl, skillid, skilllv, tick,
                              flag);
            else
            {
                skill_attack(BF_WEAPON, src, src, bl, skillid, skilllv, tick,
                              flag);
                if (sd)
                {
                    for (int i = 1; i < sd->spiritball_old; i++)
                        skill_addtimerskill(src, tick + i * 200, bl->id, 0,
                                             0, skillid, skilllv,
                                             skill_timerskill::sktst::from_bf(BF_WEAPON),
                                             flag);
                    sd->canmove_tick = tick + (sd->spiritball_old - 1) * 200;
                }
            }
            if (sc_data && sc_data[SC_BLADESTOP].timer != -1)
                skill_status_change_end(src, SC_BLADESTOP, -1);
        }
            break;
        case MO_CHAINCOMBO:    /* 連打掌 */
        {
            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(src);
            skill_attack(BF_WEAPON, src, src, bl, skillid, skilllv, tick,
                          flag);
            if (sc_data && sc_data[SC_BLADESTOP].timer != -1)
                skill_status_change_end(src, SC_BLADESTOP, -1);
        }
            break;
        case MO_COMBOFINISH:   /* 猛龍拳 */
        case CH_TIGERFIST:     /* 伏虎拳 */
        case CH_CHAINCRUSH:    /* 連柱崩撃 */
        case CH_PALMSTRIKE:    /* 猛虎硬派山 */
            skill_attack(BF_WEAPON, src, src, bl, skillid, skilllv, tick,
                          flag);
            break;
        case MO_EXTREMITYFIST: /* 阿修羅覇鳳拳 */
        {
            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(src);

            if (sd)
            {
                struct walkpath_data wpd;
                int dx, dy;

                dx = bl->x - sd->bl.x;
                dy = bl->y - sd->bl.y;
                if (dx > 0)
                    dx++;
                else if (dx < 0)
                    dx--;
                if (dy > 0)
                    dy++;
                else if (dy < 0)
                    dy--;
                if (dx == 0 && dy == 0)
                    dx++;
                if (path_search(&wpd, src->m, sd->bl.x, sd->bl.y, sd->bl.x + dx,
                     sd->bl.y + dy, 1) == -1)
                {
                    dx = bl->x - sd->bl.x;
                    dy = bl->y - sd->bl.y;
                    if (path_search(&wpd, src->m, sd->bl.x, sd->bl.y, sd->bl.x + dx,
                         sd->bl.y + dy, 1) == -1)
                    {
                        clif_skill_fail(sd, sd->skillid, 0, 0);
                        break;
                    }
                }
                sd->to_x = sd->bl.x + dx;
                sd->to_y = sd->bl.y + dy;
                skill_attack(BF_WEAPON, src, src, bl, skillid, skilllv, tick,
                              flag);
                clif_walkok(sd);
                clif_movechar(sd);
                if (dx < 0)
                    dx = -dx;
                if (dy < 0)
                    dy = -dy;
                sd->attackabletime = sd->canmove_tick =
                    tick + 100 + sd->speed * ((dx > dy) ? dx : dy);
                if (sd->canact_tick < sd->canmove_tick)
                    sd->canact_tick = sd->canmove_tick;
                pc_movepos(sd, sd->to_x, sd->to_y);
                skill_status_change_end(&sd->bl, SC_COMBO, -1);
            }
            else
                skill_attack(BF_WEAPON, src, src, bl, skillid, skilllv, tick,
                              flag);
            skill_status_change_end(src, SC_EXPLOSIONSPIRITS, -1);
            if (sc_data && sc_data[SC_BLADESTOP].timer != -1)
                skill_status_change_end(src, SC_BLADESTOP, -1);
        }
            break;
            /* 武器系範囲攻撃スキル */
        case AC_SHOWER:        /* アローシャワー */
        case SM_MAGNUM:        /* マグナムブレイク */
        case AS_GRIMTOOTH:     /* グリムトゥース */
        case MC_CARTREVOLUTION:    /* カートレヴォリューション */
        case NPC_SPLASHATTACK: /* スプラッシュアタック */
        case ASC_METEORASSAULT:    /* メテオアサルト */
        case AS_SPLASHER:      /* [Valaris] */
        {
            if (flag & BCT_lo_x01)
            {
                /* 個別にダメージを与える */
                if (bl->id != skill_area_temp_id)
                {
                    BCT dist = BCT_ZERO;
                    if (skillid == SM_MAGNUM)
                    {
                        /* マグナムブレイクなら中心からの距離を計算 */
                        int dx = abs(bl->x - skill_area_temp_x);
                        int dy = abs(bl->y - skill_area_temp_y);
                        dist.lo = ((dx > dy) ? dx : dy);
                    }
                    skill_attack(BF_WEAPON, src, src, bl, skillid, skilllv,
                                  tick, BCT_mid_x05 | dist);
                }
            }
            else
            {
                int ar = 1;
                int x = bl->x, y = bl->y;
                if (skillid == SM_MAGNUM)
                {
                    x = src->x;
                    y = src->y;
                }
                else if (skillid == AC_SHOWER || skillid == ASC_METEORASSAULT)  /* アローシャワー、メテオアサルト範囲5*5 */
                    ar = 2;
                else if (skillid == AS_SPLASHER)    /* ベナムスプラッシャー範囲3*3 */
                    ar = 1;
                else if (skillid == NPC_SPLASHATTACK)   /* スプラッシュアタックは範囲7*7 */
                    ar = 3;
                skill_area_temp_id = bl->id;
                skill_area_temp_x = x;
                skill_area_temp_y = y;
                /* まずターゲットに攻撃を加える */
                skill_attack(BF_WEAPON, src, src, bl, skillid, skilllv, tick,
                              BCT_ZERO);
                /* その後ターゲット以外の範囲内の敵全体に処理を行う */
                // the BCT_lo_x01 is the important thing
                map_foreachinarea(std::bind(skill_area_sub, ph::_1, src, skillid, skilllv, tick, flag | BCT_ENEMY | BCT_lo_x01, skill_castend_damage_id),
                                   bl->m, x - ar, y - ar,
                                   x + ar, y + ar, BL_NUL);
            }
        }
            break;

        case KN_BOWLINGBASH:   /* ボウリングバッシュ */
            if (flag & 1)
            {
                /* 個別にダメージを与える */
                if (bl->id != skill_area_temp_id)
                    skill_attack(BF_WEAPON, src, src, bl, skillid, skilllv,
                                  tick, BCT_mid_x05);
            }
            else
            {
                int damage;
                map_freeblock_lock();
                damage =
                    skill_attack(BF_WEAPON, src, src, bl, skillid, skilllv,
                                  tick, BCT_ZERO);
                if (damage > 0)
                {
                    int i, c;  /* 他人から聞いた動きなので間違ってる可能性大&効率が悪いっす>< */
                    c = skill_get_blewcount(skillid, skilllv);
                    for (i = 0; i < c; i++)
                    {
                        skill_blown(src, bl, 1);
                        if (bl->type == BL_MOB)
                            clif_fixmobpos((struct mob_data *) bl);
                        else
                            clif_fixpos(bl);
                        skill_area_temp_counter = BCT_ZERO;
                        map_foreachinarea(std::bind(skill_area_sub, ph::_1, src, skillid, skilllv, tick, flag | BCT_ENEMY, skill_area_sub_count),
                                           bl->m, bl->x - 1, bl->y - 1,
                                           bl->x + 1, bl->y + 1, BL_NUL);
                        if (skill_area_temp_counter > 1)
                            break;
                    }
                    skill_area_temp_id = bl->id;
                    skill_area_temp_x = bl->x;
                    skill_area_temp_y = bl->y;
                    /* その後ターゲット以外の範囲内の敵全体に処理を行う */
                    map_foreachinarea(std::bind(skill_area_sub, ph::_1, src, skillid, skilllv, tick, flag | BCT_ENEMY | BCT_lo_x01, skill_castend_damage_id),
                            bl->m, bl->x - 1, bl->y - 1,
                            bl->x + 1, bl->y + 1, BL_NUL);
                    battle_damage(src, bl, damage, 1);
                    if (rdamage > 0)
                        battle_damage(bl, src, rdamage, 0);
                }
                map_freeblock_unlock();
            }
            break;

        case ALL_RESURRECTION: /* リザレクション */
        case PR_TURNUNDEAD:    /* ターンアンデッド */
            if (bl->type != BL_PC
                && battle_check_undead(battle_get_race(bl),
                                        battle_get_elem_type(bl)))
                skill_attack(BF_MAGIC, src, src, bl, skillid, skilllv, tick,
                              flag);
            else
            {
                map_freeblock_unlock();
                return 1;
            }
            break;

            /* 魔法系スキル */
        case MG_SOULSTRIKE:    /* ソウルストライク */
        case MG_COLDBOLT:      /* コールドボルト */
        case MG_FIREBOLT:      /* ファイアーボルト */
        case MG_LIGHTNINGBOLT: /* ライトニングボルト */
        case WZ_EARTHSPIKE:    /* アーススパイク */
        case AL_HEAL:          /* ヒール */
        case AL_HOLYLIGHT:     /* ホーリーライト */
        case MG_FROSTDIVER:    /* フロストダイバー */
        case WZ_JUPITEL:       /* ユピテルサンダー */
        case NPC_MAGICALATTACK:    /* MOB:魔法打撃攻撃 */
        case PR_ASPERSIO:      /* アスペルシオ */
            skill_attack(BF_MAGIC, src, src, bl, skillid, skilllv, tick,
                          flag);
            break;

        case WZ_WATERBALL:     /* ウォーターボール */
            skill_attack(BF_MAGIC, src, src, bl, skillid, skilllv, tick,
                          flag);
            if (skilllv > 1)
                skill_status_change_start(src, SC_WATERBALL, skilllv, bl->id,
                                           0, 0, 0, 0);
            break;

        case PR_BENEDICTIO:    /* 聖体降福 */
            if (battle_get_race(bl) == 1 || battle_get_race(bl) == 6)
                skill_attack(BF_MAGIC, src, src, bl, skillid, skilllv, tick,
                              flag);
            break;

            /* 魔法系範囲攻撃スキル */
        case MG_NAPALMBEAT:    /* ナパームビート */
        case MG_FIREBALL:      /* ファイヤーボール */
            if (flag & 1)
            {
                /* 個別にダメージを与える */
                if (bl->id != skill_area_temp_id)
                {
                    BCT dist = BCT_ZERO;
                    if (skillid == MG_FIREBALL)
                    {           /* ファイヤーボールなら中心からの距離を計算 */
                        int dx = abs(bl->x - skill_area_temp_x);
                        int dy = abs(bl->y - skill_area_temp_y);
                        dist.lo = ((dx > dy) ? dx : dy);
                    }
                    skill_attack(BF_MAGIC, src, src, bl, skillid, skilllv,
                                  tick, dist | BCT_mid_x05);
                }
            }
            else
            {
                int ar = (skillid == MG_NAPALMBEAT) ? 1 : 2;
                skill_area_temp_id = bl->id;
                skill_area_temp_counter = BCT_ZERO;
                if (skillid == MG_NAPALMBEAT)
                {
                    /* ナパームでは先に数える */
                    map_foreachinarea(std::bind(skill_area_sub, ph::_1, src, skillid, skilllv, tick, flag | BCT_ENEMY, skill_area_sub_count),
                            bl->m, bl->x - 1, bl->y - 1,
                            bl->x + 1, bl->y + 1, BL_NUL);
                }
                else
                {
                    skill_area_temp_x = bl->x;
                    skill_area_temp_y = bl->y;
                }
                BCT counter = BCT_ZERO;
                counter.lo = skill_area_temp_counter;
                counter.mid = skill_area_temp_counter >> 8;
                /* まずターゲットに攻撃を加える */
                skill_attack(BF_MAGIC, src, src, bl, skillid, skilllv, tick,
                              counter);
                /* その後ターゲット以外の範囲内の敵全体に処理を行う */
                map_foreachinarea(std::bind(skill_area_sub, ph::_1, src, skillid, skilllv, tick, flag | BCT_ENEMY | BCT_lo_x01, skill_castend_damage_id),
                        bl->m, bl->x - ar, bl->y - ar,
                        bl->x + ar, bl->y + ar, BL_NUL);
            }
            break;

        case HW_NAPALMVULCAN:  // Fixed By SteelViruZ
            if (flag & 1)
            {
                if (bl->id != skill_area_temp_id)
                {
                    skill_attack(BF_MAGIC, src, src, bl, skillid, skilllv,
                                  tick, skill_area_temp_counter/* wtf */);
                }
            }
            else
            {
                int ar = (skillid == HW_NAPALMVULCAN) ? 1 : 2;
                skill_area_temp_id = bl->id;
                skill_area_temp_counter = BCT_ZERO;
                if (skillid == HW_NAPALMVULCAN)
                {
                    map_foreachinarea(std::bind(skill_area_sub, ph::_1, src, skillid, skilllv, tick, flag | BCT_ENEMY, skill_area_sub_count),
                            bl->m, bl->x - 1, bl->y - 1,
                            bl->x + 1, bl->y + 1, BL_NUL);
                }
                else
                {
                    skill_area_temp_x = bl->x;
                    skill_area_temp_y = bl->y;
                }
                skill_attack(BF_MAGIC, src, src, bl, skillid, skilllv, tick,
                              skill_area_temp_counter);
                map_foreachinarea(std::bind(skill_area_sub, ph::_1, src, skillid, skilllv, tick, flag | BCT_ENEMY | BCT_lo_x01, skill_castend_damage_id),
                        bl->m, bl->x - ar, bl->y - ar,
                        bl->x + ar, bl->y + ar, BL_NUL);
            }
            break;

        case WZ_FROSTNOVA:     /* フロストノヴァ */
            skill_castend_pos2(src, bl->x, bl->y, skillid, skilllv, tick, BCT_ZERO);
            skill_attack(BF_MAGIC, src, src, bl, skillid, skilllv, tick,
                          flag);
            break;

        case WZ_SIGHTRASHER:
            skill_castend_pos2(src, bl->x, bl->y, skillid, skilllv, tick, BCT_ZERO);
            skill_status_change_end(src, SC_SIGHT, -1);
            break;

            /* その他 */
        case HT_BLITZBEAT:     /* ブリッツビート */
            if (flag & 1)
            {
                /* 個別にダメージを与える */
                if (bl->id != skill_area_temp_id)
                    skill_attack(BF_MISC, src, src, bl, skillid, skilllv,
                                  tick,
                                  skill_area_temp_counter | (flag & BCT_highnib));
            }
            else
            {
                skill_area_temp_counter = BCT_ZERO;
                skill_area_temp_id = bl->id;
                if (flag & BCT_highnib)
                    map_foreachinarea(std::bind(skill_area_sub, ph::_1, src, skillid, skilllv, tick, flag | BCT_ENEMY, skill_area_sub_count),
                            bl->m, bl->x - 1, bl->y - 1,
                            bl->x + 1, bl->y + 1, BL_NUL);
                /* まずターゲットに攻撃を加える */
                skill_attack(BF_MISC, src, src, bl, skillid, skilllv, tick,
                              skill_area_temp_counter | (flag & BCT_highnib));
                /* その後ターゲット以外の範囲内の敵全体に処理を行う */
                map_foreachinarea(std::bind(skill_area_sub, ph::_1, src, skillid, skilllv, tick, flag | BCT_ENEMY | BCT_lo_x01, skill_castend_damage_id),
                        bl->m, bl->x - 1, bl->y - 1,
                        bl->x + 1, bl->y + 1, BL_NUL);
            }
            break;

        case CR_GRANDCROSS:    /* グランドクロス */
            /* スキルユニット配置 */
            skill_castend_pos2(src, bl->x, bl->y, skillid, skilllv, tick, BCT_ZERO);
            if (sd)
                sd->canmove_tick = tick + 1000;
            else if (src->type == BL_MOB)
                mob_changestate((struct mob_data *) src, MS_DELAY, 1000);
            break;

        case TF_THROWSTONE:    /* 石投げ */
        case NPC_SMOKING:      /* スモーキング */
            skill_attack(BF_MISC, src, src, bl, skillid, skilllv, tick, BCT_ZERO);
            break;

        case NPC_SELFDESTRUCTION:  /* 自爆 */
        case NPC_SELFDESTRUCTION2: /* 自爆2 */
            if (flag & 1)
            {
                /* 個別にダメージを与える */
                if (src->type == BL_MOB)
                {
                    struct mob_data *mb = (struct mob_data *) src;
                    nullpo_retr(1, mb);
                    mb->hp = skill_area_temp_hp;
                    if (bl->id != skill_area_temp_id)
                        skill_attack(BF_MISC, src, src, bl,
                                      NPC_SELFDESTRUCTION, skilllv, tick,
                                      flag);
                    mb->hp = 1;
                }
            }
            else
            {
                struct mob_data *md;
                if ((md = (struct mob_data *) src))
                {
                    skill_area_temp_id = bl->id;
                    skill_area_temp_hp = battle_get_hp(src);
                    map_foreachinarea(std::bind(skill_area_sub, ph::_1, src, skillid, skilllv, tick, flag | BCT_ENEMY | BCT_lo_x01, skill_castend_damage_id),
                            bl->m, bl->x - 5, bl->y - 5,
                            bl->x + 5, bl->y + 5, BL_NUL);
                    battle_damage(src, src, md->hp, 0);
                }
            }
            break;

            /* HP吸収/HP吸収魔法 */
        case NPC_BLOODDRAIN:
        case NPC_ENERGYDRAIN:
        {
            int heal;
            heal =
                skill_attack((skillid ==
                               NPC_BLOODDRAIN) ? BF_WEAPON : BF_MAGIC, src,
                              src, bl, skillid, skilllv, tick, flag);
            if (heal > 0)
                battle_heal(NULL, src, heal, 0, 0);
        }
            break;
        case SkillID::ZERO:
            if (sd)
            {
                if (flag & 3)
                {
                    if (bl->id != skill_area_temp_id)
                        skill_attack(BF_WEAPON, src, src, bl, skillid,
                                      skilllv, tick, BCT_mid_x05);
                }
                else
                {
                    int ar = sd->splash_range;
                    skill_area_temp_id = bl->id;
                    map_foreachinarea(std::bind(skill_area_sub, ph::_1, src, skillid, skilllv, tick, flag | BCT_ENEMY | BCT_lo_x01, skill_castend_damage_id),
                            bl->m, bl->x - ar, bl->y - ar,
                            bl->x + ar, bl->y + ar, BL_NUL);
                }
            }
            break;

        default:
            map_freeblock_unlock();
            return 1;
    }
    map_freeblock_unlock();

    return 0;
}

/*==========================================
 * スキル使用(詠唱完了、ID指定支援系)
 *------------------------------------------
 */
int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl,
        SkillID skillid, int skilllv,
        unsigned int tick, BCT flag)
{
    struct map_session_data *sd = NULL;
    struct map_session_data *dstsd = NULL;
    struct mob_data *md = NULL;
    struct mob_data *dstmd = NULL;
    int sc_def_vit, sc_def_mdef, strip_fix, strip_time, strip_per;
    //クラスチェンジ用ボスモンスターID
    int changeclass[] =
        { 1038, 1039, 1046, 1059, 1086, 1087, 1112, 1115, 1157, 1159, 1190,
        1272, 1312, 1373, 1492
    };
    int poringclass[] = { 1002 };

    nullpo_retr(1, src);
    nullpo_retr(1, bl);

    if (src->type == BL_PC)
        sd = (struct map_session_data *) src;
    else if (src->type == BL_MOB)
        md = (struct mob_data *) src;

    sc_def_vit = 100 - (3 + battle_get_vit(bl) + battle_get_luk(bl) / 3);
    sc_def_vit = 100 - (3 + battle_get_vit(bl) + battle_get_luk(bl) / 3);
    sc_def_mdef = 100 - (3 + battle_get_mdef(bl) + battle_get_luk(bl) / 3);
    strip_fix = battle_get_dex(src) - battle_get_dex(bl);

    if (bl->type == BL_PC)
    {
        nullpo_retr(1, dstsd = (struct map_session_data *) bl);
    }
    else if (bl->type == BL_MOB)
    {
        nullpo_retr(1, dstmd = (struct mob_data *) bl);
        if (sc_def_vit > 50)
            sc_def_vit = 50;
        if (sc_def_mdef > 50)
            sc_def_mdef = 50;
    }
    if (sc_def_vit < 0)
        sc_def_vit = 0;
    if (sc_def_mdef < 0)
        sc_def_mdef = 0;
    if (strip_fix < 0)
        strip_fix = 0;

    if (bl == NULL || bl->prev == NULL)
        return 1;
    if (sd && pc_isdead(sd))
        return 1;
    if (dstsd && pc_isdead(dstsd) && skillid != ALL_RESURRECTION)
        return 1;
    if (battle_get_class(bl) == 1288)
        return 1;
    if (skillnotok(skillid, (struct map_session_data *) bl))   // [MouseJstr]
        return 0;

    map_freeblock_lock();
    switch (skillid)
    {
        case AL_HEAL:          /* ヒール */
        {
            int heal = skill_calc_heal(src, skilllv);
            int heal_get_jobexp;
            int skill;
            struct pc_base_job s_class;

            if (dstsd && dstsd->special_state.no_magic_damage)
                heal = 0;       /* 黄金蟲カード(ヒール量0) */
            if (sd)
            {
                s_class = pc_calc_base_job(sd->status.pc_class);
                if ((skill = pc_checkskill(sd, HP_MEDITATIO)) > 0) // メディテイティオ
                    heal += heal * (skill * 2 / 100);
                if (sd && dstsd && sd->status.partner_id == dstsd->status.char_id && s_class.job == 23 && sd->status.sex == 0)  //自分も対象もPC、対象が自分のパートナー、自分がスパノビ、自分が♀なら
                    heal = heal * 2;    //スパノビの嫁が旦那にヒールすると2倍になる
            }

            heal_get_jobexp = battle_heal(NULL, bl, heal, 0, 0);

            // JOB経験値獲得
            if (src->type == BL_PC && bl->type == BL_PC && heal > 0
                && src != bl && battle_config.heal_exp > 0)
            {
                heal_get_jobexp =
                    heal_get_jobexp * battle_config.heal_exp / 100;
                if (heal_get_jobexp <= 0)
                    heal_get_jobexp = 1;
                pc_gainexp((struct map_session_data *) src, 0,
                            heal_get_jobexp);
            }
        }
            break;

        case ALL_RESURRECTION: /* リザレクション */
            if (bl->type == BL_PC)
            {
                int per = 0;
                struct map_session_data *tsd = (struct map_session_data *) bl;
                nullpo_retr(1, tsd);
                if ((map[bl->m].flag.pvp) && tsd->pvp_point < 0)
                    break;      /* PVPで復活不可能状態 */

                if (pc_isdead(tsd))
                {               /* 死亡判定 */
                    switch (skilllv)
                    {
                        case 1:
                            per = 10;
                            break;
                        case 2:
                            per = 30;
                            break;
                        case 3:
                            per = 50;
                            break;
                        case 4:
                            per = 80;
                            break;
                    }
                    tsd->status.hp = tsd->status.max_hp * per / 100;
                    if (tsd->status.hp <= 0)
                        tsd->status.hp = 1;
                    if (tsd->special_state.restart_full_recover)
                    {           /* オシリスカード */
                        tsd->status.hp = tsd->status.max_hp;
                        tsd->status.sp = tsd->status.max_sp;
                    }
                    pc_setstand(tsd);
                    if (battle_config.pc_invincible_time > 0)
                        pc_setinvincibletimer(tsd,
                                               battle_config.pc_invincible_time);
                    clif_updatestatus(tsd, SP_HP);
                    clif_resurrection(&tsd->bl, 1);
                    if (src != bl && sd && battle_config.resurrection_exp > 0)
                    {
                        int exp = 0, jexp = 0;
                        int lv =
                            tsd->status.base_level - sd->status.base_level,
                            jlv =
                            tsd->status.job_level - sd->status.job_level;
                        if (lv > 0)
                        {
                            exp =
                                (int)((double) tsd->status.base_exp *
                                       (double) lv *
                                       (double) battle_config.resurrection_exp
                                       / 1000000.);
                            if (exp < 1)
                                exp = 1;
                        }
                        if (jlv > 0)
                        {
                            jexp =
                                (int)((double) tsd->status.job_exp *
                                       (double) lv *
                                       (double) battle_config.resurrection_exp
                                       / 1000000.);
                            if (jexp < 1)
                                jexp = 1;
                        }
                        if (exp > 0 || jexp > 0)
                            pc_gainexp(sd, exp, jexp);
                    }
                }
            }
            break;

        case AL_DECAGI:        /* 速度減少 */
            if (bl->type == BL_PC
                && ((struct map_session_data *) bl)->
                special_state.no_magic_damage)
                break;
            if (MRAND(100) <
                (50 + skilllv * 3 +
                 (battle_get_lv(src) + battle_get_int(src) / 5) -
                 sc_def_mdef))
            {
                skill_status_change_start(bl,
                                           SkillStatusChangeTable[skillid],
                                           skilllv, 0, 0, 0,
                                           skill_get_time(skillid, skilllv),
                                           0);
            }
            break;

        case AL_CRUCIS:
            if (flag & 1)
            {
                int race = battle_get_race(bl), ele =
                    battle_get_elem_type(bl);
                if (battle_check_target(src, bl, BCT_ENEMY)
                    && (race == 6 || battle_check_undead(race, ele)))
                {
                    int slv = battle_get_lv(src), tlv =
                        battle_get_lv(bl), rate;
                    rate = 25 + skilllv * 2 + slv - tlv;
                    if (MRAND(100) < rate)
                        skill_status_change_start(bl,
                                SkillStatusChangeTable[skillid], skilllv,
                                0, 0, 0, 0, 0);
                }
            }
            else
            {
                int range = 15;
                map_foreachinarea(std::bind(skill_area_sub, ph::_1, src, skillid, skilllv, tick, flag | BCT_ENEMY | BCT_lo_x01, skill_castend_nodamage_id),
                        src->m, src->x - range, src->y - range,
                        src->x + range, src->y + range, BL_NUL);
            }
            break;

        case PR_LEXDIVINA:     /* レックスディビーナ */
        {
            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);
            if (bl->type == BL_PC
                && ((struct map_session_data *) bl)->
                special_state.no_magic_damage)
                break;
            if (sc_data && sc_data[SC_DIVINA].timer != -1)
                skill_status_change_end(bl, SC_DIVINA, -1);
            else if (MRAND(100) < sc_def_vit)
            {
                skill_status_change_start(bl,
                                           SkillStatusChangeTable[skillid],
                                           skilllv, 0, 0, 0,
                                           skill_get_time(skillid, skilllv),
                                           0);
            }
        }
            break;
        case SA_ABRACADABRA:
            break;
        case SA_COMA:
            if (bl->type == BL_PC
                && ((struct map_session_data *) bl)->
                special_state.no_magic_damage)
                break;
            if (dstsd)
            {
                dstsd->status.hp = 1;
                dstsd->status.sp = 1;
                clif_updatestatus(dstsd, SP_HP);
                clif_updatestatus(dstsd, SP_SP);
            }
            if (dstmd)
                dstmd->hp = 1;
            break;
        case SA_FULLRECOVERY:
            if (bl->type == BL_PC
                && ((struct map_session_data *) bl)->
                special_state.no_magic_damage)
                break;
            if (dstsd)
                pc_heal(dstsd, dstsd->status.max_hp, dstsd->status.max_sp);
            if (dstmd)
                dstmd->hp = battle_get_max_hp(&dstmd->bl);
            break;
        case SA_SUMMONMONSTER:
            if (sd)
                mob_once_spawn(sd, map[sd->bl.m].name, sd->bl.x, sd->bl.y,
                                "--ja--", -1, 1, "");
            break;
        case SA_LEVELUP:
            if (sd && pc_nextbaseexp(sd))
                pc_gainexp(sd, pc_nextbaseexp(sd) * 10 / 100, 0);
            break;

        case SA_INSTANTDEATH:
            if (sd)
                pc_damage(NULL, sd, sd->status.max_hp);
            break;

        case SA_QUESTION:
        case SA_GRAVITY:
            break;
        case SA_CLASSCHANGE:
            if (dstmd)
                mob_class_change(dstmd, changeclass);
            break;
        case SA_MONOCELL:
            if (dstmd)
                mob_class_change(dstmd, poringclass);
            break;
        case SA_DEATH:
            if (dstsd)
                pc_damage(NULL, dstsd, dstsd->status.max_hp);
            if (dstmd)
                mob_damage(NULL, dstmd, dstmd->hp, 1);
            break;
        case SA_REVERSEORCISH:
            if (dstsd)
                pc_setoption(dstsd, dstsd->status.option | Option::ORC_HEAD);
            break;
        case SA_FORTUNE:
            if (sd)
                pc_getzeny(sd, battle_get_lv(bl) * 100);
            break;
        case AL_INCAGI:        /* 速度増加 */
        case AL_BLESSING:      /* ブレッシング */
        case PR_SLOWPOISON:
        case PR_IMPOSITIO:     /* イムポシティオマヌス */
        case PR_LEXAETERNA:    /* レックスエーテルナ */
        case PR_SUFFRAGIUM:    /* サフラギウム */
        case PR_BENEDICTIO:    /* 聖体降福 */
        case CR_PROVIDENCE:    /* プロヴィデンス */
        case CG_MARIONETTE:    /* マリオネットコントロール */
            if (bl->type == BL_PC
                && ((struct map_session_data *) bl)->
                special_state.no_magic_damage)
            {
            }
            else
            {
                skill_status_change_start(bl,
                                           SkillStatusChangeTable[skillid],
                                           skilllv, 0, 0, 0,
                                           skill_get_time(skillid, skilllv),
                                           0);
            }
            break;

        case SA_FLAMELAUNCHER: // added failure chance and chance to break weapon if turned on [Valaris]
        case SA_FROSTWEAPON:
        case SA_LIGHTNINGLOADER:
        case SA_SEISMICWEAPON:
            if (bl->type == BL_PC
                && ((struct map_session_data *) bl)->
                special_state.no_magic_damage)
            {
                break;
            }
            if (bl->type == BL_PC)
            {
                struct map_session_data *sd2 = (struct map_session_data *) bl;
                if (sd2->status.weapon == 0
                    || sd2->sc_data[SC_FLAMELAUNCHER].timer != -1
                    || sd2->sc_data[SC_FROSTWEAPON].timer != -1
                    || sd2->sc_data[SC_LIGHTNINGLOADER].timer != -1
                    || sd2->sc_data[SC_SEISMICWEAPON].timer != -1
                    || sd2->sc_data[SC_ENCPOISON].timer != -1)
                {
                    clif_skill_fail(sd, skillid, 0, 0);
                    break;
                }
            }
            if (MRAND(100) > (75 + skilllv * 1) && (skilllv != 5))
            {
                clif_skill_fail(sd, skillid, 0, 0);
                if (bl->type == BL_PC && battle_config.equipment_breaking)
                {
                    struct map_session_data *sd2 =
                        (struct map_session_data *) bl;
                    if (sd != sd2)
                        clif_displaymessage(sd->fd,
                                             "You broke target's weapon");
                    pc_breakweapon(sd2);
                }
                break;
            }
            else
            {
                skill_status_change_start(bl,
                                           SkillStatusChangeTable[skillid],
                                           skilllv, 0, 0, 0,
                                           skill_get_time(skillid, skilllv),
                                           0);
            }
            break;

        case PR_ASPERSIO:      /* アスペルシオ */
            if (bl->type == BL_PC
                && ((struct map_session_data *) bl)->
                special_state.no_magic_damage)
                break;
            if (bl->type == BL_MOB)
                break;
            skill_status_change_start(bl, SkillStatusChangeTable[skillid],
                                       skilllv, 0, 0, 0,
                                       skill_get_time(skillid, skilllv), 0);
            break;
        case PR_KYRIE:         /* キリエエレイソン */
            if (bl->type == BL_PC
                && ((struct map_session_data *) bl)->
                special_state.no_magic_damage)
                break;
            skill_status_change_start(bl, SkillStatusChangeTable[skillid],
                                       skilllv, 0, 0, 0,
                                       skill_get_time(skillid, skilllv), 0);
            break;
        case KN_AUTOCOUNTER:   /* オートカウンター */
        case KN_TWOHANDQUICKEN:    /* ツーハンドクイッケン */
        case CR_SPEARQUICKEN:  /* スピアクイッケン */
        case CR_REFLECTSHIELD:
        case AS_POISONREACT:   /* ポイズンリアクト */
        case MC_LOUD:          /* ラウドボイス */
        case MG_ENERGYCOAT:    /* エナジーコート */
        case SM_ENDURE:        /* インデュア */
        case MG_SIGHT:         /* サイト */
        case AL_RUWACH:        /* ルアフ */
        case MO_EXPLOSIONSPIRITS:  // 爆裂波動
        case MO_STEELBODY:     // 金剛
        case LK_AURABLADE:     /* オーラブレード */
        case LK_PARRYING:      /* パリイング */
        case LK_CONCENTRATION: /* コンセントレーション */
        case LK_BERSERK:       /* バーサーク */
        case HP_ASSUMPTIO:     /*  */
        case WS_CARTBOOST:     /* カートブースト */
        case SN_SIGHT:         /* トゥルーサイト */
        case WS_MELTDOWN:      /* メルトダウン */
        case ST_REJECTSWORD:   /* リジェクトソード */
        case HW_MAGICPOWER:    /* 魔法力増幅 */
        case PF_MEMORIZE:      /* メモライズ */
            skill_status_change_start(bl, SkillStatusChangeTable[skillid],
                                       skilllv, 0, 0, 0,
                                       skill_get_time(skillid, skilllv), 0);
            break;
        case AS_ENCHANTPOISON: // Prevent spamming [Valaris]
            if (bl->type == BL_PC)
            {
                struct map_session_data *sd2 = (struct map_session_data *) bl;
                if (sd2->sc_data[SC_FLAMELAUNCHER].timer != -1
                    || sd2->sc_data[SC_FROSTWEAPON].timer != -1
                    || sd2->sc_data[SC_LIGHTNINGLOADER].timer != -1
                    || sd2->sc_data[SC_SEISMICWEAPON].timer != -1
                    || sd2->sc_data[SC_ENCPOISON].timer != -1)
                {
                    clif_skill_fail(sd, skillid, 0, 0);
                    break;
                }
            }
            skill_status_change_start(bl, SkillStatusChangeTable[skillid],
                                       skilllv, 0, 0, 0,
                                       skill_get_time(skillid, skilllv), 0);
            break;
        case LK_TENSIONRELAX:  /* テンションリラックス */
            pc_setsit(sd);
            clif_sitting(sd->fd, sd);
            skill_status_change_start(bl, SkillStatusChangeTable[skillid],
                                       skilllv, 0, 0, 0,
                                       skill_get_time(skillid, skilllv), 0);
            break;
        case MC_CHANGECART:
            break;
        case AC_CONCENTRATION: /* 集中力向上 */
        {
            int range = 1;
            skill_status_change_start(bl, SkillStatusChangeTable[skillid],
                                       skilllv, 0, 0, 0,
                                       skill_get_time(skillid, skilllv), 0);
            map_foreachinarea(std::bind(skill_status_change_timer_sub, ph::_1, src, SkillStatusChangeTable[skillid], tick),
                    src->m, src->x - range, src->y - range,
                    src->x + range, src->y + range, BL_NUL);
        }
            break;
        case SM_PROVOKE:       /* プロボック */
        {
            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);

            /* MVPmobと不死には効かない */
            if ((bl->type == BL_MOB && battle_get_mode(bl) & 0x20) || battle_check_undead(battle_get_race(bl), battle_get_elem_type(bl)))   //不死には効かない
            {
                map_freeblock_unlock();
                return 1;
            }

            skill_status_change_start(bl, SkillStatusChangeTable[skillid],
                                       skilllv, 0, 0, 0,
                                       skill_get_time(skillid, skilllv), 0);

            if (dstmd && dstmd->skilltimer != -1 && dstmd->state.skillcastcancel)   // 詠唱妨害
                skill_castcancel(bl, 0);
            if (dstsd && dstsd->skilltimer != -1
                && !dstsd->special_state.no_castcancel
                && dstsd->state.skillcastcancel
                && !dstsd->special_state.no_castcancel2)
                skill_castcancel(bl, 0);

            if (sc_data)
            {
                if (sc_data[SC_FREEZE].timer != -1)
                    skill_status_change_end(bl, SC_FREEZE, -1);
                if (sc_data[SC_STONE].timer != -1
                    && sc_data[SC_STONE].val2 == 0)
                    skill_status_change_end(bl, SC_STONE, -1);
                if (sc_data[SC_SLEEP].timer != -1)
                    skill_status_change_end(bl, SC_SLEEP, -1);
            }

            if (bl->type == BL_MOB)
            {
                int range = skill_get_range(skillid, skilllv);
                if (range < 0)
                    range = battle_get_range(src) - (range + 1);
                mob_target((struct mob_data *) bl, src, range);
            }
        }
            break;

        case CR_DEVOTION:      /* ディボーション */
            if (sd && dstsd)
            {
                //転生や養子の場合の元の職業を算出する

                int lv = sd->status.base_level - dstsd->status.base_level;
                lv = (lv < 0) ? -lv : lv;
                if ((dstsd->bl.type != BL_PC)   // 相手はPCじゃないとだめ
                    || (sd->bl.id == dstsd->bl.id)  // 相手が自分はだめ
                    || (lv > 10)    // レベル差±10まで
                    || (!sd->status.party_id)   // PTにもギルドにも所属無しはだめ
                    || (sd->status.party_id != dstsd->status.party_id) // 同じパーティーか、
                         // 同じギルドじゃないとだめ
                    || (dstsd->status.pc_class == 14 || dstsd->status.pc_class == 21
                        || dstsd->status.pc_class == 4015
                        || dstsd->status.pc_class == 4022))
                {               // クルセだめ
                    clif_skill_fail(sd, skillid, 0, 0);
                    map_freeblock_unlock();
                    return 1;
                }
                for (int i = 0; i < skilllv; i++)
                {
                    if (!sd->dev.val1[i])
                    {           // 空きがあったら入れる
                        sd->dev.val1[i] = bl->id;
                        sd->dev.val2[i] = bl->id;
                        break;
                    }
                    else if (i == skilllv - 1)
                    {           // 空きがなかった
                        clif_skill_fail(sd, skillid, 0, 0);
                        map_freeblock_unlock();
                        return 1;
                    }
                }
                skill_status_change_start(bl,
                                           SkillStatusChangeTable[skillid],
                                           src->id, 1, 0, 0,
                                           1000 * (15 + 15 * skilllv), 0);
            }
            else
                clif_skill_fail(sd, skillid, 0, 0);
            break;
        case MO_CALLSPIRITS:   // 気功
            if (sd)
            {
                pc_addspiritball(sd, skill_get_time(skillid, skilllv),
                                  skilllv);
            }
            break;
        case CH_SOULCOLLECT:   // 狂気功
            if (sd)
            {
                for (int i = 0; i < 5; i++)
                    pc_addspiritball(sd, skill_get_time(skillid, skilllv),
                                      5);
            }
            break;
        case MO_BLADESTOP:     // 白刃取り
            skill_status_change_start(src, SkillStatusChangeTable[skillid],
                                       skilllv, 0, 0, 0,
                                       skill_get_time(skillid, skilllv), 0);
            break;
        case MO_ABSORBSPIRITS: // 気奪
        {
            int i = 0;
            if (sd && dstsd)
            {
                if (sd == dstsd || map[sd->bl.m].flag.pvp)
                {
                    if (dstsd->spiritball > 0)
                    {
                        i = dstsd->spiritball * 7;
                        pc_delspiritball(dstsd, dstsd->spiritball, 0);
                        if (i > 0x7FFF)
                            i = 0x7FFF;
                        if (sd->status.sp + i > sd->status.max_sp)
                            i = sd->status.max_sp - sd->status.sp;
                    }
                }
            }
            else if (sd && dstmd)
            {                   //対象がモンスターの場合
                //20%の確率で対象のLv*2のSPを回復する。成功したときはターゲット(σ゚Д゚)σゲッツ!!
                if (MRAND(100) < 20)
                {
                    i = 2 * mob_db[dstmd->mob_class].lv;
                    mob_target(dstmd, src, 0);
                }
            }
            if (i)
                sd->status.sp += i;
            break;
        }

        case AC_MAKINGARROW:   /* 矢作成 */
            break;

        case AM_PHARMACY:      /* ポーション作成 */
            break;
        case WS_CREATECOIN:    /* クリエイトコイン */
            break;
        case WS_CREATENUGGET:  /* 塊製造 */
            break;
        case BS_HAMMERFALL:    /* ハンマーフォール */
            if (bl->type == BL_PC
                && ((struct map_session_data *) bl)->
                special_state.no_weapon_damage)
                break;
            if (MRAND(100) < (20 + 10 * skilllv) * sc_def_vit / 100)
            {
                skill_status_change_start(bl, SC_STAN, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            }
            break;

        case RG_RAID:          /* サプライズアタック */
            {
                int x = bl->x, y = bl->y;
                skill_area_temp_id = bl->id;
                skill_area_temp_x = x;
                skill_area_temp_y = y;
                map_foreachinarea(std::bind(skill_area_sub, ph::_1, src, skillid, skilllv, tick, flag | BCT_ENEMY | BCT_lo_x01, skill_castend_damage_id),
                                   bl->m, x - 1, y - 1,
                                   x + 1, y + 1, BL_NUL);
            }
            skill_status_change_end(src, SC_HIDING, -1);   // ハイディング解除
            break;

        case KN_BRANDISHSPEAR: /*ブランディッシュスピア */
        {
            int c;
            BCT n = BCT_ZERO;
            n.lo = 4;
            int dir = map_calc_dir(src, bl->x, bl->y);
            struct square tc;
            int x = bl->x, y = bl->y;
            skill_brandishspear_first(&tc, dir, x, y);
            skill_brandishspear_dir(&tc, dir, 4);
            /* 範囲C */
            if (skilllv == 10)
            {
                for (c = 1; c < 4; c++)
                {
                    map_foreachinarea(std::bind(skill_area_sub, ph::_1, src, skillid, skilllv, tick, flag | BCT_ENEMY | n, skill_castend_damage_id),
                            bl->m, tc.val1[c], tc.val2[c],
                            tc.val1[c], tc.val2[c], BL_NUL);
                }
            }
            /* 範囲BA */
            if (skilllv > 6)
            {
                skill_brandishspear_dir(&tc, dir, -1);
                n.lo--;
            }
            else
            {
                skill_brandishspear_dir(&tc, dir, -2);
                n.lo -= 2;
            }

            if (skilllv > 3)
            {
                for (c = 0; c < 5; c++)
                {
                    map_foreachinarea(std::bind(skill_area_sub, ph::_1, src, skillid, skilllv, tick, flag | BCT_ENEMY | n, skill_castend_damage_id),
                            bl->m, tc.val1[c], tc.val2[c],
                            tc.val1[c], tc.val2[c], BL_NUL);
                    if (skilllv > 6 && n.lo == 3 && c == 4)
                    {
                        skill_brandishspear_dir(&tc, dir, -1);
                        n.lo--;
                        c = -1;
                    }
                }
            }
            /* 範囲@ */
            for (c = 0; c < 10; c++)
            {
                if (c == 0 || c == 5)
                    skill_brandishspear_dir(&tc, dir, -1);
                map_foreachinarea(std::bind(skill_area_sub, ph::_1, src, skillid, skilllv, tick, flag | BCT_ENEMY | BCT_lo_x01, skill_castend_damage_id),
                        bl->m, tc.val1[c % 5], tc.val2[c % 5],
                        tc.val1[c % 5], tc.val2[c % 5], BL_NUL);
            }
        }
            break;

            /* パーティスキル */
        case AL_ANGELUS:       /* エンジェラス */
        case PR_MAGNIFICAT:    /* マグニフィカート */
        case PR_GLORIA:        /* グロリア */
        case SN_WINDWALK:      /* ウインドウォーク */
            if (sd == NULL || sd->status.party_id == 0 || (flag & 1))
            {
                if (bl->type == BL_PC
                    && ((struct map_session_data *) bl)->
                    special_state.no_magic_damage)
                    break;
                skill_status_change_start(bl,
                                           SkillStatusChangeTable[skillid],
                                           skilllv, 0, 0, 0,
                                           skill_get_time(skillid, skilllv),
                                           0);
            }
            else
            {
                /* パーティ全体への処理 */
                party_foreachsamemap(std::bind(skill_area_sub, ph::_1, src, skillid, skilllv, tick, flag | BCT_PARTY | BCT_lo_x01, skill_castend_nodamage_id),
                                      sd, 1);
            }
            break;
        case BS_ADRENALINE:    /* アドレナリンラッシュ */
        case BS_WEAPONPERFECT: /* ウェポンパーフェクション */
        case BS_OVERTHRUST:    /* オーバートラスト */
            if (sd == NULL || sd->status.party_id == 0 || (flag & 1))
            {
                skill_status_change_start(bl,
                                           SkillStatusChangeTable[skillid],
                                           skilllv, (src == bl) ? 1 : 0, 0, 0,
                                           skill_get_time(skillid, skilllv),
                                           0);
            }
            else
            {
                /* パーティ全体への処理 */
                party_foreachsamemap(std::bind(skill_area_sub, ph::_1, src, skillid, skilllv, tick, flag | BCT_PARTY | BCT_lo_x01, skill_castend_nodamage_id),
                        sd, 1);
            }
            break;

            /*(付加と解除が必要) */
        case BS_MAXIMIZE:      /* マキシマイズパワー */
        case NV_TRICKDEAD:     /* 死んだふり */
        case CR_DEFENDER:      /* ディフェンダー */
        case CR_AUTOGUARD:     /* オートガード */
        {
            eptr<struct status_change, StatusChange> tsc_data = battle_get_sc_data(bl);
            StatusChange sc = SkillStatusChangeTable[skillid];
            if (tsc_data)
            {
                if (tsc_data[sc].timer == -1)
                    /* 付加する */
                    skill_status_change_start(bl, sc, skilllv, 0, 0, 0,
                                               skill_get_time(skillid,
                                                               skilllv), 0);
                else
                    /* 解除する */
                    skill_status_change_end(bl, sc, -1);
            }
        }
            break;

        case TF_HIDING:        /* ハイディング */
        {
            eptr<struct status_change, StatusChange> tsc_data = battle_get_sc_data(bl);
            StatusChange sc = SkillStatusChangeTable[skillid];
            if (tsc_data)
            {
                if (tsc_data[sc].timer == -1)
                    /* 付加する */
                    skill_status_change_start(bl, sc, skilllv, 0, 0, 0,
                                               skill_get_time(skillid,
                                                               skilllv), 0);
                else
                    /* 解除する */
                    skill_status_change_end(bl, sc, -1);
            }
        }
            break;

        case AS_CLOAKING:      /* クローキング */
        {
            eptr<struct status_change, StatusChange> tsc_data = battle_get_sc_data(bl);
            StatusChange sc = SkillStatusChangeTable[skillid];
            if (tsc_data)
            {
                if (tsc_data[sc].timer == -1)
                    /* 付加する */
                    skill_status_change_start(bl, sc, skilllv, 0, 0, 0,
                                               skill_get_time(skillid,
                                                               skilllv), 0);
                else
                    /* 解除する */
                    skill_status_change_end(bl, sc, -1);
            }

            skill_check_cloaking(bl);
        }
            break;

        case ST_CHASEWALK:     /* ハイディング */
        {
            eptr<struct status_change, StatusChange> tsc_data = battle_get_sc_data(bl);
            StatusChange sc = SkillStatusChangeTable[skillid];
            if (tsc_data)
            {
                if (tsc_data[sc].timer == -1)
                    /* 付加する */
                    skill_status_change_start(bl, sc, skilllv, 0, 0, 0,
                                               skill_get_time(skillid,
                                                               skilllv), 0);
                else
                    /* 解除する */
                    skill_status_change_end(bl, sc, -1);
            }
        }
            break;

            /* 対地スキル */
        case BD_LULLABY:       /* 子守唄 */
        case BD_RICHMANKIM:    /* ニヨルドの宴 */
        case BD_ETERNALCHAOS:  /* 永遠の混沌 */
        case BD_DRUMBATTLEFIELD:   /* 戦太鼓の響き */
        case BD_RINGNIBELUNGEN:    /* ニーベルングの指輪 */
        case BD_ROKISWEIL:     /* ロキの叫び */
        case BD_INTOABYSS:     /* 深淵の中に */
        case BD_SIEGFRIED:     /* 不死身のジークフリード */
        case BA_DISSONANCE:    /* 不協和音 */
        case BA_POEMBRAGI:     /* ブラギの詩 */
        case BA_WHISTLE:       /* 口笛 */
        case BA_ASSASSINCROSS: /* 夕陽のアサシンクロス */
        case BA_APPLEIDUN:     /* イドゥンの林檎 */
        case DC_UGLYDANCE:     /* 自分勝手なダンス */
        case DC_HUMMING:       /* ハミング */
        case DC_DONTFORGETME:  /* 私を忘れないで… */
        case DC_FORTUNEKISS:   /* 幸運のキス */
        case DC_SERVICEFORYOU: /* サービスフォーユー */
        case CG_MOONLIT:       /* 月明りの泉に落ちる花びら */
            skill_unitsetting(src, skillid, skilllv, src->x, src->y, 0);
            break;

        case HP_BASILICA:      /* バジリカ */
        case PA_GOSPEL:        /* ゴスペル */
            skill_clear_unitgroup(src);
            skill_unitsetting(src, skillid, skilllv, src->x, src->y, 0);
            break;

        case BD_ADAPTATION:    /* アドリブ */
        {
            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(src);
            if (sc_data && sc_data[SC_DANCING].timer != -1)
                skill_stop_dancing(src, 0);
        }
            break;

        case BA_FROSTJOKE:     /* 寒いジョーク */
        case DC_SCREAM:        /* スクリーム */
            skill_addtimerskill(src, tick + 3000, bl->id, 0, 0, skillid,
                                 skilllv, skill_timerskill::sktst::from_n(0), flag);
            break;

        case TF_STEAL:         // スティール
            break;

        case RG_STEALCOIN:     // スティールコイン
            if (sd)
            {
                if (pc_steal_coin(sd, bl))
                {
                    int range = skill_get_range(skillid, skilllv);
                    if (range < 0)
                        range = battle_get_range(src) - (range + 1);
                    mob_target((struct mob_data *) bl, src, range);
                }
            }
            break;

        case MG_STONECURSE:    /* ストーンカース */
            if (bl->type == BL_MOB && battle_get_mode(bl) & 0x20)
            {
                clif_skill_fail(sd, sd->skillid, 0, 0);
                break;
            }
            if (bl->type == BL_PC
                && ((struct map_session_data *) bl)->
                special_state.no_magic_damage)
                break;
            if (MRAND(100) < skilllv * 4 + 20
                && !battle_check_undead(battle_get_race(bl),
                                         battle_get_elem_type(bl)))
                skill_status_change_start(bl, SC_STONE, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            else if (sd)
                clif_skill_fail(sd, skillid, 0, 0);
            break;

        case NV_FIRSTAID:      /* 応急手当 */
            battle_heal(NULL, bl, 5, 0, 0);
            break;

        case AL_CURE:          /* キュアー */
            if (bl->type == BL_PC
                && ((struct map_session_data *) bl)->
                special_state.no_magic_damage)
                break;
            skill_status_change_end(bl, SC_SILENCE, -1);
            skill_status_change_end(bl, SC_BLIND, -1);
            skill_status_change_end(bl, SC_CONFUSION, -1);
            if (battle_check_undead(battle_get_race(bl), battle_get_elem_type(bl)))
            {                   //アンデッドなら暗闇効果
                skill_status_change_start(bl, SC_CONFUSION, 1, 0, 0, 0, 6000,
                                           0);
            }
            break;

        case TF_DETOXIFY:      /* 解毒 */
            skill_status_change_end(bl, SC_POISON, -1);
            break;

        case PR_STRECOVERY:    /* リカバリー */
        {
            if (bl->type == BL_PC
                && ((struct map_session_data *) bl)->
                special_state.no_magic_damage)
                break;
            skill_status_change_end(bl, SC_FREEZE, -1);
            skill_status_change_end(bl, SC_STONE, -1);
            skill_status_change_end(bl, SC_SLEEP, -1);
            skill_status_change_end(bl, SC_STAN, -1);
            if (battle_check_undead(battle_get_race(bl), battle_get_elem_type(bl)))
            {                   //アンデッドなら暗闇効果
                int blind_time;
                //blind_time=30-battle_get_vit(bl)/10-battle_get_int/15;
                blind_time =
                    30 * (100 -
                          (battle_get_int(bl) +
                           battle_get_vit(bl)) / 2) / 100;
                if (MRAND(100) <
                    (100 -
                     (battle_get_int(bl) / 2 + battle_get_vit(bl) / 3 +
                      battle_get_luk(bl) / 10)))
                    skill_status_change_start(bl, SC_BLIND, 1, 0, 0, 0,
                                               blind_time, 0);
            }
            if (dstmd)
            {
                dstmd->attacked_id = 0;
                dstmd->target_id = 0;
                dstmd->state.attackable = false;
                dstmd->state.skillstate = MSS_IDLE;
                dstmd->next_walktime = tick + MRAND(3000) + 3000;
            }
        }
            break;

        case WZ_ESTIMATION:    /* モンスター情報 */
            break;

        case MC_IDENTIFY:      /* アイテム鑑定 */
            break;

        case BS_REPAIRWEAPON:  /* 武器修理 */
            break;

        case AL_TELEPORT:      /* テレポート */
            if (bl->type == BL_MOB)
                mob_warp((struct mob_data *) bl, -1, -1, -1, 3);
            break;

        case AL_HOLYWATER:     /* アクアベネディクタ */
            if (sd)
            {
                struct item item_tmp;
                memset(&item_tmp, 0, sizeof(item_tmp));
                item_tmp.nameid = 523;
                item_tmp.identify = 1;
                if (battle_config.holywater_name_input)
                {
                    item_tmp.card[0] = 0xfe;
                    item_tmp.card[1] = 0;
                    *((unsigned long *) (&item_tmp.card[2])) = sd->char_id; /* キャラID */
                }
                PickupFail eflag = pc_additem(sd, &item_tmp, 1);
                if (eflag != PickupFail::OKAY)
                {
                    clif_additem(sd, 0, 0, eflag);
                    map_addflooritem(&item_tmp, 1, sd->bl.m, sd->bl.x,
                                      sd->bl.y, NULL, NULL, NULL, 0);
                }
            }
            break;
        case TF_PICKSTONE:
            if (sd)
            {
                struct item item_tmp;
                struct block_list tbl;
                memset(&item_tmp, 0, sizeof(item_tmp));
                memset(&tbl, 0, sizeof(tbl)); // [MouseJstr]
                item_tmp.nameid = 7049;
                item_tmp.identify = 1;
                tbl.id = 0;
                clif_takeitem(&sd->bl, &tbl);
                PickupFail eflag = pc_additem(sd, &item_tmp, 1);
                if (eflag != PickupFail::OKAY)
                {
                    clif_additem(sd, 0, 0, eflag);
                    map_addflooritem(&item_tmp, 1, sd->bl.m, sd->bl.x,
                                      sd->bl.y, NULL, NULL, NULL, 0);
                }
            }
            break;

        case RG_STRIPWEAPON:   /* ストリップウェポン */
        {
            eptr<struct status_change, StatusChange> tsc_data = battle_get_sc_data(bl);

            if (tsc_data && tsc_data[SC_CP_WEAPON].timer != -1)
                break;
            strip_per = 5 + 2 * skilllv + strip_fix / 5;
            strip_time = skill_get_time(skillid, skilllv) + strip_fix / 2;
            if (MRAND(100) < strip_per)
            {
                skill_status_change_start(bl,
                                           SkillStatusChangeTable[skillid],
                                           skilllv, 0, 0, 0, strip_time, 0);
                if (dstsd)
                {
                    for (int i = 0; i < MAX_INVENTORY; i++)
                    {
                        if (bool(dstsd->status.inventory[i].equip)
                            && bool(dstsd->status.inventory[i].equip & EPOS::WEAPON))
                        {
                            pc_unequipitem(dstsd, i, CalcStatus::NOW);
                            break;
                        }
                    }
                }
            }
        }
            break;

        case RG_STRIPSHIELD:   /* ストリップシールド */
        {
            eptr<struct status_change, StatusChange> tsc_data = battle_get_sc_data(bl);

            if (tsc_data && tsc_data[SC_CP_SHIELD].timer != -1)
                break;
            strip_per = 5 + 2 * skilllv + strip_fix / 5;
            strip_time = skill_get_time(skillid, skilllv) + strip_fix / 2;
            if (MRAND(100) < strip_per)
            {
                skill_status_change_start(bl,
                                           SkillStatusChangeTable[skillid],
                                           skilllv, 0, 0, 0, strip_time, 0);
                if (dstsd)
                {
                    for (int i = 0; i < MAX_INVENTORY; i++)
                    {
                        if (bool(dstsd->status.inventory[i].equip)
                            && bool(dstsd->status.inventory[i].equip & EPOS::SHIELD))
                        {
                            pc_unequipitem(dstsd, i, CalcStatus::NOW);
                            break;
                        }
                    }
                }
            }
        }
            break;

        case RG_STRIPARMOR:    /* ストリップアーマー */
        {
            eptr<struct status_change, StatusChange> tsc_data = battle_get_sc_data(bl);

            if (tsc_data && tsc_data[SC_CP_ARMOR].timer != -1)
                break;
            strip_per = 5 + 2 * skilllv + strip_fix / 5;
            strip_time = skill_get_time(skillid, skilllv) + strip_fix / 2;
            if (MRAND(100) < strip_per)
            {
                skill_status_change_start(bl,
                                           SkillStatusChangeTable[skillid],
                                           skilllv, 0, 0, 0, strip_time, 0);
                if (dstsd)
                {
                    for (int i = 0; i < MAX_INVENTORY; i++)
                    {
                        if (bool(dstsd->status.inventory[i].equip)
                            && bool(dstsd->status.inventory[i].equip & EPOS::MISC1))
                        {
                            pc_unequipitem(dstsd, i, CalcStatus::NOW);
                            break;
                        }
                    }
                }
            }
        }
            break;
        case RG_STRIPHELM:     /* ストリップヘルム */
        {
            eptr<struct status_change, StatusChange> tsc_data = battle_get_sc_data(bl);

            if (tsc_data && tsc_data[SC_CP_HELM].timer != -1)
                break;
            strip_per = 5 + 2 * skilllv + strip_fix / 5;
            strip_time = skill_get_time(skillid, skilllv) + strip_fix / 2;
            if (MRAND(100) < strip_per)
            {
                skill_status_change_start(bl,
                                           SkillStatusChangeTable[skillid],
                                           skilllv, 0, 0, 0, strip_time, 0);
                if (dstsd)
                {
                    for (int i = 0; i < MAX_INVENTORY; i++)
                    {
                        if (bool(dstsd->status.inventory[i].equip)
                            && bool(dstsd->status.inventory[i].equip & EPOS::HAT))
                        {
                            pc_unequipitem(dstsd, i, CalcStatus::NOW);
                            break;
                        }
                    }
                }
            }
        }
            break;
            /* PotionPitcher */
        case AM_POTIONPITCHER: /* ポーションピッチャー */
        {
            int i, x, hp = 0, sp = 0;
            if (sd)
            {
                if (sd == dstsd)
                {               // cancel use on oneself
                    map_freeblock_unlock();
                    return 1;
                }
                x = skilllv % 11 - 1;
                i = pc_search_inventory(sd, skill_db[skillid].itemid[x]);
                if (i < 0 || skill_db[skillid].itemid[x] <= 0)
                {
                    clif_skill_fail(sd, skillid, 0, 0);
                    map_freeblock_unlock();
                    return 1;
                }
                if (sd->inventory_data[i] == NULL
                    || sd->status.inventory[i].amount <
                    skill_db[skillid].amount[x])
                {
                    clif_skill_fail(sd, skillid, 0, 0);
                    map_freeblock_unlock();
                    return 1;
                }
                sd->state.potionpitcher_flag = 1;
                sd->potion_hp = sd->potion_sp = sd->potion_per_hp =
                    sd->potion_per_sp = 0;
                sd->skilltarget = bl->id;
                run_script(sd->inventory_data[i]->use_script, 0, sd->bl.id,
                            0);
                pc_delitem(sd, i, skill_db[skillid].amount[x], 0);
                sd->state.potionpitcher_flag = 0;
                if (sd->potion_per_hp > 0 || sd->potion_per_sp > 0)
                {
                    hp = battle_get_max_hp(bl) * sd->potion_per_hp / 100;
                    hp = hp * (100 +
                               pc_checkskill(sd,
                                              AM_POTIONPITCHER) * 10 +
                               pc_checkskill(sd,
                                              AM_LEARNINGPOTION) * 5) / 100;
                    if (dstsd)
                    {
                        sp = dstsd->status.max_sp * sd->potion_per_sp / 100;
                        sp = sp * (100 +
                                   pc_checkskill(sd,
                                                  AM_POTIONPITCHER) +
                                   pc_checkskill(sd,
                                                  AM_LEARNINGPOTION) * 5) /
                            100;
                    }
                }
                else
                {
                    if (sd->potion_hp > 0)
                    {
                        hp = sd->potion_hp * (100 +
                                              pc_checkskill(sd,
                                                             AM_POTIONPITCHER)
                                              * 10 + pc_checkskill(sd,
                                                                    AM_LEARNINGPOTION)
                                              * 5) / 100;
                        hp = hp * (100 + (battle_get_vit(bl) << 1)) / 100;
                        if (dstsd)
                            hp = hp * (100 +
                                       pc_checkskill(dstsd,
                                                      SM_RECOVERY) * 10) /
                                100;
                    }
                    if (sd->potion_sp > 0)
                    {
                        sp = sd->potion_sp * (100 +
                                              pc_checkskill(sd,
                                                             AM_POTIONPITCHER)
                                              + pc_checkskill(sd,
                                                               AM_LEARNINGPOTION)
                                              * 5) / 100;
                        sp = sp * (100 + (battle_get_int(bl) << 1)) / 100;
                        if (dstsd)
                            sp = sp * (100 +
                                       pc_checkskill(dstsd,
                                                      MG_SRECOVERY) * 10) /
                                100;
                    }
                }
            }
            else
            {
                hp = (1 + MRAND(400)) * (100 + skilllv * 10) / 100;
                hp = hp * (100 + (battle_get_vit(bl) << 1)) / 100;
                if (dstsd)
                    hp = hp * (100 +
                               pc_checkskill(dstsd, SM_RECOVERY) * 10) / 100;
            }
            battle_heal(src, bl, hp, sp, 0);
        }
            break;
        case AM_CP_WEAPON:
        {
            eptr<struct status_change, StatusChange> tsc_data = battle_get_sc_data(bl);
            if (tsc_data && tsc_data[SC_STRIPWEAPON].timer != -1)
                skill_status_change_end(bl, SC_STRIPWEAPON, -1);
            skill_status_change_start(bl, SkillStatusChangeTable[skillid],
                                       skilllv, 0, 0, 0,
                                       skill_get_time(skillid, skilllv), 0);
        }
            break;
        case AM_CP_SHIELD:
        {
            eptr<struct status_change, StatusChange> tsc_data = battle_get_sc_data(bl);
            if (tsc_data && tsc_data[SC_STRIPSHIELD].timer != -1)
                skill_status_change_end(bl, SC_STRIPSHIELD, -1);
            skill_status_change_start(bl, SkillStatusChangeTable[skillid],
                                       skilllv, 0, 0, 0,
                                       skill_get_time(skillid, skilllv), 0);
        }
            break;
        case AM_CP_ARMOR:
        {
            eptr<struct status_change, StatusChange> tsc_data = battle_get_sc_data(bl);
            if (tsc_data && tsc_data[SC_STRIPARMOR].timer != -1)
                skill_status_change_end(bl, SC_STRIPARMOR, -1);
            skill_status_change_start(bl, SkillStatusChangeTable[skillid],
                                       skilllv, 0, 0, 0,
                                       skill_get_time(skillid, skilllv), 0);
        }
            break;
        case AM_CP_HELM:
        {
            eptr<struct status_change, StatusChange> tsc_data = battle_get_sc_data(bl);
            if (tsc_data && tsc_data[SC_STRIPHELM].timer != -1)
                skill_status_change_end(bl, SC_STRIPHELM, -1);
            skill_status_change_start(bl, SkillStatusChangeTable[skillid],
                                       skilllv, 0, 0, 0,
                                       skill_get_time(skillid, skilllv), 0);
        }
            break;
        case SA_DISPELL:       /* ディスペル */
        {
            if (bl->type == BL_PC
                && ((struct map_session_data *) bl)->
                special_state.no_magic_damage)
                break;
            // up to SC_BLIND, exclusive. WTF?
            for (StatusChange i : erange(StatusChange(0), StatusChange(136)))
            {
                if (i == SC_RIDING || i == SC_FALCON || i == SC_HALLUCINATION
                    || i == SC_WEIGHT50 || i == SC_WEIGHT90
                    || i == SC_STRIPWEAPON || i == SC_STRIPSHIELD
                    || i == SC_STRIPARMOR || i == SC_STRIPHELM
                    || i == SC_CP_WEAPON || i == SC_CP_SHIELD
                    || i == SC_CP_ARMOR || i == SC_CP_HELM || i == SC_COMBO)
                    continue;
                skill_status_change_end(bl, i, -1);
            }
        }
            break;

        case TF_BACKSLIDING:   /* バックステップ */
            battle_stopwalking(src, 1);
            skill_blown(src, bl,
                         skill_get_blewcount(skillid, skilllv) | 0x10000);
            if (src->type == BL_MOB)
                clif_fixmobpos((struct mob_data *) src);
            else if (src->type == BL_PC)
                clif_fixpos(src);
            skill_addtimerskill(src, tick + 200, src->id, 0, 0, skillid,
                                 skilllv, skill_timerskill::sktst::from_n(0), flag);
            break;

        case SA_CASTCANCEL:
            skill_castcancel(src, 1);
            if (sd)
            {
                int sp = skill_get_sp(sd->skillid_old, sd->skilllv_old);
                sp = sp * (90 - (skilllv - 1) * 20) / 100;
                if (sp < 0)
                    sp = 0;
                pc_heal(sd, 0, -sp);
            }
            break;
        case SA_SPELLBREAKER:  // スペルブレイカー
        {
            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);
            int sp;
            if (sc_data && sc_data[SC_MAGICROD].timer != -1)
            {
                if (dstsd)
                {
                    sp = skill_get_sp(skillid, skilllv);
                    sp = sp * sc_data[SC_MAGICROD].val2 / 100;
                    if (sp > 0x7fff)
                        sp = 0x7fff;
                    else if (sp < 1)
                        sp = 1;
                    if (dstsd->status.sp + sp > dstsd->status.max_sp)
                    {
                        sp = dstsd->status.max_sp - dstsd->status.sp;
                        dstsd->status.sp = dstsd->status.max_sp;
                    }
                    else
                        dstsd->status.sp += sp;
                }
                if (sd)
                {
                    sp = sd->status.max_sp / 5;
                    if (sp < 1)
                        sp = 1;
                    pc_heal(sd, 0, -sp);
                }
            }
            else
            {
                SkillID bl_skillid = SkillID::ZERO;
                int bl_skilllv = 0;
                if (bl->type == BL_PC)
                {
                    if (dstsd && dstsd->skilltimer != -1)
                    {
                        bl_skillid = dstsd->skillid;
                        bl_skilllv = dstsd->skilllv;
                    }
                }
                else if (bl->type == BL_MOB)
                {
                    if (dstmd && dstmd->skilltimer != -1)
                    {
                        bl_skillid = dstmd->skillid;
                        bl_skilllv = dstmd->skilllv;
                    }
                }
                if (bl_skillid != SkillID::ZERO
                    && bl_skillid != SkillID::NEGATIVE
                    && skill_db[bl_skillid].skill_type == BF_MAGIC)
                {
                    skill_castcancel(bl, 0);
                    sp = skill_get_sp(bl_skillid, bl_skilllv);
                    if (dstsd)
                        pc_heal(dstsd, 0, -sp);
                    if (sd)
                    {
                        sp = sp * (25 * (skilllv - 1)) / 100;
                        if (skilllv > 1 && sp < 1)
                            sp = 1;
                        if (sp > 0x7fff)
                            sp = 0x7fff;
                        else if (sp < 1)
                            sp = 1;
                        if (sd->status.sp + sp > sd->status.max_sp)
                        {
                            sp = sd->status.max_sp - sd->status.sp;
                            sd->status.sp = sd->status.max_sp;
                        }
                        else
                            sd->status.sp += sp;
                    }
                }
                else if (sd)
                    clif_skill_fail(sd, skillid, 0, 0);
            }
        }
            break;
        case SA_MAGICROD:
            if (bl->type == BL_PC
                && ((struct map_session_data *) bl)->
                special_state.no_magic_damage)
                break;
            skill_status_change_start(bl, SkillStatusChangeTable[skillid],
                                       skilllv, 0, 0, 0,
                                       skill_get_time(skillid, skilllv), 0);
            break;
        case SA_AUTOSPELL:     /* オートスペル */
            if (sd)
            {}
            else
            {
                int maxlv = 1;
                SkillID spellid = SkillID::ZERO;
                static const SkillID spellarray[3] =
                {
                    MG_COLDBOLT, MG_FIREBOLT, MG_LIGHTNINGBOLT,
                };
                if (skilllv >= 10)
                {
                    spellid = MG_FROSTDIVER;
                    maxlv = skilllv - 9;
                }
                else if (skilllv >= 8)
                {
                    spellid = MG_FIREBALL;
                    maxlv = skilllv - 7;
                }
                else if (skilllv >= 5)
                {
                    spellid = MG_SOULSTRIKE;
                    maxlv = skilllv - 4;
                }
                else if (skilllv >= 2)
                {
                    int i = MRAND(3);
                    spellid = spellarray[i];
                    maxlv = skilllv - 1;
                }
                else if (skilllv > 0)
                {
                    spellid = MG_NAPALMBEAT;
                    maxlv = 3;
                }
                if (spellid != SkillID::ZERO)
                    skill_status_change_start(src, SC_AUTOSPELL, skilllv,
                                               uint16_t(spellid), maxlv, 0,
                                               skill_get_time(SA_AUTOSPELL,
                                                               skilllv), 0);
            }
            break;

            /* ランダム属性変化、水属性変化、地、火、風 */
        case NPC_ATTRICHANGE:
        case NPC_CHANGEWATER:
        case NPC_CHANGEGROUND:
        case NPC_CHANGEFIRE:
        case NPC_CHANGEWIND:
            /* 毒、聖、念、闇 */
        case NPC_CHANGEPOISON:
        case NPC_CHANGEHOLY:
        case NPC_CHANGEDARKNESS:
        case NPC_CHANGETELEKINESIS:
            if (md)
            {
                md->def_ele = skill_get_pl(skillid);
                if (md->def_ele == 0)   /* ランダム変化、ただし、 */
                    md->def_ele = MRAND(10);   /* 不死属性は除く */
                md->def_ele += (1 + MRAND(4)) * 20;    /* 属性レベルはランダム */
            }
            break;

        case NPC_HALLUCINATION:
            if (bl->type == BL_PC
                && ((struct map_session_data *) bl)->
                special_state.no_magic_damage)
                break;
            skill_status_change_start(bl, SkillStatusChangeTable[skillid],
                                       skilllv, 0, 0, 0,
                                       skill_get_time(skillid, skilllv), 0);
            break;

        case NPC_KEEPING:
        case NPC_BARRIER:
        {
            int skill_time = skill_get_time(skillid, skilllv);
            skill_status_change_start(bl, SkillStatusChangeTable[skillid],
                                       skilllv, 0, 0, 0, skill_time, 0);
            mob_changestate((struct mob_data *) src, MS_DELAY, skill_time);
        }
            break;

        case NPC_DARKBLESSING:
        {
            int sc_def = 100 - battle_get_mdef(bl);
            if (bl->type == BL_PC
                && ((struct map_session_data *) bl)->
                special_state.no_magic_damage)
                break;
            if (battle_get_elem_type(bl) == 7 || battle_get_race(bl) == 6)
                break;
            if (MRAND(100) < sc_def * (50 + skilllv * 5) / 100)
            {
                if (dstsd)
                {
                    int hp = battle_get_hp(bl) - 1;
                    pc_heal(dstsd, -hp, 0);
                }
                else if (dstmd)
                    dstmd->hp = 1;
            }
        }
            break;

        case NPC_SELFDESTRUCTION:  /* 自爆 */
        case NPC_SELFDESTRUCTION2: /* 自爆2 */
            skill_status_change_start(bl, SkillStatusChangeTable[skillid],
                                       skilllv, uint16_t(skillid), 0, 0,
                                       skill_get_time(skillid, skilllv), 0);
            break;
        case NPC_LICK:
            if (bl->type == BL_PC
                && ((struct map_session_data *) bl)->
                special_state.no_weapon_damage)
                break;
            if (dstsd)
                pc_heal(dstsd, 0, -100);
            if (MRAND(100) < (skilllv * 5) * sc_def_vit / 100)
                skill_status_change_start(bl, SC_STAN, skilllv, 0, 0, 0,
                                           skill_get_time2(skillid, skilllv),
                                           0);
            break;

        case NPC_SUICIDE:      /* 自決 */
            if (src && bl && md)
                mob_damage(NULL, md, md->hp, 0);
            break;

        case NPC_SUMMONSLAVE:  /* 手下召喚 */
        case NPC_SUMMONMONSTER:    /* MOB召喚 */
            if (md && !md->master_id)
            {
                mob_summonslave(md,
                                 mob_db[md->mob_class].skill[md->skillidx].val,
                                 skilllv,
                                 (skillid == NPC_SUMMONSLAVE) ? 1 : 0);
            }
            break;

        case NPC_TRANSFORMATION:
        case NPC_METAMORPHOSIS:
            if (md)
                mob_class_change(md,
                                  mob_db[md->mob_class].skill[md->skillidx].val);
            break;

        case NPC_EMOTION:      /* エモーション */
            if (md)
                clif_emotion(&md->bl,
                              mob_db[md->mob_class].skill[md->skillidx].val[0]);
            break;

        case NPC_DEFENDER:
            break;

        case WE_MALE:          /* 君だけは護るよ */
            if (sd && dstsd)
            {
                int hp_rate =
                    (skilllv <=
                     0) ? 0 : skill_db[skillid].hp_rate[skilllv - 1];
                int gain_hp = sd->status.max_hp * abs(hp_rate) / 100; // 15%
                battle_heal(NULL, bl, gain_hp, 0, 0);
            }
            break;
        case WE_FEMALE:        /* あなたの為に犠牲になります */
            if (sd && dstsd)
            {
                int sp_rate =
                    (skilllv <=
                     0) ? 0 : skill_db[skillid].sp_rate[skilllv - 1];
                int gain_sp = sd->status.max_sp * abs(sp_rate) / 100; // 15%
                battle_heal(NULL, bl, 0, gain_sp, 0);
            }
            break;

        case WE_CALLPARTNER:   /* あなたに会いたい */
            if (sd && dstsd)
            {
                if (map[sd->bl.m].flag.nomemo)
                {
                    return 0;
                }
                if ((dstsd = pc_get_partner(sd)) == NULL)
                {
                    clif_skill_fail(sd, skillid, 0, 0);
                    return 0;
                }
                skill_unitsetting(src, skillid, skilllv, sd->bl.x, sd->bl.y,
                                   0);
            }
            break;

        case PF_HPCONVERSION:  /* ライフ置き換え */
            if (sd)
            {
                int conv_hp = 0, conv_sp = 0;
                conv_hp = sd->status.hp / 10;   //基本はHPの10%
                sd->status.hp -= conv_hp;   //HPを減らす
                conv_sp = conv_hp * 20 * skilllv / 100;
                conv_sp =
                    (sd->status.sp + conv_sp >
                     sd->status.max_sp) ? sd->status.max_sp -
                    sd->status.sp : conv_sp;
                sd->status.sp += conv_sp;   //SPを増やす
                pc_heal(sd, -conv_hp, conv_sp);
            }
            break;
        case HT_REMOVETRAP:    /* リムーブトラップ */
            {
                struct skill_unit *su = NULL;
                struct item item_tmp;
                if ((bl->type == BL_SKILL) &&
                    (su = (struct skill_unit *) bl) &&
                    (su->group->src_id == src->id || map[bl->m].flag.pvp)
                    && (su->group->unit_id >= 0x8f
                        && su->group->unit_id <= 0x99)
                    && (su->group->unit_id != 0x92))
                {               //罠を取り返す
                    if (sd)
                    {
                        if (battle_config.skill_removetrap_type == 1)
                        {
                            for (int i = 0; i < 10; i++)
                            {
                                if (skill_db[su->group->skill_id].itemid[i] >
                                    0)
                                {
                                    memset(&item_tmp, 0, sizeof(item_tmp));
                                    item_tmp.nameid =
                                        skill_db[su->group->
                                                 skill_id].itemid[i];
                                    item_tmp.identify = 1;
                                    PickupFail item_flag;
                                    if (item_tmp.nameid
                                        && (item_flag =
                                            pc_additem(sd, &item_tmp,
                                                skill_db[su->group->skill_id].amount[i]))
                                        != PickupFail::OKAY)
                                    {
                                        clif_additem(sd, 0, 0, item_flag);
                                        map_addflooritem(&item_tmp,
                                                          skill_db[su->
                                                                   group->skill_id].amount
                                                          [i], sd->bl.m,
                                                          sd->bl.x, sd->bl.y,
                                                          NULL, NULL, NULL,
                                                          0);
                                    }
                                }
                            }
                        }
                        else
                        {
                            memset(&item_tmp, 0, sizeof(item_tmp));
                            item_tmp.nameid = 1065;
                            item_tmp.identify = 1;
                            PickupFail item_flag;
                            if (item_tmp.nameid
                                && (item_flag = pc_additem(sd, &item_tmp, 1))
                                != PickupFail::OKAY)
                            {
                                clif_additem(sd, 0, 0, item_flag);
                                map_addflooritem(&item_tmp, 1, sd->bl.m,
                                                  sd->bl.x, sd->bl.y, NULL,
                                                  NULL, NULL, 0);
                            }
                        }

                    }
                    if (su->group->unit_id == 0x91 && su->group->val2)
                    {
                        struct block_list *target =
                            map_id2bl(su->group->val2);
                        if (target
                            && (target->type == BL_PC
                                || target->type == BL_MOB))
                            skill_status_change_end(target, SC_ANKLE, -1);
                    }
                    skill_delunit(su);
                }
            }
            break;
        case HT_SPRINGTRAP:    /* スプリングトラップ */
            {
                struct skill_unit *su = NULL;
                if ((bl->type == BL_SKILL) && (su = (struct skill_unit *) bl)
                    && (su->group))
                {
                    switch (su->group->unit_id)
                    {
                        case 0x8f: /* ブラストマイン */
                        case 0x90: /* スキッドトラップ */
                        case 0x93: /* ランドマイン */
                        case 0x94: /* ショックウェーブトラップ */
                        case 0x95: /* サンドマン */
                        case 0x96: /* フラッシャー */
                        case 0x97: /* フリージングトラップ */
                        case 0x98: /* クレイモアートラップ */
                        case 0x99: /* トーキーボックス */
                            su->group->unit_id = 0x8c;
                            clif_changelook(bl, LOOK_BASE,
                                             su->group->unit_id);
                            su->group->limit =
                                DIFF_TICK(tick + 1500, su->group->tick);
                            su->limit =
                                DIFF_TICK(tick + 1500, su->group->tick);
                    }
                }
            }
            break;
        case BD_ENCORE:        /* アンコール */
            if (sd)
                skill_use_id(sd, src->id, sd->skillid_dance,
                              sd->skilllv_dance);
            break;
        case AS_SPLASHER:      /* ベナムスプラッシャー */
            if ((double) battle_get_max_hp(bl) * 2 / 3 < battle_get_hp(bl))   //HPが2/3以上残っていたら失敗
                return 1;
            skill_status_change_start(bl, SkillStatusChangeTable[skillid],
                                       skilllv, uint16_t(skillid), src->id, 0,
                                       skill_get_time(skillid, skilllv), 0);
            break;
        case PF_MINDBREAKER:   /* プロボック */
        {
            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);

            /* MVPmobと不死には効かない */
            if ((bl->type == BL_MOB && battle_get_mode(bl) & 0x20) || battle_check_undead(battle_get_race(bl), battle_get_elem_type(bl)))   //不死には効かない
            {
                map_freeblock_unlock();
                return 1;
            }

            skill_status_change_start(bl, SkillStatusChangeTable[skillid],
                                       skilllv, 0, 0, 0,
                                       skill_get_time(skillid, skilllv), 0);

            if (dstmd && dstmd->skilltimer != -1 && dstmd->state.skillcastcancel)   // 詠唱妨害
                skill_castcancel(bl, 0);
            if (dstsd && dstsd->skilltimer != -1
                && !dstsd->special_state.no_castcancel
                && dstsd->state.skillcastcancel
                && !dstsd->special_state.no_castcancel2)
                skill_castcancel(bl, 0);

            if (sc_data)
            {
                if (sc_data[SC_FREEZE].timer != -1)
                    skill_status_change_end(bl, SC_FREEZE, -1);
                if (sc_data[SC_STONE].timer != -1
                    && sc_data[SC_STONE].val2 == 0)
                    skill_status_change_end(bl, SC_STONE, -1);
                if (sc_data[SC_SLEEP].timer != -1)
                    skill_status_change_end(bl, SC_SLEEP, -1);
            }

            if (bl->type == BL_MOB)
            {
                int range = skill_get_range(skillid, skilllv);
                if (range < 0)
                    range = battle_get_range(src) - (range + 1);
                mob_target((struct mob_data *) bl, src, range);
            }
        }
            break;

        case RG_CLEANER:       //AppleGirl
            {
                struct skill_unit *su = NULL;
                if ((bl->type == BL_SKILL) &&
                    (su = (struct skill_unit *) bl) &&
                    (su->group->src_id == src->id || map[bl->m].flag.pvp)
                    && (su->group->unit_id == 0xb0))
                {               //罠を取り返す
                    if (sd)
                        skill_delunit(su);
                }
            }
            break;
        default:
            printf("Unknown skill used:%d\n", uint16_t(skillid));
            map_freeblock_unlock();
            return 1;
    }

    map_freeblock_unlock();
    return 0;
}

/*==========================================
 * スキル使用(詠唱完了、ID指定)
 *------------------------------------------
 */
static
void skill_castend_id(timer_id tid, tick_t tick, custom_id_t id, custom_data_t)
{
    struct map_session_data *sd = map_id2sd(id) /*,*target_sd=NULL */ ;
    struct block_list *bl;
    int range, inf2;

    nullpo_retv( sd);

    if (sd->bl.prev == NULL)    //prevが無いのはありなの?
        return;

    if (sd->skillid != SA_CASTCANCEL && sd->skilltimer != tid)  /* タイマIDの確認 */
        return;
    if (sd->skillid != SA_CASTCANCEL && sd->skilltimer != -1
        && pc_checkskill(sd, SA_FREECAST) > 0)
    {
        sd->speed = sd->prev_speed;
        clif_updatestatus(sd, SP_SPEED);
    }
    if (sd->skillid != SA_CASTCANCEL)
        sd->skilltimer = -1;

    if ((bl = map_id2bl(sd->skilltarget)) == NULL || bl->prev == NULL)
    {
        sd->canact_tick = tick;
        sd->canmove_tick = tick;
        sd->skillitem = SkillID::NEGATIVE;
        sd->skillitemlv = -1;
        return;
    }
    if (sd->bl.m != bl->m || pc_isdead(sd))
    {                           //マップが違うか自分が死んでいる
        sd->canact_tick = tick;
        sd->canmove_tick = tick;
        sd->skillitem = SkillID::NEGATIVE;
        sd->skillitemlv = -1;
        return;
    }

    if (sd->skillid == PR_LEXAETERNA)
    {
        eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);
        if (sc_data
            && (sc_data[SC_FREEZE].timer != -1
                || (sc_data[SC_STONE].timer != -1
                    && sc_data[SC_STONE].val2 == 0)))
        {
            clif_skill_fail(sd, sd->skillid, 0, 0);
            sd->canact_tick = tick;
            sd->canmove_tick = tick;
            sd->skillitem = SkillID::NEGATIVE;
            sd->skillitemlv = -1;
            return;
        }
    }
    else if (sd->skillid == RG_BACKSTAP)
    {
        int dir = map_calc_dir(&sd->bl, bl->x, bl->y), t_dir =
            battle_get_dir(bl);
        int dist = distance(sd->bl.x, sd->bl.y, bl->x, bl->y);
        if (bl->type != BL_SKILL && (dist == 0 || map_check_dir(dir, t_dir)))
        {
            clif_skill_fail(sd, sd->skillid, 0, 0);
            sd->canact_tick = tick;
            sd->canmove_tick = tick;
            sd->skillitem = SkillID::NEGATIVE;
            sd->skillitemlv = -1;
            return;
        }
    }

    inf2 = skill_get_inf2(sd->skillid);
    if (((skill_get_inf(sd->skillid) & 1) || inf2 & 4) &&  // 彼我敵対関係チェック
        battle_check_target(&sd->bl, bl, BCT_ENEMY) <= 0)
    {
        sd->canact_tick = tick;
        sd->canmove_tick = tick;
        sd->skillitem = SkillID::NEGATIVE;
        sd->skillitemlv = -1;
        return;
    }
    if (inf2 & 0xC00 && sd->bl.id != bl->id)
    {
        int fail_flag = 1;
        if (inf2 & 0x400 && battle_check_target(&sd->bl, bl, BCT_PARTY) > 0)
            fail_flag = 0;
        if (fail_flag)
        {
            clif_skill_fail(sd, sd->skillid, 0, 0);
            sd->canact_tick = tick;
            sd->canmove_tick = tick;
            sd->skillitem = SkillID::NEGATIVE;
            sd->skillitemlv = -1;
            return;
        }
    }

    range = skill_get_range(sd->skillid, sd->skilllv);
    if (range < 0)
        range = battle_get_range(&sd->bl) - (range + 1);
    range += battle_config.pc_skill_add_range;
    if ((sd->skillid == MO_EXTREMITYFIST && sd->sc_data[SC_COMBO].timer != -1
            && SkillID(sd->sc_data[SC_COMBO].val1) == MO_COMBOFINISH)
        || (sd->skillid == CH_TIGERFIST && sd->sc_data[SC_COMBO].timer != -1
            && SkillID(sd->sc_data[SC_COMBO].val1) == MO_COMBOFINISH)
        || (sd->skillid == CH_CHAINCRUSH && sd->sc_data[SC_COMBO].timer != -1
            && SkillID(sd->sc_data[SC_COMBO].val1) == MO_COMBOFINISH)
        || (sd->skillid == CH_CHAINCRUSH && sd->sc_data[SC_COMBO].timer != -1
            && SkillID(sd->sc_data[SC_COMBO].val1) == CH_TIGERFIST))
        range +=
            skill_get_blewcount(MO_COMBOFINISH, sd->sc_data[SC_COMBO].val2);
    if (battle_config.skill_out_range_consume)
    {
        // changed to allow casting when target walks out of range [Valaris]
        if (range < distance(sd->bl.x, sd->bl.y, bl->x, bl->y))
        {
            clif_skill_fail(sd, sd->skillid, 0, 0);
            sd->canact_tick = tick;
            sd->canmove_tick = tick;
            sd->skillitem = SkillID::NEGATIVE;
            sd->skillitemlv = -1;
            return;
        }
    }
    if (!skill_check_condition(sd, 1))
    {                           /* 使用条件チェック */
        sd->canact_tick = tick;
        sd->canmove_tick = tick;
        sd->skillitem = SkillID::NEGATIVE;
        sd->skillitemlv = -1;
        return;
    }
    sd->skillitem = SkillID::NEGATIVE;
    sd->skillitemlv = -1;
    if (battle_config.skill_out_range_consume)
    {
        if (range < distance(sd->bl.x, sd->bl.y, bl->x, bl->y))
        {
            clif_skill_fail(sd, sd->skillid, 0, 0);
            sd->canact_tick = tick;
            sd->canmove_tick = tick;
            return;
        }
    }

    if (battle_config.pc_skill_log)
        printf("PC %d skill castend skill=%d\n",
                sd->bl.id, uint16_t(sd->skillid));
    pc_stop_walking(sd, 0);

    switch (skill_get_nk(sd->skillid))
    {
            /* 攻撃系/吹き飛ばし系 */
        case 0:
        case 2:
            skill_castend_damage_id(&sd->bl, bl, sd->skillid, sd->skilllv,
                                     tick, BCT_ZERO);
            break;
        case 1:                /* 支援系 */
            if ((sd->skillid == AL_HEAL
                 || (sd->skillid == ALL_RESURRECTION && bl->type != BL_PC)
                 || sd->skillid == PR_ASPERSIO)
                && battle_check_undead(battle_get_race(bl),
                                        battle_get_elem_type(bl)))
                skill_castend_damage_id(&sd->bl, bl, sd->skillid,
                                         sd->skilllv, tick, BCT_ZERO);
            else
                skill_castend_nodamage_id(&sd->bl, bl, sd->skillid,
                                           sd->skilllv, tick, BCT_ZERO);
            break;
    }
}

/*==========================================
 * スキル使用(詠唱完了、場所指定の実際の処理)
 *------------------------------------------
 */
int skill_castend_pos2(struct block_list *src, int x, int y,
        SkillID skillid, int skilllv, unsigned int tick, BCT flag)
{
    struct map_session_data *sd = NULL;
    int i, tmpx = 0, tmpy = 0, x1 = 0, y1 = 0;

    nullpo_ret(src);

    if (src->type == BL_PC)
    {
        nullpo_ret(sd = (struct map_session_data *) src);
    }

    if (skillnotok(skillid, sd))   // [MouseJstr]
        return 0;

    switch (skillid)
    {
        case PR_BENEDICTIO:    /* 聖体降福 */
            skill_area_temp_id = src->id;
            map_foreachinarea(std::bind(skill_area_sub, ph::_1, src, skillid, skilllv, tick, flag | BCT_NOENEMY | BCT_lo_x01, skill_castend_nodamage_id),
                               src->m, x - 1, y - 1, x + 1, y + 1, BL_NUL);
            map_foreachinarea(std::bind(skill_area_sub, ph::_1, src, skillid, skilllv, tick, flag | BCT_ENEMY | BCT_lo_x01, skill_castend_damage_id),
                    src->m, x - 1, y - 1,
                    x + 1, y + 1, BL_NUL);
            break;

        case BS_HAMMERFALL:    /* ハンマーフォール */
            skill_area_temp_id = src->id;
            skill_area_temp_x = x;
            skill_area_temp_y = y;
            map_foreachinarea(std::bind(skill_area_sub, ph::_1, src, skillid, skilllv, tick, flag | BCT_ENEMY | BCT_lo_x02, skill_castend_nodamage_id),
                               src->m, x - 2, y - 2, x + 2, y + 2, BL_NUL);
            break;

        case HT_DETECTING:     /* ディテクティング */
        {
            const int range = 7;
            map_foreachinarea(std::bind(skill_status_change_timer_sub, ph::_1, src, SC_SIGHT, tick),
                    src->m, src->x - range, src->y - range,
                    src->x + range, src->y + range, BL_NUL);
        }
            break;

        case MG_SAFETYWALL:    /* セイフティウォール */
        case MG_FIREWALL:      /* ファイヤーウォール */
        case MG_THUNDERSTORM:  /* サンダーストーム */
        case AL_PNEUMA:        /* ニューマ */
        case WZ_ICEWALL:       /* アイスウォール */
        case WZ_FIREPILLAR:    /* ファイアピラー */
        case WZ_SIGHTRASHER:
        case WZ_QUAGMIRE:      /* クァグマイア */
        case WZ_VERMILION:     /* ロードオブヴァーミリオン */
        case WZ_FROSTNOVA:     /* フロストノヴァ */
        case WZ_STORMGUST:     /* ストームガスト */
        case WZ_HEAVENDRIVE:   /* ヘヴンズドライブ */
        case PR_SANCTUARY:     /* サンクチュアリ */
        case PR_MAGNUS:        /* マグヌスエクソシズム */
        case CR_GRANDCROSS:    /* グランドクロス */
        case HT_SKIDTRAP:      /* スキッドトラップ */
        case HT_LANDMINE:      /* ランドマイン */
        case HT_ANKLESNARE:    /* アンクルスネア */
        case HT_SHOCKWAVE:     /* ショックウェーブトラップ */
        case HT_SANDMAN:       /* サンドマン */
        case HT_FLASHER:       /* フラッシャー */
        case HT_FREEZINGTRAP:  /* フリージングトラップ */
        case HT_BLASTMINE:     /* ブラストマイン */
        case HT_CLAYMORETRAP:  /* クレイモアートラップ */
        case AS_VENOMDUST:     /* ベノムダスト */
        case AM_DEMONSTRATION: /* デモンストレーション */
        case PF_SPIDERWEB:     /* スパイダーウェッブ */
        case PF_FOGWALL:       /* フォグウォール */
        case HT_TALKIEBOX:     /* トーキーボックス */
            skill_unitsetting(src, skillid, skilllv, x, y, 0);
            break;

        case RG_GRAFFITI:      /* Graffiti [Valaris] */
            skill_clear_unitgroup(src);
            skill_unitsetting(src, skillid, skilllv, x, y, 0);
            break;

        case SA_VOLCANO:       /* ボルケーノ */
        case SA_DELUGE:        /* デリュージ */
        case SA_VIOLENTGALE:   /* バイオレントゲイル */
        case SA_LANDPROTECTOR: /* ランドプロテクター */
            skill_clear_element_field(src);    //既に自分が発動している属性場をクリア
            skill_unitsetting(src, skillid, skilllv, x, y, 0);
            break;

        case WZ_METEOR:        //メテオストーム
        {
            BCT flag_ = BCT_ZERO;
            for (i = 0; i < 2 + (skilllv >> 1); i++)
            {
                int j = 0, c;
                do
                {
                    tmpx = x + (MRAND(7) - 3);
                    tmpy = y + (MRAND(7) - 3);
                    if (tmpx < 0)
                        tmpx = 0;
                    else if (tmpx >= map[src->m].xs)
                        tmpx = map[src->m].xs - 1;
                    if (tmpy < 0)
                        tmpy = 0;
                    else if (tmpy >= map[src->m].ys)
                        tmpy = map[src->m].ys - 1;
                    j++;
                }
                while (((c = map_getcell(src->m, tmpx, tmpy)) == 1 || c == 5)
                       && j < 100);
                if (j >= 100)
                    continue;
                if (flag_ == BCT_ZERO)
                    flag_ = BCT_lo_x01;
                if (i > 0)
                    skill_addtimerskill(src, tick + i * 1000, 0, tmpx, tmpy,
                                         skillid, skilllv, skill_timerskill::sktst::from_xy(uint16_t(x1), uint16_t(y1)),
                                         flag_);
                x1 = tmpx;
                y1 = tmpy;
            }
            skill_addtimerskill(src, tick + i * 1000, 0, tmpx, tmpy, skillid,
                                 skilllv, skill_timerskill::sktst::from_n(-1), flag_);
        }
            break;

        case AL_WARP:          /* ワープポータル */
            break;
        case MO_BODYRELOCATION:
            if (sd)
            {
                pc_movepos(sd, x, y);
            }
            else if (src->type == BL_MOB)
                mob_warp((struct mob_data *) src, -1, x, y, 0);
            break;
        case AM_CANNIBALIZE:   // バイオプラント
            if (sd)
            {
                int mx, my, id = 0;
                struct mob_data *md;

                mx = x;         // + (rand()%10 - 5);
                my = y;         // + (rand()%10 - 5);
                id = mob_once_spawn(sd, "this", mx, my, "--ja--", 1118, 1,
                                     "");
                if ((md = (struct mob_data *) map_id2bl(id)) != NULL)
                {
                    md->master_id = sd->bl.id;
                    md->hp = 2210 + skilllv * 200;
                    md->state.special_mob_ai = 1;
                    md->deletetimer =
                        add_timer(gettick() +
                                   skill_get_time(skillid, skilllv),
                                   mob_timer_delete, id, 0);
                }
            }
            break;
        case AM_SPHEREMINE:    // スフィアーマイン
            if (sd)
            {
                int mx, my, id = 0;
                struct mob_data *md;

                mx = x;         // + (rand()%10 - 5);
                my = y;         // + (rand()%10 - 5);
                id = mob_once_spawn(sd, "this", mx, my, "--ja--", 1142, 1,
                                     "");
                if ((md = (struct mob_data *) map_id2bl(id)) != NULL)
                {
                    md->master_id = sd->bl.id;
                    md->hp = 1000 + skilllv * 200;
                    md->state.special_mob_ai = 2;
                    md->deletetimer =
                        add_timer(gettick() +
                                   skill_get_time(skillid, skilllv),
                                   mob_timer_delete, id, 0);
                }
            }
            break;
    }

    return 0;
}

/*==========================================
 * スキル使用(詠唱完了、map指定)
 *------------------------------------------
 */
int skill_castend_map(struct map_session_data *sd, SkillID skill_num,
                       const char *mapname)
{
    int x = 0, y = 0;

    nullpo_ret(sd);
    if (sd->bl.prev == NULL || pc_isdead(sd))
        return 0;

    if (bool(sd->opt1)
        || bool(sd->status.option & Option::HIDE2))
        return 0;

    if (sd->sc_data[SC_DIVINA].timer != -1
        || sd->sc_data[SC_ROKISWEIL].timer != -1
        || sd->sc_data[SC_AUTOCOUNTER].timer != -1
        || sd->sc_data[SC_STEELBODY].timer != -1
        || sd->sc_data[SC_DANCING].timer != -1
        || sd->sc_data[SC_BERSERK].timer != -1)
        return 0;

    if (skill_num != sd->skillid)   /* 不正パケットらしい */
        return 0;

    pc_stopattack(sd);

    if (battle_config.pc_skill_log)
        printf("PC %d skill castend skill =%d map=%s\n",
                sd->bl.id, uint16_t(skill_num), mapname);
    pc_stop_walking(sd, 0);

    if (strcmp(mapname, "cancel") == 0)
        return 0;

    switch (skill_num)
    {
        case AL_TELEPORT:      /* テレポート */
            if (strcmp(mapname, "Random") == 0)
                pc_randomwarp(sd, 3);
            else
                pc_setpos(sd, sd->status.save_point.map,
                           sd->status.save_point.x, sd->status.save_point.y,
                           3);
            break;

        case AL_WARP:          /* ワープポータル */
        {
            const struct point *p[] = {
                &sd->status.save_point, &sd->status.memo_point[0],
                &sd->status.memo_point[1], &sd->status.memo_point[2],
            };
            struct skill_unit_group *group;
            int i;
            int maxcount = 0;

            if ((maxcount = skill_get_maxcount(sd->skillid)) > 0)
            {
                int c;
                for (i = c = 0; i < MAX_SKILLUNITGROUP; i++)
                {
                    if (sd->skillunit[i].alive_count > 0
                        && sd->skillunit[i].skill_id == sd->skillid)
                        c++;
                }
                if (c >= maxcount)
                {
                    clif_skill_fail(sd, sd->skillid, 0, 0);
                    sd->canact_tick = gettick();
                    sd->canmove_tick = gettick();
                    sd->skillitem = SkillID::NEGATIVE;
                    sd->skillitemlv = -1;
                    return 0;
                }
            }

            for (i = 0; i < sd->skilllv; i++)
            {
                if (strcmp(mapname, p[i]->map) == 0)
                {
                    x = p[i]->x;
                    y = p[i]->y;
                    break;
                }
            }
            if (x == 0 || y == 0)   /* 不正パケット? */
                return 0;

            if (!skill_check_condition(sd, 3))
                return 0;
            if ((group =
                 skill_unitsetting(&sd->bl, sd->skillid, sd->skilllv,
                                    sd->skillx, sd->skilly, 0)) == NULL)
                return 0;
            CREATE(group->valstr, char, 24);
            memcpy(group->valstr, map, 24);
            group->val2 = (x << 16) | y;
        }
            break;
    }

    return 0;
}

/*==========================================
 * スキルユニット設定処理
 *------------------------------------------
 */
struct skill_unit_group *skill_unitsetting(struct block_list *src,
        SkillID skillid, int skilllv,
        int x, int y, int flag)
{
    struct skill_unit_group *group;
    int i, count = 1, limit_ = 10000, val1_ = 0, val2_ = 0;
    BCT target = BCT_ENEMY;
    int interval = 1000, range_ = 0;
    int dir = 0, aoe_diameter = 0; // -- aoe_diameter (moonsoul) added for sage Area Of Effect skills

    nullpo_ret(src);

    switch (skillid)
    {                           /* 設定 */

        case MG_SAFETYWALL:    /* セイフティウォール */
            limit_ = skill_get_time(skillid, skilllv);
            val2_ = skilllv + 1;
            interval = -1;
            target = (battle_config.defnotenemy) ? BCT_NOENEMY : BCT_ALL;
            break;

        case MG_FIREWALL:      /* ファイヤーウォール */
            if (src->x == x && src->y == y)
                dir = 2;
            else
                dir = map_calc_dir(src, x, y);
            if (dir & 1)
                count = 5;
            else
                count = 3;
            limit_ = skill_get_time(skillid, skilllv);
            val2_ = 4 + skilllv;
            interval = 1;
            break;

        case AL_PNEUMA:        /* ニューマ */
            limit_ = skill_get_time(skillid, skilllv);
            interval = -1;
            target = (battle_config.defnotenemy) ? BCT_NOENEMY : BCT_ALL;
            count = 9;
            break;

        case AL_WARP:          /* ワープポータル */
            target = BCT_ALL;
            val1_ = skilllv + 6;
            if (flag == 0)
                limit_ = 2000;
            else
                limit_ = skill_get_time(skillid, skilllv);
            break;

        case PR_SANCTUARY:     /* サンクチュアリ */
            count = 21;
            limit_ = skill_get_time(skillid, skilllv);
            val1_ = skilllv + 3;
            val2_ = (skilllv > 6) ? 777 : skilllv * 100;
            target = BCT_ALL;
            range_ = 1;
            break;

        case PR_MAGNUS:        /* マグヌスエクソシズム */
            count = 33;
            limit_ = skill_get_time(skillid, skilllv);
            interval = 3000;
            break;

        case WZ_FIREPILLAR:    /* ファイアーピラー */
            if (flag == 0)
                limit_ = skill_get_time(skillid, skilllv);
            else
                limit_ = 1000;
            interval = 2000;
            val1_ = skilllv + 2;
            range_ = 1;
            break;

        case MG_THUNDERSTORM:  /* サンダーストーム */
            limit_ = 500;
            range_ = 1;
            break;

        case WZ_FROSTNOVA:     /* フロストノヴァ */
            limit_ = 500;
            range_ = 5;
            break;
        case WZ_HEAVENDRIVE:   /* ヘヴンズドライブ */
            limit_ = 500;
            range_ = 2;
            break;

        case WZ_METEOR:        /* メテオストーム */
            limit_ = 500;
            range_ = 3;
            break;

        case WZ_SIGHTRASHER:
            limit_ = 500;
            count = 41;
            break;

        case WZ_VERMILION:     /* ロードオブヴァーミリオン */
            limit_ = 4100;
            interval = 1000;
            range_ = 6;
            break;

        case WZ_ICEWALL:       /* アイスウォール */
            limit_ = skill_get_time(skillid, skilllv);
            count = 5;
            break;

        case WZ_STORMGUST:     /* ストームガスト */
            limit_ = 4600;
            interval = 450;
            range_ = 5;
            break;

        case WZ_QUAGMIRE:      /* クァグマイア */
            limit_ = skill_get_time(skillid, skilllv);
            interval = 200;
            count = 25;
            break;

        case HT_SKIDTRAP:      /* スキッドトラップ */
        case HT_LANDMINE:      /* ランドマイン */
        case HT_ANKLESNARE:    /* アンクルスネア */
        case HT_SANDMAN:       /* サンドマン */
        case PF_SPIDERWEB:     /* スパイダーウェッブ */
        case HT_FLASHER:       /* フラッシャー */
        case HT_FREEZINGTRAP:  /* フリージングトラップ */
        case HT_BLASTMINE:     /* ブラストマイン */
        case HT_CLAYMORETRAP:  /* クレイモアートラップ */
            limit_ = skill_get_time(skillid, skilllv);
            range_ = 1;
            break;

        case HT_TALKIEBOX:     /* トーキーボックス */
            limit_ = skill_get_time(skillid, skilllv);
            range_ = 1;
            target = BCT_ALL;
            break;

        case HT_SHOCKWAVE:     /* ショックウェーブトラップ */
            limit_ = skill_get_time(skillid, skilllv);
            range_ = 1;
            val1_ = skilllv * 15 + 10;
            break;

        case AS_VENOMDUST:     /* ベノムダスト */
            limit_ = skill_get_time(skillid, skilllv);
            interval = 1000;
            count = 5;
            break;

        case CR_GRANDCROSS:    /* グランドクロス */
            count = 29;
            limit_ = 1000;
            interval = 300;
            break;

        case SA_VOLCANO:       /* ボルケーノ */
        case SA_DELUGE:        /* デリュージ */
        case SA_VIOLENTGALE:   /* バイオレントゲイル */
            limit_ = skill_get_time(skillid, skilllv);
            count = skilllv <= 2 ? 25 : (skilllv <= 4 ? 49 : 81);
            target = BCT_ALL;
            break;

        case SA_LANDPROTECTOR: /* グランドクロス */
            limit_ = skill_get_time(skillid, skilllv);  // changed to get duration from cast_db (moonsoul)
            val1_ = skilllv * 15 + 10;
            aoe_diameter = skilllv + skilllv % 2 + 5;
            target = BCT_ALL;
            count = aoe_diameter * aoe_diameter;    // -- this will not function if changed to ^2 (moonsoul)
            break;

        case BD_LULLABY:       /* 子守唄 */
        case BD_ETERNALCHAOS:  /* エターナルカオス */
        case BD_ROKISWEIL:     /* ロキの叫び */
            count = 81;
            limit_ = skill_get_time(skillid, skilllv);
            range_ = 5;
            target = BCT_ALL;
            break;
        case BD_RICHMANKIM:
        case BD_DRUMBATTLEFIELD:   /* 戦太鼓の響き */
        case BD_RINGNIBELUNGEN:    /* ニーベルングの指輪 */
        case BD_INTOABYSS:     /* 深淵の中に */
        case BD_SIEGFRIED:     /* 不死身のジークフリード */
            count = 81;
            limit_ = skill_get_time(skillid, skilllv);
            range_ = 5;
            target = BCT_PARTY;
            break;

        case BA_WHISTLE:       /* 口笛 */
            count = 49;
            limit_ = skill_get_time(skillid, skilllv);
            range_ = 5;
            target = BCT_NOENEMY;
            if (src->type == BL_PC)
                val1_ =
                    (pc_checkskill((struct map_session_data *) src,
                      BA_MUSICALLESSON) + 1) >> 1;
            val2_ = ((battle_get_agi(src) / 10) & 0xffff) << 16;
            val2_ |= (battle_get_luk(src) / 10) & 0xffff;
            break;
        case DC_HUMMING:       /* ハミング */
            count = 49;
            limit_ = skill_get_time(skillid, skilllv);
            range_ = 5;
            target = BCT_NOENEMY;
            if (src->type == BL_PC)
                val1_ =
                    (pc_checkskill((struct map_session_data *) src,
                      DC_DANCINGLESSON) + 1) >> 1;
            val2_ = battle_get_dex(src) / 10;
            break;

        case BA_DISSONANCE:    /* 不協和音 */
        case DC_UGLYDANCE:     /* 自分勝手なダンス */
            count = 49;
            limit_ = skill_get_time(skillid, skilllv);
            range_ = 5;
            target = BCT_ENEMY;
            break;

        case DC_DONTFORGETME:  /* 私を忘れないで… */
            count = 49;
            limit_ = skill_get_time(skillid, skilllv);
            range_ = 5;
            target = BCT_ENEMY;
            if (src->type == BL_PC)
                val1_ =
                    (pc_checkskill((struct map_session_data *) src,
                      DC_DANCINGLESSON) + 1) >> 1;
            val2_ = ((battle_get_str(src) / 20) & 0xffff) << 16;
            val2_ |= (battle_get_agi(src) / 10) & 0xffff;
            break;
        case BA_POEMBRAGI:     /* ブラギの詩 */
            count = 49;
            limit_ = skill_get_time(skillid, skilllv);
            range_ = 5;
            target = BCT_NOENEMY;
            if (src->type == BL_PC)
                val1_ =
                    pc_checkskill((struct map_session_data *) src,
                                   BA_MUSICALLESSON);
            val2_ = ((battle_get_dex(src) / 10) & 0xffff) << 16;
            val2_ |= (battle_get_int(src) / 5) & 0xffff;
            break;
        case BA_APPLEIDUN:     /* イドゥンの林檎 */
            count = 49;
            limit_ = skill_get_time(skillid, skilllv);
            range_ = 5;
            target = BCT_NOENEMY;
            if (src->type == BL_PC)
                val1_ =
                    ((pc_checkskill((struct map_session_data *) src,
                       BA_MUSICALLESSON)) & 0xffff) << 16;
            else
                val1_ = 0;
            val1_ |= (battle_get_vit(src)) & 0xffff;
            val2_ = 0;           //回復用タイムカウンタ(6秒毎に1増加)
            break;
        case DC_SERVICEFORYOU: /* サービスフォーユー */
            count = 49;
            limit_ = skill_get_time(skillid, skilllv);
            range_ = 5;
            target = BCT_PARTY;
            if (src->type == BL_PC)
                val1_ =
                    (pc_checkskill((struct map_session_data *) src,
                      DC_DANCINGLESSON) + 1) >> 1;
            val2_ = battle_get_int(src) / 10;
            break;
        case BA_ASSASSINCROSS: /* 夕陽のアサシンクロス */
            count = 49;
            limit_ = skill_get_time(skillid, skilllv);
            range_ = 5;
            target = BCT_NOENEMY;
            if (src->type == BL_PC)
                val1_ =
                    (pc_checkskill((struct map_session_data *) src,
                      BA_MUSICALLESSON) + 1) >> 1;
            val2_ = battle_get_agi(src) / 20;
            break;
        case DC_FORTUNEKISS:   /* 幸運のキス */
            count = 49;
            limit_ = skill_get_time(skillid, skilllv);
            range_ = 5;
            target = BCT_NOENEMY;
            if (src->type == BL_PC)
                val1_ =
                    (pc_checkskill((struct map_session_data *) src,
                      DC_DANCINGLESSON) + 1) >> 1;
            val2_ = battle_get_luk(src) / 10;
            break;
        case AM_DEMONSTRATION: /* デモンストレーション */
            limit_ = skill_get_time(skillid, skilllv);
            interval = 1000;
            range_ = 1;
            target = BCT_ENEMY;
            break;
        case WE_CALLPARTNER:   /* あなたに逢いたい */
            limit_ = skill_get_time(skillid, skilllv);
            range_ = -1;
            break;

        case HP_BASILICA:      /* バジリカ */
            limit_ = skill_get_time(skillid, skilllv);
            target = BCT_ALL;
            range_ = 3;
            //Fix to prevent the priest from walking while Basilica is up.
            battle_stopwalking(src, 1);
            skill_status_change_start(src, SC_ANKLE, skilllv, 0, 0, 0, limit_,
                                       0);
            break;
        case PA_GOSPEL:        /* ゴスペル */
            count = 49;
            target = BCT_PARTY;
            limit_ = skill_get_time(skillid, skilllv);
            break;
        case PF_FOGWALL:       /* フォグウォール */
            count = 15;
            limit_ = skill_get_time(skillid, skilllv);
            break;
        case RG_GRAFFITI:      /* Graffiti */
            count = 1;          // Leave this at 1 [Valaris]
            limit_ = 600000;     // Time length [Valaris]
            break;
    };

    nullpo_retr(NULL, group =
                 skill_initunitgroup(src, count, skillid, skilllv,
                                      skill_get_unit_id(skillid, flag & 1)));
    group->limit = limit_;
    group->val1 = val1_;
    group->val2 = val2_;
    group->target_flag = target;
    group->interval = interval;
    group->range = range_;
    if (skillid == HT_TALKIEBOX || skillid == RG_GRAFFITI)
    {
        CREATE(group->valstr, char, 80);
        memcpy(group->valstr, talkie_mes, 80);
    }
    for (i = 0; i < count; i++)
    {
        struct skill_unit *unit;
        int ux = x, uy = y, val1 = skilllv, val2 = 0, limit =
            group->limit, alive = 1;
        int range = group->range;
        switch (skillid)
        {                       /* 設定 */
            case AL_PNEUMA:    /* ニューマ */
            {
                static const int dx[9] = { -1, 0, 1, -1, 0, 1, -1, 0, 1 };
                static const int dy[9] = { -1, -1, -1, 0, 0, 0, 1, 1, 1 };
                ux += dx[i];
                uy += dy[i];
            }
                break;
            case MG_FIREWALL:  /* ファイヤーウォール */
            {
                if (dir & 1)
                {               /* 斜め配置 */
                    static const int dx[][5] = {
                        {1, 1, 0, 0, -1}, {-1, -1, 0, 0, 1},
                    }, dy[][5] =
                    {
                        {
                        1, 0, 0, -1, -1},
                        {
                    1, 0, 0, -1, -1},};
                    ux += dx[(dir >> 1) & 1][i];
                    uy += dy[(dir >> 1) & 1][i];
                }
                else
                {               /* 上下配置 */
                    if (dir % 4 == 0)   /* 上下 */
                        ux += i - 1;
                    else        /* 左右 */
                        uy += i - 1;
                }
                val2 = group->val2;
            }
                break;

            case PR_SANCTUARY: /* サンクチュアリ */
            {
                static const int dx[] = {
                    -1, 0, 1, -2, -1, 0, 1, 2, -2, -1, 0, 1, 2, -2, -1, 0, 1,
                    2, -1, 0, 1
                };
                static const int dy[] = {
                    -2, -2, -2, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 1, 1, 1, 1,
                    1, 2, 2, 2,
                };
                ux += dx[i];
                uy += dy[i];
            }
                break;

            case PR_MAGNUS:    /* マグヌスエクソシズム */
            {
                static const int dx[] =
                    { -1, 0, 1, -1, 0, 1, -3, -2, -1, 0, 1, 2, 3,
                    -3, -2, -1, 0, 1, 2, 3, -3, -2, -1, 0, 1, 2, 3, -1, 0, 1,
                    -1, 0, 1,
                };
                static const int dy[] = {
                    -3, -3, -3, -2, -2, -2, -1, -1, -1, -1, -1, -1, -1,
                    0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3
                };
                ux += dx[i];
                uy += dy[i];
            }
                break;

            case WZ_SIGHTRASHER:
            {
                static const int dx[] = {
                    -5, 0, 5, -4, 0, 4, -3, 0, 3, -2, 0, 2, -1, 0, 1, -5, -4,
                    -3, -2, -1, 0, 1, 2, 3, 4, 5, -1, 0, 1, -2, 0, 2, -3,
                    0, 3, -4, 0, 4, -5, 0, 5
                };
                static const int dy[] = {
                    -5, -5, -5, -4, -4, -4, -3, -3, -3, -2, -2, -2, -1, -1,
                    -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2,
                    3, 3, 3, 4, 4, 4, 5, 5, 5
                };
                ux += dx[i];
                uy += dy[i];
            }
                break;

            case WZ_ICEWALL:   /* アイスウォール */
            {
                if (skilllv <= 1)
                    val1 = 500;
                else
                    val1 = 200 + 200 * skilllv;
                if (src->x == x && src->y == y)
                    dir = 2;
                else
                    dir = map_calc_dir(src, x, y);
                ux += (2 - i) * diry[dir];
                uy += (i - 2) * dirx[dir];
            }
                break;

            case WZ_QUAGMIRE:  /* クァグマイア */
                ux += (i % 5 - 2);
                uy += (i / 5 - 2);
                if (i == 12)
                    range = 2;
                else
                    range = -1;

                break;

            case AS_VENOMDUST: /* ベノムダスト */
            {
                static const int dx[] = { -1, 0, 0, 0, 1 };
                static const int dy[] = { 0, -1, 0, 1, 0 };
                ux += dx[i];
                uy += dy[i];
            }
                break;

            case CR_GRANDCROSS:    /* グランドクロス */
            {
                static const int dx[] = {
                    0, 0, -1, 0, 1, -2, -1, 0, 1, 2, -4, -3, -2, -1, 0, 1, 2,
                    3, 4, -2, -1, 0, 1, 2, -1, 0, 1, 0, 0,
                };
                static const int dy[] = {
                    -4, -3, -2, -2, -2, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 3, 4,
                };
                ux += dx[i];
                uy += dy[i];
            }
                break;
            case SA_VOLCANO:   /* ボルケーノ */
            case SA_DELUGE:    /* デリュージ */
            case SA_VIOLENTGALE:   /* バイオレントゲイル */
            {
                int u_range = 0, central = 0;
                if (skilllv <= 2)
                {
                    u_range = 2;
                    central = 12;
                }
                else if (skilllv <= 4)
                {
                    u_range = 3;
                    central = 24;
                }
                else if (skilllv >= 5)
                {
                    u_range = 4;
                    central = 40;
                }
                ux += (i % (u_range * 2 + 1) - u_range);
                uy += (i / (u_range * 2 + 1) - u_range);

                if (i == central)
                    range = u_range;    //中央のユニットの効果範囲は全範囲
                else
                    range = -1; //中央以外のユニットは飾り
            }
                break;
            case SA_LANDPROTECTOR: /* ランドプロテクター */
            {
                int u_range = 0;

                if (skilllv <= 2)
                    u_range = 3;
                else if (skilllv <= 4)
                    u_range = 4;
                else if (skilllv >= 5)
                    u_range = 5;

                ux += (i % (u_range * 2 + 1) - u_range);
                uy += (i / (u_range * 2 + 1) - u_range);

                range = 0;
            }
                break;

                /* ダンスなど */
            case BD_LULLABY:   /* 子守歌 */
            case BD_RICHMANKIM:    /* ニヨルドの宴 */
            case BD_ETERNALCHAOS:  /* 永遠の混沌 */
            case BD_DRUMBATTLEFIELD:   /* 戦太鼓の響き */
            case BD_RINGNIBELUNGEN:    /* ニーベルングの指輪 */
            case BD_ROKISWEIL: /* ロキの叫び */
            case BD_INTOABYSS: /* 深淵の中に */
            case BD_SIEGFRIED: /* 不死身のジークフリード */
                ux += (i % 9 - 4);
                uy += (i / 9 - 4);
                if (i == 40)
                    range = 4;  /* 中心の場合は範囲を4にオーバーライド */
                else
                    range = -1; /* 中心じゃない場合は範囲を-1にオーバーライド */
                break;
            case BA_DISSONANCE:    /* 不協和音 */
            case BA_WHISTLE:   /* 口笛 */
            case BA_ASSASSINCROSS: /* 夕陽のアサシンクロス */
            case BA_POEMBRAGI: /* ブラギの詩 */
            case BA_APPLEIDUN: /* イドゥンの林檎 */
            case DC_UGLYDANCE: /* 自分勝手なダンス */
            case DC_HUMMING:   /* ハミング */
            case DC_DONTFORGETME:  /* 私を忘れないで… */
            case DC_FORTUNEKISS:   /* 幸運のキス */
            case DC_SERVICEFORYOU: /* サービスフォーユー */
                ux += (i % 7 - 3);
                uy += (i / 7 - 3);
                if (i == 40)
                    range = 4;  /* 中心の場合は範囲を4にオーバーライド */
                else
                    range = -1; /* 中心じゃない場合は範囲を-1にオーバーライド */
                break;
            case PA_GOSPEL:    /* ゴスペル */
                ux += (i % 7 - 3);
                uy += (i / 7 - 3);
                break;
            case PF_FOGWALL:   /* フォグウォール */
                ux += (i % 5 - 2);
                uy += (i / 5 - 1);
                break;
            case RG_GRAFFITI:  /* Graffiti [Valaris] */
                ux += (i % 5 - 2);
                uy += (i / 5 - 2);
                break;
        }
        //直上スキルの場合設置座標上にランドプロテクターがないかチェック
        if (range <= 0)
            map_foreachinarea(std::bind(skill_landprotector, ph::_1, skillid, &alive),
                    src->m, ux, uy,
                    ux, uy, BL_SKILL);

        if (skillid == WZ_ICEWALL && alive)
        {
            val2 = map_getcell(src->m, ux, uy);
            if (val2 == 5 || val2 == 1)
                alive = 0;
            else
            {
                map_setcell(src->m, ux, uy, 5);
            }
        }

        if (alive)
        {
            nullpo_retr(NULL, unit = skill_initunit(group, i, ux, uy));
            unit->val1 = val1;
            unit->val2 = val2;
            unit->limit = limit;
            unit->range = range;
        }
    }
    return group;
}

/*==========================================
 * スキルユニットの発動イベント
 *------------------------------------------
 */
static
int skill_unit_onplace(struct skill_unit *src, struct block_list *bl,
                        unsigned int tick)
{
    struct skill_unit_group *sg;
    struct block_list *ss;
    struct skill_unit_group_tickset *ts;
    struct map_session_data *srcsd = NULL;
    int diff, goflag, splash_count = 0;

    nullpo_ret(src);
    nullpo_ret(bl);

    if (bl->prev == NULL || !src->alive
        || (bl->type == BL_PC && pc_isdead((struct map_session_data *) bl)))
        return 0;

    nullpo_ret(sg = src->group);
    nullpo_ret(ss = map_id2bl(sg->src_id));

    if (ss->type == BL_PC)
        nullpo_ret(srcsd = (struct map_session_data *) ss);
    if (srcsd && srcsd->chatID)
        return 0;

    if (bl->type != BL_PC && bl->type != BL_MOB)
        return 0;
    nullpo_ret(ts = skill_unitgrouptickset_search(bl, sg->group_id));
    diff = DIFF_TICK(tick, ts->tick);
    goflag = (diff > sg->interval || diff < 0);
    if (sg->skill_id == CR_GRANDCROSS && !battle_config.gx_allhit)  // 重なっていたら3HITしない
        goflag = (diff > sg->interval * map_count_oncell(bl->m, bl->x, bl->y)
                  || diff < 0);

    //対象がLP上に居る場合は無効
    map_foreachinarea(std::bind(skill_landprotector, ph::_1, SkillID::ZERO, &goflag),
            bl->m, bl->x, bl->y,
            bl->x, bl->y, BL_SKILL);

    if (!goflag)
        return 0;
    ts->tick = tick;
    ts->group_id = sg->group_id;

    switch (sg->unit_id)
    {
        case 0x83:             /* サンクチュアリ */
        {
            int race = battle_get_race(bl);
            int damage_flag =
                (battle_check_undead(race, battle_get_elem_type(bl))
                 || race == 6) ? 1 : 0;

            if (battle_get_hp(bl) >= battle_get_max_hp(bl) && !damage_flag)
                break;

            if ((sg->val1--) <= 0)
            {
                skill_delunitgroup(sg);
                return 0;
            }
            if (!damage_flag)
            {
                int heal = sg->val2;
                if (bl->type == BL_PC
                    && ((struct map_session_data *) bl)->
                    special_state.no_magic_damage)
                    heal = 0;   /* 黄金蟲カード(ヒール量0) */
                battle_heal(NULL, bl, heal, 0, 0);
            }
            else
                skill_attack(BF_MAGIC, ss, &src->bl, bl, sg->skill_id,
                              sg->skill_lv, tick, BCT_ZERO);
        }
            break;

        case 0x84:             /* マグヌスエクソシズム */
        {
            int race = battle_get_race(bl);
            int damage_flag =
                (battle_check_undead(race, battle_get_elem_type(bl))
                 || race == 6) ? 1 : 0;

            if (!damage_flag)
                return 0;
            skill_attack(BF_MAGIC, ss, &src->bl, bl, sg->skill_id,
                          sg->skill_lv, tick, BCT_ZERO);
        }
            break;

        case 0x85:             /* ニューマ */
        {
            struct skill_unit *unit2;
            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);
            StatusChange type = SC_PNEUMA;
            if (sc_data && sc_data[type].timer == -1)
                skill_status_change_start(bl, type, sg->skill_lv, (int) src,
                                           0, 0, 0, 0);
            else if ((unit2 = (struct skill_unit *) sc_data[type].val2)
                     && unit2 != src)
            {
                if (DIFF_TICK(sg->tick, unit2->group->tick) > 0)
                    skill_status_change_start(bl, type, sg->skill_lv,
                                               (int) src, 0, 0, 0, 0);
                ts->tick -= sg->interval;
            }
        }
            break;
        case 0x7e:             /* セイフティウォール */
        {
            struct skill_unit *unit2;
            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);
            StatusChange type = SC_SAFETYWALL;
            if (sc_data && sc_data[type].timer == -1)
                skill_status_change_start(bl, type, sg->skill_lv, (int) src,
                                           0, 0, 0, 0);
            else if ((unit2 = (struct skill_unit *) sc_data[type].val2)
                     && unit2 != src)
            {
                if (sg->val1 < unit2->group->val1)
                    skill_status_change_start(bl, type, sg->skill_lv,
                                               (int) src, 0, 0, 0, 0);
                ts->tick -= sg->interval;
            }
        }
            break;

        case 0x86:             /* ロードオブヴァーミリオン(&ストームガスト &グランドクロス) */
            skill_attack(BF_MAGIC, ss, &src->bl, bl, sg->skill_id,
                          sg->skill_lv, tick, BCT_ZERO);
            break;

        case 0x7f:             /* ファイヤーウォール */
            if ((src->val2--) > 0)
                skill_attack(BF_MAGIC, ss, &src->bl, bl,
                              sg->skill_id, sg->skill_lv, tick, BCT_ZERO);
            if (src->val2 <= 0)
                skill_delunit(src);
            break;

        case 0x87:             /* ファイアーピラー(発動前) */
            skill_delunit(src);
            skill_unitsetting(ss, sg->skill_id, sg->skill_lv, src->bl.x,
                               src->bl.y, 1);
            break;

        case 0x88:             /* ファイアーピラー(発動後) */
            if (DIFF_TICK(tick, sg->tick) < 150)
                skill_attack(BF_MAGIC, ss, &src->bl, bl, sg->skill_id,
                              sg->skill_lv, tick, BCT_ZERO);
            break;

        case 0x90:             /* スキッドトラップ */
        {
            int i, c = skill_get_blewcount(sg->skill_id, sg->skill_lv);
            for (i = 0; i < c; i++)
                skill_blown(&src->bl, bl, 1 | 0x30000);
            sg->unit_id = 0x8c;
            clif_changelook(&src->bl, LOOK_BASE, sg->unit_id);
            sg->limit = DIFF_TICK(tick, sg->tick) + 1500;
        }
            break;

        case 0x93:             /* ランドマイン */
            skill_attack(BF_MISC, ss, &src->bl, bl, sg->skill_id,
                          sg->skill_lv, tick, BCT_ZERO);
            sg->unit_id = 0x8c;
            clif_changelook(&src->bl, LOOK_BASE, 0x88);
            sg->limit = DIFF_TICK(tick, sg->tick) + 1500;
            break;

        case 0x8f:             /* ブラストマイン */
        case 0x94:             /* ショックウェーブトラップ */
        case 0x95:             /* サンドマン */
        case 0x96:             /* フラッシャー */
        case 0x97:             /* フリージングトラップ */
        case 0x98:             /* クレイモアートラップ */
            map_foreachinarea(std::bind(skill_count_target, ph::_1,  &src->bl, &splash_count),
                    src->bl.m, src->bl.x - src->range, src->bl.y - src->range,
                    src->bl.x + src->range, src->bl.y + src->range, BL_NUL);
            map_foreachinarea(std::bind(skill_trap_splash, ph::_1, &src->bl, tick, splash_count),
                    src->bl.m, src->bl.x - src->range, src->bl.y - src->range,
                    src->bl.x + src->range, src->bl.y + src->range, BL_NUL);
            sg->unit_id = 0x8c;
            clif_changelook(&src->bl, LOOK_BASE, sg->unit_id);
            sg->limit = DIFF_TICK(tick, sg->tick) + 1500;
            break;

        case 0x91:             /* アンクルスネア */
        {
            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);
            if (sg->val2 == 0 && sc_data && sc_data[SC_ANKLE].timer == -1)
            {
                int moveblock = (bl->x / BLOCK_SIZE != src->bl.x / BLOCK_SIZE
                                  || bl->y / BLOCK_SIZE !=
                                  src->bl.y / BLOCK_SIZE);
                int sec = skill_get_time2(sg->skill_id,
                                            sg->skill_lv) -
                    (double) battle_get_agi(bl) * 0.1;
                if (battle_get_mode(bl) & 0x20)
                    sec = sec / 5;
                battle_stopwalking(bl, 1);
                skill_status_change_start(bl, SC_ANKLE, sg->skill_lv, 0, 0,
                                           0, sec, 0);

                if (moveblock)
                    map_delblock(bl);
                bl->x = src->bl.x;
                bl->y = src->bl.y;
                if (moveblock)
                    map_addblock(bl);
                if (bl->type == BL_MOB)
                    clif_fixmobpos((struct mob_data *) bl);
                else
                    clif_fixpos(bl);
                sg->limit = DIFF_TICK(tick, sg->tick) + sec;
                sg->val2 = bl->id;
            }
        }
            break;

        case 0x80:             /* ワープポータル(発動後) */
            if (bl->type == BL_PC)
            {
                struct map_session_data *sd = (struct map_session_data *) bl;
                if (sd && src->bl.m == bl->m && src->bl.x == bl->x
                    && src->bl.y == bl->y && src->bl.x == sd->to_x
                    && src->bl.y == sd->to_y)
                {
                    if (battle_config.chat_warpportal || !sd->chatID)
                    {
                        if ((sg->val1--) > 0)
                        {
                            pc_setpos(sd, sg->valstr, sg->val2 >> 16,
                                       sg->val2 & 0xffff, 3);
                            if (sg->src_id == bl->id
                                || (strcmp(map[src->bl.m].name, sg->valstr)
                                    == 0 && src->bl.x == (sg->val2 >> 16)
                                    && src->bl.y == (sg->val2 & 0xffff)))
                                skill_delunitgroup(sg);
                        }
                        else
                            skill_delunitgroup(sg);
                    }
                }
            }
            else if (bl->type == BL_MOB && battle_config.mob_warpportal)
            {
                int m = map_mapname2mapid(sg->valstr);
                mob_warp((struct mob_data *) bl, m, sg->val2 >> 16,
                          sg->val2 & 0xffff, 3);
            }
            break;

        case 0x8e:             /* クァグマイア */
        {
            StatusChange type = SkillStatusChangeTable[sg->skill_id];
            if (bl->type == BL_PC
                && ((struct map_session_data *) bl)->
                special_state.no_magic_damage)
                break;
            if (battle_get_sc_data(bl)[type].timer == -1)
                skill_status_change_start(bl, type, sg->skill_lv, (int) src,
                                           0, 0,
                                           skill_get_time2(sg->skill_id,
                                                            sg->skill_lv), 0);
        }
            break;
        case 0x92:             /* ベノムダスト */
        {
            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);
            StatusChange type = SkillStatusChangeTable[sg->skill_id];
            if (sc_data && sc_data[type].timer == -1)
                skill_status_change_start(bl, type, sg->skill_lv, (int) src,
                                           0, 0,
                                           skill_get_time2(sg->skill_id,
                                                            sg->skill_lv), 0);
        }
            break;
        case 0x9a:             /* ボルケーノ */
        case 0x9b:             /* デリュージ */
        case 0x9c:             /* バイオレントゲイル */
        {
            struct skill_unit *unit2;
            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);
            StatusChange type = SkillStatusChangeTable[sg->skill_id];
            if (sc_data && sc_data[type].timer == -1)
                skill_status_change_start(bl, type, sg->skill_lv, (int) src,
                                           0, 0,
                                           skill_get_time2(sg->skill_id,
                                                            sg->skill_lv), 0);
            else if ((unit2 = (struct skill_unit *) sc_data[type].val2)
                     && unit2 != src)
            {
                if (DIFF_TICK(sg->tick, unit2->group->tick) > 0)
                    skill_status_change_start(bl, type, sg->skill_lv,
                                               (int) src, 0, 0,
                                               skill_get_time2(sg->skill_id,
                                                                sg->skill_lv),
                                               0);
                ts->tick -= sg->interval;
            }
        } break;

        case 0x9e:             /* 子守唄 */
        case 0x9f:             /* ニヨルドの宴 */
        case 0xa0:             /* 永遠の混沌 */
        case 0xa1:             /* 戦太鼓の響き */
        case 0xa2:             /* ニーベルングの指輪 */
        case 0xa3:             /* ロキの叫び */
        case 0xa4:             /* 深淵の中に */
        case 0xa5:             /* 不死身のジークフリード */
        case 0xa6:             /* 不協和音 */
        case 0xa7:             /* 口笛 */
        case 0xa8:             /* 夕陽のアサシンクロス */
        case 0xa9:             /* ブラギの詩 */
        case 0xab:             /* 自分勝手なダンス */
        case 0xac:             /* ハミング */
        case 0xad:             /* 私を忘れないで… */
        case 0xae:             /* 幸運のキス */
        case 0xaf:             /* サービスフォーユー */
        case 0xb4:
        {
            struct skill_unit *unit2;
            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);
            StatusChange type = SkillStatusChangeTable[sg->skill_id];
            if (sg->src_id == bl->id)
                break;
            if (sc_data && sc_data[type].timer == -1)
                skill_status_change_start(bl, type, sg->skill_lv, sg->val1,
                                           sg->val2, (int) src,
                                           skill_get_time2(sg->skill_id,
                                                            sg->skill_lv), 0);
            else if ((unit2 = (struct skill_unit *) sc_data[type].val4)
                     && unit2 != src)
            {
                if (unit2->group
                    && DIFF_TICK(sg->tick, unit2->group->tick) > 0)
                    skill_status_change_start(bl, type, sg->skill_lv,
                                               sg->val1, sg->val2, (int) src,
                                               skill_get_time2(sg->skill_id,
                                                                sg->skill_lv),
                                               0);
                ts->tick -= sg->interval;
            }
        } break;

        case 0xaa:             /* イドゥンの林檎 */
        {
            struct skill_unit *unit2;
            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);
            StatusChange type = SkillStatusChangeTable[sg->skill_id];
            if (sg->src_id == bl->id)
                break;
            if (sc_data && sc_data[type].timer == -1)
                skill_status_change_start(bl, type, sg->skill_lv,
                                           (sg->val1) >> 16,
                                           (sg->val1) & 0xffff, (int) src,
                                           skill_get_time2(sg->skill_id,
                                                            sg->skill_lv), 0);
            else if ((unit2 = (struct skill_unit *) sc_data[type].val4)
                     && unit2 != src)
            {
                if (DIFF_TICK(sg->tick, unit2->group->tick) > 0)
                    skill_status_change_start(bl, type, sg->skill_lv,
                                               (sg->val1) >> 16,
                                               (sg->val1) & 0xffff, (int) src,
                                               skill_get_time2(sg->skill_id,
                                                                sg->skill_lv),
                                               0);
                ts->tick -= sg->interval;
            }
        } break;

        case 0xb1:             /* デモンストレーション */
            skill_attack(BF_WEAPON, ss, &src->bl, bl, sg->skill_id,
                          sg->skill_lv, tick, BCT_ZERO);
            if (bl->type == BL_PC && MRAND(100) < sg->skill_lv
                && battle_config.equipment_breaking)
                pc_breakweapon((struct map_session_data *) bl);
            break;
        case 0x99:             /* トーキーボックス */
            if (sg->src_id == bl->id)   //自分が踏んでも発動しない
                break;
            if (sg->val2 == 0)
            {
                sg->unit_id = 0x8c;
                clif_changelook(&src->bl, LOOK_BASE, sg->unit_id);
                sg->limit = DIFF_TICK(tick, sg->tick) + 5000;
                sg->val2 = -1;  //踏んだ
            }
            break;
        case 0xb2:             /* あなたを_会いたいです */
        case 0xb3:             /* ゴスペル */
        case 0xb6:             /* フォグウォール */
            //とりあえず何もしない
            break;

        case 0xb7:             /* スパイダーウェッブ */
            if (sg->val2 == 0)
            {
                int moveblock = (bl->x / BLOCK_SIZE != src->bl.x / BLOCK_SIZE
                                  || bl->y / BLOCK_SIZE !=
                                  src->bl.y / BLOCK_SIZE);
                skill_additional_effect(ss, bl, sg->skill_id, sg->skill_lv,
                                         BF_MISC, tick);
                if (moveblock)
                    map_delblock(bl);
                bl->x = (&src->bl)->x;
                bl->y = (&src->bl)->y;
                if (moveblock)
                    map_addblock(bl);
                if (bl->type == BL_MOB)
                    clif_fixmobpos((struct mob_data *) bl);
                else
                    clif_fixpos(bl);
                sg->limit =
                    DIFF_TICK(tick,
                               sg->tick) + skill_get_time2(sg->skill_id,
                                                            sg->skill_lv);
                sg->val2 = bl->id;
            }
            break;

/*      default:
                if (battle_config.error_log)
                        printf("skill_unit_onplace: Unknown skill unit id=%d block=%d\n",sg->unit_id,bl->id);
                break;*/
    }
    if (bl->type == BL_MOB && ss != bl) /* スキル使用条件のMOBスキル */
    {
        if (battle_config.mob_changetarget_byskill == 1)
        {
            int target = ((struct mob_data *) bl)->target_id;
            if (ss->type == BL_PC)
                ((struct mob_data *) bl)->target_id = ss->id;
            mobskill_use((struct mob_data *) bl, tick,
                          MSC_SKILLUSED, sg->skill_id);
            ((struct mob_data *) bl)->target_id = target;
        }
        else
            mobskill_use((struct mob_data *) bl, tick,
                          MSC_SKILLUSED, sg->skill_id);
    }

    return 0;
}

/*==========================================
 * スキルユニットから離脱する(もしくはしている)場合
 *------------------------------------------
 */
static
int skill_unit_onout(struct skill_unit *src, struct block_list *bl,
                      unsigned int tick)
{
    struct skill_unit_group *sg;

    nullpo_ret(src);
    nullpo_ret(bl);
    nullpo_ret(sg = src->group);

    if (bl->prev == NULL || !src->alive)
        return 0;

    if (bl->type != BL_PC && bl->type != BL_MOB)
        return 0;

    switch (sg->unit_id)
    {
        case 0x7e:             /* セイフティウォール */
        case 0x85:             /* ニューマ */
        case 0x8e:             /* クァグマイア */
        {
            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);
            StatusChange type =
                (sg->unit_id == 0x85) ? SC_PNEUMA :
                ((sg->unit_id == 0x7e) ? SC_SAFETYWALL : SC_QUAGMIRE);
            if ((type != SC_QUAGMIRE || bl->type != BL_MOB) &&
                sc_data && sc_data[type].timer != -1
                && ((struct skill_unit *) sc_data[type].val2) == src)
            {
                skill_status_change_end(bl, type, -1);
            }
        } break;

        case 0x91:             /* アンクルスネア */
        {
            struct block_list *target = map_id2bl(sg->val2);
            if (target && target == bl)
            {
                skill_status_change_end(bl, SC_ANKLE, -1);
                sg->limit = DIFF_TICK(tick, sg->tick) + 1000;
            }
        }
            break;
        case 0xb5:
        case 0xb8:
        {
            struct block_list *target = map_id2bl(sg->val2);
            if (target == bl)
                skill_status_change_end(bl, SC_SPIDERWEB, -1);
            sg->limit = DIFF_TICK(tick, sg->tick) + 1000;
        }
            break;
        case 0xb6:
        {
            struct block_list *target = map_id2bl(sg->val2);
            if (target == bl)
                skill_status_change_end(bl, SC_FOGWALL, -1);
            sg->limit = DIFF_TICK(tick, sg->tick) + 1000;
        }
            break;
        case 0x9a:             /* ボルケーノ */
        case 0x9b:             /* デリュージ */
        case 0x9c:             /* バイオレントゲイル */
        {
            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);
            struct skill_unit *su;
            StatusChange type = SkillStatusChangeTable[sg->skill_id];
            if (sc_data && sc_data[type].timer != -1
                && (su = ((struct skill_unit *) sc_data[type].val2))
                && su == src)
            {
                skill_status_change_end(bl, type, -1);
            }
        }
            break;

        case 0x9e:             /* 子守唄 */
        case 0x9f:             /* ニヨルドの宴 */
        case 0xa0:             /* 永遠の混沌 */
        case 0xa1:             /* 戦太鼓の響き */
        case 0xa2:             /* ニーベルングの指輪 */
        case 0xa3:             /* ロキの叫び */
        case 0xa4:             /* 深淵の中に */
        case 0xa5:             /* 不死身のジークフリード */
        case 0xa6:             /* 不協和音 */
        case 0xa7:             /* 口笛 */
        case 0xa8:             /* 夕陽のアサシンクロス */
        case 0xa9:             /* ブラギの詩 */
        case 0xaa:             /* イドゥンの林檎 */
        case 0xab:             /* 自分勝手なダンス */
        case 0xac:             /* ハミング */
        case 0xad:             /* 私を忘れないで… */
        case 0xae:             /* 幸運のキス */
        case 0xaf:             /* サービスフォーユー */
        case 0xb4:
        {
            eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);
            struct skill_unit *su;
            StatusChange type = SkillStatusChangeTable[sg->skill_id];
            if (sc_data && sc_data[type].timer != -1
                && (su = ((struct skill_unit *) sc_data[type].val4))
                && su == src)
            {
                skill_status_change_end(bl, type, -1);
            }
        }
            break;
        case 0xb7:             /* スパイダーウェッブ */
        {
            struct block_list *target = map_id2bl(sg->val2);
            if (target && target == bl)
                skill_status_change_end(bl, SC_SPIDERWEB, -1);
            sg->limit = DIFF_TICK(tick, sg->tick) + 1000;
        }
            break;

/*      default:
                if (battle_config.error_log)
                        printf("skill_unit_onout: Unknown skill unit id=%d block=%d\n",sg->unit_id,bl->id);
                break;*/
    }
    skill_unitgrouptickset_delete(bl, sg->group_id);
    return 0;
}

/*==========================================
 * スキルユニットの削除イベント
 *------------------------------------------
 */
static
int skill_unit_ondelete(struct skill_unit *src, struct block_list *bl,
                         unsigned int tick)
{
    struct skill_unit_group *sg;

    nullpo_ret(src);
    nullpo_ret(bl);
    nullpo_ret(sg = src->group);

    if (bl->prev == NULL || !src->alive)
        return 0;

    if (bl->type != BL_PC && bl->type != BL_MOB)
        return 0;

    switch (sg->unit_id)
    {
        case 0x85:             /* ニューマ */
        case 0x7e:             /* セイフティウォール */
        case 0x8e:             /* クァグマイヤ */
        case 0x9a:             /* ボルケーノ */
        case 0x9b:             /* デリュージ */
        case 0x9c:             /* バイオレントゲイル */
        case 0x9e:             /* 子守唄 */
        case 0x9f:             /* ニヨルドの宴 */
        case 0xa0:             /* 永遠の混沌 */
        case 0xa1:             /* 戦太鼓の響き */
        case 0xa2:             /* ニーベルングの指輪 */
        case 0xa3:             /* ロキの叫び */
        case 0xa4:             /* 深淵の中に */
        case 0xa5:             /* 不死身のジークフリード */
        case 0xa6:             /* 不協和音 */
        case 0xa7:             /* 口笛 */
        case 0xa8:             /* 夕陽のアサシンクロス */
        case 0xa9:             /* ブラギの詩 */
        case 0xaa:             /* イドゥンの林檎 */
        case 0xab:             /* 自分勝手なダンス */
        case 0xac:             /* ハミング */
        case 0xad:             /* 私を忘れないで… */
        case 0xae:             /* 幸運のキス */
        case 0xaf:             /* サービスフォーユー */
        case 0xb4:
            return skill_unit_onout(src, bl, tick);

/*      default:
                if (battle_config.error_log)
                        printf("skill_unit_ondelete: Unknown skill unit id=%d block=%d\n",sg->unit_id,bl->id);
                break;*/
    }
    skill_unitgrouptickset_delete(bl, sg->group_id);
    return 0;
}

/*==========================================
 * スキルユニットの限界イベント
 *------------------------------------------
 */
static
int skill_unit_onlimit(struct skill_unit *src, unsigned int)
{
    struct skill_unit_group *sg;

    nullpo_ret(src);
    nullpo_ret(sg = src->group);

    switch (sg->unit_id)
    {
        case 0x81:             /* ワープポータル(発動前) */
        {
            struct skill_unit_group *group =
                skill_unitsetting(map_id2bl(sg->src_id), sg->skill_id,
                                   sg->skill_lv,
                                   src->bl.x, src->bl.y, 1);
            if (group == NULL)
                return 0;
            CREATE(group->valstr, char, 24);
            memcpy(group->valstr, sg->valstr, 24);
            group->val2 = sg->val2;
        }
            break;

        case 0x8d:             /* アイスウォール */
            map_setcell(src->bl.m, src->bl.x, src->bl.y, src->val2);
            break;
        case 0xb2:             /* あなたに会いたい */
        {
            struct map_session_data *sd = NULL;
            struct map_session_data *p_sd = NULL;
            if ((sd =
                 (struct map_session_data *)(map_id2bl(sg->src_id))) ==
                NULL)
                return 0;
            if ((p_sd = pc_get_partner(sd)) == NULL)
                return 0;

            pc_setpos(p_sd, map[src->bl.m].name, src->bl.x, src->bl.y, 3);
        }
            break;
    }
    return 0;
}

/*==========================================
 * スキルユニットのダメージイベント
 *------------------------------------------
 */
int skill_unit_ondamaged(struct skill_unit *src, struct block_list *bl,
                          int damage, unsigned int)
{
    struct skill_unit_group *sg;

    nullpo_ret(src);
    nullpo_ret(sg = src->group);

    switch (sg->unit_id)
    {
        case 0x8d:             /* アイスウォール */
            src->val1 -= damage;
            break;
        case 0x8f:             /* ブラストマイン */
        case 0x98:             /* クレイモアートラップ */
            skill_blown(bl, &src->bl, 2);  //吹き飛ばしてみる
            break;
        default:
            damage = 0;
            break;
    }
    return damage;
}

/*---------------------------------------------------------------------------- */

/*==========================================
 * スキル使用(詠唱完了、場所指定)
 *------------------------------------------
 */
static
void skill_castend_pos(timer_id tid, tick_t tick, custom_id_t id, custom_data_t)
{
    struct map_session_data *sd = map_id2sd(id) /*,*target_sd=NULL */ ;
    int range, maxcount;

    nullpo_retv(sd);

    if (sd->bl.prev == NULL)
        return;
    if (sd->skilltimer != tid)  /* タイマIDの確認 */
        return;
    if (sd->skilltimer != -1 && pc_checkskill(sd, SA_FREECAST) > 0)
    {
        sd->speed = sd->prev_speed;
        clif_updatestatus(sd, SP_SPEED);
    }
    sd->skilltimer = -1;
    if (pc_isdead(sd))
    {
        sd->canact_tick = tick;
        sd->canmove_tick = tick;
        sd->skillitem = SkillID::NEGATIVE;
        sd->skillitemlv = -1;
        return;
    }

    if (battle_config.pc_skill_reiteration == 0)
    {
        range = -1;
        switch (sd->skillid)
        {
            case MG_SAFETYWALL:
            case WZ_FIREPILLAR:
            case HT_SKIDTRAP:
            case HT_LANDMINE:
            case HT_ANKLESNARE:
            case HT_SHOCKWAVE:
            case HT_SANDMAN:
            case HT_FLASHER:
            case HT_FREEZINGTRAP:
            case HT_BLASTMINE:
            case HT_CLAYMORETRAP:
            case HT_TALKIEBOX:
            case AL_WARP:
            case PF_SPIDERWEB: /* スパイダーウェッブ */
            case RG_GRAFFITI:  /* グラフィティ */
                range = 0;
                break;
            case AL_PNEUMA:
                range = 1;
                break;
        }
        if (range >= 0)
        {
            if (skill_check_unit_range(sd->bl.m, sd->skillx, sd->skilly, range, sd->skillid) > 0)
            {
                clif_skill_fail(sd, sd->skillid, 0, 0);
                sd->canact_tick = tick;
                sd->canmove_tick = tick;
                sd->skillitem = SkillID::NEGATIVE;
                sd->skillitemlv = -1;
                return;
            }
        }
    }
    if (battle_config.pc_skill_nofootset)
    {
        range = -1;
        switch (sd->skillid)
        {
            case WZ_FIREPILLAR:
            case HT_SKIDTRAP:
            case HT_LANDMINE:
            case HT_ANKLESNARE:
            case HT_SHOCKWAVE:
            case HT_SANDMAN:
            case HT_FLASHER:
            case HT_FREEZINGTRAP:
            case HT_BLASTMINE:
            case HT_CLAYMORETRAP:
            case HT_TALKIEBOX:
            case PF_SPIDERWEB: /* スパイダーウェッブ */
            case WZ_ICEWALL:
                range = 1;
                break;
            case AL_WARP:
                range = 0;
                break;
        }
        if (range >= 0)
        {
            if (skill_check_unit_range2(sd->bl.m, sd->skillx, sd->skilly, range) > 0)
            {
                clif_skill_fail(sd, sd->skillid, 0, 0);
                sd->canact_tick = tick;
                sd->canmove_tick = tick;
                sd->skillitem = SkillID::NEGATIVE;
                sd->skillitemlv = -1;
                return;
            }
        }
    }

    if (battle_config.pc_land_skill_limit)
    {
        maxcount = skill_get_maxcount(sd->skillid);
        if (maxcount > 0)
        {
            int i, c;
            for (i = c = 0; i < MAX_SKILLUNITGROUP; i++)
            {
                if (sd->skillunit[i].alive_count > 0
                    && sd->skillunit[i].skill_id == sd->skillid)
                    c++;
            }
            if (c >= maxcount)
            {
                clif_skill_fail(sd, sd->skillid, 0, 0);
                sd->canact_tick = tick;
                sd->canmove_tick = tick;
                sd->skillitem = SkillID::NEGATIVE;
                sd->skillitemlv = -1;
                return;
            }
        }
    }

    range = skill_get_range(sd->skillid, sd->skilllv);
    if (range < 0)
        range = battle_get_range(&sd->bl) - (range + 1);
    range += battle_config.pc_skill_add_range;
    if (battle_config.skill_out_range_consume)
    {                           // changed to allow casting when target walks out of range [Valaris]
        if (range < distance(sd->bl.x, sd->bl.y, sd->skillx, sd->skilly))
        {
            clif_skill_fail(sd, sd->skillid, 0, 0);
            sd->canact_tick = tick;
            sd->canmove_tick = tick;
            sd->skillitem = SkillID::NEGATIVE;
            sd->skillitemlv = -1;
            return;
        }
    }
    if (!skill_check_condition(sd, 1))
    {                           /* 使用条件チェック */
        sd->canact_tick = tick;
        sd->canmove_tick = tick;
        sd->skillitem = SkillID::NEGATIVE;
        sd->skillitemlv = -1;
        return;
    }
    sd->skillitem = SkillID::NEGATIVE;
    sd->skillitemlv = -1;
    if (battle_config.skill_out_range_consume)
    {
        if (range < distance(sd->bl.x, sd->bl.y, sd->skillx, sd->skilly))
        {
            clif_skill_fail(sd, sd->skillid, 0, 0);
            sd->canact_tick = tick;
            sd->canmove_tick = tick;
            return;
        }
    }

    if (battle_config.pc_skill_log)
        printf("PC %d skill castend skill=%d\n",
                sd->bl.id, uint16_t(sd->skillid));
    pc_stop_walking(sd, 0);

    skill_castend_pos2(&sd->bl, sd->skillx, sd->skilly, sd->skillid,
                        sd->skilllv, tick, BCT_ZERO);
}

/*==========================================
 * 範囲内キャラ存在確認判定処理(foreachinarea)
 *------------------------------------------
 */

static
void skill_check_condition_char_sub(struct block_list *bl, struct block_list *src, int *c)
{
    struct map_session_data *sd;
    struct map_session_data *ssd;
    struct pc_base_job s_class;
    struct pc_base_job ss_class;

    nullpo_retv(bl);
    sd = (struct map_session_data *) bl;
    nullpo_retv(src);
    nullpo_retv(c);
    ssd = (struct map_session_data *) src;

    s_class = pc_calc_base_job(sd->status.pc_class);
    //チェックしない設定ならcにありえない大きな数字を返して終了
    if (!battle_config.player_skill_partner_check)
    {                           //本当はforeachの前にやりたいけど設定適用箇所をまとめるためにここへ
        (*c) = 99;
        return;
    }

    ;
    ss_class = pc_calc_base_job(ssd->status.pc_class);

    switch (ssd->skillid)
    {
        case PR_BENEDICTIO:    /* 聖体降福 */
            if (sd != ssd
                && (sd->status.pc_class == 4 || sd->status.pc_class == 8
                    || sd->status.pc_class == 15 || sd->status.pc_class == 4005
                    || sd->status.pc_class == 4009 || sd->status.pc_class == 4016)
                && (sd->bl.x == ssd->bl.x - 1 || sd->bl.x == ssd->bl.x + 1)
                && sd->status.sp >= 10)
                (*c)++;
            break;
        case BD_LULLABY:       /* 子守歌 */
        case BD_RICHMANKIM:    /* ニヨルドの宴 */
        case BD_ETERNALCHAOS:  /* 永遠の混沌 */
        case BD_DRUMBATTLEFIELD:   /* 戦太鼓の響き */
        case BD_RINGNIBELUNGEN:    /* ニーベルングの指輪 */
        case BD_ROKISWEIL:     /* ロキの叫び */
        case BD_INTOABYSS:     /* 深淵の中に */
        case BD_SIEGFRIED:     /* 不死身のジークフリード */
        case BD_RAGNAROK:      /* 神々の黄昏 */
        case CG_MOONLIT:       /* 月明りの泉に落ちる花びら */
            if (sd != ssd &&
                ((ssd->status.pc_class == 19 && sd->status.pc_class == 20) ||
                 (ssd->status.pc_class == 20 && sd->status.pc_class == 19) ||
                 (ssd->status.pc_class == 4020 && sd->status.pc_class == 4021) ||
                 (ssd->status.pc_class == 4021 && sd->status.pc_class == 4020) ||
                 (ssd->status.pc_class == 20 && sd->status.pc_class == 4020) ||
                 (ssd->status.pc_class == 19 && sd->status.pc_class == 4021)) &&
                pc_checkskill(sd, ssd->skillid) > 0 &&
                (*c) == 0 &&
                sd->status.party_id == ssd->status.party_id &&
                !pc_issit(sd) && sd->sc_data[SC_DANCING].timer == -1)
                (*c) = pc_checkskill(sd, ssd->skillid);
            break;
    }
    return;
}

/*==========================================
 * 範囲内キャラ存在確認判定後スキル使用処理(foreachinarea)
 *------------------------------------------
 */

static
void skill_check_condition_use_sub(struct block_list *bl, struct block_list *src, int *c)
{
    struct map_session_data *sd;
    struct map_session_data *ssd;
    struct pc_base_job s_class;
    struct pc_base_job ss_class;
    int skilllv;

    nullpo_retv(bl);
    sd = (struct map_session_data *) bl;
    nullpo_retv(src);
    nullpo_retv(c);
    ssd = (struct map_session_data *) src;

    s_class = pc_calc_base_job(sd->status.pc_class);

    //チェックしない設定ならcにありえない大きな数字を返して終了
    if (!battle_config.player_skill_partner_check)
    {                           //本当はforeachの前にやりたいけど設定適用箇所をまとめるためにここへ
        (*c) = 99;
        return;
    }

    ss_class = pc_calc_base_job(ssd->status.pc_class);
    SkillID skillid = ssd->skillid;
    skilllv = ssd->skilllv;
    switch (skillid)
    {
        case PR_BENEDICTIO:    /* 聖体降福 */
            if (sd != ssd
                && (sd->status.pc_class == 4 || sd->status.pc_class == 8
                    || sd->status.pc_class == 15 || sd->status.pc_class == 4005
                    || sd->status.pc_class == 4009 || sd->status.pc_class == 4016)
                && (sd->bl.x == ssd->bl.x - 1 || sd->bl.x == ssd->bl.x + 1)
                && sd->status.sp >= 10)
            {
                sd->status.sp -= 10;
                pc_calcstatus(sd, 0);
                (*c)++;
            }
            break;
        case BD_LULLABY:       /* 子守歌 */
        case BD_RICHMANKIM:    /* ニヨルドの宴 */
        case BD_ETERNALCHAOS:  /* 永遠の混沌 */
        case BD_DRUMBATTLEFIELD:   /* 戦太鼓の響き */
        case BD_RINGNIBELUNGEN:    /* ニーベルングの指輪 */
        case BD_ROKISWEIL:     /* ロキの叫び */
        case BD_INTOABYSS:     /* 深淵の中に */
        case BD_SIEGFRIED:     /* 不死身のジークフリード */
        case BD_RAGNAROK:      /* 神々の黄昏 */
        case CG_MOONLIT:       /* 月明りの泉に落ちる花びら */
            if (sd != ssd &&    //本人以外で
                ((ssd->status.pc_class == 19 && sd->status.pc_class == 20) ||
                (ssd->status.pc_class == 20 && sd->status.pc_class == 19) ||
                (ssd->status.pc_class == 4020 && sd->status.pc_class == 4021) ||
                (ssd->status.pc_class == 4021 && sd->status.pc_class == 4020) ||
                (ssd->status.pc_class == 20 && sd->status.pc_class == 4020) ||
                (ssd->status.pc_class == 19 && sd->status.pc_class == 4021)) && //自分がダンサーならバードで
                pc_checkskill(sd, skillid) > 0 &&  //スキルを持っていて
                (*c) == 0 &&    //最初の一人で
                sd->status.party_id == ssd->status.party_id &&  //パーティーが同じで
                !pc_issit(sd) &&   //座ってない
                sd->sc_data[SC_DANCING].timer == -1 //ダンス中じゃない
                )
            {
                ssd->sc_data[SC_DANCING].val4 = bl->id;
                skill_status_change_start(bl, SC_DANCING, uint16_t(skillid),
                                           ssd->sc_data[SC_DANCING].val2, 0,
                                           src->id, skill_get_time(skillid,
                                                                    skilllv) +
                                           1000, 0);
                sd->skillid_dance = sd->skillid = skillid;
                sd->skilllv_dance = sd->skilllv = skilllv;
                (*c)++;
            }
            break;
    }
}

/*==========================================
 * 範囲内バイオプラント、スフィアマイン用Mob存在確認判定処理(foreachinarea)
 *------------------------------------------
 */

static
void skill_check_condition_mob_master_sub(struct block_list *bl, int src_id, int mob_class, int *c)
{
    struct mob_data *md;

    nullpo_retv(bl);
    md = (struct mob_data *) bl;

    if (!src_id)
        return;
    if (!mob_class)
        return;
    nullpo_retv(c);

    if (md->mob_class == mob_class && md->master_id == src_id)
        (*c)++;
}

/*==========================================
 * スキル使用条件(偽で使用失敗)
 *------------------------------------------
 */
int skill_check_condition(struct map_session_data *sd, int type)
{
    int hp, sp, hp_rate, sp_rate, zeny, weapon, spiritball,
        lv, mhp;
    int index[10], itemid[10], amount[10];

    nullpo_ret(sd);

    if (battle_config.gm_skilluncond > 0
        && pc_isGM(sd) >= battle_config.gm_skilluncond)
    {
        sd->skillitem = SkillID::NEGATIVE;
        sd->skillitemlv = -1;
        return 1;
    }

    if (bool(sd->opt1))
    {
        clif_skill_fail(sd, sd->skillid, 0, 0);
        sd->skillitem = SkillID::NEGATIVE;
        sd->skillitemlv = -1;
        return 0;
    }
    if (pc_is90overweight(sd))
    {
        clif_skill_fail(sd, sd->skillid, 9, 0);
        sd->skillitem = SkillID::NEGATIVE;
        sd->skillitemlv = -1;
        return 0;
    }

    if (sd->skillid == AC_MAKINGARROW && sd->state.make_arrow_flag == 1)
    {
        sd->skillitem = SkillID::NEGATIVE;
        sd->skillitemlv = -1;
        return 0;
    }
    /*if (sd->skillid == AM_PHARMACY &&  sd->state.produce_flag == 1) {
     * sd->skillitem = sd->skillitemlv = -1;
     * return 0;
     * } */

    if (sd->skillitem == sd->skillid)
    {                           /* アイテムの場合無条件成功 */
        if (type & 1)
        {
            sd->skillitem = SkillID::NEGATIVE;
            sd->skillitemlv = -1;
        }
        return 1;
    }
    if (bool(sd->opt1))
    {
        clif_skill_fail(sd, sd->skillid, 0, 0);
        return 0;
    }
    if (sd->sc_data[SC_DIVINA].timer != -1 ||
        sd->sc_data[SC_ROKISWEIL].timer != -1 ||
        (sd->sc_data[SC_AUTOCOUNTER].timer != -1
         && sd->skillid != KN_AUTOCOUNTER)
        || sd->sc_data[SC_STEELBODY].timer != -1
        || sd->sc_data[SC_BERSERK].timer != -1)
    {
        clif_skill_fail(sd, sd->skillid, 0, 0);
        return 0;           /* 状態異常や沈黙など */
    }
    SkillID skill = sd->skillid;
    lv = sd->skilllv;
    hp = skill_get_hp(skill, lv);  /* 消費HP */
    sp = skill_get_sp(skill, lv);  /* 消費SP */
    if ((sd->skillid_old == BD_ENCORE) && skill == sd->skillid_dance)
        sp = sp / 2;            //アンコール時はSP消費が半分
    hp_rate = (lv <= 0) ? 0 : skill_db[skill].hp_rate[lv - 1];
    sp_rate = (lv <= 0) ? 0 : skill_db[skill].sp_rate[lv - 1];
    zeny = skill_get_zeny(skill, lv);
    weapon = skill_db[skill].weapon;
    SkillState state = skill_db[skill].state;
    spiritball = (lv <= 0) ? 0 : skill_db[skill].spiritball[lv - 1];
    mhp = skill_get_mhp(skill, lv);    /* 消費HP */
    for (int i = 0; i < 10; i++)
    {
        itemid[i] = skill_db[skill].itemid[i];
        amount[i] = skill_db[skill].amount[i];
    }
    if (mhp > 0)
        hp += (sd->status.max_hp * mhp) / 100;
    if (hp_rate > 0)
        hp += (sd->status.hp * hp_rate) / 100;
    else
        hp += (sd->status.max_hp * abs(hp_rate)) / 100;
    if (sp_rate > 0)
        sp += (sd->status.sp * sp_rate) / 100;
    else
        sp += (sd->status.max_sp * abs(sp_rate)) / 100;
    if (sd->dsprate != 100)
        sp = sp * sd->dsprate / 100;    /* 消費SP修正 */

    switch (skill)
    {
        case SA_CASTCANCEL:
            if (sd->skilltimer == -1)
            {
                clif_skill_fail(sd, skill, 0, 0);
                return 0;
            }
            break;
        case BS_MAXIMIZE:      /* マキシマイズパワー */
        case NV_TRICKDEAD:     /* 死んだふり */
        case TF_HIDING:        /* ハイディング */
        case AS_CLOAKING:      /* クローキング */
        case CR_AUTOGUARD:     /* オートガード */
        case CR_DEFENDER:      /* ディフェンダー */
        case ST_CHASEWALK:
            if (sd->sc_data[SkillStatusChangeTable[skill]].timer != -1)
                return 1;       /* 解除する場合はSP消費しない */
            break;
        case AL_TELEPORT:
        case AL_WARP:
            if (map[sd->bl.m].flag.noteleport)
                return 0;
            break;
        case MO_CALLSPIRITS:   /* 気功 */
            if (sd->spiritball >= lv)
            {
                clif_skill_fail(sd, skill, 0, 0);
                return 0;
            }
            break;
        case CH_SOULCOLLECT:   /* 狂気功 */
            if (sd->spiritball >= 5)
            {
                clif_skill_fail(sd, skill, 0, 0);
                return 0;
            }
            break;
        case MO_FINGEROFFENSIVE:   //指弾
            if (sd->spiritball > 0 && sd->spiritball < spiritball)
            {
                spiritball = sd->spiritball;
                sd->spiritball_old = sd->spiritball;
            }
            else
                sd->spiritball_old = lv;
            break;
        case MO_CHAINCOMBO:    //連打掌
            if (sd->sc_data[SC_BLADESTOP].timer == -1)
            {
                if (sd->sc_data[SC_COMBO].timer == -1
                    || SkillID(sd->sc_data[SC_COMBO].val1) != MO_TRIPLEATTACK)
                    return 0;
            }
            break;
        case MO_COMBOFINISH:   //猛龍拳
            if (sd->sc_data[SC_COMBO].timer == -1
                || SkillID(sd->sc_data[SC_COMBO].val1) != MO_CHAINCOMBO)
                return 0;
            break;
        case CH_TIGERFIST:     //伏虎拳
            if (sd->sc_data[SC_COMBO].timer == -1
                || SkillID(sd->sc_data[SC_COMBO].val1) != MO_COMBOFINISH)
                return 0;
            break;
        case CH_CHAINCRUSH:    //連柱崩撃
            if (sd->sc_data[SC_COMBO].timer == -1)
                return 0;
            if (SkillID(sd->sc_data[SC_COMBO].val1) != MO_COMBOFINISH
                && SkillID(sd->sc_data[SC_COMBO].val1) != CH_TIGERFIST)
                return 0;
            break;
        case MO_EXTREMITYFIST: // 阿修羅覇鳳拳
            if ((sd->sc_data[SC_COMBO].timer != -1
                 && (SkillID(sd->sc_data[SC_COMBO].val1) == MO_COMBOFINISH
                     || SkillID(sd->sc_data[SC_COMBO].val1) == CH_CHAINCRUSH))
                || sd->sc_data[SC_BLADESTOP].timer != -1)
                spiritball--;
            break;
        case BD_ADAPTATION:    /* アドリブ */
        {
            struct skill_unit_group *group = NULL;
            if (sd->sc_data[SC_DANCING].timer == -1
                ||
                ((group =
                  (struct skill_unit_group *) sd->sc_data[SC_DANCING].val2)
                 &&
                 (skill_get_time(SkillID(sd->sc_data[SC_DANCING].val1),
                   group->skill_lv) - sd->sc_data[SC_DANCING].val3 * 1000) <=
                 skill_get_time2(skill, lv)))
            {                   //ダンス中で使用後5秒以上のみ?
                clif_skill_fail(sd, skill, 0, 0);
                return 0;
            }
        }
            break;
        case PR_BENEDICTIO:    /* 聖体降福 */
        {
            int range = 1;
            int c = 0;
            if (!(type & 1))
            {
                map_foreachinarea(std::bind(skill_check_condition_char_sub, ph::_1, &sd->bl, &c),
                        sd->bl.m, sd->bl.x - range, sd->bl.y - range,
                        sd->bl.x + range, sd->bl.y + range, BL_PC);
                if (c < 2)
                {
                    clif_skill_fail(sd, skill, 0, 0);
                    return 0;
                }
            }
            else
            {
                map_foreachinarea(std::bind(skill_check_condition_use_sub, ph::_1, &sd->bl, &c),
                        sd->bl.m, sd->bl.x - range, sd->bl.y - range,
                        sd->bl.x + range, sd->bl.y + range, BL_PC);
            }
        }
            break;
        case WE_CALLPARTNER:   /* あなたに逢いたい */
            if (!sd->status.partner_id)
            {
                clif_skill_fail(sd, skill, 0, 0);
                return 0;
            }
            break;
        case AM_CANNIBALIZE:   /* バイオプラント */
        case AM_SPHEREMINE:    /* スフィアーマイン */
            if (type & 1)
            {
                int c = 0;
                int maxcount = skill_get_maxcount(skill);
                int mob_class = (skill == AM_CANNIBALIZE) ? 1118 : 1142;
                if (battle_config.pc_land_skill_limit && maxcount > 0)
                {
                    map_foreachinarea(std::bind(skill_check_condition_mob_master_sub, ph::_1, sd->bl.id, mob_class, &c),

                            sd->bl.m, 0, 0,
                            map[sd->bl.m].xs, map[sd->bl.m].ys, BL_MOB);
                    if (c >= maxcount)
                    {
                        clif_skill_fail(sd, skill, 0, 0);
                        return 0;
                    }
                }
            }
            break;
        case MG_FIREWALL:      /* ファイアーウォール */
            /* 数制限 */
            if (battle_config.pc_land_skill_limit)
            {
                int maxcount = skill_get_maxcount(skill);
                if (maxcount > 0)
                {
                    int i, c;
                    for (i = c = 0; i < MAX_SKILLUNITGROUP; i++)
                    {
                        if (sd->skillunit[i].alive_count > 0
                            && sd->skillunit[i].skill_id == skill)
                            c++;
                    }
                    if (c >= maxcount)
                    {
                        clif_skill_fail(sd, skill, 0, 0);
                        return 0;
                    }
                }
            }
            break;
    }

    if (!(type & 2))
    {
        if (hp > 0 && sd->status.hp < hp)
        {                       /* HPチェック */
            clif_skill_fail(sd, skill, 2, 0);  /* HP不足:失敗通知 */
            return 0;
        }
        if (sp > 0 && sd->status.sp < sp)
        {                       /* SPチェック */
            clif_skill_fail(sd, skill, 1, 0);  /* SP不足:失敗通知 */
            return 0;
        }
        if (zeny > 0 && sd->status.zeny < zeny)
        {
            clif_skill_fail(sd, skill, 5, 0);
            return 0;
        }
        if (!(weapon & (1 << sd->status.weapon)))
        {
            clif_skill_fail(sd, skill, 6, 0);
            return 0;
        }
        if (spiritball > 0 && sd->spiritball < spiritball)
        {
            clif_skill_fail(sd, skill, 0, 0);  // 氣球不足
            return 0;
        }
    }

    switch (state)
    {
        case ST_HIDING:
            if (!bool(sd->status.option & Option::HIDE2))
            {
                clif_skill_fail(sd, skill, 0, 0);
                return 0;
            }
            break;
        case ST_CLOAKING:
            if (!bool(sd->status.option & Option::CLOAK))
            {
                clif_skill_fail(sd, skill, 0, 0);
                return 0;
            }
            break;
        case ST_HIDDEN:
            if (!pc_ishiding(sd))
            {
                clif_skill_fail(sd, skill, 0, 0);
                return 0;
            }
            break;
        case ST_RIDING:
            if (!pc_isriding(sd))
            {
                clif_skill_fail(sd, skill, 0, 0);
                return 0;
            }
            break;
        case ST_FALCON:
            if (!pc_isfalcon(sd))
            {
                clif_skill_fail(sd, skill, 0, 0);
                return 0;
            }
            break;
        case ST_CART:
            if (!pc_iscarton(sd))
            {
                clif_skill_fail(sd, skill, 0, 0);
                return 0;
            }
            break;
        case ST_SHIELD:
            if (sd->status.shield <= 0)
            {
                clif_skill_fail(sd, skill, 0, 0);
                return 0;
            }
            break;
        case ST_SIGHT:
            if (sd->sc_data[SC_SIGHT].timer == -1 && type & 1)
            {
                clif_skill_fail(sd, skill, 0, 0);
                return 0;
            }
            break;
        case ST_EXPLOSIONSPIRITS:
            if (sd->sc_data[SC_EXPLOSIONSPIRITS].timer == -1)
            {
                clif_skill_fail(sd, skill, 0, 0);
                return 0;
            }
            break;
        case ST_RECOV_WEIGHT_RATE:
            if (battle_config.natural_heal_weight_rate <= 100
                && sd->weight * 100 / sd->max_weight >=
                battle_config.natural_heal_weight_rate)
            {
                clif_skill_fail(sd, skill, 0, 0);
                return 0;
            }
            break;
        case ST_MOVE_ENABLE:
        {
            struct walkpath_data wpd;
            if (path_search(&wpd, sd->bl.m, sd->bl.x, sd->bl.y, sd->skillx, sd->skilly,
                 1) == -1)
            {
                clif_skill_fail(sd, skill, 0, 0);
                return 0;
            }
        }
            break;
        case ST_WATER:
            if (map_getcell(sd->bl.m, sd->bl.x, sd->bl.y) != 3
                && (sd->sc_data[SC_DELUGE].timer == -1))
            {                   //水場判定
                clif_skill_fail(sd, skill, 0, 0);
                return 0;
            }
            break;
    }

    for (int i = 0; i < 10; i++)
    {
        int x = lv % 11 - 1;
        index[i] = -1;
        if (itemid[i] <= 0)
            continue;
        if (itemid[i] >= 715 && itemid[i] <= 717
            && sd->special_state.no_gemstone)
            continue;
        if (((itemid[i] >= 715 && itemid[i] <= 717) || itemid[i] == 1065)
            && sd->sc_data[SC_INTOABYSS].timer != -1)
            continue;
        if (skill == AM_POTIONPITCHER && i != x)
            continue;

        index[i] = pc_search_inventory(sd, itemid[i]);
        if (index[i] < 0 || sd->status.inventory[index[i]].amount < amount[i])
        {
            if (itemid[i] == 716 || itemid[i] == 717)
                clif_skill_fail(sd, skill, (7 + (itemid[i] - 716)), 0);
            else
                clif_skill_fail(sd, skill, 0, 0);
            return 0;
        }
    }

    if (!(type & 1))
        return 1;

    if (skill != AM_POTIONPITCHER)
    {
        if (skill == AL_WARP && !(type & 2))
            return 1;
        for (int i = 0; i < 10; i++)
        {
            if (index[i] >= 0)
                pc_delitem(sd, index[i], amount[i], 0);    // アイテム消費
        }
    }

    if (type & 2)
        return 1;

    pc_heal(sd, -sp, -hp);     // [Fate] This might suppress some dupe messages

/*      if (sp > 0) {                                   // SP消費 */
/*              sd->status.sp-=sp; */
/*              clif_updatestatus(sd,SP_SP); */
/*      } */
/*      if (hp > 0) {                                   // HP消費 */
/*              sd->status.hp-=hp; */
/*              clif_updatestatus(sd,SP_HP); */
/*      } */
    if (zeny > 0)               // Zeny消費
        pc_payzeny(sd, zeny);
    if (spiritball > 0)         // 氣球消費
        pc_delspiritball(sd, spiritball, 0);

    return 1;
}

/*==========================================
 * 詠唱時間計算
 *------------------------------------------
 */
int skill_castfix(struct block_list *bl, int time)
{
    struct map_session_data *sd;
    struct mob_data *md;        // [Valaris]
    eptr<struct status_change, StatusChange> sc_data;
    int dex;
    int castrate = 100;
    SkillID skill;
    int lv, castnodex;

    nullpo_ret(bl);

    if (bl->type == BL_MOB)
    {                           // Crash fix [Valaris]
        md = (struct mob_data *) bl;
        skill = md->skillid;
        lv = md->skilllv;
    }

    else
    {
        sd = (struct map_session_data *) bl;
        skill = sd->skillid;
        lv = sd->skilllv;
    }

    sc_data = battle_get_sc_data(bl);
    dex = battle_get_dex(bl);

    if (skill > MAX_SKILL_DB /*|| skill < SkillID()*/)
        return 0;

    castnodex = skill_get_castnodex(skill, lv);

    if (time == 0)
        return 0;
    if (castnodex > 0 && bl->type == BL_PC)
        castrate = ((struct map_session_data *) bl)->castrate;
    else if (castnodex <= 0 && bl->type == BL_PC)
    {
        castrate = ((struct map_session_data *) bl)->castrate;
        time =
            time * castrate * (battle_config.castrate_dex_scale -
                               dex) / (battle_config.castrate_dex_scale *
                                       100);
        time = time * battle_config.cast_rate / 100;
    }

    /* サフラギウム */
    if (sc_data && sc_data[SC_SUFFRAGIUM].timer != -1)
    {
        time = time * (100 - sc_data[SC_SUFFRAGIUM].val1 * 15) / 100;
        skill_status_change_end(bl, SC_SUFFRAGIUM, -1);
    }
    /* ブラギの詩 */
    if (sc_data && sc_data[SC_POEMBRAGI].timer != -1)
        time =
            time * (100 -
                    (sc_data[SC_POEMBRAGI].val1 * 3 +
                     sc_data[SC_POEMBRAGI].val2 +
                     (sc_data[SC_POEMBRAGI].val3 >> 16))) / 100;

    return (time > 0) ? time : 0;
}

/*==========================================
 * ディレイ計算
 *------------------------------------------
 */
int skill_delayfix(struct block_list *bl, int time)
{
    eptr<struct status_change, StatusChange> sc_data;

    nullpo_ret(bl);

    sc_data = battle_get_sc_data(bl);
    if (time <= 0)
        return 0;

    if (bl->type == BL_PC)
    {
        if (battle_config.delay_dependon_dex)   /* dexの影響を計算する */
            time =
                time * (battle_config.castrate_dex_scale -
                        battle_get_dex(bl)) /
                battle_config.castrate_dex_scale;
        time = time * battle_config.delay_rate / 100;
    }

    /* ブラギの詩 */
    if (sc_data && sc_data[SC_POEMBRAGI].timer != -1)
        time =
            time * (100 -
                    (sc_data[SC_POEMBRAGI].val1 * 3 +
                     sc_data[SC_POEMBRAGI].val2 +
                     (sc_data[SC_POEMBRAGI].val3 & 0xffff))) / 100;

    return (time > 0) ? time : 0;
}

/*==========================================
 * スキル使用(ID指定)
 *------------------------------------------
 */
int skill_use_id(struct map_session_data *sd, int target_id,
        SkillID skill_num, int skill_lv)
{
    unsigned int tick;
    int casttime = 0, delay = 0, skill, range_;
    struct map_session_data *target_sd = NULL;
    int forcecast = 0;
    struct block_list *bl;
    eptr<struct status_change, StatusChange> sc_data;
    tick = gettick();

    nullpo_ret(sd);

    if ((bl = map_id2bl(target_id)) == NULL)
    {
/*              if (battle_config.error_log)
                        printf("skill target not found %d\n",target_id); */
        return 0;
    }
    if (sd->bl.m != bl->m || pc_isdead(sd))
        return 0;

    if (skillnotok(skill_num, sd)) // [MouseJstr]
        return 0;

    if (sd->skillid == WZ_ICEWALL && map[sd->bl.m].flag.noicewall
        && !map[sd->bl.m].flag.pvp)
    {                           // noicewall flag [Valaris]
        clif_skill_fail(sd, sd->skillid, 0, 0);
        return 0;
    }
    sc_data = sd->sc_data;

    /* 沈黙や異常(ただし、グリムなどの判定をする) */
    if (bool(sd->opt1))
        return 0;

    if (sc_data[SC_CHASEWALK].timer != -1)
        return 0;
    if (sc_data[SC_VOLCANO].timer != -1)
    {
        if (skill_num == WZ_ICEWALL)
            return 0;
    }
    if (sc_data[SC_ROKISWEIL].timer != -1)
    {
        if (skill_num == BD_ADAPTATION)
            return 0;
    }
    if (sd->sc_data[SC_DIVINA].timer != -1 ||
        sd->sc_data[SC_ROKISWEIL].timer != -1 ||
        (sd->sc_data[SC_AUTOCOUNTER].timer != -1
         && sd->skillid != KN_AUTOCOUNTER)
        || sd->sc_data[SC_STEELBODY].timer != -1
        || sd->sc_data[SC_BERSERK].timer != -1)
    {
        return 0;           /* 状態異常や沈黙など */
    }

    if (sc_data[SC_BLADESTOP].timer != -1)
    {
        int lv = sc_data[SC_BLADESTOP].val1;
        if (sc_data[SC_BLADESTOP].val2 == 1)
            return 0;       //白羽された側なのでダメ
        if (lv == 1)
            return 0;
        if (lv == 2 && skill_num != MO_FINGEROFFENSIVE)
            return 0;
        if (lv == 3 && skill_num != MO_FINGEROFFENSIVE
            && skill_num != MO_INVESTIGATE)
            return 0;
        if (lv == 4 && skill_num != MO_FINGEROFFENSIVE
            && skill_num != MO_INVESTIGATE && skill_num != MO_CHAINCOMBO)
            return 0;
        if (lv == 5 && skill_num != MO_FINGEROFFENSIVE
            && skill_num != MO_INVESTIGATE && skill_num != MO_CHAINCOMBO
            && skill_num != MO_EXTREMITYFIST)
            return 0;
    }

    if (bool(sd->status.option & Option::CLOAK)
        && skill_num == TF_HIDING)
        return 0;
    if (bool(sd->status.option & Option::HIDE2)
        && skill_num != TF_HIDING
        && skill_num != AS_GRIMTOOTH
        && skill_num != RG_BACKSTAP
        && skill_num != RG_RAID)
        return 0;

    /* 演奏/ダンス中 */
    if (sc_data && sc_data[SC_DANCING].timer != -1)
    {
//      if(battle_config.pc_skill_log)
//          printf("dancing! %d\n",skill_num);
        if (sc_data[SC_DANCING].val4 && skill_num != BD_ADAPTATION) //合奏中はアドリブ以外不可
            return 0;
        if (skill_num != BD_ADAPTATION && skill_num != BA_MUSICALSTRIKE
            && skill_num != DC_THROWARROW)
        {
            return 0;
        }
    }

    if (skill_get_inf2(skill_num) & 0x200 && sd->bl.id == target_id)
        return 0;
    //直前のスキルが何か覚える必要のあるスキル
    switch (skill_num)
    {
        case SA_CASTCANCEL:
            if (sd->skillid != skill_num)
            {                   //キャストキャンセル自体は覚えない
                sd->skillid_old = sd->skillid;
                sd->skilllv_old = sd->skilllv;
                break;
            }
        case BD_ENCORE:        /* アンコール */
            if (sd->skillid_dance == SkillID::ZERO)
            {                   //前回使用した踊りがないとだめ
                clif_skill_fail(sd, skill_num, 0, 0);
                return 0;
            }
            else
            {
                sd->skillid_old = skill_num;
            }
            break;
    }

    sd->skillid = skill_num;
    sd->skilllv = skill_lv;

    switch (skill_num)
    {                           //事前にレベルが変わったりするスキル
        case BD_LULLABY:       /* 子守歌 */
        case BD_RICHMANKIM:    /* ニヨルドの宴 */
        case BD_ETERNALCHAOS:  /* 永遠の混沌 */
        case BD_DRUMBATTLEFIELD:   /* 戦太鼓の響き */
        case BD_RINGNIBELUNGEN:    /* ニーベルングの指輪 */
        case BD_ROKISWEIL:     /* ロキの叫び */
        case BD_INTOABYSS:     /* 深淵の中に */
        case BD_SIEGFRIED:     /* 不死身のジークフリード */
        case BD_RAGNAROK:      /* 神々の黄昏 */
        case CG_MOONLIT:       /* 月明りの泉に落ちる花びら */
        {
            int range = 1;
            int c = 0;
            map_foreachinarea(std::bind(skill_check_condition_char_sub, ph::_1, &sd->bl, &c),
                    sd->bl.m, sd->bl.x - range, sd->bl.y - range,
                    sd->bl.x + range, sd->bl.y + range, BL_PC);
            if (c < 1)
            {
                clif_skill_fail(sd, skill_num, 0, 0);
                return 0;
            }
            else if (c == 99)
            {                   //相方不要設定だった
                ;
            }
            else
            {
                sd->skilllv = (c + skill_lv) / 2;
            }
        }
            break;
    }

    if (!skill_check_condition(sd, 0))
        return 0;

    /* 射程と障害物チェック */
    range_ = skill_get_range(skill_num, skill_lv);
    if (range_ < 0)
        range_ = battle_get_range(&sd->bl) - (range_ + 1);
    if (!battle_check_range(&sd->bl, bl, range_))
        return 0;

    if (bl->type == BL_PC)
    {
        target_sd = (struct map_session_data *) bl;
        if (target_sd && skill_num == ALL_RESURRECTION
            && !pc_isdead(target_sd))
            return 0;
    }
    if ((skill_num != MO_CHAINCOMBO &&
         skill_num != MO_COMBOFINISH &&
         skill_num != MO_EXTREMITYFIST &&
         skill_num != CH_TIGERFIST &&
         skill_num != CH_CHAINCRUSH) ||
        (skill_num == MO_EXTREMITYFIST && sd->state.skill_flag))
        pc_stopattack(sd);

    casttime = skill_castfix(&sd->bl, skill_get_cast(skill_num, skill_lv));
    if (skill_num != SA_MAGICROD)
        delay =
            skill_delayfix(&sd->bl, skill_get_delay(skill_num, skill_lv));
    sd->state.skillcastcancel = skill_db[skill_num].castcancel;

    switch (skill_num)
    {                           /* 何か特殊な処理が必要 */
//  case AL_HEAL:   /* ヒール */
//      if(battle_check_undead(battle_get_race(bl),battle_get_elem_type(bl)))
//          forcecast=1;    /* ヒールアタックなら詠唱エフェクト有り */
//      break;
        case ALL_RESURRECTION: /* リザレクション */
            if (bl->type != BL_PC
                && battle_check_undead(battle_get_race(bl),
                                        battle_get_elem_type(bl)))
            {                   /* 敵がアンデッドなら */
                forcecast = 1;  /* ターンアンデットと同じ詠唱時間 */
                casttime =
                    skill_castfix(&sd->bl,
                                   skill_get_cast(PR_TURNUNDEAD, skill_lv));
            }
            break;
        case MO_FINGEROFFENSIVE:   /* 指弾 */
            casttime +=
                casttime *
                ((skill_lv > sd->spiritball) ? sd->spiritball : skill_lv);
            break;
        case MO_CHAINCOMBO:    /*連打掌 */
            target_id = sd->attacktarget;
            if (sc_data && sc_data[SC_BLADESTOP].timer != -1)
            {
                struct block_list *tbl;
                if ((tbl = (struct block_list *) sc_data[SC_BLADESTOP].val4) == NULL)   //ターゲットがいない?
                    return 0;
                target_id = tbl->id;
            }
            break;
        case MO_COMBOFINISH:   /*猛龍拳 */
        case CH_TIGERFIST:     /* 伏虎拳 */
        case CH_CHAINCRUSH:    /* 連柱崩撃 */
            target_id = sd->attacktarget;
            break;

// -- moonsoul  (altered to allow proper usage of extremity from new champion combos)
//
        case MO_EXTREMITYFIST: /*阿修羅覇鳳拳 */
            if (sc_data && sc_data[SC_COMBO].timer != -1
                && (SkillID(sc_data[SC_COMBO].val1) == MO_COMBOFINISH
                    || SkillID(sc_data[SC_COMBO].val1) == CH_CHAINCRUSH))
            {
                casttime = 0;
                target_id = sd->attacktarget;
            }
            forcecast = 1;
            break;
        case SA_MAGICROD:
        case SA_SPELLBREAKER:
            forcecast = 1;
            break;
        case WE_MALE:
        case WE_FEMALE:
        {
            struct map_session_data *p_sd = NULL;
            if ((p_sd = pc_get_partner(sd)) == NULL)
                return 0;
            target_id = p_sd->bl.id;
            //rangeをもう1回検査
            range_ = skill_get_range(skill_num, skill_lv);
            if (range_ < 0)
                range_ = battle_get_range(&sd->bl) - (range_ + 1);
            if (!battle_check_range(&sd->bl, &p_sd->bl, range_))
            {
                return 0;
            }
        }
            break;
        case AS_SPLASHER:      /* ベナムスプラッシャー */
        {
            eptr<struct status_change, StatusChange> t_sc_data = battle_get_sc_data(bl);
            if (t_sc_data && t_sc_data[SC_POISON].timer == -1)
            {
                clif_skill_fail(sd, skill_num, 0, 10);
                return 0;
            }
        }
            break;
        case PF_MEMORIZE:      /* メモライズ */
            casttime = 12000;
            break;

    }

    //メモライズ状態ならキャストタイムが1/3
    if (sc_data && sc_data[SC_MEMORIZE].timer != -1 && casttime > 0)
    {
        casttime = casttime / 3;
        if ((--sc_data[SC_MEMORIZE].val2) <= 0)
            skill_status_change_end(&sd->bl, SC_MEMORIZE, -1);
    }

    if (battle_config.pc_skill_log)
        printf("PC %d skill use target_id=%d skill=%d lv=%d cast=%d\n",
                sd->bl.id, target_id, uint16_t(skill_num), skill_lv, casttime);

//  if(sd->skillitem == skill_num)
//      casttime = delay = 0;

    if (casttime > 0 || forcecast)
    {                           /* 詠唱が必要 */
        struct mob_data *md;

        /* 詠唱反応モンスター */
        if (bl->type == BL_MOB && (md = (struct mob_data *) bl)
            && mob_db[md->mob_class].mode & 0x10 && md->state.state != MS_ATTACK
            && sd->invincible_timer == -1)
        {
            md->target_id = sd->bl.id;
            md->state.attackable = true;
            md->min_chase = 13;
        }
    }

    if (casttime <= 0)          /* 詠唱の無いものはキャンセルされない */
        sd->state.skillcastcancel = 0;

    sd->skilltarget = target_id;
/*      sd->cast_target_bl      = bl; */
    sd->skillx = 0;
    sd->skilly = 0;
    sd->canact_tick = tick + casttime + delay;
    sd->canmove_tick = tick;
    if (!(battle_config.pc_cloak_check_type & 2) && sc_data
        && sc_data[SC_CLOAKING].timer != -1 && sd->skillid != AS_CLOAKING)
        skill_status_change_end(&sd->bl, SC_CLOAKING, -1);
    if (casttime > 0)
    {
        sd->skilltimer =
            add_timer(tick + casttime, skill_castend_id, sd->bl.id, 0);
        if ((skill = pc_checkskill(sd, SA_FREECAST)) > 0)
        {
            sd->prev_speed = sd->speed;
            sd->speed = sd->speed * (175 - skill * 5) / 100;
            clif_updatestatus(sd, SP_SPEED);
        }
        else
            pc_stop_walking(sd, 0);
    }
    else
    {
        if (skill_num != SA_CASTCANCEL)
            sd->skilltimer = -1;
        skill_castend_id(sd->skilltimer, tick, sd->bl.id, 0);
    }

    //マジックパワーの効果終了
    if (sc_data && sc_data[SC_MAGICPOWER].timer != -1
        && skill_num != HW_MAGICPOWER)
        skill_status_change_end(&sd->bl, SC_MAGICPOWER, -1);

    return 0;
}

/*==========================================
 * スキル使用(場所指定)
 *------------------------------------------
 */
int skill_use_pos(struct map_session_data *sd,
        int skill_x, int skill_y,
        SkillID skill_num, int skill_lv)
{
    struct block_list bl;
    eptr<struct status_change, StatusChange> sc_data;
    unsigned int tick;
    int casttime = 0, delay = 0, skill, range;

    nullpo_ret(sd);

    if (pc_isdead(sd))
        return 0;

    if (skillnotok(skill_num, sd)) // [MoueJstr]
        return 0;

    sc_data = sd->sc_data;

    if (bool(sd->opt1))
        return 0;
    if (sc_data)
    {
        if (sc_data[SC_DIVINA].timer != -1 ||
            sc_data[SC_ROKISWEIL].timer != -1 ||
            sc_data[SC_AUTOCOUNTER].timer != -1 ||
            sc_data[SC_STEELBODY].timer != -1 ||
            sc_data[SC_DANCING].timer != -1 ||
            sc_data[SC_BERSERK].timer != -1)
            return 0;           /* 状態異常や沈黙など */
    }

    if (bool(sd->status.option & Option::HIDE2))
        return 0;

    sd->skillid = skill_num;
    sd->skilllv = skill_lv;
    sd->skillx = skill_x;
    sd->skilly = skill_y;
    if (!skill_check_condition(sd, 0))
        return 0;

    /* 射程と障害物チェック */
    bl.type = BL_NUL;
    bl.m = sd->bl.m;
    bl.x = skill_x;
    bl.y = skill_y;
    range = skill_get_range(skill_num, skill_lv);
    if (range < 0)
        range = battle_get_range(&sd->bl) - (range + 1);
    if (!battle_check_range(&sd->bl, &bl, range))
        return 0;

    pc_stopattack(sd);

    casttime = skill_castfix(&sd->bl, skill_get_cast(skill_num, skill_lv));
    delay = skill_delayfix(&sd->bl, skill_get_delay(skill_num, skill_lv));
    sd->state.skillcastcancel = skill_db[skill_num].castcancel;

    if (battle_config.pc_skill_log)
        printf("PC %d skill use target_pos= (%d,%d) skill=%d lv=%d cast=%d\n",
                sd->bl.id, skill_x, skill_y,
                uint16_t(skill_num), skill_lv, casttime);

//  if(sd->skillitem == skill_num)
//      casttime = delay = 0;
    //メモライズ状態ならキャストタイムが1/3
    if (sc_data && sc_data[SC_MEMORIZE].timer != -1 && casttime > 0)
    {
        casttime = casttime / 3;
        if ((--sc_data[SC_MEMORIZE].val2) <= 0)
            skill_status_change_end(&sd->bl, SC_MEMORIZE, -1);
    }

    if (casttime <= 0)          /* 詠唱の無いものはキャンセルされない */
        sd->state.skillcastcancel = 0;

    sd->skilltarget = 0;
/*      sd->cast_target_bl      = NULL; */
    tick = gettick();
    sd->canact_tick = tick + casttime + delay;
    sd->canmove_tick = tick;
    if (!(battle_config.pc_cloak_check_type & 2) && sc_data
        && sc_data[SC_CLOAKING].timer != -1)
        skill_status_change_end(&sd->bl, SC_CLOAKING, -1);
    if (casttime > 0)
    {
        sd->skilltimer =
            add_timer(tick + casttime, skill_castend_pos, sd->bl.id, 0);
        if ((skill = pc_checkskill(sd, SA_FREECAST)) > 0)
        {
            sd->prev_speed = sd->speed;
            sd->speed = sd->speed * (175 - skill * 5) / 100;
            clif_updatestatus(sd, SP_SPEED);
        }
        else
            pc_stop_walking(sd, 0);
    }
    else
    {
        sd->skilltimer = -1;
        skill_castend_pos(sd->skilltimer, tick, sd->bl.id, 0);
    }
    //マジックパワーの効果終了
    if (sc_data && sc_data[SC_MAGICPOWER].timer != -1
        && skill_num != HW_MAGICPOWER)
        skill_status_change_end(&sd->bl, SC_MAGICPOWER, -1);

    return 0;
}

/*==========================================
 * スキル詠唱キャンセル
 *------------------------------------------
 */
int skill_castcancel(struct block_list *bl, int type)
{
    int inf;

    nullpo_ret(bl);

    if (bl->type == BL_PC)
    {
        struct map_session_data *sd = (struct map_session_data *) bl;
        unsigned long tick = gettick();
        nullpo_ret(sd);
        sd->canact_tick = tick;
        sd->canmove_tick = tick;
        if (sd->skilltimer != -1)
        {
            if (pc_checkskill(sd, SA_FREECAST) > 0)
            {
                sd->speed = sd->prev_speed;
                clif_updatestatus(sd, SP_SPEED);
            }
            if (!type)
            {
                if ((inf = skill_get_inf(sd->skillid)) == 2 || inf == 32)
                    delete_timer(sd->skilltimer, skill_castend_pos);
                else
                    delete_timer(sd->skilltimer, skill_castend_id);
            }
            else
            {
                if ((inf = skill_get_inf(sd->skillid_old)) == 2 || inf == 32)
                    delete_timer(sd->skilltimer, skill_castend_pos);
                else
                    delete_timer(sd->skilltimer, skill_castend_id);
            }
            sd->skilltimer = -1;
            clif_skillcastcancel(bl);
        }

        return 0;
    }
    else if (bl->type == BL_MOB)
    {
        struct mob_data *md = (struct mob_data *) bl;
        nullpo_ret(md);
        if (md->skilltimer != -1)
        {
            if ((inf = skill_get_inf(md->skillid)) == 2 || inf == 32)
                delete_timer(md->skilltimer, mobskill_castend_pos);
            else
                delete_timer(md->skilltimer, mobskill_castend_id);
            md->skilltimer = -1;
            clif_skillcastcancel(bl);
        }
        return 0;
    }
    return 1;
}

/*=========================================
 * ブランディッシュスピア 初期範囲決定
 *----------------------------------------
 */
void skill_brandishspear_first(struct square *tc, int dir, int x, int y)
{

    nullpo_retv(tc);

    if (dir == 0)
    {
        tc->val1[0] = x - 2;
        tc->val1[1] = x - 1;
        tc->val1[2] = x;
        tc->val1[3] = x + 1;
        tc->val1[4] = x + 2;
        tc->val2[0] =
            tc->val2[1] = tc->val2[2] = tc->val2[3] = tc->val2[4] = y - 1;
    }
    else if (dir == 2)
    {
        tc->val1[0] =
            tc->val1[1] = tc->val1[2] = tc->val1[3] = tc->val1[4] = x + 1;
        tc->val2[0] = y + 2;
        tc->val2[1] = y + 1;
        tc->val2[2] = y;
        tc->val2[3] = y - 1;
        tc->val2[4] = y - 2;
    }
    else if (dir == 4)
    {
        tc->val1[0] = x - 2;
        tc->val1[1] = x - 1;
        tc->val1[2] = x;
        tc->val1[3] = x + 1;
        tc->val1[4] = x + 2;
        tc->val2[0] =
            tc->val2[1] = tc->val2[2] = tc->val2[3] = tc->val2[4] = y + 1;
    }
    else if (dir == 6)
    {
        tc->val1[0] =
            tc->val1[1] = tc->val1[2] = tc->val1[3] = tc->val1[4] = x - 1;
        tc->val2[0] = y + 2;
        tc->val2[1] = y + 1;
        tc->val2[2] = y;
        tc->val2[3] = y - 1;
        tc->val2[4] = y - 2;
    }
    else if (dir == 1)
    {
        tc->val1[0] = x - 1;
        tc->val1[1] = x;
        tc->val1[2] = x + 1;
        tc->val1[3] = x + 2;
        tc->val1[4] = x + 3;
        tc->val2[0] = y - 4;
        tc->val2[1] = y - 3;
        tc->val2[2] = y - 1;
        tc->val2[3] = y;
        tc->val2[4] = y + 1;
    }
    else if (dir == 3)
    {
        tc->val1[0] = x + 3;
        tc->val1[1] = x + 2;
        tc->val1[2] = x + 1;
        tc->val1[3] = x;
        tc->val1[4] = x - 1;
        tc->val2[0] = y - 1;
        tc->val2[1] = y;
        tc->val2[2] = y + 1;
        tc->val2[3] = y + 2;
        tc->val2[4] = y + 3;
    }
    else if (dir == 5)
    {
        tc->val1[0] = x + 1;
        tc->val1[1] = x;
        tc->val1[2] = x - 1;
        tc->val1[3] = x - 2;
        tc->val1[4] = x - 3;
        tc->val2[0] = y + 3;
        tc->val2[1] = y + 2;
        tc->val2[2] = y + 1;
        tc->val2[3] = y;
        tc->val2[4] = y - 1;
    }
    else if (dir == 7)
    {
        tc->val1[0] = x - 3;
        tc->val1[1] = x - 2;
        tc->val1[2] = x - 1;
        tc->val1[3] = x;
        tc->val1[4] = x + 1;
        tc->val2[1] = y;
        tc->val2[0] = y + 1;
        tc->val2[2] = y - 1;
        tc->val2[3] = y - 2;
        tc->val2[4] = y - 3;
    }

}

/*=========================================
 * ブランディッシュスピア 方向判定 範囲拡張
 *-----------------------------------------
 */
void skill_brandishspear_dir(struct square *tc, int dir, int are)
{

    int c;

    nullpo_retv(tc);

    for (c = 0; c < 5; c++)
    {
        if (dir == 0)
        {
            tc->val2[c] += are;
        }
        else if (dir == 1)
        {
            tc->val1[c] -= are;
            tc->val2[c] += are;
        }
        else if (dir == 2)
        {
            tc->val1[c] -= are;
        }
        else if (dir == 3)
        {
            tc->val1[c] -= are;
            tc->val2[c] -= are;
        }
        else if (dir == 4)
        {
            tc->val2[c] -= are;
        }
        else if (dir == 5)
        {
            tc->val1[c] += are;
            tc->val2[c] -= are;
        }
        else if (dir == 6)
        {
            tc->val1[c] += are;
        }
        else if (dir == 7)
        {
            tc->val1[c] += are;
            tc->val2[c] += are;
        }
    }
}

/*==========================================
 * ディボーション 有効確認
 *------------------------------------------
 */
void skill_devotion(struct map_session_data *md, int)
{
    // 総確認
    int n;

    nullpo_retv(md);

    for (n = 0; n < 5; n++)
    {
        if (md->dev.val1[n])
        {
            struct map_session_data *sd = map_id2sd(md->dev.val1[n]);
            // 相手が見つからない // 相手をディボしてるのが自分じゃない // 距離が離れてる
            if (sd == NULL
                || (md->bl.id != sd->sc_data[SC_DEVOTION].val1)
                || skill_devotion3(&md->bl, md->dev.val1[n]))
            {
                skill_devotion_end(md, sd, n);
            }
        }
    }
}

void skill_devotion2(struct block_list *bl, int crusader)
{
    // 被ディボーションが歩いた時の距離チェック
    struct map_session_data *sd = map_id2sd(crusader);

    nullpo_retv(bl);

    if (sd)
        skill_devotion3(&sd->bl, bl->id);
}

int skill_devotion3(struct block_list *bl, int target)
{
    // クルセが歩いた時の距離チェック
    struct map_session_data *md;
    struct map_session_data *sd;
    int n, r = 0;

    nullpo_retr(1, bl);

    if ((md = (struct map_session_data *) bl) == NULL
        || (sd = map_id2sd(target)) == NULL)
        return 1;
    else
        r = distance(bl->x, bl->y, sd->bl.x, sd->bl.y);

    if (pc_checkskill(sd, CR_DEVOTION) + 6 < r)
    {                           // 許容範囲を超えてた
        for (n = 0; n < 5; n++)
            if (md->dev.val1[n] == target)
                md->dev.val2[n] = 0;    // 離れた時は、糸を切るだけ
        return 1;
    }
    return 0;
}

void skill_devotion_end(struct map_session_data *md,
                         struct map_session_data *sd, int target)
{
    // クルセと被ディボキャラのリセット
    nullpo_retv(md);
    nullpo_retv(sd);

    md->dev.val1[target] = md->dev.val2[target] = 0;
    if (sd)
    {
        //  skill_status_change_end(sd->bl,SC_DEVOTION,-1);
        sd->sc_data[SC_DEVOTION].val1 = 0;
        sd->sc_data[SC_DEVOTION].val2 = 0;
        clif_status_change(&sd->bl, SC_DEVOTION, 0);
    }
}

/*==========================================
 * ギャングスターパラダイス判定処理(foreachinarea)
 *------------------------------------------
 */

static
void skill_gangster_count(struct block_list *bl, int *c)
{
    struct map_session_data *sd;

    nullpo_retv(bl);
    nullpo_retv(c);

    sd = (struct map_session_data *) bl;

    if (pc_issit(sd) && pc_checkskill(sd, RG_GANGSTER) > 0)
        (*c)++;
}

static
void skill_gangster_in(struct block_list *bl)
{
    struct map_session_data *sd;

    nullpo_retv(bl);

    sd = (struct map_session_data *) bl;

    if (pc_issit(sd) && pc_checkskill(sd, RG_GANGSTER) > 0)
        sd->state.gangsterparadise = 1;
}

static
void skill_gangster_out(struct block_list *bl)
{
    struct map_session_data *sd;

    nullpo_retv(bl);

    sd = (struct map_session_data *) bl;

    if (sd->state.gangsterparadise)
        sd->state.gangsterparadise = 0;
}

int skill_gangsterparadise(struct map_session_data *sd, int type)
{
    int range = 1;
    int c = 0;

    nullpo_ret(sd);

    if (pc_checkskill(sd, RG_GANGSTER) <= 0)
        return 0;

    if (type == 1)
    {                           /* 座った時の処理 */
        map_foreachinarea(std::bind(skill_gangster_count, ph::_1, &c),
                sd->bl.m, sd->bl.x - range, sd->bl.y - range,
                sd->bl.x + range, sd->bl.y + range, BL_PC);
        if (c > 0)
        {                       /*ギャングスター成功したら自分にもギャングスター属性付与 */
            map_foreachinarea(skill_gangster_in, sd->bl.m,
                               sd->bl.x - range, sd->bl.y - range,
                               sd->bl.x + range, sd->bl.y + range, BL_PC);
            sd->state.gangsterparadise = 1;
        }
        return 0;
    }
    else if (type == 0)
    {                           /* 立ち上がったときの処理 */
        map_foreachinarea(std::bind(skill_gangster_count, ph::_1, &c),
                sd->bl.m, sd->bl.x - range, sd->bl.y - range,
                sd->bl.x + range, sd->bl.y + range, BL_PC);
        if (c < 1)
            map_foreachinarea(skill_gangster_out, sd->bl.m,
                               sd->bl.x - range, sd->bl.y - range,
                               sd->bl.x + range, sd->bl.y + range, BL_PC);
        sd->state.gangsterparadise = 0;
        return 0;
    }
    return 0;
}

/*==========================================
 * 寒いジョーク・スクリーム判定処理(foreachinarea)
 *------------------------------------------
 */
void skill_frostjoke_scream(struct block_list *bl,
        struct block_list *src, SkillID skillnum, int skilllv, unsigned int tick)
{
    nullpo_retv(bl);
    nullpo_retv(src);

    if (src == bl)              //自分には効かない
        return;

    if (battle_check_target(src, bl, BCT_ENEMY) > 0)
        skill_additional_effect(src, bl, skillnum, skilllv, BF_MISC, tick);
    else if (battle_check_target(src, bl, BCT_PARTY) > 0)
    {
        if (MRAND(100) < 10)   //PTメンバにも低確率でかかる(とりあえず10%)
            skill_additional_effect(src, bl, skillnum, skilllv, BF_MISC,
                                     tick);
    }
}

/*==========================================
 *
 *------------------------------------------
 */
void skill_clear_element_field(struct block_list *bl)
{
    struct mob_data *md = NULL;
    struct map_session_data *sd = NULL;
    int i;

    nullpo_retv(bl);

    if (bl->type == BL_MOB)
        md = (struct mob_data *) bl;
    if (bl->type == BL_PC)
        sd = (struct map_session_data *) bl;

    for (i = 0; i < MAX_MOBSKILLUNITGROUP; i++)
    {
        if (sd)
        {
            SkillID skillid = sd->skillunit[i].skill_id;
            if (skillid == SA_DELUGE || skillid == SA_VOLCANO
                || skillid == SA_VIOLENTGALE || skillid == SA_LANDPROTECTOR)
                skill_delunitgroup(&sd->skillunit[i]);
        }
        else if (md)
        {
            SkillID skillid = md->skillunit[i].skill_id;
            if (skillid == SA_DELUGE || skillid == SA_VOLCANO
                || skillid == SA_VIOLENTGALE || skillid == SA_LANDPROTECTOR)
                skill_delunitgroup(&md->skillunit[i]);
        }
    }
}

/*==========================================
 * ランドプロテクターチェック(foreachinarea)
 *------------------------------------------
 */
void skill_landprotector(struct block_list *bl, SkillID skillid, int *alive)
{
    struct skill_unit *unit;

    nullpo_retv(bl);

    unit = (struct skill_unit *) bl;

    if (skillid == SA_LANDPROTECTOR)
    {
        skill_delunit(unit);
    }
    else
    {
        if (alive && unit->group->skill_id == SA_LANDPROTECTOR)
            (*alive) = 0;
    }
}

/*==========================================
 * イドゥンの林檎の回復処理(foreachinarea)
 *------------------------------------------
 */
static
void skill_idun_heal(struct block_list *bl, struct skill_unit *unit)
{
    struct skill_unit_group *sg;
    int heal;

    nullpo_retv(bl);
    nullpo_retv(unit);
    nullpo_retv(sg = unit->group);

    heal =
        30 + sg->skill_lv * 5 + ((sg->val1) >> 16) * 5 +
        ((sg->val1) & 0xfff) / 2;

    if (bl->type == BL_SKILL || bl->id == sg->src_id)
        return;

    if (bl->type == BL_PC || bl->type == BL_MOB)
    {
        battle_heal(NULL, bl, heal, 0, 0);
    }
}

/*==========================================
 * 指定範囲内でsrcに対して有効なターゲットのblの数を数える(foreachinarea)
 *------------------------------------------
 */
void skill_count_target(struct block_list *bl,
        struct block_list *src, int *c)
{
    nullpo_retv(bl);

    if (src == NULL)
        return;
    if (c == NULL)
        return;
    if (battle_check_target(src, bl, BCT_ENEMY) > 0)
        (*c)++;
}

/*==========================================
 * トラップ範囲処理(foreachinarea)
 *------------------------------------------
 */
void skill_trap_splash(struct block_list *bl,
        struct block_list *src, int tick, int splash_count)
{
    struct skill_unit *unit;
    struct skill_unit_group *sg;
    struct block_list *ss;
    int i;

    nullpo_retv(bl);
    nullpo_retv(src);
    unit = (struct skill_unit *) src;
    nullpo_retv(sg = unit->group);
    nullpo_retv(ss = map_id2bl(sg->src_id));

    if (battle_check_target(src, bl, BCT_ENEMY) > 0)
    {
        switch (sg->unit_id)
        {
            case 0x95:         /* サンドマン */
            case 0x96:         /* フラッシャー */
            case 0x94:         /* ショックウェーブトラップ */
                skill_additional_effect(ss, bl, sg->skill_id, sg->skill_lv,
                                         BF_MISC, tick);
                break;
            case 0x8f:         /* ブラストマイン */
            case 0x98:         /* クレイモアートラップ */
                for (i = 0; i < splash_count; i++)
                {
                    skill_attack(BF_MISC, ss, src, bl, sg->skill_id,
                                  sg->skill_lv, tick,
                                  (sg->val2) ? BCT_mid_x05 : BCT_ZERO);
                }
            case 0x97:         /* フリージングトラップ */
                skill_attack(BF_WEAPON, ss, src, bl, sg->skill_id,
                              sg->skill_lv, tick, (sg->val2) ? BCT_mid_x05 : BCT_ZERO);
                break;
            default:
                break;
        }
    }
}

/*----------------------------------------------------------------------------
 * ステータス異常
 *----------------------------------------------------------------------------
 */

/*==========================================
 * ステータス異常タイマー範囲処理
 *------------------------------------------
 */
void skill_status_change_timer_sub(struct block_list *bl,
        struct block_list *src, StatusChange type, unsigned int tick)
{
    nullpo_retv(bl);
    nullpo_retv(src);

    if (bl->type != BL_PC && bl->type != BL_MOB)
        return;

    switch (type)
    {
        case SC_SIGHT:         /* サイト */
        case SC_CONCENTRATE:
            if (bool((*battle_get_option(bl)) & (Option::HIDE2 | Option::CLOAK)))
            {
                skill_status_change_end(bl, SC_HIDING, -1);
                skill_status_change_end(bl, SC_CLOAKING, -1);
            }
            break;
        case SC_RUWACH:        /* ルアフ */
            if (bool((*battle_get_option(bl)) & (Option::HIDE2 | Option::CLOAK)))
            {
                skill_status_change_end(bl, SC_HIDING, -1);
                skill_status_change_end(bl, SC_CLOAKING, -1);
                if (battle_check_target(src, bl, BCT_ENEMY) > 0)
                {
                    eptr<struct status_change, StatusChange> sc_data = battle_get_sc_data(bl);
                    skill_attack(BF_MAGIC, src, src, bl, AL_RUWACH,
                                  sc_data[type].val1, tick, BCT_ZERO);
                }
            }
            break;
    }
}

/*==========================================
 * ステータス異常終了
 *------------------------------------------
 */
int skill_status_change_active(struct block_list *bl, StatusChange type)
{
    eptr<struct status_change, StatusChange> sc_data;

    nullpo_ret(bl);
    if (bl->type != BL_PC && bl->type != BL_MOB)
    {
        if (battle_config.error_log)
            printf("skill_status_change_active: neither MOB nor PC !\n");
        return 0;
    }

    sc_data = battle_get_sc_data(bl);
    if (not sc_data)
        return 0;

    return sc_data[type].timer != -1;
}

int skill_status_change_end(struct block_list *bl, StatusChange type, int tid)
{
    eptr<struct status_change, StatusChange> sc_data;
    int opt_flag = 0, calc_flag = 0;
    short *sc_count;
    Option *option;
    Opt1 *opt1;
    Opt2 *opt2;
    Opt3 *opt3;

    nullpo_ret(bl);
    if (bl->type != BL_PC && bl->type != BL_MOB)
    {
        if (battle_config.error_log)
            printf("skill_status_change_end: neither MOB nor PC !\n");
        return 0;
    }
    sc_data = battle_get_sc_data(bl);
    if (not sc_data)
        return 0;
    nullpo_ret(sc_count = battle_get_sc_count(bl));
    nullpo_ret(option = battle_get_option(bl));
    nullpo_ret(opt1 = battle_get_opt1(bl));
    nullpo_ret(opt2 = battle_get_opt2(bl));
    nullpo_ret(opt3 = battle_get_opt3(bl));

    if ((*sc_count) > 0 && sc_data[type].timer != -1
        && (sc_data[type].timer == tid || tid == -1))
    {

        if (tid == -1)          // タイマから呼ばれていないならタイマ削除をする
            delete_timer(sc_data[type].timer, skill_status_change_timer);

        /* 該当の異常を正常に戻す */
        sc_data[type].timer = -1;
        (*sc_count)--;

        switch (type)
        {                       /* 異常の種類ごとの処理 */
            case SC_PROVOKE:   /* プロボック */
            case SC_CONCENTRATE:   /* 集中力向上 */
            case SC_BLESSING:  /* ブレッシング */
            case SC_ANGELUS:   /* アンゼルス */
            case SC_INCREASEAGI:   /* 速度上昇 */
            case SC_DECREASEAGI:   /* 速度減少 */
            case SC_SIGNUMCRUCIS:  /* シグナムクルシス */
            case SC_HIDING:
            case SC_TWOHANDQUICKEN:    /* 2HQ */
            case SC_ADRENALINE:    /* アドレナリンラッシュ */
            case SC_ENCPOISON: /* エンチャントポイズン */
            case SC_IMPOSITIO: /* インポシティオマヌス */
            case SC_GLORIA:    /* グロリア */
            case SC_LOUD:      /* ラウドボイス */
            case SC_QUAGMIRE:  /* クァグマイア */
            case SC_PROVIDENCE:    /* プロヴィデンス */
            case SC_SPEARSQUICKEN: /* スピアクイッケン */
            case SC_VOLCANO:
            case SC_DELUGE:
            case SC_VIOLENTGALE:
            case SC_ETERNALCHAOS:  /* エターナルカオス */
            case SC_DRUMBATTLE:    /* 戦太鼓の響き */
            case SC_NIBELUNGEN:    /* ニーベルングの指輪 */
            case SC_SIEGFRIED: /* 不死身のジークフリード */
            case SC_WHISTLE:   /* 口笛 */
            case SC_ASSNCROS:  /* 夕陽のアサシンクロス */
            case SC_HUMMING:   /* ハミング */
            case SC_DONTFORGETME:  /* 私を忘れないで */
            case SC_FORTUNE:   /* 幸運のキス */
            case SC_SERVICE4U: /* サービスフォーユー */
            case SC_EXPLOSIONSPIRITS:  // 爆裂波動
            case SC_STEELBODY: // 金剛
            case SC_DEFENDER:
            case SC_SPEEDPOTION0:  /* 増速ポーション */
            case SC_SPEEDPOTION1:
            case SC_SPEEDPOTION2:
            case SC_APPLEIDUN: /* イドゥンの林檎 */
            case SC_RIDING:
            case SC_BLADESTOP_WAIT:
            case SC_AURABLADE: /* オーラブレード */
            case SC_PARRYING:  /* パリイング */
            case SC_CONCENTRATION: /* コンセントレーション */
            case SC_TENSIONRELAX:  /* テンションリラックス */
            case SC_ASSUMPTIO: /* アシャンプティオ */
            case SC_WINDWALK:  /* ウインドウォーク */
            case SC_TRUESIGHT: /* トゥルーサイト */
            case SC_SPIDERWEB: /* スパイダーウェッブ */
            case SC_MAGICPOWER:    /* 魔法力増幅 */
            case SC_CHASEWALK:
            case SC_ATKPOT:    /* attack potion [Valaris] */
            case SC_MATKPOT:   /* magic attack potion [Valaris] */
            case SC_WEDDING:   //結婚用(結婚衣裳になって歩くのが遅いとか)
            case SC_MELTDOWN:  /* メルトダウン */
            case SC_PHYS_SHIELD:
            case SC_HASTE:
                calc_flag = 1;
                break;
            case SC_BERSERK:   /* バーサーク */
                calc_flag = 1;
                clif_status_change(bl, SC_INCREASEAGI, 0); /* アイコン消去 */
                break;
            case SC_DEVOTION:  /* ディボーション */
            {
                struct map_session_data *md = map_id2sd(sc_data[type].val1);
                sc_data[type].val1 = sc_data[type].val2 = 0;
                skill_devotion(md, bl->id);
                calc_flag = 1;
            }
                break;
            case SC_BLADESTOP:
            {
                eptr<struct status_change, StatusChange> t_sc_data =
                    battle_get_sc_data((struct block_list *)
                                        sc_data[type].val4);
                //片方が切れたので相手の白刃状態が切れてないのなら解除
                if (t_sc_data && t_sc_data[SC_BLADESTOP].timer != -1)
                    skill_status_change_end((struct block_list *)
                                             sc_data[type].val4, SC_BLADESTOP,
                                             -1);

            }
                break;
            case SC_DANCING:
            {
                struct map_session_data *dsd;
                eptr<struct status_change, StatusChange> d_sc_data;
                if (sc_data[type].val4
                    && (dsd = map_id2sd(sc_data[type].val4)))
                {
                    d_sc_data = dsd->sc_data;
                    //合奏で相手がいる場合相手のval4を0にする
                    if (d_sc_data && d_sc_data[type].timer != -1)
                        d_sc_data[type].val4 = 0;
                }
            }
                calc_flag = 1;
                break;
            case SC_GRAFFITI:
            {
                struct skill_unit_group *sg = (struct skill_unit_group *) sc_data[type].val4;   //val4がグラフィティのgroup_id
                if (sg)
                    skill_delunitgroup(sg);
            }
                break;
            case SC_NOCHAT:    //チャット禁止状態
                break;
            case SC_SPLASHER:  /* ベナムスプラッシャー */
            {
                struct block_list *src = map_id2bl(sc_data[type].val3);
                if (src && tid != -1)
                {
                    //自分にダメージ&周囲3*3にダメージ
                    skill_castend_damage_id(src, bl,
                            SkillID(sc_data[type].val2), sc_data[type].val1,
                            gettick(), BCT_ZERO);
                }
            }
                break;
            case SC_SELFDESTRUCTION:   /* 自爆 */
            {
                //自分のダメージは0にして
                struct mob_data *md = NULL;
                if (bl->type == BL_MOB && (md = (struct mob_data *) bl))
                    skill_castend_damage_id(bl, bl,
                           SkillID( sc_data[type].val2), sc_data[type].val1,
                           gettick(), BCT_ZERO);
            }
                break;
                /* option1 */
            case SC_FREEZE:
                sc_data[type].val3 = 0;
                break;

                /* option2 */
            case SC_POISON:    /* 毒 */
            case SC_BLIND:     /* 暗黒 */
            case SC_CURSE:
                calc_flag = 1;
                break;
        }

        if (bl->type == BL_PC && type < SC_SENDMAX)
            clif_status_change(bl, type, 0);   /* アイコン消去 */

        switch (type)
        {                       /* 正常に戻るときなにか処理が必要 */
            case SC_STONE:
            case SC_FREEZE:
            case SC_STAN:
            case SC_SLEEP:
                *opt1 = Opt1::ZERO;
                opt_flag = 1;
                break;

            case SC_POISON:
                *opt2 &= ~Opt2::_poison;
                opt_flag = 1;
                break;

            case SC_CURSE:
                *opt2 &= ~Opt2::_curse;
                opt_flag = 1;
                break;

            case SC_SILENCE:
                *opt2 &= ~Opt2::_silence;
                opt_flag = 1;
                break;

            case SC_BLIND:
                *opt2 &= ~Opt2::BLIND;
                opt_flag = 1;
                break;

            case SC_SLOWPOISON:
                if (sc_data[SC_POISON].timer != -1)
                    *opt2 |= Opt2::_poison;
                *opt2 &= ~Opt2::_slowpoison;
                opt_flag = 1;
                break;

            case SC_SIGNUMCRUCIS:
                *opt2 &= ~Opt2::_signumcrucis;
                opt_flag = 1;
                break;

            case SC_SPEEDPOTION0:
                *opt2 &= ~Opt2::_speedpotion0;
                opt_flag = 1;
                break;

            case SC_ATKPOT:
                *opt2 &= ~Opt2::_atkpot;
                opt_flag = 1;
                break;

            case SC_HIDING:
                *option &= ~Option::HIDE2;
                opt_flag = 1;
                break;

            case SC_CLOAKING:
                *option &= ~Option::CLOAK;
                opt_flag = 1;
                break;

            case SC_CHASEWALK:
                *option &= ~Option::CHASEWALK;
                opt_flag = 1;
                break;

            case SC_SIGHT:
                *option &= ~Option::SIGHT;
                opt_flag = 1;
                break;
            case SC_WEDDING:   //結婚用(結婚衣裳になって歩くのが遅いとか)
                *option &= ~Option::_wedding;
                opt_flag = 1;
                break;
            case SC_RUWACH:
                *option &= ~Option::_ruwach;
                opt_flag = 1;
                break;

                //opt3
            case SC_TWOHANDQUICKEN:    /* 2HQ */
            case SC_SPEARSQUICKEN: /* スピアクイッケン */
            case SC_CONCENTRATION: /* コンセントレーション */
                *opt3 &= ~Opt3::_concentration;
                break;
            case SC_OVERTHRUST:    /* オーバースラスト */
                *opt3 &= ~Opt3::_overthrust;
                break;
            case SC_ENERGYCOAT:    /* エナジーコート */
                *opt3 &= ~Opt3::_energycoat;
                break;
            case SC_EXPLOSIONSPIRITS:  // 爆裂波動
                *opt3 &= ~Opt3::_explosionspirits;
                break;
            case SC_STEELBODY: // 金剛
                *opt3 &= ~Opt3::_steelbody;
                break;
            case SC_BLADESTOP: /* 白刃取り */
                *opt3 &= ~Opt3::_bladestop;
                break;
            case SC_BERSERK:   /* バーサーク */
                *opt3 &= ~Opt3::_berserk;
                break;
            case SC_MARIONETTE:    /* マリオネットコントロール */
                *opt3 &= ~Opt3::_marionette;
                break;
            case SC_ASSUMPTIO: /* アスムプティオ */
                *opt3 &= ~Opt3::_assumptio;
                break;
        }

        if (night_flag == 1
            && !bool(*opt2 & Opt2::BLIND)
            && bl->type == BL_PC)
        {                       // by [Yor]
            *opt2 |= Opt2::BLIND;
            opt_flag = 1;
        }

        if (opt_flag)           /* optionの変更を伝える */
            clif_changeoption(bl);

        if (bl->type == BL_PC && calc_flag)
            pc_calcstatus((struct map_session_data *) bl, 0);  /* ステータス再計算 */
    }

    return 0;
}

int skill_update_heal_animation(struct map_session_data *sd)
{
    const Opt2 mask = Opt2::_heal;

    nullpo_ret(sd);
    bool was_active = bool(sd->opt2 & mask);
    bool is_active = sd->quick_regeneration_hp.amount > 0;

    if (was_active == is_active)
        return 0;               // no update

    if (is_active)
        sd->opt2 |= mask;
    else
        sd->opt2 &= ~mask;

    return clif_changeoption(&sd->bl);
}

/*==========================================
 * ステータス異常終了タイマー
 *------------------------------------------
 */
void skill_status_change_timer(timer_id tid, tick_t tick, custom_id_t id, custom_data_t data)
{
    StatusChange type = StatusChange(data);
    struct block_list *bl;
    struct map_session_data *sd = NULL;
    eptr<struct status_change, StatusChange> sc_data;
    //short *sc_count; //使ってない?

    if ((bl = map_id2bl(id)) == NULL)
        return;
    //該当IDがすでに消滅しているというのはいかにもありそうなのでスルーしてみる
    sc_data = battle_get_sc_data(bl);
    if (not sc_data)
        return;

    if (bl->type == BL_PC)
        sd = (struct map_session_data *) bl;

    //sc_count=battle_get_sc_count(bl); //使ってない?

    if (sc_data[type].timer != tid)
    {
        if (battle_config.error_log)
            printf("skill_status_change_timer %d != %d\n", tid,
                    sc_data[type].timer);
    }

    if (sc_data[type].spell_invocation)
    {                           // Must report termination
        spell_effect_report_termination(sc_data[type].spell_invocation,
                                         bl->id, type, 0);
        sc_data[type].spell_invocation = 0;
    }

    switch (type)
    {                           /* 特殊な処理になる場合 */
        case SC_MAXIMIZEPOWER: /* マキシマイズパワー */
        case SC_CLOAKING:      /* クローキング */
        case SC_CHASEWALK:
            if (sd)
            {
                if (sd->status.sp > 0)
                {               /* SP切れるまで持続 */
                    sd->status.sp--;
                    clif_updatestatus(sd, SP_SP);
                    sc_data[type].timer = add_timer(   /* タイマー再設定 */
                                                        sc_data[type].val2 +
                                                        tick,
                                                        skill_status_change_timer,
                                                        bl->id, data);
                    return;
                }
            }
            break;

        case SC_HIDING:        /* ハイディング */
            if (sd)
            {                   /* SPがあって、時間制限の間は持続 */
                if (sd->status.sp > 0 && (--sc_data[type].val2) > 0)
                {
                    if (sc_data[type].val2 % (sc_data[type].val1 + 3) == 0)
                    {
                        sd->status.sp--;
                        clif_updatestatus(sd, SP_SP);
                    }
                    sc_data[type].timer = add_timer(   /* タイマー再設定 */
                                                        1000 + tick,
                                                        skill_status_change_timer,
                                                        bl->id, data);
                    return;
                }
            }
            break;

        case SC_SIGHT:         /* サイト */
        {
            const int range = 7;
            map_foreachinarea(std::bind(skill_status_change_timer_sub, ph::_1, bl, type, tick),
                    bl->m, bl->x - range, bl->y - range,
                    bl->x + range, bl->y + range, BL_NUL);

            if ((--sc_data[type].val2) > 0)
            {
                sc_data[type].timer = add_timer(   /* タイマー再設定 */
                                                    250 + tick,
                                                    skill_status_change_timer,
                                                    bl->id, data);
                return;
            }
        }
            break;
        case SC_RUWACH:        /* ルアフ */
        {
            const int range = 5;
            map_foreachinarea(std::bind(skill_status_change_timer_sub, ph::_1, bl, type, tick),
                    bl->m, bl->x - range, bl->y - range,
                    bl->x + range, bl->y + range, BL_NUL);

            if ((--sc_data[type].val2) > 0)
            {
                sc_data[type].timer = add_timer(   /* タイマー再設定 */
                                                    250 + tick,
                                                    skill_status_change_timer,
                                                    bl->id, data);
                return;
            }
        }
            break;

        case SC_SIGNUMCRUCIS:  /* シグナムクルシス */
        {
            int race = battle_get_race(bl);
            if (race == 6
                || battle_check_undead(race, battle_get_elem_type(bl)))
            {
                sc_data[type].timer =
                    add_timer(1000 * 600 + tick, skill_status_change_timer,
                               bl->id, data);
                return;
            }
        }
            break;

        case SC_PROVOKE:       /* プロボック/オートバーサーク */
            if (sc_data[type].val2 != 0)
            {                   /* オートバーサーク(1秒ごとにHPチェック) */
                if (sd && sd->status.hp > sd->status.max_hp >> 2)   /* 停止 */
                    break;
                sc_data[type].timer =
                    add_timer(1000 + tick, skill_status_change_timer, bl->id,
                               data);
                return;
            }
            break;

        case SC_WATERBALL:     /* ウォーターボール */
        {
            struct block_list *target = map_id2bl(sc_data[type].val2);
            if (target == NULL || target->prev == NULL)
                break;
            skill_attack(BF_MAGIC, bl, bl, target, WZ_WATERBALL,
                          sc_data[type].val1, tick, BCT_ZERO);
            if ((--sc_data[type].val3) > 0)
            {
                sc_data[type].timer =
                    add_timer(150 + tick, skill_status_change_timer, bl->id,
                               data);
                return;
            }
        }
            break;

        case SC_ENDURE:        /* インデュア */
            if (sd && sd->special_state.infinite_endure)
            {
                sc_data[type].timer =
                    add_timer(1000 * 600 + tick, skill_status_change_timer,
                               bl->id, data);
                sc_data[type].val2 = 1;
                return;
            }
            break;

        case SC_DISSONANCE:    /* 不協和音 */
            if ((--sc_data[type].val2) > 0)
            {
                struct skill_unit *unit =
                    (struct skill_unit *) sc_data[type].val4;
                struct block_list *src;

                if (!unit || !unit->group)
                    break;
                src = map_id2bl(unit->group->src_id);
                if (!src)
                    break;
                skill_attack(BF_MISC, src, &unit->bl, bl,
                              unit->group->skill_id, sc_data[type].val1, tick,
                              BCT_ZERO);
                sc_data[type].timer =
                    add_timer(skill_get_time2(unit->group->skill_id,
                                unit->group->skill_lv) + tick,
                               skill_status_change_timer, bl->id, data);
                return;
            }
            break;

        case SC_LULLABY:       /* 子守唄 */
            if ((--sc_data[type].val2) > 0)
            {
                struct skill_unit *unit =
                    (struct skill_unit *) sc_data[type].val4;
                if (!unit || !unit->group || unit->group->src_id == bl->id)
                    break;
                skill_additional_effect(bl, bl, unit->group->skill_id,
                                         sc_data[type].val1,
                                         BF_LONG | BF_SKILL | BF_MISC, tick);
                sc_data[type].timer =
                    add_timer(skill_get_time(unit->group->skill_id,
                                unit->group->skill_lv) / 10 + tick,
                               skill_status_change_timer, bl->id, data);
                return;
            }
            break;

        case SC_STONE:
            if (sc_data[type].val2 != 0)
            {
                Opt1 *opt1 = battle_get_opt1(bl);
                sc_data[type].val2 = 0;
                sc_data[type].val4 = 0;
                battle_stopwalking(bl, 1);
                if (opt1)
                {
                    *opt1 = Opt1::_stone1;
                    clif_changeoption(bl);
                }
                sc_data[type].timer =
                    add_timer(1000 + tick, skill_status_change_timer, bl->id,
                               data);
                return;
            }
            else if ((--sc_data[type].val3) > 0)
            {
                int hp = battle_get_max_hp(bl);
                if ((++sc_data[type].val4) % 5 == 0
                    && battle_get_hp(bl) > hp >> 2)
                {
                    hp = hp / 100;
                    if (hp < 1)
                        hp = 1;
                    if (bl->type == BL_PC)
                        pc_heal((struct map_session_data *) bl, -hp, 0);
                    else if (bl->type == BL_MOB)
                    {
                        struct mob_data *md;
                        if ((md = ((struct mob_data *) bl)) == NULL)
                            break;
                        md->hp -= hp;
                    }
                }
                sc_data[type].timer =
                    add_timer(1000 + tick, skill_status_change_timer, bl->id,
                               data);
                return;
            }
            break;
        case SC_POISON:
            if (sc_data[SC_SLOWPOISON].timer == -1)
            {
                const int resist_poison =
                    skill_power_bl(bl, TMW_RESIST_POISON) >> 3;
                if (resist_poison)
                    sc_data[type].val1 -= MRAND(resist_poison + 1);

                if ((--sc_data[type].val1) > 0)
                {

                    int hp = battle_get_max_hp(bl);
                    if (battle_get_hp(bl) > hp >> 4)
                    {
                        if (bl->type == BL_PC)
                        {
                            hp = 3 + hp * 3 / 200;
                            pc_heal((struct map_session_data *) bl, -hp, 0);
                        }
                        else if (bl->type == BL_MOB)
                        {
                            struct mob_data *md;
                            if ((md = ((struct mob_data *) bl)) == NULL)
                                break;
                            hp = 3 + hp / 200;
                            md->hp -= hp;
                        }
                    }
                    sc_data[type].timer =
                        add_timer(1000 + tick, skill_status_change_timer,
                                   bl->id, data);
                }
            }
            else
                sc_data[type].timer =
                    add_timer(2000 + tick, skill_status_change_timer, bl->id,
                               data);
            break;

        case SC_TENSIONRELAX:  /* テンションリラックス */
            if (sd)
            {                   /* SPがあって、HPが満タンでなければ継続 */
                if (sd->status.sp > 12 && sd->status.max_hp > sd->status.hp)
                {
                    if (sc_data[type].val2 % (sc_data[type].val1 + 3) == 0)
                    {
                        sd->status.sp -= 12;
                        clif_updatestatus(sd, SP_SP);
                    }
                    sc_data[type].timer = add_timer(   /* タイマー再設定 */
                                                        10000 + tick,
                                                        skill_status_change_timer,
                                                        bl->id, data);
                    return;
                }
                if (sd->status.max_hp <= sd->status.hp)
                    skill_status_change_end(&sd->bl, SC_TENSIONRELAX, -1);
            }
            break;

            /* 時間切れ無し?? */
        case SC_AETERNA:
        case SC_TRICKDEAD:
        case SC_RIDING:
        case SC_FALCON:
        case SC_WEIGHT50:
        case SC_WEIGHT90:
        case SC_MAGICPOWER:    /* 魔法力増幅 */
        case SC_REJECTSWORD:   /* リジェクトソード */
        case SC_MEMORIZE:      /* メモライズ */
        case SC_BROKNWEAPON:
        case SC_BROKNARMOR:
            if (sc_data[type].timer == tid)
                sc_data[type].timer =
                    add_timer(1000 * 600 + tick, skill_status_change_timer,
                               bl->id, data);
            return;

        case SC_DANCING:       //ダンススキルの時間SP消費
        {
            int s = 0;
            if (sd)
            {
                if (sd->status.sp > 0 && (--sc_data[type].val3) > 0)
                {
                    switch (SkillID(sc_data[type].val1))
                    {
                        case BD_RICHMANKIM:    /* ニヨルドの宴 3秒にSP1 */
                        case BD_DRUMBATTLEFIELD:   /* 戦太鼓の響き 3秒にSP1 */
                        case BD_RINGNIBELUNGEN:    /* ニーベルングの指輪 3秒にSP1 */
                        case BD_SIEGFRIED: /* 不死身のジークフリード 3秒にSP1 */
                        case BA_DISSONANCE:    /* 不協和音 3秒でSP1 */
                        case BA_ASSASSINCROSS: /* 夕陽のアサシンクロス 3秒でSP1 */
                        case DC_UGLYDANCE: /* 自分勝手なダンス 3秒でSP1 */
                            s = 3;
                            break;
                        case BD_LULLABY:   /* 子守歌 4秒にSP1 */
                        case BD_ETERNALCHAOS:  /* 永遠の混沌 4秒にSP1 */
                        case BD_ROKISWEIL: /* ロキの叫び 4秒にSP1 */
                        case DC_FORTUNEKISS:   /* 幸運のキス 4秒でSP1 */
                            s = 4;
                            break;
                        case BD_INTOABYSS: /* 深淵の中に 5秒にSP1 */
                        case BA_WHISTLE:   /* 口笛 5秒でSP1 */
                        case DC_HUMMING:   /* ハミング 5秒でSP1 */
                        case BA_POEMBRAGI: /* ブラギの詩 5秒でSP1 */
                        case DC_SERVICEFORYOU: /* サービスフォーユー 5秒でSP1 */
                            s = 5;
                            break;
                        case BA_APPLEIDUN: /* イドゥンの林檎 6秒でSP1 */
                            s = 6;
                            break;
                        case DC_DONTFORGETME:  /* 私を忘れないで… 10秒でSP1 */
                        case CG_MOONLIT:   /* 月明りの泉に落ちる花びら 10秒でSP1? */
                            s = 10;
                            break;
                    }
                    if (s && ((sc_data[type].val3 % s) == 0))
                    {
                        sd->status.sp--;
                        clif_updatestatus(sd, SP_SP);
                    }
                    sc_data[type].timer = add_timer(   /* タイマー再設定 */
                                                        1000 + tick,
                                                        skill_status_change_timer,
                                                        bl->id, data);
                    return;
                }
            }
        }
            break;
        case SC_BERSERK:       /* バーサーク */
            if (sd)
            {                   /* HPが100以上なら継続 */
                if ((sd->status.hp - sd->status.hp / 100) > 100)
                {
                    sd->status.hp -= sd->status.hp / 100;
                    clif_updatestatus(sd, SP_HP);
                    sc_data[type].timer = add_timer(   /* タイマー再設定 */
                                                        15000 + tick,
                                                        skill_status_change_timer,
                                                        bl->id, data);
                    return;
                }
            }
            break;
        case SC_WEDDING:       //結婚用(結婚衣裳になって歩くのが遅いとか)
            if (sd)
            {
                time_t timer;
                if (time(&timer) < ((sc_data[type].val2) + 3600))
                {               //1時間たっていないので継続
                    sc_data[type].timer = add_timer(   /* タイマー再設定 */
                                                        10000 + tick,
                                                        skill_status_change_timer,
                                                        bl->id, data);
                    return;
                }
            }
            break;
        case SC_NOCHAT:        //チャット禁止状態
            if (sd && battle_config.muting_players)
            {
                time_t timer;
                if ((++sd->status.manner)
                    && time(&timer) <
                    ((sc_data[type].val2) + 60 * (0 - sd->status.manner)))
                {               //開始からstatus.manner分経ってないので継続
                    sc_data[type].timer = add_timer(   /* タイマー再設定(60秒) */
                                                        60000 + tick,
                                                        skill_status_change_timer,
                                                        bl->id, data);
                    return;
                }
            }
            break;
        case SC_SELFDESTRUCTION:   /* 自爆 */
            if (--sc_data[type].val3 > 0)
            {
                struct mob_data *md;
                if (bl->type == BL_MOB && (md = (struct mob_data *) bl)
                    && md->stats[MOB_SPEED] > 250)
                {
                    md->stats[MOB_SPEED] -= 250;
                    md->next_walktime = tick;
                }
                sc_data[type].timer = add_timer(   /* タイマー再設定 */
                                                    1000 + tick,
                                                    skill_status_change_timer,
                                                    bl->id, data);
                return;
            }
            break;

        case SC_FLYING_BACKPACK:
            clif_updatestatus(sd, SP_WEIGHT);
            break;

    }

    skill_status_change_end(bl, type, tid);
}

/*==========================================
 * ステータス異常終了
 *------------------------------------------
 */
int skill_encchant_eremental_end(struct block_list *bl, StatusChange type)
{
    eptr<struct status_change, StatusChange> sc_data;

    nullpo_ret(bl);
    sc_data = battle_get_sc_data(bl);
    if (not sc_data)
        return 0;

    if (type != SC_ENCPOISON && sc_data[SC_ENCPOISON].timer != -1)  /* エンチャントポイズン解除 */
        skill_status_change_end(bl, SC_ENCPOISON, -1);
    if (type != SC_ASPERSIO && sc_data[SC_ASPERSIO].timer != -1)    /* アスペルシオ解除 */
        skill_status_change_end(bl, SC_ASPERSIO, -1);
    if (type != SC_FLAMELAUNCHER && sc_data[SC_FLAMELAUNCHER].timer != -1)  /* フレイムランチャ解除 */
        skill_status_change_end(bl, SC_FLAMELAUNCHER, -1);
    if (type != SC_FROSTWEAPON && sc_data[SC_FROSTWEAPON].timer != -1)  /* フロストウェポン解除 */
        skill_status_change_end(bl, SC_FROSTWEAPON, -1);
    if (type != SC_LIGHTNINGLOADER && sc_data[SC_LIGHTNINGLOADER].timer != -1)  /* ライトニングローダー解除 */
        skill_status_change_end(bl, SC_LIGHTNINGLOADER, -1);
    if (type != SC_SEISMICWEAPON && sc_data[SC_SEISMICWEAPON].timer != -1)  /* サイスミックウェポン解除 */
        skill_status_change_end(bl, SC_SEISMICWEAPON, -1);

    return 0;
}

/*==========================================
 * ステータス異常開始
 *------------------------------------------
 */
int skill_status_change_start(struct block_list *bl, StatusChange type,
        int val1, int val2, int val3, int val4,
        int tick, int flag)
{
    return skill_status_effect(bl, type, val1, val2, val3, val4, tick, flag,
                                0);
}

int skill_status_effect(struct block_list *bl, StatusChange type,
        int val1, int val2, int val3, int val4,
        int tick, int flag, int spell_invocation)
{
    struct map_session_data *sd = NULL;
    eptr<struct status_change, StatusChange> sc_data;
    short *sc_count;
    Option *option;
    Opt1 *opt1;
    Opt2 *opt2;
    Opt3 *opt3;
    int opt_flag = 0, calc_flag = 0;
    int race, mode, elem, undead_flag;
    SP updateflag;
    int scdef = 0;

    nullpo_ret(bl);
    if (bl->type == BL_SKILL)
        return 0;
    sc_data = battle_get_sc_data(bl);
    if (not sc_data)
        return 0;
    nullpo_ret(sc_count = battle_get_sc_count(bl));
    nullpo_ret(option = battle_get_option(bl));
    nullpo_ret(opt1 = battle_get_opt1(bl));
    nullpo_ret(opt2 = battle_get_opt2(bl));
    nullpo_ret(opt3 = battle_get_opt3(bl));

    race = battle_get_race(bl);
    mode = battle_get_mode(bl);
    elem = battle_get_elem_type(bl);
    undead_flag = battle_check_undead(race, elem);

    if (type == SC_AETERNA
        && (sc_data[SC_STONE].timer != -1 || sc_data[SC_FREEZE].timer != -1))
        return 0;

    switch (type)
    {
        case SC_STONE:
        case SC_FREEZE:
            scdef = 3 + battle_get_mdef(bl) + battle_get_luk(bl) / 3;
            break;
        case SC_STAN:
        case SC_SILENCE:
        case SC_POISON:
            scdef = 3 + battle_get_vit(bl) + battle_get_luk(bl) / 3;
            break;
        case SC_SLEEP:
        case SC_BLIND:
            scdef = 3 + battle_get_int(bl) + battle_get_luk(bl) / 3;
            break;
        case SC_CURSE:
            scdef = 3 + battle_get_luk(bl);
            break;

//      case SC_CONFUSION:
        default:
            scdef = 0;
    }
    if (scdef >= 100)
        return 0;
    if (bl->type == BL_PC)
    {
        sd = (struct map_session_data *) bl;
        if (sd && type == SC_ADRENALINE
            && !(skill_get_weapontype(BS_ADRENALINE) &
                 (1 << sd->status.weapon)))
            return 0;

        if (SC_STONE <= type && type <= SC_BLIND)
        {
            BadSC bsc = BadSC_from_SC(type);
            /* カードによる耐性 */
            if (sd && sd->reseff[bsc] > 0
                && MRAND(10000) < sd->reseff[bsc])
            {
                if (battle_config.battle_log)
                    printf("PC %d skill_sc_start: cardによる異常耐性発動\n",
                            sd->bl.id);
                return 0;
            }
        }
    }
    else if (bl->type == BL_MOB)
    {
    }
    else
    {
        if (battle_config.error_log)
            printf("skill_status_change_start: neither MOB nor PC !\n");
        return 0;
    }

    if (type == SC_FREEZE && undead_flag && !(flag & 1))
        return 0;

    if ((type == SC_ADRENALINE || type == SC_WEAPONPERFECTION
         || type == SC_OVERTHRUST) && sc_data[type].timer != -1
        && sc_data[type].val2 && !val2)
        return 0;

    if (mode & 0x20 && (type == SC_STONE || type == SC_FREEZE ||
                        type == SC_STAN || type == SC_SLEEP
                        || type == SC_SILENCE || type == SC_QUAGMIRE
                        || type == SC_DECREASEAGI || type == SC_SIGNUMCRUCIS
                        || type == SC_PROVOKE || (type == SC_BLESSING
                                                  && (undead_flag
                                                      || race == 6)))
        && !(flag & 1))
    {
        /* ボスには効かない(ただしカードによる効果は適用される) */
        return 0;
    }
    if (type == SC_FREEZE || type == SC_STAN || type == SC_SLEEP)
        battle_stopwalking(bl, 1);

    if (sc_data[type].timer != -1)
    {                           /* すでに同じ異常になっている場合タイマ解除 */
        if (sc_data[type].val1 > val1 && type != SC_COMBO && type != SC_DANCING && type != SC_DEVOTION && type != SC_SPEEDPOTION0 && type != SC_SPEEDPOTION1 && type != SC_SPEEDPOTION2 && type != SC_ATKPOT && type != SC_MATKPOT) // added atk and matk potions [Valaris]
            return 0;
        if (type >= SC_STAN && type <= SC_BLIND)
            return 0;           /* 継ぎ足しができない状態異常である時は状態異常を行わない */
        if (type == SC_GRAFFITI)
        {                       //異常中にもう一度状態異常になった時に解除してから再度かかる
            skill_status_change_end(bl, type, -1);
        }
        else
        {
            (*sc_count)--;
            delete_timer(sc_data[type].timer, skill_status_change_timer);
            sc_data[type].timer = -1;
        }
    }

    switch (type)
    {                           /* 異常の種類ごとの処理 */
        case SC_PROVOKE:       /* プロボック */
            calc_flag = 1;
            if (tick <= 0)
                tick = 1000;    /* (オートバーサーク) */
            break;
        case SC_ENDURE:        /* インデュア */
            if (tick <= 0)
                tick = 1000 * 60;
            break;
        case SC_CONCENTRATE:   /* 集中力向上 */
            calc_flag = 1;
            break;
        case SC_BLESSING:      /* ブレッシング */
        {
            if (bl->type == BL_PC || (!undead_flag && race != 6))
            {
                if (sc_data[SC_CURSE].timer != -1)
                    skill_status_change_end(bl, SC_CURSE, -1);
                if (sc_data[SC_STONE].timer != -1
                    && sc_data[SC_STONE].val2 == 0)
                    skill_status_change_end(bl, SC_STONE, -1);
            }
            calc_flag = 1;
        }
            break;
        case SC_ANGELUS:       /* アンゼルス */
            calc_flag = 1;
            break;
        case SC_INCREASEAGI:   /* 速度上昇 */
            calc_flag = 1;
            if (sc_data[SC_DECREASEAGI].timer != -1)
                skill_status_change_end(bl, SC_DECREASEAGI, -1);
            if (sc_data[SC_WINDWALK].timer != -1)   /* ウインドウォーク */
                skill_status_change_end(bl, SC_WINDWALK, -1);
            break;
        case SC_DECREASEAGI:   /* 速度減少 */
            calc_flag = 1;
            if (sc_data[SC_INCREASEAGI].timer != -1)
                skill_status_change_end(bl, SC_INCREASEAGI, -1);
            break;
        case SC_SIGNUMCRUCIS:  /* シグナムクルシス */
            calc_flag = 1;
//          val2 = 14 + val1;
            val2 = 10 + val1 * 2;
            tick = 600 * 1000;
            clif_emotion(bl, 4);
            break;
        case SC_SLOWPOISON:
            if (sc_data[SC_POISON].timer == -1)
                return 0;
            break;
        case SC_TWOHANDQUICKEN:    /* 2HQ */
            *opt3 |= Opt3::_concentration;
            calc_flag = 1;
            break;
        case SC_ADRENALINE:    /* アドレナリンラッシュ */
            calc_flag = 1;
            break;
        case SC_WEAPONPERFECTION:  /* ウェポンパーフェクション */
            if (battle_config.party_skill_penaly && !val2)
                tick /= 5;
            break;
        case SC_OVERTHRUST:    /* オーバースラスト */
            *opt3 |= Opt3::_overthrust;
            if (battle_config.party_skill_penaly && !val2)
                tick /= 10;
            break;
        case SC_MAXIMIZEPOWER: /* マキシマイズパワー(SPが1減る時間,val2にも) */
            if (bl->type == BL_PC)
                val2 = tick;
            else
                tick = 5000 * val1;
            break;
        case SC_ENCPOISON:     /* エンチャントポイズン */
            calc_flag = 1;
            val2 = (((val1 - 1) / 2) + 3) * 100;    /* 毒付与確率 */
            skill_encchant_eremental_end(bl, SC_ENCPOISON);
            break;
        case SC_POISONREACT:   /* ポイズンリアクト */
            break;
        case SC_IMPOSITIO:     /* インポシティオマヌス */
            calc_flag = 1;
            break;
        case SC_ASPERSIO:      /* アスペルシオ */
            skill_encchant_eremental_end(bl, SC_ASPERSIO);
            break;
        case SC_SUFFRAGIUM:    /* サフラギム */
        case SC_BENEDICTIO:    /* 聖体 */
        case SC_MAGNIFICAT:    /* マグニフィカート */
        case SC_AETERNA:       /* エーテルナ */
            break;
        case SC_ENERGYCOAT:    /* エナジーコート */
            *opt3 |= Opt3::_energycoat;
            break;
        case SC_MAGICROD:
            val2 = val1 * 20;
            break;
        case SC_KYRIE:         /* キリエエレイソン */
            val2 = battle_get_max_hp(bl) * (val1 * 2 + 10) / 100;  /* 耐久度 */
            val3 = (val1 / 2 + 5);  /* 回数 */
// -- moonsoul (added to undo assumptio status if target has it)
            if (sc_data[SC_ASSUMPTIO].timer != -1)
                skill_status_change_end(bl, SC_ASSUMPTIO, -1);
            break;
        case SC_MINDBREAKER:
            calc_flag = 1;
            if (tick <= 0)
                tick = 1000;    /* (オートバーサーク) */
        case SC_GLORIA:        /* グロリア */
            calc_flag = 1;
            break;
        case SC_LOUD:          /* ラウドボイス */
            calc_flag = 1;
            break;
        case SC_TRICKDEAD:     /* 死んだふり */
            break;
        case SC_QUAGMIRE:      /* クァグマイア */
            calc_flag = 1;
            if (sc_data[SC_CONCENTRATE].timer != -1)    /* 集中力向上解除 */
                skill_status_change_end(bl, SC_CONCENTRATE, -1);
            if (sc_data[SC_INCREASEAGI].timer != -1)    /* 速度上昇解除 */
                skill_status_change_end(bl, SC_INCREASEAGI, -1);
            if (sc_data[SC_TWOHANDQUICKEN].timer != -1)
                skill_status_change_end(bl, SC_TWOHANDQUICKEN, -1);
            if (sc_data[SC_SPEARSQUICKEN].timer != -1)
                skill_status_change_end(bl, SC_SPEARSQUICKEN, -1);
            if (sc_data[SC_ADRENALINE].timer != -1)
                skill_status_change_end(bl, SC_ADRENALINE, -1);
            if (sc_data[SC_LOUD].timer != -1)
                skill_status_change_end(bl, SC_LOUD, -1);
            if (sc_data[SC_TRUESIGHT].timer != -1)  /* トゥルーサイト */
                skill_status_change_end(bl, SC_TRUESIGHT, -1);
            if (sc_data[SC_WINDWALK].timer != -1)   /* ウインドウォーク */
                skill_status_change_end(bl, SC_WINDWALK, -1);
            if (sc_data[SC_CARTBOOST].timer != -1)  /* カートブースト */
                skill_status_change_end(bl, SC_CARTBOOST, -1);
            break;
        case SC_FLAMELAUNCHER: /* フレームランチャー */
            skill_encchant_eremental_end(bl, SC_FLAMELAUNCHER);
            break;
        case SC_FROSTWEAPON:   /* フロストウェポン */
            skill_encchant_eremental_end(bl, SC_FROSTWEAPON);
            break;
        case SC_LIGHTNINGLOADER:   /* ライトニングローダー */
            skill_encchant_eremental_end(bl, SC_LIGHTNINGLOADER);
            break;
        case SC_SEISMICWEAPON: /* サイズミックウェポン */
            skill_encchant_eremental_end(bl, SC_SEISMICWEAPON);
            break;
        case SC_DEVOTION:      /* ディボーション */
            calc_flag = 1;
            break;
        case SC_PROVIDENCE:    /* プロヴィデンス */
            calc_flag = 1;
            val2 = val1 * 5;
            break;
        case SC_REFLECTSHIELD:
            val2 = 10 + val1 * 3;
            break;
        case SC_STRIPWEAPON:
        case SC_STRIPSHIELD:
        case SC_STRIPARMOR:
        case SC_STRIPHELM:
        case SC_CP_WEAPON:
        case SC_CP_SHIELD:
        case SC_CP_ARMOR:
        case SC_CP_HELM:
            break;

        case SC_AUTOSPELL:     /* オートスペル */
            val4 = 5 + val1 * 2;
            break;

        case SC_VOLCANO:
            calc_flag = 1;
            val3 = val1 * 10;
            val4 =
                val1 >= 5 ? 20 : (val1 ==
                                  4 ? 19 : (val1 ==
                                            3 ? 17 : (val1 == 2 ? 14 : 10)));
            break;
        case SC_DELUGE:
            calc_flag = 1;
            val3 =
                val1 >= 5 ? 15 : (val1 ==
                                  4 ? 14 : (val1 ==
                                            3 ? 12 : (val1 == 2 ? 9 : 5)));
            val4 =
                val1 >= 5 ? 20 : (val1 ==
                                  4 ? 19 : (val1 ==
                                            3 ? 17 : (val1 == 2 ? 14 : 10)));
            break;
        case SC_VIOLENTGALE:
            calc_flag = 1;
            val3 = val1 * 3;
            val4 =
                val1 >= 5 ? 20 : (val1 ==
                                  4 ? 19 : (val1 ==
                                            3 ? 17 : (val1 == 2 ? 14 : 10)));
            break;

        case SC_SPEARSQUICKEN: /* スピアクイッケン */
            calc_flag = 1;
            val2 = 20 + val1;
            *opt3 |= Opt3::_concentration;
            break;
        case SC_COMBO:
            break;
        case SC_BLADESTOP_WAIT:    /* 白刃取り(待ち) */
            break;
        case SC_BLADESTOP:     /* 白刃取り */
            *opt3 |= Opt3::_bladestop;
            break;

        case SC_LULLABY:       /* 子守唄 */
            val2 = 11;
            break;
        case SC_RICHMANKIM:
            break;
        case SC_ETERNALCHAOS:  /* エターナルカオス */
            calc_flag = 1;
            break;
        case SC_DRUMBATTLE:    /* 戦太鼓の響き */
            calc_flag = 1;
            val2 = (val1 + 1) * 25;
            val3 = (val1 + 1) * 2;
            break;
        case SC_NIBELUNGEN:    /* ニーベルングの指輪 */
            calc_flag = 1;
            val2 = (val1 + 2) * 50;
            val3 = (val1 + 2) * 25;
            break;
        case SC_ROKISWEIL:     /* ロキの叫び */
            break;
        case SC_INTOABYSS:     /* 深淵の中に */
            break;
        case SC_SIEGFRIED:     /* 不死身のジークフリード */
            calc_flag = 1;
            val2 = 40 + val1 * 5;
            val3 = val1 * 10;
            break;
        case SC_DISSONANCE:    /* 不協和音 */
            val2 = 10;
            break;
        case SC_WHISTLE:       /* 口笛 */
            calc_flag = 1;
            break;
        case SC_ASSNCROS:      /* 夕陽のアサシンクロス */
            calc_flag = 1;
            break;
        case SC_POEMBRAGI:     /* ブラギの詩 */
            break;
        case SC_APPLEIDUN:     /* イドゥンの林檎 */
            calc_flag = 1;
            break;
        case SC_UGLYDANCE:     /* 自分勝手なダンス */
            val2 = 10;
            break;
        case SC_HUMMING:       /* ハミング */
            calc_flag = 1;
            break;
        case SC_DONTFORGETME:  /* 私を忘れないで */
            calc_flag = 1;
            if (sc_data[SC_INCREASEAGI].timer != -1)    /* 速度上昇解除 */
                skill_status_change_end(bl, SC_INCREASEAGI, -1);
            if (sc_data[SC_TWOHANDQUICKEN].timer != -1)
                skill_status_change_end(bl, SC_TWOHANDQUICKEN, -1);
            if (sc_data[SC_SPEARSQUICKEN].timer != -1)
                skill_status_change_end(bl, SC_SPEARSQUICKEN, -1);
            if (sc_data[SC_ADRENALINE].timer != -1)
                skill_status_change_end(bl, SC_ADRENALINE, -1);
            if (sc_data[SC_ASSNCROS].timer != -1)
                skill_status_change_end(bl, SC_ASSNCROS, -1);
            if (sc_data[SC_TRUESIGHT].timer != -1)  /* トゥルーサイト */
                skill_status_change_end(bl, SC_TRUESIGHT, -1);
            if (sc_data[SC_WINDWALK].timer != -1)   /* ウインドウォーク */
                skill_status_change_end(bl, SC_WINDWALK, -1);
            if (sc_data[SC_CARTBOOST].timer != -1)  /* カートブースト */
                skill_status_change_end(bl, SC_CARTBOOST, -1);
            break;
        case SC_FORTUNE:       /* 幸運のキス */
            calc_flag = 1;
            break;
        case SC_SERVICE4U:     /* サービスフォーユー */
            calc_flag = 1;
            break;
        case SC_DANCING:       /* ダンス/演奏中 */
            calc_flag = 1;
            val3 = tick / 1000;
            tick = 1000;
            break;

        case SC_EXPLOSIONSPIRITS:  // 爆裂波動
            calc_flag = 1;
            val2 = 75 + 25 * val1;
            *opt3 |= Opt3::_explosionspirits;
            break;
        case SC_STEELBODY:     // 金剛
            calc_flag = 1;
            *opt3 |= Opt3::_steelbody;
            break;
        case SC_EXTREMITYFIST: /* 阿修羅覇凰拳 */
            break;
        case SC_AUTOCOUNTER:
            val3 = val4 = 0;
            break;

        case SC_SPEEDPOTION0:  /* 増速ポーション */
            *opt2 |= Opt2::_speedpotion0;
        case SC_SPEEDPOTION1:
        case SC_SPEEDPOTION2:
            calc_flag = 1;
            tick = 1000 * tick;
//          val2 = 5*(2+type-SC_SPEEDPOTION0);
            break;

            /* atk & matk potions [Valaris] */
        case SC_ATKPOT:
            *opt2 |= Opt2::_atkpot;
        case SC_MATKPOT:
            calc_flag = 1;
            tick = 1000 * tick;
            break;
        case SC_WEDDING:       //結婚用(結婚衣裳になって歩くのが遅いとか)
        {
            time_t timer;

            calc_flag = 1;
            tick = 10000;
            if (!val2)
                val2 = time(&timer);
        }
            break;
        case SC_NOCHAT:        //チャット禁止状態
        {
            time_t timer;

            if (!battle_config.muting_players)
                break;

            tick = 60000;
            if (!val2)
                val2 = time(&timer);
            // updateflag = SP_MANNER;
        }
            break;
        case SC_SELFDESTRUCTION:   //自爆
            val3 = tick / 1000;
            tick = 1000;
            break;

            /* option1 */
        case SC_STONE:         /* 石化 */
            if (!(flag & 2))
            {
                int sc_def = battle_get_mdef(bl) * 200;
                tick = tick - sc_def;
            }
            val3 = tick / 1000;
            if (val3 < 1)
                val3 = 1;
            tick = 5000;
            val2 = 1;
            break;
        case SC_SLEEP:         /* 睡眠 */
            if (!(flag & 2))
            {
//              int sc_def = 100 - (battle_get_int(bl) + battle_get_luk(bl)/3);
//              tick = tick * sc_def / 100;
//              if(tick < 1000) tick = 1000;
                tick = 30000;   //睡眠はステータス耐性に関わらず30秒
            }
            break;
        case SC_FREEZE:        /* 凍結 */
            if (!(flag & 2))
            {
                int sc_def = 100 - battle_get_mdef(bl);
                tick = tick * sc_def / 100;
            }
            break;
        case SC_STAN:          /* スタン(val2にミリ秒セット) */
            if (!(flag & 2))
            {
                int sc_def =
                    100 - (battle_get_vit(bl) + battle_get_luk(bl) / 3);
                tick = tick * sc_def / 100;
            }
            break;

            /* option2 */
        case SC_POISON:        /* 毒 */
            calc_flag = 1;
            if (!(flag & 2))
            {
                int sc_def =
                    100 - (battle_get_vit(bl) + battle_get_luk(bl) / 5);
                tick = tick * sc_def / 100;
            }
            val3 = tick / 1000;
            if (val3 < 1)
                val3 = 1;
            tick = 1000;
            break;
        case SC_SILENCE:       /* 沈黙(レックスデビーナ) */
            if (!(flag & 2))
            {
                int sc_def = 100 - battle_get_vit(bl);
                tick = tick * sc_def / 100;
            }
            break;
        case SC_BLIND:         /* 暗黒 */
            calc_flag = 1;
            if (!(flag & 2))
            {
                int sc_def =
                    battle_get_lv(bl) / 10 + battle_get_int(bl) / 15;
                tick = 30000 - sc_def;
            }
            break;
        case SC_CURSE:
            calc_flag = 1;
            if (!(flag & 2))
            {
                int sc_def = 100 - battle_get_vit(bl);
                tick = tick * sc_def / 100;
            }
            break;

            /* option */
        case SC_HIDING:        /* ハイディング */
            calc_flag = 1;
            if (bl->type == BL_PC)
            {
                val2 = tick / 1000; /* 持続時間 */
                tick = 1000;
            }
            break;
        case SC_CHASEWALK:
        case SC_CLOAKING:      /* クローキング */
            if (bl->type == BL_PC)
                val2 = tick;
            else
                tick = 5000 * val1;
            break;
        case SC_SIGHT:         /* サイト/ルアフ */
        case SC_RUWACH:
            val2 = tick / 250;
            tick = 10;
            break;

            /* セーフティウォール、ニューマ */
        case SC_SAFETYWALL:
        case SC_PNEUMA:
            tick = ((struct skill_unit *) val2)->group->limit;
            break;

            /* アンクル */
        case SC_ANKLE:
            break;

            /* ウォーターボール */
        case SC_WATERBALL:
            tick = 150;
            if (val1 > 5)       //レベルが5以上の場合は25発に制限(1発目はすでに打ってるので-1)
                val3 = 5 * 5 - 1;
            else
                val3 = (val1 | 1) * (val1 | 1) - 1;
            break;

            /* スキルじゃない/時間に関係しない */
        case SC_RIDING:
            calc_flag = 1;
            tick = 600 * 1000;
            break;
        case SC_FALCON:
        case SC_WEIGHT50:
        case SC_WEIGHT90:
        case SC_BROKNWEAPON:
        case SC_BROKNARMOR:
            tick = 600 * 1000;
            break;

        case SC_AUTOGUARD:
        {
            int i, t;
            for (i = val2 = 0; i < val1; i++)
            {
                t = 5 - (i >> 1);
                val2 += (t < 0) ? 1 : t;
            }
        }
            break;

        case SC_DEFENDER:
            calc_flag = 1;
            val2 = 5 + val1 * 15;
            break;

        case SC_KEEPING:
        case SC_BARRIER:
        case SC_HALLUCINATION:
            break;
        case SC_CONCENTRATION: /* コンセントレーション */
            *opt3 |= Opt3::_concentration;
            calc_flag = 1;
            break;
        case SC_TENSIONRELAX:  /* テンションリラックス */
            calc_flag = 1;
            if (bl->type == BL_PC)
            {
                tick = 10000;
            }
            break;
        case SC_AURABLADE:     /* オーラブレード */
        case SC_PARRYING:      /* パリイング */
//      case SC_ASSUMPTIO:      /*  */
        case SC_HEADCRUSH:     /* ヘッドクラッシュ */
        case SC_JOINTBEAT:     /* ジョイントビート */
//      case SC_MARIONETTE:     /* マリオネットコントロール */

            //とりあえず手抜き
            break;

// -- moonsoul  (for new upper class related skill status effects)
/*
                case SC_AURABLADE:
                        val2 = val1*10;
                        break;
                case SC_PARRYING:
                        val2=val1*3;
                        break;
                case SC_CONCENTRATION:
                        calc_flag=1;
                        val2=val1*10;
                        val3=val1*5;
                        break;
                case SC_TENSIONRELAX:
//                      val2 = 10;
//                      val3 = 15;
                        break;
                case SC_BERSERK:
                        calc_flag=1;
                        break;
                case SC_ASSUMPTIO:
                        if (sc_data[SC_KYRIE].timer!=-1 )
                                skill_status_change_end(bl,SC_KYRIE,-1);
                                break;
*/
        case SC_WINDWALK:      /* ウインドウォーク */
            calc_flag = 1;
            val2 = (val1 / 2);  //Flee上昇率
            break;
        case SC_BERSERK:       /* バーサーク */
            if (sd)
            {
                sd->status.sp = 0;
                clif_updatestatus(sd, SP_SP);
                clif_status_change(bl, SC_INCREASEAGI, 1); /* アイコン表示 */
            }
            *opt3 |= Opt3::_berserk;
            tick = 1000;
            calc_flag = 1;
            break;
        case SC_ASSUMPTIO:     /* アスムプティオ */
            *opt3 |= Opt3::_assumptio;
            break;
        case SC_MARIONETTE:    /* マリオネットコントロール */
            *opt3 |= Opt3::_marionette;
            break;
        case SC_MELTDOWN:      /* メルトダウン */
        case SC_CARTBOOST:     /* カートブースト */
        case SC_TRUESIGHT:     /* トゥルーサイト */
        case SC_SPIDERWEB:     /* スパイダーウェッブ */
        case SC_MAGICPOWER:    /* 魔法力増幅 */
            calc_flag = 1;
            break;
        case SC_REJECTSWORD:   /* リジェクトソード */
            val2 = 3;           //3回攻撃を跳ね返す
            break;
        case SC_MEMORIZE:      /* メモライズ */
            val2 = 3;           //3回詠唱を1/3にする
            break;
        case SC_GRAFFITI:      /* グラフィティ */
        {
            struct skill_unit_group *sg =
                skill_unitsetting(bl, RG_GRAFFITI, val1, val2, val3, 0);
            if (sg)
                val4 = (int) sg;
        }
            break;
        case SC_HASTE:
            calc_flag = 1;
        case SC_SPLASHER:      /* ベナムスプラッシャー */
        case SC_PHYS_SHIELD:
        case SC_MBARRIER:
        case SC_HALT_REGENERATE:
        case SC_HIDE:
            break;
        case SC_FLYING_BACKPACK:
            updateflag = SP_WEIGHT;
            break;
        default:
            if (battle_config.error_log)
                printf("UnknownStatusChange [%d]\n", uint16_t(type));
            return 0;
    }

    if (bl->type == BL_PC && type < SC_SENDMAX)
        clif_status_change(bl, type, 1);   /* アイコン表示 */

    /* optionの変更 */
    switch (type)
    {
        case SC_STONE:
        case SC_FREEZE:
        case SC_STAN:
        case SC_SLEEP:
            battle_stopattack(bl); /* 攻撃停止 */
            skill_stop_dancing(bl, 0); /* 演奏/ダンスの中断 */
            /* 同時に掛からないステータス異常を解除 */
            for (StatusChange i : MAJOR_STATUS_EFFECTS_1)
            {
                if (sc_data[i].timer != -1)
                {
                    (*sc_count)--;
                    delete_timer(sc_data[i].timer,
                                  skill_status_change_timer);
                    sc_data[i].timer = -1;
                }
            }
            switch (type)
            {
            case SC_STONE:  *opt1 = Opt1::_stone6; break;
            case SC_FREEZE: *opt1 = Opt1::_freeze; break;
            case SC_STAN:   *opt1 = Opt1::_stan; break;
            case SC_SLEEP:  *opt1 = Opt1::_sleep; break;
            }
            opt_flag = 1;
            break;
        case SC_POISON:
            if (sc_data[SC_SLOWPOISON].timer == -1)
            {
                *opt2 |= Opt2::_poison;
                opt_flag = 1;
            }
            break;

        case SC_CURSE:
            *opt2 |= Opt2::_curse;
            opt_flag = 1;
            break;
        case SC_SILENCE:
            *opt2 |= Opt2::_silence;
            opt_flag = 1;
            break;
        case SC_BLIND:
            *opt2 |= Opt2::BLIND;
            opt_flag = 1;
            break;

        case SC_SLOWPOISON:
            *opt2 &= ~Opt2::_poison;
            *opt2 |= Opt2::_slowpoison;
            opt_flag = 1;
            break;
        case SC_SIGNUMCRUCIS:
            *opt2 |= Opt2::_signumcrucis;
            opt_flag = 1;
            break;
        case SC_HIDING:
            battle_stopattack(bl); /* 攻撃停止 */
            *option |= Option::HIDE2;
            opt_flag = 1;
            break;
        case SC_CLOAKING:
            battle_stopattack(bl); /* 攻撃停止 */
            *option |= Option::CLOAK;
            opt_flag = 1;
            break;
        case SC_CHASEWALK:
            battle_stopattack(bl); /* 攻撃停止 */
            *option |= Option::CHASEWALK | Option::CLOAK;
            opt_flag = 1;
            break;
        case SC_SIGHT:
            *option |= Option::SIGHT;
            opt_flag = 1;
            break;
        case SC_RUWACH:
            *option |= Option::_ruwach;
            opt_flag = 1;
            break;
        case SC_WEDDING:
            *option |= Option::_wedding;
            opt_flag = 1;
    }

    if (opt_flag)               /* optionの変更 */
        clif_changeoption(bl);

    (*sc_count)++;              /* ステータス異常の数 */

    sc_data[type].val1 = val1;
    sc_data[type].val2 = val2;
    sc_data[type].val3 = val3;
    sc_data[type].val4 = val4;
    if (sc_data[type].spell_invocation) // Supplant by newer spell
        spell_effect_report_termination(sc_data[type].spell_invocation,
                                         bl->id, type, 1);

    sc_data[type].spell_invocation = spell_invocation;

    /* タイマー設定 */
    sc_data[type].timer =
        add_timer(gettick() + tick, skill_status_change_timer, bl->id,
                   custom_data_t(type));

    if (bl->type == BL_PC && calc_flag)
        pc_calcstatus(sd, 0);  /* ステータス再計算 */

    if (bl->type == BL_PC && updateflag != SP::ZERO)
        clif_updatestatus(sd, updateflag); /* ステータスをクライアントに送る */

    return 0;
}

/*==========================================
 * ステータス異常全解除
 *------------------------------------------
 */
int skill_status_change_clear(struct block_list *bl, int type)
{
    eptr<struct status_change, StatusChange> sc_data;
    short *sc_count;
    Option *option;
    Opt1 *opt1;
    Opt2 *opt2;
    Opt3 *opt3;

    nullpo_ret(bl);
    sc_data = battle_get_sc_data(bl);
    if (not sc_data)
        return 0;
    nullpo_ret(sc_count = battle_get_sc_count(bl));
    nullpo_ret(option = battle_get_option(bl));
    nullpo_ret(opt1 = battle_get_opt1(bl));
    nullpo_ret(opt2 = battle_get_opt2(bl));
    nullpo_ret(opt3 = battle_get_opt3(bl));

    if (*sc_count == 0)
        return 0;
    for (StatusChange i : erange(StatusChange(), MAX_STATUSCHANGE))
    {
        if (sc_data[i].timer != -1)
        {                       /* 異常があるならタイマーを削除する */
/*
                        delete_timer(sc_data[i].timer, skill_status_change_timer);
                        sc_data[i].timer = -1;

                        if (!type && i < SC_SENDMAX)
                                clif_status_change(bl, i, 0);
*/

            skill_status_change_end(bl, i, -1);
        }
    }
    *sc_count = 0;
    *opt1 = Opt1::ZERO;
    *opt2 = Opt2::ZERO;
    *opt3 = Opt3::ZERO;
    *option &= Option::MASK;

    if (night_flag == 1 && type == 1)   // by [Yor]
        *opt2 |= Opt2::BLIND;

    if (type == 0 || type & 2)
        clif_changeoption(bl);

    return 0;
}

/* クローキング検査(周りに移動不可能地帯があるか) */
int skill_check_cloaking(struct block_list *bl)
{
    struct map_session_data *sd = NULL;
    static int dx[] = { -1, 0, 1, -1, 1, -1, 0, 1 };
    static int dy[] = { -1, -1, -1, 0, 0, 1, 1, 1 };
    int end = 1, i;

    nullpo_ret(bl);

    if (pc_checkskill(sd, AS_CLOAKING) > 2)
        return 0;
    if (bl->type == BL_PC && battle_config.pc_cloak_check_type & 1)
        return 0;
    if (bl->type == BL_MOB && battle_config.monster_cloak_check_type & 1)
        return 0;
    for (i = 0; i < sizeof(dx) / sizeof(dx[0]); i++)
    {
        int c = map_getcell(bl->m, bl->x + dx[i], bl->y + dy[i]);
        if (c == 1 || c == 5)
            end = 0;
    }
    if (end)
    {
        skill_status_change_end(bl, SC_CLOAKING, -1);
        *battle_get_option(bl) &= ~Option::CLOAK;  /* 念のための処理 */
    }
    return end;
}

/*
 *----------------------------------------------------------------------------
 * スキルユニット
 *----------------------------------------------------------------------------
 */

/*==========================================
 * 演奏/ダンススキルかどうか判定
 * 引数 スキルID
 * 戻り ダンスじゃない=0 合奏=2 それ以外のダンス=1
 *------------------------------------------
 */
static
int skill_is_danceskill(SkillID id)
{
    switch (id)
    {
        case BD_LULLABY:       /* 子守歌 */
        case BD_RICHMANKIM:    /* ニヨルドの宴 */
        case BD_ETERNALCHAOS:  /* 永遠の混沌 */
        case BD_DRUMBATTLEFIELD:   /* 戦太鼓の響き */
        case BD_RINGNIBELUNGEN:    /* ニーベルングの指輪 */
        case BD_ROKISWEIL:     /* ロキの叫び */
        case BD_INTOABYSS:     /* 深淵の中に */
        case BD_SIEGFRIED:     /* 不死身のジークフリード */
        case BD_RAGNAROK:      /* 神々の黄昏 */
        case CG_MOONLIT:       /* 月明りの泉に落ちる花びら */
            return 2;
        case BA_DISSONANCE:    /* 不協和音 */
        case BA_FROSTJOKE:     /* 寒いジョーク */
        case BA_WHISTLE:       /* 口笛 */
        case BA_ASSASSINCROSS: /* 夕陽のアサシンクロス */
        case BA_POEMBRAGI:     /* ブラギの詩 */
        case BA_APPLEIDUN:     /* イドゥンの林檎 */
        case DC_UGLYDANCE:     /* 自分勝手なダンス */
        case DC_SCREAM:        /* スクリーム */
        case DC_HUMMING:       /* ハミング */
        case DC_DONTFORGETME:  /* 私を忘れないで… */
        case DC_FORTUNEKISS:   /* 幸運のキス */
        case DC_SERVICEFORYOU: /* サービスフォーユー */
            return 1;
        default:
            return 0;
    }
}

/*==========================================
 * 演奏/ダンスをやめる
 * flag 1で合奏中なら相方にユニットを任せる
 *
 *------------------------------------------
 */
void skill_stop_dancing(struct block_list *src, int flag)
{
    eptr<struct status_change, StatusChange> sc_data;
    struct skill_unit_group *group;

    nullpo_retv(src);

    sc_data = battle_get_sc_data(src);
    if (sc_data && sc_data[SC_DANCING].timer == -1)
        return;
    group = (struct skill_unit_group *) sc_data[SC_DANCING].val2;   //ダンスのスキルユニットIDはval2に入ってる
    if (group && src->type == BL_PC && sc_data && sc_data[SC_DANCING].val4)
    {                           //合奏中断
        struct map_session_data *dsd = map_id2sd(sc_data[SC_DANCING].val4);    //相方のsd取得
        if (flag)
        {                       //ログアウトなど片方が落ちても演奏が継続される
            if (dsd && src->id == group->src_id)
            {                   //グループを持ってるPCが落ちる
                group->src_id = sc_data[SC_DANCING].val4;   //相方にグループを任せる
                if (flag & 1)   //ログアウト
                    dsd->sc_data[SC_DANCING].val4 = 0;  //相方の相方を0にして合奏終了→通常のダンス状態
                if (flag & 2)   //ハエ飛びなど
                    return;     //合奏もダンス状態も終了させない&スキルユニットは置いてけぼり
            }
            else if (dsd && dsd->bl.id == group->src_id)
            {                   //相方がグループを持っているPCが落ちる(自分はグループを持っていない)
                if (flag & 1)   //ログアウト
                    dsd->sc_data[SC_DANCING].val4 = 0;  //相方の相方を0にして合奏終了→通常のダンス状態
                if (flag & 2)   //ハエ飛びなど
                    return;     //合奏もダンス状態も終了させない&スキルユニットは置いてけぼり
            }
            skill_status_change_end(src, SC_DANCING, -1);  //自分のステータスを終了させる
            //そしてグループは消さない&消さないのでステータス計算もいらない?
            return;
        }
        else
        {
            if (dsd && src->id == group->src_id)
            {                   //グループを持ってるPCが止める
                skill_status_change_end((struct block_list *) dsd, SC_DANCING, -1);    //相手のステータスを終了させる
            }
            if (dsd && dsd->bl.id == group->src_id)
            {                   //相方がグループを持っているPCが止める(自分はグループを持っていない)
                skill_status_change_end(src, SC_DANCING, -1);  //自分のステータスを終了させる
            }
        }
    }
    if (flag & 2 && group && src->type == BL_PC)
    {                           //ハエで飛んだときとかはユニットも飛ぶ
        struct map_session_data *sd = (struct map_session_data *) src;
        skill_unit_move_unit_group(group, sd->bl.m, (sd->to_x - sd->bl.x),
                                    (sd->to_y - sd->bl.y));
        return;
    }
    skill_delunitgroup(group);
    if (src->type == BL_PC)
        pc_calcstatus((struct map_session_data *) src, 0);
}

/*==========================================
 * スキルユニット初期化
 *------------------------------------------
 */
struct skill_unit *skill_initunit(struct skill_unit_group *group, int idx,
                                   int x, int y)
{
    struct skill_unit *unit;

    nullpo_retr(NULL, group);
    nullpo_retr(NULL, unit = &group->unit[idx]);

    if (!unit->alive)
        group->alive_count++;

    unit->bl.id = map_addobject(&unit->bl);
    unit->bl.type = BL_SKILL;
    unit->bl.m = group->map;
    unit->bl.x = x;
    unit->bl.y = y;
    unit->group = group;
    unit->val1 = unit->val2 = 0;
    unit->alive = 1;

    map_addblock(&unit->bl);
    return unit;
}

void skill_unit_timer_sub_ondelete(struct block_list *bl,
        struct block_list *src, unsigned int tick);
/*==========================================
 * スキルユニット削除
 *------------------------------------------
 */
int skill_delunit(struct skill_unit *unit)
{
    struct skill_unit_group *group;
    int range;

    nullpo_ret(unit);
    if (!unit->alive)
        return 0;
    nullpo_ret(group = unit->group);

    /* onlimitイベント呼び出し */
    skill_unit_onlimit(unit, gettick());

    /* ondeleteイベント呼び出し */
    range = group->range;
    map_foreachinarea(std::bind(skill_unit_timer_sub_ondelete, ph::_1,  &unit->bl, gettick()),
            unit->bl.m, unit->bl.x - range, unit->bl.y - range,
            unit->bl.x + range, unit->bl.y + range, BL_NUL);

    unit->group = NULL;
    unit->alive = 0;
    map_delobjectnofree(unit->bl.id, BL_SKILL);
    if (group->alive_count > 0 && (--group->alive_count) <= 0)
        skill_delunitgroup(group);

    return 0;
}

/*==========================================
 * スキルユニットグループ初期化
 *------------------------------------------
 */
static
int skill_unit_group_newid = 10;
struct skill_unit_group *skill_initunitgroup(struct block_list *src,
        int count, SkillID skillid, int skilllv, int unit_id)
{
    int i;
    struct skill_unit_group *group = NULL, *list = NULL;
    int maxsug = 0;

    nullpo_retr(NULL, src);

    if (src->type == BL_PC)
    {
        list = ((struct map_session_data *) src)->skillunit;
        maxsug = MAX_SKILLUNITGROUP;
    }
    else if (src->type == BL_MOB)
    {
        list = ((struct mob_data *) src)->skillunit;
        maxsug = MAX_MOBSKILLUNITGROUP;
    }
    if (list)
    {
        for (i = 0; i < maxsug; i++)    /* 空いているもの検索 */
            if (list[i].group_id == 0)
            {
                group = &list[i];
                break;
            }

        if (group == NULL)
        {                       /* 空いてないので古いもの検索 */
            int j = 0;
            unsigned maxdiff = 0, x, tick = gettick();
            for (i = 0; i < maxsug; i++)
                if ((x = DIFF_TICK(tick, list[i].tick)) > maxdiff)
                {
                    maxdiff = x;
                    j = i;
                }
            skill_delunitgroup(&list[j]);
            group = &list[j];
        }
    }

    if (group == NULL)
    {
        printf("skill_initunitgroup: error unit group !\n");
        exit(1);
    }

    group->src_id = src->id;
    group->party_id = battle_get_party_id(src);
    group->group_id = skill_unit_group_newid++;
    if (skill_unit_group_newid <= 0)
        skill_unit_group_newid = 10;
    CREATE(group->unit, struct skill_unit, count);
    group->unit_count = count;
    group->val1 = group->val2 = 0;
    group->skill_id = skillid;
    group->skill_lv = skilllv;
    group->unit_id = unit_id;
    group->map = src->m;
    group->range = 0;
    group->limit = 10000;
    group->interval = 1000;
    group->tick = gettick();
    group->valstr = NULL;

    if (skill_is_danceskill(skillid))
    {
        struct map_session_data *sd = NULL;
        if (src->type == BL_PC && (sd = (struct map_session_data *) src))
        {
            sd->skillid_dance = skillid;
            sd->skilllv_dance = skilllv;
        }
        skill_status_change_start(src, SC_DANCING,
                uint16_t(skillid), (int) group, 0, 0,
                skill_get_time(skillid, skilllv) + 1000, 0);
        switch (skillid)
        {                       //合奏スキルは相方をダンス状態にする
            case BD_LULLABY:   /* 子守歌 */
            case BD_RICHMANKIM:    /* ニヨルドの宴 */
            case BD_ETERNALCHAOS:  /* 永遠の混沌 */
            case BD_DRUMBATTLEFIELD:   /* 戦太鼓の響き */
            case BD_RINGNIBELUNGEN:    /* ニーベルングの指輪 */
            case BD_ROKISWEIL: /* ロキの叫び */
            case BD_INTOABYSS: /* 深淵の中に */
            case BD_SIEGFRIED: /* 不死身のジークフリード */
            case BD_RAGNAROK:  /* 神々の黄昏 */
            case CG_MOONLIT:   /* 月明りの泉に落ちる花びら */
            {
                int range = 1;
                int c = 0;
                if (sd)
                {
                    map_foreachinarea(std::bind(skill_check_condition_use_sub, ph::_1, &sd->bl, &c),
                            sd->bl.m, sd->bl.x - range, sd->bl.y - range,
                            sd->bl.x + range, sd->bl.y + range, BL_PC);
                }
            }
        }
    }
    return group;
}

/*==========================================
 * スキルユニットグループ削除
 *------------------------------------------
 */
int skill_delunitgroup(struct skill_unit_group *group)
{
    struct block_list *src;
    int i;

    nullpo_ret(group);
    if (group->unit_count <= 0)
        return 0;

    src = map_id2bl(group->src_id);
    if (skill_is_danceskill(group->skill_id))
    {                           //ダンススキルはダンス状態を解除する
        if (src)
            skill_status_change_end(src, SC_DANCING, -1);
    }

    group->alive_count = 0;
    if (group->unit != NULL)
    {
        for (i = 0; i < group->unit_count; i++)
            if (group->unit[i].alive)
                skill_delunit(&group->unit[i]);
    }
    if (group->valstr != NULL)
    {
        map_freeblock(group->valstr);
        group->valstr = NULL;
    }

    map_freeblock(group->unit);    /* free()の替わり */
    group->unit = NULL;
    group->src_id = 0;
    group->group_id = 0;
    group->unit_count = 0;
    return 0;
}

/*==========================================
 * スキルユニットグループ全削除
 *------------------------------------------
 */
int skill_clear_unitgroup(struct block_list *src)
{
    struct skill_unit_group *group = NULL;
    int maxsug = 0;

    nullpo_ret(src);

    if (src->type == BL_PC)
    {
        group = ((struct map_session_data *) src)->skillunit;
        maxsug = MAX_SKILLUNITGROUP;
    }
    else if (src->type == BL_MOB)
    {
        group = ((struct mob_data *) src)->skillunit;
        maxsug = MAX_MOBSKILLUNITGROUP;
    }
    if (group)
    {
        int i;
        for (i = 0; i < maxsug; i++)
            if (group[i].group_id > 0 && group[i].src_id == src->id)
                skill_delunitgroup(&group[i]);
    }
    return 0;
}

/*==========================================
 * スキルユニットグループの被影響tick検索
 *------------------------------------------
 */
struct skill_unit_group_tickset *skill_unitgrouptickset_search(
        struct block_list *bl, int group_id)
{
    int i, j = 0, k, s = group_id % MAX_SKILLUNITGROUPTICKSET;
    struct skill_unit_group_tickset *set = NULL;

    nullpo_ret(bl);

    if (bl->type == BL_PC)
    {
        set = ((struct map_session_data *) bl)->skillunittick;
    }
    else
    {
        set = ((struct mob_data *) bl)->skillunittick;
    }
    if (set == NULL)
        return 0;
    for (i = 0; i < MAX_SKILLUNITGROUPTICKSET; i++)
        if (set[(k = (i + s) % MAX_SKILLUNITGROUPTICKSET)].group_id ==
            group_id)
            return &set[k];
        else if (set[k].group_id == 0)
            j = k;

    return &set[j];
}

/*==========================================
 * スキルユニットグループの被影響tick削除
 *------------------------------------------
 */
int skill_unitgrouptickset_delete(struct block_list *bl, int group_id)
{
    int i, s = group_id % MAX_SKILLUNITGROUPTICKSET;
    struct skill_unit_group_tickset *set = NULL, *ts;

    nullpo_ret(bl);

    if (bl->type == BL_PC)
    {
        set = ((struct map_session_data *) bl)->skillunittick;
    }
    else
    {
        set = ((struct mob_data *) bl)->skillunittick;
    }

    if (set != NULL)
    {

        for (i = 0; i < MAX_SKILLUNITGROUPTICKSET; i++)
            if ((ts =
                 &set[(i + s) % MAX_SKILLUNITGROUPTICKSET])->group_id ==
                group_id)
                ts->group_id = 0;

    }
    return 0;
}

/*==========================================
 * スキルユニットタイマー発動処理用(foreachinarea)
 *------------------------------------------
 */
static
void skill_unit_timer_sub_onplace(struct block_list *bl,
        struct block_list *src, unsigned int tick)
{
    struct skill_unit *su;

    nullpo_retv(bl);

    su = (struct skill_unit *) src;

    if (su && su->alive)
    {
        struct skill_unit_group *sg;
        sg = su->group;
        if (sg && battle_check_target(src, bl, sg->target_flag) > 0)
            skill_unit_onplace(su, bl, tick);
    }
}

/*==========================================
 * スキルユニットタイマー削除処理用(foreachinarea)
 *------------------------------------------
 */
void skill_unit_timer_sub_ondelete(struct block_list *bl,
        struct block_list *src, unsigned int tick)
{
    struct skill_unit *su;

    nullpo_retv(bl);

    su = (struct skill_unit *) src;

    if (su && su->alive)
    {
        struct skill_unit_group *sg;
        sg = su->group;
        if (sg && battle_check_target(src, bl, sg->target_flag) > 0)
            skill_unit_ondelete(su, bl, tick);
    }
}

/*==========================================
 * スキルユニットタイマー処理用(foreachobject)
 *------------------------------------------
 */
static
void skill_unit_timer_sub(struct block_list *bl, unsigned int tick)
{
    struct skill_unit *unit;
    struct skill_unit_group *group;
    int range;

    nullpo_retv(bl);
    unit = (struct skill_unit *) bl;
    nullpo_retv(group = unit->group);

    if (!unit->alive)
        return;

    range = (unit->range != 0) ? unit->range : group->range;

    /* onplaceイベント呼び出し */
    if (unit->alive && unit->range >= 0)
    {
        map_foreachinarea(std::bind(skill_unit_timer_sub_onplace, ph::_1, bl, tick),
                bl->m, bl->x - range, bl->y - range,
                bl->x + range, bl->y + range, BL_NUL);
        if (group->unit_id == 0xaa
            && DIFF_TICK(tick, group->tick) >= 6000 * group->val2)
        {
            map_foreachinarea(std::bind(skill_idun_heal, ph::_1, unit),
                    bl->m, bl->x - range, bl->y - range,
                    bl->x + range, bl->y + range, BL_NUL);
            group->val2++;
        }
    }
    /* 時間切れ削除 */
    if (unit->alive &&
        (DIFF_TICK(tick, group->tick) >= group->limit
         || DIFF_TICK(tick, group->tick) >= unit->limit))
    {
        switch (group->unit_id)
        {

            case 0x8f:         /* ブラストマイン */
                group->unit_id = 0x8c;
                clif_changelook(bl, LOOK_BASE, group->unit_id);
                group->limit = DIFF_TICK(tick + 1500, group->tick);
                unit->limit = DIFF_TICK(tick + 1500, group->tick);
                break;
            case 0x90:         /* スキッドトラップ */
            case 0x91:         /* アンクルスネア */
            case 0x93:         /* ランドマイン */
            case 0x94:         /* ショックウェーブトラップ */
            case 0x95:         /* サンドマン */
            case 0x96:         /* フラッシャー */
            case 0x97:         /* フリージングトラップ */
            case 0x98:         /* クレイモアートラップ */
            case 0x99:         /* トーキーボックス */
            {
                struct block_list *src = map_id2bl(group->src_id);
                if (group->unit_id == 0x91 && group->val2);
                else
                {
                    if (src && src->type == BL_PC)
                    {
                        struct item item_tmp;
                        memset(&item_tmp, 0, sizeof(item_tmp));
                        item_tmp.nameid = 1065;
                        item_tmp.identify = 1;
                        map_addflooritem(&item_tmp, 1, bl->m, bl->x, bl->y, NULL, NULL, NULL, 0);  // 罠返還
                    }
                }
            }
            default:
                skill_delunit(unit);
        }
    }

    if (group->unit_id == 0x8d)
    {
        unit->val1 -= 5;
        if (unit->val1 <= 0 && unit->limit + group->tick > tick + 700)
            unit->limit = DIFF_TICK(tick + 700, group->tick);
    }
}

/*==========================================
 * スキルユニットタイマー処理
 *------------------------------------------
 */
static
void skill_unit_timer(timer_id, tick_t tick, custom_id_t, custom_data_t)
{
    map_freeblock_lock();

    map_foreachobject(std::bind(skill_unit_timer_sub, ph::_1, tick), BL_SKILL);

    map_freeblock_unlock();
}

/*==========================================
 * スキルユニット移動時処理用(foreachinarea)
 *------------------------------------------
 */
static
void skill_unit_out_all_sub(struct block_list *bl,
        struct block_list *src, unsigned int tick)
{
    struct skill_unit *unit;
    struct skill_unit_group *group;
    int range;

    nullpo_retv(bl);
    nullpo_retv(src);
    unit = (struct skill_unit *) bl;
    nullpo_retv(group = unit->group);

    if (!unit->alive || src->prev == NULL)
        return;

    range = (unit->range != 0) ? unit->range : group->range;

    if (range < 0 || battle_check_target(bl, src, group->target_flag) <= 0)
        return;

    if (src->x >= bl->x - range && src->x <= bl->x + range &&
        src->y >= bl->y - range && src->y <= bl->y + range)
        skill_unit_onout(unit, src, tick);
}

/*==========================================
 * スキルユニット移動時処理
 *------------------------------------------
 */
int skill_unit_out_all(struct block_list *bl, unsigned int tick, int range)
{
    nullpo_ret(bl);

    if (bl->prev == NULL)
        return 0;

    if (range < 7)
        range = 7;
    map_foreachinarea(std::bind(skill_unit_out_all_sub, ph::_1, bl, tick),
            bl->m, bl->x - range, bl->y - range,
            bl->x + range, bl->y + range, BL_SKILL);

    return 0;
}

/*==========================================
 * スキルユニット移動時処理用(foreachinarea)
 *------------------------------------------
 */
static
void skill_unit_move_sub(struct block_list *bl,
        struct block_list *src, unsigned int tick)
{
    struct skill_unit *unit;
    struct skill_unit_group *group;
    int range;

    nullpo_retv(bl);
    nullpo_retv(unit = (struct skill_unit *) bl);
    nullpo_retv(src);

    if (!unit->alive || src->prev == NULL)
        return;

    if ((group = unit->group) == NULL)
        return;
    range = (unit->range != 0) ? unit->range : group->range;

    if (range < 0 || battle_check_target(bl, src, group->target_flag) <= 0)
        return;

    if (src->x >= bl->x - range && src->x <= bl->x + range &&
        src->y >= bl->y - range && src->y <= bl->y + range)
        skill_unit_onplace(unit, src, tick);
    else
        skill_unit_onout(unit, src, tick);
}

/*==========================================
 * スキルユニット移動時処理
 *------------------------------------------
 */
int skill_unit_move(struct block_list *bl, unsigned int tick, int range)
{
    nullpo_ret(bl);

    if (bl->prev == NULL)
        return 0;

    if (range < 7)
        range = 7;
    map_foreachinarea(std::bind(skill_unit_move_sub, ph::_1, bl, tick),
            bl->m, bl->x - range, bl->y - range,
            bl->x + range, bl->y + range, BL_SKILL);

    return 0;
}

/*==========================================
 * スキルユニット自体の移動時処理(foreachinarea)
 *------------------------------------------
 */
static
void skill_unit_move_unit_group_sub(struct block_list *bl,
        struct block_list *src, unsigned int tick)
{
    struct skill_unit *unit;
    struct skill_unit_group *group;
    int range;

    nullpo_retv(bl);
    nullpo_retv(src);
    unit = (struct skill_unit *) src;
    nullpo_retv(group = unit->group);

    if (!unit->alive || bl->prev == NULL)
        return;

    range = (unit->range != 0) ? unit->range : group->range;

    if (range < 0 || battle_check_target(src, bl, group->target_flag) <= 0)
        return;
    if (bl->x >= src->x - range && bl->x <= src->x + range &&
        bl->y >= src->y - range && bl->y <= src->y + range)
        skill_unit_onplace(unit, bl, tick);
    else
        skill_unit_onout(unit, bl, tick);
}

/*==========================================
 * スキルユニット自体の移動時処理
 * 引数はグループと移動量
 *------------------------------------------
 */
int skill_unit_move_unit_group(struct skill_unit_group *group, int m, int dx,
                                int dy)
{
    nullpo_ret(group);

    if (group->unit_count <= 0)
        return 0;

    if (group->unit != NULL)
    {
        if (!battle_config.unit_movement_type)
        {
            int i;
            for (i = 0; i < group->unit_count; i++)
            {
                struct skill_unit *unit = &group->unit[i];
                if (unit->alive && !(m == unit->bl.m && dx == 0 && dy == 0))
                {
                    int range = unit->range;
                    map_delblock(&unit->bl);
                    unit->bl.m = m;
                    unit->bl.x += dx;
                    unit->bl.y += dy;
                    map_addblock(&unit->bl);
                    if (range > 0)
                    {
                        if (range < 7)
                            range = 7;
                        map_foreachinarea(std::bind(skill_unit_move_unit_group_sub, ph::_1, &unit->bl, gettick()),
                                unit->bl.m, unit->bl.x - range, unit->bl.y - range,
                                unit->bl.x + range, unit->bl.y + range, BL_NUL);
                    }
                }
            }
        }
        else
        {
            int i, j, *r_flag, *s_flag, *m_flag;
            struct skill_unit *unit1;
            struct skill_unit *unit2;
            r_flag = (int *) malloc(sizeof(int) * group->unit_count);
            s_flag = (int *) malloc(sizeof(int) * group->unit_count);
            m_flag = (int *) malloc(sizeof(int) * group->unit_count);
            memset(r_flag, 0, sizeof(int) * group->unit_count);   // 継承フラグ
            memset(s_flag, 0, sizeof(int) * group->unit_count);   // 継承フラグ
            memset(m_flag, 0, sizeof(int) * group->unit_count);   // 継承フラグ

            //先にフラグを全部決める
            for (i = 0; i < group->unit_count; i++)
            {
                int move_check = 0;    // かぶりフラグ
                unit1 = &group->unit[i];
                for (j = 0; j < group->unit_count; j++)
                {
                    unit2 = &group->unit[j];
                    if (unit1->bl.m == m && unit1->bl.x + dx == unit2->bl.x
                        && unit1->bl.y + dy == unit2->bl.y)
                    {
                        //移動先にユニットがかぶってたら
                        s_flag[i] = 1;  // 移動前のユニットナンバーの継承フラグon
                        r_flag[j] = 1;  // かぶるユニットナンバーの残留フラグon
                        move_check = 1; //ユニットがかぶった。
                        break;
                    }
                }
                if (!move_check)    // ユニットがかぶってなかったら
                    m_flag[i] = 1;  // 移動前ユニットナンバーの移動フラグon
            }

            //フラグに基づいてユニット移動
            for (i = 0; i < group->unit_count; i++)
            {
                unit1 = &group->unit[i];
                if (m_flag[i])
                {               // 移動フラグがonで
                    if (!r_flag[i])
                    {           // 残留フラグがoffなら
                        //単純移動(rangeも継承の必要無し)
                        int range = unit1->range;
                        map_delblock(&unit1->bl);
                        unit1->bl.m = m;
                        unit1->bl.x += dx;
                        unit1->bl.y += dy;
                        map_addblock(&unit1->bl);
                        if (range > 0)
                        {
                            if (range < 7)
                                range = 7;
                            map_foreachinarea(std::bind(skill_unit_move_unit_group_sub, ph::_1, &unit1->bl, gettick()),

                                    unit1->bl.m, unit1->bl.x - range, unit1->bl.y - range,
                                    unit1->bl.x + range, unit1->bl.y + range, BL_NUL);
                        }
                    }
                    else
                    {           // 残留フラグがonなら
                        //空ユニットになるので、継承可能なユニットを探す
                        for (j = 0; j < group->unit_count; j++)
                        {
                            unit2 = &group->unit[j];
                            if (s_flag[j] && !r_flag[j])
                            {
                                // 継承移動(range継承付き)
                                int range = unit1->range;
                                map_delblock(&unit2->bl);
                                unit2->bl.m = m;
                                unit2->bl.x = unit1->bl.x + dx;
                                unit2->bl.y = unit1->bl.y + dy;
                                unit2->range = unit1->range;
                                map_addblock(&unit2->bl);
                                if (range > 0)
                                {
                                    if (range < 7)
                                        range = 7;
                                    map_foreachinarea(std::bind(skill_unit_move_unit_group_sub, ph::_1, &unit2->bl, gettick()),

                                            unit2->bl.m, unit2->bl.x - range, unit2->bl.y - range,
                                            unit2->bl.x + range, unit2->bl.y + range, BL_NUL);
                                }
                                s_flag[j] = 0;  // 継承完了したのでoff
                                break;
                            }
                        }
                    }
                }
            }
            free(r_flag);
            free(s_flag);
            free(m_flag);
        }
    }
    return 0;
}

/*----------------------------------------------------------------------------
 * アイテム合成
 *----------------------------------------------------------------------------
 */

/*----------------------------------------------------------------------------
 * 初期化系
 */

static
SP scan_stat(char *statname)
{
    if (!strcasecmp(statname, "str"))
        return SP_STR;
    if (!strcasecmp(statname, "dex"))
        return SP_DEX;
    if (!strcasecmp(statname, "agi"))
        return SP_AGI;
    if (!strcasecmp(statname, "vit"))
        return SP_VIT;
    if (!strcasecmp(statname, "int"))
        return SP_INT;
    if (!strcasecmp(statname, "luk"))
        return SP_LUK;
    if (!strcasecmp(statname, "none"))
        return SP::ZERO;

    fprintf(stderr, "Unknown stat `%s'\n", statname);
    return SP::ZERO;
}

/*==========================================
 * スキル関係ファイル読み込み
 * skill_db.txt スキルデータ
 * skill_cast_db.txt スキルの詠唱時間とディレイデータ
 *------------------------------------------
 */
static
int skill_readdb(void)
{
    int j, k, l;
    FILE *fp;
    char line[1024], *p;

    /* The main skill database */
    memset(&skill_db, 0, sizeof(skill_db));
    fp = fopen_("db/skill_db.txt", "r");
    if (fp == NULL)
    {
        printf("can't read db/skill_db.txt\n");
        return 1;
    }
    while (fgets(line, 1020, fp))
    {
        char *split[50], *split2[MAX_SKILL_LEVEL];
        if (line[0] == '/' && line[1] == '/')
            continue;
        for (j = 0, p = line; j < 18 && p; j++)
        {
            while (*p == '\t' || *p == ' ')
                p++;
            split[j] = p;
            p = strchr(p, ',');
            if (p)
                *p++ = 0;
        }
        if (split[17] == NULL || j < 18)
        {
            fprintf(stderr, "Incomplete skill db data online (%d entries)\n",
                     j);
            continue;
        }

        SkillID i = SkillID(atoi(split[0]));
        if (/*i < SkillID() ||*/ i > MAX_SKILL_DB)
            continue;

        memset(split2, 0, sizeof(split2));
        for (j = 0, p = split[1]; j < MAX_SKILL_LEVEL && p; j++)
        {
            split2[j] = p;
            p = strchr(p, ':');
            if (p)
                *p++ = 0;
        }
        for (k = 0; k < MAX_SKILL_LEVEL; k++)
            skill_db[i].range[k] =
                (split2[k]) ? atoi(split2[k]) : atoi(split2[0]);
        skill_db[i].hit = atoi(split[2]);
        skill_db[i].inf = atoi(split[3]);
        skill_db[i].pl = atoi(split[4]);
        skill_db[i].nk = atoi(split[5]);
        skill_db[i].max_raise = atoi(split[6]);
        skill_db[i].max = atoi(split[7]);

        memset(split2, 0, sizeof(split2));
        for (j = 0, p = split[8]; j < MAX_SKILL_LEVEL && p; j++)
        {
            split2[j] = p;
            p = strchr(p, ':');
            if (p)
                *p++ = 0;
        }
        for (k = 0; k < MAX_SKILL_LEVEL; k++)
            skill_db[i].num[k] =
                (split2[k]) ? atoi(split2[k]) : atoi(split2[0]);

        if (strcasecmp(split[9], "yes") == 0)
            skill_db[i].castcancel = 1;
        else
            skill_db[i].castcancel = 0;
        skill_db[i].cast_def_rate = atoi(split[9]);
        skill_db[i].inf2 = atoi(split[10]);
        skill_db[i].maxcount = atoi(split[11]);
        if (strcasecmp(split[13], "weapon") == 0)
            skill_db[i].skill_type = BF_WEAPON;
        else if (strcasecmp(split[12], "magic") == 0)
            skill_db[i].skill_type = BF_MAGIC;
        else if (strcasecmp(split[12], "misc") == 0)
            skill_db[i].skill_type = BF_MISC;
        else
            skill_db[i].skill_type = BF::ZERO;
        memset(split2, 0, sizeof(split2));
        for (j = 0, p = split[14]; j < MAX_SKILL_LEVEL && p; j++)
        {
            split2[j] = p;
            p = strchr(p, ':');
            if (p)
                *p++ = 0;
        }
        for (k = 0; k < MAX_SKILL_LEVEL; k++)
            skill_db[i].blewcount[k] =
                (split2[k]) ? atoi(split2[k]) : atoi(split2[0]);

        if (!strcasecmp(split[15], "passive"))
        {
            skill_pool_register(i);
            skill_db[i].poolflags = SKILL_POOL_FLAG;
        }
        else if (!strcasecmp(split[15], "active"))
        {
            skill_pool_register(i);
            skill_db[i].poolflags = SKILL_POOL_FLAG | SKILL_POOL_ACTIVE;
        }
        else
            skill_db[i].poolflags = SkillFlags::ZERO;

        skill_db[i].stat = scan_stat(split[16]);

        char *tmp = strdup(split[17]);
        {
            // replace "_" by " "
            char *s = tmp;
            while ((s = strchr(s, '_')))
                *s = ' ';
            if ((s = strchr(tmp, '\t'))
                || (s = strchr(tmp, ' '))
                || (s = strchr(tmp, '\n')))
                *s = '\000';
        }
        skill_lookup_by_id(i).desc = tmp;
    }
    fclose_(fp);
    printf("read db/skill_db.txt done\n");

    fp = fopen_("db/skill_require_db.txt", "r");
    if (fp == NULL)
    {
        printf("can't read db/skill_require_db.txt\n");
        return 1;
    }
    while (fgets(line, 1020, fp))
    {
        char *split[51], *split2[MAX_SKILL_LEVEL];
        if (line[0] == '/' && line[1] == '/')
            continue;
        for (j = 0, p = line; j < 30 && p; j++)
        {
            while (*p == '\t' || *p == ' ')
                p++;
            split[j] = p;
            p = strchr(p, ',');
            if (p)
                *p++ = 0;
        }
        if (split[29] == NULL || j < 30)
            continue;

        SkillID i = SkillID(atoi(split[0]));
        if (/*i < SkillID() ||*/ i > MAX_SKILL_DB)
            continue;

        memset(split2, 0, sizeof(split2));
        for (j = 0, p = split[1]; j < MAX_SKILL_LEVEL && p; j++)
        {
            split2[j] = p;
            p = strchr(p, ':');
            if (p)
                *p++ = 0;
        }
        for (k = 0; k < MAX_SKILL_LEVEL; k++)
            skill_db[i].hp[k] =
                (split2[k]) ? atoi(split2[k]) : atoi(split2[0]);

        memset(split2, 0, sizeof(split2));
        for (j = 0, p = split[2]; j < MAX_SKILL_LEVEL && p; j++)
        {
            split2[j] = p;
            p = strchr(p, ':');
            if (p)
                *p++ = 0;
        }
        for (k = 0; k < MAX_SKILL_LEVEL; k++)
            skill_db[i].mhp[k] =
                (split2[k]) ? atoi(split2[k]) : atoi(split2[0]);

        memset(split2, 0, sizeof(split2));
        for (j = 0, p = split[3]; j < MAX_SKILL_LEVEL && p; j++)
        {
            split2[j] = p;
            p = strchr(p, ':');
            if (p)
                *p++ = 0;
        }
        for (k = 0; k < MAX_SKILL_LEVEL; k++)
            skill_db[i].sp[k] =
                (split2[k]) ? atoi(split2[k]) : atoi(split2[0]);

        memset(split2, 0, sizeof(split2));
        for (j = 0, p = split[4]; j < MAX_SKILL_LEVEL && p; j++)
        {
            split2[j] = p;
            p = strchr(p, ':');
            if (p)
                *p++ = 0;
        }
        for (k = 0; k < MAX_SKILL_LEVEL; k++)
            skill_db[i].hp_rate[k] =
                (split2[k]) ? atoi(split2[k]) : atoi(split2[0]);

        memset(split2, 0, sizeof(split2));
        for (j = 0, p = split[5]; j < MAX_SKILL_LEVEL && p; j++)
        {
            split2[j] = p;
            p = strchr(p, ':');
            if (p)
                *p++ = 0;
        }
        for (k = 0; k < MAX_SKILL_LEVEL; k++)
            skill_db[i].sp_rate[k] =
                (split2[k]) ? atoi(split2[k]) : atoi(split2[0]);

        memset(split2, 0, sizeof(split2));
        for (j = 0, p = split[6]; j < MAX_SKILL_LEVEL && p; j++)
        {
            split2[j] = p;
            p = strchr(p, ':');
            if (p)
                *p++ = 0;
        }
        for (k = 0; k < MAX_SKILL_LEVEL; k++)
            skill_db[i].zeny[k] =
                (split2[k]) ? atoi(split2[k]) : atoi(split2[0]);

        memset(split2, 0, sizeof(split2));
        for (j = 0, p = split[7]; j < 32 && p; j++)
        {
            split2[j] = p;
            p = strchr(p, ':');
            if (p)
                *p++ = 0;
        }
        for (k = 0; k < 32 && split2[k]; k++)
        {
            l = atoi(split2[k]);
            if (l == 99)
            {
                skill_db[i].weapon = 0xffffffff;
                break;
            }
            else
                skill_db[i].weapon |= 1 << l;
        }

        if (strcasecmp(split[8], "hiding") == 0)
            skill_db[i].state = ST_HIDING;
        else if (strcasecmp(split[8], "cloaking") == 0)
            skill_db[i].state = ST_CLOAKING;
        else if (strcasecmp(split[8], "hidden") == 0)
            skill_db[i].state = ST_HIDDEN;
        else if (strcasecmp(split[8], "riding") == 0)
            skill_db[i].state = ST_RIDING;
        else if (strcasecmp(split[8], "falcon") == 0)
            skill_db[i].state = ST_FALCON;
        else if (strcasecmp(split[8], "cart") == 0)
            skill_db[i].state = ST_CART;
        else if (strcasecmp(split[8], "shield") == 0)
            skill_db[i].state = ST_SHIELD;
        else if (strcasecmp(split[8], "sight") == 0)
            skill_db[i].state = ST_SIGHT;
        else if (strcasecmp(split[8], "explosionspirits") == 0)
            skill_db[i].state = ST_EXPLOSIONSPIRITS;
        else if (strcasecmp(split[8], "recover_weight_rate") == 0)
            skill_db[i].state = ST_RECOV_WEIGHT_RATE;
        else if (strcasecmp(split[8], "move_enable") == 0)
            skill_db[i].state = ST_MOVE_ENABLE;
        else if (strcasecmp(split[8], "water") == 0)
            skill_db[i].state = ST_WATER;
        else
            skill_db[i].state = ST_NONE;

        memset(split2, 0, sizeof(split2));
        for (j = 0, p = split[9]; j < MAX_SKILL_LEVEL && p; j++)
        {
            split2[j] = p;
            p = strchr(p, ':');
            if (p)
                *p++ = 0;
        }
        for (k = 0; k < MAX_SKILL_LEVEL; k++)
            skill_db[i].spiritball[k] =
                (split2[k]) ? atoi(split2[k]) : atoi(split2[0]);
        skill_db[i].itemid[0] = atoi(split[10]);
        skill_db[i].amount[0] = atoi(split[11]);
        skill_db[i].itemid[1] = atoi(split[12]);
        skill_db[i].amount[1] = atoi(split[13]);
        skill_db[i].itemid[2] = atoi(split[14]);
        skill_db[i].amount[2] = atoi(split[15]);
        skill_db[i].itemid[3] = atoi(split[16]);
        skill_db[i].amount[3] = atoi(split[17]);
        skill_db[i].itemid[4] = atoi(split[18]);
        skill_db[i].amount[4] = atoi(split[19]);
        skill_db[i].itemid[5] = atoi(split[20]);
        skill_db[i].amount[5] = atoi(split[21]);
        skill_db[i].itemid[6] = atoi(split[22]);
        skill_db[i].amount[6] = atoi(split[23]);
        skill_db[i].itemid[7] = atoi(split[24]);
        skill_db[i].amount[7] = atoi(split[25]);
        skill_db[i].itemid[8] = atoi(split[26]);
        skill_db[i].amount[8] = atoi(split[27]);
        skill_db[i].itemid[9] = atoi(split[28]);
        skill_db[i].amount[9] = atoi(split[29]);
    }
    fclose_(fp);
    printf("read db/skill_require_db.txt done\n");

    /* ? */
    fp = fopen_("db/skill_cast_db.txt", "r");
    if (fp == NULL)
    {
        printf("can't read db/skill_cast_db.txt\n");
        return 1;
    }
    while (fgets(line, 1020, fp))
    {
        char *split[50], *split2[MAX_SKILL_LEVEL];
        memset(split, 0, sizeof(split));  // [Valaris] thanks to fov
        if (line[0] == '/' && line[1] == '/')
            continue;
        for (j = 0, p = line; j < 5 && p; j++)
        {
            while (*p == '\t' || *p == ' ')
                p++;
            split[j] = p;
            p = strchr(p, ',');
            if (p)
                *p++ = 0;
        }
        if (split[4] == NULL || j < 5)
            continue;

        SkillID i = SkillID(atoi(split[0]));
        if (/*i < SkillID() ||*/ i > MAX_SKILL_DB)
            continue;

        memset(split2, 0, sizeof(split2));
        for (j = 0, p = split[1]; j < MAX_SKILL_LEVEL && p; j++)
        {
            split2[j] = p;
            p = strchr(p, ':');
            if (p)
                *p++ = 0;
        }
        for (k = 0; k < MAX_SKILL_LEVEL; k++)
            skill_db[i].cast[k] =
                (split2[k]) ? atoi(split2[k]) : atoi(split2[0]);

        memset(split2, 0, sizeof(split2));
        for (j = 0, p = split[2]; j < MAX_SKILL_LEVEL && p; j++)
        {
            split2[j] = p;
            p = strchr(p, ':');
            if (p)
                *p++ = 0;
        }
        for (k = 0; k < MAX_SKILL_LEVEL; k++)
            skill_db[i].delay[k] =
                (split2[k]) ? atoi(split2[k]) : atoi(split2[0]);

        memset(split2, 0, sizeof(split2));
        for (j = 0, p = split[3]; j < MAX_SKILL_LEVEL && p; j++)
        {
            split2[j] = p;
            p = strchr(p, ':');
            if (p)
                *p++ = 0;
        }
        for (k = 0; k < MAX_SKILL_LEVEL; k++)
            skill_db[i].upkeep_time[k] =
                (split2[k]) ? atoi(split2[k]) : atoi(split2[0]);

        memset(split2, 0, sizeof(split2));
        for (j = 0, p = split[4]; j < MAX_SKILL_LEVEL && p; j++)
        {
            split2[j] = p;
            p = strchr(p, ':');
            if (p)
                *p++ = 0;
        }
        for (k = 0; k < MAX_SKILL_LEVEL; k++)
            skill_db[i].upkeep_time2[k] =
                (split2[k]) ? atoi(split2[k]) : atoi(split2[0]);
    }
    fclose_(fp);
    printf("read db/skill_cast_db.txt done\n");

    fp = fopen_("db/skill_castnodex_db.txt", "r");
    if (fp == NULL)
    {
        printf("can't read db/skill_castnodex_db.txt\n");
        return 1;
    }
    while (fgets(line, 1020, fp))
    {
        char *split[50], *split2[MAX_SKILL_LEVEL];
        memset(split, 0, sizeof(split));
        if (line[0] == '/' && line[1] == '/')
            continue;
        for (j = 0, p = line; j < 2 && p; j++)
        {
            while (*p == '\t' || *p == ' ')
                p++;
            split[j] = p;
            p = strchr(p, ',');
            if (p)
                *p++ = 0;
        }

        SkillID i = SkillID(atoi(split[0]));
        if (/*i < SkillID() ||*/ i > MAX_SKILL_DB)
            continue;

        memset(split2, 0, sizeof(split2));
        for (j = 0, p = split[1]; j < MAX_SKILL_LEVEL && p; j++)
        {
            split2[j] = p;
            p = strchr(p, ':');
            if (p)
                *p++ = 0;
        }
        for (k = 0; k < MAX_SKILL_LEVEL; k++)
            skill_db[i].castnodex[k] =
                (split2[k]) ? atoi(split2[k]) : atoi(split2[0]);
    }
    fclose_(fp);
    printf("read db/skill_castnodex_db.txt done\n");

    return 0;
}

void skill_reload(void)
{
    /*
     *
     * <empty skill database>
     * <?>
     *
     */

    do_init_skill();
}

/*==========================================
 * スキル関係初期化処理
 *------------------------------------------
 */
int do_init_skill(void)
{
    skill_readdb();

    add_timer_interval(gettick() + SKILLUNITTIMER_INVERVAL,
                        skill_unit_timer, 0, 0, SKILLUNITTIMER_INVERVAL);

    return 0;
}

constexpr size_t num_names = sizeof(skill_names) / sizeof(skill_names[0]);

skill_name_db& skill_lookup_by_id(SkillID id)
{
    for (skill_name_db& ner : skill_names)
        if (ner.id == id)
            return ner;
    return skill_names[num_names - 1];
}

skill_name_db& skill_lookup_by_name(const char *name)
{
    for (skill_name_db& ner : skill_names)
        if (!strcasecmp(name, ner.name) || !strcasecmp(name, ner.desc))
            return ner;
    return skill_names[num_names - 1];
}