//*****************************************************************************
//
// utils.c
//
// This file contains all sorts of utility functions used
// all sorts of places in the code.
//
//*****************************************************************************
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <dirent.h>
#include <time.h>
// include main header file
#include "mud.h"
#include "prototype.h"
#include "character.h"
#include "object.h"
#include "world.h"
#include "zone.h"
#include "room.h"
#include "room_reset.h"
#include "exit.h"
#include "socket.h"
#include "utils.h"
#include "save.h"
#include "handler.h"
#include "inform.h"
#include "event.h"
#include "action.h"
#include "hooks.h"
//*****************************************************************************
// mandatory modules
//*****************************************************************************
#include "items/items.h"
//*****************************************************************************
// implementation of utils.h
//*****************************************************************************
void extract_obj_final(OBJ_DATA *obj) {
obj_from_game(obj);
deleteObj(obj);
}
void extract_obj(OBJ_DATA *obj) {
// make sure we're not attached to anything
CHAR_DATA *sitter = NULL;
while( (sitter = (CHAR_DATA *)listGet(objGetUsers(obj), 0)) != NULL)
char_from_furniture(sitter);
OBJ_DATA *content = NULL;
while( (content = (OBJ_DATA *)listGet(objGetContents(obj), 0)) != NULL)
extract_obj(content);
if(objGetRoom(obj))
obj_from_room(obj);
if(objGetWearer(obj))
try_unequip(objGetWearer(obj), obj);
if(objGetCarrier(obj))
obj_from_char(obj);
if(objGetContainer(obj))
obj_from_obj(obj);
if(!listIn(objs_to_delete, obj))
listPut(objs_to_delete, obj);
}
void extract_mobile_final(CHAR_DATA *ch) {
char_from_game(ch);
if(charIsNPC(ch) || !player_exists(charGetName(ch)))
deleteChar(ch);
else
unreference_player(ch);
}
void extract_mobile(CHAR_DATA *ch) {
// unequip everything the character is wearing
// and send it to inventory
unequip_all(ch);
// extract everything in the character's inventory
LIST_ITERATOR *obj_i = newListIterator(charGetInventory(ch));
OBJ_DATA *obj = NULL;
ITERATE_LIST(obj, obj_i) {
extract_obj(obj);
} deleteListIterator(obj_i);
// make sure we're not attached to anything
if(charGetFurniture(ch))
char_from_furniture(ch);
if(charGetRoom(ch))
char_from_room(ch);
// make sure we close down the socket
if(charGetSocket(ch) != NULL) {
close_socket(charGetSocket(ch), FALSE);
charSetSocket(ch, NULL);
}
if(!listIn(mobs_to_delete, ch))
listPut(mobs_to_delete, ch);
}
void extract_room_final(ROOM_DATA *room) {
room_from_game(room);
deleteRoom(room);
}
void extract_room(ROOM_DATA *room) {
roomSetExtracted(room);
// extract all of the objects characters in us
CHAR_DATA *ch = NULL;
while( (ch = listGet(roomGetCharacters(room), 0)) != NULL)
extract_mobile(ch);
// and the objects
OBJ_DATA *obj = NULL;
while( (obj = listGet(roomGetContents(room), 0)) != NULL)
extract_obj(obj);
// remove us from the world we're in ... the if should always be true if
// we are in fact part of the world.
if(worldRoomLoaded(gameworld, roomGetClass(room)) &&
worldGetRoom(gameworld, roomGetClass(room)) == room)
worldRemoveRoom(gameworld, roomGetClass(room));
// If anyone's last room was us, make sure we set the last room to NULL
LIST_ITERATOR *ch_i = newListIterator(mobile_list);
ITERATE_LIST(ch, ch_i) {
if(charGetLastRoom(ch) == room)
charSetLastRoom(ch, NULL);
} deleteListIterator(ch_i);
if(!listIn(rooms_to_delete, room))
listPut(rooms_to_delete, room);
}
void communicate(CHAR_DATA *dMob, char *txt, int range)
{
switch(range) {
default:
bug("Communicate: Bad Range %d.", range);
return;
case COMM_LOG:
send_to_groups("admin, scripter", "[LOG: %s]\r\n", txt);
break;
}
}
/*
* load the world and its inhabitants, as well as other misc game data
*/
void load_muddata() {
if(gameworld == NULL) {
log_string("ERROR: Could not boot game world.");
abort();
}
worldAddType(gameworld, "mproto", protoRead, protoStore, deleteProto,
protoSetKey);
worldAddType(gameworld, "oproto", protoRead, protoStore, deleteProto,
protoSetKey);
worldAddType(gameworld, "rproto", protoRead, protoStore, deleteProto,
protoSetKey);
worldAddType(gameworld, "reset", resetListRead, resetListStore,
deleteResetList, resetListSetKey);
worldSetPath(gameworld, WORLD_PATH);
worldInit(gameworld);
greeting = read_file("../lib/txt/greeting");
motd = read_file("../lib/txt/motd");
}
char *get_time()
{
static char buf[16];
char *strtime;
int i;
strtime = ctime(¤t_time);
for (i = 0; i < 15; i++)
buf[i] = strtime[i + 4];
buf[15] = '\0';
return buf;
}
// try entering into the game
// disconnect the socket if we fail.
bool try_enter_game(CHAR_DATA *ch) {
// find the loadroom
ROOM_DATA *loadroom = worldGetRoom(gameworld, charGetLoadroom(ch));
// if the loadroom doesn't exist,
// try loading the character to the start room
if(loadroom == NULL) {
send_to_char(ch,
"Your loadroom seems to be missing. Attempting to "
"load you to the start room.\r\n");
log_string("ERROR: %s had invalid loadroom, %s",
charGetName(ch), charGetLoadroom(ch));
loadroom = worldGetRoom(gameworld, START_ROOM);
}
// we have a loadroom... all is good
if(loadroom != NULL) {
// add him to the game
char_to_game(ch);
char_to_room(ch, loadroom);
return TRUE;
}
// oops! No rooms seem to exist
else {
send_to_char(ch,
"The gameworld was not properly loaded. The MUD may "
"be going through maintenance. Try again later.\r\n");
log_string("ERROR: When loading %s, start room did not exist!",
charGetName(ch));
return FALSE;
}
}
CHAR_DATA *check_reconnect(const char *player) {
CHAR_DATA *dMob;
LIST_ITERATOR *mob_i = newListIterator(mobile_list);
ITERATE_LIST(dMob, mob_i) {
if (!charIsNPC(dMob) && charIsName(dMob, player)) {
if (charGetSocket(dMob)) {
close_socket(charGetSocket(dMob), TRUE);
charSetSocket(dMob, NULL);
}
break;
}
} deleteListIterator(mob_i);
return dMob;
}
void do_mass_transfer(ROOM_DATA *from, ROOM_DATA *to, bool chars, bool mobs,
bool objs) {
if(chars || mobs) {
LIST_ITERATOR *ch_i = newListIterator(roomGetCharacters(from));
CHAR_DATA *ch = NULL;
ITERATE_LIST(ch, ch_i) {
if(mobs || (chars && !charIsNPC(ch))) {
char_from_room(ch);
char_to_room(ch, to);
}
} deleteListIterator(ch_i);
}
if(objs) {
LIST_ITERATOR *obj_i = newListIterator(roomGetContents(from));
OBJ_DATA *obj = NULL;
ITERATE_LIST(obj, obj_i) {
obj_from_room(obj);
obj_to_room(obj, to);
} deleteListIterator(obj_i);
}
}
const char *exitGetToFull(EXIT_DATA *exit) {
if(exitGetRoom(exit) == NULL)
return exitGetTo(exit);
else
return get_fullkey_relative(exitGetTo(exit), get_key_locale(roomGetClass(exitGetRoom(exit))));
}
ROOM_DATA *objGetRootRoom(OBJ_DATA *obj) {
if(objGetCarrier(obj))
return charGetRoom(objGetCarrier(obj));
else if(objGetWearer(obj))
return charGetRoom(objGetWearer(obj));
else if(objGetContainer(obj))
return objGetRootRoom(objGetContainer(obj));
return objGetRoom(obj);
}
int can_see_hidden(CHAR_DATA *ch) {
return 0;
}
int can_see_invis(CHAR_DATA *ch) {
return 0;
}
LIST *char_see_checks = NULL;
LIST *obj_see_checks = NULL;
LIST *exit_see_checks = NULL;
void register_char_see( bool (* check)(CHAR_DATA *ch, CHAR_DATA *target)) {
if(char_see_checks == NULL)
char_see_checks = newList();
listPut(char_see_checks, check);
}
void register_obj_see( bool (* check)(CHAR_DATA *ch, OBJ_DATA *target)) {
if(obj_see_checks == NULL)
obj_see_checks = newList();
listPut(obj_see_checks, check);
}
void register_exit_see(bool (* check)(CHAR_DATA *ch, EXIT_DATA *target)) {
if(exit_see_checks == NULL)
exit_see_checks = newList();
listPut(exit_see_checks, check);
}
bool can_see_char(CHAR_DATA *ch, CHAR_DATA *target) {
if(ch == target)
return TRUE;
if(poscmp(charGetPos(ch), POS_SLEEPING) <= 0)
return FALSE;
bool ret = TRUE;
if(char_see_checks != NULL) {
LIST_ITERATOR *chk_i = newListIterator(char_see_checks);
bool (*chk)(CHAR_DATA *, CHAR_DATA *) = NULL;
ITERATE_LIST(chk, chk_i) {
ret = chk(ch, target);
if(ret == FALSE)
break;
} deleteListIterator(chk_i);
}
return ret;
}
bool can_see_obj(CHAR_DATA *ch, OBJ_DATA *target) {
if(poscmp(charGetPos(ch), POS_SLEEPING) <= 0)
return FALSE;
bool ret = TRUE;
if(obj_see_checks != NULL) {
LIST_ITERATOR *chk_i = newListIterator(obj_see_checks);
bool (*chk)(CHAR_DATA *, OBJ_DATA *) = NULL;
ITERATE_LIST(chk, chk_i) {
ret = chk(ch, target);
if(ret == FALSE)
break;
} deleteListIterator(chk_i);
}
return ret;
}
bool can_see_exit(CHAR_DATA *ch, EXIT_DATA *target) {
if(poscmp(charGetPos(ch), POS_SLEEPING) <= 0)
return FALSE;
bool ret = TRUE;
if(exit_see_checks != NULL) {
LIST_ITERATOR *chk_i = newListIterator(exit_see_checks);
bool (*chk)(CHAR_DATA *, EXIT_DATA *) = NULL;
ITERATE_LIST(chk, chk_i) {
ret = chk(ch, target);
if(ret == FALSE)
break;
} deleteListIterator(chk_i);
}
return ret;
}
const char *see_exit_as(CHAR_DATA *ch, EXIT_DATA *target) {
if(!can_see_exit(ch, target))
return SOMEWHERE;
else {
BUFFER *buf = newBuffer(1);
const char *dir = NULL;
ROOM_DATA *dest = NULL;
if(exitGetRoom(target))
dir = roomGetExitDir(exitGetRoom(target), target);
// build up what the exit looks like
if(exitIsClosed(target)) {
if(*exitGetName(target))
bprintf(buf, exitGetName(target));
else
bprintf(buf, "closed");
}
else if( (dest = worldGetRoom(gameworld, exitGetToFull(target))) != NULL)
bprintf(buf, "%s", roomGetName(dest));
else
bprintf(buf, "%s", SOMEWHERE);
listPush(bufs_to_delete, buf);
return bufferString(buf);
}
}
const char *see_char_as(CHAR_DATA *ch, CHAR_DATA *target) {
if(!can_see_char(ch, target))
return SOMEONE;
// put the interaction commands around our name
else
return charGetName(target);
}
//
// finds the UID of the room the object is in
int find_obj_room(OBJ_DATA *obj) {
if(objGetRoom(obj))
return roomGetUID(objGetRoom(obj));
else if(objGetCarrier(obj))
return roomGetUID(charGetRoom(objGetCarrier(obj)));
else if(objGetWearer(obj))
return roomGetUID(charGetRoom(objGetWearer(obj)));
else if(objGetContainer(obj))
return find_obj_room(objGetContainer(obj));
return NOWHERE;
}
const char *see_obj_as(CHAR_DATA *ch, OBJ_DATA *target) {
if(!can_see_obj(ch, target))
return SOMETHING;
else
return objGetName(target);
}
//
// returns a name as a UID, or -1 if it does not translate
int name_as_uid(const char *name) {
if(name == NULL)
return NOBODY;
int i = 0, uid = NOBODY;
for(; name[i] != '\0'; i++)
if(!isdigit(name[i]))
return NOBODY;
sscanf(name, "%d", &uid);
return uid;
}
int count_objs(CHAR_DATA *looker, LIST *list, const char *name,
const char *prototype, bool must_see) {
LIST_ITERATOR *obj_i = newListIterator(list);
OBJ_DATA *obj;
int count = 0;
int uid = name_as_uid(name);
ITERATE_LIST(obj, obj_i) {
if(must_see && !can_see_obj(looker, obj))
continue;
// if we have a name, search by it
if(objGetUID(obj) == uid || (name && *name && objIsName(obj, name)))
count++;
// otherwise search by prototype
else if(prototype && *prototype && objIsInstance(obj, prototype))
count++;
}
deleteListIterator(obj_i);
return count;
}
int count_chars(CHAR_DATA *looker, LIST *list, const char *name,
const char *prototype, bool must_see) {
LIST_ITERATOR *char_i = newListIterator(list);
CHAR_DATA *ch;
int count = 0;
int uid = name_as_uid(name);
ITERATE_LIST(ch, char_i) {
if(must_see && !can_see_char(looker, ch))
continue;
// if we have a name, search by it
if((name && *name && charIsName(ch, name)) || charGetUID(ch) == uid)
count++;
// otherwise, search by prototype
else if(prototype && *prototype && charIsInstance(ch, prototype))
count++;
} deleteListIterator(char_i);
return count;
}
//
// find the numth occurance of the character with name, "name"
// if name is not supplied, search by prototype. If name is supplied as m.XXX,
// then search by the mob's UID
//
CHAR_DATA *find_char(CHAR_DATA *looker, LIST *list, int num, const char *name,
const char *prototype, bool must_see) {
if(num <= 0)
return NULL;
CHAR_DATA *ch = NULL;
// is everything in the description a number? Search by UID
int uid = name_as_uid(name);
if(uid != NOBODY) {
ch = propertyTableGet(mob_table, uid);
if(listIn(list, ch) && can_see_char(looker, ch))
return ch;
return NULL;
}
LIST_ITERATOR *char_i = newListIterator(list);
ITERATE_LIST(ch, char_i) {
if(must_see && !can_see_char(looker, ch))
continue;
// if we have a name, search by name
if(name && *name && charIsName(ch, name))
num--;
// otherwise search by prototype
else if(prototype && *prototype && charIsInstance(ch, prototype))
num--;
if(num == 0)
break;
} deleteListIterator(char_i);
return ch;
}
//
// find the numth occurance of the object with name, "name"
// if name is not supplied, search by prototype
//
OBJ_DATA *find_obj(CHAR_DATA *looker, LIST *list, int num,
const char *name, const char *prototype, bool must_see) {
if(num == 0)
return NULL;
OBJ_DATA *obj = NULL;
// is everything in the description a number? Search by UID
int uid = name_as_uid(name);
if(uid != NOTHING) {
obj = propertyTableGet(obj_table, uid);
if(listIn(list, obj) && can_see_obj(looker, obj))
return obj;
return NULL;
}
LIST_ITERATOR *obj_i = newListIterator(list);
ITERATE_LIST(obj, obj_i) {
if(must_see && !can_see_obj(looker, obj))
continue;
// if a name is supplied, search by name
if(name && *name && objIsName(obj, name))
num--;
// otherwise, search by prototype
else if(prototype && *prototype && objIsInstance(obj, prototype))
num--;
if(num == 0)
break;
} deleteListIterator(obj_i);
return obj;
}
//
// Find all characters in the list with the given name. Or all characters
// if name is NULL
//
LIST *find_all_chars(CHAR_DATA *looker, LIST *list, const char *name,
const char *prototype, bool must_see) {
LIST_ITERATOR *char_i = newListIterator(list);
LIST *char_list = newList();
int uid = name_as_uid(name);
CHAR_DATA *ch;
ITERATE_LIST(ch, char_i) {
if(must_see && !can_see_char(looker, ch))
continue;
if((name && (!*name || charIsName(ch, name))) || charGetUID(ch) == uid)
listPut(char_list, ch);
else if(prototype && *prototype && charIsInstance(ch, prototype))
listPut(char_list, ch);
} deleteListIterator(char_i);
return char_list;
}
//
// Returns a llist of all the chars found with a specific name in the list.
// the list must be deleted after use.
//
LIST *find_all_objs(CHAR_DATA *looker, LIST *list, const char *name,
const char *prototype, bool must_see) {
LIST_ITERATOR *obj_i = newListIterator(list);
LIST *obj_list = newList();
int uid = name_as_uid(name);
OBJ_DATA *obj;
ITERATE_LIST(obj, obj_i) {
if(must_see && !can_see_obj(looker, obj))
continue;
if((name && (!*name || objIsName(obj, name))) || objGetUID(obj) == uid)
listPut(obj_list, obj);
else if(prototype && *prototype && objIsInstance(obj, prototype))
listPut(obj_list, obj);
} deleteListIterator(obj_i);
return obj_list;
}
//
// separates a joint item-count (e.g. 2.sword, all.woman) into its
// count and its word
//
void get_count(const char *buf, char *target, int *count) {
// hmmm... we can probably condense these two checks into one, non?
if(!strncasecmp(buf, "all.", 4)) {
//sscanf(buf, "all.%s", target);
strcpyto(target, buf+4, '\0');
*count = COUNT_ALL;
}
else if(!strcasecmp(buf, "all")) {
*target = '\0';
*count = COUNT_ALL;
}
else if(!strstr(buf, ".")) {
strcpyto(target, buf, '\0');
//sscanf(buf, "%s", target);
*count = 1;
}
else {
//*count = 1;
//strcpyto(target, buf, '\0');
sscanf(buf, "%d", count);
strcpyto(target, buf+next_letter_in(buf, '.')+1, '\0');
}
}
//
// concats an item count and a target into a single term
//
void print_count(char *buf, const char *target, int count) {
if(count > 1)
sprintf(buf, "%d.%s", count, target);
else if(count == COUNT_ALL && *target)
sprintf(buf, "all.%s", target);
else if(count == COUNT_ALL)
sprintf(buf, "all");
else
sprintf(buf, "%s", target);
}
//
// Calculates how many letters until we hit the next one
// of a specified type
//
int next_letter_in(const char *string, char marker) {
int i = 0;
for(i = 0; string[i] != '\0'; i++)
if(string[i] == marker)
return i;
return -1; // none found
}
//
// Calculates how many characters until we hit the next whitespace. Newlines,
// tabs, and spaces are treated as whitespace.
int next_space_in(const char *string) {
int i = 0;
for(i = 0; string[i] != '\0'; i++)
if(isspace(string[i]))
return i;
return -1; // none found
}
//
// If we're at the beginning of a new paragraph, return where the new paragraph
// starts. Otherwise, return our current position (index)
int is_paragraph_marker(const char *string, int index) {
int nl_count = 0;
int i = 0;
for(i = index; isspace(string[i]); i++) {
if(string[i] == '\n')
nl_count++;
}
if(nl_count > 1)
return i;
else
return index;
}
//
// hashing array 1 for pearson hashing
int pearson_table1[] = { 66, 93, 11, 153, 155, 113, 214, 132, 91, 193, 240, 82, 175, 145, 84, 34, 76, 217, 250, 230, 139, 172, 65, 254, 196, 56, 165, 116, 48, 219, 199, 142, 35, 27, 210, 149, 45, 127, 41, 150, 85, 87, 253, 100, 234, 216, 192, 226, 154, 106, 78, 146, 131, 38, 120, 151, 177, 29, 50, 231, 68, 168, 227, 161, 126, 141, 36, 191, 110, 81, 197, 190, 9, 236, 140, 0, 20, 162, 23, 189, 42, 130, 117, 86, 243, 123, 237, 249, 64, 135, 61, 167, 39, 57, 96, 148, 118, 13, 235, 188, 19, 71, 49, 115, 21, 182, 15, 200, 179, 251, 75, 77, 204, 32, 180, 16, 218, 22, 171, 88, 30, 248, 47, 238, 105, 94, 92, 67, 28, 69, 33, 215, 1, 7, 241, 109, 209, 98, 12, 208, 156, 52, 195, 89, 185, 55, 170, 104, 17, 173, 122, 138, 4, 202, 136, 247, 169, 222, 163, 211, 144, 252, 2, 186, 201, 40, 207, 107, 18, 24, 46, 129, 44, 14, 174, 26, 124, 194, 37, 223, 102, 183, 99, 114, 70, 158, 53, 111, 147, 119, 73, 152, 79, 203, 157, 221, 10, 97, 133, 62, 229, 178, 205, 184, 164, 176, 198, 80, 58, 245, 31, 59, 128, 101, 60, 181, 246, 232, 63, 143, 121, 213, 187, 206, 43, 134, 6, 225, 228, 72, 54, 233, 224, 5, 8, 239, 112, 244, 255, 137, 3, 74, 108, 159, 83, 125, 103, 51, 220, 25, 166, 90, 160, 212, 95, 242 };
int pearson_table2[] = { 202, 142, 134, 22, 233, 237, 13, 31, 41, 97, 141, 148, 74, 165, 7, 162, 53, 117, 210, 226, 174, 88, 5, 163, 17, 49, 170, 99, 93, 39, 69, 108, 207, 244, 254, 101, 159, 30, 188, 67, 235, 150, 24, 136, 208, 221, 234, 43, 96, 12, 78, 10, 25, 81, 239, 120, 37, 21, 42, 183, 121, 213, 14, 161, 137, 23, 9, 255, 245, 209, 222, 236, 119, 199, 216, 71, 115, 110, 63, 107, 173, 70, 20, 89, 91, 102, 227, 1, 177, 113, 104, 111, 253, 181, 95, 243, 72, 6, 124, 131, 190, 86, 164, 85, 251, 3, 50, 154, 217, 155, 8, 105, 82, 28, 75, 147, 0, 80, 252, 140, 29, 2, 242, 160, 57, 34, 247, 167, 47, 126, 144, 168, 18, 231, 44, 58, 206, 77, 125, 171, 36, 76, 98, 26, 241, 180, 61, 151, 194, 15, 45, 84, 212, 32, 196, 92, 192, 139, 112, 229, 100, 109, 189, 248, 156, 94, 153, 145, 127, 146, 175, 138, 215, 195, 198, 128, 182, 218, 19, 250, 132, 40, 214, 103, 83, 73, 106, 133, 135, 186, 123, 219, 158, 38, 152, 232, 116, 64, 172, 52, 200, 204, 240, 224, 203, 249, 59, 157, 114, 191, 230, 48, 166, 122, 65, 228, 184, 4, 205, 220, 225, 62, 169, 79, 27, 197, 11, 87, 193, 179, 223, 56, 68, 178, 187, 149, 143, 16, 55, 35, 201, 118, 185, 51, 66, 33, 54, 176, 60, 46, 211, 246, 238, 130, 90, 129 };
int pearson_table3[] = { 44, 181, 139, 127, 174, 243, 236, 14, 5, 200, 235, 180, 195, 185, 193, 116, 161, 110, 72, 121, 9, 3, 104, 224, 136, 182, 15, 94, 222, 84, 186, 20, 239, 147, 21, 34, 183, 93, 61, 164, 189, 89, 17, 226, 56, 205, 176, 51, 128, 201, 73, 75, 190, 163, 96, 178, 102, 33, 150, 130, 98, 76, 120, 240, 79, 158, 24, 196, 78, 4, 202, 168, 48, 255, 227, 97, 138, 101, 207, 170, 58, 27, 45, 225, 179, 215, 251, 123, 209, 38, 63, 36, 6, 175, 62, 208, 86, 65, 107, 188, 249, 146, 198, 194, 254, 230, 253, 103, 46, 133, 192, 26, 108, 219, 191, 77, 137, 81, 145, 66, 91, 106, 7, 10, 29, 95, 165, 88, 119, 151, 40, 22, 1, 122, 114, 134, 37, 214, 217, 68, 0, 83, 199, 70, 80, 156, 140, 144, 90, 118, 42, 173, 111, 157, 204, 171, 212, 241, 53, 11, 148, 135, 206, 172, 23, 109, 13, 220, 245, 197, 177, 47, 59, 210, 49, 74, 54, 25, 234, 115, 43, 169, 218, 50, 87, 31, 143, 248, 69, 92, 160, 141, 41, 228, 184, 233, 117, 2, 231, 252, 28, 216, 125, 153, 18, 100, 166, 8, 52, 124, 250, 132, 67, 244, 12, 246, 32, 64, 213, 242, 247, 223, 82, 131, 112, 221, 113, 155, 71, 211, 60, 129, 149, 237, 30, 85, 55, 152, 229, 35, 232, 187, 19, 105, 203, 39, 159, 238, 167, 162, 57, 126, 99, 154, 142, 16 };
int pearson_table4[] = { 231, 223, 174, 160, 113, 173, 104, 49, 122, 229, 13, 8, 232, 81, 38, 90, 64, 131, 123, 176, 33, 84, 166, 241, 16, 190, 159, 144, 189, 193, 66, 137, 163, 162, 111, 26, 15, 9, 1, 119, 255, 136, 167, 178, 94, 130, 114, 32, 110, 99, 78, 153, 239, 179, 243, 249, 133, 76, 86, 242, 165, 169, 19, 155, 152, 67, 215, 220, 36, 24, 213, 105, 117, 168, 128, 204, 248, 238, 177, 161, 222, 205, 108, 186, 116, 51, 230, 68, 181, 58, 39, 47, 71, 211, 209, 101, 251, 164, 60, 10, 12, 83, 180, 50, 172, 55, 158, 20, 70, 107, 147, 170, 91, 118, 40, 140, 3, 252, 184, 34, 146, 127, 28, 254, 150, 57, 228, 126, 192, 14, 253, 45, 227, 225, 30, 4, 17, 44, 95, 201, 18, 149, 124, 65, 129, 154, 195, 102, 212, 219, 6, 75, 132, 244, 52, 187, 240, 198, 85, 217, 185, 224, 208, 21, 250, 87, 216, 183, 245, 203, 79, 61, 100, 200, 246, 80, 138, 109, 120, 92, 247, 143, 202, 72, 134, 156, 207, 233, 218, 37, 23, 125, 82, 234, 56, 151, 106, 112, 197, 41, 88, 96, 171, 31, 175, 93, 182, 188, 135, 48, 148, 5, 226, 103, 29, 97, 139, 115, 0, 77, 89, 74, 35, 42, 157, 59, 69, 2, 62, 236, 142, 196, 145, 7, 54, 237, 206, 194, 73, 121, 98, 199, 27, 235, 11, 221, 46, 141, 43, 63, 25, 22, 210, 53, 191, 214 };
unsigned long pearson_hash8(const char *string, int *table) {
unsigned long h = 0;
for(; *string; string++)
h = table[h ^ tolower(*string)];
return h;
}
unsigned long pearson_hash8_1(const char *string) {
return pearson_hash8(string, pearson_table1);
}
unsigned long pearson_hash8_2(const char *string) {
return pearson_hash8(string, pearson_table2);
}
unsigned long pearson_hash8_3(const char *string) {
return pearson_hash8(string, pearson_table3);
}
unsigned long pearson_hash8_4(const char *string) {
return pearson_hash8(string, pearson_table4);
}
// concatinate two strings of 8 bits
unsigned long pearson_hash16_1(const char *string) {
return pearson_hash8_1(string) | (pearson_hash8_2(string) << 8);
}
// again, different hashing functions
unsigned long pearson_hash16_2(const char *string) {
return pearson_hash8_3(string) | (pearson_hash8_4(string) << 8);
}
// concatinate four strings of 8 bits
unsigned long pearson_hash32(const char *string) {
return ((pearson_hash8_1(string)) | (pearson_hash8_2(string) << 8) |
(pearson_hash8_3(string) << 16) | (pearson_hash8_4(string) << 24));
}
//
// just a generic function for hashing a string. This could be
// sped up tremendously if it's performance becoming a problem.
unsigned long string_hash(const char *key) {
return pearson_hash32(key);
}
bool endswith(const char *string, const char *end) {
int slen = strlen(string);
int elen = strlen(end);
return (slen >= elen && !strcasecmp(string + slen - elen, end));
}
bool startswith(const char *string, const char *start) {
return !strncasecmp(string, start, strlen(start));
}
const char *strcpyto(char *to, const char *from, char end) {
// copy everything up to end, and then delimit our destination buffer
for(; *from != '\0' && *from != end; to++, from++)
*to = *from;
*to = '\0';
// skip our end character and return whatever's left
if(*from != '\0')
from++;
return from;
}
//
// counts how many times ch occurs in string
//
int count_letters(const char *string, const char ch, const int strlen) {
int i, n;
for(i = n = 0; i < strlen; i++)
if(string[i] == ch)
n++;
return n;
}
//
// counts how many times word occurs in string. Assumes strlen(word) >= 1
//
int count_occurences(const char *string, const char *word) {
int count = 0, i = 0, word_len = strlen(word);
for(; string[i] != '\0'; i++) {
if(!strncmp(string+i, word, word_len)) {
count++;
i += word_len;
}
}
return count;
}
//
// return a pointer to the start of the line num (lines are ended with \n's).
// return NULL if the line does not exist
//
char *line_start(char *string, int line) {
// skip forward to the appropriate line
int i, count = 1;
// are we looking for the start?
if(line == 1) return string;
for(i = 0; string[i] != '\0'; i++) {
if(string[i] == '\n')
count++;
if(count == line)
return string+i+1;
}
return NULL;
}
//
// trim trailing and leading whitespace
//
void trim(char *string) {
int len = strlen(string);
int max = len-1;
int min = 0;
int i;
// kill all whitespace to the right
for(max = len - 1; max >= 0; max--) {
if(isspace(string[max]))
string[max] = '\0';
else
break;
}
// find our first non-whitespace
while(isspace(string[min]))
min++;
// shift everything to the left
for(i = 0; i <= max-min; i++)
string[i] = string[i+min];
string[i] = '\0';
}
//
// Returns true if "word" is found in the comma-separated list of
// keywords
//
bool is_keyword(const char *keywords, const char *word, bool abbrev_ok) {
int word_len = strlen(word);
if(word_len < 1)
return FALSE;
// while we haven't reached the end of the string
while(*keywords != '\0') {
// skip all spaces and commas
while(isspace(*keywords) || *keywords == ',')
keywords = keywords+1;
// figure out the length of the current keyword
int keyword_len = next_letter_in(keywords, ',');
if(keyword_len == -1)
keyword_len = strlen(keywords);
// see if we compare to the current keyword
if(!abbrev_ok && !strncasecmp(keywords, word, keyword_len) &&
keyword_len == word_len)
return TRUE;
if(abbrev_ok && !strncasecmp(keywords, word, word_len))
return TRUE;
// we didn't. skip this current keyword, and find
// the start of the next keyword or the end of the string
else while(!(*keywords == '\0' || *keywords == ','))
keywords = keywords+1;
}
return FALSE;
}
//
// Return 0 if the head of the string does not match any of our
// keywords. Returns the length of the keyword if it does match
int find_keyword(const char *keywords, const char *string) {
LIST *words = parse_keywords(keywords);
LIST_ITERATOR *word_i = newListIterator(words);
char *word = NULL;
int len = 0;
// try to find the longest keyword
ITERATE_LIST(word, word_i) {
int word_len = strlen(word);
if(!strncasecmp(word, string, word_len) && word_len > len)
len = word_len;
} deleteListIterator(word_i);
deleteListWith(words, free);
return len;
}
//
// returns whether or not a keyword exists twice in the list
bool dup_keywords_exist(const char *keywords) {
LIST *keys = parse_keywords(keywords);
char *key = NULL;
bool dup_found = FALSE;
while( !dup_found && (key = listPop(keys)) != NULL) {
if(listGetWith(keys, key, strcasecmp) != NULL)
dup_found = TRUE;
free(key);
} deleteListWith(keys, free);
return dup_found;
}
//
// Return a list of all the strings in this list. String are separated by the
// delimeter. The list and contents must be deleted after use.
LIST *parse_strings(const char *string, char delimeter) {
// make our list that we will be returning
LIST *list = newList();
// first, we check if the string have any non-spaces
int i;
bool nonspace_found = FALSE;
for(i = 0; string[i] != '\0'; i++) {
if(!isspace(string[i])) {
nonspace_found = TRUE;
break;
}
}
// we didn't find any non-spaces. Return NULL
if(!nonspace_found)
return list;
// find all of our keywords
while(*string != '\0') {
i = 0;
// find the endpoint
while(string[i] != delimeter && string[i] != '\0')
i++;
char buf[i+1];
strncpy(buf, string, i); buf[i] = '\0';
trim(buf); // skip all whitespaces
// make sure something still exists. If it does, queue it
if(*buf != '\0')
listQueue(list, strdup(buf));
// skip everything we just copied, plus our delimeter
string = &string[i+(string[i] != '\0' ? 1 : 0)];
}
// return whatever we found
return list;
}
//
// return a list of all the unique keywords found in the keywords string
// keywords can be more than one word long (e.g. blue flame) and each
// keyword must be separated by a comma
LIST *parse_keywords(const char *keywords) {
return parse_strings(keywords, ',');
}
//
// If the keyword does not already exist, add it to the keyword list
// keywords may be freed and re-built in the process, to make room
void add_keyword(char **keywords_ptr, const char *word) {
// if it's already a keyword, do nothing
if(!is_keyword(*keywords_ptr, word, FALSE)) {
BUFFER *buf = newBuffer(MAX_BUFFER);
// make our new keyword list
bprintf(buf, "%s%s%s", *keywords_ptr, (**keywords_ptr ? ", " : ""), word);
// free the old string, copy the new one
free(*keywords_ptr);
*keywords_ptr = strdup(bufferString(buf));
// clean up our garbage
deleteBuffer(buf);
}
}
//
// go through the keywords and if the word is found, remove it
void remove_keyword(char *keywords, const char *word) {
LIST *words = parse_keywords(keywords);
char *copy = NULL;
int count = 0;
// remove all copies of it
while( (copy = listRemoveWith(words, word, strcasecmp)) != NULL) {
free(copy);
count++;
}
// did we find a copy of the bad keyword?
if(count > 0) {
LIST_ITERATOR *word_i = newListIterator(words);
int key_i = 0;
count = 0;
// clear the current keywords... we'll rebuild them
*keywords = '\0';
ITERATE_LIST(copy, word_i) {
count++;
key_i += sprintf(keywords+key_i, "%s", copy);
if(count < listSize(words) - 1)
key_i += sprintf(keywords+key_i, ", ");
} deleteListIterator(word_i);
}
// clean up our garbage
deleteListWith(words, free);
}
//
// print the string on the buffer, centered for a line of length linelen.
// if border is TRUE, put a border to either side of the string.
//
void center_string(char *buf, const char *string, int linelen, int buflen,
bool border) {
char fmt[32];
int str_len = strlen(string);
int spaces = (linelen - str_len)/2;
if(border) {
int i, buf_i = 0;
sprintf(fmt, "{n%%-%ds[{c", spaces-2);
buf_i = snprintf(buf, buflen, fmt, " ");
// replace all of the spaces with -
for(i = 0; buf[i] != '\0'; i++) if(buf[i] == ' ') buf[i] = '-';
buf_i += snprintf(buf+buf_i, buflen-buf_i, " %s ", string);
sprintf(fmt, "{n]%%-%ds\r\n",
spaces-2 + (((linelen-str_len) % 2) == 1 ? 1 : 0));
i = buf_i;
buf_i += snprintf(buf+buf_i, buflen-buf_i, fmt, " ");
// replace all of the spaces with -
for(; buf[i] != '\0'; i++) if(buf[i] == ' ') buf[i] = '-';
}
else {
int buf_i = 0;
sprintf(fmt, "%%-%ds", spaces);
buf_i = snprintf(buf, buflen, fmt, " ");
buf_i += snprintf(buf+buf_i, buflen-buf_i, "%s\r\n", string);
}
}
//
// fill up the buffer with characters until
// a newline is reached, or we hit our critical
// length. Return how many characters were read
//
int fgetline(FILE *file, char *p, int maxlen)
{
int count = 0;
while(!feof(file) && count < maxlen - 1) {
p[count] = fgetc(file);
if(p[count] == '\n')
break;
count++;
}
p[count] = '\0';
return count;
}
int rand_number(int min, int max) {
if(min > max) {
log_string("ERROR: rand_number passed a min (%d) higher than its max (%d).",
min, max);
return 0;
}
return min + rand() % (max-min + 1);
}
double rand_percent(void) {
double rnd = rand_number(0, RAND_MAX);
return rnd / (double)RAND_MAX;
}
double rand_gaussian(void) {
return sqrt(-2.0 * log(rand_percent())) * cos(2.0 * PI * rand_percent());
}
double sigmoid(double val) {
return 1.0 / (1.0 + pow(MATH_E, -val));
}
//
// returns "st", "nd", "rd", or "th", based on the number passed in
//
const char *numth(int num) {
if(num != 11 && num % 10 == 1)
return "st";
else if(num != 12 && num % 10 == 2)
return "nd";
else if(num != 13 && num % 10 == 3)
return "rd";
else
return "th";
}
//
// Strips all occurances of a word from the string
//
// used to just replace occurances of 'word' with nothing,
// but this doesn't work so well since replace_string will
// replace it, even if the 'word' is embedded inside of another
// word. This is undesirable.
//
// replace_string(&string, word, "", TRUE);
//
void strip_word(char *string, const char *word) {
int word_len = strlen(word);
int i = 0;
for(i = 0; string[i] != '\0'; i++) {
// skip all spaces and newline stuff
while(isspace(string[i]) || string[i] == '\n' || string[i] == '\r')
i++;
// we've found a match
if(!strncmp(string+i, word, word_len) &&
(string[i+word_len] == '\0' || isspace(string[i+word_len]) ||
string[i+word_len] == '\n' || string[i+word_len] == '\r')) {
// count all of the spaces following us, so we can remove them too
int space_count = 0;
while(isspace(string[i+word_len+space_count]))
space_count++;
// shuffle everything down
int j = i-1;
do {
j++;
string[j] = string[j+word_len+space_count];
} while(string[j+word_len+space_count] != '\0');
}
}
}
char *tag_keywords(const char *string, const char *keywords,
const char *start_tag, const char *end_tag) {
char buf[strlen(string) * 2];
int i = 0, j = 0;
int start_len = strlen(start_tag);
int end_len = strlen(end_tag);
while(*string) {
int keyword_len;
// check for a match
if( (keyword_len = find_keyword(keywords, string)) != 0) {
for(j = 0; j < start_len; j++)
buf[i++] = start_tag[j];
while(keyword_len > 0) {
buf[i++] = *string;
string++;
keyword_len--;
}
for(j = 0; j < end_len; j++)
buf[i++] = end_tag[j];
}
// skip ahead one word
else {
while(!isspace(*string) && *string != '\0') {
buf[i++] = *string;
string++;
}
// put in our space
if(*string != '\0') {
buf[i++] = *string;
string++;
}
}
}
buf[i++] = '\0';//dialogue++;
return strdup(buf);
}
void buf_tag_keywords(BUFFER *buf, const char *keywords, const char *start_tag,
const char *end_tag) {
char *new_str = tag_keywords(bufferString(buf), keywords, start_tag, end_tag);
bufferClear(buf);
bufferCat(buf, new_str);
free(new_str);
}
bitvector_t parse_bits(const char *string) {
bitvector_t bits = 0;
while(*string) {
SET_BIT(bits, (1 << (*string-'a')));
string = string+1;
}
return bits;
}
const char *write_bits(bitvector_t bits) {
static char buf[SMALL_BUFFER]; // really, we only need about 64...
int buf_i = 0, i = 0;
for(i = 0; i < BITS_PER_BITVECTOR; i++)
if(IS_SET(bits, (1 << i)))
buf[buf_i++] = 'a'+i;
buf[buf_i] = '\0';
return buf;
}
void print_bits(bitvector_t bits, const char **names, char *buf) {
int i, count = 0;
for(i = 0; i < BITS_PER_BITVECTOR; i++) {
if(IS_SET(bits, (1 << i))) {
count++;
sprintf(buf, "%s%s%s",
(count == 1 ? "" : buf ),
(count == 1 ? "" : ", "),
names[i]);
}
}
if(count == 0)
sprintf(buf, "NOBITS");
}
char *print_list(LIST *list, void *descriptor, void *multi_descriptor) {
const char *(* desc_func)(void *) = descriptor;
const char *(* multi_desc)(void *) = multi_descriptor;
if(listSize(list) == 0)
return strdup("");
char buf[MAX_BUFFER] = "";
char one_thing[SMALL_BUFFER];
int i;
int tot_things = 0;
int size = listSize(list);
int counts[size];
void *things[size];
void *thing;
LIST_ITERATOR *thing_i = newListIterator(list);
for(i = 0; i < size; i++) {
counts[i] = 0;
things[i] = NULL;
}
// first, collect groups of all the things in the list
ITERATE_LIST(thing, thing_i) {
// see if we have one with the current name already
for(i = 0; i < size; i++) {
// it's a thing with a new name
if(things[i] == NULL) {
things[i] = thing;
counts[i]++;
tot_things++;
break;
}
// it has the same name as something else
else if(!strcmp(desc_func(thing), desc_func(things[i]))) {
counts[i]++;
break;
}
}
} deleteListIterator(thing_i);
// now, print everything to the buffer
for(i = 0; i < tot_things; i++) {
if(counts[i] == 1)
sprintf(one_thing, "%s", desc_func(things[i]));
else if(multi_desc == NULL || !*multi_desc(things[i]))
sprintf(one_thing, "(%d) %s", counts[i], desc_func(things[i]));
else
sprintf(one_thing, multi_desc(things[i]), counts[i]);
// we're at the last one... we have to print an and
if(i == tot_things - 1)
sprintf(buf, "%s%s%s", buf,
(i < 1 ? "" : (i == 1 ? " and " : ", and ")),
one_thing);
// regular comma-separated dealy
else
sprintf(buf, "%s%s%s",
(i == 0 ? "" : buf), (i == 0 ? "" : ", "), one_thing);
}
return strdup(buf);
}
void show_list(CHAR_DATA *ch, LIST *list, void *descriptor,
void *multi_descriptor) {
const char *(* desc_func)(void *) = descriptor;
const char *(* multi_desc)(void *) = multi_descriptor;
int i;
int size = listSize(list);
int counts[size];
void *things[size];
void *thing;
LIST_ITERATOR *thing_i = newListIterator(list);
for(i = 0; i < size; i++) {
counts[i] = 0;
things[i] = NULL;
}
// find a list of all things with unique names
ITERATE_LIST(thing, thing_i) {
// see if we have one with the current name already
for(i = 0; i < size; i++) {
// it's a thing with a new name
if(things[i] == NULL) {
things[i] = thing;
counts[i]++;
break;
}
// it has the same name as something else
else if(!strcmp(desc_func(thing), desc_func(things[i]))) {
counts[i]++;
break;
}
}
} deleteListIterator(thing_i);
// print out all of the things
for(i = 0; i < size; i++) {
// we've run into the end of the list
if(things[i] == NULL)
break;
else {
if(counts[i] == 1)
send_to_char(ch, "{n%s\r\n", desc_func(things[i]));
else if(multi_desc == NULL || !*multi_desc(things[i]))
send_to_char(ch, "{n(%d) %s\r\n", counts[i], desc_func(things[i]));
else {
char fmt[SMALL_BUFFER];
sprintf(fmt, "{n%s\r\n", multi_desc(things[i]));
send_to_char(ch, fmt, counts[i]);
}
}
}
}
LIST *get_unused_items(CHAR_DATA *ch, LIST *list, bool invis_ok) {
OBJ_DATA *obj;
LIST *newlist = newList();
LIST_ITERATOR *obj_i = newListIterator(list);
ITERATE_LIST(obj, obj_i) {
if(listSize(objGetUsers(obj)) != 0)
continue;
if(!(invis_ok || can_see_obj(ch, obj)))
continue;
listPut(newlist, obj);
} deleteListIterator(obj_i);
return newlist;
}
LIST *get_used_items(CHAR_DATA *ch, LIST *list, bool invis_ok) {
OBJ_DATA *obj;
LIST *newlist = newList();
LIST_ITERATOR *obj_i = newListIterator(list);
ITERATE_LIST(obj, obj_i) {
if(listSize(objGetUsers(obj)) < 1)
continue;
if(!(invis_ok || can_see_obj(ch, obj)))
continue;
listPut(newlist, obj);
} deleteListIterator(obj_i);
return newlist;
}
bool has_obj(CHAR_DATA *ch, const char *prototype) {
LIST *vis_inv = find_all_objs(ch, charGetInventory(ch), NULL, prototype,TRUE);
int ret_val = FALSE;
if(listSize(vis_inv) > 0)
ret_val = TRUE;
deleteList(vis_inv);
return ret_val;
}
void *identity_func(void *data) {
return data;
}
LIST *reverse_list(LIST *list) {
LIST *newlist = newList();
LIST_ITERATOR *list_i = newListIterator(list);
void *elem = NULL;
ITERATE_LIST(elem, list_i) {
listPut(newlist, elem);
} deleteListIterator(list_i);
return newlist;
}
bool parse_worldkey(const char *key, char *name, char *locale) {
*name = *locale = '\0';
int pos = next_letter_in(key, '@');
if(pos == -1)
return FALSE;
else {
strncpy(name, key, pos);
*(name+pos) = '\0';
strcpy(locale, key+pos+1);
if(*name == '\0' || *locale == '\0')
return FALSE;
return TRUE;
}
}
bool parse_worldkey_relative(CHAR_DATA *ch, const char *key, char *name,
char *locale) {
int pos = next_letter_in(key, '@');
if(pos != -1)
return parse_worldkey(key, name, locale);
else {
strcpy(name, key);
strcpy(locale, get_key_locale(roomGetClass(charGetRoom(ch))));
return TRUE;
}
}
const char *get_key_locale(const char *key) {
int pos = next_letter_in(key, '@');
if(pos == -1)
return "";
else
return key+pos+1;
}
const char *get_key_name(const char *key) {
int pos = next_letter_in(key, '@');
if(pos == -1)
return key;
else {
static char name[SMALL_BUFFER];
strcpy(name, key);
name[pos] = '\0';
return name;
}
}
const char *get_fullkey(const char *name, const char *locale) {
static char full_key[SMALL_BUFFER];
sprintf(full_key, "%s@%s", name, locale);
return full_key;
}
const char *get_fullkey_relative(const char *key, const char *locale) {
int pos = next_letter_in(key, '@');
if(pos > 0)
return key;
else {
static char full_key[SMALL_BUFFER];
sprintf(full_key, "%s@%s", key, locale);
return full_key;
}
}
const char *get_shortkey(const char *key, const char *to) {
// are we missing a locale?
int pos = next_letter_in(key, '@');
if(pos < 0)
return key;
// if 'to' doesn't exist, make sure we return the full thing back.
// Only relevant for attaching triggers to characters instead of mobiles
if(!*to)
return key;
// is 'to' missing a locale?
pos = next_letter_in(to, '@');
if(pos < 0)
return get_key_name(key);
// two keys, both with a name and a locale. See if our locales match up
static char name[SMALL_BUFFER];
static char locale[SMALL_BUFFER];
parse_worldkey(key, name, locale);
if(!strcmp(locale, get_key_locale(to)))
return name;
// different locales, return the full key
return key;
}
bool key_malformed(const char *key) {
int at_count = 0;
for(; *key; *key++) {
if(*key == '@') {
if(at_count > 0)
return TRUE;
at_count++;
}
else if(!(*key == '_' || isalpha(*key) || isdigit(*key)))
return TRUE;
}
return FALSE;
}
bool locale_malformed(const char *key) {
for(; *key; *key++) {
if(!(isalpha(*key) || isdigit(*key) || *key == '_'))
return TRUE;
}
return FALSE;
}
bool cmd_matches(const char *pattern, const char *cmd) {
int len = next_letter_in(pattern, '*');
// we have to match exactly
if(len == -1)
return !strcasecmp(pattern, cmd);
else if(len == 0)
return TRUE;
else
return !strncasecmp(pattern, cmd, len);
}
bool charHasMoreUserGroups(CHAR_DATA *ch1, CHAR_DATA *ch2) {
return (bitIsAllSet(charGetUserGroups(ch1),
bitvectorGetBits(charGetUserGroups(ch2))) &&
!bitIsAllSet(charGetUserGroups(ch2),
bitvectorGetBits(charGetUserGroups(ch1))));
}
bool canEditZone(ZONE_DATA *zone, CHAR_DATA *ch) {
return (!charIsNPC(ch) &&
(is_keyword(zoneGetEditors(zone), charGetName(ch), FALSE) ||
bitIsOneSet(charGetUserGroups(ch), "admin")));
}
bool file_exists(const char *fname) {
FILE *fl = fopen(fname, "r");
if(fl == NULL) return FALSE;
fclose(fl);
return TRUE;
}
bool dir_exists(const char *dname) {
DIR *dir = opendir(dname);
if(dir == NULL) return FALSE;
closedir(dir);
return TRUE;
}
void show_prompt(SOCKET_DATA *socket) {
if(socketGetChar(socket))
text_to_buffer(socket, custom_prompt(socketGetChar(socket)));
}
const char *custom_prompt(CHAR_DATA *ch) {
static char prompt[SMALL_BUFFER];
*prompt = '\0';
strcat(prompt, "\r\n{nprompt> ");
return prompt;
}
//
// Delete an object, room, mobile, etc... from the game. First remove it from
// the gameworld database, and then delete it and its contents. The onus is on
// the builder to make sure deleting a prototype won't screw anything up (e.g.
// people standing about in a room when it's deleted).
bool do_delete(CHAR_DATA *ch, const char *type, void *deleter, const char *arg){
void (* delete_func)(void *data) = deleter;
void *data = NULL;
const char *key = get_fullkey_relative(arg,
get_key_locale(roomGetClass(charGetRoom(ch))));
ZONE_DATA *zone = worldGetZone(gameworld, get_key_locale(key));
if(!arg || !*arg)
send_to_char(ch, "Which %s did you want to delete?\r\n", type);
else if(key_malformed(arg))
send_to_char(ch, "The %s key you entered was malformed.\r\n", type);
else if(zone == NULL)
send_to_char(ch, "No such zone exists.\r\n");
else if(!canEditZone(zone, ch))
send_to_char(ch, "You are not authorized to edit that zone.\r\n");
else if((data = worldRemoveType(gameworld, type, key)) == NULL)
send_to_char(ch, "The %s you tried to delete does not exist.\r\n", type);
else {
send_to_char(ch, "You remove the %s %s from the world database.\r\n",
key, type);
delete_func(data);
return TRUE;
}
return FALSE;
}
//
// generic xxxlist for builders.
void do_list(CHAR_DATA *ch, const char *locale, const char *type,
const char *header, void *informer) {
if(locale_malformed(locale)) {
send_to_char(ch, "You supplied a malformed zone name.\r\n");
return;
}
ZONE_DATA *zone = worldGetZone(gameworld, locale);
if(zone == NULL)
send_to_char(ch, "No such zone exists.\r\n");
else {
const char *(* info_func)(void *) = informer;
LIST *name_list = zoneGetTypeKeys(zone, type);
listSortWith(name_list, strcasecmp);
LIST_ITERATOR *name_i = newListIterator(name_list);
char *name = NULL;
BUFFER *buf = newBuffer(1);
void *data = NULL;
bprintf(buf, " {wKey %74s \r\n"
"{b--------------------------------------------------------------------------------{n\r\n", header);
ITERATE_LIST(name, name_i) {
data = worldGetType(gameworld, type, get_fullkey(name, locale));
if(data != NULL)
bprintf(buf, " {c%-20s %57s{n\r\n", name,
(info_func ? info_func(zoneGetType(zone, type, name)) : ""));
} deleteListIterator(name_i);
deleteListWith(name_list, free);
page_string(charGetSocket(ch), bufferString(buf));
deleteBuffer(buf);
}
}
//
// moves something of the given type with one name to the other name
bool do_rename(CHAR_DATA *ch,const char *type,const char *from,const char *to) {
// make sure we can edit all of the zones involved
const char *locale = get_key_locale(roomGetClass(charGetRoom(ch)));
void *tgt = NULL;
ZONE_DATA *zone = NULL;
// make sure everything is formed properly
if(key_malformed(from) || key_malformed(to))
send_to_char(ch, "You entered a malformed %s key.\r\n", type);
// make sure "to" does not already exist, and that we have zone editing privs
else if((zone = worldGetZone(gameworld,
get_key_locale(get_fullkey_relative(to, locale)))) == NULL)
send_to_char(ch, "Destination zone does not exist!\r\n");
else if(!canEditZone(zone, ch))
send_to_char(ch, "You cannot edit the destination zone.\r\n");
else if(worldGetType(gameworld, type, get_fullkey_relative(to, locale)))
send_to_char(ch, "%s already exists!\r\n", to);
else {
// make sure "from" exists, and that we have zone editing privs
if((zone = worldGetZone(gameworld,
get_key_locale(get_fullkey_relative(from, locale)))) == NULL)
send_to_char(ch, "The originating zone does not exist!\r\n");
else if(!canEditZone(zone, ch))
send_to_char(ch, "You do not have editing priviledges for %s!\r\n", from);
else if( (tgt = worldRemoveType(gameworld, type,
get_fullkey_relative(from, locale))) == NULL)
send_to_char(ch, "%s %s does not exist.\r\n", from, type);
else {
send_to_char(ch, "%s %s renamed to %s.\r\n", from, type, to);
worldPutType(gameworld, type, get_fullkey_relative(to, locale), tgt);
worldSaveType(gameworld, type, get_fullkey_relative(to, locale));
return TRUE;
}
}
// failed!
return FALSE;
}