summaryrefslogblamecommitdiff
path: root/src/map/map.cpp
blob: 32df1fdac12cb7def36149f588819bad1021433a (plain) (tree)
1
2
3
4
5
6
7
8
9

                  
                     
                     
 
                  
                   
 
                  

                  
 
                                 



                                 
                             


                          
                             
                           
                                
                                

                               
                              


                        

                    
                    

                     
                                
                  
                  
                    
                 
                     
                    
                      
                    
 

                        
                                      
 
                                     
 
      
                                                   


                  
                  


               
      
                                       
 


              
                                           

                                                 
 
                                                     
                           
 

                                   
 
                                                                                                                 
 
      
                                 
 

                                                
                                                       

 





                                                                         
                                            

                                       

                                            
                        

              


                                            
                                                           

                                            
                      

                 

 


                        
                                             
 
                                                     

                             
                     
        
                                 
 
 
                            
 
                      

 
                             
 
                                 

                                 

                                                  
                           
     

 


                                                                 

                          

                                            

                                       
  
                                                       

                                            
                                         
 
                   
 
                    

                                    
                                                               


                 




                                                   

                 
                               
     
                                                                              
                                                     

                                      
                                                                     


        
                                                                           
                                                     

                                      
                                                                  
                                  
                       


             


                                            

                                                

                                            
                                         
 
                   
 
                                           
                     
     
                        
         
                                                                               
                                        
                                                                   



                 
                              
                          
 

                                           
                                                      
     
                                                                       
                                   
         
                                                                                                       


            
                                                                                                    



         
                                           
     

                       

             


                                            
                                                                    

                                            
                                                
 
               
                                   
                  
 
                                                       



                        

                                      
     
                                                                    

                    

                                         
     
                                           




                    

 
                                            


                                                

                                            
                                                                      
                     
                                       
                
 
                                              
 
           
               



               



                       
                                           
                                                                   
         
                                                                       
             

                                                                       
                 
                                                               
                                 

                                                            
                                              


                 
                                           
                                                                   
         
                                                                       
             

                                                                          
                 

                                                            
                                              



                 
                      
 
                                           
                        
                     


                                            


                                                         
  
                                                                          

                                            
                                                                          
                     

                                       
                
 
                                              
                                                                  
                                                         

                           

                                                                       


                       
                                 
                
                                 



                         
                                 
                
                                 




                   



                           
                                                                   
         
                                                                       
             

                                                                       
                 
                                                               
                                 

                                                            
                                              
                 

                                                     
                 
                                                               
                                 

                                                            
                                              





                 
                              




                   



                           
                                                                   
         
                                                                       
             

                                                                       
                 
                                                               
                                 

                                                                 
                                 



                                                          
                                              
                 

                                                     
                 
                                                               
                                 

                                                                  
                                 



                                                          
                                              





                 
                      
 
                                           
                        
                     




                                                                                   
  
                                                                      
                     
                     
                
 
                                              

                            
 
                                           
     

                                                               
         
                                                       
                         
                                               
                                      


         
                                           
     

                                                                  
         
                                               
                                      


         
                      
 
                                           
                        
                     


                                            

                                                               
  
                                                    

                                            
                                          
 
          
            
     
                                          




                                                                          
                       



                                    
                                          





                             
                     
             


                                            
                        
                                                    

                                            
                                        
 
                    
                 
 
                                    
     

                                                                
                                     
                
     
 
                             
                                          
                              
                         
 

                                  
 

                                                                
 
             


                                            


                                                   
  
                                                

                                            
                                  
 
                                          
 

                    
 
                                  
                                                                                                                                    
                                     
 
                                 
 
             


                                            
                                     


                                            
                                                                      
                
 
                                              
                                             
     

                       
         
                                                              
                         
                                         

         
 
                      
 
                                           
                                       
                     


                                            
                           
  

                                                          
  

                                        

                                            
                                                             
 

                                             
                                                    
             
                                   
                                  
                                          

 

                                                            
 
                                            
     

                         
                                                                      
                                                                                  
     

                                                                
 

                                                                  
                                                                                           


                                                                               


                                            
                                                       
  
                                        

                                            
                                                            
                                   
                                                                         
                                           
 
                                          
 
                          

                                                         
                 
 
                 




                                           
                            
                                     
                             
                                      
                            
                                     
 

                                        
     
                        


                 
                            

                  
                                               


                                                       
                                                


                                                        
                                               
                                                       
 
                                  
                                     






                                                                   
                                                   
                                                               
                               
 
                        
                              
 
                        

 
                                                        
                                   


                                             
 
                                                                             
                                   
 
     


                                                                                                                

     
                                                           

                                                                          

 
                                            
                                                     

                                            
                                               
 
                                                     
                  
                                   
 
                   
                  


                                            
                      

                                            
                                         
 
                    
 
                             


                                            
                         

                                            
                                         
 
                    
 
                                  


                                            
                        

                                            
                                                 
 
                    
 
                                     


                                            
                              
  
                                                          

                                            
                                            
 
                    
 
                                                        
                              
 
                                                                    
                                                            
 
                                                                                     
 
                                                                      
 

                                                           
 
                                                                             


                              
 
                         
 
                                             
 


                                  
                                                         
 
                                                                          
                                
                       
                                    
                                 
 
                             
 
                     
 
                                  

                                          


                                            
                                               

                                            
                                            
 

                                                                   






                                                                                                                             
                                
 
                                  
                                      

                                                    
  






                                                                                                   
                                
                                                      

         
 
                


                                            
                                  

                                            
                                
 
                                                 
 
                  
                          
                       
                          
                   

 


                                                           
      
                                                 
 





                                                                                              
                                                 
     
 
                

 
      
                                                             
 
                                        
     
                                                          


                     
 
                

 
      
                                                              
 
          

                                
                                                          


                     
 
                

 
                                                      
 
                                      

 
                                                                             
 
                                              

 
                                                     
 
                                            

 
                                                                             
 
                                               

 





                                            
                                                     
 
                                    
     



                                                                                                  
         
             
                                               
                                                             


             
                


                                            

                                                

                                            
                                      
 
                                   
                                                

                        
                           
 
              


                                            
                                                  

                                            
                                                   
 
          
           
                  

                                                           



                                    
                                                              

                  
                        
     
                     

     
                   
 
                   
              
                             



             
      
                        
 
              
 
                              
     



                                                                   
         
                                  
             



                                                                 
                 

                                                        
                 
                                    



                    
                                    


                                            
                                 

                                            
                                          
 
                                         
                                      

                                        


                                            
                                  

                                            
                                                               
 

                                         
                  
                                                     


                       

 




                                                             

                       









                                                     


                                            
                           

                                            
                                                        
 
                     
               
 
                             
 

                       
                           
     
                     

                                
     
                      
                            
                         
                        
                         

                                
     
                      
                             
                         
                         
                         

                                
     
                      
                            
                         
                        
                         

        
     
                      
                             
                         
                         
                         

               

 
         
                                            
                               

                                            
                                               
 
                                                           
                                   
                                 


                                            
                                

                                            
                                                       
 
                                                   
               
                              


                                            
                                         

                                            
                                                        
 
                                         
                   
     
                                    
                                              
                           


                          
                                                  



                    

                                  
                                                             
             

                                                          



                         

                     
                                                             




                              

 
                                            
                            

                                            
      
                                                      
 
                        



                                                 
 



                                                       
                        
                   
 
                          
                                       
 

                   
                                  
                              
                                                                      
                                                            
                                            
 


                                                    
 
                


                                            
                                       

                                            
      
                        
 

                         
 
                             
     
         
             

                                                                           
                 


                                                                  
                                   
                 

                          
             
         

     






                                                                           
             


                                            
                                 

                                            
      
                                
 
                           
     

                        
     
 
                                           



                                                          
                                         


                                            
                                 

                                            
                                
 
                         
     

                        

     
                                  

 
                                                   
 
      
                                            
      
                         

                       
 

                            
 

                    
                                                                                    







                                                
 
                            
 





                                 
     

 
      
                                  
 
                              
 
                                     


                               



                                                            
                                         
     

 
      
                                      
 
                      
 
                                           
                            
 
                                                                    
 
                            

 
                          
 

                     
 

                                                  
 
                               
     
                            
                             

     
                                           

 
                                            
                                    

                                            
      
                                    
 

                             
                             
                      
     
                                                                     
                
     
 
                 
                            
     

                   
                                             
                     
                           
         

                                                          


                                

                                                          



                                          
                            
                          
             
                                   


                                                           

                                                           

                                                                  
             
                



                                                   
                              







                                            
                            
                          
             





                                                           

                                                            
             
                



                                                   
                             






                                           

                                           


                                

                                           


                             
                               


                                
                               


                                       


                                                                   


                                  
                          


                                  
                          


                                    
                            


                                
                                   


                                  
                                


                                
                                

         



             
      
                                         
 
                    
 
                        
     
                    
                                                              
                  
                     
                                     
                  
                     
                                     
                  
                      
                                          
                  
                       
                                                  
                  
     


                                            
                        

                                            
                    
 
                             
     








                                                                       

     
                                    
                          
 
                    
 

                    


                       

                        

 

                                   
                                
                         
 
            

 
                                                







                                                                      

 



                                                        
                                    
 
          
 


                                                                   



                              

                                                  
                             





                                                 





                                                       

     


                                                   
                         
 
                     
 

                     










                                                                                                                        

                                   
                                                                       
 
                                                                                                
                            



             
                                                         
 
                                            



                 
                        
     
                     
                                          
                       
                                                 
                  
     
 
             
 
#include "map.hpp"

#include <sys/time.h>
#include <sys/wait.h>

#include <netdb.h>
#include <unistd.h>

#include <cassert>
#include <cstdlib>
#include <cstring>

#include "../strings/fstring.hpp"
#include "../strings/zstring.hpp"
#include "../strings/xstring.hpp"
#include "../strings/vstring.hpp"

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

#include "../common/core.hpp"
#include "../common/db.hpp"
#include "../common/extract.hpp"
#include "../common/random2.hpp"
#include "../common/nullpo.hpp"
#include "../common/socket.hpp"
#include "../common/timer.hpp"

#include "atcommand.hpp"
#include "battle.hpp"
#include "chrif.hpp"
#include "clif.hpp"
#include "grfio.hpp"
#include "itemdb.hpp"
#include "magic.hpp"
#include "magic-interpreter.hpp"
#include "mob.hpp"
#include "npc.hpp"
#include "party.hpp"
#include "pc.hpp"
#include "script.hpp"
#include "skill.hpp"
#include "storage.hpp"
#include "trade.hpp"

#include "../poison.hpp"

DMap<int, dumb_ptr<block_list>> id_db;

UPMap<MapName, map_abstract> maps_db;

static
DMap<CharName, dumb_ptr<map_session_data>> nick_db;

struct charid2nick
{
    CharName nick;
    int req_id;
};

static
Map<int, struct charid2nick> charid_db;

static
int users = 0;
static
dumb_ptr<block_list> object[MAX_FLOORITEM];
static
int first_free_object_id = 0, last_object_id = 0;

interval_t autosave_time = DEFAULT_AUTOSAVE_INTERVAL;
int save_settings = 0xFFFF;

FString motd_txt = "conf/motd.txt";
FString help_txt = "conf/help.txt";

CharName wisp_server_name = stringish<CharName>("Server");   // can be modified in char-server configuration file

static
void map_delmap(MapName mapname);

void SessionDeleter::operator()(SessionData *sd)
{
    really_delete1 static_cast<map_session_data *>(sd);
}

bool extract(XString str, NpcEvent *ev)
{
    XString mid;
    return extract(str, record<':'>(&ev->npc, &mid, &ev->label)) && !mid;
}

/*==========================================
 * 全map鯖総計での接続数設定
 * (char鯖から送られてくる)
 *------------------------------------------
 */
void map_setusers(int n)
{
    users = n;
}

/*==========================================
 * 全map鯖総計での接続数取得 (/wへの応答用)
 *------------------------------------------
 */
int map_getusers(void)
{
    return users;
}

static
int block_free_lock = 0;
static
std::vector<dumb_ptr<block_list>> block_free;

void MapBlockLock::freeblock(dumb_ptr<block_list> bl)
{
    if (block_free_lock == 0)
        bl.delete_();
    else
        block_free.push_back(bl);
}

MapBlockLock::MapBlockLock()
{
    ++block_free_lock;
}

MapBlockLock::~MapBlockLock()
{
    assert (block_free_lock > 0);
    if ((--block_free_lock) == 0)
    {
        for (dumb_ptr<block_list> bl : block_free)
            bl.delete_();
        block_free.clear();
    }
}

/// This is a dummy entry that is shared by all the linked lists,
/// so that any entry can unlink itself without worrying about
/// whether it was the the head of the list.
static
struct block_list bl_head;

/*==========================================
 * map[]のblock_listに追加
 * mobは数が多いので別リスト
 *
 * 既にlink済みかの確認が無い。危険かも
 *------------------------------------------
 */
int map_addblock(dumb_ptr<block_list> bl)
{
    nullpo_ret(bl);

    if (bl->bl_prev)
    {
        if (battle_config.error_log)
            PRINTF("map_addblock error : bl->bl_prev!=NULL\n");
        return 0;
    }

    map_local *m = bl->bl_m;
    int x = bl->bl_x;
    int y = bl->bl_y;
    if (!m ||
        x < 0 || x >= m->xs || y < 0 || y >= m->ys)
        return 1;

    if (bl->bl_type == BL::MOB)
    {
        bl->bl_next = m->blocks.ref(x / BLOCK_SIZE, y / BLOCK_SIZE).mobs_only;
        bl->bl_prev = dumb_ptr<block_list>(&bl_head);
        if (bl->bl_next)
            bl->bl_next->bl_prev = bl;
        m->blocks.ref(x / BLOCK_SIZE, y / BLOCK_SIZE).mobs_only = bl;
    }
    else
    {
        bl->bl_next = m->blocks.ref(x / BLOCK_SIZE, y / BLOCK_SIZE).normal;
        bl->bl_prev = dumb_ptr<block_list>(&bl_head);
        if (bl->bl_next)
            bl->bl_next->bl_prev = bl;
        m->blocks.ref(x / BLOCK_SIZE, y / BLOCK_SIZE).normal = bl;
        if (bl->bl_type == BL::PC)
            m->users++;
    }

    return 0;
}

/*==========================================
 * map[]のblock_listから外す
 * prevがNULLの場合listに繋がってない
 *------------------------------------------
 */
int map_delblock(dumb_ptr<block_list> bl)
{
    nullpo_ret(bl);

    // 既にblocklistから抜けている
    if (!bl->bl_prev)
    {
        if (bl->bl_next)
        {
            // prevがNULLでnextがNULLでないのは有ってはならない
            if (battle_config.error_log)
                PRINTF("map_delblock error : bl->bl_next!=NULL\n");
        }
        return 0;
    }

    if (bl->bl_type == BL::PC)
        bl->bl_m->users--;

    if (bl->bl_next)
        bl->bl_next->bl_prev = bl->bl_prev;
    if (bl->bl_prev == dumb_ptr<block_list>(&bl_head))
    {
        // リストの頭なので、map[]のblock_listを更新する
        if (bl->bl_type == BL::MOB)
        {
            bl->bl_m->blocks.ref(bl->bl_x / BLOCK_SIZE, bl->bl_y / BLOCK_SIZE).mobs_only = bl->bl_next;
        }
        else
        {
            bl->bl_m->blocks.ref(bl->bl_x / BLOCK_SIZE, bl->bl_y / BLOCK_SIZE).normal = bl->bl_next;
        }
    }
    else
    {
        bl->bl_prev->bl_next = bl->bl_next;
    }
    bl->bl_next = NULL;
    bl->bl_prev = NULL;

    return 0;
}

/*==========================================
 * セル上のPCとMOBの数を数える (グランドクロス用)
 *------------------------------------------
 */
int map_count_oncell(map_local *m, int x, int y)
{
    int bx, by;
    dumb_ptr<block_list> bl = NULL;
    int count = 0;

    if (x < 0 || y < 0 || (x >= m->xs) || (y >= m->ys))
        return 1;
    bx = x / BLOCK_SIZE;
    by = y / BLOCK_SIZE;

    bl = m->blocks.ref(bx, by).normal;
    for (; bl; bl = bl->bl_next)
    {
        if (bl->bl_x == x && bl->bl_y == y && bl->bl_type == BL::PC)
            count++;
    }
    bl = m->blocks.ref(bx, by).mobs_only;
    for (; bl; bl = bl->bl_next)
    {
        if (bl->bl_x == x && bl->bl_y == y)
            count++;
    }
    if (!count)
        count = 1;
    return count;
}

/*==========================================
 * map m (x0,y0)-(x1,y1)内の全objに対して
 * funcを呼ぶ
 * type!=0 ならその種類のみ
 *------------------------------------------
 */
void map_foreachinarea(std::function<void(dumb_ptr<block_list>)> func,
        map_local *m,
        int x0, int y0, int x1, int y1,
        BL type)
{
    std::vector<dumb_ptr<block_list>> bl_list;

    if (!m)
        return;
    if (x0 < 0)
        x0 = 0;
    if (y0 < 0)
        y0 = 0;
    if (x1 >= m->xs)
        x1 = m->xs - 1;
    if (y1 >= m->ys)
        y1 = m->ys - 1;
    if (type == BL::NUL || type != BL::MOB)
        for (int by = y0 / BLOCK_SIZE; by <= y1 / BLOCK_SIZE; by++)
        {
            for (int bx = x0 / BLOCK_SIZE; bx <= x1 / BLOCK_SIZE; bx++)
            {
                dumb_ptr<block_list> bl = m->blocks.ref(bx, by).normal;
                for (; bl; bl = bl->bl_next)
                {
                    if (type != BL::NUL && bl->bl_type != type)
                        continue;
                    if (bl->bl_x >= x0 && bl->bl_x <= x1
                        && bl->bl_y >= y0 && bl->bl_y <= y1)
                        bl_list.push_back(bl);
                }
            }
        }
    if (type == BL::NUL || type == BL::MOB)
        for (int by = y0 / BLOCK_SIZE; by <= y1 / BLOCK_SIZE; by++)
        {
            for (int bx = x0 / BLOCK_SIZE; bx <= x1 / BLOCK_SIZE; bx++)
            {
                dumb_ptr<block_list> bl = m->blocks.ref(bx, by).mobs_only;
                for (; bl; bl = bl->bl_next)
                {
                    if (bl->bl_x >= x0 && bl->bl_x <= x1
                        && bl->bl_y >= y0 && bl->bl_y <= y1)
                        bl_list.push_back(bl);
                }
            }
        }

    MapBlockLock lock;

    for (dumb_ptr<block_list> bl : bl_list)
        if (bl->bl_prev)
            func(bl);
}

/*==========================================
 * 矩形(x0,y0)-(x1,y1)が(dx,dy)移動した時の
 * 領域外になる領域(矩形かL字形)内のobjに
 * 対してfuncを呼ぶ
 *
 * dx,dyは-1,0,1のみとする(どんな値でもいいっぽい?)
 *------------------------------------------
 */
void map_foreachinmovearea(std::function<void(dumb_ptr<block_list>)> func,
        map_local *m,
        int x0, int y0, int x1, int y1,
        int dx, int dy,
        BL type)
{
    std::vector<dumb_ptr<block_list>> bl_list;
    // Note: the x0, y0, x1, y1 are bl.bl_x, bl.bl_y ± AREA_SIZE,
    // but only a small subset actually needs to be done.
    if (dx == 0 || dy == 0)
    {
        assert (dx || dy);
        // for aligned movement, only needs to check a rectangular area
        if (dx == 0)
        {
            if (dy < 0)
                y0 = y1 + dy + 1;
            else
                y1 = y0 + dy - 1;
        }
        else if (dy == 0)
        {
            if (dx < 0)
                x0 = x1 + dx + 1;
            else
                x1 = x0 + dx - 1;
        }
        if (x0 < 0)
            x0 = 0;
        if (y0 < 0)
            y0 = 0;
        if (x1 >= m->xs)
            x1 = m->xs - 1;
        if (y1 >= m->ys)
            y1 = m->ys - 1;
        for (int by = y0 / BLOCK_SIZE; by <= y1 / BLOCK_SIZE; by++)
        {
            for (int bx = x0 / BLOCK_SIZE; bx <= x1 / BLOCK_SIZE; bx++)
            {
                dumb_ptr<block_list> bl = m->blocks.ref(bx, by).normal;
                for (; bl; bl = bl->bl_next)
                {
                    if (type != BL::NUL && bl->bl_type != type)
                        continue;
                    if (bl->bl_x >= x0 && bl->bl_x <= x1
                        && bl->bl_y >= y0 && bl->bl_y <= y1)
                        bl_list.push_back(bl);
                }
                bl = m->blocks.ref(bx, by).mobs_only;
                for (; bl; bl = bl->bl_next)
                {
                    if (type != BL::NUL && bl->bl_type != type)
                        continue;
                    if (bl->bl_x >= x0 && bl->bl_x <= x1
                        && bl->bl_y >= y0 && bl->bl_y <= y1)
                        bl_list.push_back(bl);
                }
            }
        }
    }
    else
    {
        // L字領域の場合

        if (x0 < 0)
            x0 = 0;
        if (y0 < 0)
            y0 = 0;
        if (x1 >= m->xs)
            x1 = m->xs - 1;
        if (y1 >= m->ys)
            y1 = m->ys - 1;
        for (int by = y0 / BLOCK_SIZE; by <= y1 / BLOCK_SIZE; by++)
        {
            for (int bx = x0 / BLOCK_SIZE; bx <= x1 / BLOCK_SIZE; bx++)
            {
                dumb_ptr<block_list> bl = m->blocks.ref(bx, by).normal;
                for (; bl; bl = bl->bl_next)
                {
                    if (type != BL::NUL && bl->bl_type != type)
                        continue;
                    if (!(bl->bl_x >= x0 && bl->bl_x <= x1
                            && bl->bl_y >= y0 && bl->bl_y <= y1))
                        continue;
                    if ((dx > 0 && bl->bl_x < x0 + dx)
                        || (dx < 0 && bl->bl_x > x1 + dx)
                        || (dy > 0 && bl->bl_y < y0 + dy)
                        || (dy < 0 && bl->bl_y > y1 + dy))
                        bl_list.push_back(bl);
                }
                bl = m->blocks.ref(bx, by).mobs_only;
                for (; bl; bl = bl->bl_next)
                {
                    if (type != BL::NUL && bl->bl_type != type)
                        continue;
                    if (!(bl->bl_x >= x0 && bl->bl_x <= x1
                             && bl->bl_y >= y0 && bl->bl_y <= y1))
                        continue;
                    if ((dx > 0 && bl->bl_x < x0 + dx)
                        || (dx < 0 && bl->bl_x > x1 + dx)
                        || (dy > 0 && bl->bl_y < y0 + dy)
                        || (dy < 0 && bl->bl_y > y1 + dy))
                        bl_list.push_back(bl);
                }
            }
        }

    }

    MapBlockLock lock;

    for (dumb_ptr<block_list> bl : bl_list)
        if (bl->bl_prev)
            func(bl);
}

// -- moonsoul  (added map_foreachincell which is a rework of map_foreachinarea but
//           which only checks the exact single x/y passed to it rather than an
//           area radius - may be more useful in some instances)
//
void map_foreachincell(std::function<void(dumb_ptr<block_list>)> func,
        map_local *m,
        int x, int y,
        BL type)
{
    std::vector<dumb_ptr<block_list>> bl_list;
    int by = y / BLOCK_SIZE;
    int bx = x / BLOCK_SIZE;

    if (type == BL::NUL || type != BL::MOB)
    {
        dumb_ptr<block_list> bl = m->blocks.ref(bx, by).normal;
        for (; bl; bl = bl->bl_next)
        {
            if (type != BL::NUL && bl->bl_type != type)
                continue;
            if (bl->bl_x == x && bl->bl_y == y)
                bl_list.push_back(bl);
        }
    }

    if (type == BL::NUL || type == BL::MOB)
    {
        dumb_ptr<block_list> bl = m->blocks.ref(bx, by).mobs_only;
        for (; bl; bl = bl->bl_next)
        {
            if (bl->bl_x == x && bl->bl_y == y)
                bl_list.push_back(bl);
        }
    }

    MapBlockLock lock;

    for (dumb_ptr<block_list> bl : bl_list)
        if (bl->bl_prev)
            func(bl);
}

/*==========================================
 * 床アイテムやエフェクト用の一時obj割り当て
 * object[]への保存とid_db登録まで
 *
 * bl->bl_idもこの中で設定して問題無い?
 *------------------------------------------
 */
int map_addobject(dumb_ptr<block_list> bl)
{
    int i;
    if (!bl)
    {
        PRINTF("map_addobject nullpo?\n");
        return 0;
    }
    if (first_free_object_id < 2 || first_free_object_id >= MAX_FLOORITEM)
        first_free_object_id = 2;
    for (i = first_free_object_id; i < MAX_FLOORITEM; i++)
        if (!object[i])
            break;
    if (i >= MAX_FLOORITEM)
    {
        if (battle_config.error_log)
            PRINTF("no free object id\n");
        return 0;
    }
    first_free_object_id = i;
    if (last_object_id < i)
        last_object_id = i;
    object[i] = bl;
    id_db.put(i, bl);
    return i;
}

/*==========================================
 * 一時objectの解放
 *      map_delobjectのfreeしないバージョン
 *------------------------------------------
 */
int map_delobjectnofree(int id, BL type)
{
    if (!object[id])
        return 0;

    if (object[id]->bl_type != type)
    {
        FPRINTF(stderr, "Incorrect type: expected %d, got %d\n",
                type,
                object[id]->bl_type);
        abort();
    }

    map_delblock(object[id]);
    id_db.put(id, dumb_ptr<block_list>());
//  map_freeblock(object[id]);
    object[id] = nullptr;

    if (first_free_object_id > id)
        first_free_object_id = id;

    while (last_object_id > 2 && object[last_object_id] == NULL)
        last_object_id--;

    return 0;
}

/*==========================================
 * 一時objectの解放
 * block_listからの削除、id_dbからの削除
 * object dataのfree、object[]へのNULL代入
 *
 * addとの対称性が無いのが気になる
 *------------------------------------------
 */
int map_delobject(int id, BL type)
{
    dumb_ptr<block_list> obj = object[id];

    if (obj == NULL)
        return 0;

    map_delobjectnofree(id, type);
    if (obj->bl_type == BL::PC)     // [Fate] Not sure where else to put this... I'm not sure where delobject for PCs is called from
        pc_cleanup(obj->is_player());

    MapBlockLock::freeblock(obj);

    return 0;
}

/*==========================================
 * 全一時obj相手にfuncを呼ぶ
 *
 *------------------------------------------
 */
void map_foreachobject(std::function<void(dumb_ptr<block_list>)> func,
        BL type)
{
    std::vector<dumb_ptr<block_list>> bl_list;
    for (int i = 2; i <= last_object_id; i++)
    {
        if (!object[i])
            continue;
        {
            if (type != BL::NUL && object[i]->bl_type != type)
                continue;
            bl_list.push_back(object[i]);
        }
    }

    MapBlockLock lock;

    for (dumb_ptr<block_list> bl : bl_list)
        if (bl->bl_prev || bl->bl_next)
            func(bl);
}

/*==========================================
 * 床アイテムを消す
 *
 * data==0の時はtimerで消えた時
 * data!=0の時は拾う等で消えた時として動作
 *
 * 後者は、map_clearflooritem(id)へ
 * map.h内で#defineしてある
 *------------------------------------------
 */
void map_clearflooritem_timer(TimerData *tid, tick_t, int id)
{
    dumb_ptr<block_list> obj = object[id];
    assert (obj && obj->bl_type == BL::ITEM);
    dumb_ptr<flooritem_data> fitem = obj->is_item();
    if (!tid)
        fitem->cleartimer.cancel();
    clif_clearflooritem(fitem, 0);
    map_delobject(fitem->bl_id, BL::ITEM);
}

std::pair<uint16_t, uint16_t> map_randfreecell(map_local *m,
        uint16_t x, uint16_t y, uint16_t w, uint16_t h)
{
    for (int itr : random_::iterator(w * h))
    {
        int dx = itr % w;
        int dy = itr / w;
        if (!bool(read_gatp(m, x + dx, y + dy) & MapCell::UNWALKABLE))
            return {static_cast<uint16_t>(x + dx), static_cast<uint16_t>(y + dy)};
    }
    return {static_cast<uint16_t>(0), static_cast<uint16_t>(0)};
}

/// Return a randomly selected passable cell within a given range.
static
std::pair<uint16_t, uint16_t> map_searchrandfreecell(map_local *m, int x, int y, int range)
{
    int whole_range = 2 * range + 1;
    return map_randfreecell(m, x - range, y - range, whole_range, whole_range);
}

/*==========================================
 * (m,x,y)を中心に3x3以内に床アイテム設置
 *
 * item_dataはamount以外をcopyする
 *------------------------------------------
 */
int map_addflooritem_any(struct item *item_data, int amount,
        map_local *m, int x, int y,
        dumb_ptr<map_session_data> *owners, interval_t *owner_protection,
        interval_t lifetime, int dispersal)
{
    dumb_ptr<flooritem_data> fitem = NULL;

    nullpo_ret(item_data);
    auto xy = map_searchrandfreecell(m, x, y, dispersal);
    if (xy.first == 0 && xy.second == 0)
        return 0;

    fitem.new_();
    fitem->bl_type = BL::ITEM;
    fitem->bl_prev = fitem->bl_next = NULL;
    fitem->bl_m = m;
    fitem->bl_x = xy.first;
    fitem->bl_y = xy.second;
    fitem->first_get_id = 0;
    fitem->first_get_tick = tick_t();
    fitem->second_get_id = 0;
    fitem->second_get_tick = tick_t();
    fitem->third_get_id = 0;
    fitem->third_get_tick = tick_t();

    fitem->bl_id = map_addobject(fitem);
    if (fitem->bl_id == 0)
    {
        fitem.delete_();
        return 0;
    }

    tick_t tick = gettick();

    if (owners[0])
        fitem->first_get_id = owners[0]->bl_id;
    fitem->first_get_tick = tick + owner_protection[0];

    if (owners[1])
        fitem->second_get_id = owners[1]->bl_id;
    fitem->second_get_tick = tick + owner_protection[1];

    if (owners[2])
        fitem->third_get_id = owners[2]->bl_id;
    fitem->third_get_tick = tick + owner_protection[2];

    fitem->item_data = *item_data;
    fitem->item_data.amount = amount;
    // TODO - talk to 4144 about maybe removing this.
    // It has no effect on the server itself, it is visual only.
    // If it is desirable to prevent items from visibly stacking
    // on the ground, that can be done with client-side randomness.
    // Currently, it yields the numbers {3 6 9 12}.
    fitem->subx = random_::in(1, 4) * 3;
    fitem->suby = random_::in(1, 4) * 3;
    fitem->cleartimer = Timer(gettick() + lifetime,
            std::bind(map_clearflooritem_timer, ph::_1, ph::_2,
                fitem->bl_id));

    map_addblock(fitem);
    clif_dropflooritem(fitem);

    return fitem->bl_id;
}

int map_addflooritem(struct item *item_data, int amount,
        map_local *m, int x, int y,
        dumb_ptr<map_session_data> first_sd,
        dumb_ptr<map_session_data> second_sd,
        dumb_ptr<map_session_data> third_sd)
{
    dumb_ptr<map_session_data> owners[3] = { first_sd, second_sd, third_sd };
    interval_t owner_protection[3];

    {
        owner_protection[0] = static_cast<interval_t>(battle_config.item_first_get_time);
        owner_protection[1] = owner_protection[0] + static_cast<interval_t>(battle_config.item_second_get_time);
        owner_protection[2] = owner_protection[1] + static_cast<interval_t>(battle_config.item_third_get_time);
    }

    return map_addflooritem_any(item_data, amount, m, x, y,
            owners, owner_protection,
            static_cast<interval_t>(battle_config.flooritem_lifetime), 1);
}

/*==========================================
 * charid_dbへ追加(返信待ちがあれば返信)
 *------------------------------------------
 */
void map_addchariddb(int charid, CharName name)
{
    struct charid2nick *p = charid_db.search(charid);
    if (p == NULL)
        p = charid_db.init(charid);

    p->nick = name;
    p->req_id = 0;
}

/*==========================================
 * id_dbへblを追加
 *------------------------------------------
 */
void map_addiddb(dumb_ptr<block_list> bl)
{
    nullpo_retv(bl);

    id_db.put(bl->bl_id, bl);
}

/*==========================================
 * id_dbからblを削除
 *------------------------------------------
 */
void map_deliddb(dumb_ptr<block_list> bl)
{
    nullpo_retv(bl);

    id_db.put(bl->bl_id, nullptr);
}

/*==========================================
 * nick_dbへsdを追加
 *------------------------------------------
 */
void map_addnickdb(dumb_ptr<map_session_data> sd)
{
    nullpo_retv(sd);

    nick_db.put(sd->status.name, sd);
}

/*==========================================
 * PCのquit処理 map.c内分
 *
 * quit処理の主体が違うような気もしてきた
 *------------------------------------------
 */
void map_quit(dumb_ptr<map_session_data> sd)
{
    nullpo_retv(sd);

    if (sd->trade_partner)      // 取引を中断する
        trade_tradecancel(sd);

    if (sd->party_invite > 0)   // パーティ勧誘を拒否する
        party_reply_invite(sd, sd->party_invite_account, 0);

    party_send_logout(sd);     // パーティのログアウトメッセージ送信

    pc_cleareventtimer(sd);    // イベントタイマを破棄する

    skill_castcancel(sd, 0);  // 詠唱を中断する
    skill_stop_dancing(sd, 1);    // ダンス/演奏中断

    skill_status_change_clear(sd, 1); // ステータス異常を解除する
    pc_stop_walking(sd, 0);
    pc_stopattack(sd);
    pc_delinvincibletimer(sd);

    pc_calcstatus(sd, 4);

    clif_clearchar(sd, BeingRemoveWhy::QUIT);

    if (pc_isdead(sd))
        pc_setrestartvalue(sd, 2);
    pc_makesavestatus(sd);
    //クローンスキルで覚えたスキルは消す

    //The storage closing routines will save the char if needed. [Skotlex]
    if (!sd->state.storage_open)
        chrif_save(sd);
    else if (sd->state.storage_open)
        storage_storage_quit(sd);

    sd->npc_stackbuf.clear();

    map_delblock(sd);

    id_db.put(sd->bl_id, nullptr);
    nick_db.put(sd->status.name, nullptr);
    charid_db.erase(sd->status.char_id);
}

/*==========================================
 * id番号のPCを探す。居なければNULL
 *------------------------------------------
 */
dumb_ptr<map_session_data> map_id2sd(int id)
{
    // This is bogus.
    // However, there might be differences for de-auth'ed accounts.
// remove search from db, because:
// 1 - all players, npc, items and mob are in this db (to search, it's not speed, and search in session is more sure)
// 2 - DB seems not always correct. Sometimes, when a player disconnects, its id (account value) is not removed and structure
//     point to a memory area that is not more a session_data and value are incorrect (or out of available memory) -> crash
// replaced by searching in all session.
// by searching in session, we are sure that fd, session, and account exist.
/*
        dumb_ptr<block_list> bl;

        bl=numdb_search(id_db,id);
        if (bl && bl->bl_type==BL::PC)
                return (struct map_session_data*)bl;
        return NULL;
*/
    for (int i = 0; i < fd_max; i++)
    {
        if (!session[i])
            continue;
        if (session[i]->session_data)
        {
            map_session_data *sd = static_cast<map_session_data *>(session[i]->session_data.get());
            if (sd->bl_id == id)
                return dumb_ptr<map_session_data>(sd);
        }
    }

    return NULL;
}

/*==========================================
 * char_id番号の名前を探す
 *------------------------------------------
 */
CharName map_charid2nick(int id)
{
    struct charid2nick *p = charid_db.search(id);

    if (p == NULL)
        return CharName();
    if (p->req_id != 0)
        return CharName();
    return p->nick;
}

/*========================================*/
/* [Fate] Operations to iterate over active map sessions */

static
dumb_ptr<map_session_data> map_get_session(int i)
{
    if (i >= 0 && i < fd_max)
    {
        if (!session[i])
            return nullptr;
        map_session_data *d = static_cast<map_session_data *>(session[i]->session_data.get());
        if (d && d->state.auth)
            return dumb_ptr<map_session_data>(d);
    }

    return NULL;
}

static
dumb_ptr<map_session_data> map_get_session_forward(int start)
{
    for (int i = start; i < fd_max; i++)
    {
        dumb_ptr<map_session_data> d = map_get_session(i);
        if (d)
            return d;
    }

    return NULL;
}

static
dumb_ptr<map_session_data> map_get_session_backward(int start)
{
    int i;
    for (i = start; i >= 0; i--)
    {
        dumb_ptr<map_session_data> d = map_get_session(i);
        if (d)
            return d;
    }

    return NULL;
}

dumb_ptr<map_session_data> map_get_first_session(void)
{
    return map_get_session_forward(0);
}

dumb_ptr<map_session_data> map_get_next_session(dumb_ptr<map_session_data> d)
{
    return map_get_session_forward(d->fd + 1);
}

dumb_ptr<map_session_data> map_get_last_session(void)
{
    return map_get_session_backward(fd_max);
}

dumb_ptr<map_session_data> map_get_prev_session(dumb_ptr<map_session_data> d)
{
    return map_get_session_backward(d->fd - 1);
}

/*==========================================
 * Search session data from a nick name
 * (without sensitive case if necessary)
 * return map_session_data pointer or NULL
 *------------------------------------------
 */
dumb_ptr<map_session_data> map_nick2sd(CharName nick)
{
    for (int i = 0; i < fd_max; i++)
    {
        if (!session[i])
            continue;
        map_session_data *pl_sd = static_cast<map_session_data *>(session[i]->session_data.get());
        if (pl_sd && pl_sd->state.auth)
        {
            {
                if (pl_sd->status.name == nick)
                    return dumb_ptr<map_session_data>(pl_sd);
            }
        }
    }
    return NULL;
}

/*==========================================
 * id番号の物を探す
 * 一時objectの場合は配列を引くのみ
 *------------------------------------------
 */
dumb_ptr<block_list> map_id2bl(int id)
{
    dumb_ptr<block_list> bl = NULL;
    if (id < sizeof(object) / sizeof(object[0]))
        bl = object[id];
    else
        bl = id_db.get(id);

    return bl;
}

/*==========================================
 * map.npcへ追加 (warp等の領域持ちのみ)
 *------------------------------------------
 */
int map_addnpc(map_local *m, dumb_ptr<npc_data> nd)
{
    int i;
    if (!m)
        return -1;
    for (i = 0; i < m->npc_num && i < MAX_NPC_PER_MAP; i++)
        if (m->npc[i] == NULL)
            break;
    if (i == MAX_NPC_PER_MAP)
    {
        if (battle_config.error_log)
            PRINTF("too many NPCs in one map %s\n", m->name_);
        return -1;
    }
    if (i == m->npc_num)
    {
        m->npc_num++;
    }

    nullpo_ret(nd);

    m->npc[i] = nd;
    nd->n = i;
    id_db.put(nd->bl_id, nd);

    return i;
}

static
void map_removenpc(void)
{
    int n = 0;

    for (auto& mitp : maps_db)
    {
        if (!mitp.second->gat)
            continue;
        map_local *m = static_cast<map_local *>(mitp.second.get());
        for (int i = 0; i < m->npc_num && i < MAX_NPC_PER_MAP; i++)
        {
            if (m->npc[i] != NULL)
            {
                clif_clearchar(m->npc[i], BeingRemoveWhy::QUIT);
                map_delblock(m->npc[i]);
                id_db.put(m->npc[i]->bl_id, nullptr);
                if (m->npc[i]->npc_subtype == NpcSubtype::SCRIPT)
                {
//                    free(m->npc[i]->u.scr.script);
//                    free(m->npc[i]->u.scr.label_list);
                }
                m->npc[i].delete_();
                n++;
            }
        }
    }
    PRINTF("%d NPCs removed.\n", n);
}

/*==========================================
 * map名からmap番号へ変換
 *------------------------------------------
 */
map_local *map_mapname2mapid(MapName name)
{
    map_abstract *md = maps_db.get(name);
    if (md == NULL || md->gat == NULL)
        return nullptr;
    return static_cast<map_local *>(md);
}

/*==========================================
 * 他鯖map名からip,port変換
 *------------------------------------------
 */
int map_mapname2ipport(MapName name, IP4Address *ip, int *port)
{
    map_abstract *md = maps_db.get(name);
    if (md == NULL || md->gat)
        return -1;
    map_remote *mdos = static_cast<map_remote *>(md);
    *ip = mdos->ip;
    *port = mdos->port;
    return 0;
}

/// Check compatibility of directions.
/// Directions are compatible if they are at most 45° apart.
///
/// @return false if compatible, true if incompatible.
bool map_check_dir(const DIR s_dir, const DIR t_dir)
{
    if (s_dir == t_dir)
        return false;

    const uint8_t sdir = static_cast<uint8_t>(s_dir);
    const uint8_t tdir = static_cast<uint8_t>(t_dir);
    if ((sdir + 1) % 8 == tdir)
        return false;
    if (sdir == (tdir + 1) % 8)
        return false;

    return true;
}

/*==========================================
 * 彼我の方向を計算
 *------------------------------------------
 */
DIR map_calc_dir(dumb_ptr<block_list> src, int x, int y)
{
    DIR dir = DIR::S;
    int dx, dy;

    nullpo_retr(DIR::S, src);

    dx = x - src->bl_x;
    dy = y - src->bl_y;
    if (dx == 0 && dy == 0)
    {
        dir = DIR::S;
    }
    else if (dx >= 0 && dy >= 0)
    {
        dir = DIR::SE;
        if (dx * 3 - 1 < dy)
            dir = DIR::S;
        if (dx > dy * 3)
            dir = DIR::E;
    }
    else if (dx >= 0 && dy <= 0)
    {
        dir = DIR::NE;
        if (dx * 3 - 1 < -dy)
            dir = DIR::N;
        if (dx > -dy * 3)
            dir = DIR::E;
    }
    else if (dx <= 0 && dy <= 0)
    {
        dir = DIR::NW;
        if (dx * 3 + 1 > dy)
            dir = DIR::N;
        if (dx < dy * 3)
            dir = DIR::W;
    }
    else
    {
        dir = DIR::SW;
        if (-dx * 3 - 1 < dy)
            dir = DIR::S;
        if (-dx > dy * 3)
            dir = DIR::W;
    }
    return dir;
}

// gat系
/*==========================================
 * (m,x,y)の状態を調べる
 *------------------------------------------
 */
MapCell map_getcell(map_local *m, int x, int y)
{
    if (x < 0 || x >= m->xs - 1 || y < 0 || y >= m->ys - 1)
        return MapCell::UNWALKABLE;
    return m->gat[x + y * m->xs];
}

/*==========================================
 * (m,x,y)の状態をtにする
 *------------------------------------------
 */
void map_setcell(map_local *m, int x, int y, MapCell t)
{
    if (x < 0 || x >= m->xs || y < 0 || y >= m->ys)
        return;
    m->gat[x + y * m->xs] = t;
}

/*==========================================
 * 他鯖管理のマップをdbに追加
 *------------------------------------------
 */
int map_setipport(MapName name, IP4Address ip, int port)
{
    map_abstract *md = maps_db.get(name);
    if (md == NULL)
    {
        // not exist -> add new data
        auto mdos = make_unique<map_remote>();
        mdos->name_ = name;
        mdos->gat = NULL;
        mdos->ip = ip;
        mdos->port = port;
        maps_db.put(mdos->name_, std::move(mdos));
    }
    else
    {
        if (md->gat)
        {
            // local -> check data
            if (ip != clif_getip() || port != clif_getport())
            {
                PRINTF("from char server : %s -> %s:%d\n",
                        name, ip, port);
                return 1;
            }
        }
        else
        {
            // update
            map_remote *mdos = static_cast<map_remote *>(md);
            mdos->ip = ip;
            mdos->port = port;
        }
    }
    return 0;
}

/*==========================================
 * マップ1枚読み込み
 *------------------------------------------
 */
static
bool map_readmap(map_local *m, size_t num, MapName fn)
{
    // read & convert fn
    std::vector<uint8_t> gat_v = grfio_reads(fn);
    if (gat_v.empty())
        return false;
    size_t s = gat_v.size() - 4;

    int xs = m->xs = gat_v[0] | gat_v[1] << 8;
    int ys = m->ys = gat_v[2] | gat_v[3] << 8;
    PRINTF("\rLoading Maps [%zu/%zu]: %-30s  (%i, %i)",
            num, maps_db.size(),
            fn, xs, ys);
    fflush(stdout);

    assert (s == xs * ys);
    m->gat = make_unique<MapCell[]>(s);

    m->npc_num = 0;
    m->users = 0;
    really_memzero_this(&m->flag);
    if (battle_config.pk_mode)
        m->flag.pvp = 1;    // make all maps pvp for pk_mode [Valaris]
    MapCell *gat_m = reinterpret_cast<MapCell *>(&gat_v[4]);
    std::copy(gat_m, gat_m + s, &m->gat[0]);

    size_t bxs = (xs + BLOCK_SIZE - 1) / BLOCK_SIZE;
    size_t bys = (ys + BLOCK_SIZE - 1) / BLOCK_SIZE;
    m->blocks.reset(bxs, bys);

    return true;
}

/*==========================================
 * 全てのmapデータを読み込む
 *------------------------------------------
 */
static
int map_readallmap(void)
{
    int maps_removed = 0;
    int num = 0;

    for (auto& mit : maps_db)
    {
        {
            {
                map_local *ml = static_cast<map_local *>(mit.second.get());
                if (!map_readmap(ml, num, mit.first))
                {
                    // Can't remove while implicitly iterating,
                    // and I don't feel like explicitly iterating.
                    //map_delmap(map[i].name);
                    maps_removed++;
                }
                else
                    num++;
            }
        }
    }

    PRINTF("\rMaps Loaded: %-65zu\n", maps_db.size());
    if (maps_removed)
    {
        PRINTF("Cowardly refusing to keep going after removing %d maps.\n",
                maps_removed);
        exit(1);
    }
    return 0;
}

/*==========================================
 * 読み込むmapを追加する
 *------------------------------------------
 */
static
void map_addmap(MapName mapname)
{
    if (mapname == "clear")
    {
        maps_db.clear();
        return;
    }

    auto newmap = make_unique<map_local>();
    newmap->name_ = mapname;
    // novice challenge: figure out why this is necessary,
    // and why the previous version worked
    MapName name = newmap->name_;
    maps_db.put(name, std::move(newmap));
}

/*==========================================
 * 読み込むmapを削除する
 *------------------------------------------
 */
void map_delmap(MapName mapname)
{
    if (mapname == "all")
    {
        maps_db.clear();
        return;
    }

    maps_db.put(mapname, nullptr);
}

constexpr int LOGFILE_SECONDS_PER_CHUNK_SHIFT = 10;

static
std::unique_ptr<io::AppendFile> map_logfile;
static
FString map_logfile_name;
static
long map_logfile_index;

static
void map_close_logfile(void)
{
    if (map_logfile)
    {
        FString filename = STRPRINTF("%s.%ld", map_logfile_name, map_logfile_index);
        const char *args[] =
        {
            "gzip",
            "-f",
            filename.c_str(),
            NULL
        };
        char **argv = const_cast<char **>(args);

        map_logfile.reset();

        if (!fork())
        {
            execvp("gzip", argv);
            _exit(1);
        }
        wait(NULL);
    }
}

static
void map_start_logfile(long index)
{
    map_logfile_index = index;

    FString filename_buf = STRPRINTF(
            "%s.%ld",
            map_logfile_name,
            map_logfile_index);
    map_logfile = make_unique<io::AppendFile>(filename_buf);
    if (!map_logfile->is_open())
    {
        map_logfile.reset();
        perror(map_logfile_name.c_str());
    }
}

static
void map_set_logfile(FString filename)
{
    struct timeval tv;

    map_logfile_name = std::move(filename);
    gettimeofday(&tv, NULL);

    map_start_logfile(tv.tv_sec >> LOGFILE_SECONDS_PER_CHUNK_SHIFT);

    MAP_LOG("log-start v5");
}

void map_log(XString line)
{
    if (!map_logfile)
        return;

    time_t t = TimeT::now();
    long i = t >> LOGFILE_SECONDS_PER_CHUNK_SHIFT;

    if (i != map_logfile_index)
    {
        map_close_logfile();
        map_start_logfile(i);
    }

    log_with_timestamp(*map_logfile, line);
}

/*==========================================
 * 設定ファイルを読み込む
 *------------------------------------------
 */
static
int map_config_read(ZString cfgName)
{
    struct hostent *h = NULL;

    io::ReadFile in(cfgName);
    if (!in.is_open())
    {
        PRINTF("Map configuration file not found at: %s\n", cfgName);
        exit(1);
    }

    FString line;
    while (in.getline(line))
    {
        XString w1;
        ZString w2;
        if (!split_key_value(line, &w1, &w2))
            continue;
        if (w1 == "userid")
        {
            AccountName name = stringish<AccountName>(w2);
            chrif_setuserid(name);
        }
        else if (w1 == "passwd")
        {
            AccountPass pass = stringish<AccountPass>(w2);
            chrif_setpasswd(pass);
        }
        else if (w1 == "char_ip")
        {
            h = gethostbyname(w2.c_str());
            IP4Address w2ip;
            if (h != NULL)
            {
                w2ip = IP4Address({
                        static_cast<uint8_t>(h->h_addr[0]),
                        static_cast<uint8_t>(h->h_addr[1]),
                        static_cast<uint8_t>(h->h_addr[2]),
                        static_cast<uint8_t>(h->h_addr[3]),
                });
                PRINTF("Character server IP address : %s -> %s\n",
                        w2, w2ip);
            }
            else
            {
                PRINTF("Bad IP value: %s\n", line);
                abort();
            }
            chrif_setip(w2ip);
        }
        else if (w1 == "char_port")
        {
            chrif_setport(atoi(w2.c_str()));
        }
        else if (w1 == "map_ip")
        {
            h = gethostbyname(w2.c_str());
            IP4Address w2ip;
            if (h != NULL)
            {
                w2ip = IP4Address({
                        static_cast<uint8_t>(h->h_addr[0]),
                        static_cast<uint8_t>(h->h_addr[1]),
                        static_cast<uint8_t>(h->h_addr[2]),
                        static_cast<uint8_t>(h->h_addr[3]),
                });
                PRINTF("Map server IP address : %s -> %s\n",
                        w2, w2ip);
            }
            else
            {
                PRINTF("Bad IP value: %s\n", line);
                abort();
            }
            clif_setip(w2ip);
        }
        else if (w1 == "map_port")
        {
            clif_setport(atoi(w2.c_str()));
        }
        else if (w1 == "map")
        {
            MapName name = VString<15>(w2);
            map_addmap(name);
        }
        else if (w1 == "delmap")
        {
            MapName name = VString<15>(w2);
            map_delmap(name);
        }
        else if (w1 == "npc")
        {
            npc_addsrcfile(w2);
        }
        else if (w1 == "delnpc")
        {
            npc_delsrcfile(w2);
        }
        else if (w1 == "autosave_time")
        {
            autosave_time = std::chrono::seconds(atoi(w2.c_str()));
            if (autosave_time <= interval_t::zero())
                autosave_time = DEFAULT_AUTOSAVE_INTERVAL;
        }
        else if (w1 == "motd_txt")
        {
            motd_txt = w2;
        }
        else if (w1 == "help_txt")
        {
            help_txt = w2;
        }
        else if (w1 == "mapreg_txt")
        {
            mapreg_txt = w2;
        }
        else if (w1 == "gm_log")
        {
            gm_log = std::move(w2);
        }
        else if (w1 == "log_file")
        {
            map_set_logfile(w2);
        }
        else if (w1 == "import")
        {
            map_config_read(w2);
        }
    }

    return 0;
}

static
void cleanup_sub(dumb_ptr<block_list> bl)
{
    nullpo_retv(bl);

    switch (bl->bl_type)
    {
        case BL::PC:
            map_delblock(bl);  // There is something better...
            break;
        case BL::NPC:
            npc_delete(bl->is_npc());
            break;
        case BL::MOB:
            mob_delete(bl->is_mob());
            break;
        case BL::ITEM:
            map_clearflooritem(bl->bl_id);
            break;
        case BL::SPELL:
            spell_free_invocation(bl->is_spell());
            break;
    }
}

/*==========================================
 * map鯖終了時処理
 *------------------------------------------
 */
void term_func(void)
{
    for (auto& mit : maps_db)
    {
        if (!mit.second->gat)
            continue;
        map_local *map_id = static_cast<map_local *>(mit.second.get());

        map_foreachinarea(cleanup_sub,
                map_id,
                0, 0,
                map_id->xs, map_id->ys,
                BL::NUL);
    }

    for (int i = 0; i < fd_max; i++)
        delete_session(i);

    map_removenpc();

    maps_db.clear();

    do_final_script();
    do_final_itemdb();
    do_final_storage();

    map_close_logfile();
}

/// --help was passed
// FIXME this should produce output
static __attribute__((noreturn))
void map_helpscreen(void)
{
    exit(1);
}

int compare_item(struct item *a, struct item *b)
{
    return ((a->nameid == b->nameid) &&
            (a->identify == b->identify) &&
            (a->refine == b->refine) &&
            (a->attribute == b->attribute) &&
            (a->card[0] == b->card[0]) &&
            (a->card[1] == b->card[1]) &&
            (a->card[2] == b->card[2]) && (a->card[3] == b->card[3]));
}

/*======================================================
 * Map-Server Init and Command-line Arguments [Valaris]
 *------------------------------------------------------
 */
int do_init(int argc, ZString *argv)
{
    int i;

    ZString MAP_CONF_NAME = "conf/map_athena.conf";
    ZString BATTLE_CONF_FILENAME = "conf/battle_athena.conf";
    ZString ATCOMMAND_CONF_FILENAME = "conf/atcommand_athena.conf";

    for (i = 1; i < argc; i++)
    {

        if (argv[i] == "--help" || argv[i] == "-h"
            || argv[i] == "-?" || argv[i] == "/?")
            map_helpscreen();
        else if (argv[i] == "--map_config")
            MAP_CONF_NAME = argv[++i];
        else if (argv[i] == "--battle_config")
            BATTLE_CONF_FILENAME = argv[++i];
        else if (argv[i] == "--atcommand_config")
            ATCOMMAND_CONF_FILENAME = argv[++i];
        else if (argv[i] == "--write-atcommand-config")
        {
            ZString filename = argv[++i];
            atcommand_config_write(filename);
            exit(0);
        }
    }

    map_config_read(MAP_CONF_NAME);
    battle_config_read(BATTLE_CONF_FILENAME);
    atcommand_config_read(ATCOMMAND_CONF_FILENAME);
    script_config_read();

    map_readallmap();

    do_init_chrif ();
    do_init_clif ();
    do_init_itemdb();
    do_init_mob();             // npcの初期化時内でmob_spawnして、mob_dbを参照するのでinit_npcより先
    do_init_script();
    do_init_npc();
    do_init_pc();
    do_init_party();
    do_init_storage();
    do_init_skill();
    do_init_magic();

    npc_event_do_oninit();     // npcのOnInitイベント実行

    if (battle_config.pk_mode == 1)
        PRINTF("The server is running in \033[1;31mPK Mode\033[0m.\n");

    PRINTF("The map-server is \033[1;32mready\033[0m (Server is listening on the port %d).\n\n",
            clif_getport());

    return 0;
}

int map_scriptcont(dumb_ptr<map_session_data> sd, int id)
{
    dumb_ptr<block_list> bl = map_id2bl(id);

    if (!bl)
        return 0;

    switch (bl->bl_type)
    {
        case BL::NPC:
            return npc_scriptcont(sd, id);
        case BL::SPELL:
            spell_execute_script(bl->is_spell());
            break;
    }

    return 0;
}