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: keyring.c,v 1.666 2004/09/20 10:49:49 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.                                                *
 *                                                                                  *
 ************************************************************************************/
/************************************************************************************
 * Original eyring [C] 2002 Petr [Dingo] Dvorak <dingo@texoma.net>                  *
 *                                                                                  *
 * Written for Anime Planet MUD [animeplanet.genesismuds.com:3333 ]                 *
 ************************************************************************************/

#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"
#include "db/db.h"

extern char *format_obj_to_char(OBJ_DATA *obj, CHAR_DATA *ch, bool fShort);

KEY_DATA * new_key(void)
{
    KEY_DATA * key;

    key = calloc(1,sizeof(*key));
    VALIDATE(key);

    return key;
}

void free_key(KEY_DATA * key)
{
    if (!key || !IS_VALID(key))
        return;

    key->next  = NULL;
    key->index = NULL;
    INVALIDATE(key);

    free(key);

    return;
}

// adds key to the keyring
int add_key(OBJ_DATA * keyring, OBJ_DATA * key)
{
    KEY_DATA * nkey;
    int        i;


    if (!keyring)
        return KEYRING_NO_KEYRING;
    if (!key)
        return KEYRING_NO_KEY;
    if (!IS_VALID(keyring))
        return KEYRING_INVALID_KEYRING;
    if (!IS_VALID(key))
        return KEYRING_INVALID_KEY;

    i = 0;

    for (nkey = keyring->keys; nkey != NULL; nkey = nkey->next)
    {
        i++;

        if (nkey->index == key->pIndexData)
            return KEYRING_KEY_DUP; //TODO: May be allow dups keys
    }

    if( i >= keyring->value[0])
        return KEYRING_MAX_REACHED;

    if ((IS_OBJ_STAT(key, ITEM_NODROP) || IS_OBJ_STAT(key, ITEM_NOREMOVE)))
        return KEYRING_CURSED;

    nkey = new_key();

    nkey->index = key->pIndexData;

    nkey->next = keyring->keys;
    keyring->keys = nkey;

    obj_from_char(key);
    extract_obj(key);

    return KEYRING_OK;
}


int remove_key(CHAR_DATA * ch, OBJ_DATA * keyring, char * name)
{
    KEY_DATA    * key;
    KEY_DATA    * key_next;

    if (!keyring)
        return KEYRING_NO_KEYRING;
    if (!keyring->keys)
        return KEYRING_NO_KEY;
    if (!name)
        return KEYRING_INVALID_NAME;
    if (name[0] == '\0')
        return KEYRING_INVALID_NAME;

    // let's find the key
    for (key = keyring->keys; key != NULL; key = key_next)
    {
        key_next = key->next;

        // check the name
        if (key && key->index->name && !str_prefix(name, key->index->name))
        {
            OBJ_DATA *phys_key;

            phys_key = create_obj(key->index,key->index->level);
            obj_to_char(phys_key, ch);

            if (keyring->keys == key)
                keyring->keys = key->next;
            else
            {
                KEY_DATA *prev;

                for (prev = keyring->keys; prev != NULL; prev = prev->next)
                {
                    if (prev->next == key)
                    {
                        // drop the key from the ring;
                        prev->next = key->next;
                        break;
                    }
                }
            }

            free_key(key);

            return KEYRING_OK;
        }
    }

    return KEYRING_NO_REMKEY;
}

void save_keyring(FILE * fp, OBJ_DATA * obj)
{
    KEY_DATA *  keys;

    if (!obj || !obj->keys)
        return;

    fprintf(fp, "Keyring  ");

    for (keys = obj->keys; keys != NULL; keys = keys->next)
    {
        if (keys->index->vnum)
            fprintf(fp, "%d ", keys->index->vnum);
    }

    // save -1 on the end of the list to terminate it
    fprintf(fp,"-1\n\r");

    return;
}

void load_keyring(FILE * fp, OBJ_DATA * obj)
{
    int         vnum = 0;
    KEY_DATA *  nkey;

    do
    {
        vnum = fread_number(fp);
        if (vnum > 0)
        {
            nkey = new_key();

            nkey->index = get_obj_index(vnum);
            nkey->next = obj->keys;
            obj->keys = nkey;
        }
    }
    while (vnum > 0);

    return;
}


void list_keys(CHAR_DATA * ch, OBJ_DATA * keyring)
{
    KEY_DATA    * key;
    char          buf[MAX_STRING_LENGTH];
    //char        * buf;

    if (keyring == NULL)
        return;

    if (!keyring->keys)
    {
        char_act("The keyring is empty.",ch);
        return;
    }

    char_act("\n\rThe keyring contains the following keys:\n\r",ch);

    for (key = keyring->keys; key != NULL; key = key->next)
    {
        buf[0] = '\0';

        if (IS_IMMORTAL(ch))
            char_printf(ch,"{D[{C%5.5d{D]{x",key->index->vnum);
            char_printf(ch,"    %s.\n\r", key->index->short_descr ? mlstr_val(key->index->short_descr, ch->lang) : "Unknown");
    }

    return;
}

OBJ_DATA * find_keyring(CHAR_DATA * ch)
{
    OBJ_DATA *obj;

    // search players inventory for keyring object
    for (obj = ch->carrying; obj != NULL; obj = obj->next_content)
    {
        if ((can_see_obj(ch, obj))   &&   obj->pIndexData->item_type == ITEM_KEYRING)
            return obj;
    }
    return NULL;
}

void keyring_message(int message, CHAR_DATA * ch, OBJ_DATA * key)
{

    switch (message)
    {
    case KEYRING_OK:                     // everything ok .. what are we doing here ?
        return;
        break;
    case KEYRING_NO_KEYRING:             // no keyring
        char_act("You don't have a keyring, go buy one.",ch);
        break;
    case KEYRING_NO_KEY:                 // no key
        char_act("You don't have that key.",ch);
        break;
    case KEYRING_NO_REMKEY:              // no key on keyring
        char_act("You don't have that key on your keyring.",ch);
        break;
    case KEYRING_KEY_DUP:
        char_printf(ch, "You already have %s on your keyring.\n\r",mlstr_val(key->short_descr, ch->lang));
        break;
    case KEYRING_MAX_REACHED:
        char_act("You already have max keys on your keyring.",ch);
        break;
    case KEYRING_CURSED:
        char_act("You cannot add cursed key on your keyring.",ch);
        break;
    case KEYRING_INVALID_NAME:
    case KEYRING_INVALID_KEYRING:
    case KEYRING_INVALID_KEY:
    default:
        char_act("Something gone horribly wrong, please tell the nearest immortal.",ch);
        break;
    }

    return;
}

void do_keyring(CHAR_DATA * ch, const char *argument)
{
    OBJ_DATA *  keyring = NULL;
    OBJ_DATA *  key = NULL;
    char        arg1[MAX_INPUT_LENGTH];
    char        arg2[MAX_INPUT_LENGTH];
    int         message = KEYRING_OK;
    const char *msg;

    keyring = find_keyring(ch);

    if (!keyring)
    {
        keyring_message(KEYRING_NO_KEYRING,ch,NULL);
        return;
    }

    // no arguments ? just show list of the keys on the keyring then.
    if (argument[0] == '\0')
    {
        // yes i know, this is really filthy way to do this, but this way it
        // will show the same stuff like if people examine normal object
        // every mud is little different :)
        do_examine(ch, keyring->name);
        return;
    }

    argument = one_argument(argument, arg1, sizeof(arg1));  // command - add | remove
    argument = one_argument(argument, arg2, sizeof(arg2));  // key name

    if (arg2[0] == '\0')
    {
        char_act("You must specify the name of the key you wish to add or remove.", ch);
        return;
    }

    if (is_name(arg1, "add"))
    {
        key = get_obj_carry(ch, arg2);

        if (!key)
        {
            char_act("You don't have that key.", ch);
            return;
        }

        if (key->pIndexData->item_type != ITEM_KEY)
        {
            char_act("That is not a key!", ch);
            return;
        }

        msg = mlstr_val(key->short_descr, ch->lang);
        message = add_key(keyring, key);

        if (!message)
        {
            act_puts("$n adds $p on $s keyring.", ch, key, NULL, TO_ROOM, POS_RESTING);
            char_printf(ch, "You added %s on your keyring.\n\r", msg);
        }
        else
        {
            keyring_message(message,ch,key);
        }
    }
    else if (is_name(arg1, "remove"))
    {
        message = remove_key(ch, keyring, arg2);
        if (!message)
        {
            act_puts("$n removes a key from $s keyring.", ch, NULL, NULL, TO_ROOM, POS_RESTING);
            act_puts("You removed a key from your keyring.", ch, NULL, NULL, TO_CHAR, POS_RESTING);
        }
        else
        {
            keyring_message(message,ch,NULL);
        }
    }
    else
    {
        char_act("What exactly do you want to do with the keyring ?", ch);
        return;
    }

    return;
}