summaryrefslogblamecommitdiff
path: root/src/map/clif.cpp
blob: 1deb1f359f29664891627699e5251189df542573 (plain) (tree)
1
2
3
4
5
6
7
8
9
5034
5035
5036
5037
5038
5039
5040
5041
5042
5043
5044
5045
5046
5047
5048
5049
5050
5051
5052
5053
5054
5055
5056
5057
5058
5059
5060
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
5071
5072
5073
5074
5075
5076
5077
5078
5079
5080
5081
5082
5083
5084
5085
5086
5087
5088
5089
5090
5091
5092
5093
5094
5095
5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
5141
5142
5143
5144
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279
5280
5281
5282
5283
5284
5285
5286
5287
5288
5289
5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
5334
5335
5336
5337
5338
5339
5340
5341
5342
5343
5344
5345
5346
5347
5348
5349
5350
5351
5352
5353
5354
5355
5356
5357
5358
5359
5360
5361
5362
5363
5364
5365
5366
5367
5368
5369
5370
5371
5372
5373
5374
5375
5376
5377
5378
5379
5380
5381
5382
5383
5384
5385
5386
5387
5388
5389
5390
5391
5392
5393
5394
5395
5396
5397
5398
5399
5400
5401
5402
5403
5404
5405
5406
5407
5408
5409
5410
5411
5412
5413
5414
5415
5416
5417
5418
5419
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429
5430
5431
5432
5433
5434
5435
5436
5437
5438
5439
5440
5441
5442
5443
5444
5445
5446
5447
5448
5449
5450
5451
5452
5453
5454
5455
5456
5457
5458
5459
5460
5461
5462
5463
5464
5465
5466
5467
5468
5469
5470
5471
5472
5473
5474
5475
5476
5477
5478
5479
5480
5481
5482
5483
5484
5485
5486
5487
5488
5489
5490
5491
5492
5493
5494
5495
5496
5497
5498
5499
5500
5501
5502
5503
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
5514
5515
5516
5517
5518
5519
5520
5521
5522
5523
5524
5525
5526
5527
5528
5529
5530
5531
5532
5533
5534
5535
5536
5537
5538
5539
5540
5541
5542
5543
5544
5545
5546
5547
5548
5549
5550
5551
5552
5553
5554
5555
5556
5557
5558
5559
5560
5561
5562
5563
5564
5565
5566
5567
5568
5569
5570
5571
5572
5573
5574
5575
5576
5577
5578
5579
                   
 
                      
 



                  
                                 
                                
                               
                               
                               
                              
                                
 

                        
                    



                     


                    



                      
 

                        
                                 
 
                                   
 















                                                                     

  





                                         
               
                  







                  
         






                      
         

  

















                                                                                         
 









                                                                                      
 





                      
 
      
                                                                      

                                                             
                                            
                    

                                            
                               
 

                                          


                                            
                      

                                            
                           
 
                    


                                            
                          

                                            
                               
 
                  


                                            
                            

                                            
                      
 
                    





                                            
                         
 
                     
                                
 

                                
                                                                                          
                                                                
                                                   


                    


                                            
                                          

                                            
                                                                           
 
          
                                
 

                                
                                                                                          
                              
                     
     
             

 

                                  
 
                                                                 
                                  

                                  

 

                                                
                                                                       
 

                                                               
                                                   
 
                                            
                                         

                                            
      
                                                                            
                                                
 
                    
                                                                 
 

                 
                               
                                   
                       
                  
 
                                    
                           
                                       
                                                                     
             
                                                                
                       
             
                        
                               
                                                           
                       
 
                  
                                

                                                                              
                       




                                
                                     
         

                                                                                                
                                
                                                           



                                                                                             


                                                         

                                                    


             





                                            
      
                                                                               
 
          


                                
                                       
 
                                    
     
                       
 
                               
         
                                                                          
                                                                

                                     
 

                             


                                             
                              
 

                                            
                                 
 








                              
                                                                         

                                        
                                                                                                    

                                      
                                                                 
                                                    

                                                       



                     
                                                                                           

                                        
                                                                                                    

                                                           
                                                                 
                                                    

                                                       



                     



                                

                                                                                   
                                                                  
                  

                                                                                                     
                                                                    
                                                                      
                  

                               
                                         
                                   

                                                    
                                                                
             
                                          




                                           
                                             

                                                                       
                                                             
                                                    

                                                                   



                  

                                                                                                                



                                   
                        



                                                                                                                    
                                   



                                                    
                                                   



                                                
                                                              







                                                       

                                                                                      
                                                              
                                                                             
                                     
                                                                                                                                  
                                     
                                                                                               


                                                              
                                                                     
                                                    

                                                                


                         

                                            
                                                                                                        



                                                        
                                                                         
                                                    

                                                                    





                             
                           
                                                
                                                         
                                                    

                                                    

                  
 

                                        
                                                                  

                      
 
             


  
                              




                                            
                                            
 
           
 
                   
 

                 
 

                 
 
                
 
                         
                                                         


                                        
                                                  
 
             





                                            
                                      


                            
 

                         
                                                  
 
                          
 
             





                                            
                             

                                
           
 
                                     
                 
 

                 
 
                

                         
                                                  
 
             





                                            

                                                            
 
             
 
                      
 
                                                                                        



                                                            
        






                                                
 
                                           





                                            
                                                    
 
                    
 
                      
 

                                     
                             
                                                                               
 
             





                                            
                                                             

                          
 
                      
 

                                 
 

                
                                                                                   


        
                                      
                                                      
     
 
             





                                            
                                                              

                          
 
                   
 

                           
                                         
     
                                                                   
                                                                           


        
                                                   

                                                                                     
     
 
             

 
      

                                                   
 
                             
                      

 

                                                   
 
                             
                                        
 
                                                 
               
                                                               

                            
 
             





                                            
                                                          

                          
 

                         
                                               
                                  
                                                  
 
             





                                            

                                                                 
 
                   
 

                              



                                                              
                                        
                                     
                                  
                                                        

        

                                                                  
         
                                                                                
                                
                                                                                
                
                                
                                                                                
         
            
                               
     


                                                                           
     

                                                                                         
            
                                                                                         

        





                                              
                                                        


                                           
                                        


                                         


                                                


                                                                         
 
                                            





                                            

                                                                 
 
                   
 

                              



                                                              
                                        
                                     

                                                              
     

                                                                                         
            
                                                                                         

        
                           


                                                                           
     

                                                                                         
            
                                                                                         

        

                                            
                                                          



                                              
                                                        


                                          
                                        





                                                              
 
                                            


                                            
             

                                            

                                                         
 
              
 
                                                    
 
                   
 

                              



                                                                             

                                              
                                         


                                                


                       
                 
                                   
                                                              
 
                                           


                                            
             

                                            

                                                         
 
              
 
                                                    
 
                   
 

                              



                                                                             

                                                
                                                          
 



                                                              
                 
                                   

                                                              
                                           





                                            

                                                         
 
                   
 
                                                    
 

                              
                                                             

                                         


                                                

                       
 
                                           

 
                                                                         
      

                                                 













                                               
   
 



                                            
                                             

                           
 
                   
 
                          
 

                          
                                                                                 
 
                                
                                            
                               
                                            
                                  
                                            
                                  
                                            
                                
                                            
 
                                                     
 
             





                                            
                                      
 
                          
            
 
                   
 
                                                                              
                 
 
                                                    
 

                              
                                                             

                                         
 
                                                                            
 
                                
                                                
 
             

 
                                                                                
 
           
 
                   
 

                
                 
 







                                         
                                                  
 











                                                   
                                                  


             
 



                                            
                                      
 
                          
            
 
                   
 
     
                                                        
 

                                  
                                                   


                                              
                                       
                                             
                                                                                

     
                                
                                                
 
             

 



                                            
      
                                                
 
           
 
                   
 
                
                         

                                                               
 
             





                                            
                                            
 
           
 
                   
 
                
                         
                                                         

                                                             
                                                  
 
             





                                            
                                              
 
            
                           
 
                   
 
                                
 
                                                    
 
                                                                           
                                                     
                                                   
 
             





                                            
      
                                                    
 
                 





                                            
      
                                                
 

                                                   

                             





                                            
                              
 
                                              
                                                     

                   





                                            
                                                                                  
 
           
 
                   
 
                
 



                                       
                                                  
 
             





                                            
                                                                                 
                                                             
 
           
 
                   
 
                





                                       
                                                  
 
             





                                            
                                      
 
                    
 
                   
 



                           
 
                                                                       
 
             





                                            
                                                        
 
           
 
                   
 
                

                         
                                                  
 
             





                                            
                                                                  

                         
                   
 

                   

                
                         

                                                   
                                                      
                                       

                                                     
                                                    
                            
                                                  
            
                                                                
     

                                

             





                                            
                                              
 
                          
 
                   

                
                         






                                                                        
                                           

                                                          


                

                                

             





                                            
                                                                           
 
           
 
                   
 
                




                                       
 
             





                                            
                                                           
 
           
 
                   
 
                

                          
                                                  
 
             





                                            
                                                            
 
           
 
                   
 
                

                          
                                                  
 
             





                                            
                                                                            
 
           
 
                   
 
                




                                       
 
             





                                            
                                                            
 
           
 
                   
 
                

                          
                                                   
 
             





                                            
                                                               
 
           
 
                   
 
                

                          
                                                   
 
             





                                            
                                                                            

                                             
           
 
                   
 
                






                           
                                                   
 
             





                                            
                                                                        
 
           
 
                   
 
                


                                     
                                                   
 
             





                                            
                                                                                 
 
                   
 
                    
                                 
     













                                       






                                                                              


                               
                                               
                                                           
            

                                                           
                                                
                                                            
            

                                                              



                                                                 



                                                             


            
                  
                                                   
                                                                            
                                   
                
                                                                 
                                                   
                                                                            
                                   
                
                                                                 
                                                   
                                                                            
                                   
                
                                                                 
                                                   
                                                                            
                                   
                
                                                                 
         

                                                                            

                                           
                                       
     
 
                                                  
             





                                            
                                                                
 
           
 
                   
 
                


                           
 
                                                  
 
             





                                            
                                              
 
                   
 




                                           


                                               
                                                      
                     
                                       
                                               
                                                                    
            



                                                                      
                                                        
         
                                                            
                                                    
                                                                    

            




                                                                  



            
                                   
                                    

                   
                                   
             





                                            
                                               
 
                   
 



                                           


                                               
                                                       
                     
                                       
                                               
                                                                    
            

                                                                    


                                                           


                                                                          
                                                
                                                                        
            

                                                                        



                                                                 



                                                                      


            
                  
                                                   
                                                                            
                                            
                
                                                                          
                                                   
                                                                            
                                            
                
                                                                          
                                                   
                                                                            
                                            
                
                                                                          
                                                   
                                                                            
                                            
                
                                                                          




            
                                   
                                    

             


                                            
                                                                

                                            
                                                                           
 

                     
 



                                         


                                          

                             

                                                     
                                

                     
                                       
                            
                                                 
            








                                                              



            
                                   
                                    

             


                                            
                                                   

                                            
                                                                            
 

                     
 



                                         


                                          

                             

                                                     
                                 
                     
                                       
                            
                                                 
            




                                                                    
                                          
                                                                       
            

                                                                  



                                                           



                                                                


            
                  
                                             
                                                                      
                                            
                
                                                                    
                                             
                                                                      
                                            
                
                                                                    
                                             
                                                                      
                                            
                
                                                                    
                                             
                                                                      
                                            
                
                                                                    




            
                                   
                                    

             


                                            

                                                      

                                            
                                                           
 
                    
 
                   


                
                         
                                                


                   
                        
                                   
                                                                         
                                 
                                                        
                                       
                  
                           
                                           
                  
                       

                                                                     
                  
                           
                                                  
                  
                          
                              
                  
                             
                                                    
                  
                            
                                                   
                  
                     
                                    
                  
                       
                                     
                  
                       
                                           
                  
                       
                                              
                  
                       
                                              
                  
                    
                                          
                  
                    
                                          
                  
                      
                                                                    
                  
                      
                                                    
                  
                      
                                    
                  
                       
                                     
                  
                      
                                      
                  
                      
                                     
                  
                       
                                      
                  
                          
                                              
                  
                       
                                      
                  
                       
                                      

                  
                      

                                 

                                    
                                            
                  
                         

                                                
                  
                        

                                               
                  
                             

                                               
                  
                            

                                              

                  
                          





                      
                                 
                                                                      


                    
                          
                             

                                                       



                                                           
                          





                     

                                         
                                  


                                                                 
                     
         

                  
                    
                                        



                                        

                                                               

                     
                      



             



                                            
                                                              
 
                                                        
 
 
                                                                      
                                                            
 
                          
                                       
 
                   
 
                           
                                            
 
                                                             
                 
 
          
                                                                                 
     

                               
                                
         
                                                   
 
                                           
                                                 
                                                                    


                                                                              
                                   

                                                                              
                    
                                   



                                                                              

                                  


            
                              
                                          
                                                               

                
                                                       
                                                                          
                 
                                                                                        
                                       
                                                                                        
                        
                                       
                                                                                        
                 
                    
                                      
             

                                                                                   
                                                                      
             
                                                                                    
                                   
                                                                                    
                    
                                   
                                                                                    

                
                                  

                  
                                                                                        
            
                                                                                


        

                               
                                      

                            
                  
                                                                                        
            
                                                                                

             





                                            
      
                                                   
 
                   
 





                                                          
                                                      
                                                          
                                                      
                                                          
                                                      
                                                           
                                                       
                                                           
                                                       
                                                           
                                                       














                                              
 
                                                  
 





                                   
 

                                           

             


                                            
           

                                            
                                                         
 
           
 
                   
 

                                                                
 
                

                                                     
 
                                                    
 
             





                                            
                                                          
 
           
 
                   
 
                

                           
 
                                                    
 
             


                                            


                                            
                                                                           
 
           
 
                   
 
                
                         
                                   

                        
                                                  
 
             





                                            
                                                                           
 
           
 
                   
 
                

                          
                                  
                       
                                                  
 
             





                                            
                                                                             
 
           
 
                   
 
                

                          
                                  
                       
                                                  
 
             





                                            
                                                    
 
                    
 
                   
 


                           
 
                                                                        
 
             
 
 
                                            
                              

                                            
                                            
 
                    
                                                     
 
                   
 
                                           
                                     
 

                           


                                                   
                                    
 
                                                                        
 
             





                                            
                                                                       
                            
 
                   
 

            




                                  
                                                      


        
                        
 

                                  

                                                      
                                                               
            



                                                               
                                                                                 


             


                                            
                           

                                            
                                                                    
 
           
 
                   
 
                

                                        
                                                  
 
             


                                            
                           

                                            
                                                          
 
           
 
                   
 
                

                         
                                                  
 
             


                                            
                                       

                                            
                                                  

                                                                           
              
 

                    

                 

                           

                   







                                              





                                                      
                                                               
            

                                                                              
                                                    
                                                           
            

                                                                               



                                                                     



                                                                              




                                                       

                                                                            
                
                                                                     

                                                       

                                                                            
                
                                                                     

                                                       

                                                                            
                
                                                                     

                                                       

                                                                            
                
                                                                     

         
                                                  
 
             


                                            
                                  

                                            
                                                                        
                               
 
           
 
                   
 
                
                          


                           
                                                   
 
             


                                            
                       

                                            
                                                              
 
           
 
                   
 
                

                                                          
                                                  
 
             


                                            
                                                

                                            
                                                    
 
           
 
                   
 
                
                         
                                                  
 
             


                                            
                     

                                            
                                                              
 
           
 
                   
 
                

                         
                                                  
 
             


                                            
                                             

                                            
                                                         
                                                   
 
           
 

                     
 
                


                                                       
                                                  
 
             


                                            
                                                

                                            
                                                                            
                                                 
 
              
 

                     
 
                







                                                                      
                                          
                                                            
        

                                                                       



                                                           



                                                                      



                                             

                                                                      
            
                                                           
                                             

                                                                      
            
                                                           
                                             

                                                                      
            
                                                           
                                             

                                                                      
            
                                                           
     
                                                  

             


                                            
                                                   

                                            
                                                                   
                                        
 
           
 
                   
 
                


                                                      
                                                  
 
             


                                            
                              

                                            
                                                  
 
           
 
                   
 
                
                                                
                                                  
 
             

 
                                                       
                                                           
 
                                                                         
                                                

 
  
                

                                            
           

                                            
      
                                                     
                                                         
 
            
 
                                                          
               
 

                       
 
                         
     
                                                                             
                              


        
                                                                             
                              
     
 
                                                                              
                                                        
                                                      
 

                                                


                                            
            

                                            
      
                                                                           
 
            
 

                    
 
                                                                              
               
 
                                                                      
                          


                                            
               

                                            
                                     
 
                           
            
 
                   
 
                                
                                                
 
             


                                            
                                 

                                            
                                       
 
                           
            
 
                   
 
                                    
     
                                    
                                                    


        
                                    
                                                    
     
 
             


                                            
                    

                                            
                                              
 
                           
            
 
                   
 
                      
     
                                    
                                                    


        
                                    
                                                    
     
                                               
 
             


                                            
                                             

                                            
                                                               

                                                                      

                           
                                                     
 

                    
 
                                      
 


                            


                                                     

                                                         
                                                
                             
                                                                        
 
             





                                            
      
                                                                           
 


                    
 
                                    
     
                                                                          
                              


        
                                                                          
                              
     





                                            
      
                                                       
                                                         
 
                 
 

                       


                                                                                        



                                                            
        






                                                
 
                                                  
 
 
                                            


                                            
      
                                                                         
 
                    


                     
                    

                                                     
                                                                    
                  
                     
                                                             
                  
                     
                                                             
                  
                      
                                                                    
                  

                                        

                                                

                  





                                            
                                                                        
 
                                   
 
                    
                    
 

                     
                    


                                                   

                                                                              

                  
                     
                                                                       
                                                                        
                  

                                                                    
                  
                      
                                                                      
                  
     





                                            
                                                                       
 
                                   
 
                    
                    
 

                     
                    


                                                   

                                               

                  
                     
                                                             
                  
                     
                                                             
                  
                      
                                                                    
                  
     





                                            
                                                                 
 
                                
 
                    
                    
 
                                                                    
     
                                                                   
     





                                            
                                                                
 
                                
 
                    
                    
 
                                                                    
     
                                     
     





                                            
                                                                          

                              
           
 
                   

                
                                      
                 
                          
                                                   
                 
                                               
        


                                                 
                                                                         

                  
                                                                       
                      

                                                            

        

                                  
                                                                                 
                                                   

             


                                            
                                    

                                            
                                                    
 
           
                       
 
                   

                
                          
                                                  
     
                                                           

                                                                                      


                                                        
                                     
                                                                            
                                                         

                                                                          
                          


                                                                
                                                                                   
                      

         

                        
 
             


                                            
                              

                                            
                                                                
 
                  
 
                   
 
                
                          
                                        


                                                                            
                  

                                                        
                                                                                     
                                                   
 
             


                                            


                                            
                                               
 
                          
 
                   
 

                           
                                                                        
 
             


                                            
                        

                                            
                                                                            
                               
 
           
 
                   
 
                
 



                                                                   
 
                          
                                       



                          
                                                   
 
             


                                            
                                                

                                            
                                                                     

                                                                      
 
                          
                                                     
 

                    
 
                                      
 
                          
                                       

                            


                                                                            



                                                                 
                                                                         
 
             


                                            
                                                 

                                            
                                                                          
 
                          
 
                   
 



                                   
                                                                        
             


                                            
                                   

                                            
                                                  
 


                                                                                                        
                             



                                                                    
     
 
 
                                            
                           

                                            
                                                                      
 
                                       
                                   
 
                         
                                        
                               

                                                   
                 
                                     



                                                   


                                            
               

                                            
                                                      
 
                          
 
                   
 



                           
                                                                                                        
 
             


                                            
                                                     

                                            
                                                                                                                        
 






                                         
 







                                                                                                                                            
                                                  
             


                                            
                           







                                          

                                            
                                                             
 
           
 
                   
 
                

                         
                                                  
             
 
 
                                            
                           

                                            
                                            

                            
             

                                       
                  
 

                                       






                                               




                                                               


                
                                
                
                                                                               

                                                  


                   
                                                               
             
 
 
                                            
                     

                            
                                          

                                            
                                                  
                                                    
 
           
                    
 

                    
 
                 
 
                                                 
                 
 


                                          
                                                  
             


                                            
                           









                                            

                                            
                                                                                 
 
           
 
                   
 
                


                                    
                                                  
             


                                            



                                     

                                            
                                                                             
 
                          
 
                  
 
                             
                                                                    

                                
              
                                       
                                                                  



                      


                                                  
                  
                                                                                  

        

                                                                         

             
 
 
                                            
                                                   

                                            
                                                                   
                                                                  
 
                          
          
 
                  
 



                                    







                                                   
                                                                                      


                        

                                                                         

             
 
 
                                            
                                    

                                            
                                                                                 
 

                                                
          
 
                  
 







                                           



                                        
                                                         

             
 
 
                                            
                           

                                            
                                                              
 
                          
 
                   
 



                                          
                                                                                          
                             
                                                           
             
 
 
                                            
                       

                                            
                                                              
 
                          
 
                   
 



                                                                      
                                                                  
                                                                                       
                             
                                                           
             
 
 
                                            
                                       

                                            
                                                                         
 
           
 

                   
 
                






                                     
                                                   
             
 
 
                                            
                     

                                            
                                                
 
                          
 
                   
 

                              
                                                                             
             
 
 
                                            
                     

                                            
                                                  
 
                         
 
                    
 


                           
                                                                       
 
 

                                                
                                                                      
 
                         
                                              
                                                                     
 

                        
 
                               
               
 


                           
 

                                        
 
 
                                            
         

                                            
                                                   
 
                          
 
                    
 


                              
                                                                            


                                            
  

                                            
      
                                                        
 
           
 
                   
 
                

                         
                                                  
             
 
 
      
                                                              
 
                                                                           
                           
 
                    
 
             
                                                    

                           
                                      
 
             
 
 
                                                            
                                                                 

                          
 
                   
 
                                                     
 


                           
 


                                           
              

                                    
                                                                                                
                                                       
                                                     

         
 
                       
                                                                            
                   
                                                                            

             

 
 


               
                                          



                                            
      
                                                                     

                                    
                                                          



                                    
                                                                       


               
                              
     
                                   



                                                      

                               

                                                                      
                                                 
     

                                                     
                                                                                                                      



                                         
                                               
                                       
                    
 
                                                                  

                                                                
 
                             
 
                          
     
 
           


                                            

                                                            

                                            
      
                                                            

                           

                    



                            
                  

                    


                              

                   
                    
               

                                           
                  
                                          
           

                       
                
                           
            
                           




                                             
                                                                                             

     

                                                    

                       

                                         

          


                               


                                   

                                                     
                                                                             

                                                                    



                                  


        
                                   
     
 
                              

                          
                                                                                  
                                                                           
                                                     

                                                   
             
                               

                                       

                                                                 
                                                   
                                                                                                    

                                                                
                                                   
                                                                                                   
     
 
                                                
 
                                                                                              
                                                                  
                                                      





                                            
      
                                                             
 
                    
 
                                                                     

                                





                                            
      
                                                             
 
             
 
                    
 
                      
     
                                                      

               
 
                                                  
               
 

                   
 
                                     
               
 
                                                                                                
                                                      
               
 
                             
                                  
 
                      
 


                                                             






                                            
                                                             
 
                            
 
                    
 
                          

                                                                              
     
                          
                                                       

               
 
                                                          

                                                              
     

                              


        
                          
     
                                                   






                                            
      
                                                                       

                          
                   
 

                               


                   

                               


                     
                    

                                                                          
 
                             

                                         
                                             
                
                                                            
                                                          
 

                                   
                                        


                         
                                                                                             






                                     





                                                                                                         
                                                               


             
                                                                
             
                                            
                                      


                                                             
                                                            
 

                                           
                                                               
              
 

                  
                     
                                                                      
             

                                                                                                           







                                                                                            
                                                          
                  
                     


                                                         
                            
 
                                                
                                                          



                                        

                                                                            

                  


                                            

                                         
  
                                

                                            
      
                                                                  
 
                                                                 
                           
                        
                     
                                                              
 
                    
 
                                                                   
     
                                                                   
               
     
 
                                                              
     
                  

               
 
                                         
     
                                                               
                                           
         

                                                                       


                   
                                                                            


                                                                                                        
 
                                
                                                             
                                                                            
     
 
                                               


                                                        
 
              
           

 
                                                        
 
                                             
                           
 

                           
 
                   
 



                                        
 
                                                     
 
             





                                            
      
                                                              

                          
 
                    
 



                                              
 


                       
                       
 


                              
                                              
 
                                                                                






                                            
      
                                                            

                          
 
                    
 
                                            
                                                     
     


                                      
                                                                                

        
                                                





                                            
      
                                                                     
 

                                   
                                                  





                                            
      
                                                                  
 
                          
                               
 
                    
 
                      
     
                                                      

               

                         
                                  

               
                            
 

                           
 

                                




                                                   
                                                       
                       
                                                    
             
                                           
                 
                                                            


                           
                                     
                                          

                                                    
                                                       

                                         



                                                                                        

                                         




                                                                                        
                                                                                    

                  





                                            
      
                                                            
 
                    
 
                          

                  
                              
             


                                                        
                                                                            
                                                 


                  
                                                                      

                                                                           
             
                                        


                

                                      
 
                                                                


                  


                                            






                                           

                                            
      
                                                        


                           
                                                              
                                          
 
                    
 
                                                                   
     
                                                                   


               
                                         
     
                  
               
     
 
                                                           
                                       
     

                                                                   


               





                                                                             


                                                                                         

        


                                                
                                                          
                                                                         
         

            
                                                      
                                      
                                        
                                    

                
                      
                                                                              


                                                                
                                                                            
                     
                                                
                                            

                              


                                                      
                 

                                                                         
                                                            
                                        



                 
 
              





                                            
      
                                                             

                                 
                      
 
                    
 

                                                               
 
                      
     
                                                      

               
 
                       
                                                   
               
 

                                                 
 

                                            
                                                          
 
                                                                         
                           
 
                           





                                            
      
                                                             
 
                                
 
                    
 
                      
     
                                                      

               




                                                              
                       
                                  

                                                                   
               
     
 

                                   
 
                                             





                                            
      
                                                            
 
                    
 
                      
     
                                                      

               
                       
                                                   
               
 
                             
                                  
 
                                      





                                            
      
                                                              
 
              
 
                    
 
                      
     
                                                      

               
                              

                        

                                                  
                                            





                                                                  
                                             

                                  
                                        

                                                                     
                               

                                                                      
                                      
     





                                            
      
                                                                
 
              
 
                    
 
                      
     
                                                      

               
                              



                                                                                                   
 

                                  
               
                                               





                                            
      
                                                               
 
                    
 
                      
     
                                                      



                        
                                 





                                            
      
                                                                       
 
                                                     





                                            
      
                                                                   
 


                                                                             
 
                                             
 

                         
                                                  





                                            
      
                                                                    
 


                                                                             
 
                                              
 

                         
                                                  


                                            
                                 

                                            
      
                                                              
 
                    
 
                                            
                                                     
     
                                                  

        
                                                


                                            
               

                                            
      
                                                          
 
                    
 
                                          


                                            
                     

                                            
      
                                                              
 
                    
 
                                                                 


                                            
                                     

                                            
      
                                                         
 
                      


                                            
                        

                                            
      
                                                             
 
                          


                                            
                            

                                            
      
                                                             
 
                          





                                            
      
                                                            
 
                      


                                            
                           

                                            
      
                                                             
 
                                       


                                            
                              

                                            
      
                                                            
 
                                           


                                            


                                            
      
                                                                  
 
                    
 

                                      





                                            
      
                                                                   
 
                                      





                                            
      
                                                                   
 
                    
 
                                   
                                      


                                            
                                         
  
                                           

                                            
      
                                                                   
 

                    
 
                            
 






                                                                          
                                       
     
                                                                        
                                      
     

                
                                                               

                            
                                      





                                            
      
                                                                    
 
                                      


                                            
                              

                                            
      
                                                                
 
                                
 
                    
 

                                   
 
                                                                             
                                   
               
 
                               
                                                        


                                            
                              

                                            
      
                                                                  
 
                                
 
                    
 

                                   
 
                                                                             
                                   
               
 
                               
                                                        


                                            
                              

                                            
      
                                                            
 
                    
 
                               
                                 


                                            
                        


                                     

                                            
      
                                                                

                                            
                                                     
     
                                                      

        
                                                


                                            
                        


                                      

                                            
      
                                                                
 
                                    


                                            
                           


                                     

                                            
      
                                                                     

                                            
                                                     
     
                                                             


        
                                                 
                                                
     


                                            
                           

                                            
      
                                                            
 
                    


                                            
                           

                                            
      
                                                                      
 
                                                                       


                                            
                                 

                                            
      
                                                                      
 
                                                         


                                            
                                          



                                         

                                            
      
                                                                 
 

                           
                                                              
 
                    
 
                                                                   
     
                                                                   
               
     
 
                                                              
     
                  
               
     
 
                                                           
                                       
     

                                                                   


               

                                                       

 
                                           
      
                                                                
                                                     
                                                      
                           
                                                                                                                

                                                                                                              


                               
                                         
                                                           


            
                                      
                                                           
                                                  
                                                            
                                                                         



         

                                                                                                              


                               
                                         
                                                           


            
                                      
                                                           
                                                  
                                                            
                                                                         

         
 
           

 

































































































































































































































































































































































































































































































































































                                                                                                                                        
  

                             
      
                                            
 
                                                                                       
                            




                                                               
                                                                                             
                 








                                    


                                                      



                                                                       
                                        
                                                       
                                                 
            
                                           

     

                                             








                                                                        
      
 


                                           
                                 



                                                         
                                                                                                        






                                                                   
                                                                                   













                                               
 





                                                                              




                                                                      
                                                             
                                                           
                                                                              



                                                                               

                                                               
                                                  






                                                                  



                     
                          







                                                                         

                                       
      













                                                                               
                                                  





                                                                    
                                                






                                                                       

                                                      


                    
                                                                                            

                                                       
      
                                                                 
      





                                                                               
                                                                  





                                                                               

                                          



                                                         







                                   
                               
                                     
                                                        

                                       
                      
                                                      

                                                                  










                                                                               
                                            

                                                    

                                            

                       
 
                                
                                                                                       
 

                                       
                              


                                                                
                                  




                                                                    
                                           
                                               
                                                                                                      

                                 

                                  
                                        
                                                                                                                         
                
                                                                                                                             


                                                                                                                     
                                                                                                                                             
                                                                                               

               
                               
               

     
                          
                                                             
 
                        
 
                                  



                     
                                                    









                                                     
                      
                                                 


                                     
               

                          
               
 
                               

                                                
     
                              
         
                                                                                    
         
                                   


                                                 
                                                                     


         
                                   
     
                                                                       


                                                                      
                                                                                      

     
                                             
     



                                             
                   

         
                                                


        
                                


                                    
                                                                             
                                             
                          
             
                      

                                                         
                                                                               


                                                

                                                   



                                                
                                                                                     


                                                                       
                                                                

                                                                                                                     
                                                            
 
                                                           
                 
                                                                            
                                        
                           


                    

                                                 


                                                    
                                       



                                                                                                                           
                            
                                       

                                                                                         

                                                                                                                         
                                   

                                                                                     
 
                               



                                                                                       

                                                            
                     
                                        
                                

                 
      

         
                              





                                            

                       
                                 
                               
 
             
 
#include "clif.hpp"

#include <arpa/inet.h>

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

#include "../common/cxxstdio.hpp"
#include "../common/md5calc.hpp"
#include "../common/random.hpp"
#include "../common/nullpo.hpp"
#include "../common/socket.hpp"
#include "../common/timer.hpp"
#include "../common/version.hpp"

#include "atcommand.hpp"
#include "battle.hpp"
#include "chrif.hpp"
#include "intif.hpp"
#include "itemdb.hpp"
#include "magic.hpp"
#include "map.hpp"
#include "npc.hpp"
#include "party.hpp"
#include "pc.hpp"
#include "skill.hpp"
#include "storage.hpp"
#include "tmw.hpp"
#include "trade.hpp"

#include "../poison.hpp"

#define DUMP_UNKNOWN_PACKET     1

constexpr int EMOTE_IGNORED = 0x0e;

// functions list. Rate is how many milliseconds are required between
// calls. Packets exceeding this rate will be dropped. flood_rates in
// map.h must be the same length as this table. rate 0 is default
// rate -1 is unlimited

typedef void (*clif_func)(int fd, struct map_session_data *sd);
struct func_table
{
    interval_t rate;
    int len;
    clif_func func;

    // ctor exists because interval_t must be explicit
    func_table(int r, int l, clif_func f)
    : rate(r), len(l), func(f)
    {}
};

constexpr int VAR = -1;

extern // not really - defined below
func_table clif_parse_func_table[0x0220];


// local define
enum class SendWho
{
    ALL_CLIENT,
    ALL_SAMEMAP,
    AREA,
    AREA_WOS,
    AREA_WOC,
    AREA_WOSC,
    AREA_CHAT_WOC,
    CHAT,
    CHAT_WOS,
    PARTY,
    PARTY_WOS,
    PARTY_SAMEMAP,
    PARTY_SAMEMAP_WOS,
    PARTY_AREA,
    PARTY_AREA_WOS,
    SELF,
};

inline
void WBUFPOS(uint8_t *p, size_t pos, uint16_t x, uint16_t y)
{
    p += pos;
    p[0] = x >> 2;
    p[1] = (x << 6) | ((y >> 4) & 0x3f);
    p[2] = y << 4;
}
inline
void WBUFPOS2(uint8_t *p, size_t pos, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
{
    p += pos;
    p[0] = x0 >> 2;
    p[1] = (x0 << 6) | ((y0 >> 4) & 0x3f);
    p[2] = (y0 << 4) | ((x1 >> 6) & 0x0f);
    p[3] = (x1 << 2) | ((y1 >> 8) & 0x03);
    p[4] = y1;
}

inline
void WFIFOPOS(int fd, size_t pos, uint16_t x, uint16_t y)
{
    WBUFPOS(static_cast<uint8_t *>(WFIFOP(fd, pos)), 0, x, y);
}
inline
void WFIFOPOS2(int fd, size_t pos, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
{
    WBUFPOS2(static_cast<uint8_t *>(WFIFOP(fd, pos)), 0, x0, y0, x1, y1);
}

static
char map_ip_str[16];
static
struct in_addr map_ip;
static
int map_port = 5121;

static
int clif_changelook_towards(struct block_list *bl, LOOK type, int val,
                             struct map_session_data *dstsd);

/*==========================================
 * map鯖のip設定
 *------------------------------------------
 */
void clif_setip(const char *ip)
{
    memcpy(map_ip_str, ip, 16);
    map_ip.s_addr = inet_addr(map_ip_str);
}

/*==========================================
 * map鯖のport設定
 *------------------------------------------
 */
void clif_setport(int port)
{
    map_port = port;
}

/*==========================================
 * map鯖のip読み出し
 *------------------------------------------
 */
struct in_addr clif_getip(void)
{
    return map_ip;
}

/*==========================================
 * map鯖のport読み出し
 *------------------------------------------
 */
int clif_getport(void)
{
    return map_port;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_countusers(void)
{
    int users = 0, i;
    struct map_session_data *sd;

    for (i = 0; i < fd_max; i++)
    {
        if (session[i] && (sd = (struct map_session_data *)session[i]->session_data) && sd
            && sd->state.auth && !(battle_config.hide_GM_session
                                   && pc_isGM(sd)))
            users++;
    }
    return users;
}

/*==========================================
 * 全てのclientに対してfunc()実行
 *------------------------------------------
 */
int clif_foreachclient(std::function<void(struct map_session_data *)> func)
{
    int i;
    struct map_session_data *sd;

    for (i = 0; i < fd_max; i++)
    {
        if (session[i] && (sd = (struct map_session_data *)session[i]->session_data) && sd
            && sd->state.auth)
            func(sd);
    }
    return 0;
}

static
int is_deaf(struct block_list *bl)
{
    struct map_session_data *sd = (struct map_session_data *) bl;
    if (!bl || bl->type != BL::PC)
        return 0;
    return sd->special_state.deaf;
}

static
void clif_emotion_towards(struct block_list *bl,
                                  struct block_list *target, int type);

static
char *clif_validate_chat(struct map_session_data *sd, int type,
        const char **message, size_t *message_len);

/*==========================================
 * clif_sendでSendWho::AREA*指定時用
 *------------------------------------------
 */
static
void clif_send_sub(struct block_list *bl, const unsigned char *buf, int len,
        struct block_list *src_bl, SendWho type)
{
    nullpo_retv(bl);
    struct map_session_data *sd = (struct map_session_data *) bl;

    switch (type)
    {
        case SendWho::AREA_WOS:
            if (bl && bl == src_bl)
                return;
            break;

        case SendWho::AREA_CHAT_WOC:
            if (is_deaf(bl)
                && !(bl->type == BL::PC
                     && pc_isGM((struct map_session_data *) src_bl)))
            {
                clif_emotion_towards(src_bl, bl, EMOTE_IGNORED);
                return;
            }
            FALLTHROUGH;
        case SendWho::AREA_WOC:
            if ((sd && sd->chatID) || (bl && bl == src_bl))
                return;

            break;
        case SendWho::AREA_WOSC:
            if ((sd) && sd->chatID
                && sd->chatID == ((struct map_session_data *) src_bl)->chatID)
                return;
            break;
    }

    if (session[sd->fd] != NULL)
    {
        if (WFIFOP(sd->fd, 0) == buf)
        {
            PRINTF("WARNING: Invalid use of clif_send function\n");
            PRINTF("         Packet x%4x use a WFIFO of a player instead of to use a buffer.\n",
                 RBUFW(buf, 0));
            PRINTF("         Please correct your code.\n");
            // don't send to not move the pointer of the packet for next sessions in the loop
        }
        else
        {
            if (clif_parse_func_table[RBUFW(buf, 0)].len)
            {
                // packet must exist
                memcpy(WFIFOP(sd->fd, 0), buf, len);
                WFIFOSET(sd->fd, len);
            }
        }
    }
}

/*==========================================
 *
 *------------------------------------------
 */
static
int clif_send(const uint8_t *buf, int len, struct block_list *bl, SendWho type)
{
    int i;
    struct map_session_data *sd;
    struct chat_data *cd;
    struct party *p = NULL;
    int x0 = 0, x1 = 0, y0 = 0, y1 = 0;

    if (type != SendWho::ALL_CLIENT)
    {
        nullpo_ret(bl);

        if (bl->type == BL::PC)
        {
            struct map_session_data *sd2 = (struct map_session_data *) bl;
            if (bool(sd2->status.option & Option::INVISIBILITY))
            {
                // Obscure hidden GMs

                switch (type)
                {
                    case SendWho::AREA:
                    case SendWho::AREA_WOC:
                        type = SendWho::SELF;
                        break;

                    case SendWho::AREA_WOS:
                    case SendWho::AREA_WOSC:
                        return 1;

                    default:
                        break;
                }
            }
        }
    }

    switch (type)
    {
        case SendWho::ALL_CLIENT:       // 全クライアントに送信
            for (i = 0; i < fd_max; i++)
            {
                if (session[i] && (sd = (struct map_session_data *)session[i]->session_data) != NULL
                    && sd->state.auth)
                {
                    if (clif_parse_func_table[RBUFW(buf, 0)].len)
                    {           // packet must exist
                        memcpy(WFIFOP(i, 0), buf, len);
                        WFIFOSET(i, len);
                    }
                }
            }
            break;
        case SendWho::ALL_SAMEMAP:      // 同じマップの全クライアントに送信
            for (i = 0; i < fd_max; i++)
            {
                if (session[i] && (sd = (struct map_session_data *)session[i]->session_data) != NULL
                    && sd->state.auth && sd->bl.m == bl->m)
                {
                    if (clif_parse_func_table[RBUFW(buf, 0)].len)
                    {           // packet must exist
                        memcpy(WFIFOP(i, 0), buf, len);
                        WFIFOSET(i, len);
                    }
                }
            }
            break;
        case SendWho::AREA:
        case SendWho::AREA_WOS:
        case SendWho::AREA_WOC:
        case SendWho::AREA_WOSC:
            map_foreachinarea(std::bind(clif_send_sub, ph::_1, buf, len, bl, type),
                    bl->m, bl->x - AREA_SIZE, bl->y - AREA_SIZE,
                    bl->x + AREA_SIZE, bl->y + AREA_SIZE, BL::PC);
            break;
        case SendWho::AREA_CHAT_WOC:
            map_foreachinarea(std::bind(clif_send_sub, ph::_1, buf, len, bl, SendWho::AREA_CHAT_WOC),
                    bl->m, bl->x - (AREA_SIZE), bl->y - (AREA_SIZE),
                    bl->x + (AREA_SIZE), bl->y + (AREA_SIZE), BL::PC);
            break;
        case SendWho::CHAT:
        case SendWho::CHAT_WOS:
            cd = (struct chat_data *) bl;
            if (bl->type == BL::PC)
            {
                sd = (struct map_session_data *) bl;
                cd = (struct chat_data *) map_id2bl(sd->chatID);
            }
            else if (bl->type != BL::CHAT)
                break;
            if (cd == NULL)
                break;
            for (i = 0; i < cd->users; i++)
            {
                if (type == SendWho::CHAT_WOS
                    && cd->usersd[i] == (struct map_session_data *) bl)
                    continue;
                if (clif_parse_func_table[RBUFW(buf, 0)].len)
                {               // packet must exist
                    memcpy(WFIFOP(cd->usersd[i]->fd, 0), buf, len);
                    WFIFOSET(cd->usersd[i]->fd, len);
                }
            }
            break;

        case SendWho::PARTY_AREA:       // 同じ画面内の全パーティーメンバに送信
        case SendWho::PARTY_AREA_WOS:   // 自分以外の同じ画面内の全パーティーメンバに送信
            x0 = bl->x - AREA_SIZE;
            y0 = bl->y - AREA_SIZE;
            x1 = bl->x + AREA_SIZE;
            y1 = bl->y + AREA_SIZE;
            FALLTHROUGH;
        case SendWho::PARTY:            // 全パーティーメンバに送信
        case SendWho::PARTY_WOS:        // 自分以外の全パーティーメンバに送信
        case SendWho::PARTY_SAMEMAP:    // 同じマップの全パーティーメンバに送信
        case SendWho::PARTY_SAMEMAP_WOS:    // 自分以外の同じマップの全パーティーメンバに送信
            if (bl->type == BL::PC)
            {
                sd = (struct map_session_data *) bl;
                if (sd->partyspy > 0)
                {
                    p = party_search(sd->partyspy);
                }
                else
                {
                    if (sd->status.party_id > 0)
                        p = party_search(sd->status.party_id);
                }
            }
            if (p)
            {
                for (i = 0; i < MAX_PARTY; i++)
                {
                    if ((sd = p->member[i].sd) != NULL)
                    {
                        if (sd->bl.id == bl->id && (type == SendWho::PARTY_WOS ||
                                                    type == SendWho::PARTY_SAMEMAP_WOS
                                                    || type ==
                                                    SendWho::PARTY_AREA_WOS))
                            continue;
                        if (type != SendWho::PARTY && type != SendWho::PARTY_WOS && bl->m != sd->bl.m)    // マップチェック
                            continue;
                        if ((type == SendWho::PARTY_AREA || type == SendWho::PARTY_AREA_WOS) &&
                            (sd->bl.x < x0 || sd->bl.y < y0 ||
                             sd->bl.x > x1 || sd->bl.y > y1))
                            continue;
                        if (clif_parse_func_table[RBUFW(buf, 0)].len)
                        {       // packet must exist
                            memcpy(WFIFOP(sd->fd, 0), buf, len);
                            WFIFOSET(sd->fd, len);
                        }
                    }
                }
                for (i = 0; i < fd_max; i++)
                {
                    if (session[i] && (sd = (struct map_session_data *)session[i]->session_data) != NULL
                        && sd->state.auth)
                    {
                        if (sd->partyspy == p->party_id)
                        {
                            if (clif_parse_func_table[RBUFW(buf, 0)].len)
                            {   // packet must exist
                                memcpy(WFIFOP(sd->fd, 0), buf, len);
                                WFIFOSET(sd->fd, len);
                            }
                        }
                    }
                }
            }
            break;
        case SendWho::SELF:
            sd = (struct map_session_data *) bl;
            if (clif_parse_func_table[RBUFW(buf, 0)].len)
            {                   // packet must exist
                memcpy(WFIFOP(sd->fd, 0), buf, len);
                WFIFOSET(sd->fd, len);
            }
            break;

        default:
            if (battle_config.error_log)
                PRINTF("clif_send まだ作ってないよー\n");
            return -1;
    }

    return 0;
}

//
// パケット作って送信
//
/*==========================================
 *
 *------------------------------------------
 */
int clif_authok(struct map_session_data *sd)
{
    int fd;

    nullpo_ret(sd);

    if (!sd)
        return 0;

    if (!sd->fd)
        return 0;

    fd = sd->fd;

    WFIFOW(fd, 0) = 0x73;
    WFIFOL(fd, 2) = gettick().time_since_epoch().count();
    WFIFOPOS(fd, 6, sd->bl.x, sd->bl.y);
    WFIFOB(fd, 9) = 5;
    WFIFOB(fd, 10) = 5;
    WFIFOSET(fd, clif_parse_func_table[0x73].len);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_authfail_fd(int fd, int type)
{
    if (!fd || !session[fd])
        return 0;

    WFIFOW(fd, 0) = 0x81;
    WFIFOL(fd, 2) = type;
    WFIFOSET(fd, clif_parse_func_table[0x81].len);

    clif_setwaitclose(fd);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_charselectok(int id)
{
    struct map_session_data *sd;
    int fd;

    if ((sd = map_id2sd(id)) == NULL)
        return 1;

    if (!sd->fd)
        return 1;

    fd = sd->fd;
    WFIFOW(fd, 0) = 0xb3;
    WFIFOB(fd, 2) = 1;
    WFIFOSET(fd, clif_parse_func_table[0xb3].len);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
static
int clif_set009e(struct flooritem_data *fitem, uint8_t *buf)
{
    int view;

    nullpo_ret(fitem);

    //009e <ID>.l <name ID>.w <identify flag>.B <X>.w <Y>.w <subX>.B <subY>.B <amount>.w
    WBUFW(buf, 0) = 0x9e;
    WBUFL(buf, 2) = fitem->bl.id;
    if ((view = itemdb_viewid(fitem->item_data.nameid)) > 0)
        WBUFW(buf, 6) = view;
    else
        WBUFW(buf, 6) = fitem->item_data.nameid;
    WBUFB(buf, 8) = fitem->item_data.identify;
    WBUFW(buf, 9) = fitem->bl.x;
    WBUFW(buf, 11) = fitem->bl.y;
    WBUFB(buf, 13) = fitem->subx;
    WBUFB(buf, 14) = fitem->suby;
    WBUFW(buf, 15) = fitem->item_data.amount;

    return clif_parse_func_table[0x9e].len;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_dropflooritem(struct flooritem_data *fitem)
{
    uint8_t buf[64];

    nullpo_ret(fitem);

    if (fitem->item_data.nameid <= 0)
        return 0;
    clif_set009e(fitem, buf);
    clif_send(buf, clif_parse_func_table[0x9e].len, &fitem->bl, SendWho::AREA);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_clearflooritem(struct flooritem_data *fitem, int fd)
{
    unsigned char buf[16];

    nullpo_ret(fitem);

    WBUFW(buf, 0) = 0xa1;
    WBUFL(buf, 2) = fitem->bl.id;

    if (fd == 0)
    {
        clif_send(buf, clif_parse_func_table[0xa1].len, &fitem->bl, SendWho::AREA);
    }
    else
    {
        memcpy(WFIFOP(fd, 0), buf, 6);
        WFIFOSET(fd, clif_parse_func_table[0xa1].len);
    }

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_clearchar(struct block_list *bl, BeingRemoveWhy type)
{
    unsigned char buf[16];

    nullpo_ret(bl);

    WBUFW(buf, 0) = 0x80;
    WBUFL(buf, 2) = bl->id;
    if (type == BeingRemoveWhy::DISGUISE)
    {
        WBUFB(buf, 6) = static_cast<uint8_t>(BeingRemoveWhy::GONE);
        clif_send(buf, clif_parse_func_table[0x80].len, bl, SendWho::AREA);
    }
    else
    {
        WBUFB(buf, 6) = static_cast<uint8_t>(type);
        clif_send(buf, clif_parse_func_table[0x80].len, bl,
                   type == BeingRemoveWhy::DEAD ? SendWho::AREA : SendWho::AREA_WOS);
    }

    return 0;
}

static
void clif_clearchar_delay_sub(TimerData *, tick_t,
        struct block_list *bl, BeingRemoveWhy type)
{
    clif_clearchar(bl, type);
    map_freeblock(bl);
}

int clif_clearchar_delay(tick_t tick,
        struct block_list *bl, BeingRemoveWhy type)
{
    struct block_list *tmpbl;
    CREATE(tmpbl, struct block_list, 1);

    memcpy(tmpbl, bl, sizeof(struct block_list));
    Timer(tick,
            std::bind(clif_clearchar_delay_sub, ph::_1, ph::_2,
                tmpbl, type)
    ).detach();

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_clearchar_id(int id, BeingRemoveWhy type, int fd)
{
    unsigned char buf[16];

    WBUFW(buf, 0) = 0x80;
    WBUFL(buf, 2) = id;
    WBUFB(buf, 6) = static_cast<uint8_t>(type);
    memcpy(WFIFOP(fd, 0), buf, 7);
    WFIFOSET(fd, clif_parse_func_table[0x80].len);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
static
int clif_set0078(struct map_session_data *sd, unsigned char *buf)
{
    nullpo_ret(sd);

    WBUFW(buf, 0) = 0x1d8;
    WBUFL(buf, 2) = sd->bl.id;
    WBUFW(buf, 6) = static_cast<uint16_t>(sd->speed.count());
    WBUFW(buf, 8) = static_cast<uint16_t>(sd->opt1);
    WBUFW(buf, 10) = static_cast<uint16_t>(sd->opt2);
    WBUFW(buf, 12) = static_cast<uint16_t>(sd->status.option);
    WBUFW(buf, 14) = sd->status.species;
    WBUFW(buf, 16) = sd->status.hair;
    if (sd->attack_spell_override)
        WBUFW(buf, 18) = sd->attack_spell_look_override;
    else
    {
        if (sd->equip_index[EQUIP::WEAPON] >= 0
            && sd->inventory_data[sd->equip_index[EQUIP::WEAPON]])
        {
            if (sd->inventory_data[sd->equip_index[EQUIP::WEAPON]]->view_id > 0)
                WBUFW(buf, 18) =
                    sd->inventory_data[sd->equip_index[EQUIP::WEAPON]]->view_id;
            else
                WBUFW(buf, 18) =
                    sd->status.inventory[sd->equip_index[EQUIP::WEAPON]].nameid;
        }
        else
            WBUFW(buf, 18) = 0;
    }
    if (sd->equip_index[EQUIP::SHIELD] >= 0
        && sd->equip_index[EQUIP::SHIELD] != sd->equip_index[EQUIP::WEAPON]
        && sd->inventory_data[sd->equip_index[EQUIP::SHIELD]])
    {
        if (sd->inventory_data[sd->equip_index[EQUIP::SHIELD]]->view_id > 0)
            WBUFW(buf, 20) = sd->inventory_data[sd->equip_index[EQUIP::SHIELD]]->view_id;
        else
            WBUFW(buf, 20) = sd->status.inventory[sd->equip_index[EQUIP::SHIELD]].nameid;
    }
    else
        WBUFW(buf, 20) = 0;
    WBUFW(buf, 22) = sd->status.head_bottom;
    WBUFW(buf, 24) = sd->status.head_top;
    WBUFW(buf, 26) = sd->status.head_mid;
    WBUFW(buf, 28) = sd->status.hair_color;
    WBUFW(buf, 30) = sd->status.clothes_color;
    WBUFW(buf, 32) = static_cast<uint8_t>(sd->head_dir);
    WBUFL(buf, 34) = 0 /*guild_id*/;
    WBUFW(buf, 38) = 0 /*guild_emblem_id*/;
    WBUFW(buf, 40) = sd->status.manner;
    WBUFW(buf, 42) = uint16_t(sd->opt3);
    WBUFB(buf, 44) = sd->status.karma;
    WBUFB(buf, 45) = sd->sex;
    WBUFPOS(buf, 46, sd->bl.x, sd->bl.y);
    // work around ICE in gcc 4.6
    uint8_t dir = static_cast<uint8_t>(sd->dir);
    WBUFB(buf, 48) |= dir;
    WBUFW(buf, 49) = (pc_isGM(sd) == 60 || pc_isGM(sd) == 99) ? 0x80 : 0;
    WBUFB(buf, 51) = sd->state.dead_sit;
    WBUFW(buf, 52) = 0;

    return clif_parse_func_table[0x1d8].len;
}

/*==========================================
 *
 *------------------------------------------
 */
static
int clif_set007b(struct map_session_data *sd, unsigned char *buf)
{
    nullpo_ret(sd);

    WBUFW(buf, 0) = 0x1da;
    WBUFL(buf, 2) = sd->bl.id;
    WBUFW(buf, 6) = static_cast<uint16_t>(sd->speed.count());
    WBUFW(buf, 8) = static_cast<uint16_t>(sd->opt1);
    WBUFW(buf, 10) = static_cast<uint16_t>(sd->opt2);
    WBUFW(buf, 12) = static_cast<uint16_t>(sd->status.option);
    WBUFW(buf, 14) = sd->status.species;
    WBUFW(buf, 16) = sd->status.hair;
    if (sd->equip_index[EQUIP::WEAPON] >= 0
        && sd->inventory_data[sd->equip_index[EQUIP::WEAPON]])
    {
        if (sd->inventory_data[sd->equip_index[EQUIP::WEAPON]]->view_id > 0)
            WBUFW(buf, 18) = sd->inventory_data[sd->equip_index[EQUIP::WEAPON]]->view_id;
        else
            WBUFW(buf, 18) = sd->status.inventory[sd->equip_index[EQUIP::WEAPON]].nameid;
    }
    else
        WBUFW(buf, 18) = 0;
    if (sd->equip_index[EQUIP::SHIELD] >= 0
        && sd->equip_index[EQUIP::SHIELD] != sd->equip_index[EQUIP::WEAPON]
        && sd->inventory_data[sd->equip_index[EQUIP::SHIELD]])
    {
        if (sd->inventory_data[sd->equip_index[EQUIP::SHIELD]]->view_id > 0)
            WBUFW(buf, 20) = sd->inventory_data[sd->equip_index[EQUIP::SHIELD]]->view_id;
        else
            WBUFW(buf, 20) = sd->status.inventory[sd->equip_index[EQUIP::SHIELD]].nameid;
    }
    else
        WBUFW(buf, 20) = 0;
    WBUFW(buf, 22) = sd->status.head_bottom;
    WBUFL(buf, 24) = gettick().time_since_epoch().count();
    WBUFW(buf, 28) = sd->status.head_top;
    WBUFW(buf, 30) = sd->status.head_mid;
    WBUFW(buf, 32) = sd->status.hair_color;
    WBUFW(buf, 34) = sd->status.clothes_color;
    WBUFW(buf, 36) = static_cast<uint8_t>(sd->head_dir);
    WBUFL(buf, 38) = 0/*guild_id*/;
    WBUFW(buf, 42) = 0/*guild_emblem_id*/;
    WBUFW(buf, 44) = sd->status.manner;
    WBUFW(buf, 46) = uint16_t(sd->opt3);
    WBUFB(buf, 48) = sd->status.karma;
    WBUFB(buf, 49) = sd->sex;
    WBUFPOS2(buf, 50, sd->bl.x, sd->bl.y, sd->to_x, sd->to_y);
    WBUFW(buf, 55) = pc_isGM(sd) == 60 ? 0x80 : 0;
    WBUFB(buf, 57) = 5;
    WBUFW(buf, 58) = 0;

    return clif_parse_func_table[0x1da].len;
}

/*==========================================
 * MOB表示1
 *------------------------------------------
 */
static
int clif_mob0078(struct mob_data *md, unsigned char *buf)
{
    int level;

    memset(buf, 0, clif_parse_func_table[0x78].len);

    nullpo_ret(md);

    WBUFW(buf, 0) = 0x78;
    WBUFL(buf, 2) = md->bl.id;
    WBUFW(buf, 6) = static_cast<uint16_t>(battle_get_speed(&md->bl).count());
    WBUFW(buf, 8) = static_cast<uint16_t>(md->opt1);
    WBUFW(buf, 10) = static_cast<uint16_t>(md->opt2);
    WBUFW(buf, 12) = static_cast<uint16_t>(md->option);
    WBUFW(buf, 14) = md->mob_class;
    // snip: stuff do do with disguise as a PC
    WBUFPOS(buf, 46, md->bl.x, md->bl.y);
    // work around ICE in gcc 4.6
    uint8_t dir = static_cast<uint8_t>(md->dir);
    WBUFB(buf, 48) |= dir;
    WBUFB(buf, 49) = 5;
    WBUFB(buf, 50) = 5;
    WBUFW(buf, 52) =
        ((level =
          battle_get_lv(&md->bl)) >
         battle_config.max_lv) ? battle_config.max_lv : level;

    return clif_parse_func_table[0x78].len;
}

/*==========================================
 * MOB表示2
 *------------------------------------------
 */
static
int clif_mob007b(struct mob_data *md, unsigned char *buf)
{
    int level;

    memset(buf, 0, clif_parse_func_table[0x7b].len);

    nullpo_ret(md);

    WBUFW(buf, 0) = 0x7b;
    WBUFL(buf, 2) = md->bl.id;
    WBUFW(buf, 6) = static_cast<uint16_t>(battle_get_speed(&md->bl).count());
    WBUFW(buf, 8) = static_cast<uint16_t>(md->opt1);
    WBUFW(buf, 10) = static_cast<uint16_t>(md->opt2);
    WBUFW(buf, 12) = static_cast<uint16_t>(md->option);
    WBUFW(buf, 14) = md->mob_class;
    // snip: stuff for monsters disguised as PCs
    WBUFL(buf, 22) = gettick().time_since_epoch().count();

    WBUFPOS2(buf, 50, md->bl.x, md->bl.y, md->to_x, md->to_y);
    WBUFB(buf, 56) = 5;
    WBUFB(buf, 57) = 5;
    WBUFW(buf, 58) =
        ((level =
          battle_get_lv(&md->bl)) >
         battle_config.max_lv) ? battle_config.max_lv : level;

    return clif_parse_func_table[0x7b].len;
}

/*==========================================
 *
 *------------------------------------------
 */
static
int clif_npc0078(struct npc_data *nd, unsigned char *buf)
{
    nullpo_ret(nd);

    memset(buf, 0, clif_parse_func_table[0x78].len);

    WBUFW(buf, 0) = 0x78;
    WBUFL(buf, 2) = nd->bl.id;
    WBUFW(buf, 6) = static_cast<uint16_t>(nd->speed.count());
    WBUFW(buf, 14) = nd->npc_class;
    WBUFPOS(buf, 46, nd->bl.x, nd->bl.y);
    // work around ICE in gcc 4.6
    uint8_t dir = static_cast<uint8_t>(nd->dir);
    WBUFB(buf, 48) |= dir;
    WBUFB(buf, 49) = 5;
    WBUFB(buf, 50) = 5;

    return clif_parse_func_table[0x78].len;
}

/* These indices are derived from equip_pos in pc.c and some guesswork */
static
earray<EQUIP, LOOK, LOOK::COUNT> equip_points //=
{{
    EQUIP::NONE,    // base
    EQUIP::NONE,    // hair
    EQUIP::WEAPON,  // weapon
    EQUIP::LEGS,    // head botom -- leg armour
    EQUIP::HAT,     // head top -- hat
    EQUIP::TORSO,   // head mid -- torso armour
    EQUIP::NONE,    // hair colour
    EQUIP::NONE,    // clothes colour
    EQUIP::SHIELD,  // shield
    EQUIP::SHOES,   // shoes
    EQUIP::GLOVES,  // gloves
    EQUIP::CAPE,    // cape
    EQUIP::MISC1,   // misc1
    EQUIP::MISC2,   // misc2
}};

/*==========================================
 *
 *------------------------------------------
 */
int clif_spawnpc(struct map_session_data *sd)
{
    unsigned char buf[128];

    nullpo_ret(sd);

    clif_set0078(sd, buf);

    WBUFW(buf, 0) = 0x1d9;
    WBUFW(buf, 51) = 0;
    clif_send(buf, clif_parse_func_table[0x1d9].len, &sd->bl, SendWho::AREA_WOS);

    if (map[sd->bl.m].flag.snow)
        clif_specialeffect(&sd->bl, 162, 1);
    if (map[sd->bl.m].flag.fog)
        clif_specialeffect(&sd->bl, 233, 1);
    if (map[sd->bl.m].flag.sakura)
        clif_specialeffect(&sd->bl, 163, 1);
    if (map[sd->bl.m].flag.leaves)
        clif_specialeffect(&sd->bl, 333, 1);
    if (map[sd->bl.m].flag.rain)
        clif_specialeffect(&sd->bl, 161, 1);

//        clif_changelook_accessories(&sd->bl, NULL);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_spawnnpc(struct npc_data *nd)
{
    unsigned char buf[64];
    int len;

    nullpo_ret(nd);

    if (nd->npc_class < 0 || nd->flag & 1 || nd->npc_class == INVISIBLE_CLASS)
        return 0;

    memset(buf, 0, clif_parse_func_table[0x7c].len);

    WBUFW(buf, 0) = 0x7c;
    WBUFL(buf, 2) = nd->bl.id;
    WBUFW(buf, 6) = static_cast<uint16_t>(nd->speed.count());
    WBUFW(buf, 20) = nd->npc_class;
    WBUFPOS(buf, 36, nd->bl.x, nd->bl.y);

    clif_send(buf, clif_parse_func_table[0x7c].len, &nd->bl, SendWho::AREA);

    len = clif_npc0078(nd, buf);
    clif_send(buf, len, &nd->bl, SendWho::AREA);

    return 0;
}

int clif_spawn_fake_npc_for_player(struct map_session_data *sd, int fake_npc_id)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    if (!fd)
        return 0;

    WFIFOW(fd, 0) = 0x7c;
    WFIFOL(fd, 2) = fake_npc_id;
    WFIFOW(fd, 6) = 0;
    WFIFOW(fd, 8) = 0;
    WFIFOW(fd, 10) = 0;
    WFIFOW(fd, 12) = 0;
    WFIFOW(fd, 20) = 127;
    WFIFOPOS(fd, 36, sd->bl.x, sd->bl.y);
    WFIFOSET(fd, clif_parse_func_table[0x7c].len);

    WFIFOW(fd, 0) = 0x78;
    WFIFOL(fd, 2) = fake_npc_id;
    WFIFOW(fd, 6) = 0;
    WFIFOW(fd, 8) = 0;
    WFIFOW(fd, 10) = 0;
    WFIFOW(fd, 12) = 0;
    WFIFOW(fd, 14) = 127;      // identifies as NPC
    WFIFOW(fd, 20) = 127;
    WFIFOPOS(fd, 46, sd->bl.x, sd->bl.y);
    WFIFOPOS(fd, 36, sd->bl.x, sd->bl.y);
    WFIFOB(fd, 49) = 5;
    WFIFOB(fd, 50) = 5;
    WFIFOSET(fd, clif_parse_func_table[0x78].len);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_spawnmob(struct mob_data *md)
{
    unsigned char buf[64];
    int len;

    nullpo_ret(md);

    {
        memset(buf, 0, clif_parse_func_table[0x7c].len);

        WBUFW(buf, 0) = 0x7c;
        WBUFL(buf, 2) = md->bl.id;
        WBUFW(buf, 6) = md->stats[mob_stat::SPEED];
        WBUFW(buf, 8) = uint16_t(md->opt1);
        WBUFW(buf, 10) = uint16_t(md->opt2);
        WBUFW(buf, 12) = uint16_t(md->option);
        WBUFW(buf, 20) = md->mob_class;
        WBUFPOS(buf, 36, md->bl.x, md->bl.y);
        clif_send(buf, clif_parse_func_table[0x7c].len, &md->bl, SendWho::AREA);
    }

    len = clif_mob0078(md, buf);
    clif_send(buf, len, &md->bl, SendWho::AREA);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
static
int clif_servertick(struct map_session_data *sd)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0x7f;
    WFIFOL(fd, 2) = sd->server_tick.time_since_epoch().count();
    WFIFOSET(fd, clif_parse_func_table[0x7f].len);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_walkok(struct map_session_data *sd)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0x87;
    WFIFOL(fd, 2) = gettick().time_since_epoch().count();
    WFIFOPOS2(fd, 6, sd->bl.x, sd->bl.y, sd->to_x, sd->to_y);
    WFIFOB(fd, 11) = 0;
    WFIFOSET(fd, clif_parse_func_table[0x87].len);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_movechar(struct map_session_data *sd)
{
    int len;
    unsigned char buf[256];

    nullpo_ret(sd);

    len = clif_set007b(sd, buf);

    clif_send(buf, len, &sd->bl, SendWho::AREA_WOS);

    if (battle_config.save_clothcolor == 1 && sd->status.clothes_color > 0)
        clif_changelook(&sd->bl, LOOK::CLOTHES_COLOR,
                         sd->status.clothes_color);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_quitsave(int, struct map_session_data *sd)
{
    map_quit(sd);
}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_waitclose(TimerData *, tick_t, int id)
{
    // TODO: what happens if the player disconnects
    // and someone else connects?
    if (session[id])
        session[id]->eof = 1;
}

/*==========================================
 *
 *------------------------------------------
 */
void clif_setwaitclose(int fd)
{
    Timer(gettick() + std::chrono::seconds(5),
            std::bind(clif_waitclose, ph::_1, ph::_2,
                fd)
    ).detach();
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_changemap(struct map_session_data *sd, const char *mapname, int x, int y)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;

    WFIFOW(fd, 0) = 0x91;
    memcpy(WFIFOP(fd, 2), mapname, 16);
    WFIFOW(fd, 18) = x;
    WFIFOW(fd, 20) = y;
    WFIFOSET(fd, clif_parse_func_table[0x91].len);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_changemapserver(struct map_session_data *sd, const char *mapname, int x,
                          int y, struct in_addr ip, int port)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0x92;
    memcpy(WFIFOP(fd, 2), mapname, 16);
    WFIFOW(fd, 18) = x;
    WFIFOW(fd, 20) = y;
    WFIFOL(fd, 22) = ip.s_addr;
    WFIFOW(fd, 26) = port;
    WFIFOSET(fd, clif_parse_func_table[0x92].len);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_fixpos(struct block_list *bl)
{
    uint8_t buf[16];

    nullpo_ret(bl);

    WBUFW(buf, 0) = 0x88;
    WBUFL(buf, 2) = bl->id;
    WBUFW(buf, 6) = bl->x;
    WBUFW(buf, 8) = bl->y;

    clif_send(buf, clif_parse_func_table[0x88].len, bl, SendWho::AREA);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_npcbuysell(struct map_session_data *sd, int id)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0xc4;
    WFIFOL(fd, 2) = id;
    WFIFOSET(fd, clif_parse_func_table[0xc4].len);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_buylist(struct map_session_data *sd, struct npc_data *nd)
{
    struct item_data *id;
    int fd, i, val;

    nullpo_ret(sd);
    nullpo_ret(nd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0xc6;
    for (i = 0; nd->u.shop_item[i].nameid > 0; i++)
    {
        id = itemdb_search(nd->u.shop_item[i].nameid);
        val = nd->u.shop_item[i].value;
        WFIFOL(fd, 4 + i * 11) = val; // base price
        WFIFOL(fd, 8 + i * 11) = val; // actual price
        WFIFOB(fd, 12 + i * 11) = uint8_t(id->type);
        if (id->view_id > 0)
            WFIFOW(fd, 13 + i * 11) = id->view_id;
        else
            WFIFOW(fd, 13 + i * 11) = nd->u.shop_item[i].nameid;
    }
    WFIFOW(fd, 2) = i * 11 + 4;
    WFIFOSET(fd, WFIFOW(fd, 2));

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_selllist(struct map_session_data *sd)
{
    int fd, i, c = 0, val;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0xc7;
    for (i = 0; i < MAX_INVENTORY; i++)
    {
        if (sd->status.inventory[i].nameid > 0 && sd->inventory_data[i])
        {
            val = sd->inventory_data[i]->value_sell;
            if (val < 0)
                continue;
            WFIFOW(fd, 4 + c * 10) = i + 2;
            WFIFOL(fd, 6 + c * 10) = val; // base price
            WFIFOL(fd, 10 + c * 10) = val; // actual price
            c++;
        }
    }
    WFIFOW(fd, 2) = c * 10 + 4;
    WFIFOSET(fd, WFIFOW(fd, 2));

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_scriptmes(struct map_session_data *sd, int npcid, const char *mes)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0xb4;
    WFIFOW(fd, 2) = strlen(mes) + 9;
    WFIFOL(fd, 4) = npcid;
    strcpy((char *)WFIFOP(fd, 8), mes);
    WFIFOSET(fd, WFIFOW(fd, 2));

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_scriptnext(struct map_session_data *sd, int npcid)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0xb5;
    WFIFOL(fd, 2) = npcid;
    WFIFOSET(fd, clif_parse_func_table[0xb5].len);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_scriptclose(struct map_session_data *sd, int npcid)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0xb6;
    WFIFOL(fd, 2) = npcid;
    WFIFOSET(fd, clif_parse_func_table[0xb6].len);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_scriptmenu(struct map_session_data *sd, int npcid, const char *mes)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0xb7;
    WFIFOW(fd, 2) = strlen(mes) + 8;
    WFIFOL(fd, 4) = npcid;
    strcpy((char *)WFIFOP(fd, 8), mes);
    WFIFOSET(fd, WFIFOW(fd, 2));

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_scriptinput(struct map_session_data *sd, int npcid)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0x142;
    WFIFOL(fd, 2) = npcid;
    WFIFOSET(fd, clif_parse_func_table[0x142].len);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_scriptinputstr(struct map_session_data *sd, int npcid)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0x1d4;
    WFIFOL(fd, 2) = npcid;
    WFIFOSET(fd, clif_parse_func_table[0x1d4].len);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_viewpoint(struct map_session_data *sd, int npc_id, int type, int x,
                    int y, int id, int color)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0x144;
    WFIFOL(fd, 2) = npc_id;
    WFIFOL(fd, 6) = type;
    WFIFOL(fd, 10) = x;
    WFIFOL(fd, 14) = y;
    WFIFOB(fd, 18) = id;
    WFIFOL(fd, 19) = color;
    WFIFOSET(fd, clif_parse_func_table[0x144].len);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_cutin(struct map_session_data *sd, const char *image, int type)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0x1b3;
    memcpy(WFIFOP(fd, 2), image, 64);
    WFIFOB(fd, 66) = type;
    WFIFOSET(fd, clif_parse_func_table[0x1b3].len);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_additem(struct map_session_data *sd, int n, int amount, PickupFail fail)
{
    nullpo_ret(sd);

    int fd = sd->fd;
    if (fail != PickupFail::OKAY)
    {
        WFIFOW(fd, 0) = 0xa0;
        WFIFOW(fd, 2) = n + 2;
        WFIFOW(fd, 4) = amount;
        WFIFOW(fd, 6) = 0;
        WFIFOB(fd, 8) = 0;
        WFIFOB(fd, 9) = 0;
        WFIFOB(fd, 10) = 0;
        WFIFOW(fd, 11) = 0;
        WFIFOW(fd, 13) = 0;
        WFIFOW(fd, 15) = 0;
        WFIFOW(fd, 17) = 0;
        WFIFOW(fd, 19) = 0;
        WFIFOB(fd, 21) = 0;
        WFIFOB(fd, 22) = uint8_t(fail);
    }
    else
    {
        if (n < 0 || n >= MAX_INVENTORY || sd->status.inventory[n].nameid <= 0
            || sd->inventory_data[n] == NULL)
            return 1;

        WFIFOW(fd, 0) = 0xa0;
        WFIFOW(fd, 2) = n + 2;
        WFIFOW(fd, 4) = amount;
        if (sd->inventory_data[n]->view_id > 0)
            WFIFOW(fd, 6) = sd->inventory_data[n]->view_id;
        else
            WFIFOW(fd, 6) = sd->status.inventory[n].nameid;
        WFIFOB(fd, 8) = sd->status.inventory[n].identify;
        if (sd->status.inventory[n].broken == 1)
            WFIFOB(fd, 9) = 1; // is weapon broken [Valaris]
        else
            WFIFOB(fd, 9) = sd->status.inventory[n].attribute;
        WFIFOB(fd, 10) = sd->status.inventory[n].refine;
        if (sd->status.inventory[n].card[0] == 0x00ff
            || sd->status.inventory[n].card[0] == 0x00fe
            || sd->status.inventory[n].card[0] == (short) 0xff00)
        {
            WFIFOW(fd, 11) = sd->status.inventory[n].card[0];
            WFIFOW(fd, 13) = sd->status.inventory[n].card[1];
            WFIFOW(fd, 15) = sd->status.inventory[n].card[2];
            WFIFOW(fd, 17) = sd->status.inventory[n].card[3];
        }
        else
        {
            int j;
            if (sd->status.inventory[n].card[0] > 0
                && (j = itemdb_viewid(sd->status.inventory[n].card[0])) > 0)
                WFIFOW(fd, 11) = j;
            else
                WFIFOW(fd, 11) = sd->status.inventory[n].card[0];
            if (sd->status.inventory[n].card[1] > 0
                && (j = itemdb_viewid(sd->status.inventory[n].card[1])) > 0)
                WFIFOW(fd, 13) = j;
            else
                WFIFOW(fd, 13) = sd->status.inventory[n].card[1];
            if (sd->status.inventory[n].card[2] > 0
                && (j = itemdb_viewid(sd->status.inventory[n].card[2])) > 0)
                WFIFOW(fd, 15) = j;
            else
                WFIFOW(fd, 15) = sd->status.inventory[n].card[2];
            if (sd->status.inventory[n].card[3] > 0
                && (j = itemdb_viewid(sd->status.inventory[n].card[3])) > 0)
                WFIFOW(fd, 17) = j;
            else
                WFIFOW(fd, 17) = sd->status.inventory[n].card[3];
        }
        WFIFOW(fd, 19) = uint16_t(pc_equippoint(sd, n));
        WFIFOB(fd, 21) = uint8_t(sd->inventory_data[n]->type == ItemType::_7
            ? ItemType::WEAPON
            : sd->inventory_data[n]->type);
        WFIFOB(fd, 22) = uint8_t(fail);
    }

    WFIFOSET(fd, clif_parse_func_table[0xa0].len);
    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_delitem(struct map_session_data *sd, int n, int amount)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0xaf;
    WFIFOW(fd, 2) = n + 2;
    WFIFOW(fd, 4) = amount;

    WFIFOSET(fd, clif_parse_func_table[0xaf].len);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_itemlist(struct map_session_data *sd)
{
    nullpo_ret(sd);

    int n = 0;
    int arrow = -1;
    int fd = sd->fd;
    WFIFOW(fd, 0) = 0x1ee;
    for (int i = 0; i < MAX_INVENTORY; i++)
    {
        if (sd->status.inventory[i].nameid <= 0
            || sd->inventory_data[i] == NULL
            || itemdb_isequip2(sd->inventory_data[i]))
            continue;
        WFIFOW(fd, n * 18 + 4) = i + 2;
        if (sd->inventory_data[i]->view_id > 0)
            WFIFOW(fd, n * 18 + 6) = sd->inventory_data[i]->view_id;
        else
            WFIFOW(fd, n * 18 + 6) = sd->status.inventory[i].nameid;
        WFIFOB(fd, n * 18 + 8) = uint8_t(sd->inventory_data[i]->type);
        WFIFOB(fd, n * 18 + 9) = sd->status.inventory[i].identify;
        WFIFOW(fd, n * 18 + 10) = sd->status.inventory[i].amount;
        if (sd->inventory_data[i]->equip == EPOS::ARROW)
        {
            WFIFOW(fd, n * 18 + 12) = uint16_t(EPOS::ARROW);
            if (bool(sd->status.inventory[i].equip))
                arrow = i;      // ついでに矢装備チェック
        }
        else
            WFIFOW(fd, n * 18 + 12) = uint16_t(EPOS::ZERO);
        WFIFOW(fd, n * 18 + 14) = sd->status.inventory[i].card[0];
        WFIFOW(fd, n * 18 + 16) = sd->status.inventory[i].card[1];
        WFIFOW(fd, n * 18 + 18) = sd->status.inventory[i].card[2];
        WFIFOW(fd, n * 18 + 20) = sd->status.inventory[i].card[3];
        n++;
    }
    if (n)
    {
        WFIFOW(fd, 2) = 4 + n * 18;
        WFIFOSET(fd, WFIFOW(fd, 2));
    }
    if (arrow >= 0)
        clif_arrowequip(sd, arrow);
    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_equiplist(struct map_session_data *sd)
{
    nullpo_ret(sd);

    int fd = sd->fd;
    WFIFOW(fd, 0) = 0xa4;
    int n = 0;
    for (int i = 0; i < MAX_INVENTORY; i++)
    {
        if (sd->status.inventory[i].nameid <= 0
            || sd->inventory_data[i] == NULL
            || !itemdb_isequip2(sd->inventory_data[i]))
            continue;
        WFIFOW(fd, n * 20 + 4) = i + 2;
        if (sd->inventory_data[i]->view_id > 0)
            WFIFOW(fd, n * 20 + 6) = sd->inventory_data[i]->view_id;
        else
            WFIFOW(fd, n * 20 + 6) = sd->status.inventory[i].nameid;
        WFIFOB(fd, n * 20 + 8) = uint8_t(
                sd->inventory_data[i]->type == ItemType::_7
                ? ItemType::WEAPON
                : sd->inventory_data[i]->type);
        WFIFOB(fd, n * 20 + 9) = sd->status.inventory[i].identify;
        WFIFOW(fd, n * 20 + 10) = uint16_t(pc_equippoint(sd, i));
        WFIFOW(fd, n * 20 + 12) = uint16_t(sd->status.inventory[i].equip);
        if (sd->status.inventory[i].broken == 1)
            WFIFOB(fd, n * 20 + 14) = 1;   // is weapon broken [Valaris]
        else
            WFIFOB(fd, n * 20 + 14) = sd->status.inventory[i].attribute;
        WFIFOB(fd, n * 20 + 15) = sd->status.inventory[i].refine;
        if (sd->status.inventory[i].card[0] == 0x00ff
            || sd->status.inventory[i].card[0] == 0x00fe
            || sd->status.inventory[i].card[0] == (short) 0xff00)
        {
            WFIFOW(fd, n * 20 + 16) = sd->status.inventory[i].card[0];
            WFIFOW(fd, n * 20 + 18) = sd->status.inventory[i].card[1];
            WFIFOW(fd, n * 20 + 20) = sd->status.inventory[i].card[2];
            WFIFOW(fd, n * 20 + 22) = sd->status.inventory[i].card[3];
        }
        else
        {
            int j;
            if (sd->status.inventory[i].card[0] > 0
                && (j = itemdb_viewid(sd->status.inventory[i].card[0])) > 0)
                WFIFOW(fd, n * 20 + 16) = j;
            else
                WFIFOW(fd, n * 20 + 16) = sd->status.inventory[i].card[0];
            if (sd->status.inventory[i].card[1] > 0
                && (j = itemdb_viewid(sd->status.inventory[i].card[1])) > 0)
                WFIFOW(fd, n * 20 + 18) = j;
            else
                WFIFOW(fd, n * 20 + 18) = sd->status.inventory[i].card[1];
            if (sd->status.inventory[i].card[2] > 0
                && (j = itemdb_viewid(sd->status.inventory[i].card[2])) > 0)
                WFIFOW(fd, n * 20 + 20) = j;
            else
                WFIFOW(fd, n * 20 + 20) = sd->status.inventory[i].card[2];
            if (sd->status.inventory[i].card[3] > 0
                && (j = itemdb_viewid(sd->status.inventory[i].card[3])) > 0)
                WFIFOW(fd, n * 20 + 22) = j;
            else
                WFIFOW(fd, n * 20 + 22) = sd->status.inventory[i].card[3];
        }
        n++;
    }
    if (n)
    {
        WFIFOW(fd, 2) = 4 + n * 20;
        WFIFOSET(fd, WFIFOW(fd, 2));
    }
    return 0;
}

/*==========================================
 * カプラさんに預けてある消耗品&収集品リスト
 *------------------------------------------
 */
int clif_storageitemlist(struct map_session_data *sd, struct storage *stor)
{
    nullpo_ret(sd);
    nullpo_ret(stor);

    int fd = sd->fd;
    WFIFOW(fd, 0) = 0x1f0;
    int n = 0;
    for (int i = 0; i < MAX_STORAGE; i++)
    {
        if (stor->storage_[i].nameid <= 0)
            continue;

        struct item_data *id;
        id = itemdb_search(stor->storage_[i].nameid);
        nullpo_ret(id);
        if (itemdb_isequip2(id))
            continue;

        WFIFOW(fd, n * 18 + 4) = i + 1;
        if (id->view_id > 0)
            WFIFOW(fd, n * 18 + 6) = id->view_id;
        else
            WFIFOW(fd, n * 18 + 6) = stor->storage_[i].nameid;
        WFIFOB(fd, n * 18 + 8) = uint8_t(id->type);
        WFIFOB(fd, n * 18 + 9) = stor->storage_[i].identify;
        WFIFOW(fd, n * 18 + 10) = stor->storage_[i].amount;
        WFIFOW(fd, n * 18 + 12) = 0;
        WFIFOW(fd, n * 18 + 14) = stor->storage_[i].card[0];
        WFIFOW(fd, n * 18 + 16) = stor->storage_[i].card[1];
        WFIFOW(fd, n * 18 + 18) = stor->storage_[i].card[2];
        WFIFOW(fd, n * 18 + 20) = stor->storage_[i].card[3];
        n++;
    }
    if (n)
    {
        WFIFOW(fd, 2) = 4 + n * 18;
        WFIFOSET(fd, WFIFOW(fd, 2));
    }
    return 0;
}

/*==========================================
 * カプラさんに預けてある装備リスト
 *------------------------------------------
 */
int clif_storageequiplist(struct map_session_data *sd, struct storage *stor)
{
    nullpo_ret(sd);
    nullpo_ret(stor);

    int fd = sd->fd;
    WFIFOW(fd, 0) = 0xa6;
    int n = 0;
    for (int i = 0; i < MAX_STORAGE; i++)
    {
        if (stor->storage_[i].nameid <= 0)
            continue;

        struct item_data *id;
        id = itemdb_search(stor->storage_[i].nameid);
        nullpo_ret(id);
        if (!itemdb_isequip2(id))
            continue;
        WFIFOW(fd, n * 20 + 4) = i + 1;
        if (id->view_id > 0)
            WFIFOW(fd, n * 20 + 6) = id->view_id;
        else
            WFIFOW(fd, n * 20 + 6) = stor->storage_[i].nameid;
        WFIFOB(fd, n * 20 + 8) = uint8_t(id->type);
        WFIFOB(fd, n * 20 + 9) = stor->storage_[i].identify;
        WFIFOW(fd, n * 20 + 10) = uint16_t(id->equip);
        WFIFOW(fd, n * 20 + 12) = uint16_t(stor->storage_[i].equip);
        if (stor->storage_[i].broken == 1)
            WFIFOB(fd, n * 20 + 14) = 1;   //is weapon broken [Valaris]
        else
            WFIFOB(fd, n * 20 + 14) = stor->storage_[i].attribute;
        WFIFOB(fd, n * 20 + 15) = stor->storage_[i].refine;
        if (stor->storage_[i].card[0] == 0x00ff
            || stor->storage_[i].card[0] == 0x00fe
            || stor->storage_[i].card[0] == (short) 0xff00)
        {
            WFIFOW(fd, n * 20 + 16) = stor->storage_[i].card[0];
            WFIFOW(fd, n * 20 + 18) = stor->storage_[i].card[1];
            WFIFOW(fd, n * 20 + 20) = stor->storage_[i].card[2];
            WFIFOW(fd, n * 20 + 22) = stor->storage_[i].card[3];
        }
        else
        {
            int j;
            if (stor->storage_[i].card[0] > 0
                && (j = itemdb_viewid(stor->storage_[i].card[0])) > 0)
                WFIFOW(fd, n * 20 + 16) = j;
            else
                WFIFOW(fd, n * 20 + 16) = stor->storage_[i].card[0];
            if (stor->storage_[i].card[1] > 0
                && (j = itemdb_viewid(stor->storage_[i].card[1])) > 0)
                WFIFOW(fd, n * 20 + 18) = j;
            else
                WFIFOW(fd, n * 20 + 18) = stor->storage_[i].card[1];
            if (stor->storage_[i].card[2] > 0
                && (j = itemdb_viewid(stor->storage_[i].card[2])) > 0)
                WFIFOW(fd, n * 20 + 20) = j;
            else
                WFIFOW(fd, n * 20 + 20) = stor->storage_[i].card[2];
            if (stor->storage_[i].card[3] > 0
                && (j = itemdb_viewid(stor->storage_[i].card[3])) > 0)
                WFIFOW(fd, n * 20 + 22) = j;
            else
                WFIFOW(fd, n * 20 + 22) = stor->storage_[i].card[3];
        }
        n++;
    }
    if (n)
    {
        WFIFOW(fd, 2) = 4 + n * 20;
        WFIFOSET(fd, WFIFOW(fd, 2));
    }
    return 0;
}

/*==========================================
 * ステータスを送りつける
 * 表示専用数字はこの中で計算して送る
 *------------------------------------------
 */
int clif_updatestatus(struct map_session_data *sd, SP type)
{
    int fd, len = 8;

    nullpo_ret(sd);

    fd = sd->fd;

    WFIFOW(fd, 0) = 0xb0;
    WFIFOW(fd, 2) = static_cast<uint16_t>(type);
    switch (type)
    {
            // 00b0
        case SP::WEIGHT:
            pc_checkweighticon(sd);
            // is this because pc_checkweighticon can send other packets?
            WFIFOW(fd, 0) = 0xb0;
            WFIFOW(fd, 2) = static_cast<uint16_t>(type);
            WFIFOL(fd, 4) = sd->weight;
            break;
        case SP::MAXWEIGHT:
            WFIFOL(fd, 4) = sd->max_weight;
            break;
        case SP::SPEED:
            // ...
            WFIFOL(fd, 4) = static_cast<uint16_t>(sd->speed.count());
            break;
        case SP::BASELEVEL:
            WFIFOL(fd, 4) = sd->status.base_level;
            break;
        case SP::JOBLEVEL:
            WFIFOL(fd, 4) = 0;
            break;
        case SP::STATUSPOINT:
            WFIFOL(fd, 4) = sd->status.status_point;
            break;
        case SP::SKILLPOINT:
            WFIFOL(fd, 4) = sd->status.skill_point;
            break;
        case SP::HIT:
            WFIFOL(fd, 4) = sd->hit;
            break;
        case SP::FLEE1:
            WFIFOL(fd, 4) = sd->flee;
            break;
        case SP::FLEE2:
            WFIFOL(fd, 4) = sd->flee2 / 10;
            break;
        case SP::MAXHP:
            WFIFOL(fd, 4) = sd->status.max_hp;
            break;
        case SP::MAXSP:
            WFIFOL(fd, 4) = sd->status.max_sp;
            break;
        case SP::HP:
            WFIFOL(fd, 4) = sd->status.hp;
            break;
        case SP::SP:
            WFIFOL(fd, 4) = sd->status.sp;
            break;
        case SP::ASPD:
            WFIFOL(fd, 4) = static_cast<uint16_t>(sd->aspd.count());
            break;
        case SP::ATK1:
            WFIFOL(fd, 4) = sd->base_atk + sd->watk;
            break;
        case SP::DEF1:
            WFIFOL(fd, 4) = sd->def;
            break;
        case SP::MDEF1:
            WFIFOL(fd, 4) = sd->mdef;
            break;
        case SP::ATK2:
            WFIFOL(fd, 4) = sd->watk2;
            break;
        case SP::DEF2:
            WFIFOL(fd, 4) = sd->def2;
            break;
        case SP::MDEF2:
            WFIFOL(fd, 4) = sd->mdef2;
            break;
        case SP::CRITICAL:
            WFIFOL(fd, 4) = sd->critical / 10;
            break;
        case SP::MATK1:
            WFIFOL(fd, 4) = sd->matk1;
            break;
        case SP::MATK2:
            WFIFOL(fd, 4) = sd->matk2;
            break;

        case SP::ZENY:
            trade_verifyzeny(sd);
            WFIFOW(fd, 0) = 0xb1;
            if (sd->status.zeny < 0)
                sd->status.zeny = 0;
            WFIFOL(fd, 4) = sd->status.zeny;
            break;
        case SP::BASEEXP:
            WFIFOW(fd, 0) = 0xb1;
            WFIFOL(fd, 4) = sd->status.base_exp;
            break;
        case SP::JOBEXP:
            WFIFOW(fd, 0) = 0xb1;
            WFIFOL(fd, 4) = sd->status.job_exp;
            break;
        case SP::NEXTBASEEXP:
            WFIFOW(fd, 0) = 0xb1;
            WFIFOL(fd, 4) = pc_nextbaseexp(sd);
            break;
        case SP::NEXTJOBEXP:
            WFIFOW(fd, 0) = 0xb1;
            WFIFOL(fd, 4) = pc_nextjobexp(sd);
            break;

            // 00be 終了
        case SP::USTR:
        case SP::UAGI:
        case SP::UVIT:
        case SP::UINT:
        case SP::UDEX:
        case SP::ULUK:
            WFIFOW(fd, 0) = 0xbe;
            WFIFOB(fd, 4) = pc_need_status_point(sd, usp_to_sp(type));
            len = 5;
            break;

            // 013a 終了
        case SP::ATTACKRANGE:
            WFIFOW(fd, 0) = 0x13a;
            WFIFOW(fd, 2) = (sd->attack_spell_override)
                ? sd->attack_spell_range : sd->attackrange;
            len = 4;
            break;

            // 0141 終了
        case SP::STR:
        case SP::AGI:
        case SP::VIT:
        case SP::INT:
        case SP::DEX:
        case SP::LUK:
        {
            ATTR attr = sp_to_attr(type);
            WFIFOW(fd, 0) = 0x141;
            WFIFOL(fd, 2) = uint16_t(type);
            WFIFOL(fd, 6) = sd->status.attrs[attr];
            WFIFOL(fd, 10) = sd->paramb[attr] + sd->parame[attr];
            len = 14;
        }
            break;

        case SP::GM:
            WFIFOL(fd, 4) = pc_isGM(sd);
            break;

        default:
            if (battle_config.error_log)
                PRINTF("clif_updatestatus : make %d routine\n",
                        type);
            return 1;
    }
    WFIFOSET(fd, len);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_changelook(struct block_list *bl, LOOK type, int val)
{
    return clif_changelook_towards(bl, type, val, NULL);
}

int clif_changelook_towards(struct block_list *bl, LOOK type, int val,
                             struct map_session_data *dstsd)
{
    unsigned char buf[32];
    struct map_session_data *sd = NULL;

    nullpo_ret(bl);

    if (bl->type == BL::PC)
        sd = (struct map_session_data *) bl;

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

    if (sd
        && (type == LOOK::WEAPON || type == LOOK::SHIELD || type >= LOOK::SHOES))
    {
        WBUFW(buf, 0) = 0x1d7;
        WBUFL(buf, 2) = bl->id;
        if (type >= LOOK::SHOES)
        {
            EQUIP equip_point = equip_points[type];

            WBUFB(buf, 6) = uint16_t(type);
            if (sd->equip_index[equip_point] >= 0
                && sd->inventory_data[sd->equip_index[equip_point]])
            {
                if (sd->
                    inventory_data[sd->equip_index[equip_point]]->view_id > 0)
                    WBUFW(buf, 7) =
                        sd->inventory_data[sd->
                                           equip_index[equip_point]]->view_id;
                else
                    WBUFW(buf, 7) =
                        sd->status.inventory[sd->
                                             equip_index[equip_point]].nameid;
            }
            else
                WBUFW(buf, 7) = 0;
            WBUFW(buf, 9) = 0;
        }
        else
        {
            WBUFB(buf, 6) = 2;
            if (sd->attack_spell_override)
                WBUFW(buf, 7) = sd->attack_spell_look_override;
            else
            {
                if (sd->equip_index[EQUIP::WEAPON] >= 0
                    && sd->inventory_data[sd->equip_index[EQUIP::WEAPON]])
                {
                    if (sd->inventory_data[sd->equip_index[EQUIP::WEAPON]]->view_id > 0)
                        WBUFW(buf, 7) =
                            sd->inventory_data[sd->equip_index[EQUIP::WEAPON]]->view_id;
                    else
                        WBUFW(buf, 7) =
                            sd->status.inventory[sd->equip_index[EQUIP::WEAPON]].nameid;
                }
                else
                    WBUFW(buf, 7) = 0;
            }
            if (sd->equip_index[EQUIP::SHIELD] >= 0
                && sd->equip_index[EQUIP::SHIELD] != sd->equip_index[EQUIP::WEAPON]
                && sd->inventory_data[sd->equip_index[EQUIP::SHIELD]])
            {
                if (sd->inventory_data[sd->equip_index[EQUIP::SHIELD]]->view_id > 0)
                    WBUFW(buf, 9) =
                        sd->inventory_data[sd->equip_index[EQUIP::SHIELD]]->view_id;
                else
                    WBUFW(buf, 9) =
                        sd->status.inventory[sd->equip_index[EQUIP::SHIELD]].nameid;
            }
            else
                WBUFW(buf, 9) = 0;
        }
        if (dstsd)
            clif_send(buf, clif_parse_func_table[0x1d7].len, &dstsd->bl, SendWho::SELF);
        else
            clif_send(buf, clif_parse_func_table[0x1d7].len, bl, SendWho::AREA);
    }
    else
    {
        WBUFW(buf, 0) = 0x1d7;
        WBUFL(buf, 2) = bl->id;
        WBUFB(buf, 6) = uint8_t(type);
        WBUFW(buf, 7) = val;
        WBUFW(buf, 9) = 0;
        if (dstsd)
            clif_send(buf, clif_parse_func_table[0x1d7].len, &dstsd->bl, SendWho::SELF);
        else
            clif_send(buf, clif_parse_func_table[0x1d7].len, bl, SendWho::AREA);
    }
    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
static
int clif_initialstatus(struct map_session_data *sd)
{
    nullpo_ret(sd);

    int fd = sd->fd;

    WFIFOW(fd, 0) = 0xbd;
    WFIFOW(fd, 2) = sd->status.status_point;

    WFIFOB(fd, 4) = min(sd->status.attrs[ATTR::STR], 255);
    WFIFOB(fd, 5) = pc_need_status_point(sd, SP::STR);
    WFIFOB(fd, 6) = min(sd->status.attrs[ATTR::AGI], 255);
    WFIFOB(fd, 7) = pc_need_status_point(sd, SP::AGI);
    WFIFOB(fd, 8) = min(sd->status.attrs[ATTR::VIT], 255);
    WFIFOB(fd, 9) = pc_need_status_point(sd, SP::VIT);
    WFIFOB(fd, 10) = min(sd->status.attrs[ATTR::INT], 255);
    WFIFOB(fd, 11) = pc_need_status_point(sd, SP::INT);
    WFIFOB(fd, 12) = min(sd->status.attrs[ATTR::DEX], 255);
    WFIFOB(fd, 13) = pc_need_status_point(sd, SP::DEX);
    WFIFOB(fd, 14) = min(sd->status.attrs[ATTR::LUK], 255);
    WFIFOB(fd, 15) = pc_need_status_point(sd, SP::LUK);

    WFIFOW(fd, 16) = sd->base_atk + sd->watk;
    WFIFOW(fd, 18) = sd->watk2;    //atk bonus
    WFIFOW(fd, 20) = sd->matk1;
    WFIFOW(fd, 22) = sd->matk2;
    WFIFOW(fd, 24) = sd->def;  // def
    WFIFOW(fd, 26) = sd->def2;
    WFIFOW(fd, 28) = sd->mdef; // mdef
    WFIFOW(fd, 30) = sd->mdef2;
    WFIFOW(fd, 32) = sd->hit;
    WFIFOW(fd, 34) = sd->flee;
    WFIFOW(fd, 36) = sd->flee2 / 10;
    WFIFOW(fd, 38) = sd->critical / 10;
    WFIFOW(fd, 40) = sd->status.karma;
    WFIFOW(fd, 42) = sd->status.manner;

    WFIFOSET(fd, clif_parse_func_table[0xbd].len);

    clif_updatestatus(sd, SP::STR);
    clif_updatestatus(sd, SP::AGI);
    clif_updatestatus(sd, SP::VIT);
    clif_updatestatus(sd, SP::INT);
    clif_updatestatus(sd, SP::DEX);
    clif_updatestatus(sd, SP::LUK);

    clif_updatestatus(sd, SP::ATTACKRANGE);
    clif_updatestatus(sd, SP::ASPD);

    return 0;
}

/*==========================================
 *矢装備
 *------------------------------------------
 */
int clif_arrowequip(struct map_session_data *sd, int val)
{
    int fd;

    nullpo_ret(sd);

    if (sd->attacktarget && sd->attacktarget > 0)   // [Valaris]
        sd->attacktarget = 0;

    fd = sd->fd;
    WFIFOW(fd, 0) = 0x013c;
    WFIFOW(fd, 2) = val + 2;   //矢のアイテムID

    WFIFOSET(fd, clif_parse_func_table[0x013c].len);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_arrow_fail(struct map_session_data *sd, int type)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0x013b;
    WFIFOW(fd, 2) = type;

    WFIFOSET(fd, clif_parse_func_table[0x013b].len);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_statusupack(struct map_session_data *sd, SP type, int ok, int val)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0xbc;
    WFIFOW(fd, 2) = uint16_t(type);
    WFIFOB(fd, 4) = ok;
    WFIFOB(fd, 5) = val;
    WFIFOSET(fd, clif_parse_func_table[0xbc].len);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_equipitemack(struct map_session_data *sd, int n, EPOS pos, int ok)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0xaa;
    WFIFOW(fd, 2) = n + 2;
    WFIFOW(fd, 4) = uint16_t(pos);
    WFIFOB(fd, 6) = ok;
    WFIFOSET(fd, clif_parse_func_table[0xaa].len);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_unequipitemack(struct map_session_data *sd, int n, EPOS pos, int ok)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0xac;
    WFIFOW(fd, 2) = n + 2;
    WFIFOW(fd, 4) = uint16_t(pos);
    WFIFOB(fd, 6) = ok;
    WFIFOSET(fd, clif_parse_func_table[0xac].len);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_misceffect(struct block_list *bl, int type)
{
    uint8_t buf[32];

    nullpo_ret(bl);

    WBUFW(buf, 0) = 0x19b;
    WBUFL(buf, 2) = bl->id;
    WBUFL(buf, 6) = type;

    clif_send(buf, clif_parse_func_table[0x19b].len, bl, SendWho::AREA);

    return 0;
}

/*==========================================
 * 表示オプション変更
 *------------------------------------------
 */
int clif_changeoption(struct block_list *bl)
{
    uint8_t buf[32];
    eptr<struct status_change, StatusChange> sc_data;

    nullpo_ret(bl);

    Option option = *battle_get_option(bl);
    sc_data = battle_get_sc_data(bl);

    WBUFW(buf, 0) = 0x119;
    WBUFL(buf, 2) = bl->id;
    WBUFW(buf, 6) = uint16_t(*battle_get_opt1(bl));
    WBUFW(buf, 8) = uint16_t(*battle_get_opt2(bl));
    WBUFW(buf, 10) = uint16_t(option);
    WBUFB(buf, 12) = 0;        // ??

    clif_send(buf, clif_parse_func_table[0x119].len, bl, SendWho::AREA);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_useitemack(struct map_session_data *sd, int index, int amount,
                     int ok)
{
    nullpo_ret(sd);

    if (!ok)
    {
        int fd = sd->fd;
        WFIFOW(fd, 0) = 0xa8;
        WFIFOW(fd, 2) = index + 2;
        WFIFOW(fd, 4) = amount;
        WFIFOB(fd, 6) = ok;
        WFIFOSET(fd, clif_parse_func_table[0xa8].len);
    }
    else
    {
        uint8_t buf[32];

        WBUFW(buf, 0) = 0x1c8;
        WBUFW(buf, 2) = index + 2;
        if (sd->inventory_data[index]
            && sd->inventory_data[index]->view_id > 0)
            WBUFW(buf, 4) = sd->inventory_data[index]->view_id;
        else
            WBUFW(buf, 4) = sd->status.inventory[index].nameid;
        WBUFL(buf, 6) = sd->bl.id;
        WBUFW(buf, 10) = amount;
        WBUFB(buf, 12) = ok;
        clif_send(buf, clif_parse_func_table[0x1c8].len, &sd->bl, SendWho::SELF);
    }

    return 0;
}

/*==========================================
 * 取り引き要請受け
 *------------------------------------------
 */
int clif_traderequest(struct map_session_data *sd, const char *name)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0xe5;
    strcpy((char *)WFIFOP(fd, 2), name);
    WFIFOSET(fd, clif_parse_func_table[0xe5].len);

    return 0;
}

/*==========================================
 * 取り引き要求応答
 *------------------------------------------
 */
int clif_tradestart(struct map_session_data *sd, int type)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0xe7;
    WFIFOB(fd, 2) = type;
    WFIFOSET(fd, clif_parse_func_table[0xe7].len);

    return 0;
}

/*==========================================
 * 相手方からのアイテム追加
 *------------------------------------------
 */
int clif_tradeadditem(struct map_session_data *sd,
                       struct map_session_data *tsd, int index, int amount)
{
    int fd, j;

    nullpo_ret(sd);
    nullpo_ret(tsd);

    fd = tsd->fd;
    WFIFOW(fd, 0) = 0xe9;
    WFIFOL(fd, 2) = amount;
    if (index == 0)
    {
        WFIFOW(fd, 6) = 0;     // type id
        WFIFOB(fd, 8) = 0;     //identify flag
        WFIFOB(fd, 9) = 0;     // attribute
        WFIFOB(fd, 10) = 0;    //refine
        WFIFOW(fd, 11) = 0;    //card (4w)
        WFIFOW(fd, 13) = 0;    //card (4w)
        WFIFOW(fd, 15) = 0;    //card (4w)
        WFIFOW(fd, 17) = 0;    //card (4w)
    }
    else
    {
        index -= 2;
        if (sd->inventory_data[index]
            && sd->inventory_data[index]->view_id > 0)
            WFIFOW(fd, 6) = sd->inventory_data[index]->view_id;
        else
            WFIFOW(fd, 6) = sd->status.inventory[index].nameid;    // type id
        WFIFOB(fd, 8) = sd->status.inventory[index].identify;  //identify flag
        if (sd->status.inventory[index].broken == 1)
            WFIFOB(fd, 9) = 1; // is broke weapon [Valaris]
        else
            WFIFOB(fd, 9) = sd->status.inventory[index].attribute; // attribute
        WFIFOB(fd, 10) = sd->status.inventory[index].refine;   //refine
        if (sd->status.inventory[index].card[0] == 0x00ff
            || sd->status.inventory[index].card[0] == 0x00fe
            || sd->status.inventory[index].card[0] == (short) 0xff00)
        {
            WFIFOW(fd, 11) = sd->status.inventory[index].card[0];  //card (4w)
            WFIFOW(fd, 13) = sd->status.inventory[index].card[1];  //card (4w)
            WFIFOW(fd, 15) = sd->status.inventory[index].card[2];  //card (4w)
            WFIFOW(fd, 17) = sd->status.inventory[index].card[3];  //card (4w)
        }
        else
        {
            if (sd->status.inventory[index].card[0] > 0
                && (j =
                    itemdb_viewid(sd->status.inventory[index].card[0])) > 0)
                WFIFOW(fd, 11) = j;
            else
                WFIFOW(fd, 11) = sd->status.inventory[index].card[0];
            if (sd->status.inventory[index].card[1] > 0
                && (j =
                    itemdb_viewid(sd->status.inventory[index].card[1])) > 0)
                WFIFOW(fd, 13) = j;
            else
                WFIFOW(fd, 13) = sd->status.inventory[index].card[1];
            if (sd->status.inventory[index].card[2] > 0
                && (j =
                    itemdb_viewid(sd->status.inventory[index].card[2])) > 0)
                WFIFOW(fd, 15) = j;
            else
                WFIFOW(fd, 15) = sd->status.inventory[index].card[2];
            if (sd->status.inventory[index].card[3] > 0
                && (j =
                    itemdb_viewid(sd->status.inventory[index].card[3])) > 0)
                WFIFOW(fd, 17) = j;
            else
                WFIFOW(fd, 17) = sd->status.inventory[index].card[3];
        }
    }
    WFIFOSET(fd, clif_parse_func_table[0xe9].len);

    return 0;
}

/*==========================================
 * アイテム追加成功/失敗
 *------------------------------------------
 */
int clif_tradeitemok(struct map_session_data *sd, int index, int amount,
                      int fail)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0x1b1;
    WFIFOW(fd, 2) = index;
    WFIFOW(fd, 4) = amount;
    WFIFOB(fd, 6) = fail;
    WFIFOSET(fd, clif_parse_func_table[0x1b1].len);

    return 0;
}

/*==========================================
 * 取り引きok押し
 *------------------------------------------
 */
int clif_tradedeal_lock(struct map_session_data *sd, int fail)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0xec;
    WFIFOB(fd, 2) = fail;      // 0=you 1=the other person
    WFIFOSET(fd, clif_parse_func_table[0xec].len);

    return 0;
}

/*==========================================
 * 取り引きがキャンセルされました
 *------------------------------------------
 */
int clif_tradecancelled(struct map_session_data *sd)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0xee;
    WFIFOSET(fd, clif_parse_func_table[0xee].len);

    return 0;
}

/*==========================================
 * 取り引き完了
 *------------------------------------------
 */
int clif_tradecompleted(struct map_session_data *sd, int fail)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0xf0;
    WFIFOB(fd, 2) = fail;
    WFIFOSET(fd, clif_parse_func_table[0xf0].len);

    return 0;
}

/*==========================================
 * カプラ倉庫のアイテム数を更新
 *------------------------------------------
 */
int clif_updatestorageamount(struct map_session_data *sd,
                              struct storage *stor)
{
    int fd;

    nullpo_ret(sd);
    nullpo_ret(stor);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0xf2;      // update storage amount
    WFIFOW(fd, 2) = stor->storage_amount;  //items
    WFIFOW(fd, 4) = MAX_STORAGE;   //items max
    WFIFOSET(fd, clif_parse_func_table[0xf2].len);

    return 0;
}

/*==========================================
 * カプラ倉庫にアイテムを追加する
 *------------------------------------------
 */
int clif_storageitemadded(struct map_session_data *sd, struct storage *stor,
                           int index, int amount)
{
    int fd, j;

    nullpo_ret(sd);
    nullpo_ret(stor);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0xf4;      // Storage item added
    WFIFOW(fd, 2) = index + 1; // index
    WFIFOL(fd, 4) = amount;    // amount
/*      if ((view = itemdb_viewid(stor->storage_[index].nameid)) > 0)
                WFIFOW(fd,8) =view;
        else*/
    WFIFOW(fd, 8) = stor->storage_[index].nameid;
    WFIFOB(fd, 10) = stor->storage_[index].identify;   //identify flag
    if (stor->storage_[index].broken == 1)
        WFIFOB(fd, 11) = 1;    // is weapon broken [Valaris]
    else
        WFIFOB(fd, 11) = stor->storage_[index].attribute;  // attribute
    WFIFOB(fd, 12) = stor->storage_[index].refine; //refine
    if (stor->storage_[index].card[0] == 0x00ff
        || stor->storage_[index].card[0] == 0x00fe
        || stor->storage_[index].card[0] == (short) 0xff00)
    {
        WFIFOW(fd, 13) = stor->storage_[index].card[0];    //card (4w)
        WFIFOW(fd, 15) = stor->storage_[index].card[1];    //card (4w)
        WFIFOW(fd, 17) = stor->storage_[index].card[2];    //card (4w)
        WFIFOW(fd, 19) = stor->storage_[index].card[3];    //card (4w)
    }
    else
    {
        if (stor->storage_[index].card[0] > 0
            && (j = itemdb_viewid(stor->storage_[index].card[0])) > 0)
            WFIFOW(fd, 13) = j;
        else
            WFIFOW(fd, 13) = stor->storage_[index].card[0];
        if (stor->storage_[index].card[1] > 0
            && (j = itemdb_viewid(stor->storage_[index].card[1])) > 0)
            WFIFOW(fd, 15) = j;
        else
            WFIFOW(fd, 15) = stor->storage_[index].card[1];
        if (stor->storage_[index].card[2] > 0
            && (j = itemdb_viewid(stor->storage_[index].card[2])) > 0)
            WFIFOW(fd, 17) = j;
        else
            WFIFOW(fd, 17) = stor->storage_[index].card[2];
        if (stor->storage_[index].card[3] > 0
            && (j = itemdb_viewid(stor->storage_[index].card[3])) > 0)
            WFIFOW(fd, 19) = j;
        else
            WFIFOW(fd, 19) = stor->storage_[index].card[3];
    }
    WFIFOSET(fd, clif_parse_func_table[0xf4].len);

    return 0;
}

/*==========================================
 * カプラ倉庫からアイテムを取り去る
 *------------------------------------------
 */
int clif_storageitemremoved(struct map_session_data *sd, int index,
                             int amount)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0xf6;      // Storage item removed
    WFIFOW(fd, 2) = index + 1;
    WFIFOL(fd, 4) = amount;
    WFIFOSET(fd, clif_parse_func_table[0xf6].len);

    return 0;
}

/*==========================================
 * カプラ倉庫を閉じる
 *------------------------------------------
 */
int clif_storageclose(struct map_session_data *sd)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0xf8;      // Storage Closed
    WFIFOSET(fd, clif_parse_func_table[0xf8].len);

    return 0;
}

void clif_changelook_accessories(struct block_list *bl,
                             struct map_session_data *dest)
{
    for (LOOK i = LOOK::SHOES; i < LOOK::COUNT; i = LOOK(uint8_t(i) + 1))
        clif_changelook_towards(bl, i, 0, dest);
}

//
// callback系 ?
//
/*==========================================
 * PC表示
 *------------------------------------------
 */
static
void clif_getareachar_pc(struct map_session_data *sd,
                          struct map_session_data *dstsd)
{
    int len;

    if (bool(dstsd->status.option & Option::INVISIBILITY))
        return;

    nullpo_retv(sd);
    nullpo_retv(dstsd);

    if (dstsd->walktimer)
    {
        len = clif_set007b(dstsd, static_cast<uint8_t *>(WFIFOP(sd->fd, 0)));
        WFIFOSET(sd->fd, len);
    }
    else
    {
        len = clif_set0078(dstsd, static_cast<uint8_t *>(WFIFOP(sd->fd, 0)));
        WFIFOSET(sd->fd, len);
    }

    if (battle_config.save_clothcolor == 1 && dstsd->status.clothes_color > 0)
        clif_changelook(&dstsd->bl, LOOK::CLOTHES_COLOR,
                         dstsd->status.clothes_color);

    clif_changelook_accessories(&sd->bl, dstsd);
    clif_changelook_accessories(&dstsd->bl, sd);
}

/*==========================================
 * NPC表示
 *------------------------------------------
 */
static
void clif_getareachar_npc(struct map_session_data *sd, struct npc_data *nd)
{
    int len;

    nullpo_retv(sd);
    nullpo_retv(nd);

    if (nd->npc_class < 0 || nd->flag & 1 || nd->npc_class == INVISIBLE_CLASS)
        return;

    len = clif_npc0078(nd, static_cast<uint8_t *>(WFIFOP(sd->fd, 0)));
    WFIFOSET(sd->fd, len);
}

/*==========================================
 * 移動停止
 *------------------------------------------
 */
int clif_movemob(struct mob_data *md)
{
    unsigned char buf[256];
    int len;

    nullpo_ret(md);

    len = clif_mob007b(md, buf);
    clif_send(buf, len, &md->bl, SendWho::AREA);

    return 0;
}

/*==========================================
 * モンスターの位置修正
 *------------------------------------------
 */
int clif_fixmobpos(struct mob_data *md)
{
    unsigned char buf[256];
    int len;

    nullpo_ret(md);

    if (md->state.state == MS::WALK)
    {
        len = clif_mob007b(md, buf);
        clif_send(buf, len, &md->bl, SendWho::AREA);
    }
    else
    {
        len = clif_mob0078(md, buf);
        clif_send(buf, len, &md->bl, SendWho::AREA);
    }

    return 0;
}

/*==========================================
 * PCの位置修正
 *------------------------------------------
 */
int clif_fixpcpos(struct map_session_data *sd)
{
    unsigned char buf[256];
    int len;

    nullpo_ret(sd);

    if (sd->walktimer)
    {
        len = clif_set007b(sd, buf);
        clif_send(buf, len, &sd->bl, SendWho::AREA);
    }
    else
    {
        len = clif_set0078(sd, buf);
        clif_send(buf, len, &sd->bl, SendWho::AREA);
    }
    clif_changelook_accessories(&sd->bl, NULL);

    return 0;
}

/*==========================================
 * 通常攻撃エフェクト&ダメージ
 *------------------------------------------
 */
int clif_damage(struct block_list *src, struct block_list *dst,
        tick_t tick, interval_t sdelay, interval_t ddelay, int damage,
        int div, DamageType type, int damage2)
{
    unsigned char buf[256];
    eptr<struct status_change, StatusChange> sc_data;

    nullpo_ret(src);
    nullpo_ret(dst);

    sc_data = battle_get_sc_data(dst);

    WBUFW(buf, 0) = 0x8a;
    WBUFL(buf, 2) = src->id;
    WBUFL(buf, 6) = dst->id;
    WBUFL(buf, 10) = tick.time_since_epoch().count();
    WBUFL(buf, 14) = sdelay.count();
    WBUFL(buf, 18) = ddelay.count();
    WBUFW(buf, 22) = (damage > 0x7fff) ? 0x7fff : damage;
    WBUFW(buf, 24) = div;
    WBUFB(buf, 26) = static_cast<uint8_t>(type);
    WBUFW(buf, 27) = damage2;
    clif_send(buf, clif_parse_func_table[0x8a].len, src, SendWho::AREA);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_getareachar_mob(struct map_session_data *sd, struct mob_data *md)
{
    int len;
    nullpo_retv(sd);
    nullpo_retv(md);

    if (md->state.state == MS::WALK)
    {
        len = clif_mob007b(md, static_cast<uint8_t *>(WFIFOP(sd->fd, 0)));
        WFIFOSET(sd->fd, len);
    }
    else
    {
        len = clif_mob0078(md, static_cast<uint8_t *>(WFIFOP(sd->fd, 0)));
        WFIFOSET(sd->fd, len);
    }
}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_getareachar_item(struct map_session_data *sd,
                            struct flooritem_data *fitem)
{
    int view, fd;

    nullpo_retv(sd);
    nullpo_retv(fitem);

    fd = sd->fd;
    //009d <ID>.l <item ID>.w <identify flag>.B <X>.w <Y>.w <amount>.w <subX>.B <subY>.B
    WFIFOW(fd, 0) = 0x9d;
    WFIFOL(fd, 2) = fitem->bl.id;
    if ((view = itemdb_viewid(fitem->item_data.nameid)) > 0)
        WFIFOW(fd, 6) = view;
    else
        WFIFOW(fd, 6) = fitem->item_data.nameid;
    WFIFOB(fd, 8) = fitem->item_data.identify;
    WFIFOW(fd, 9) = fitem->bl.x;
    WFIFOW(fd, 11) = fitem->bl.y;
    WFIFOW(fd, 13) = fitem->item_data.amount;
    WFIFOB(fd, 15) = fitem->subx;
    WFIFOB(fd, 16) = fitem->suby;

    WFIFOSET(fd, clif_parse_func_table[0x9d].len);
}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_getareachar(struct block_list *bl, struct map_session_data *sd)
{
    nullpo_retv(bl);

    switch (bl->type)
    {
        case BL::PC:
            if (sd == (struct map_session_data *) bl)
                break;
            clif_getareachar_pc(sd, (struct map_session_data *) bl);
            break;
        case BL::NPC:
            clif_getareachar_npc(sd, (struct npc_data *) bl);
            break;
        case BL::MOB:
            clif_getareachar_mob(sd, (struct mob_data *) bl);
            break;
        case BL::ITEM:
            clif_getareachar_item(sd, (struct flooritem_data *) bl);
            break;
        default:
            if (battle_config.error_log)
                PRINTF("get area char ??? %d\n",
                        bl->type);
            break;
    }
}

/*==========================================
 *
 *------------------------------------------
 */
void clif_pcoutsight(struct block_list *bl, struct map_session_data *sd)
{
    struct map_session_data *dstsd;

    nullpo_retv(bl);
    nullpo_retv(sd);

    switch (bl->type)
    {
        case BL::PC:
            dstsd = (struct map_session_data *) bl;
            if (sd != dstsd)
            {
                clif_clearchar_id(dstsd->bl.id, BeingRemoveWhy::GONE, sd->fd);
                clif_clearchar_id(sd->bl.id, BeingRemoveWhy::GONE, dstsd->fd);
            }
            break;
        case BL::NPC:
            if (((struct npc_data *) bl)->npc_class != INVISIBLE_CLASS)
                clif_clearchar_id(bl->id, BeingRemoveWhy::GONE, sd->fd);
            break;
        case BL::MOB:
            clif_clearchar_id(bl->id, BeingRemoveWhy::GONE, sd->fd);
            break;
        case BL::ITEM:
            clif_clearflooritem((struct flooritem_data *) bl, sd->fd);
            break;
    }
}

/*==========================================
 *
 *------------------------------------------
 */
void clif_pcinsight(struct block_list *bl, struct map_session_data *sd)
{
    struct map_session_data *dstsd;

    nullpo_retv(bl);
    nullpo_retv(sd);

    switch (bl->type)
    {
        case BL::PC:
            dstsd = (struct map_session_data *) bl;
            if (sd != dstsd)
            {
                clif_getareachar_pc(sd, dstsd);
                clif_getareachar_pc(dstsd, sd);
            }
            break;
        case BL::NPC:
            clif_getareachar_npc(sd, (struct npc_data *) bl);
            break;
        case BL::MOB:
            clif_getareachar_mob(sd, (struct mob_data *) bl);
            break;
        case BL::ITEM:
            clif_getareachar_item(sd, (struct flooritem_data *) bl);
            break;
    }
}

/*==========================================
 *
 *------------------------------------------
 */
void clif_moboutsight(struct block_list *bl, struct mob_data *md)
{
    struct map_session_data *sd;

    nullpo_retv(bl);
    nullpo_retv(md);

    if (bl->type == BL::PC && (sd = (struct map_session_data *) bl))
    {
        clif_clearchar_id(md->bl.id, BeingRemoveWhy::GONE, sd->fd);
    }
}

/*==========================================
 *
 *------------------------------------------
 */
void clif_mobinsight(struct block_list *bl, struct mob_data *md)
{
    struct map_session_data *sd;

    nullpo_retv(bl);
    nullpo_retv(md);

    if (bl->type == BL::PC && (sd = (struct map_session_data *) bl))
    {
        clif_getareachar_mob(sd, md);
    }
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_skillinfo(struct map_session_data *sd, SkillID skillid, int type,
                    int range)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    if (!sd->status.skill[skillid].lv)
        return 0;
    WFIFOW(fd, 0) = 0x147;
    WFIFOW(fd, 2) = static_cast<uint16_t>(skillid);
    if (type < 0)
        WFIFOW(fd, 4) = skill_get_inf(skillid);
    else
        WFIFOW(fd, 4) = type;
    WFIFOW(fd, 6) = 0;
    WFIFOW(fd, 8) = sd->status.skill[skillid].lv;
    WFIFOW(fd, 10) = skill_get_sp(skillid, sd->status.skill[skillid].lv);
    if (range < 0)
    {
        range = skill_get_range(skillid, sd->status.skill[skillid].lv);
        if (range < 0)
            range = battle_get_range(&sd->bl) - (range + 1);
        WFIFOW(fd, 12) = range;
    }
    else
        WFIFOW(fd, 12) = range;
    memset(WFIFOP(fd, 14), 0, 24);
    WFIFOB(fd, 38) = sd->status.skill[skillid].lv < skill_get_max_raise(skillid);
    WFIFOSET(fd, clif_parse_func_table[0x147].len);

    return 0;
}

/*==========================================
 * スキルリストを送信する
 *------------------------------------------
 */
int clif_skillinfoblock(struct map_session_data *sd)
{
    int fd;
    int len = 4, range;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0x10f;
    for (SkillID i : erange(SkillID(), MAX_SKILL))
    {
        if (sd->status.skill[i].lv && sd->tmw_version >= 1)
        {
            // [Fate] Version 1 and later don't crash because of bad skill IDs anymore
            WFIFOW(fd, len) = static_cast<uint16_t>(i);
            WFIFOW(fd, len + 2) = skill_get_inf(i);
            WFIFOW(fd, len + 4) = static_cast<uint16_t>(
                skill_db[i].poolflags
                | (sd->status.skill[i].flags & SkillFlags::POOL_ACTIVATED));
            WFIFOW(fd, len + 6) = sd->status.skill[i].lv;
            WFIFOW(fd, len + 8) = skill_get_sp(i, sd->status.skill[i].lv);
            range = skill_get_range(i, sd->status.skill[i].lv);
            if (range < 0)
                range = battle_get_range(&sd->bl) - (range + 1);
            WFIFOW(fd, len + 10) = range;
            memset(WFIFOP(fd, len + 12), 0, 24);
            WFIFOB(fd, len + 36) = sd->status.skill[i].lv < skill_get_max_raise(i);
            len += 37;
        }
    }
    WFIFOW(fd, 2) = len;
    WFIFOSET(fd, len);

    return 0;
}

/*==========================================
 * スキル割り振り通知
 *------------------------------------------
 */
int clif_skillup(struct map_session_data *sd, SkillID skill_num)
{
    int range, fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0x10e;
    WFIFOW(fd, 2) = uint16_t(skill_num);
    WFIFOW(fd, 4) = sd->status.skill[skill_num].lv;
    WFIFOW(fd, 6) = skill_get_sp(skill_num, sd->status.skill[skill_num].lv);
    range = skill_get_range(skill_num, sd->status.skill[skill_num].lv);
    if (range < 0)
        range = battle_get_range(&sd->bl) - (range + 1);
    WFIFOW(fd, 8) = range;
    WFIFOB(fd, 10) = sd->status.skill[skill_num].lv < skill_get_max_raise(skill_num);
    WFIFOSET(fd, clif_parse_func_table[0x10e].len);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
int clif_skillcastcancel(struct block_list *bl)
{
    unsigned char buf[16];

    nullpo_ret(bl);

    WBUFW(buf, 0) = 0x1b9;
    WBUFL(buf, 2) = bl->id;
    clif_send(buf, clif_parse_func_table[0x1b9].len, bl, SendWho::AREA);

    return 0;
}

/*==========================================
 * スキル詠唱失敗
 *------------------------------------------
 */
int clif_skill_fail(struct map_session_data *sd, SkillID skill_id, int type,
                     int btype)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;

    if (type == 0x4 && battle_config.display_delay_skill_fail == 0)
    {
        return 0;
    }

    WFIFOW(fd, 0) = 0x110;
    WFIFOW(fd, 2) = uint16_t(skill_id);
    WFIFOW(fd, 4) = btype;
    WFIFOW(fd, 6) = 0;
    WFIFOB(fd, 8) = 0;
    WFIFOB(fd, 9) = type;
    WFIFOSET(fd, clif_parse_func_table[0x110].len);

    return 0;
}

/*==========================================
 * スキル攻撃エフェクト&ダメージ
 *------------------------------------------
 */
int clif_skill_damage(struct block_list *src, struct block_list *dst,
        tick_t tick, interval_t sdelay, interval_t ddelay, int damage,
        int div, SkillID skill_id, int skill_lv, int type)
{
    unsigned char buf[64];
    eptr<struct status_change, StatusChange> sc_data;

    nullpo_ret(src);
    nullpo_ret(dst);

    sc_data = battle_get_sc_data(dst);

    WBUFW(buf, 0) = 0x1de;
    WBUFW(buf, 2) = uint16_t(skill_id);
    WBUFL(buf, 4) = src->id;
    WBUFL(buf, 8) = dst->id;
    WBUFL(buf, 12) = static_cast<uint32_t>(tick.time_since_epoch().count());
    WBUFL(buf, 16) = static_cast<uint32_t>(sdelay.count());
    WBUFL(buf, 20) = static_cast<uint32_t>(ddelay.count());
    WBUFL(buf, 24) = damage;
    WBUFW(buf, 28) = skill_lv;
    WBUFW(buf, 30) = div;
    WBUFB(buf, 32) = (type > 0) ? type : skill_get_hit(skill_id);
    clif_send(buf, clif_parse_func_table[0x1de].len, src, SendWho::AREA);

    return 0;
}

/*==========================================
 * 状態異常アイコン/メッセージ表示
 *------------------------------------------
 */
int clif_status_change(struct block_list *bl, StatusChange type, int flag)
{
    unsigned char buf[16];

    nullpo_ret(bl);

    WBUFW(buf, 0) = 0x0196;
    WBUFW(buf, 2) = uint16_t(type);
    WBUFL(buf, 4) = bl->id;
    WBUFB(buf, 8) = flag;
    clif_send(buf, clif_parse_func_table[0x196].len, bl, SendWho::AREA);
    return 0;
}

/*==========================================
 * Send message (modified by [Yor])
 *------------------------------------------
 */
void clif_displaymessage(int fd, const_string mes)
{
    if (mes)
    {
        // don't send a void message (it's not displaying on the client chat). @help can send void line.
        WFIFOW(fd, 0) = 0x8e;
        WFIFOW(fd, 2) = 5 + mes.size();   // 4 + len + NULL teminate
        memcpy(WFIFOP(fd, 4), mes.data(), mes.size());
        WFIFOB(fd, 4 + mes.size()) = '\0';
        WFIFOSET(fd, 5 + mes.size());
    }
}

/*==========================================
 * 天の声を送信する
 *------------------------------------------
 */
void clif_GMmessage(struct block_list *bl, const_string mes, int flag)
{
    unsigned char buf[mes.size() + 16];
    int lp = (flag & 0x10) ? 8 : 4;

    WBUFW(buf, 0) = 0x9a;
    WBUFW(buf, 2) = mes.size() + 1 + lp;
    WBUFL(buf, 4) = 0x65756c62;
    memcpy(WBUFP(buf, lp), mes.data(), mes.size());
    WBUFB(buf, lp + mes.size()) = '\0';
    flag &= 0x07;
    clif_send(buf, WBUFW(buf, 2), bl,
               (flag == 1) ? SendWho::ALL_SAMEMAP :
               (flag == 2) ? SendWho::AREA :
               (flag == 3) ? SendWho::SELF :
               SendWho::ALL_CLIENT);
}

/*==========================================
 * 復活する
 *------------------------------------------
 */
int clif_resurrection(struct block_list *bl, int type)
{
    unsigned char buf[16];

    nullpo_ret(bl);

    WBUFW(buf, 0) = 0x148;
    WBUFL(buf, 2) = bl->id;
    WBUFW(buf, 6) = type;

    clif_send(buf, clif_parse_func_table[0x148].len, bl, type == 1 ? SendWho::AREA : SendWho::AREA_WOS);

    return 0;
}

/*==========================================
 * Wisp/page is transmitted to the destination player
 *------------------------------------------
 */
int clif_wis_message(int fd, const char *nick, const char *mes, int mes_len)   // R 0097 <len>.w <nick>.24B <message>.?B
{
    WFIFOW(fd, 0) = 0x97;
    WFIFOW(fd, 2) = mes_len + 24 + 4;
    memcpy(WFIFOP(fd, 4), nick, 24);
    memcpy(WFIFOP(fd, 28), mes, mes_len);
    WFIFOSET(fd, WFIFOW(fd, 2));
    return 0;
}

/*==========================================
 * The transmission result of Wisp/page is transmitted to the source player
 *------------------------------------------
 */
int clif_wis_end(int fd, int flag) // R 0098 <type>.B: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target
{
    WFIFOW(fd, 0) = 0x98;
    WFIFOW(fd, 2) = flag;
    WFIFOSET(fd, clif_parse_func_table[0x98].len);
    return 0;
}

/*==========================================
 * パーティ作成完了
 * Relay the result of party creation.
 *
 * (R 00fa <flag>.B)
 *
 * flag:
 *  0 The party was created.
 *  1 The party name is invalid/taken.
 *  2 The character is already in a party.
 *------------------------------------------
 */
int clif_party_created(struct map_session_data *sd, int flag)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0xfa;
    WFIFOB(fd, 2) = flag;
    WFIFOSET(fd, clif_parse_func_table[0xfa].len);
    return 0;
}

/*==========================================
 * パーティ情報送信
 *------------------------------------------
 */
int clif_party_info(struct party *p, int fd)
{
    unsigned char buf[1024];
    int i, c;
    struct map_session_data *sd = NULL;

    nullpo_ret(p);

    WBUFW(buf, 0) = 0xfb;
    memcpy(WBUFP(buf, 4), p->name, 24);
    for (i = c = 0; i < MAX_PARTY; i++)
    {
        struct party_member *m = &p->member[i];
        if (m->account_id > 0)
        {
            if (sd == NULL)
                sd = m->sd;
            WBUFL(buf, 28 + c * 46) = m->account_id;
            memcpy(WBUFP(buf, 28 + c * 46 + 4), m->name, 24);
            memcpy(WBUFP(buf, 28 + c * 46 + 28), m->map, 16);
            WBUFB(buf, 28 + c * 46 + 44) = (m->leader) ? 0 : 1;
            WBUFB(buf, 28 + c * 46 + 45) = (m->online) ? 0 : 1;
            c++;
        }
    }
    WBUFW(buf, 2) = 28 + c * 46;
    if (fd >= 0)
    {                           // fdが設定されてるならそれに送る
        memcpy(WFIFOP(fd, 0), buf, WBUFW(buf, 2));
        WFIFOSET(fd, WFIFOW(fd, 2));
        return 9;
    }
    if (sd != NULL)
        clif_send(buf, WBUFW(buf, 2), &sd->bl, SendWho::PARTY);
    return 0;
}

/*==========================================
 * パーティ勧誘
 * Relay a party invitation.
 *
 * (R 00fe <sender_ID>.l <party_name>.24B)
 *------------------------------------------
 */
int clif_party_invite(struct map_session_data *sd,
                       struct map_session_data *tsd)
{
    int fd;
    struct party *p;

    nullpo_ret(sd);
    nullpo_ret(tsd);

    fd = tsd->fd;

    if (!(p = party_search(sd->status.party_id)))
        return 0;

    WFIFOW(fd, 0) = 0xfe;
    WFIFOL(fd, 2) = sd->status.account_id;
    memcpy(WFIFOP(fd, 6), p->name, 24);
    WFIFOSET(fd, clif_parse_func_table[0xfe].len);
    return 0;
}

/*==========================================
 * パーティ勧誘結果
 * Relay the response to a party invitation.
 *
 * (R 00fd <name>.24B <flag>.B)
 *
 * flag:
 *  0 The character is already in a party.
 *  1 The invitation was rejected.
 *  2 The invitation was accepted.
 *  3 The party is full.
 *  4 The character is in the same party.
 *------------------------------------------
 */
int clif_party_inviteack(struct map_session_data *sd, const char *nick, int flag)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0xfd;
    memcpy(WFIFOP(fd, 2), nick, 24);
    WFIFOB(fd, 26) = flag;
    WFIFOSET(fd, clif_parse_func_table[0xfd].len);
    return 0;
}

/*==========================================
 * パーティ設定送信
 * flag & 0x001=exp変更ミス
 *        0x010=item変更ミス
 *        0x100=一人にのみ送信
 *------------------------------------------
 */
int clif_party_option(struct party *p, struct map_session_data *sd, int flag)
{
    unsigned char buf[16];

    nullpo_ret(p);

//  if(battle_config.etc_log)
//      PRINTF("clif_party_option: %d %d %d\n",p->exp,p->item,flag);
    if (sd == NULL && flag == 0)
    {
        int i;
        for (i = 0; i < MAX_PARTY; i++)
            if ((sd = map_id2sd(p->member[i].account_id)) != NULL)
                break;
    }
    if (sd == NULL)
        return 0;
    WBUFW(buf, 0) = 0x101;
    WBUFW(buf, 2) = ((flag & 0x01) ? 2 : p->exp);
    WBUFW(buf, 4) = ((flag & 0x10) ? 2 : p->item);
    if (flag == 0)
        clif_send(buf, clif_parse_func_table[0x101].len, &sd->bl, SendWho::PARTY);
    else
    {
        memcpy(WFIFOP(sd->fd, 0), buf, clif_parse_func_table[0x101].len);
        WFIFOSET(sd->fd, clif_parse_func_table[0x101].len);
    }
    return 0;
}

/*==========================================
 * パーティ脱退(脱退前に呼ぶこと)
 *------------------------------------------
 */
int clif_party_leaved(struct party *p, struct map_session_data *sd,
                       int account_id, const char *name, int flag)
{
    unsigned char buf[64];
    int i;

    nullpo_ret(p);

    WBUFW(buf, 0) = 0x105;
    WBUFL(buf, 2) = account_id;
    memcpy(WBUFP(buf, 6), name, 24);
    WBUFB(buf, 30) = flag & 0x0f;

    if ((flag & 0xf0) == 0)
    {
        if (sd == NULL)
            for (i = 0; i < MAX_PARTY; i++)
                if ((sd = p->member[i].sd) != NULL)
                    break;
        if (sd != NULL)
            clif_send(buf, clif_parse_func_table[0x105].len, &sd->bl, SendWho::PARTY);
    }
    else if (sd != NULL)
    {
        memcpy(WFIFOP(sd->fd, 0), buf, clif_parse_func_table[0x105].len);
        WFIFOSET(sd->fd, clif_parse_func_table[0x105].len);
    }
    return 0;
}

/*==========================================
 * パーティメッセージ送信
 *------------------------------------------
 */
int clif_party_message(struct party *p, int account_id, const char *mes, int len)
{
    // always set, but clang is not smart enough
    struct map_session_data *sd = nullptr;
    int i;

    nullpo_ret(p);

    for (i = 0; i < MAX_PARTY; i++)
    {
        if ((sd = p->member[i].sd) != NULL)
            break;
    }
    if (sd != NULL)
    {
        unsigned char buf[1024];
        WBUFW(buf, 0) = 0x109;
        WBUFW(buf, 2) = len + 8;
        WBUFL(buf, 4) = account_id;
        memcpy(WBUFP(buf, 8), mes, len);
        clif_send(buf, len + 8, &sd->bl, SendWho::PARTY);
    }
    return 0;
}

/*==========================================
 * パーティ座標通知
 *------------------------------------------
 */
int clif_party_xy(struct party *, struct map_session_data *sd)
{
    unsigned char buf[16];

    nullpo_ret(sd);

    WBUFW(buf, 0) = 0x107;
    WBUFL(buf, 2) = sd->status.account_id;
    WBUFW(buf, 6) = sd->bl.x;
    WBUFW(buf, 8) = sd->bl.y;
    clif_send(buf, clif_parse_func_table[0x107].len, &sd->bl, SendWho::PARTY_SAMEMAP_WOS);
//  if(battle_config.etc_log)
//      PRINTF("clif_party_xy %d\n",sd->status.account_id);
    return 0;
}

/*==========================================
 * パーティHP通知
 *------------------------------------------
 */
int clif_party_hp(struct party *, struct map_session_data *sd)
{
    unsigned char buf[16];

    nullpo_ret(sd);

    WBUFW(buf, 0) = 0x106;
    WBUFL(buf, 2) = sd->status.account_id;
    WBUFW(buf, 6) = (sd->status.hp > 0x7fff) ? 0x7fff : sd->status.hp;
    WBUFW(buf, 8) =
        (sd->status.max_hp > 0x7fff) ? 0x7fff : sd->status.max_hp;
    clif_send(buf, clif_parse_func_table[0x106].len, &sd->bl, SendWho::PARTY_AREA_WOS);
//  if(battle_config.etc_log)
//      PRINTF("clif_party_hp %d\n",sd->status.account_id);
    return 0;
}

/*==========================================
 * 攻撃するために移動が必要
 *------------------------------------------
 */
int clif_movetoattack(struct map_session_data *sd, struct block_list *bl)
{
    int fd;

    nullpo_ret(sd);
    nullpo_ret(bl);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0x139;
    WFIFOL(fd, 2) = bl->id;
    WFIFOW(fd, 6) = bl->x;
    WFIFOW(fd, 8) = bl->y;
    WFIFOW(fd, 10) = sd->bl.x;
    WFIFOW(fd, 12) = sd->bl.y;
    WFIFOW(fd, 14) = sd->attackrange;
    WFIFOSET(fd, clif_parse_func_table[0x139].len);
    return 0;
}

/*==========================================
 * MVPエフェクト
 *------------------------------------------
 */
int clif_mvp_effect(struct map_session_data *sd)
{
    unsigned char buf[16];

    nullpo_ret(sd);

    WBUFW(buf, 0) = 0x10c;
    WBUFL(buf, 2) = sd->bl.id;
    clif_send(buf, clif_parse_func_table[0x10c].len, &sd->bl, SendWho::AREA);
    return 0;
}

/*==========================================
 * エモーション
 *------------------------------------------
 */
void clif_emotion(struct block_list *bl, int type)
{
    unsigned char buf[8];

    nullpo_retv(bl);

    WBUFW(buf, 0) = 0xc0;
    WBUFL(buf, 2) = bl->id;
    WBUFB(buf, 6) = type;
    clif_send(buf, clif_parse_func_table[0xc0].len, bl, SendWho::AREA);
}

static
void clif_emotion_towards(struct block_list *bl,
                                  struct block_list *target, int type)
{
    unsigned char buf[8];
    int len = clif_parse_func_table[0xc0].len;
    struct map_session_data *sd = (struct map_session_data *) target;

    nullpo_retv(bl);
    nullpo_retv(target);

    if (target->type != BL::PC)
        return;

    WBUFW(buf, 0) = 0xc0;
    WBUFL(buf, 2) = bl->id;
    WBUFB(buf, 6) = type;

    memcpy(WFIFOP(sd->fd, 0), buf, len);
    WFIFOSET(sd->fd, len);
}

/*==========================================
 * 座る
 *------------------------------------------
 */
void clif_sitting(int, struct map_session_data *sd)
{
    unsigned char buf[64];

    nullpo_retv(sd);

    WBUFW(buf, 0) = 0x8a;
    WBUFL(buf, 2) = sd->bl.id;
    WBUFB(buf, 26) = 2;
    clif_send(buf, clif_parse_func_table[0x8a].len, &sd->bl, SendWho::AREA);
}

/*==========================================
 *
 *------------------------------------------
 */
static
int clif_GM_kickack(struct map_session_data *sd, int id)
{
    int fd;

    nullpo_ret(sd);

    fd = sd->fd;
    WFIFOW(fd, 0) = 0xcd;
    WFIFOL(fd, 2) = id;
    WFIFOSET(fd, clif_parse_func_table[0xcd].len);
    return 0;
}

static
void clif_parse_QuitGame(int fd, struct map_session_data *sd);

int clif_GM_kick(struct map_session_data *sd, struct map_session_data *tsd,
                  int type)
{
    nullpo_ret(tsd);

    if (type)
        clif_GM_kickack(sd, tsd->status.account_id);
    tsd->opt1 = Opt1::ZERO;
    tsd->opt2 = Opt2::ZERO;
    clif_parse_QuitGame(tsd->fd, tsd);

    return 0;
}

// displaying special effects (npcs, weather, etc) [Valaris]
int clif_specialeffect(struct block_list *bl, int type, int flag)
{
    unsigned char buf[24];

    nullpo_ret(bl);

    memset(buf, 0, clif_parse_func_table[0x19b].len);

    WBUFW(buf, 0) = 0x19b;
    WBUFL(buf, 2) = bl->id;
    WBUFL(buf, 6) = type;

    if (flag == 2)
    {
        struct map_session_data *sd = NULL;
        int i;
        for (i = 0; i < fd_max; i++)
        {
            if (session[i] && (sd = (struct map_session_data *)session[i]->session_data) != NULL
                && sd->state.auth && sd->bl.m == bl->m)
                clif_specialeffect(&sd->bl, type, 1);
        }
    }

    else if (flag == 1)
        clif_send(buf, clif_parse_func_table[0x19b].len, bl, SendWho::SELF);
    else if (!flag)
        clif_send(buf, clif_parse_func_table[0x19b].len, bl, SendWho::AREA);

    return 0;

}

// ------------
// clif_parse_*
// ------------
// パケット読み取って色々操作
/*==========================================
 *
 *------------------------------------------
 */
static
void clif_parse_WantToConnection(int fd, struct map_session_data *sd)
{
    struct map_session_data *old_sd;
    int account_id;            // account_id in the packet

    if (sd)
    {
        if (battle_config.error_log)
            PRINTF("clif_parse_WantToConnection : invalid request?\n");
        return;
    }

    if (RFIFOW(fd, 0) == 0x72)
    {
        account_id = RFIFOL(fd, 2);
    }
    else
        return;                 // Not the auth packet

    WFIFOL(fd, 0) = account_id;
    WFIFOSET(fd, 4);

    // if same account already connected, we disconnect the 2 sessions
    if ((old_sd = map_id2sd(account_id)) != NULL)
    {
        clif_authfail_fd(fd, 2);   // same id
        clif_authfail_fd(old_sd->fd, 2);   // same id
        PRINTF("clif_parse_WantToConnection: Double connection for account %d (sessions: #%d (new) and #%d (old)).\n",
             account_id, fd, old_sd->fd);
    }
    else
    {
        CREATE(sd, struct map_session_data, 1);
        session[fd]->session_data = sd;
        sd->fd = fd;

        pc_setnewpc(sd, account_id, RFIFOL(fd, 6), RFIFOL(fd, 10),
                tick_t(static_cast<interval_t>(RFIFOL(fd, 14))),
                RFIFOB(fd, 18));

        map_addiddb(&sd->bl);

        chrif_authreq(sd);
    }

    return;
}

/*==========================================
 * 007d クライアント側マップ読み込み完了
 * map侵入時に必要なデータを全て送りつける
 *------------------------------------------
 */
static
void clif_parse_LoadEndAck(int, struct map_session_data *sd)
{
//  struct item_data* item;
    int i;
    nullpo_retv(sd);

    if (sd->bl.prev != NULL)
        return;

    // 接続ok時
    //clif_authok();
    if (sd->npc_id)
        npc_event_dequeue(sd);
    clif_skillinfoblock(sd);
    pc_checkitem(sd);
    //guild_info();

    // loadendack時
    // next exp
    clif_updatestatus(sd, SP::NEXTBASEEXP);
    clif_updatestatus(sd, SP::NEXTJOBEXP);
    // skill point
    clif_updatestatus(sd, SP::SKILLPOINT);
    // item
    clif_itemlist(sd);
    clif_equiplist(sd);
    // param all
    clif_initialstatus(sd);
    // party
    party_send_movemap(sd);
    // 119
    // 78

    if (battle_config.pc_invincible_time > 0)
    {
        pc_setinvincibletimer(sd, static_cast<interval_t>(battle_config.pc_invincible_time));
    }

    map_addblock(&sd->bl);     // ブロック登録
    clif_spawnpc(sd);          // spawn

    // weight max , now
    clif_updatestatus(sd, SP::MAXWEIGHT);
    clif_updatestatus(sd, SP::WEIGHT);

    // pvp
    if (!battle_config.pk_mode)
        sd->pvp_timer.cancel();

    if (map[sd->bl.m].flag.pvp)
    {
        if (!battle_config.pk_mode)
        {
            // remove pvp stuff for pk_mode [Valaris]
            sd->pvp_timer = Timer(gettick() + std::chrono::milliseconds(200),
                    std::bind(pc_calc_pvprank_timer, ph::_1, ph::_2,
                        sd->bl.id));
            sd->pvp_rank = 0;
            sd->pvp_lastusers = 0;
            sd->pvp_point = 5;
        }
    }
    else
    {
        // sd->pvp_timer = nullptr;
    }

    sd->state.connect_new = 0;

    // view equipment item
    clif_changelook(&sd->bl, LOOK::WEAPON, static_cast<uint16_t>(ItemLook::NONE));
    if (battle_config.save_clothcolor == 1 && sd->status.clothes_color > 0)
        clif_changelook(&sd->bl, LOOK::CLOTHES_COLOR,
                         sd->status.clothes_color);

    // option
    clif_changeoption(&sd->bl);
    for (i = 0; i < MAX_INVENTORY; i++)
    {
        if (bool(sd->status.inventory[i].equip)
            && bool(sd->status.inventory[i].equip & EPOS::WEAPON)
            && sd->status.inventory[i].broken == 1)
            skill_status_change_start(&sd->bl, StatusChange::SC_BROKNWEAPON, 0, interval_t::zero());
        if (bool(sd->status.inventory[i].equip)
            && bool(sd->status.inventory[i].equip & EPOS::MISC1)
            && sd->status.inventory[i].broken == 1)
            skill_status_change_start(&sd->bl, StatusChange::SC_BROKNARMOR, 0, interval_t::zero());
    }

//        clif_changelook_accessories(sd, NULL);

    map_foreachinarea(std::bind(clif_getareachar, ph::_1, sd), sd->bl.m, sd->bl.x - AREA_SIZE,
                       sd->bl.y - AREA_SIZE, sd->bl.x + AREA_SIZE,
                       sd->bl.y + AREA_SIZE, BL::NUL);
}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_parse_TickSend(int fd, struct map_session_data *sd)
{
    nullpo_retv(sd);

    sd->client_tick = tick_t(static_cast<interval_t>(RFIFOL(fd, 2)));
    sd->server_tick = gettick();
    clif_servertick(sd);
}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_parse_WalkToXY(int fd, struct map_session_data *sd)
{
    int x, y;

    nullpo_retv(sd);

    if (pc_isdead(sd))
    {
        clif_clearchar(&sd->bl, BeingRemoveWhy::DEAD);
        return;
    }

    if (sd->npc_id != 0 || sd->state.storage_open)
        return;

    if (sd->chatID)
        return;

    if (sd->canmove_tick > gettick())
        return;

    // ステータス異常やハイディング中(トンネルドライブ無)で動けない
    if (bool(sd->opt1) && sd->opt1 != (Opt1::_stone6))
        return;

    if (sd->invincible_timer)
        pc_delinvincibletimer(sd);

    pc_stopattack(sd);

    x = RFIFOB(fd, 2) * 4 + (RFIFOB(fd, 3) >> 6);
    y = ((RFIFOB(fd, 3) & 0x3f) << 4) + (RFIFOB(fd, 4) >> 4);
    pc_walktoxy(sd, x, y);

}

/*==========================================
 *
 *------------------------------------------
 */
void clif_parse_QuitGame(int fd, struct map_session_data *sd)
{
    tick_t tick = gettick();

    nullpo_retv(sd);

    WFIFOW(fd, 0) = 0x18b;
    if ((!pc_isdead(sd) && (sd->opt1 != Opt1::ZERO || sd->opt2 != Opt2::ZERO))
        || (tick < sd->canact_tick))
    {
        WFIFOW(fd, 2) = 1;
        WFIFOSET(fd, clif_parse_func_table[0x18b].len);
        return;
    }

    /*  Rovert's prevent logout option fixed [Valaris]  */
    if (!battle_config.prevent_logout
        || tick >= sd->canlog_tick + std::chrono::seconds(10))
    {
        clif_setwaitclose(fd);
        WFIFOW(fd, 2) = 0;
    }
    else
    {
        WFIFOW(fd, 2) = 1;
    }
    WFIFOSET(fd, clif_parse_func_table[0x18b].len);

}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_parse_GetCharNameRequest(int fd, struct map_session_data *sd)
{
    struct block_list *bl;
    int account_id;

    account_id = RFIFOL(fd, 2);
    bl = map_id2bl(account_id);
    if (bl == NULL)
        return;

    WFIFOW(fd, 0) = 0x95;
    WFIFOL(fd, 2) = account_id;

    switch (bl->type)
    {
        case BL::PC:
        {
            struct map_session_data *ssd = (struct map_session_data *) bl;

            nullpo_retv(ssd);

            if (ssd->state.shroud_active)
                memset(WFIFOP(fd, 6), 0, 24);
            else
                memcpy(WFIFOP(fd, 6), ssd->status.name, 24);
            WFIFOSET(fd, clif_parse_func_table[0x95].len);

            struct party *p = NULL;

            const char *party_name = "";

            int send = 0;

            if (ssd->status.party_id > 0 && (p = party_search(ssd->status.party_id)) != NULL)
            {
                party_name = p->name;
                send = 1;
            }

            if (send)
            {
                WFIFOW(fd, 0) = 0x195;
                WFIFOL(fd, 2) = account_id;
                memcpy(WFIFOP(fd, 6), party_name, 24);
                memcpy(WFIFOP(fd, 30), "", 24);
                memcpy(WFIFOP(fd, 54), "", 24);
                memcpy(WFIFOP(fd, 78), "", 24); // We send this value twice because the client expects it
                WFIFOSET(fd, clif_parse_func_table[0x195].len);

            }

            if (pc_isGM(sd) >= battle_config.hack_info_GM_level)
            {
                struct in_addr ip = ssd->ip;
                WFIFOW(fd, 0) = 0x20C;

                // Mask the IP using the char-server password
                if (battle_config.mask_ip_gms)
                    ip = MD5_ip(chrif_getpasswd(), ssd->ip);

                WFIFOL(fd, 2) = account_id;
                WFIFOL(fd, 6) = ip.s_addr;
                WFIFOSET(fd, clif_parse_func_table[0x20C].len);
             }

        }
            break;
        case BL::NPC:
            memcpy(WFIFOP(fd, 6), ((struct npc_data *) bl)->name, 24);
            {
                char *start = (char *)WFIFOP(fd, 6);
                char *end = strchr(start, '#');    // [fate] elim hashed out/invisible names for the client
                if (end)
                    while (*end)
                        *end++ = 0;

                // [fate] Elim preceding underscores for (hackish) name position fine-tuning
                while (*start == '_')
                    *start++ = ' ';
            }
            WFIFOSET(fd, clif_parse_func_table[0x95].len);
            break;
        case BL::MOB:
        {
            struct mob_data *md = (struct mob_data *) bl;

            nullpo_retv(md);

            memcpy(WFIFOP(fd, 6), md->name, 24);
            WFIFOSET(fd, clif_parse_func_table[0x95].len);
        }
            break;
        default:
            if (battle_config.error_log)
                PRINTF("clif_parse_GetCharNameRequest : bad type %d (%d)\n",
                        bl->type, account_id);
            break;
    }
}

/*==========================================
 * Validate and process transmission of a
 * global/public message.
 *
 * (S 008c <len>.w <message>.?B)
 *------------------------------------------
 */
static
void clif_parse_GlobalMessage(int fd, struct map_session_data *sd)
{
    int msg_len = RFIFOW(fd, 2) - 4; /* Header(2) + length(2). */
    size_t message_len = 0;
    // sometimes uint8_t
    char *buf = NULL;
    const char *message = NULL;   /* The message text only. */

    nullpo_retv(sd);

    if (!(buf = clif_validate_chat(sd, 2, &message, &message_len)))
    {
        clif_displaymessage(fd, "Your message could not be sent.");
        return;
    }

    if (is_atcommand(fd, sd, message, 0)) //チャット禁止
    {
        free(buf);
        return;
    }

    if (!magic_message(sd, buf, msg_len))
    {
        /* Don't send chat that results in an automatic ban. */
        if (tmw_CheckChatSpam(sd, message))
        {
            free(buf);
            clif_displaymessage(fd, "Your message could not be sent.");
            return;
        }

        /* It's not a spell/magic message, so send the message to others. */
        WBUFW(reinterpret_cast<uint8_t *>(buf), 0) = 0x8d;
        WBUFW(reinterpret_cast<uint8_t *>(buf), 2) = msg_len + 8;   /* Header(2) + length(2) + ID(4). */
        WBUFL(reinterpret_cast<uint8_t *>(buf), 4) = sd->bl.id;

        // evil multiuse buffer!
        clif_send((const uint8_t *)buf, msg_len + 8, &sd->bl,
                   sd->chatID ? SendWho::CHAT_WOS : SendWho::AREA_CHAT_WOC);
    }

    /* Send the message back to the speaker. */
    memcpy(WFIFOP(fd, 0), RFIFOP(fd, 0), RFIFOW(fd, 2));
    WFIFOW(fd, 0) = 0x8e;
    WFIFOSET(fd, WFIFOW(fd, 2));

    free(buf);
    return;
}

int clif_message(struct block_list *bl, const char *msg)
{
    unsigned short msg_len = strlen(msg) + 1;
    unsigned char buf[512];

    if (msg_len + 16 > 512)
        return 0;

    nullpo_ret(bl);

    WBUFW(buf, 0) = 0x8d;
    WBUFW(buf, 2) = msg_len + 8;
    WBUFL(buf, 4) = bl->id;
    memcpy(WBUFP(buf, 8), msg, msg_len);

    clif_send(buf, WBUFW(buf, 2), bl, SendWho::AREA);

    return 0;
}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_parse_ChangeDir(int fd, struct map_session_data *sd)
{
    unsigned char buf[64];

    nullpo_retv(sd);

    // RFIFOW(fd, 2) is always 0
    DIR dir = static_cast<DIR>(RFIFOB(fd, 4));
    if (dir >= DIR::COUNT)
        return;

    if (dir == sd->dir)
        return;

    pc_setdir(sd, dir);

    WBUFW(buf, 0) = 0x9c;
    WBUFL(buf, 2) = sd->bl.id;
    WBUFW(buf, 6) = 0;
    WBUFB(buf, 8) = static_cast<uint8_t>(dir);

    clif_send(buf, clif_parse_func_table[0x9c].len, &sd->bl, SendWho::AREA_WOS);

}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_parse_Emotion(int fd, struct map_session_data *sd)
{
    unsigned char buf[64];

    nullpo_retv(sd);

    if (battle_config.basic_skill_check == 0
        || pc_checkskill(sd, SkillID::NV_EMOTE) >= 1)
    {
        WBUFW(buf, 0) = 0xc0;
        WBUFL(buf, 2) = sd->bl.id;
        WBUFB(buf, 6) = RFIFOB(fd, 2);
        clif_send(buf, clif_parse_func_table[0xc0].len, &sd->bl, SendWho::AREA);
    }
    else
        clif_skill_fail(sd, SkillID::ONE, 0, 1);
}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_parse_HowManyConnections(int fd, struct map_session_data *)
{
    WFIFOW(fd, 0) = 0xc2;
    WFIFOL(fd, 2) = map_getusers();
    WFIFOSET(fd, clif_parse_func_table[0xc2].len);
}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_parse_ActionRequest(int fd, struct map_session_data *sd)
{
    unsigned char buf[64];
    int action_type, target_id;

    nullpo_retv(sd);

    if (pc_isdead(sd))
    {
        clif_clearchar(&sd->bl, BeingRemoveWhy::DEAD);
        return;
    }
    if (sd->npc_id != 0
        || bool(sd->opt1)
        || sd->state.storage_open)
        return;

    tick_t tick = gettick();

    pc_stop_walking(sd, 0);
    pc_stopattack(sd);

    target_id = RFIFOL(fd, 2);
    action_type = RFIFOB(fd, 6);

    switch (action_type)
    {
        case 0x00:             // once attack
        case 0x07:             // continuous attack
            if (bool(sd->status.option & Option::HIDE))
                return;
            if (!battle_config.sdelay_attack_enable)
            {
                if (tick < sd->canact_tick)
                {
                    clif_skill_fail(sd, SkillID::ONE, 4, 0);
                    return;
                }
            }
            if (sd->invincible_timer)
                pc_delinvincibletimer(sd);
            if (sd->attacktarget > 0)   // [Valaris]
                sd->attacktarget = 0;
            pc_attack(sd, target_id, action_type != 0);
            break;
        case 0x02:             // sitdown
            pc_stop_walking(sd, 1);
            skill_gangsterparadise(sd, 1); // ギャングスターパラダイス設定
            pc_setsit(sd);
            clif_sitting(fd, sd);
            break;
        case 0x03:             // standup
            skill_gangsterparadise(sd, 0); // ギャングスターパラダイス解除
            pc_setstand(sd);
            WBUFW(buf, 0) = 0x8a;
            WBUFL(buf, 2) = sd->bl.id;
            WBUFB(buf, 26) = 3;
            clif_send(buf, clif_parse_func_table[0x8a].len, &sd->bl, SendWho::AREA);
            break;
    }
}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_parse_Restart(int fd, struct map_session_data *sd)
{
    nullpo_retv(sd);

    switch (RFIFOB(fd, 2))
    {
        case 0x00:
            if (pc_isdead(sd))
            {
                pc_setstand(sd);
                pc_setrestartvalue(sd, 3);
                pc_setpos(sd, sd->status.save_point.map,
                           sd->status.save_point.x, sd->status.save_point.y,
                           BeingRemoveWhy::QUIT);
            }
            break;
        case 0x01:
            /*  Rovert's Prevent logout option - Fixed [Valaris]    */
            if (!battle_config.prevent_logout
                || gettick() >= sd->canlog_tick + std::chrono::seconds(10))
            {
                chrif_charselectreq(sd);
            }
            else
            {
                WFIFOW(fd, 0) = 0x18b;
                WFIFOW(fd, 2) = 1;

                WFIFOSET(fd, clif_parse_func_table[0x018b].len);
            }
            break;
    }
}

/*==========================================
 * Validate and process transmission of a
 * whisper/private message.
 *
 * (S 0096 <len>.w <nick>.24B <message>.?B)
 *
 * rewritten by [Yor], then partially by
 * [remoitnane]
 *------------------------------------------
 */
static
void clif_parse_Wis(int fd, struct map_session_data *sd)
{
    size_t message_len = 0;
    char *buf = NULL;
    const char *message = NULL;   /* The message text only. */
    struct map_session_data *dstsd = NULL;

    nullpo_retv(sd);

    if (!(buf = clif_validate_chat(sd, 1, &message, &message_len)))
    {
        clif_displaymessage(fd, "Your message could not be sent.");
        return;
    }

    if (is_atcommand(fd, sd, message, 0))
    {
        free(buf);
        return;
    }

    /* Don't send chat that results in an automatic ban. */
    if (tmw_CheckChatSpam(sd, message))
    {
        free(buf);
        clif_displaymessage(fd, "Your message could not be sent.");
        return;
    }

    /*
     * The player is not on this server. Only send the whisper if the name is
     * exactly the same, because if there are multiple map-servers and a name
     * conflict (for instance, "Test" versus "test"), the char-server must
     * settle the discrepancy.
     */
    if (!(dstsd = map_nick2sd((const char *)RFIFOP(fd, 4)))
            || strcmp(dstsd->status.name, (const char *)RFIFOP(fd, 4)) != 0)
        intif_wis_message(sd, (const char *)RFIFOP(fd, 4), message,  RFIFOW(fd, 2) - 28);
    else
    {
        /* Refuse messages addressed to self. */
        if (dstsd->fd == fd)
        {
            const char *mes = "You cannot page yourself.";
            clif_wis_message(fd, wisp_server_name, mes, strlen(mes) + 1);
        }
        else
        {
            /* The target is ignoring all whispers. */
            if (dstsd->ignoreAll == 1)
                /* Ignored by target. */
                clif_wis_end(fd, 2);
            else
            {
                int i;
                size_t end = sizeof(dstsd->ignore) / sizeof(dstsd->ignore[0]);

                /* See if the source player is being ignored. */
                for (i = 0; i < end; ++i)
                    if (strcmp(dstsd->ignore[i].name, sd->status.name) == 0)
                    {
                        /* Ignored by target. */
                        clif_wis_end(fd, 2);
                        break;
                    }

                /* The player is not being ignored. */
                if (i == end)
                {
                    clif_wis_message(dstsd->fd, sd->status.name, message,
                                      RFIFOW(fd, 2) - 28);
                    /* The whisper was sent successfully. */
                    clif_wis_end(fd, 0);
                }
            }
        }
    }

    free(buf);
}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_parse_TakeItem(int fd, struct map_session_data *sd)
{
    struct flooritem_data *fitem;
    int map_object_id;

    nullpo_retv(sd);

    map_object_id = RFIFOL(fd, 2);
    fitem = (struct flooritem_data *) map_id2bl(map_object_id);

    if (pc_isdead(sd))
    {
        clif_clearchar(&sd->bl, BeingRemoveWhy::DEAD);
        return;
    }

    if (sd->npc_id != 0
        || sd->opt1 != Opt1::ZERO)   //会話禁止
        return;

    if (fitem == NULL || fitem->bl.m != sd->bl.m)
        return;

    if (abs(sd->bl.x - fitem->bl.x) >= 2
        || abs(sd->bl.y - fitem->bl.y) >= 2)
        return;                 // too far away to pick up

    if (sd->state.shroud_active && sd->state.shroud_disappears_on_pickup)
        magic_unshroud(sd);

    pc_takeitem(sd, fitem);
}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_parse_DropItem(int fd, struct map_session_data *sd)
{
    int item_index, item_amount;

    nullpo_retv(sd);

    if (pc_isdead(sd))
    {
        clif_clearchar(&sd->bl, BeingRemoveWhy::DEAD);
        return;
    }
    if (map[sd->bl.m].flag.no_player_drops)
    {
        clif_displaymessage(sd->fd, "Can't drop items here.");
        return;
    }
    if (sd->npc_id != 0
        || sd->opt1 != Opt1::ZERO)
    {
        clif_displaymessage(sd->fd, "Can't drop items right now.");
        return;
    }

    item_index = RFIFOW(fd, 2) - 2;
    item_amount = RFIFOW(fd, 4);

    pc_dropitem(sd, item_index, item_amount);
}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_parse_UseItem(int fd, struct map_session_data *sd)
{
    nullpo_retv(sd);

    if (pc_isdead(sd))
    {
        clif_clearchar(&sd->bl, BeingRemoveWhy::DEAD);
        return;
    }
    if (sd->npc_id != 0
        || sd->opt1 != Opt1::ZERO)   //会話禁止
        return;

    if (sd->invincible_timer)
        pc_delinvincibletimer(sd);

    pc_useitem(sd, RFIFOW(fd, 2) - 2);
}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_parse_EquipItem(int fd, struct map_session_data *sd)
{
    int index;

    nullpo_retv(sd);

    if (pc_isdead(sd))
    {
        clif_clearchar(&sd->bl, BeingRemoveWhy::DEAD);
        return;
    }
    index = RFIFOW(fd, 2) - 2;
    if (sd->npc_id != 0)
        return;

    if (sd->status.inventory[index].identify != 1)
    {                           // 未鑑定
        // Bjorn: Auto-identify items when equipping them as there
        //  is no nice way to do this in the client yet.
        sd->status.inventory[index].identify = 1;
        //clif_equipitemack(sd,index,0,0);  // fail
        //return;
    }
    //ペット用装備であるかないか
    if (sd->inventory_data[index])
    {
        EPOS epos = EPOS(RFIFOW(fd, 4));
        if (sd->inventory_data[index]->type == ItemType::ARROW)
            // 矢を無理やり装備できるように(−−;
            epos = EPOS::ARROW;

        // Note: the EPOS argument to pc_equipitem is actually ignored
        pc_equipitem(sd, index, epos);
    }
}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_parse_UnequipItem(int fd, struct map_session_data *sd)
{
    int index;

    nullpo_retv(sd);

    if (pc_isdead(sd))
    {
        clif_clearchar(&sd->bl, BeingRemoveWhy::DEAD);
        return;
    }
    index = RFIFOW(fd, 2) - 2;
    if (sd->status.inventory[index].broken == 1 && sd->sc_data[StatusChange::SC_BROKNWEAPON].timer)
        skill_status_change_end(&sd->bl, StatusChange::SC_BROKNWEAPON, nullptr);
    if (sd->status.inventory[index].broken == 1 && sd->sc_data[StatusChange::SC_BROKNARMOR].timer)
        skill_status_change_end(&sd->bl, StatusChange::SC_BROKNARMOR, nullptr);

    if (sd->npc_id != 0
        || sd->opt1 != Opt1::ZERO)
        return;
    pc_unequipitem(sd, index, CalcStatus::NOW);
}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_parse_NpcClicked(int fd, struct map_session_data *sd)
{
    nullpo_retv(sd);

    if (pc_isdead(sd))
    {
        clif_clearchar(&sd->bl, BeingRemoveWhy::DEAD);
        return;
    }
    if (sd->npc_id != 0)
        return;
    npc_click(sd, RFIFOL(fd, 2));
}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_parse_NpcBuySellSelected(int fd, struct map_session_data *sd)
{
    npc_buysellsel(sd, RFIFOL(fd, 2), RFIFOB(fd, 6));
}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_parse_NpcBuyListSend(int fd, struct map_session_data *sd)
{
    int n = (RFIFOW(fd, 2) - 4) / 4;
    // really an array of pairs of uint16_t
    const uint16_t *item_list = static_cast<const uint16_t *>(RFIFOP(fd, 4));

    int fail = npc_buylist(sd, n, item_list);

    WFIFOW(fd, 0) = 0xca;
    WFIFOB(fd, 2) = fail;
    WFIFOSET(fd, clif_parse_func_table[0xca].len);
}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_parse_NpcSellListSend(int fd, struct map_session_data *sd)
{
    int n = (RFIFOW(fd, 2) - 4) / 4;
    // really an array of pairs of uint16_t
    const uint16_t *item_list = static_cast<const uint16_t *>(RFIFOP(fd, 4));

    int fail = npc_selllist(sd, n, item_list);

    WFIFOW(fd, 0) = 0xcb;
    WFIFOB(fd, 2) = fail;
    WFIFOSET(fd, clif_parse_func_table[0xcb].len);
}

/*==========================================
 * 取引要請を相手に送る
 *------------------------------------------
 */
static
void clif_parse_TradeRequest(int, struct map_session_data *sd)
{
    nullpo_retv(sd);

    if (battle_config.basic_skill_check == 0
        || pc_checkskill(sd, SkillID::NV_TRADE) >= 1)
    {
        trade_traderequest(sd, RFIFOL(sd->fd, 2));
    }
    else
        clif_skill_fail(sd, SkillID::ONE, 0, 0);
}

/*==========================================
 * 取引要請
 *------------------------------------------
 */
static
void clif_parse_TradeAck(int, struct map_session_data *sd)
{
    nullpo_retv(sd);

    trade_tradeack(sd, RFIFOB(sd->fd, 2));
}

/*==========================================
 * アイテム追加
 *------------------------------------------
 */
static
void clif_parse_TradeAddItem(int, struct map_session_data *sd)
{
    nullpo_retv(sd);

    trade_tradeadditem(sd, RFIFOW(sd->fd, 2), RFIFOL(sd->fd, 4));
}

/*==========================================
 * アイテム追加完了(ok押し)
 *------------------------------------------
 */
static
void clif_parse_TradeOk(int, struct map_session_data *sd)
{
    trade_tradeok(sd);
}

/*==========================================
 * 取引キャンセル
 *------------------------------------------
 */
static
void clif_parse_TradeCansel(int, struct map_session_data *sd)
{
    trade_tradecancel(sd);
}

/*==========================================
 * 取引許諾(trade押し)
 *------------------------------------------
 */
static
void clif_parse_TradeCommit(int, struct map_session_data *sd)
{
    trade_tradecommit(sd);
}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_parse_StopAttack(int, struct map_session_data *sd)
{
    pc_stopattack(sd);
}

/*==========================================
 * ステータスアップ
 *------------------------------------------
 */
static
void clif_parse_StatusUp(int fd, struct map_session_data *sd)
{
    pc_statusup(sd, SP(RFIFOW(fd, 2)));
}

/*==========================================
 * スキルレベルアップ
 *------------------------------------------
 */
static
void clif_parse_SkillUp(int fd, struct map_session_data *sd)
{
    pc_skillup(sd, SkillID(RFIFOW(fd, 2)));
}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_parse_NpcSelectMenu(int fd, struct map_session_data *sd)
{
    nullpo_retv(sd);

    sd->npc_menu = RFIFOB(fd, 6);
    map_scriptcont(sd, RFIFOL(fd, 2));
}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_parse_NpcNextClicked(int fd, struct map_session_data *sd)
{
    map_scriptcont(sd, RFIFOL(fd, 2));
}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_parse_NpcAmountInput(int fd, struct map_session_data *sd)
{
    nullpo_retv(sd);

    sd->npc_amount = RFIFOL(fd, 6);
    map_scriptcont(sd, RFIFOL(fd, 2));
}

/*==========================================
 * Process string-based input for an NPC.
 *
 * (S 01d5 <len>.w <npc_ID>.l <message>.?B)
 *------------------------------------------
 */
static
void clif_parse_NpcStringInput(int fd, struct map_session_data *sd)
{
    int len;
    nullpo_retv(sd);

    len = RFIFOW(fd, 2) - 8;

    /*
     * If we check for equal to 0, too, we'll freeze clients that send (or
     * claim to have sent) an "empty" message.
     */
    if (len < 0)
        return;

    if (len >= sizeof(sd->npc_str) - 1)
    {
        PRINTF("clif_parse_NpcStringInput(): Input string too long!\n");
        len = sizeof(sd->npc_str) - 1;
    }

    if (len > 0)
        strncpy(sd->npc_str, (const char *)RFIFOP(fd, 8), len);
    sd->npc_str[len] = '\0';

    map_scriptcont(sd, RFIFOL(fd, 4));
}

/*==========================================
 *
 *------------------------------------------
 */
static
void clif_parse_NpcCloseClicked(int fd, struct map_session_data *sd)
{
    map_scriptcont(sd, RFIFOL(fd, 2));
}

/*==========================================
 * カプラ倉庫へ入れる
 *------------------------------------------
 */
static
void clif_parse_MoveToKafra(int fd, struct map_session_data *sd)
{
    int item_index, item_amount;

    nullpo_retv(sd);

    item_index = RFIFOW(fd, 2) - 2;
    item_amount = RFIFOL(fd, 4);

    if ((sd->npc_id != 0 && !sd->npc_flags.storage) || sd->trade_partner != 0
        || !sd->state.storage_open)
        return;

    if (sd->state.storage_open)
        storage_storageadd(sd, item_index, item_amount);
}

/*==========================================
 * カプラ倉庫から出す
 *------------------------------------------
 */
static
void clif_parse_MoveFromKafra(int fd, struct map_session_data *sd)
{
    int item_index, item_amount;

    nullpo_retv(sd);

    item_index = RFIFOW(fd, 2) - 1;
    item_amount = RFIFOL(fd, 4);

    if ((sd->npc_id != 0 && !sd->npc_flags.storage) || sd->trade_partner != 0
        || !sd->state.storage_open)
        return;

    if (sd->state.storage_open)
        storage_storageget(sd, item_index, item_amount);
}

/*==========================================
 * カプラ倉庫を閉じる
 *------------------------------------------
 */
static
void clif_parse_CloseKafra(int, struct map_session_data *sd)
{
    nullpo_retv(sd);

    if (sd->state.storage_open)
        storage_storageclose(sd);
}

/*==========================================
 * パーティを作る
 * Process request to create a party.
 *
 * (S 00f9 <party_name>.24B)
 *------------------------------------------
 */
static
void clif_parse_CreateParty(int fd, struct map_session_data *sd)
{
    if (battle_config.basic_skill_check == 0
        || pc_checkskill(sd, SkillID::NV_PARTY) >= 2)
    {
        party_create(sd, (const char *)RFIFOP(fd, 2));
    }
    else
        clif_skill_fail(sd, SkillID::ONE, 0, 4);
}

/*==========================================
 * パーティに勧誘
 * Process invitation to join a party.
 *
 * (S 00fc <account_ID>.l)
 *------------------------------------------
 */
static
void clif_parse_PartyInvite(int fd, struct map_session_data *sd)
{
    party_invite(sd, RFIFOL(fd, 2));
}

/*==========================================
 * パーティ勧誘返答
 * Process reply to party invitation.
 *
 * (S 00ff <account_ID>.l <flag>.l)
 *------------------------------------------
 */
static
void clif_parse_ReplyPartyInvite(int fd, struct map_session_data *sd)
{
    if (battle_config.basic_skill_check == 0
        || pc_checkskill(sd, SkillID::NV_PARTY) >= 1)
    {
        party_reply_invite(sd, RFIFOL(fd, 2), RFIFOL(fd, 6));
    }
    else
    {
        party_reply_invite(sd, RFIFOL(fd, 2), 0);
        clif_skill_fail(sd, SkillID::ONE, 0, 4);
    }
}

/*==========================================
 * パーティ脱退要求
 *------------------------------------------
 */
static
void clif_parse_LeaveParty(int, struct map_session_data *sd)
{
    party_leave(sd);
}

/*==========================================
 * パーティ除名要求
 *------------------------------------------
 */
static
void clif_parse_RemovePartyMember(int fd, struct map_session_data *sd)
{
    party_removemember(sd, RFIFOL(fd, 2), (const char *)RFIFOP(fd, 6));
}

/*==========================================
 * パーティ設定変更要求
 *------------------------------------------
 */
static
void clif_parse_PartyChangeOption(int fd, struct map_session_data *sd)
{
    party_changeoption(sd, RFIFOW(fd, 2), RFIFOW(fd, 4));
}

/*==========================================
 * パーティメッセージ送信要求
 * Validate and process transmission of a
 * party message.
 *
 * (S 0108 <len>.w <message>.?B)
 *------------------------------------------
 */
static
void clif_parse_PartyMessage(int fd, struct map_session_data *sd)
{
    size_t message_len = 0;
    char *buf = NULL;
    const char *message = NULL;   /* The message text only. */

    nullpo_retv(sd);

    if (!(buf = clif_validate_chat(sd, 0, &message, &message_len)))
    {
        clif_displaymessage(fd, "Your message could not be sent.");
        return;
    }

    if (is_atcommand(fd, sd, message, 0)) //チャット禁止
    {
        free(buf);
        return;
    }

    /* Don't send chat that results in an automatic ban. */
    if (tmw_CheckChatSpam(sd, message))
    {
        free(buf);
        clif_displaymessage(fd, "Your message could not be sent.");
        return;
    }

    party_send_message(sd, message, RFIFOW(fd, 2) - 4);
    free(buf);
}

// 4144 wants this, but I don't like it ...
static
void clif_parse_PMIgnoreAll(int fd, struct map_session_data *sd)
{                               // Rewritten by [Yor]
    //PRINTF("Ignore all: state: %d\n", RFIFOB(fd,2));
    if (RFIFOB(fd, 2) == 0)
    {                           // S 00d0 <type>len.B: 00 (/exall) deny all speech, 01 (/inall) allow all speech
        WFIFOW(fd, 0) = 0x0d2; // R 00d2 <type>.B <fail>.B: type: 0: deny, 1: allow, fail: 0: success, 1: fail
        WFIFOB(fd, 2) = 0;
        if (sd->ignoreAll == 0)
        {
            sd->ignoreAll = 1;
            WFIFOB(fd, 3) = 0; // success
            WFIFOSET(fd, clif_parse_func_table[0x0d2].len);
        }
        else
        {
            WFIFOB(fd, 3) = 1; // fail
            WFIFOSET(fd, clif_parse_func_table[0x0d2].len);
            clif_wis_message(fd, wisp_server_name,
                              "You already block everyone.",
                              strlen("You already block everyone.") + 1);
        }
    }
    else
    {
        WFIFOW(fd, 0) = 0x0d2; // R 00d2 <type>.B <fail>.B: type: 0: deny, 1: allow, fail: 0: success, 1: fail
        WFIFOB(fd, 2) = 1;
        if (sd->ignoreAll == 1)
        {
            sd->ignoreAll = 0;
            WFIFOB(fd, 3) = 0; // success
            WFIFOSET(fd, clif_parse_func_table[0x0d2].len);
        }
        else
        {
            WFIFOB(fd, 3) = 1; // fail
            WFIFOSET(fd, clif_parse_func_table[0x0d2].len);
            clif_wis_message(fd, wisp_server_name,
                              "You already allow everyone.",
                              strlen("You already allow everyone.") + 1);
        }
    }

    return;
}

func_table clif_parse_func_table[0x0220] =
{
    {0,     10, NULL,                           },  // 0x0000
    {0,     0,  NULL,                           },  // 0x0001
    {0,     0,  NULL,                           },  // 0x0002
    {0,     0,  NULL,                           },  // 0x0003
    {0,     0,  NULL,                           },  // 0x0004
    {0,     0,  NULL,                           },  // 0x0005
    {0,     0,  NULL,                           },  // 0x0006
    {0,     0,  NULL,                           },  // 0x0007
    {0,     0,  NULL,                           },  // 0x0008
    {0,     0,  NULL,                           },  // 0x0009
    {0,     0,  NULL,                           },  // 0x000a
    {0,     0,  NULL,                           },  // 0x000b
    {0,     0,  NULL,                           },  // 0x000c
    {0,     0,  NULL,                           },  // 0x000d
    {0,     0,  NULL,                           },  // 0x000e
    {0,     0,  NULL,                           },  // 0x000f
    {0,     0,  NULL,                           },  // 0x0010
    {0,     0,  NULL,                           },  // 0x0011
    {0,     0,  NULL,                           },  // 0x0012
    {0,     0,  NULL,                           },  // 0x0013
    {0,     0,  NULL,                           },  // 0x0014
    {0,     0,  NULL,                           },  // 0x0015
    {0,     0,  NULL,                           },  // 0x0016
    {0,     0,  NULL,                           },  // 0x0017
    {0,     0,  NULL,                           },  // 0x0018
    {0,     0,  NULL,                           },  // 0x0019
    {0,     0,  NULL,                           },  // 0x001a
    {0,     0,  NULL,                           },  // 0x001b
    {0,     0,  NULL,                           },  // 0x001c
    {0,     0,  NULL,                           },  // 0x001d
    {0,     0,  NULL,                           },  // 0x001e
    {0,     0,  NULL,                           },  // 0x001f
    {0,     0,  NULL,                           },  // 0x0020
    {0,     0,  NULL,                           },  // 0x0021
    {0,     0,  NULL,                           },  // 0x0022
    {0,     0,  NULL,                           },  // 0x0023
    {0,     0,  NULL,                           },  // 0x0024
    {0,     0,  NULL,                           },  // 0x0025
    {0,     0,  NULL,                           },  // 0x0026
    {0,     0,  NULL,                           },  // 0x0027
    {0,     0,  NULL,                           },  // 0x0028
    {0,     0,  NULL,                           },  // 0x0029
    {0,     0,  NULL,                           },  // 0x002a
    {0,     0,  NULL,                           },  // 0x002b
    {0,     0,  NULL,                           },  // 0x002c
    {0,     0,  NULL,                           },  // 0x002d
    {0,     0,  NULL,                           },  // 0x002e
    {0,     0,  NULL,                           },  // 0x002f
    {0,     0,  NULL,                           },  // 0x0030
    {0,     0,  NULL,                           },  // 0x0031
    {0,     0,  NULL,                           },  // 0x0032
    {0,     0,  NULL,                           },  // 0x0033
    {0,     0,  NULL,                           },  // 0x0034
    {0,     0,  NULL,                           },  // 0x0035
    {0,     0,  NULL,                           },  // 0x0036
    {0,     0,  NULL,                           },  // 0x0037
    {0,     0,  NULL,                           },  // 0x0038
    {0,     0,  NULL,                           },  // 0x0039
    {0,     0,  NULL,                           },  // 0x003a
    {0,     0,  NULL,                           },  // 0x003b
    {0,     0,  NULL,                           },  // 0x003c
    {0,     0,  NULL,                           },  // 0x003d
    {0,     0,  NULL,                           },  // 0x003e
    {0,     0,  NULL,                           },  // 0x003f
    {0,     0,  NULL,                           },  // 0x0040
    {0,     0,  NULL,                           },  // 0x0041
    {0,     0,  NULL,                           },  // 0x0042
    {0,     0,  NULL,                           },  // 0x0043
    {0,     0,  NULL,                           },  // 0x0044
    {0,     0,  NULL,                           },  // 0x0045
    {0,     0,  NULL,                           },  // 0x0046
    {0,     0,  NULL,                           },  // 0x0047
    {0,     0,  NULL,                           },  // 0x0048
    {0,     0,  NULL,                           },  // 0x0049
    {0,     0,  NULL,                           },  // 0x004a
    {0,     0,  NULL,                           },  // 0x004b
    {0,     0,  NULL,                           },  // 0x004c
    {0,     0,  NULL,                           },  // 0x004d
    {0,     0,  NULL,                           },  // 0x004e
    {0,     0,  NULL,                           },  // 0x004f
    {0,     0,  NULL,                           },  // 0x0050
    {0,     0,  NULL,                           },  // 0x0051
    {0,     0,  NULL,                           },  // 0x0052
    {0,     0,  NULL,                           },  // 0x0053
    {0,     0,  NULL,                           },  // 0x0054
    {0,     0,  NULL,                           },  // 0x0055
    {0,     0,  NULL,                           },  // 0x0056
    {0,     0,  NULL,                           },  // 0x0057
    {0,     0,  NULL,                           },  // 0x0058
    {0,     0,  NULL,                           },  // 0x0059
    {0,     0,  NULL,                           },  // 0x005a
    {0,     0,  NULL,                           },  // 0x005b
    {0,     0,  NULL,                           },  // 0x005c
    {0,     0,  NULL,                           },  // 0x005d
    {0,     0,  NULL,                           },  // 0x005e
    {0,     0,  NULL,                           },  // 0x005f
    {0,     0,  NULL,                           },  // 0x0060
    {0,     0,  NULL,                           },  // 0x0061
    {0,     0,  NULL,                           },  // 0x0062
    {0,     VAR,NULL,                           },  // 0x0063
    {0,     55, NULL,                           },  // 0x0064
    {0,     17, NULL,                           },  // 0x0065
    {0,     3,  NULL,                           },  // 0x0066
    {0,     37, NULL,                           },  // 0x0067
    {0,     46, NULL,                           },  // 0x0068
    {0,     VAR,NULL,                           },  // 0x0069
    {0,     23, NULL,                           },  // 0x006a
    {0,     VAR,NULL,                           },  // 0x006b
    {0,     3,  NULL,                           },  // 0x006c
    {0,     108,NULL,                           },  // 0x006d
    {0,     3,  NULL,                           },  // 0x006e
    {0,     2,  NULL,                           },  // 0x006f
    {0,     3,  NULL,                           },  // 0x0070
    {0,     28, NULL,                           },  // 0x0071
    {0,     19, clif_parse_WantToConnection,    },  // 0x0072
    {0,     11, NULL,                           },  // 0x0073
    {0,     3,  NULL,                           },  // 0x0074
    {0,     VAR,NULL,                           },  // 0x0075
    {0,     9,  NULL,                           },  // 0x0076
    {0,     5,  NULL,                           },  // 0x0077
    {0,     54, NULL,                           },  // 0x0078
    {0,     53, NULL,                           },  // 0x0079
    {0,     58, NULL,                           },  // 0x007a
    {0,     60, NULL,                           },  // 0x007b
    {0,     41, NULL,                           },  // 0x007c
    {-1,    2,  clif_parse_LoadEndAck,          },  // 0x007d
    {0,     6,  clif_parse_TickSend,            },  // 0x007e
    {0,     6,  NULL,                           },  // 0x007f
    {0,     7,  NULL,                           },  // 0x0080
    {0,     3,  NULL,                           },  // 0x0081
    {0,     2,  NULL,                           },  // 0x0082
    {0,     2,  NULL,                           },  // 0x0083
    {0,     2,  NULL,                           },  // 0x0084
    {-1,    5,  clif_parse_WalkToXY,            },  // 0x0085 Walk code limits this on it's own
    {0,     16, NULL,                           },  // 0x0086
    {0,     12, NULL,                           },  // 0x0087
    {0,     10, NULL,                           },  // 0x0088
    {1000,  7,  clif_parse_ActionRequest,       },  // 0x0089 Special case - see below
    {0,     29, NULL,                           },  // 0x008a
    {0,     23, NULL,                           },  // 0x008b unknown... size 2 or 23?
    {300,   VAR,clif_parse_GlobalMessage,       },  // 0x008c
    {0,     VAR,NULL,                           },  // 0x008d
    {0,     VAR,NULL,                           },  // 0x008e
    {0,     0,  NULL,                           },  // 0x008f
    {500,   7,  clif_parse_NpcClicked,          },  // 0x0090
    {0,     22, NULL,                           },  // 0x0091
    {0,     28, NULL,                           },  // 0x0092
    {0,     2,  NULL,                           },  // 0x0093
    {-1,    6,  clif_parse_GetCharNameRequest,  },  // 0x0094
    {0,     30, NULL,                           },  // 0x0095
    {300,   VAR,clif_parse_Wis,                 },  // 0x0096
    {0,     VAR,NULL,                           },  // 0x0097
    {0,     3,  NULL,                           },  // 0x0098
    {300,   VAR,NULL,                           },  // 0x0099
    {0,     VAR,NULL,                           },  // 0x009a
    {-1,    5,  clif_parse_ChangeDir,           },  // 0x009b
    {0,     9,  NULL,                           },  // 0x009c
    {0,     17, NULL,                           },  // 0x009d
    {0,     17, NULL,                           },  // 0x009e
    {400,   6,  clif_parse_TakeItem,            },  // 0x009f
    {0,     23, NULL,                           },  // 0x00a0
    {0,     6,  NULL,                           },  // 0x00a1
    {50,    6,  clif_parse_DropItem,            },  // 0x00a2
    {0,     VAR,NULL,                           },  // 0x00a3
    {0,     VAR,NULL,                           },  // 0x00a4
    {0,     VAR,NULL,                           },  // 0x00a5
    {0,     VAR,NULL,                           },  // 0x00a6
    {0,     8,  clif_parse_UseItem,             },  // 0x00a7
    {0,     7,  NULL,                           },  // 0x00a8
    {-1,    6,  clif_parse_EquipItem,           },  // 0x00a9 Special case - outfit window (not implemented yet - needs to allow bursts)
    {0,     7,  NULL,                           },  // 0x00aa
    {-1,    4,  clif_parse_UnequipItem,         },  // 0x00ab Special case - outfit window (not implemented yet - needs to allow bursts)
    {0,     7,  NULL,                           },  // 0x00ac
    {0,     0,  NULL,                           },  // 0x00ad
    {0,     VAR,NULL,                           },  // 0x00ae
    {0,     6,  NULL,                           },  // 0x00af
    {0,     8,  NULL,                           },  // 0x00b0
    {0,     8,  NULL,                           },  // 0x00b1
    {0,     3,  clif_parse_Restart,             },  // 0x00b2
    {0,     3,  NULL,                           },  // 0x00b3
    {0,     VAR,NULL,                           },  // 0x00b4
    {0,     6,  NULL,                           },  // 0x00b5
    {0,     6,  NULL,                           },  // 0x00b6
    {0,     VAR,NULL,                           },  // 0x00b7
    {0,     7,  clif_parse_NpcSelectMenu,       },  // 0x00b8
    {-1,    6,  clif_parse_NpcNextClicked,      },  // 0x00b9
    {0,     2,  NULL,                           },  // 0x00ba
    {-1,    5,  clif_parse_StatusUp,            },  // 0x00bb People click this very quickly
    {0,     6,  NULL,                           },  // 0x00bc
    {0,     44, NULL,                           },  // 0x00bd
    {0,     5,  NULL,                           },  // 0x00be
    {1000,  3,  clif_parse_Emotion,             },  // 0x00bf
    {0,     7,  NULL,                           },  // 0x00c0
    {0,     2,  clif_parse_HowManyConnections,  },  // 0x00c1
    {0,     6,  NULL,                           },  // 0x00c2
    {0,     8,  NULL,                           },  // 0x00c3
    {0,     6,  NULL,                           },  // 0x00c4
    {0,     7,  clif_parse_NpcBuySellSelected,  },  // 0x00c5
    {0,     VAR,NULL,                           },  // 0x00c6
    {0,     VAR,NULL,                           },  // 0x00c7
    {-1,    VAR,clif_parse_NpcBuyListSend,      },  // 0x00c8
    {-1,    VAR,clif_parse_NpcSellListSend,     },  // 0x00c9 Selling multiple 1-slot items
    {0,     3,  NULL,                           },  // 0x00ca
    {0,     3,  NULL,                           },  // 0x00cb
    {0,     6,  NULL,                           },  // 0x00cc
    {0,     6,  NULL,                           },  // 0x00cd
    {0,     2,  NULL,                           },  // 0x00ce
    {0,     27, NULL,                           },  // 0x00cf
    {0,     3,  clif_parse_PMIgnoreAll,         },  // 0x00d0
    {0,     4,  NULL,                           },  // 0x00d1
    {0,     4,  NULL,                           },  // 0x00d2
    {0,     2,  NULL,                           },  // 0x00d3
    {0,     VAR,NULL,                           },  // 0x00d4
    {0,     VAR,NULL,                           },  // 0x00d5
    {0,     3,  NULL,                           },  // 0x00d6
    {0,     VAR,NULL,                           },  // 0x00d7
    {0,     6,  NULL,                           },  // 0x00d8
    {0,     14, NULL,                           },  // 0x00d9
    {0,     3,  NULL,                           },  // 0x00da
    {0,     VAR,NULL,                           },  // 0x00db
    {0,     28, NULL,                           },  // 0x00dc
    {0,     29, NULL,                           },  // 0x00dd
    {0,     VAR,NULL,                           },  // 0x00de
    {0,     VAR,NULL,                           },  // 0x00df
    {0,     30, NULL,                           },  // 0x00e0
    {0,     30, NULL,                           },  // 0x00e1
    {0,     26, NULL,                           },  // 0x00e2
    {0,     2,  NULL,                           },  // 0x00e3
    {2000,  6,  clif_parse_TradeRequest,        },  // 0x00e4
    {0,     26, NULL,                           },  // 0x00e5
    {0,     3,  clif_parse_TradeAck,            },  // 0x00e6
    {0,     3,  NULL,                           },  // 0x00e7
    {0,     8,  clif_parse_TradeAddItem,        },  // 0x00e8
    {0,     19, NULL,                           },  // 0x00e9
    {0,     5,  NULL,                           },  // 0x00ea
    {0,     2,  clif_parse_TradeOk,             },  // 0x00eb
    {0,     3,  NULL,                           },  // 0x00ec
    {0,     2,  clif_parse_TradeCansel,         },  // 0x00ed
    {0,     2,  NULL,                           },  // 0x00ee
    {0,     2,  clif_parse_TradeCommit,         },  // 0x00ef
    {0,     3,  NULL,                           },  // 0x00f0
    {0,     2,  NULL,                           },  // 0x00f1
    {0,     6,  NULL,                           },  // 0x00f2
    {-1,    8,  clif_parse_MoveToKafra,         },  // 0x00f3
    {0,     21, NULL,                           },  // 0x00f4
    {-1,    8,  clif_parse_MoveFromKafra,       },  // 0x00f5
    {0,     8,  NULL,                           },  // 0x00f6
    {0,     2,  clif_parse_CloseKafra,          },  // 0x00f7
    {0,     2,  NULL,                           },  // 0x00f8
    {2000,  26, clif_parse_CreateParty,         },  // 0x00f9
    {0,     3,  NULL,                           },  // 0x00fa
    {0,     VAR,NULL,                           },  // 0x00fb
    {2000,  6,  clif_parse_PartyInvite,         },  // 0x00fc
    {0,     27, NULL,                           },  // 0x00fd
    {0,     30, NULL,                           },  // 0x00fe
    {0,     10, clif_parse_ReplyPartyInvite,    },  // 0x00ff
    {0,     2,  clif_parse_LeaveParty,          },  // 0x0100
    {0,     6,  NULL,                           },  // 0x0101
    {0,     6,  clif_parse_PartyChangeOption,   },  // 0x0102
    {0,     30, clif_parse_RemovePartyMember,   },  // 0x0103
    {0,     79, NULL,                           },  // 0x0104
    {0,     31, NULL,                           },  // 0x0105
    {0,     10, NULL,                           },  // 0x0106
    {0,     10, NULL,                           },  // 0x0107
    {300,   VAR,clif_parse_PartyMessage,        },  // 0x0108
    {0,     VAR,NULL,                           },  // 0x0109
    {0,     4,  NULL,                           },  // 0x010a
    {0,     6,  NULL,                           },  // 0x010b
    {0,     6,  NULL,                           },  // 0x010c
    {0,     2,  NULL,                           },  // 0x010d
    {0,     11, NULL,                           },  // 0x010e
    {0,     VAR,NULL,                           },  // 0x010f
    {0,     10, NULL,                           },  // 0x0110
    {0,     39, NULL,                           },  // 0x0111
    {-1,    4,  clif_parse_SkillUp,             },  // 0x0112
    {0,     10, NULL,                           },  // 0x0113
    {0,     31, NULL,                           },  // 0x0114
    {0,     35, NULL,                           },  // 0x0115
    {0,     10, NULL,                           },  // 0x0116
    {0,     18, NULL,                           },  // 0x0117
    {0,     2,  clif_parse_StopAttack,          },  // 0x0118
    {0,     13, NULL,                           },  // 0x0119
    {0,     15, NULL,                           },  // 0x011a
    {0,     20, NULL,                           },  // 0x011b
    {0,     68, NULL,                           },  // 0x011c
    {0,     2,  NULL,                           },  // 0x011d
    {0,     3,  NULL,                           },  // 0x011e
    {0,     16, NULL,                           },  // 0x011f
    {0,     6,  NULL,                           },  // 0x0120
    {0,     14, NULL,                           },  // 0x0121
    {0,     VAR,NULL,                           },  // 0x0122
    {0,     VAR,NULL,                           },  // 0x0123
    {0,     21, NULL,                           },  // 0x0124
    {0,     8,  NULL,                           },  // 0x0125
    {0,     8,  NULL,                           },  // 0x0126
    {0,     8,  NULL,                           },  // 0x0127
    {0,     8,  NULL,                           },  // 0x0128
    {0,     8,  NULL,                           },  // 0x0129
    {0,     2,  NULL,                           },  // 0x012a
    {0,     2,  NULL,                           },  // 0x012b
    {0,     3,  NULL,                           },  // 0x012c
    {0,     4,  NULL,                           },  // 0x012d
    {0,     2,  NULL,                           },  // 0x012e
    {0,     VAR,NULL,                           },  // 0x012f
    {0,     6,  NULL,                           },  // 0x0130
    {0,     86, NULL,                           },  // 0x0131
    {0,     6,  NULL,                           },  // 0x0132
    {0,     VAR,NULL,                           },  // 0x0133
    {0,     VAR,NULL,                           },  // 0x0134
    {0,     7,  NULL,                           },  // 0x0135
    {0,     VAR,NULL,                           },  // 0x0136
    {0,     6,  NULL,                           },  // 0x0137
    {0,     3,  NULL,                           },  // 0x0138
    {0,     16, NULL,                           },  // 0x0139
    {0,     4,  NULL,                           },  // 0x013a
    {0,     4,  NULL,                           },  // 0x013b
    {0,     4,  NULL,                           },  // 0x013c
    {0,     6,  NULL,                           },  // 0x013d
    {0,     24, NULL,                           },  // 0x013e
    {0,     26, NULL,                           },  // 0x013f
    {0,     22, NULL,                           },  // 0x0140
    {0,     14, NULL,                           },  // 0x0141
    {0,     6,  NULL,                           },  // 0x0142
    {300,   10, clif_parse_NpcAmountInput,      },  // 0x0143
    {0,     23, NULL,                           },  // 0x0144
    {0,     19, NULL,                           },  // 0x0145
    {300,   6,  clif_parse_NpcCloseClicked,     },  // 0x0146
    {0,     39, NULL,                           },  // 0x0147
    {0,     8,  NULL,                           },  // 0x0148
    {0,     9,  NULL,                           },  // 0x0149
    {0,     6,  NULL,                           },  // 0x014a
    {0,     27, NULL,                           },  // 0x014b
    {0,     VAR,NULL,                           },  // 0x014c
    {0,     2,  NULL,                           },  // 0x014d
    {0,     6,  NULL,                           },  // 0x014e
    {0,     6,  NULL,                           },  // 0x014f
    {0,     110,NULL,                           },  // 0x0150
    {0,     6,  NULL,                           },  // 0x0151
    {0,     VAR,NULL,                           },  // 0x0152
    {0,     VAR,NULL,                           },  // 0x0153
    {0,     VAR,NULL,                           },  // 0x0154
    {0,     VAR,NULL,                           },  // 0x0155
    {0,     VAR,NULL,                           },  // 0x0156
    {0,     6,  NULL,                           },  // 0x0157
    {0,     VAR,NULL,                           },  // 0x0158
    {0,     54, NULL,                           },  // 0x0159
    {0,     66, NULL,                           },  // 0x015a
    {0,     54, NULL,                           },  // 0x015b
    {0,     90, NULL,                           },  // 0x015c
    {0,     42, NULL,                           },  // 0x015d
    {0,     6,  NULL,                           },  // 0x015e
    {0,     42, NULL,                           },  // 0x015f
    {0,     VAR,NULL,                           },  // 0x0160
    {0,     VAR,NULL,                           },  // 0x0161
    {0,     VAR,NULL,                           },  // 0x0162
    {0,     VAR,NULL,                           },  // 0x0163
    {0,     VAR,NULL,                           },  // 0x0164
    {0,     30, NULL,                           },  // 0x0165
    {0,     VAR,NULL,                           },  // 0x0166
    {0,     3,  NULL,                           },  // 0x0167
    {0,     14, NULL,                           },  // 0x0168
    {0,     3,  NULL,                           },  // 0x0169
    {0,     30, NULL,                           },  // 0x016a
    {0,     10, NULL,                           },  // 0x016b
    {0,     43, NULL,                           },  // 0x016c
    {0,     14, NULL,                           },  // 0x016d
    {0,     186,NULL,                           },  // 0x016e
    {0,     182,NULL,                           },  // 0x016f
    {0,     14, NULL,                           },  // 0x0170
    {0,     30, NULL,                           },  // 0x0171
    {0,     10, NULL,                           },  // 0x0172
    {0,     3,  NULL,                           },  // 0x0173
    {0,     VAR,NULL,                           },  // 0x0174
    {0,     6,  NULL,                           },  // 0x0175
    {0,     106,NULL,                           },  // 0x0176
    {0,     VAR,NULL,                           },  // 0x0177
    {0,     4,  NULL,                           },  // 0x0178
    {0,     5,  NULL,                           },  // 0x0179
    {0,     4,  NULL,                           },  // 0x017a
    {0,     VAR,NULL,                           },  // 0x017b
    {0,     6,  NULL,                           },  // 0x017c
    {0,     7,  NULL,                           },  // 0x017d
    {0,     VAR,NULL,                           },  // 0x017e
    {0,     VAR,NULL,                           },  // 0x017f
    {0,     6,  NULL,                           },  // 0x0180
    {0,     3,  NULL,                           },  // 0x0181
    {0,     106,NULL,                           },  // 0x0182
    {0,     10, NULL,                           },  // 0x0183
    {0,     10, NULL,                           },  // 0x0184
    {0,     34, NULL,                           },  // 0x0185
    {0,     0,  NULL,                           },  // 0x0186
    {0,     6,  NULL,                           },  // 0x0187
    {0,     8,  NULL,                           },  // 0x0188
    {0,     4,  NULL,                           },  // 0x0189
    {0,     4,  clif_parse_QuitGame,            },  // 0x018a
    {0,     4,  NULL,                           },  // 0x018b
    {0,     29, NULL,                           },  // 0x018c
    {0,     VAR,NULL,                           },  // 0x018d
    {0,     10, NULL,                           },  // 0x018e
    {0,     6,  NULL,                           },  // 0x018f
    {0,     90, NULL,                           },  // 0x0190
    {0,     86, NULL,                           },  // 0x0191
    {0,     24, NULL,                           },  // 0x0192
    {0,     6,  NULL,                           },  // 0x0193
    {0,     30, NULL,                           },  // 0x0194
    {0,     102,NULL,                           },  // 0x0195
    {0,     9,  NULL,                           },  // 0x0196
    {0,     4,  NULL,                           },  // 0x0197
    {0,     8,  NULL,                           },  // 0x0198
    {0,     4,  NULL,                           },  // 0x0199
    {0,     14, NULL,                           },  // 0x019a
    {0,     10, NULL,                           },  // 0x019b
    {0,     VAR,NULL,                           },  // 0x019c
    {300,   6,  NULL,                           },  // 0x019d
    {0,     2,  NULL,                           },  // 0x019e
    {0,     6,  NULL,                           },  // 0x019f
    {0,     3,  NULL,                           },  // 0x01a0
    {0,     3,  NULL,                           },  // 0x01a1
    {0,     35, NULL,                           },  // 0x01a2
    {0,     5,  NULL,                           },  // 0x01a3
    {0,     11, NULL,                           },  // 0x01a4
    {0,     26, NULL,                           },  // 0x01a5
    {0,     VAR,NULL,                           },  // 0x01a6
    {0,     4,  NULL,                           },  // 0x01a7
    {0,     4,  NULL,                           },  // 0x01a8
    {0,     6,  NULL,                           },  // 0x01a9
    {0,     10, NULL,                           },  // 0x01aa
    {0,     12, NULL,                           },  // 0x01ab
    {0,     6,  NULL,                           },  // 0x01ac
    {0,     VAR,NULL,                           },  // 0x01ad
    {0,     4,  NULL,                           },  // 0x01ae
    {0,     4,  NULL,                           },  // 0x01af
    {0,     11, NULL,                           },  // 0x01b0
    {0,     7,  NULL,                           },  // 0x01b1
    {0,     VAR,NULL,                           },  // 0x01b2
    {0,     67, NULL,                           },  // 0x01b3
    {0,     12, NULL,                           },  // 0x01b4
    {0,     18, NULL,                           },  // 0x01b5
    {0,     114,NULL,                           },  // 0x01b6
    {0,     6,  NULL,                           },  // 0x01b7
    {0,     3,  NULL,                           },  // 0x01b8
    {0,     6,  NULL,                           },  // 0x01b9
    {0,     26, NULL,                           },  // 0x01ba
    {0,     26, NULL,                           },  // 0x01bb
    {0,     26, NULL,                           },  // 0x01bc
    {0,     26, NULL,                           },  // 0x01bd
    {0,     2,  NULL,                           },  // 0x01be
    {0,     3,  NULL,                           },  // 0x01bf
    {0,     2,  NULL,                           },  // 0x01c0
    {0,     14, NULL,                           },  // 0x01c1
    {0,     10, NULL,                           },  // 0x01c2
    {0,     VAR,NULL,                           },  // 0x01c3
    {0,     22, NULL,                           },  // 0x01c4
    {0,     22, NULL,                           },  // 0x01c5
    {0,     4,  NULL,                           },  // 0x01c6
    {0,     2,  NULL,                           },  // 0x01c7
    {0,     13, NULL,                           },  // 0x01c8
    {0,     97, NULL,                           },  // 0x01c9
    {0,     0,  NULL,                           },  // 0x01ca
    {0,     9,  NULL,                           },  // 0x01cb
    {0,     9,  NULL,                           },  // 0x01cc
    {0,     30, NULL,                           },  // 0x01cd
    {0,     6,  NULL,                           },  // 0x01ce
    {0,     28, NULL,                           },  // 0x01cf
    {0,     8,  NULL,                           },  // 0x01d0
    {0,     14, NULL,                           },  // 0x01d1
    {0,     10, NULL,                           },  // 0x01d2
    {0,     35, NULL,                           },  // 0x01d3
    {0,     6,  NULL,                           },  // 0x01d4
    {300,   VAR,clif_parse_NpcStringInput,      },  // 0x01d5 - set to -1
    {0,     4,  NULL,                           },  // 0x01d6
    {0,     11, NULL,                           },  // 0x01d7
    {0,     54, NULL,                           },  // 0x01d8
    {0,     53, NULL,                           },  // 0x01d9
    {0,     60, NULL,                           },  // 0x01da
    {0,     2,  NULL,                           },  // 0x01db
    {0,     VAR,NULL,                           },  // 0x01dc
    {0,     47, NULL,                           },  // 0x01dd
    {0,     33, NULL,                           },  // 0x01de
    {0,     6,  NULL,                           },  // 0x01df
    {0,     30, NULL,                           },  // 0x01e0
    {0,     8,  NULL,                           },  // 0x01e1
    {0,     34, NULL,                           },  // 0x01e2
    {0,     14, NULL,                           },  // 0x01e3
    {0,     2,  NULL,                           },  // 0x01e4
    {0,     6,  NULL,                           },  // 0x01e5
    {0,     26, NULL,                           },  // 0x01e6
    {0,     2,  NULL,                           },  // 0x01e7
    {0,     28, NULL,                           },  // 0x01e8
    {0,     81, NULL,                           },  // 0x01e9
    {0,     6,  NULL,                           },  // 0x01ea
    {0,     10, NULL,                           },  // 0x01eb
    {0,     26, NULL,                           },  // 0x01ec
    {0,     2,  NULL,                           },  // 0x01ed
    {0,     VAR,NULL,                           },  // 0x01ee
    {0,     VAR,NULL,                           },  // 0x01ef
    {0,     VAR,NULL,                           },  // 0x01f0
    {0,     VAR,NULL,                           },  // 0x01f1
    {0,     20, NULL,                           },  // 0x01f2
    {0,     10, NULL,                           },  // 0x01f3
    {0,     32, NULL,                           },  // 0x01f4
    {0,     9,  NULL,                           },  // 0x01f5
    {0,     34, NULL,                           },  // 0x01f6
    {0,     14, NULL,                           },  // 0x01f7
    {0,     2,  NULL,                           },  // 0x01f8
    {0,     6,  NULL,                           },  // 0x01f9
    {0,     48, NULL,                           },  // 0x01fa
    {0,     56, NULL,                           },  // 0x01fb
    {0,     VAR,NULL,                           },  // 0x01fc
    {0,     4,  NULL,                           },  // 0x01fd
    {0,     5,  NULL,                           },  // 0x01fe
    {0,     10, NULL,                           },  // 0x01ff
    {0,     26, NULL,                           },  // 0x0200
    {0,     VAR,NULL,                           },  // 0x0201
    {0,     26, NULL,                           },  // 0x0202
    {0,     10, NULL,                           },  // 0x0203
    {0,     18, NULL,                           },  // 0x0204
    {0,     26, NULL,                           },  // 0x0205
    {0,     11, NULL,                           },  // 0x0206
    {0,     34, NULL,                           },  // 0x0207
    {0,     14, NULL,                           },  // 0x0208
    {0,     36, NULL,                           },  // 0x0209
    {0,     10, NULL,                           },  // 0x020a
    {0,     19, NULL,                           },  // 0x020b
    {0,     10, NULL,                           },  // 0x020c
    {0,     VAR,NULL,                           },  // 0x020d
    {0,     24, NULL,                           },  // 0x020e
    {0,     0,  NULL,                           },  // 0x020f
    {0,     0,  NULL,                           },  // 0x0210
    {0,     0,  NULL,                           },  // 0x0211
    {0,     0,  NULL,                           },  // 0x0212
    {0,     0,  NULL,                           },  // 0x0213
    {0,     0,  NULL,                           },  // 0x0214
    {0,     0,  NULL,                           },  // 0x0215
    {0,     0,  NULL,                           },  // 0x0216
    {0,     0,  NULL,                           },  // 0x0217
    {0,     0,  NULL,                           },  // 0x0218
    {0,     0,  NULL,                           },  // 0x0219
    {0,     0,  NULL,                           },  // 0x021a
    {0,     0,  NULL,                           },  // 0x021b
    {0,     0,  NULL,                           },  // 0x021c
    {0,     0,  NULL,                           },  // 0x021d
    {0,     0,  NULL,                           },  // 0x021e
    {0,     0,  NULL,                           },  // 0x021f
};

// Checks for packet flooding
static
int clif_check_packet_flood(int fd, int cmd)
{
    struct map_session_data *sd = (struct map_session_data *)session[fd]->session_data;
    tick_t tick = gettick();

    // sd will not be set if the client hasn't requested
    // WantToConnection yet. Do not apply flood logic to GMs
    // as approved bots (GMlvl1) should not have to work around
    // flood logic.
    if (!sd || pc_isGM(sd) || clif_parse_func_table[cmd].rate == static_cast<interval_t>(-1))
        return 0;

    // Timer has wrapped
    if (tick < sd->flood_rates[cmd])
    {
        sd->flood_rates[cmd] = tick;
        return 0;
    }

    // Default rate is 100ms
    interval_t rate = clif_parse_func_table[cmd].rate;
    if (rate == interval_t::zero())
        rate = std::chrono::milliseconds(100);

    // ActionRequest - attacks are allowed a faster rate than sit/stand
    if (cmd == 0x89)
    {
        int action_type = RFIFOB(fd, 6);
        if (action_type == 0x00 || action_type == 0x07)
            rate = std::chrono::milliseconds(20);
        else
            rate = std::chrono::seconds(1);
    }

// Restore this code when mana1.0 is released
#if 0
    // ChangeDir - only apply limit if not walking
    if (cmd == 0x9b)
    {
        // .29 clients spam this packet when walking into a blocked tile
        if (RFIFOB(fd, 4) == sd->dir || sd->walktimer != -1)
            return 0;

        rate = 500;
    }
#endif

    // They are flooding
    if (tick < sd->flood_rates[cmd] + rate)
    {
        TimeT now = TimeT::now();

        // If it's a nasty flood we log and possibly kick
        if (now > sd->packet_flood_reset_due)
        {
            sd->packet_flood_reset_due = static_cast<time_t>(now) + battle_config.packet_spam_threshold;
            sd->packet_flood_in = 0;
        }

        sd->packet_flood_in++;

        if (sd->packet_flood_in >= battle_config.packet_spam_flood)
        {
            PRINTF("packet flood detected from %s [0x%x]\n", sd->status.name, cmd);
            if (battle_config.packet_spam_kick)
            {
                session[fd]->eof = 1; // Kick
                return 1;
            }
            sd->packet_flood_in = 0;
        }

        return 1;
    }

    sd->flood_rates[cmd] = tick;
    return 0;
}

inline
void WARN_MALFORMED_MSG(struct map_session_data *sd, const char *msg)
{
    PRINTF("clif_validate_chat(): %s (ID %d) sent a malformed message: %s.\n",
            sd->status.name, sd->status.account_id, msg);
}
/**
 * Validate message integrity (inspired by upstream source (eAthena)).
 *
 * @param sd active session data
 * @param type message type:
 *  0 for when the sender's name is not included (party chat)
 *  1 for when the target's name is included (whisper chat)
 *  2 for when the sender's name is given ("sender : text", public/guild chat)
 * @param[out] message the message text (pointing within return value, or NULL)
 * @param[out] message_len the length of the actual text, excluding NUL
 * @return a dynamically allocated copy of the message, or NULL upon failure
 */
static
char *clif_validate_chat(struct map_session_data *sd, int type,
        const char **message, size_t *message_len)
{
    int fd;
    unsigned int buf_len;       /* Actual message length. */
    unsigned int msg_len;       /* Reported message length. */
    unsigned int min_len;       /* Minimum message length. */
    size_t name_len;            /* Sender's name length. */
    char *buf = NULL;           /* Copy of actual message data. */

    *message = NULL;
    *message_len = 0;

    nullpo_retr(NULL, sd);
    /*
     * Don't send chat in the period between the ban and the connection's
     * closure.
     */
    if (type < 0 || type > 2 || sd->auto_ban_info.in_progress)
        return NULL;

    fd = sd->fd;
    msg_len = RFIFOW(fd, 2) - 4;
    name_len = strlen(sd->status.name);
    /*
     * At least one character is required in all instances.
     * Notes for length checks:
     *
     * For all types, header (2) + length (2) is considered empty.
     * For type 1, the message must be longer than the maximum name length (24)
     *      to be valid.
     * For type 2, the message must be longer than the sender's name length
     *      plus the length of the separator (" : ").
     */
    min_len = (type == 1) ? 24 : (type == 2) ? name_len + 3 : 0;

    /* The player just sent the header (2) and length (2) words. */
    if (!msg_len)
    {
        WARN_MALFORMED_MSG(sd, "no message sent");
        return NULL;
    }

    /* The client sent (or claims to have sent) an empty message. */
    if (msg_len == min_len)
    {
        WARN_MALFORMED_MSG(sd, "empty message");
        return NULL;
    }

    /* The protocol specifies that the target must be 24 bytes long. */
    if (type == 1 && msg_len < min_len)
    {
        /* Disallow malformed messages. */
        clif_setwaitclose(fd);
        WARN_MALFORMED_MSG(sd, "illegal target name");
        return NULL;
    }

    const char *p = static_cast<const char *>((type != 1) ? RFIFOP(fd, 4) : RFIFOP(fd, 28));
    buf_len = (type == 1) ? msg_len - min_len: msg_len;

    /*
     * The client attempted to exceed the maximum message length.
     *
     * The conf suggests up to chat_maxline characters, after which the message
     * is truncated. But the previous behavior was to drop the message, so
     * we'll do that, too.
     */
    if (buf_len >= battle_config.chat_maxline)
    {
        WARN_MALFORMED_MSG(sd, "exceeded maximum message length");
        return NULL;
    }

    /* We're leaving an extra eight bytes for public/global chat, 1 for NUL. */
    buf_len += (type == 2) ? 8 + 1 : 1;

    buf = (char *) malloc(buf_len);
    memcpy((type != 2) ? buf : buf + 8, p,
            (type != 2) ? buf_len - 1 : buf_len - 8 - 1);
    buf[buf_len - 1] = '\0';
    p = (type != 2) ? buf : buf + 8;

    if (type != 2)
    {
        *message = buf;
        /* Don't count the NUL. */
        *message_len = buf_len - 1;
    }
    else
    {
        const char *pos = NULL;
        if (!(pos = strstr(p, " : "))
                || strncmp(p, sd->status.name, name_len)
                || pos - p != name_len)
        {
            free(buf);
            /* Disallow malformed/spoofed messages. */
            clif_setwaitclose(fd);
            WARN_MALFORMED_MSG(sd, "spoofed name/invalid format");
            return NULL;
        }
        /* Step beyond the separator. */
        *message = pos + 3;
        /* Don't count the sender's name, the extra eight bytes, or the NUL. */
        *message_len = buf_len - min_len - 8 - 1;
    }

    return buf;
}

/*==========================================
 * クライアントからのパケット解析
 * socket.cのdo_parsepacketから呼び出される
 *------------------------------------------
 */
static
void clif_parse(int fd)
{
    int packet_len = 0, cmd = 0;
    struct map_session_data *sd = (struct map_session_data *)session[fd]->session_data;

    if (!sd || (sd && !sd->state.auth))
    {
        if (RFIFOREST(fd) < 2)
        {                       // too small a packet disconnect
            session[fd]->eof = 1;
        }
        if (RFIFOW(fd, 0) != 0x72)
        {                       // first packet not auth, disconnect
            session[fd]->eof = 1;
        }
    }

    // 接続が切れてるので後始末
    if (!chrif_isconnect() || session[fd]->eof)
    {                           // char鯖に繋がってない間は接続禁止 (!chrif_isconnect())
        if (sd && sd->state.auth)
        {
            pc_logout(sd);
            clif_quitsave(fd, sd);
            if (sd->status.name != NULL)
                PRINTF("Player [%s] has logged off your server.\n", sd->status.name);  // Player logout display [Valaris]
            else
                PRINTF("Player with account [%d] has logged off your server.\n", sd->bl.id);   // Player logout display [Yor]
        }
        else if (sd)
        {                       // not authentified! (refused by char-server or disconnect before to be authentified)
            PRINTF("Player with account [%d] has logged off your server (not auth account).\n", sd->bl.id);    // Player logout display [Yor]
            map_deliddb(&sd->bl);  // account_id has been included in the DB before auth answer
        }
        if (fd)
            delete_session(fd);
        return;
    }

    if (RFIFOREST(fd) < 2)
        return;               // Too small (no packet number)

    cmd = RFIFOW(fd, 0);

    // 管理用パケット処理
    if (cmd >= 30000)
    {
        switch (cmd)
        {
            case 0x7530:       // Athena情報所得
                WFIFOW(fd, 0) = 0x7531;
                WFIFOB(fd, 2) = ATHENA_MAJOR_VERSION;
                WFIFOB(fd, 3) = ATHENA_MINOR_VERSION;
                WFIFOB(fd, 4) = ATHENA_REVISION;
                WFIFOB(fd, 5) = ATHENA_RELEASE_FLAG;
                WFIFOB(fd, 6) = ATHENA_OFFICIAL_FLAG;
                WFIFOB(fd, 7) = ATHENA_SERVER_MAP;
                WFIFOW(fd, 8) = ATHENA_MOD_VERSION;
                WFIFOSET(fd, 10);
                RFIFOSKIP(fd, 2);
                break;
            case 0x7532:       // 接続の切断
                session[fd]->eof = 1;
                break;
        }
        return;
    }
    else if (cmd >= 0x200)
        return;

    // パケット長を計算
    packet_len = clif_parse_func_table[cmd].len;
    if (packet_len == VAR)
    {
        if (RFIFOREST(fd) < 4)
        {
            return;           // Runt packet (variable length without a length sent)
        }
        packet_len = RFIFOW(fd, 2);
        if (packet_len < 4 || packet_len > 32768)
        {
            session[fd]->eof = 1;
            return;           // Runt packet (variable out of bounds)
        }
    }

    if (RFIFOREST(fd) < packet_len)
    {
        return;               // Runt packet (sent legnth is too small)
    }

    if (sd && sd->state.auth == 1 && sd->state.waitingdisconnect == 1)
    {                           // 切断待ちの場合パケットを処理しない

    }
    else if (clif_parse_func_table[cmd].func)
    {
        if (clif_check_packet_flood(fd, cmd))
        {
            // Flood triggered. Skip packet.
            RFIFOSKIP(sd->fd, packet_len);
            return;
        }

        clif_parse_func_table[cmd].func(fd, sd);
    }
    else
    {
        // 不明なパケット
        if (battle_config.error_log)
        {
            if (fd)
                PRINTF("\nclif_parse: session #%d, packet 0x%x, lenght %d\n",
                        fd, cmd, packet_len);
#ifdef DUMP_UNKNOWN_PACKET
            {
                int i;
                FILE *fp;
                char packet_txt[256] = "save/packet.txt";
                PRINTF("---- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F");
                for (i = 0; i < packet_len; i++)
                {
                    if ((i & 15) == 0)
                        PRINTF("\n%04X ", i);
                    PRINTF("%02X ", RFIFOB(fd, i));
                }
                if (sd && sd->state.auth)
                {
                    if (sd->status.name != NULL)
                        PRINTF("\nAccount ID %d, character ID %d, player name %s.\n",
                             sd->status.account_id, sd->status.char_id,
                             sd->status.name);
                    else
                        PRINTF("\nAccount ID %d.\n", sd->bl.id);
                }
                else if (sd)    // not authentified! (refused by char-server or disconnect before to be authentified)
                    PRINTF("\nAccount ID %d.\n", sd->bl.id);

                if ((fp = fopen_(packet_txt, "a")) == NULL)
                {
                    PRINTF("clif.c: cant write [%s] !!! data is lost !!!\n",
                            packet_txt);
                    return;
                }
                else
                {
                    timestamp_seconds_buffer now;
                    stamp_time(now);
                    if (sd && sd->state.auth)
                    {
                        if (sd->status.name != NULL)
                            FPRINTF(fp,
                                    "%s\nPlayer with account ID %d (character ID %d, player name %s) sent wrong packet:\n",
                                    now,
                                    sd->status.account_id,
                                    sd->status.char_id, sd->status.name);
                        else
                            FPRINTF(fp,
                                    "%s\nPlayer with account ID %d sent wrong packet:\n",
                                    now, sd->bl.id);
                    }
                    else if (sd)    // not authentified! (refused by char-server or disconnect before to be authentified)
                        FPRINTF(fp,
                                "%s\nPlayer with account ID %d sent wrong packet:\n",
                                now, sd->bl.id);

                    FPRINTF(fp,
                             "\t---- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F");
                    for (i = 0; i < packet_len; i++)
                    {
                        if ((i & 15) == 0)
                            FPRINTF(fp, "\n\t%04X ", i);
                        FPRINTF(fp, "%02X ", RFIFOB(fd, i));
                    }
                    FPRINTF(fp, "\n\n");
                    fclose_(fp);
                }
            }
#endif
        }
    }
    RFIFOSKIP(fd, packet_len);
}

/*==========================================
 *
 *------------------------------------------
 */
int do_init_clif (void)
{
    set_defaultparse(clif_parse);
    make_listen_port(map_port);

    return 0;
}