muddy/
muddy/CVS/
muddy/area/
muddy/area/CVS/
muddy/clans/CVS/
muddy/classes/CVS/
muddy/doc/
muddy/doc/CVS/
muddy/etc/CVS/
muddy/etc/i3/
muddy/etc/i3/CVS/
muddy/imc/CVS/
muddy/lang/CVS/
muddy/licenses/CVS/
muddy/msgdb/CVS/
muddy/new/CVS/
muddy/notes/
muddy/player/
muddy/races/CVS/
muddy/religions/CVS/
muddy/src/CVS/
muddy/src/comm/CVS/
muddy/src/db/CVS/
muddy/src/intermud/
muddy/src/intermud/CVS/
muddy/src/irc/CVS/
muddy/src/olc/CVS/
/* $Id: olc_obj.c,v 1.666 2004/09/20 10:50:30 shrike Exp $ */

/************************************************************************************
 *    Copyright 2004 Astrum Metaphora consortium                                    *
 *                                                                                  *
 *    Licensed under the Apache License, Version 2.0 (the "License");               *
 *    you may not use this file except in compliance with the License.              *
 *    You may obtain a copy of the License at                                       *
 *                                                                                  *
 *    http://www.apache.org/licenses/LICENSE-2.0                                    *
 *                                                                                  *
 *    Unless required by applicable law or agreed to in writing, software           *
 *    distributed under the License is distributed on an "AS IS" BASIS,             *
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.      *
 *    See the License for the specific language governing permissions and           *
 *    limitations under the License.                                                *
 *                                                                                  *
 ************************************************************************************/
/************************************************************************************
 *     ANATOLIA 2.1 is copyright 1996-1997 Serdar BULUT, Ibrahim CANPUNAR           *
 *     ANATOLIA has been brought to you by ANATOLIA consortium                      *
 *       Serdar BULUT {Chronos}         bulut@rorqual.cc.metu.edu.tr                *
 *       Ibrahim Canpunar  {Asena}      canpunar@rorqual.cc.metu.edu.tr             *
 *       Murat BICER  {KIO}             mbicer@rorqual.cc.metu.edu.tr               *
 *       D.Baris ACAR {Powerman}        dbacar@rorqual.cc.metu.edu.tr               *
 *     By using this code, you have agreed to follow the terms of the               *
 *     ANATOLIA license, in the file Anatolia/anatolia.licence                      *
 ***********************************************************************************/

/************************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,                 *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.            *
 *                                                                                  *
 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael                   *
 *  Chastain, Michael Quan, and Mitchell Tse.                                       *
 *                                                                                  *
 *  In order to use any part of this Merc Diku Mud, you must comply with            *
 *  both the original Diku license in 'license.doc' as well the Merc                *
 *  license in 'license.txt'.  In particular, you may not remove either of          *
 *  these copyright notices.                                                        *
 *                                                                                  *
 *  Much time and thought has gone into this software and you are                   *
 *  benefitting.  We hope that you share your changes too.  What goes               *
 *  around, comes around.                                                           *
 ************************************************************************************/

/************************************************************************************
*       ROM 2.4 is copyright 1993-1995 Russ Taylor                                  *
*       ROM has been brought to you by the ROM consortium                           *
*           Russ Taylor (rtaylor@pacinfo.com)                                       *
*           Gabrielle Taylor (gtaylor@pacinfo.com)                                  *
*           Brian Moore (rom@rom.efn.org)                                           *
*       By using this code, you have agreed to follow the terms of the              *
*       ROM license, in the file Rom24/doc/rom.license                              *
*************************************************************************************/

/************************************************************************************
 * Copyright (c) 1998 fjoe <fjoe@iclub.nsu.ru>                                      *
 * All rights reserved.                                                             *
 *                                                                                  *
 * Redistribution and use in source and binary forms, with or without               *
 * modification, are permitted provided that the following conditions               *
 * are met:                                                                         *
 * 1. Redistributions of source code must retain the above copyright                *
 *    notice, this list of conditions and the following disclaimer.                 *
 * 2. Redistributions in binary form must reproduce the above copyright             *
 *    notice, this list of conditions and the following disclaimer in the           *
 *    documentation and/or other materials provided with the distribution.          *
 *                                                                                  *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND           *
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE            *
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE       *
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE          *
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL       *
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS          *
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)            *
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT       *
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY        *
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF           *
 * SUCH DAMAGE.                                                                     *
 ************************************************************************************/
 
#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "typedef.h"
#include "merc.h"
#include "olc/olc.h"
#include "db/db.h"
#include "obj_prog.h"

#define EDIT_OBJ(ch, obj)        (obj = (OBJ_INDEX_DATA*) ch->desc->pEdit)

DECLARE_OLC_FUN(objed_create        );
DECLARE_OLC_FUN(objed_edit          );
DECLARE_OLC_FUN(objed_touch         );
DECLARE_OLC_FUN(objed_show          );
DECLARE_OLC_FUN(objed_list          );
DECLARE_OLC_FUN(objed_del           );

DECLARE_OLC_FUN(objed_name          );
DECLARE_OLC_FUN(objed_short         );
DECLARE_OLC_FUN(objed_long          );
DECLARE_OLC_FUN(objed_addaffect     );
DECLARE_OLC_FUN(objed_addapply      );
DECLARE_OLC_FUN(objed_delaffect     );
DECLARE_OLC_FUN(objed_value0        );
DECLARE_OLC_FUN(objed_value1        );
DECLARE_OLC_FUN(objed_value2        );
DECLARE_OLC_FUN(objed_value3        );
DECLARE_OLC_FUN(objed_value4        );
DECLARE_OLC_FUN(objed_weight        );
DECLARE_OLC_FUN(objed_limit         );
DECLARE_OLC_FUN(objed_cost          );
DECLARE_OLC_FUN(objed_exd           );

DECLARE_OLC_FUN(objed_extra         );
DECLARE_OLC_FUN(objed_wear          );
DECLARE_OLC_FUN(objed_type          );
DECLARE_OLC_FUN(objed_affect        );
DECLARE_OLC_FUN(objed_material      );
DECLARE_OLC_FUN(objed_level         );
DECLARE_OLC_FUN(objed_condition     );
DECLARE_OLC_FUN(objed_clan          );
DECLARE_OLC_FUN(objed_clone         );
DECLARE_OLC_FUN(objed_gender        );
DECLARE_OLC_FUN(objed_obj_prog      );
DECLARE_OLC_FUN(objed_trigadd       );
DECLARE_OLC_FUN(objed_trigdel       );
DECLARE_OLC_FUN(objed_riddle        );
DECLARE_OLC_FUN(objed_size          );


DECLARE_VALIDATE_FUN(validate_condition);
DECLARE_VALIDATE_FUN(validate_material );

olc_cmd_t olc_cmds_obj[] =
{
/*        { command        function                arg                        }, */

     { "create",     objed_create,        5                           },
     { "edit",       objed_edit,          0                           },
     { "touch",      objed_touch,         0                           },
     { "show",       objed_show,          0                           },
     { "list",       objed_list,          0                           },
     { "delete_ob",  show_commands,       0                           },
     { "delete_obj", objed_del,           5                           },
     { "trigadd",    objed_trigadd,       5                           },
     { "trigdel",    objed_trigdel,       5                           },

     { "addaffect",  objed_addaffect,     5                           },
     { "addapply",   objed_addapply,      5                           },
     { "cost",       objed_cost,          5                           },
     { "delaffect",  objed_delaffect,     5                           },
     { "exd",        objed_exd,           0                           },
     { "long",       objed_long,          0                           },
     { "name",       objed_name,          0                           },
     { "short",      objed_short,         0                           },
     { "v0",         objed_value0,        5                           },
     { "v1",         objed_value1,        5                           },
     { "v2",         objed_value2,        5                           },
     { "v3",         objed_value3,        5                           },
     { "v4",         objed_value4,        5                           },
     { "weight",     objed_weight,        5                           },
     { "limit",      objed_limit,         5                           },

     { "extra",      objed_extra,         5,     extra_flags          },
     { "wear",       objed_wear,          5,     wear_flags           },
     { "type",       objed_type,          5,     item_types           },
     { "material",   objed_material,      0,     validate_material    },
     { "level",      objed_level,         5                           },
     { "condition",  objed_condition,     5,     validate_condition   },
     { "clan",       objed_clan,          5                           },
     { "clone",      objed_clone,         0                           },
     { "gender",     objed_gender,        0,     gender_table         },
     { "obj_prog",   objed_obj_prog,      5                           },
     { "riddle",     objed_riddle,        0                           },
     { "size",       objed_size,          0                           },

     { "version",    show_version,        0                           },
     { "commands",   show_commands,       0                           },

     { NULL }
};

extern void        show_obj_values        (BUFFER *output, OBJ_INDEX_DATA *pObj);
extern bool validate_item_vnum (const char *argument);

static int        set_obj_values        (BUFFER *output, OBJ_INDEX_DATA *pObj,
                                 const char *argument, int value_num);
static void        show_spells        (BUFFER *output, int tar);

OLC_FUN(objed_create)
{
        OBJ_INDEX_DATA *pObj;
        AREA_DATA *pArea;
        int  value;
        int  iHash;
        char arg[MAX_STRING_LENGTH];

        one_argument(argument, arg, sizeof(arg));
        value = atoi(arg);
        if (!value) {
                do_help(ch, "'OLC CREATE'");
                return FALSE;
        }

        pArea = area_vnum_lookup(value);
        if (!pArea) {
                char_puts("ObjEd: That vnum is not assigned an area.\n", ch);
                return FALSE;
        }

        if (!IS_BUILDER(ch, pArea)) {
                char_puts("ObjEd: Insufficient security.\n", ch);
                return FALSE;
        }

        if (get_obj_index(value)) {
                char_puts("ObjEd: Object vnum already exists.\n", ch);
                return FALSE;
        }

        pObj                        = new_obj_index();
        pObj->vnum                = value;

        if (value > top_vnum_obj)
                top_vnum_obj = value;

        iHash                        = value % MAX_KEY_HASH;
        pObj->next                = obj_index_hash[iHash];
        obj_index_hash[iHash]        = pObj;

        ch->desc->pEdit                = (void *)pObj;
        OLCED(ch)   = olced_lookup(ED_OBJ);
        touch_area(pArea);
        char_puts("ObjEd: Object created.\n", ch);
        return FALSE;
}

OLC_FUN(objed_edit)
{
     char arg[MAX_INPUT_LENGTH];
     int value;
     OBJ_INDEX_DATA *pObj;
     AREA_DATA *pArea;

     one_argument(argument, arg, sizeof(arg));
     if (arg[0] == '\0') {
               do_help(ch, "'OLC EDIT'");
               return FALSE;
     }

     value = atoi(arg);
     pObj = get_obj_index(value);
     if (!pObj) {
               char_puts("ObjEd: Vnum does not exist.\n", ch);
               return FALSE;
     }

     pArea = area_vnum_lookup(pObj->vnum);
     if (!IS_BUILDER(ch, pArea)) {
               char_puts("ObjEd: Insufficient security.\n", ch);
               return FALSE;
     }

     ch->desc->pEdit = (void*) pObj;
     OLCED(ch)   = olced_lookup(ED_OBJ);
     return FALSE;
}

OLC_FUN(objed_touch)
{
     OBJ_INDEX_DATA *pObj;
     EDIT_OBJ(ch, pObj);
     return touch_vnum(pObj->vnum);
}

OLC_FUN(objed_show)
{
    char arg[MAX_INPUT_LENGTH];
    OBJ_INDEX_DATA        *pObj;
    MPTRIG *optrig;
    AREA_DATA        *pArea;
    AFFECT_DATA *paf;
    int cnt, i;
    BUFFER *output;
    clan_t *clan;

    one_argument(argument, arg, sizeof(arg));
    if (arg[0] == '\0')
    {
        if (IS_EDIT(ch, ED_OBJ))
            EDIT_OBJ(ch, pObj);
        else
        {
            do_help(ch, "'OLC EDIT'");
            return FALSE;
        }
    }
    else
    {
        int value = atoi(arg);

        pObj = get_obj_index(value);
        if (!pObj)
        {
            char_puts("ObjEd: Vnum does not exist.\n", ch);
            return FALSE;
        }
    }

    pArea = area_vnum_lookup(pObj->vnum);

    if (!IS_IMMORTAL(ch))
    {
        if (!IS_BUILDER(ch, pArea))
        {
            char_puts("ObjEd: Insufficient security.\n", ch);
            return FALSE;
        }
    }

    output = buf_new(ch->lang);
    buf_printf(output, "Name:        [%s]\nArea:        [%5d] %s\n", pObj->name, pArea->vnum, pArea->name);

    buf_printf(output, "Vnum:        [%5d]  Gender: [%s]\nType:        [%s]\n",
               pObj->vnum,
               flag_string(gender_table, pObj->gender),
               flag_string(item_types, pObj->item_type));

    if (pObj->clan && (clan = clan_lookup(pObj->clan)))
        buf_printf(output, "Clan        : [%s]\n", clan->name);

    if (pObj->limit != -1)
        buf_printf(output, "Limit:       [%5d]\n", pObj->limit);
    else
        buf_add(output, "Limit:       [none]\n");

    buf_printf(output, "Level:       [%5d]\n", pObj->level);
    buf_printf(output, "Wear flags:  [%s]\n", flag_string(wear_flags, pObj->wear_flags));
    buf_printf(output, "Extra flags: [%s]\n", flag_string(extra_flags, pObj->extra_flags));
    buf_printf(output, "Material:    [%s]\n", pObj->material);
    buf_printf(output, "Condition:   [%5d]\n", pObj->condition);
    buf_printf(output, "Weight:      [%5d]\nCost:        [%5d]\n",        pObj->weight, pObj->cost);//FIXME
    buf_printf(output, "Size:        [%d]\n", pObj->size);

    if (pObj->ed)
    {
        ED_DATA *ed;

        buf_add(output, "Ex desc kwd: ");

        for (ed = pObj->ed; ed; ed = ed->next)
            buf_printf(output, "[%s]", ed->keyword);

        buf_add(output, "\n");
    }

    mlstr_dump(output, "Short desc: ", pObj->short_descr);
    mlstr_dump(output, "Long desc: ", pObj->description);

    for (cnt = 0, paf = pObj->affected; paf; paf = paf->next)
    {
        where_t * w = where_lookup(paf->where);

        if (cnt == 0)
        {
            buf_add(output, "Number      Affects Modifier Affects Bitvector\n");
            buf_add(output, "------ ------------ -------- ------- -----------------------------------------\n");
        }
        buf_printf(output, "[%4d] %12.12s %8d %7.7s %s\n",
                         cnt,
                         flag_string(apply_flags, paf->location),
                         paf->modifier,
                         flag_string(apply_types, paf->where),
                         w ? flag_string(w->table, paf->bitvector) : "none");
        cnt++;
    }

    show_obj_values(output, pObj);
    if (pObj->riddle)
        buf_printf(output, "Riddle VNUM: [%d]\n", pObj->riddle);

    if (pObj->oprogs_old)
    {
        buf_add(output, "Object progs:\n");
        for (i = 0; i < OPROG_MAX; i++)
            if (pObj->oprogs_old[i] != NULL)
                buf_printf(output, "%s: %s\n", optype_table[i], oprog_name_lookup(pObj->oprogs_old[i]));
    }

    // Checking of obj triggers
    if (pObj->oprogs)
    {
        int cnt = 0;

        buf_printf(output, "\nOBJPrograms for [%5d]:\n", pObj->vnum);

        for (optrig = pObj->oprogs; optrig; optrig = optrig->next)
        {
            if (cnt ==0)
            {
                buf_add(output, " Number Vnum Trigger Phrase [Flags]\n");
                buf_add(output, " ------ ---- ------- ----------------------------------------------------------\n");
            }

            buf_printf(output, "[%5d] %4d %7s %s [%s]\n", cnt,
                       optrig->vnum, flag_string(oprog_flags, optrig->type),
                       optrig->phrase,
                       flag_string(oprog_flags, optrig->flags));
                       cnt++;
        }
    }

    page_to_char(buf_string(output), ch);
    buf_free(output);

    return FALSE;
}

OLC_FUN(objed_list)
{
     OBJ_INDEX_DATA        *pObjIndex;
     AREA_DATA        *pArea;
     BUFFER                *buffer;
     char                arg  [MAX_INPUT_LENGTH];
     bool fAll, found;
     int vnum;
     int  col = 0;

     one_argument(argument, arg, sizeof(arg));
     if (arg[0] == '\0') {
               do_help(ch, "'OLC ALIST'");
               return FALSE;
     }

     if ((pArea = get_edited_area(ch)) == NULL)
               pArea = ch->in_room->area;

     if (!IS_BUILDER(ch, pArea))
     {
               char_puts("ObjEd: Insufficient security.\n", ch);
               return FALSE;
     }

     buffer  = buf_new(-1);
     fAll    = !str_cmp(arg, "all");
     found   = FALSE;

     for (vnum = pArea->min_vnum; vnum <= pArea->max_vnum; vnum++) {
               if ((pObjIndex = get_obj_index(vnum))) {
                    if (fAll || is_name(arg, pObjIndex->name)
                    || flag_value(item_types, arg) == pObjIndex->item_type) {
                              found = TRUE;
                              buf_printf(buffer, "{x[%5d] %s {x",
                                        pObjIndex->vnum,
                                        fmt_color_str(mlstr_val_true(pObjIndex->short_descr, 0), 16));
                              if (++col % 3 == 0)
                                        buf_add(buffer, "\n");
                    }
               }
     }

     if (!found)
               char_puts("Object(s) not found in this area.\n", ch);
     else {
               if (col % 3 != 0)
                    buf_add(buffer, "\n");

               page_to_char(buf_string(buffer), ch);
     }

     buf_free(buffer);
     return FALSE;
}

OLC_FUN(objed_del)
{
     OBJ_INDEX_DATA *pObj;
     OBJ_DATA *obj, *obj_next;
     AREA_DATA *area;
     int i;
     bool error = FALSE;

     EDIT_OBJ(ch, pObj);

     if (olced_busy(ch, ED_OBJ, pObj, NULL))
     return FALSE;

/* check that pObj is not in resets */
     for (i = 0; i < MAX_KEY_HASH; i++) {
               ROOM_INDEX_DATA *room;

               for (room = room_index_hash[i]; room; room = room->next) {
                    int j = 0;
                    RESET_DATA *reset;

                    for (reset = room->reset_first; reset; reset = reset->next) {
                              bool found = FALSE;

                              j++;
                              switch (reset->command) {
                              case 'P':
                                        if (reset->arg3 == pObj->vnum)
                                             found = TRUE;

                                        /* FALLTHRU */

                              case 'O':
                              case 'G':
                              case 'E':
                                        if (reset->arg1 == pObj->vnum)
                                             found = TRUE;
                                        break;
                              }

                              if (!found)
                                        continue;

                              if (!error) {
                                        error = TRUE;
                                        char_puts("ObjEd: can't delete obj "
                                                  "index: delete the "
                                                  "following resets:\n", ch);
                              }

                              char_printf(ch, "ObjEd: room %d, reset %d\n",
                                        room->vnum, j);
                    }
               }
     }

     if (error)
               return FALSE;

/* delete all the instances of obj index */
     for (obj = object_list; obj; obj = obj_next) {
               obj_next = obj->next;

               if (obj->pIndexData == pObj)
                    extract_obj_raw(obj, X_F_NORECURSE);
     }

     if ((area = area_vnum_lookup(pObj->vnum)))
               touch_area(area);

/* delete obj index itself */
     i = pObj->vnum % MAX_KEY_HASH;
     if (pObj == obj_index_hash[i])
               obj_index_hash[i] = pObj->next;
     else {
               OBJ_INDEX_DATA *prev;

               for (prev = obj_index_hash[i]; prev; prev = prev->next)
                    if (prev->next == pObj)
                              break;

               if (prev)
                    prev->next = pObj->next;
     }

     free_obj_index(pObj);
     char_puts("ObjEd: Obj index deleted.\n", ch);
     edit_done(ch->desc);
     return FALSE;
}

/*
 * Need to issue warning if flag isn't valid. -- does so now -- Hugin.
 */
OLC_FUN(objed_addaffect)
{
     int location;
     int modifier;
     flag32_t where;
     flag64_t bitvector;
     OBJ_INDEX_DATA *pObj;
     AFFECT_DATA *pAf;
     char loc[MAX_STRING_LENGTH];
     char mod[MAX_STRING_LENGTH];
     char wh[MAX_STRING_LENGTH];

     EDIT_OBJ(ch, pObj);

     argument = one_argument(argument, loc, sizeof(loc));
     argument = one_argument(argument, mod, sizeof(mod));
     argument = one_argument(argument, wh, sizeof(wh));

     if (loc[0] == '\0') {
               do_help(ch, "'OLC ADDAFFECT'");
               return FALSE;
     }

     if (!str_cmp(loc, "none")) {
               location = APPLY_NONE;
               modifier = 0;
     }
     else {
               if ((location = flag_value(apply_flags, loc)) < 0) {
                    char_puts("Valid locations are:\n", ch);
                    show_flags(ch, apply_flags);
                    return FALSE;
               }

               if (!is_number(mod)) {
                    do_help(ch, "'OLC ADDAFFECT'");
                    return FALSE;
               }
               modifier = atoi(mod);
     }

     if (wh[0] == '\0') {
               where = -1;
               bitvector = 0;
     }
     else {
               where_t *w;

               if ((where = flag_value(apply_types, wh)) < 0) {
                    char_puts("Valid bitaffect locations are:\n", ch);
                    show_flags(ch, apply_types);
                    return FALSE;
               }

               if ((w = where_lookup(where)) == NULL) {
                    char_printf(ch, "%s: not in where_table.\n",
                                   flag_string(apply_types, where));
                    return FALSE;
               }

               if ((bitvector = flag_value(w->table, argument)) == 0) {
                    char_printf(ch, "Valid '%s' bitaffect flags are:\n",
                                   flag_string(apply_types, where));
                    show_flags(ch, w->table);
                    return FALSE;
               }
     }

     pAf             = aff_new();
     pAf->location   = location;
     pAf->modifier   = modifier;
     pAf->where        = where;
     pAf->type       = -1;
     pAf->duration   = -1;
     pAf->bitvector  = bitvector;
     pAf->level      = pObj->level;
     pAf->next       = pObj->affected;
     pObj->affected  = pAf;

     char_puts("Affect added.\n", ch);
     return TRUE;
}

OLC_FUN(objed_addapply)
{
     int location, bv, where;
     OBJ_INDEX_DATA *pObj;
     AFFECT_DATA *pAf;
     where_t *wd;
     char loc[MAX_STRING_LENGTH];
     char mod[MAX_STRING_LENGTH];
     char type[MAX_STRING_LENGTH];
     char bvector[MAX_STRING_LENGTH];

     EDIT_OBJ(ch, pObj);

     argument = one_argument(argument, type, sizeof(type));
     argument = one_argument(argument, loc, sizeof(loc));
     argument = one_argument(argument, mod, sizeof(mod));
     one_argument(argument, bvector, sizeof(bvector));

     if ((where = flag_value(apply_types, type)) < 0) {
               char_puts("Invalid apply type. Valid apply types are:\n", ch);
               show_flags(ch, apply_types);
               return FALSE;
     }

     if ((location = flag_value(apply_flags, loc)) < 0) {
               char_puts("Valid applies are:\n", ch);
               show_flags(ch, apply_flags);
               return FALSE;
     }

     if ((wd = where_lookup(where)) == NULL) {
               char_puts("ObjEd: bit vector table undefined. "
                         "Report it to implementors.\n", ch);
               return FALSE;
     }

     if ((bv = flag_value(wd->table, bvector)) == 0) {
               char_puts("Valid bitvector types are:\n", ch);
               show_flags(ch, wd->table);
               return FALSE;
     }

     if (!is_number(mod)) {
               char_puts("Syntax: addapply type location "
                         "mod bitvector\n", ch);
               return FALSE;
     }

     pAf             = aff_new();
     pAf->location   = location;
     pAf->modifier   = atoi(mod);
     pAf->where        = where;
     pAf->type        = -1;
     pAf->duration   = -1;
     pAf->bitvector  = bv;
     pAf->level      = pObj->level;
     pAf->next       = pObj->affected;
     pObj->affected  = pAf;

     char_puts("Apply added.\n", ch);
     return TRUE;
}

/*
 * My thanks to Hans Hvidsten Birkeland and Noam Krendel(Walker)
 * for really teaching me how to manipulate pointers.
 */
OLC_FUN(objed_delaffect)
{
     OBJ_INDEX_DATA *pObj;
     AFFECT_DATA *pAf;
     AFFECT_DATA *pAf_next;
     char affect[MAX_STRING_LENGTH];
     int  value;
     int  cnt = 0;

     EDIT_OBJ(ch, pObj);

     one_argument(argument, affect, sizeof(affect));

     if (!is_number(affect) || affect[0] == '\0')
     {
               char_puts("Syntax:  delaffect [#xaffect]\n", ch);
               return FALSE;
     }

     value = atoi(affect);

     if (value < 0)
     {
               char_puts("Only non-negative affect-numbers allowed.\n", ch);
               return FALSE;
     }

     if (!(pAf = pObj->affected))
     {
               char_puts("ObjEd:  Non-existant affect.\n", ch);
               return FALSE;
     }

     if(value == 0)        /* First case: Remove first affect */
     {
               pAf = pObj->affected;
               pObj->affected = pAf->next;
               aff_free(pAf);
     }
     else                /* Affect to remove is not the first */
     {
               while ((pAf_next = pAf->next) && (++cnt < value))
                         pAf = pAf_next;

               if(pAf_next)                /* See if it's the next affect */
               {
                    pAf->next = pAf_next->next;
                    aff_free(pAf_next);
               }
               else                                 /* Doesn't exist */
               {
                         char_puts("No such affect.\n", ch);
                         return FALSE;
               }
     }

     char_puts("Affect removed.\n", ch);
     return TRUE;
}

OLC_FUN(objed_name)
{
     OBJ_INDEX_DATA *pObj;
     EDIT_OBJ(ch, pObj);
     return olced_name(ch, argument, cmd, &pObj->name);
}

OLC_FUN(objed_short)
{
     OBJ_INDEX_DATA *pObj;
     EDIT_OBJ(ch, pObj);
     return olced_mlstr(ch, argument, cmd, &pObj->short_descr);
}

OLC_FUN(objed_long)
{
     OBJ_INDEX_DATA *pObj;
     EDIT_OBJ(ch, pObj);
     return olced_mlstr(ch, argument, cmd, &pObj->description);
}

/*****************************************************************************
 Name:                objed_values
 Purpose:        Finds the object and sets its value.
 Called by:        The four valueX functions below. (now five -- Hugin)
 ****************************************************************************/
bool objed_values(CHAR_DATA *ch, const char *argument, int value)
{
     BUFFER *output;
     int errcode = 1;
     OBJ_INDEX_DATA *pObj;
     EDIT_OBJ(ch, pObj);

     output = buf_new(-1);
     if (argument[0] == '\0'
     ||  (errcode = set_obj_values(output, pObj, argument, value)) < 2)
               show_obj_values(output, pObj);
     page_to_char(buf_string(output), ch);
     buf_free(output);
     return !errcode;
}

OLC_FUN(objed_value0)
{
     return objed_values(ch, argument, 0);
}

OLC_FUN(objed_value1)
{
     return objed_values(ch, argument, 1);
}

OLC_FUN(objed_value2)
{
     return objed_values(ch, argument, 2);
}

OLC_FUN(objed_value3)
{
     return objed_values(ch, argument, 3);
}

OLC_FUN(objed_value4)
{
     return objed_values(ch, argument, 4);
}

OLC_FUN(objed_weight)
{
     OBJ_INDEX_DATA *pObj;
     EDIT_OBJ(ch, pObj);
     return olced_number(ch, argument, cmd, &pObj->weight);
}

OLC_FUN(objed_limit)
{
     OBJ_INDEX_DATA *pObj;
     EDIT_OBJ(ch, pObj);
     if (ch->pcdata->security < 10) {
               char_puts("ObjEd: Insufficient security.\n", ch);
               return FALSE;
     }
     return olced_number(ch, argument, cmd, &pObj->limit);
}

OLC_FUN(objed_cost)
{
     OBJ_INDEX_DATA *pObj;
     EDIT_OBJ(ch, pObj);
     return olced_number(ch, argument, cmd, &pObj->cost);
}

OLC_FUN(objed_exd)
{
     OBJ_INDEX_DATA *pObj;
     EDIT_OBJ(ch, pObj);
     return olced_exd(ch, argument, cmd, &pObj->ed);
}

OLC_FUN(objed_extra)
{
     OBJ_INDEX_DATA *pObj;
     EDIT_OBJ(ch, pObj);
     return olced_flag64(ch, argument, cmd, &pObj->extra_flags);
}

OLC_FUN(objed_wear)
{
     OBJ_INDEX_DATA *pObj;
     EDIT_OBJ(ch, pObj);
     return olced_flag64(ch, argument, cmd, &pObj->wear_flags);
}

OLC_FUN(objed_type)
{
     bool changed;
     OBJ_INDEX_DATA *pObj;
     EDIT_OBJ(ch, pObj);
     changed = olced_flag64(ch, argument, cmd, &pObj->item_type);
     if (changed) {
               pObj->value[0] = 0;
               pObj->value[1] = 0;
               pObj->value[2] = 0;
               pObj->value[3] = 0;
               pObj->value[4] = 0;     /* ROM */
     }
     return changed;
}

OLC_FUN(objed_material)
{
     OBJ_INDEX_DATA *pObj;
     int             i;
     int             j;

     j = 1;

     if (argument[0] == '\0')
     {
          char_puts("Syntax: material <material_name>.\n", ch);
          char_puts("        or ? for list.\n", ch);
          return FALSE;
     }
     else
     if (!strcmp(argument, "?"))
     {
          char_puts("Available materials:\n", ch);

          for (i = 0; i < materials.nused; i++)
          {
               char_printf(ch, "[%3d] %-15s  ", i, MATERIAL(i)->ename);
               if (j == 4)
               {
                    send_to_char("\n\r", ch);
                    j=0;
               }
            j++;
          }
          send_to_char("\n\r", ch);
          return FALSE;
     }
     else
     {
          EDIT_OBJ(ch, pObj);
          return olced_str(ch, argument, cmd, &pObj->material);
     }
}

OLC_FUN(objed_level)
{
     OBJ_INDEX_DATA *pObj;
     EDIT_OBJ(ch, pObj);
     return olced_number(ch, argument, cmd, &pObj->level);
}

OLC_FUN(objed_condition)
{
     OBJ_INDEX_DATA *pObj;
     EDIT_OBJ(ch, pObj);
     return olced_number(ch, argument, cmd, &pObj->condition);
}

OLC_FUN(objed_clan)
{
     OBJ_INDEX_DATA *pObj;
     if (ch->pcdata->security < SECURITY_CLANS) {
               char_puts("ObjEd: Insufficient security.\n", ch);
               return FALSE;
     }
     EDIT_OBJ(ch, pObj);
     return olced_clan(ch, argument, cmd, &pObj->clan);
}

OLC_FUN(objed_clone)
{
     OBJ_INDEX_DATA *pObj;
     OBJ_INDEX_DATA *pFrom;
     AREA_DATA *pArea;
     char arg[MAX_INPUT_LENGTH];
     int i;
     AFFECT_DATA *paf;
     AFFECT_DATA *paf_next;
     AFFECT_DATA **ppaf;
     ED_DATA *ed;
     ED_DATA *ed_next;
     ED_DATA **ped;

     one_argument(argument, arg, sizeof(arg));
     if (!is_number(arg)) {
               char_puts("Syntax: clone <vnum>\n", ch);
               return FALSE;
     }

     i = atoi(arg);
     if ((pFrom = get_obj_index(i)) == NULL) {
               char_printf(ch, "ObjEd: %d: Vnum does not exist.\n", i);
               return FALSE;
     }

     pArea = area_vnum_lookup(pFrom->vnum);
     if (!IS_BUILDER(ch, pArea)) {
               char_puts("ObjEd: Insufficient security.\n", ch);
               return FALSE;
     }

     EDIT_OBJ(ch, pObj);
     if (pObj == pFrom)
               return FALSE;

     free_string(pObj->name);
     pObj->name                = str_qdup(pFrom->name);
     free_string(pObj->material);
     pObj->material                = str_qdup(pFrom->material);
     mlstr_free(pObj->short_descr);
     pObj->short_descr        = mlstr_dup(pFrom->short_descr);
     mlstr_free(pObj->description);
     pObj->description        = mlstr_dup(pFrom->description);

     pObj->item_type                = pFrom->item_type;
     pObj->extra_flags        = pFrom->extra_flags;
     pObj->wear_flags        = pFrom->wear_flags;
     pObj->level                = pFrom->level;
     pObj->condition                = pFrom->condition;
     pObj->weight                = pFrom->weight;
     pObj->cost                = pFrom->cost;
     pObj->limit                = pFrom->limit;
     pObj->clan                = pFrom->clan;

     for (i = 0; i < 5; i++)
               pObj->value[i]        = pFrom->value[i];

/* copy affects */
     for (paf = pObj->affected; paf; paf = paf_next) {
               paf_next = paf->next;
               aff_free(paf);
     }

     ppaf = &pObj->affected;
     for (paf = pFrom->affected; paf; paf = paf->next) {
               *ppaf = aff_dup(paf);
               ppaf = &(*ppaf)->next;
     }

/* copy extra descriptions */
     for (ed = pObj->ed; ed; ed = ed_next) {
               ed_next = ed->next;
               ed_free(ed);
     }

     ped = &pObj->ed;
     for (ed = pFrom->ed; ed; ed = ed->next) {
               *ped = ed_dup(ed);
               ped = &(*ped)->next;
     }

     return TRUE;
}

OLC_FUN(objed_gender)
{
    OBJ_INDEX_DATA *pObj;
    EDIT_OBJ(ch, pObj);
    return olced_flag64(ch, argument, cmd, &pObj->gender);
}

void show_obj_values(BUFFER *output, OBJ_INDEX_DATA *pObj)
{
     switch(pObj->item_type) {
     default:        /* No values. */
               buf_add(output, "Currently edited obj has unknown item type.\n");
               /* FALLTHRU */

     case ITEM_TREASURE:
     case ITEM_CLOTHING:
     case ITEM_TRASH:
     case ITEM_KEY:
     case ITEM_BOAT:
     case ITEM_CORPSE_NPC:
     case ITEM_CORPSE_PC:
     case ITEM_PROTECT:
     case ITEM_MAP:
     case ITEM_WARP_STONE :
     case ITEM_ROOM_KEY:
     case ITEM_GEM:
     case ITEM_JEWELRY:
     case ITEM_JUKEBOX:
     case ITEM_TATTOO:
               break;

     case ITEM_LIGHT:
               if (pObj->value[2] == -1 || pObj->value[2] == 999) /* ROM OLC */
                    buf_printf(output, "[v2] Light:  Infinite[-1]\n");
               else
                    buf_printf(output, "[v2] Light:  [%d]\n", pObj->value[2]);
               break;

     case ITEM_WAND:
     case ITEM_STAFF:
               buf_printf(output,
                    "[v0] Level:          [%d]\n"
                    "[v1] Charges Total:  [%d]\n"
                    "[v2] Charges Left:   [%d]\n"
                    "[v3] Spell:          %s\n",
                    pObj->value[0],
                    pObj->value[1],
                    pObj->value[2],
                    skill_name(pObj->value[3]));
               break;

     case ITEM_PORTAL:
               buf_printf(output,
                         "[v0] Charges:        [%d]\n"
                         "[v1] Exit Flags:     %s\n"
                         "[v2] Portal Flags:   %s\n"
                         "[v3] Goes to (vnum): [%d]\n",
                         pObj->value[0],
                         flag_string(exit_flags, pObj->value[1]),
                         flag_string(portal_flags , pObj->value[2]),
                         pObj->value[3]);
               break;

     case ITEM_WINDOW:
               buf_printf(output,
                         "[v0] Room to view: [%d]\n\r"
                         "[v1]             : Reserved\n\r"
                         "[v2]             : Reserved\n\r"
                         "[v3]             : Reserved\n\r"
                         "[v4]             : Reserved\n\r",
                         pObj->value[0] );
               break;

    case ITEM_SLOT_MACHINE:
               buf_printf(output,
               "[v0] Progressive      [%s]\n\r"
               "[v1] Jackpot          [%6d]\n\r",
               flag_string (slot_machine_flags, pObj->value[0]),
               pObj->value[1]);
               break;

     case ITEM_RALTAR:
               buf_printf(output,
                         "[v0] Religion item:        [%d]\n",
                         pObj->value[0]);
               break;

     case ITEM_FURNITURE:
                    buf_printf(output,
                         "[v0] Max people:      [%d]\n"
                         "[v1] Max weight:      [%d]\n"
                         "[v2] Furniture Flags: %s\n"
                         "[v3] Heal bonus:      [%d]\n"
                         "[v4] Mana bonus:      [%d]\n",
                         pObj->value[0],
                         pObj->value[1],
                         flag_string(furniture_flags, pObj->value[2]),
                         pObj->value[3],
                         pObj->value[4]);
               break;

     case ITEM_SCROLL:
     case ITEM_POTION:
     case ITEM_PILL:
               buf_printf(output,
                    "[v0] Level:  [%d]\n"
                    "[v1] Spell:  %s\n"
                    "[v2] Spell:  %s\n"
                    "[v3] Spell:  %s\n"
                    "[v4] Spell:  %s\n",
                    pObj->value[0],
                    skill_name(pObj->value[1]),
                    skill_name(pObj->value[2]),
                    skill_name(pObj->value[3]),
                    skill_name(pObj->value[4]));
               break;

/* ARMOR for ROM */

     case ITEM_ARMOR:
               buf_printf(output,
                    "[v0] Ac pierce       [%d]\n"
                    "[v1] Ac bash         [%d]\n"
                    "[v2] Ac slash        [%d]\n"
                    "[v3] Ac exotic       [%d]\n",
                    pObj->value[0],
                    pObj->value[1],
                    pObj->value[2],
                    pObj->value[3]);
                    break;

/* WEAPON changed in ROM: */
/* I had to split the output here, I have no idea why, but it helped -- Hugin */
/* It somehow fixed a bug in showing scroll/pill/potions too ?! */
     case ITEM_WEAPON:
               buf_printf(output, "[v0] Weapon class:   %s\n",
                         flag_string(weapon_class, pObj->value[0]));
               buf_printf(output, "[v1] Number of dice: [%d]\n", pObj->value[1]);
               buf_printf(output, "[v2] Type of dice:   [%d]\n", pObj->value[2]);
               buf_printf(output, "[v3] Type:           %s\n",
                         attack_table[pObj->value[3]].name);
               buf_printf(output, "[v4] Special type:   %s\n",
                         flag_string(weapon_type2,  pObj->value[4]));
               break;

     case ITEM_CONTAINER:
               buf_printf(output,
                    "[v0] Weight:     [%d kg]\n"
                    "[v1] Flags:      [%s]\n"
                    "[v2] Key:     %s [%d]\n"
                    "[v3] Capacity    [%d]\n"
                    "[v4] Weight Mult [%d]\n",
                    pObj->value[0],
                    flag_string(cont_flags, pObj->value[1]),
                    get_obj_index(pObj->value[2]) ?
                    mlstr_val_true(get_obj_index(pObj->value[2])->short_descr, 0) :
                    "none",
                    pObj->value[2],
                    pObj->value[3],
                    pObj->value[4]);
               break;

     case ITEM_SCABBARD:
               buf_printf(output,
                    "[v0] Weight:     [%d kg]\n"
                    "[v1] Type:       [%d]\n"
                    "[v2] Max Weapons [%d]\n"
                    "[v3] Capacity    [%d]\n"
                    "[v4] Weight Mult [%d]\n",
                              pObj->value[0],
                              pObj->value[1],
                              pObj->value[2],
                    pObj->value[3],
                    pObj->value[4]);
               break;

     case ITEM_KEYRING:
               buf_printf(output,
                    "[v0] Max Keys:   [%d]\n",
                                 pObj->value[0]);
              break;

     case ITEM_DRINK_CON:
               buf_printf(output,
                         "[v0] Liquid Total: [%d]\n"
                         "[v1] Liquid Left:  [%d]\n"
                         "[v2] Liquid:       %s\n"
                         "[v3] Poisoned:     %s\n",
                         pObj->value[0],
                         pObj->value[1],
                         //liq_table[pObj->value[2]].liq_name,
                         liquid_name(pObj->value[2]),
                         pObj->value[3] ? "Yes" : "No");
               break;

     case ITEM_FOUNTAIN:
               buf_printf(output,
                         "[v0] Liquid Total: [%d]\n"
                         "[v1] Liquid Left:  [%d]\n"
                         "[v2] Liquid:            %s\n",
                         pObj->value[0],
                         pObj->value[1],
                         //liq_table[pObj->value[2]].liq_name);
                         liquid_name(pObj->value[2]));
               break;

     case ITEM_FOOD:
               buf_printf(output,
                    "[v0] Food hours: [%d]\n"
                    "[v1] Full hours: [%d]\n"
                    "[v3] Poisoned:   %s\n",
                    pObj->value[0],
                    pObj->value[1],
                    pObj->value[3] ? "Yes" : "No");
               break;

     case ITEM_RIDDLE:
               buf_printf(output, "[v0] min_vnum: [%d]\n", pObj->value[0]);
               buf_printf(output, "[v1] max_vnim: [%d]\n", pObj->value[1]);
               break;

     case ITEM_MONEY:
               buf_printf(output, "[v0] Silver: [%d]\n", pObj->value[0]);
               buf_printf(output, "[v1] Gold:   [%d]\n", pObj->value[1]);
               break;

     case ITEM_PAINT:
               buf_printf(output,
                         "[v0] Color:        [%s]\n",
                         flag_string(paint_color_int_flags, pObj->value[0]));
               if (pObj->value[1] != -1)
                   buf_printf(output, "[v1] Portions:     [%d]\n", pObj->value[1]);
               else
                   buf_printf(output, "[v1] Portions:     [infinite]\n", pObj->value[1]);
               buf_printf(output, "Power: %d\n", pObj->value[2]);
               break;
     case ITEM_LEARN_BOOK:
               buf_printf(output,
                    "[v0] Prcent:       [%d]\n"
                    "[v1] Max. percent: [%d]\n"
                    "[v2] Skill:        [%s]\n",
                    pObj->value[0],
                    pObj->value[1],
                    skill_name(pObj->value[2]));
               break;

     }
}

/*
 * Return values:
 *        0 - pObj was changed successfully
 *        1 - pObj was not changed
 *        2 - pObj was not changed, do not show obj values
 */
int set_obj_values(BUFFER *output, OBJ_INDEX_DATA *pObj, const char *argument, int value_num)
{
     switch (pObj->item_type)
     {
     int        val;

     default:
     return 1;

     case ITEM_LIGHT:
               switch (value_num) {
               default:
                    return 1;
               case 2:
                    buf_add(output, "HOURS OF LIGHT SET.\n\n");
                    pObj->value[2] = atoi(argument);
                    break;
               }
               break;

     case ITEM_WAND:
     case ITEM_STAFF:
               switch (value_num) {
               default:
                    return 1;
               case 0:
                    buf_add(output, "SPELL LEVEL SET.\n\n");
                    pObj->value[0] = atoi(argument);
                    break;
               case 1:
                    buf_add(output, "TOTAL NUMBER OF CHARGES SET.\n\n");
                    pObj->value[1] = atoi(argument);
                    break;
               case 2:
                    buf_add(output, "CURRENT NUMBER OF CHARGES SET.\n\n");
                    pObj->value[2] = atoi(argument);
                    break;
               case 3:
                    if (!str_cmp(argument, "?")
                    ||  (val = sn_lookup(argument)) < 0) {
                              show_spells(output, -1);
                              return 2;
                    }
                    buf_add(output, "SPELL TYPE SET.\n");
                    pObj->value[3] = val;
                    break;
               }
               break;
     
      case ITEM_KEYRING:
               switch (value_num) 
               {
               default:
                    break;
                   case 0:
                    if(atoi(argument) < 0 || atoi(argument) > 50)
                    {
                          buf_add(output, "Max keys must be in interval 0 .. 50.\n\n");
                          return -1;
                    }
                    buf_add(output, "Max keys set.\n\n");
                    pObj->value[0] = atoi(argument);
                    break;
               }
               break;

     case ITEM_SCROLL:
     case ITEM_POTION:
     case ITEM_PILL:
               switch (value_num) {
               case 0:
                    buf_add(output, "SPELL LEVEL SET.\n\n");
                    pObj->value[0] = atoi(argument);
                    break;
               case 1:
               case 2:
               case 3:
               case 4:
                    if (!str_cmp(argument, "none")
                    || (!str_cmp(argument, "-1"))) {
                              pObj->value[value_num] = -1;
                              break;
                    }
                    if (!str_cmp(argument, "?")
                    ||  (val = sn_lookup(argument)) < 0) {
                              show_spells(output, -1);
                              return 2;
                    }
                    buf_printf(output, "SPELL TYPE %d SET.\n\n", value_num);
                    pObj->value[value_num] = val;
                    break;
               }
               break;

/* ARMOR for ROM: */

     case ITEM_ARMOR:
               switch (value_num) {
               default:
                    return 1;
               case 0:
                    buf_add(output, "AC PIERCE SET.\n\n");
                    pObj->value[0] = atoi(argument);
                    break;
               case 1:
                    buf_add(output, "AC BASH SET.\n\n");
                    pObj->value[1] = atoi(argument);
                    break;
               case 2:
                    buf_add(output, "AC SLASH SET.\n\n");
                    pObj->value[2] = atoi(argument);
                    break;
               case 3:
                    buf_add(output, "AC EXOTIC SET.\n\n");
                    pObj->value[3] = atoi(argument);
                    break;
               }
               break;

/* WEAPONS changed in ROM */

     case ITEM_WEAPON:
               switch (value_num) {
               case 0:
                    if (!str_cmp(argument, "?")
                    ||  (val = flag_value(weapon_class, argument)) < 0) {
                              show_flags_buf(output, weapon_class);
                              return 2;
                    }
                    buf_add(output, "WEAPON CLASS SET.\n\n");
                    pObj->value[0] = val;
                    break;
               case 1:
                    buf_add(output, "NUMBER OF DICE SET.\n\n");
                    pObj->value[1] = atoi(argument);
                    break;
               case 2:
                    buf_add(output, "TYPE OF DICE SET.\n\n");
                    pObj->value[2] = atoi(argument);
                    break;
               case 3:
                    if (!str_cmp(argument, "?")
                    ||  (val = attack_lookup(argument)) < 0) {
                              show_attack_types(output);
                              return 2;
                    }
                    buf_add(output, "WEAPON TYPE SET.\n\n");
                    pObj->value[3] = val;
                    break;
               case 4:
                    if (!str_cmp(argument, "?")
                    ||  (val = flag_value(weapon_type2, argument)) < 0) {
                              show_flags_buf(output, weapon_type2);
                              return 2;
                    }
                    buf_add(output, "SPECIAL WEAPON TYPE TOGGLED.\n\n");
                    TOGGLE_BIT(pObj->value[4], val);
                    break;
               }
               break;

     case ITEM_PAINT:
               switch (value_num)
               {
               default:
                    return 1;
               case 0:
                    if (!str_cmp(argument, "?")
                        || (val = flag_value(paint_color_int_flags, argument)) < 0)
                    {
                        show_flags_buf(output, paint_color_int_flags);
                        return 2;
                    }
                    buf_add(output, "COLOR SET.\n\n");
                    pObj->value[0] = val;
                    break;
               case 1:
                    buf_add(output, "PORTION COUNT SET.\n\n");
                    pObj->value[1] = atoi(argument);
               case 2:
                    buf_add(output, "POWER SET.\n\n");
                    pObj->value[2] = atoi(argument);
               }
               break;

     case ITEM_LEARN_BOOK:
               switch (value_num) 
               {
               case 0:
                    buf_add(output, "PERCENT SET.\n\n");
                    pObj->value[0] = atoi(argument);
                    break;
               case 1:
                    buf_add(output, "MAX. PERCENT SET.\n\n");
                    pObj->value[1] = atoi(argument);
                    break;
               case 2:
                    if (!str_cmp(argument, "none")
                    || (!str_cmp(argument, "-1"))) {
                              pObj->value[value_num] = -1;
                              break;
                    }
                    if (!str_cmp(argument, "?")
                    ||  (val = sn_lookup(argument)) < 0) {
                              show_spells(output, -1);
                              return 2;
                    }
                    buf_printf(output, "SKILL TYPE %d SET.\n\n", value_num);
                    pObj->value[value_num] = val;
                    break;
               }
               break;

     case ITEM_PORTAL:
               switch (value_num) {
               default:
                    return 1;
               case 0:
                    buf_add(output, "CHARGES SET.\n\n");
                    pObj->value[0] = atoi(argument);
                    break;
               case 1:
                    if (!str_cmp(argument, "?")
                    ||  (val = flag_value(exit_flags, argument)) < 0) {
                              show_flags_buf(output, exit_flags);
                              return 2;
                    }
                    buf_add(output, "EXIT FLAGS TOGGLED.\n\n");
                    TOGGLE_BIT(pObj->value[1], val);
                    break;
               case 2:
                    if (!str_cmp(argument, "?")
                    ||  (val = flag_value(portal_flags, argument)) < 0) {
                              show_flags_buf(output, portal_flags);
                              return 2;
                    }
                    buf_add(output, "PORTAL FLAGS TOGGLED.\n\n");
                    TOGGLE_BIT(pObj->value[2], val);
                    break;
               case 3:
                    buf_add(output, "EXIT VNUM SET.\n\n");
                    pObj->value[3] = atoi(argument);
                    break;
               }
               break;

     case ITEM_RALTAR:
               switch (value_num) {
               default:
                    return 1;
               case 0:
                    if(!validate_item_vnum(argument))
                    {
                        buf_add(output, "Not such obj with this vnum.\n");
                        return 2;
                    }

                    buf_add(output, "Religion item set.\n\n");
                    pObj->value[0] = atoi(argument);
                    break;
               }
               break;

     case ITEM_FURNITURE:
               switch (value_num) {
               case 0:
                    buf_add(output, "NUMBER OF PEOPLE SET.\n\n");
                    pObj->value[0] = atoi(argument);
                    break;
               case 1:
                    buf_add(output, "MAX WEIGHT SET.\n\n");
                    pObj->value[1] = atoi(argument);
                    break;
               case 2:
                    if (!str_cmp(argument, "?")
                    ||  (val = flag_value(furniture_flags, argument)) < 0) {
                              show_flags_buf(output, furniture_flags);
                              return 2;
                    }
                    buf_add(output, "FURNITURE FLAGS TOGGLED.\n\n");
                    TOGGLE_BIT(pObj->value[2], val);
                    break;
               case 3:
                    buf_add(output, "HEAL BONUS SET.\n\n");
                    pObj->value[3] = atoi(argument);
                    break;
               case 4:
                    buf_add(output, "MANA BONUS SET.\n\n");
                    pObj->value[4] = atoi(argument);
                    break;
               }
               break;

     case ITEM_SCABBARD:
               switch (value_num) {
               case 0:
                    buf_add(output, "WEIGHT CAPACITY SET.\n\n");
                    pObj->value[0] = atoi(argument);
                    break;
               case 1:
                    if (!str_cmp(argument, "?")) {
                              return 2;
                    }
                    buf_add(output, "WEAPON CONTAINER TYPE SET.\n\n");
                    pObj->value[1] = atoi(argument);
                    break;
               case 2:
                    buf_add(output, "WEAPON CONTAINER MAX WEAPONS SET.\n");
                    pObj->value[2] = atoi(argument);
                    break;
               case 3:
                    buf_add(output, "WEAPON CONTAINER MAX WEIGHT SET.\n");
                    pObj->value[3] = atoi(argument);
                    break;
               case 4:
                    buf_add(output, "WEIGHT MULTIPLIER SET.\n\n");
                    pObj->value[4] = atoi(argument);
                    break;
               }
               break;

     case ITEM_CONTAINER:
               switch (value_num) {
               case 0:
                    buf_add(output, "WEIGHT CAPACITY SET.\n\n");
                    pObj->value[0] = atoi(argument);
                    break;
               case 1:
                    if (!str_cmp(argument, "?")  ||  (val = flag_value(cont_flags, argument)) < 0)
          {
                              show_flags_buf(output, cont_flags);
                              return 2;
                    }
                    buf_add(output, "CONTAINER TYPE SET.\n\n");
                    TOGGLE_BIT(pObj->value[1], val);
                    break;
               case 2:
                    if (atoi(argument) != 0) {
                              if (!get_obj_index(atoi(argument))) {
                                        buf_add(output, "THERE IS NO SUCH ITEM.\n\n");
                                        return 1;
                              }

                              if (get_obj_index(atoi(argument))->item_type != ITEM_KEY) {
                                        buf_add(output, "THAT ITEM IS NOT A KEY.\n\n");
                                        return 1;
                              }
                    }
                    buf_add(output, "CONTAINER KEY SET.\n\n");
                    pObj->value[2] = atoi(argument);
                    break;
               case 3:
                    buf_add(output, "CONTAINER MAX WEIGHT SET.\n");
                    pObj->value[3] = atoi(argument);
                    break;
               case 4:
                    buf_add(output, "WEIGHT MULTIPLIER SET.\n\n");
                    pObj->value[4] = atoi(argument);
                    break;
               }
               break;

     case ITEM_DRINK_CON:
               switch (value_num) {
               default:
                    return 1;
               case 0:
                    buf_add(output, "MAXIMUM AMOUT OF LIQUID HOURS SET.\n\n");
                    pObj->value[0] = atoi(argument);
                    break;
               case 1:
                    buf_add(output, "CURRENT AMOUNT OF LIQUID HOURS SET.\n\n");
                    pObj->value[1] = atoi(argument);
                    break;
               case 2:
                    if (!str_cmp(argument, "?")
                    ||  (val = liquid_lookup(argument)) < 0)
                    {
                              show_liquid_types(output);
                              return 2;
                    }
                    buf_add(output, "LIQUID TYPE SET.\n\n");
                    pObj->value[2] = val;
                    break;
               case 3:
                    buf_add(output, "POISON VALUE TOGGLED.\n\n");
                    pObj->value[3] = !pObj->value[3];
                    break;
               }
               break;

     case ITEM_FOUNTAIN:
               switch (value_num) {
               default:
                    return 1;
               case 0:
                    buf_add(output, "MAXIMUM AMOUT OF LIQUID HOURS SET.\n\n");
                    pObj->value[0] = atoi(argument);
                    break;
               case 1:
                    buf_add(output, "CURRENT AMOUNT OF LIQUID HOURS SET.\n\n");
                    pObj->value[1] = atoi(argument);
                    break;
               case 2:
                    if (!str_cmp(argument, "?")
                    //||  (val = liq_lookup(argument)) < 0)
                    ||  (val = liquid_lookup(argument)) < 0)
                    {
                              show_liquid_types(output);
                              return 2;
                    }
                    buf_add(output, "LIQUID TYPE SET.\n\n");
                    pObj->value[2] = val;
                    break;
               }
               break;

     case ITEM_FOOD:
               switch (value_num) {
               default:
                    return 1;
               case 0:
                    buf_add(output, "HOURS OF FOOD SET.\n\n");
                    pObj->value[0] = atoi(argument);
                    break;
               case 1:
                    buf_add(output, "HOURS OF FULL SET.\n\n");
                    pObj->value[1] = atoi(argument);
                    break;
               case 3:
                    buf_add(output, "POISON VALUE TOGGLED.\n\n");
                    pObj->value[3] = !pObj->value[3];
                    break;
               }
               break;

     case ITEM_WINDOW:

               switch ( value_num )
               {
               default:
                    buf_add(output, "set v0 to the destination window, or to zero if you wish to use the windows description \n");
                    return FALSE;
               case 0:
          buf_add(output, "VIEWING ROOM SET.\n\r\n\r");
                    if (get_room_index(atoi(argument))== NULL)
                    {
                              buf_add(output, "Not such room with this VNUM.\n\r");
               pObj->value[0] = 0;
          } else
               pObj->value[0] = atoi(argument);
          break;
     }
     break;

case ITEM_SLOT_MACHINE:

     switch ( value_num ) {
          default:
                    //do_help( ch, "ITEM_SLOT_MACHINE" );
               return FALSE;
     case 0:
               if (!str_cmp(argument, "?") ||  (val = flag_value(slot_machine_flags, argument)) < 0)
               {
                    show_flags_buf(output, slot_machine_flags);
                    return 2;
               }

               pObj->value[0] = val;
               buf_add(output, "PROGRESSIVE VALUE SET.\n\r\n\r");
                         break;

     case 1:
               buf_add(output, "JACKPOT SET.\n\r\n\r");
               pObj->value[1] = atoi( argument );
                    break;
          }
break;

case ITEM_RIDDLE:
               switch ( value_num )
               {
               default:
                    buf_add(output, "Set v0 and v1 to riddle mob's VNUMs. 0 - random riddle.\n");
                    return FALSE;
               case 0:
          buf_add(output, "RIDDLE MIN NUM SET.\n\n");
          pObj->value[0] = atoi(argument);
          break;
               case 1:
          buf_add(output, "RIDDLE MAX NUM SET.\n\n");
          pObj->value[1] = atoi(argument);
          break;
     }
          break;

     case ITEM_MONEY:
               switch (value_num) {
               default:
                    return 1;
               case 0:
                    buf_add(output, "SILVER AMOUNT SET.\n\n");
                    pObj->value[0] = atoi(argument);
                    break;
               case 1:
                    buf_add(output, "GOLD AMOUNT SET.\n\n");
                    pObj->value[1] = atoi(argument);
                    break;
               }
               break;
     }

     return 0;
}

/*****************************************************************************
Name:                show_spells
Purpose:        Displays all spells.
***************************************************************************/
static void show_spells(BUFFER *output, int tar)
{
     int  sn;
     int  col;

     col = 0;
     for (sn = 0; sn < skills.nused; sn++) {
               skill_t *sk = SKILL(sn);

               if (!str_cmp(sk->name, "reserved") || sk->spell_fun == NULL)
                    continue;

               if (tar == -1 || sk->target == tar) {
                    buf_printf(output, "%-19.18s", sk->name);
                    if (++col % 4 == 0)
                              buf_add(output, "\n");
               }
     }

     if (col % 4 != 0)
               buf_add(output, "\n");
}
/*
void show_liqlist(CHAR_DATA *ch)
{
     int liq;
     BUFFER *buffer;

     buffer = buf_new(-1);

     for (liq = 0; liq_table[liq].liq_name != NULL; liq++)
     {
               if ((liq % 21) == 0)
                    buf_add(buffer,"Name                 Color          Proof Full Thirst Food Ssize\n");

               buf_printf(buffer, "%-20s %-14s %5d %4d %6d %4d %5d\n",
                    liq_table[liq].liq_name,liq_table[liq].liq_color,
                    liq_table[liq].liq_affect[0],liq_table[liq].liq_affect[1],
                    liq_table[liq].liq_affect[2],liq_table[liq].liq_affect[3],
                    liq_table[liq].liq_affect[4]);
     }

     page_to_char(buf_string(buffer), ch);
     buf_free(buffer);
}
*/
#if 0
struct fignya_t
{
     const char         *name;
     flag64_t                *type;
     const char         *desc;
};

struct fignya_t fignya[] =
{
     { "type",            item_types,            "Types of objects."                    },
     { "extra",      extra_flags,        "Object attributes."                },
     { "wear",            wear_flags,            "Where to wear object."                },
     { "wear-loc",        wear_loc_flags,        "Where mobile wears object."},
     { "container",        cont_flags,     "Container status."                    },

/* ROM specific bits: */

     { "armor",            ac_type,            "Ac for different attacks."        },
     { "apply",            apply_flags,        "Apply flags"                        },
     { "wclass",     weapon_class,   "Weapon class."             },
     { "wtype",      weapon_type2,   "Special weapon type."      },
     { "portal",            portal_flags,        "Portal types."                        },
     { "furniture",        furniture_flags,"Furniture types."                    },
     { "liquid",            liq_table,            "Liquid types."                        },
     { "apptype",        apply_types,        "Apply types."                             },
     { "weapon",            attack_table,        "Weapon types."                        },
     { NULL,                    NULL,                     NULL                                        }
};
#endif

VALIDATE_FUN(validate_condition)
{
     int val = *(int*) arg;

     if (val < 0 || val > 100)
     {
               char_puts("ObjEd: condition can range from 0 (ruined) "
                         "to 100 (perfect).\n", ch);
               return FALSE;
     }
     return TRUE;
}

VALIDATE_FUN(validate_material)
{
     if (material_n_lookup(arg) < 0)
     {
          char_puts("ObjEd: not such material.\n", ch);
          return FALSE;
     }

     return TRUE;
}

OLC_FUN(objed_obj_prog)
{
     OBJ_INDEX_DATA *pObj;
     int opindex, i;
     OPROG_DATA *oprog;
     char arg[MAX_STRING_LENGTH];
     EDIT_OBJ(ch, pObj);

     argument = one_argument(argument, arg, sizeof(arg));

     if (arg[0] == '\0')
     {
          char_puts("Syntax: obj_prog <prog_type> <prog_name>\n", ch);
          char_puts("Syntax: obj_prog <prog_type> delete\n", ch);
          char_puts("Syntax: obj_prog ?\n", ch);
          return FALSE;
     }

     if (!strcmp(arg, "?"))
     {
          char_puts("Available obj progs types:\n", ch);
          for (i = 0; optype_table[i] != NULL; i++)
          {
               char_printf(ch, "%s", optype_table[i]);
               if ((i+1) % 6 == 0)
                         char_puts("\n", ch);
               else
                         char_puts(", ", ch);
          }
               return FALSE;
     }

     opindex = optype_lookup(arg);
     if (opindex == -1)
     {
          char_printf(ch, "ObjEd: unknown obj prog type `%s'", arg);
          return FALSE;
     }

     one_argument(argument, arg, sizeof(arg));

     if(!strcmp(arg, "delete"))
     {
          if (pObj->oprogs_old[opindex] == NULL)
          {
               char_puts("ObjEd: no obj prog of this type", ch);
               return FALSE;
          }
          pObj->oprogs_old[opindex] = NULL;

          for (i = 0; i < OPROG_MAX; i++)
               if (pObj->oprogs_old[i] != NULL)
                         return TRUE;
          free(pObj->oprogs_old);
          pObj->oprogs_old = NULL;
          return TRUE;
     }

     oprog = oprog_lookup(arg);
     if (oprog == NULL)
     {
          char_printf(ch, "ObjEd: unknown obj prog `%s'", arg);
          return FALSE;
     }

     if (pObj->oprogs_old == NULL)
               pObj->oprogs_old = calloc(1, sizeof(*pObj->oprogs_old) * OPROG_MAX);
     pObj->oprogs_old[opindex] = oprog->fn;

     return TRUE;
}

OLC_FUN(objed_trigadd)
{
     int value;
     OBJ_INDEX_DATA *pObj;
     MPTRIG *optrig;
     MPCODE *opcode;
     char trigger[MAX_STRING_LENGTH];
     char num[MAX_STRING_LENGTH];

     EDIT_OBJ(ch, pObj);
     argument = one_argument(argument, num, sizeof(num));
     argument = one_argument(argument, trigger, sizeof(trigger));

     if (!str_cmp(num, "?"))
     {
               show_flags(ch, oprog_flags);
               return FALSE;
     }

     if (!is_number(num) || trigger[0] =='\0' || argument[0] =='\0')
     {
               char_puts("Syntax: trigadd [vnum] [trigger] [phrase]\n",ch);
               return FALSE;
     }

     if ((value = flag_value(oprog_flags, trigger)) < 0)
     {
               char_puts("Invalid trigger type.\n"
               "Use 'trigadd ?' for list of triggers.\n", ch);
               return FALSE;
     }

     if ((opcode = opcode_lookup(atoi(num))) == NULL)
     {
               char_puts("No such OBJProgram.\n", ch);
               return FALSE;
     }

     optrig = optrig_new(value, argument, atoi(num));
     optrig_add(pObj, optrig);
     char_puts("Trigger added.\n",ch);
     return TRUE;
}

OLC_FUN(objed_trigdel)
{
     OBJ_INDEX_DATA *pObj;
     MPTRIG *optrig;
     MPTRIG *optrig_next;
     char oprog[MAX_STRING_LENGTH];
     int value;
     int cnt = 0;

     EDIT_OBJ(ch, pObj);

     one_argument(argument, oprog, sizeof(oprog));
     if (!is_number(oprog) || oprog[0] == '\0')
{
               char_puts("Syntax:  trigdel [#oprog]\n",ch);
               return FALSE;
     }

     value = atoi (oprog);

     if (value < 0)
{
               char_puts("Only non-negative oprog-numbers allowed.\n",ch);
               return FALSE;
     }

     if (!(optrig = pObj->oprogs))
{
               char_puts("ObjEd:  Nonexistent trigger.\n",ch);
               return FALSE;
     }

     if (value == 0)
{
               REMOVE_BIT(pObj->oprog_flags, pObj->oprogs->type);
               optrig = pObj->oprogs;
               pObj->oprogs = optrig->next;
               optrig_free(optrig);
     }
     else {
               while ((optrig_next = optrig->next) && (++cnt < value))
                    optrig = optrig_next;

               if (optrig_next)
     {
                    REMOVE_BIT(pObj->oprog_flags, optrig_next->type);
                    optrig->next = optrig_next->next;
                    optrig_free(optrig_next);
               }
               else
     {
                    char_puts("No such trigger.\n",ch);
                    return FALSE;
               }
     }
     optrig_fix(pObj);

     char_puts("Trigger removed.\n", ch);
     return TRUE;
}

OLC_FUN(objed_riddle)
{
    OBJ_INDEX_DATA *pObj;
    int riddle_vnum;

    EDIT_OBJ(ch, pObj);
    if ((pObj->item_type != ITEM_PORTAL) && (pObj->item_type != ITEM_CONTAINER))
    {
        char_act("Item of this type can't be associated with riddle.", ch);
        return FALSE;
    }

    riddle_vnum = atoi(argument);
    pObj->riddle = riddle_vnum;
    char_act("Riddle VNUM set. Ok.", ch);
    return TRUE;
}

OLC_FUN(objed_size)
{
     OBJ_INDEX_DATA *pObj;
     EDIT_OBJ(ch, pObj);
     return olced_number(ch, argument, cmd, &pObj->size);
}