/**************************************************************************
 *    PNG Loading, Coordinate Based Worldmap System for ROM MUDs, v1.0    *
 * ---------------------------------------------------------------------- *
 * This code has been released as both a standalone snippet and as part   *
 * of the StockMUD+ [ROM] project release.  It was written and developed  *
 * by Joseph Benfield (Hades_Kane / Diablos of End of Time & StockMUD)    *
 * and Matt Fillinger (Grieffels of End of Time & When Worlds Collide)    *
 * for use in When Worlds Collide and StockMUD+.  Thanks go out to those  *
 * who came before and inspired the system to begin with, and whose own   *
 * systems we learned from in our effort to simplify and optimize this    *
 * from-scratch system.  LodePNG was used in place of the libpng library. *
 * ---------------------------------------------------------------------- *
 *         PNG encoding/decoding courtesy of the LodePNG library,         *
 *                Copyright (c) 2005-2024 Lode Vandevenne.                *
 * ---------------------------------------------------------------------- *
 * Conditions of use are that applicable licenses in any codebase this is *
 * being used in are followed, this header is not removed or altered, the *
 * headers for LodePNG are not removed if being used, and that some form  *
 * of credit or acknowledgement is made in a helpfile for (your choice):  *
 * the worldmap system, snippets used / code contributors, or credits.    *
 * ---------------------------------------------------------------------- *
 Worldmap by Joseph Benfield (Hades_Kane/Diablos of End of Time & StockMUD)
    and Matt Fillinger (Grieffels of End of Time & When Worlds Collide)
 **************************************************************************/
 

void do_editmaptile(CHAR_DATA *ch, char *argument)
{
    char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH];
    int x = wmap_x(ch, NULL);
    int y = wmap_y(ch, NULL);
    int z = wmap_z(ch, NULL);
    int wmap_index = wmap_num(ch, NULL);
    WMAPTILE_DATA *tile;

    if (wmap_index == -1)
    {
        send_to_char("You are not in a valid map location.\r\n", ch);
        return;
    }

    if (!str_cmp(argument, "save"))
    {
        do_function(ch, &do_savemap, "");
        return;
    }

    argument = one_argument(argument, arg1);

    if (arg1[0] == '\0')
    {
        send_to_char("Syntax: editmaptile create|delete|show\r\n"
             "        editmaptile <sector> [<custom symbol>]\r\n"
             "        editmaptile symbol <custom symbol|none>\r\n"
             "        editmaptile name <new name|none>\r\n"
             "        editmaptile desc (enters into append mode)\r\n"
             "        editmaptile visibility <#>\r\n"
             "        editmaptile passable <yes/true|no/false>\r\n"
             "        editmaptile list [all]\r\n"
             "        editmaptile delete\r\n",ch);
        return;
    }

    int sector_id = sector_lookup(arg1);
    if (sector_id != -1)
    {
        wmapgrid[wmap_index][x][y]->terrain = sector_id;
        send_to_char("Map tile terrain updated successfully.\r\n", ch);
        return;
    }

    if (!str_cmp(arg1, "list"))
    {
        for( tile = first_wmaptile; tile != NULL; tile = tile->next )
        {
            if(str_cmp(argument,"all") && tile->wmap_index != wmap_index) continue;
            printf_to_char(ch, "Coords %s(%d) %d %d %d %d %d\n", wmap_table[tile->wmap_index].name, tile->wmap_index, tile->x, tile->y, tile->z, tile->vis, tile->pass);
        }
        return;
    }

    tile = find_wmap_tile(wmap_index,x,y,z);

    if (!str_cmp(arg1, "create"))
    {
        if(tile != NULL)
        {
            send_to_char("Map tile already present.\r\n", ch);
            return;
        }

        CREATE( tile, WMAPTILE_DATA, 1 );
        LINK( tile, first_wmaptile, last_wmaptile, next, prev );
        tile->wmap_index = wmap_index;
        tile->x = x;
        tile->y = y;
        tile->z = z;
        tile->vis = 0;
        tile->pass = 0;
        send_to_char("Map tile created.\r\n", ch);
        return;
    }


    if(tile == NULL)
    {
        send_to_char("No wmap tile present.\r\n", ch);
        return;
    }

    if (!str_cmp(arg1, "delete"))
    {
        free_string( tile->name );
        free_string( tile->desc );
        free_string(tile->symb);
        UNLINK( tile, first_wmaptile, last_wmaptile, next, prev );
        free(tile);
        send_to_char("World Map Tile deleted.\r\n", ch);
        return;
    }

    if (!str_cmp(arg1, "show"))
    {
        printf_to_char(ch,"Coords:     %d %d %d\r\n"
                          "Visibility: %d\r\n"
                          "Passable:   %s\r\n"
                          "Symbol:     %s{x\r\n"
                          "Name:       %s\r\n"
                          "Desc:\r\n%s\r\n",
        tile->x, tile->y, tile->z, tile->vis, tile->pass == 0 ? "TRUE" : "FALSE",
        tile->symb, tile->name, tile->desc);
        return;
    }

    if (!str_cmp(arg1, "name"))
    {
        if (argument[0] == '\0')
        {
            send_to_char("You must specify a name.\r\n", ch);
            return;
        }
        free_string(tile->name);
        if(!str_cmp(argument,"none"))
            tile->name = str_dup(""); 
        else
            tile->name = str_dup(argument);
        send_to_char("Map tile name updated.\r\n", ch);
        return;
    }

    if (!str_cmp(arg1, "desc")) 
    {
        if (argument[0] == '\0') 
            string_append(ch, &tile->desc); 
        return;
    }

    if (!str_prefix(arg1, "symbol"))
    {
        if (argument[0] == '\0')
        {
            send_to_char("You must specify a custom symbol.\r\n", ch);
            return;
        }
        free_string(tile->symb);
        if(!str_cmp(argument,"none"))
            tile->symb = str_dup(""); 
        else
            tile->symb = str_dup(argument);
        send_to_char("Map tile custom symbol updated.\r\n", ch);
        return;
    }

    if (!str_prefix(arg1, "visibility"))
    {
        if (argument[0] == '\0' || !is_number(argument) || atoi(argument) > MAX_WMAP_SCAN) 
        {
            printf_to_char(ch,"You must specify a numerical value between 1-%d for visibility.\r\n", MAX_WMAP_SCAN);
            return;
        }
        tile->vis = atoi(argument);
        send_to_char("Map tile visibility updated.\r\n", ch);
        return;
    }

    if (!str_prefix(arg1, "passable"))
    {
        if (!str_cmp(argument,"yes") ||  !str_cmp(argument,"true"))
            tile->pass = 0;
        else if (!str_cmp(argument,"no") ||  !str_cmp(argument,"false"))
            tile->pass = 1;
        else
        {
            send_to_char("Map tile passable must be yes/true, or no/false\r\n",ch);
            return;
        }
        send_to_char("Map tile passable updated.\r\n", ch);
        return;
    }

    // probably just remove this but leaving it for now
    // in case we decide we want to use editmapt <sector> <custom>
    strncpy(arg2, argument, sizeof(arg2) - 1);
    arg2[sizeof(arg2) - 1] = '\0';

    if (arg2[0] != '\0')
    {
        free_string(tile->symb);
        tile->symb = str_dup(arg2);
    }
    else
    {
        free_string(tile->symb);
        tile->symb = str_dup("");
    }

    send_to_char("Map tile updated successfully.\r\n", ch);
}

void do_setmapexit(CHAR_DATA *ch, char *argument)
{
    char arg1[MAX_INPUT_LENGTH];
    int wmap_index = wmap_num(ch, NULL);

    if (wmap_index == -1)
    {
        send_to_char("You are not in a valid map location.\r\n", ch);
        return;
    }
    
    argument = one_argument(argument, arg1);

    if (arg1[0] == '\0' || !is_number(arg1))
    {
        send_to_char("Syntax: setmapexit <room_vnum>\r\n", ch);
        return;
    }

    int room_vnum = atoi(arg1);

    if (room_vnum < 1 || !get_room_index(room_vnum))
    {
        send_to_char("Invalid room vnum.\r\n", ch);
        return;
    }

    add_wmap_exit(wmap_index, wmap_x(ch,NULL), wmap_y(ch,NULL), wmap_z(ch,NULL), room_vnum);
    send_to_char("Map exit created.\r\n", ch);
    return;
}

void do_editmapexit(CHAR_DATA *ch, char *argument)
{
    char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH];
    int x = wmap_x(ch, NULL);
    int y = wmap_y(ch, NULL);
    int z = wmap_z(ch, NULL);
    int wmap_index = wmap_num(ch, NULL);
    WMAP_EXIT *exit;

    if (wmap_index == -1)
    {
        send_to_char("You are not in a valid map location.\r\n", ch);
        return;
    }

    argument = one_argument(argument, arg1);
    argument = one_argument(argument, arg2);

    if (arg1[0] == '\0')
    {
        send_to_char("Syntax: editmapexit add <vnum>\r\n"
             "        editmapexit list [all]\r\n"
             "        editmapexit save|delete\r\n",ch);
        return;
    }

    if (!str_cmp(arg1, "save"))
    {
        save_wmap_exits();
        return;
    }

    if (!str_cmp(arg1, "list"))
    {
        bool exits_found = false;

        for( exit = first_wmapexit; exit != NULL; exit = exit->next )
        {
            if(str_cmp(arg2,"all") && exit->wmap_index != wmap_index) continue;
            if (!exits_found)
            {
                send_to_char("Map Exits:\r\n", ch);
                send_to_char("--------------------------\r\n", ch);
                exits_found = true;
            }

            printf_to_char(ch, "Wmap %s(%d) (X: %d, Y: %d, Z: %d) -> Room %d\r\n", 
                    wmap_table[exit->wmap_index].name, exit->wmap_index, exit->x, exit->y, exit->z, exit->room_vnum);
        }

        if (!exits_found)
            send_to_char("No map exits are currently set.\r\n", ch);
        return;
    }

    exit = find_wmap_exit(wmap_index,x,y,z);

    if (!str_cmp(arg1, "delete"))
    {
        if (exit != NULL)
        {
            UNLINK( exit, first_wmapexit, last_wmapexit, next, prev );
            free(exit);
            send_to_char("Map exit removed.\r\n", ch); 
        }
        else
            send_to_char("No map exit found at that location.\r\n", ch);
        return;
    }

    if (!str_cmp(arg1, "add"))
    {
        if (arg2[0] == '\0' || !is_number(arg2))
        {
            send_to_char("Syntax: editmapexit <room_vnum>\r\n", ch);
            return;
        }

        int room_vnum = atoi(arg2);

        if (room_vnum < 1 || !get_room_index(room_vnum))
        {
            send_to_char("Invalid room vnum.\r\n", ch);
            return;
        }

        add_wmap_exit(wmap_index, wmap_x(ch,NULL), wmap_y(ch,NULL), wmap_z(ch,NULL), room_vnum);
        send_to_char("Map exit created.\r\n", ch);
        return;
    }
}

void do_removemapexit(CHAR_DATA *ch, char *argument)
{
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];
    char arg3[MAX_INPUT_LENGTH];
    char arg4[MAX_INPUT_LENGTH];
    int wmap_index,x,y,z;

    argument = one_argument(argument, arg1);
    argument = one_argument(argument, arg2);
    argument = one_argument(argument, arg3);
    argument = one_argument(argument, arg4);

    if (arg1[0] != '\0' && !str_cmp(arg1,"here"))
    {
        wmap_index = wmap_num(ch,NULL);
        x = wmap_x(ch,NULL);
        y = wmap_y(ch,NULL);
        z = wmap_z(ch,NULL);
    }
    else if (arg1[0] == '\0' || arg2[0] == '\0' || arg3[0] == '\0'
    || !is_number(arg1) || !is_number(arg2) || !is_number(arg3) || !is_number(arg4))
    {
        send_to_char("Syntax: removemapexit <map_index> <x> <y> <z>\r\n", ch);
        send_to_char("Syntax: removemapexit here\r\n", ch);
        return;
    }
    else
    {
        wmap_index = atoi(arg1);
        x = atoi(arg2);
        y = atoi(arg3);
        z = atoi(arg4);
    }
    
    if (wmap_index < 0 || wmap_index >= MAX_WMAP || x < 0 || x >= wmap_table[wmap_index].max_x || y < 0 || y >= wmap_table[wmap_index].max_y)
    {
        send_to_char("Invalid map or coordinates.\r\n", ch);
        return;
    }

    WMAP_EXIT *exit = find_wmap_exit(wmap_index,x,y,x);

    if (exit != NULL)
    {
        UNLINK( exit, first_wmapexit, last_wmapexit, next, prev );
        free(exit);
        send_to_char("Map exit removed.\r\n", ch);
        save_wmap_exits();  
    }
    else
        send_to_char("No map exit found at that location.\r\n", ch);
}

void do_listmapexits(CHAR_DATA *ch, char *argument)
{
    WMAP_EXIT *exit;
    char buf[MAX_STRING_LENGTH];
    bool exits_found = false;

    for( exit = first_wmapexit; exit != NULL; exit = exit->next )
    {
        if (!exits_found)
        {
            send_to_char("Map Exits:\r\n", ch);
            send_to_char("--------------------------\r\n", ch);
            exits_found = true;
        }

        sprintf(buf, "Map %d (X: %d, Y: %d, Z: %d) -> Room %d\r\n", 
                exit->wmap_index, exit->x, exit->y, exit->z, exit->room_vnum);
        send_to_char(buf, ch);
    }

    if (!exits_found)
        send_to_char("No map exits are currently set.\r\n", ch);
}

void do_setwmapreset(CHAR_DATA *ch, char *argument)
{
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH]; 
    char arg3[MAX_INPUT_LENGTH]; 
    char arg4[MAX_INPUT_LENGTH]; 
    char arg5[MAX_INPUT_LENGTH]; 
    char arg6[MAX_INPUT_LENGTH];
    char buf[MAX_STRING_LENGTH]; 

    argument = one_argument(argument, arg1);
    argument = one_argument(argument, arg2);
    argument = one_argument(argument, arg3);
    argument = one_argument(argument, arg4);
    argument = one_argument(argument, arg5);
    argument = one_argument(argument, arg6);

    if (arg1[0] == '\0' || arg2[0] == '\0' || arg3[0] == '\0')
    {
        send_to_char("Syntax:\r\n"
            "  setwmapreset <mob|obj> <vnum> <max> <optional [x y]>\r\n"
            "  setwmapreset obj <vnum> <max> mob <mob_vnum> <wear|hold>\r\n", ch);
        return;
    }

    int wmap_index = wmap_num(ch, NULL);
    if (wmap_index == -1)
    {
        send_to_char("You must be on a valid map to set a reset.\r\n", ch);
        return;
    }

    int reset_type;
    if (!str_prefix(arg1, "mob"))
        reset_type = RESET_TYPE_MOB;
    else if (!str_prefix(arg1, "obj"))
        reset_type = RESET_TYPE_OBJ;
    else
    {
        send_to_char("Type must be 'mob' or 'obj'.\r\n", ch);
        return;
    }

    if (!is_number(arg2) || !is_number(arg3))
    {
        send_to_char("Vnum and max must be numbers.\r\n", ch);
        return;
    }

    int vnum = atoi(arg2);
    int max = atoi(arg3);
    int x = wmap_x(ch, NULL);
    int y = wmap_y(ch, NULL);
    int z = wmap_z(ch, NULL);

    if (max < 1)
    {
        send_to_char("Maximum must be at least 1.\r\n", ch);
        return;
    }

    if (arg4[0] != '\0' && str_cmp(arg4, "mob") && is_number(arg4))
    {
        if (!is_number(arg5))
        {
            send_to_char("Coordinates must be numbers.\r\n", ch);
            return;
        }
        x = atoi(arg4);
        y = atoi(arg5);

        if (x < 0 || x >= wmap_table[wmap_index].max_x || 
            y < 0 || y >= wmap_table[wmap_index].max_y)
        {
            send_to_char("Coordinates are out of map bounds.\r\n", ch);
            return;
        }
    }

    if (reset_type == RESET_TYPE_MOB)
    {
        if (!get_mob_index(vnum))
        {
            sprintf(buf, "Mob vnum %d does not exist.\r\n", vnum);
            send_to_char(buf, ch);
            return;
        }
    }
    else if (reset_type == RESET_TYPE_OBJ && str_cmp(arg4, "mob"))
    {
        if (!get_obj_index(vnum))
        {
            sprintf(buf, "Object vnum %d does not exist.\r\n", vnum);
            send_to_char(buf, ch);
            return;
        }
    }

    if (reset_type == RESET_TYPE_OBJ && !str_cmp(arg4, "mob"))
    {
        if (arg5[0] == '\0' || arg6[0] == '\0')
        {
            send_to_char("Syntax for obj on mob: setwmapreset obj <vnum> <max> mob <mob_vnum> <wear|hold>\r\n", ch);
            return;
        }

        if (!is_number(arg5))
        {
            send_to_char("Mob vnum must be a number.\r\n", ch);
            return;
        }

        int mob_vnum = atoi(arg5);
        if (!get_mob_index(mob_vnum))
        {
            sprintf(buf, "Mob vnum %d does not exist.\r\n", mob_vnum);
            send_to_char(buf, ch);
            return;
        }

        OBJ_INDEX_DATA *pObjIndex = get_obj_index(vnum);
        if (!pObjIndex)
        {
            sprintf(buf, "Object vnum %d does not exist.\r\n", vnum);
            send_to_char(buf, ch);
            return;
        }

        bool wear = !str_cmp(arg6, "wear");
        bool hold = !str_cmp(arg6, "hold");
        if (!wear && !hold)
        {
            send_to_char("Last argument must be 'wear' or 'hold'.\r\n", ch);
            return;
        }

        WMAP_RESET_DATA *mob_reset = NULL;
        for (WMAP_RESET_DATA *r = wmap_reset_list[wmap_index]; r != NULL; r = r->next)
        {
            if (r->reset_type == RESET_TYPE_MOB && r->vnum == mob_vnum)
            {
                mob_reset = r;
                break;
            }
        }

        if (!mob_reset)
        {
            sprintf(buf, "No reset found for mob vnum %d on this map.\r\n", mob_vnum);
            send_to_char(buf, ch);
            return;
        }

        x = mob_reset->x;
        y = mob_reset->y;
        z = mob_reset->z;

        reset_type = RESET_TYPE_OBJ_ON_MOB;
    }

    WMAP_RESET_DATA *reset = malloc(sizeof(WMAP_RESET_DATA));
    if (!reset)
    {
        send_to_char("Memory allocation failed!\r\n", ch);
        return;
    }

    reset->reset_type = reset_type;
    reset->vnum = vnum;
    reset->wmap_index = wmap_index;
    reset->x = x;
    reset->y = y;
    reset->z = z;
    reset->max = max;
    reset->mob_vnum = (reset_type == RESET_TYPE_OBJ_ON_MOB) ? atoi(arg5) : -1;
    reset->wear = (reset_type == RESET_TYPE_OBJ_ON_MOB && !str_cmp(arg6, "wear"));
    reset->next = wmap_reset_list[wmap_index];
    wmap_reset_list[wmap_index] = reset;

    save_wmap_resets(wmap_index);

    if (reset_type == RESET_TYPE_OBJ_ON_MOB)
    {
        sprintf(buf, "Reset added: Object %d [max %d] on mob %d (%s) at [X %d Y %d Z %d] on wmap %s\r\n",
                vnum, max, reset->mob_vnum, reset->wear ? "wear" : "hold", x, y, z, wmap_table[wmap_index].name);
    }
    else
    {
        sprintf(buf, "Reset added: %s %d [max %d] at [X %d Y %d Z %d] on wmap %s\r\n",
                reset_type == RESET_TYPE_MOB ? "Mob" : "Object", vnum, max, x, y, z, wmap_table[wmap_index].name);
    }
    send_to_char(buf, ch);
}

void do_listwmapresets(CHAR_DATA *ch, char *argument)
{
    char buf[MAX_STRING_LENGTH];
    bool found = false;
    int wmap_index;

    if (argument[0] != '\0')
    {
        if (!is_number(argument))
        {
            send_to_char("Syntax: listwmapresets <wmap index>\r\nUse 'wmaptable' for reference.\r\n", ch);
            return;
        }
        wmap_index = atoi(argument);
        if (wmap_index < 0 || wmap_index >= MAX_WMAP)
        {
            send_to_char("Invalid wmap index. Use 'wmaptable' for information.\r\n", ch);
            return;
        }
    }
    else
    {
        wmap_index = ch->wmap[0];
    }

    send_to_char("Num  WMap        Type Name            Vnum  Max   X    Y    Z    Extra\r\n", ch);
    send_to_char("----------------------------------------------------------------------\r\n", ch);

    WMAP_RESET_DATA *reset;
    int reset_count = 0;
    for (reset = wmap_reset_list[wmap_index]; reset != NULL; reset = reset->next)
    {
        const char *name = "Unknown";
        char extra[50];
        if (reset->reset_type == RESET_TYPE_MOB)
        {
            MOB_INDEX_DATA *mob = get_mob_index(reset->vnum);
            if (mob)
                name = mob->player_name;
            sprintf(extra, "Mob");
        }
        else if (reset->reset_type == RESET_TYPE_OBJ)
        {
            OBJ_INDEX_DATA *obj = get_obj_index(reset->vnum);
            if (obj)
                name = obj->name;
            sprintf(extra, "Obj");
        }
        else if (reset->reset_type == RESET_TYPE_OBJ_ON_MOB)
        {
            OBJ_INDEX_DATA *obj = get_obj_index(reset->vnum);
            if (obj)
                name = obj->name;
            sprintf(extra, "Obj on Mob %d (%s)", reset->mob_vnum, reset->wear ? "wear" : "hold");
        }

        sprintf(buf, "%-4d %-10s: %-20s %-5d [%-2d] [%-4d %-4d %-4d] %s\r\n",
                reset_count++, wmap_table[wmap_index].name, name, reset->vnum, reset->max, reset->x, reset->y, reset->z, extra);
        send_to_char(buf, ch);
        found = true;
    }

    if (!found)
        send_to_char("No map resets found on this map.\r\n", ch);
}

void do_removewmapreset(CHAR_DATA *ch, char *argument)
{
    char buf[MAX_STRING_LENGTH];
    char arg1[MAX_INPUT_LENGTH]; // mob|obj
    char arg2[MAX_INPUT_LENGTH]; // x or mob_vnum
    char arg3[MAX_INPUT_LENGTH]; // y or obj_vnum
    char arg4[MAX_INPUT_LENGTH]; // z
    
    argument = one_argument(argument, arg1);
    argument = one_argument(argument, arg2);
    argument = one_argument(argument, arg3);
    argument = one_argument(argument, arg4);

    int wmap_index = wmap_num(ch, NULL);
    if (wmap_index == -1)
    {
        send_to_char("You must be on a valid map to remove a reset.\r\n", ch);
        return;
    }

    if (arg1[0] != '\0' && arg2[0] == '\0' && is_number(arg1))
    {
        int reset_num = atoi(arg1);
        WMAP_RESET_DATA *reset = wmap_reset_list[wmap_index];
        WMAP_RESET_DATA *prev = NULL;
        int current_num = 0;

        while (reset != NULL)
        {
            if (current_num == reset_num)
            {
                if (prev)
                    prev->next = reset->next;
                else
                    wmap_reset_list[wmap_index] = reset->next;

                if (reset->reset_type == RESET_TYPE_OBJ_ON_MOB)
                    sprintf(buf, "Reset #%d removed: Object %d on mob %d at (%d, %d, %d).\r\n",
                            reset_num, reset->vnum, reset->mob_vnum, reset->x, reset->y, reset->z);
                else
                    sprintf(buf, "Reset #%d removed: %s %d at (%d, %d, %d).\r\n",
                            reset_num, reset->reset_type == RESET_TYPE_MOB ? "Mob" : "Object",
                            reset->vnum, reset->x, reset->y, reset->z);
                send_to_char(buf, ch);

                free(reset);
                save_wmap_resets(wmap_index);
                return;
            }
            prev = reset;
            reset = reset->next;
            current_num++;
        }

        sprintf(buf, "No reset found with number %d.\r\n", reset_num);
        send_to_char(buf, ch);
        return;
    }

    if (arg1[0] == '\0' || arg2[0] == '\0' || arg3[0] == '\0'  || arg4[0] == '\0')
    {
        send_to_char("Syntax:\r\n"
            "  removemapreset <number>\r\n"
            "  removemapreset <mob|obj> <x> <y> <z>\r\n"
            "  removemapreset obj <mob_vnum> <obj_vnum>\r\n", ch);
        return;
    }

    int reset_type;
    if (!str_prefix(arg1, "mob"))
        reset_type = RESET_TYPE_MOB;
    else if (!str_prefix(arg1, "obj"))
        reset_type = RESET_TYPE_OBJ;
    else
    {
        send_to_char("Type must be 'mob' or 'obj'.\r\n", ch);
        return;
    }

    WMAP_RESET_DATA *reset = wmap_reset_list[wmap_index];
    WMAP_RESET_DATA *prev = NULL;

    if (reset_type == RESET_TYPE_OBJ && is_number(arg2) && is_number(arg3))
    {
        int mob_vnum = atoi(arg2);
        int obj_vnum = atoi(arg3);

        while (reset != NULL)
        {
            if (reset->reset_type == RESET_TYPE_OBJ_ON_MOB
            && reset->mob_vnum == mob_vnum && reset->vnum == obj_vnum)
            {
                if (prev)
                    prev->next = reset->next;
                else
                    wmap_reset_list[wmap_index] = reset->next;
                
                sprintf(buf, "Object %d reset removed from mob %d at (%d, %d, %d).\r\n",
                        obj_vnum, mob_vnum, reset->x, reset->y, reset->z);
                send_to_char(buf, ch);
                
                free(reset);
                save_wmap_resets(wmap_index);
                return;
            }
            prev = reset;
            reset = reset->next;
        }

        sprintf(buf, "No object reset for vnum %d on mob %d found.\r\n", obj_vnum, mob_vnum);
        send_to_char(buf, ch);
        return;
    }

    if (is_number(arg2) && is_number(arg3))
    {
        int x = atoi(arg2);
        int y = atoi(arg3);
        int z = atoi(arg4);

        if (x < 0 || x >= wmap_table[wmap_index].max_x || 
            y < 0 || y >= wmap_table[wmap_index].max_y)
        {
            send_to_char("Coordinates are out of map bounds.\r\n", ch);
            return;
        }

        while (reset != NULL)
        {
            if (reset->reset_type == reset_type
            && reset->x == x && reset->y == y && reset->z == z)
            {
                if (prev)
                    prev->next = reset->next;
                else
                    wmap_reset_list[wmap_index] = reset->next;
                
                sprintf(buf, "%s reset removed from (%d, %d, %d).\r\n",
                        reset_type == RESET_TYPE_MOB ? "Mob" : "Object",
                        x, y, z);
                send_to_char(buf, ch);
                
                free(reset);
                save_wmap_resets(wmap_index);
                return;
            }
            prev = reset;
            reset = reset->next;
        }

        sprintf(buf, "No %s reset found at coordinates (%d, %d, %d).\r\n",
                reset_type == RESET_TYPE_MOB ? "mob" : "object",
                x, y, z);
        send_to_char(buf, ch);
        return;
    }

    send_to_char("Invalid syntax. Use:\r\n"
        "  removewmapreset <number>\r\n"
        "  removewmapreset <mob|obj> <x> <y> <z>\r\n"
        "  removewmapreset obj <mob_vnum> <obj_vnum>\r\n", ch);
}

