/* $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;
}