#ifndef __UTILS_H
#define __UTILS_H
//*****************************************************************************
//
// utils.h
//
// macros and definitions of miscellaneous utilities
//
//*****************************************************************************
//*****************************************************************************
// Utilities for numbers
//*****************************************************************************
#define MAX_INT 214743647
#define PI 3.14159265
#define MATH_E 2.71828182
#define UMIN(a, b) ((a) < (b) ? (a) : (b))
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
#ifndef MAX
#define MAX(a, b) ((a) < (b) ? (b) : (a))
#endif
//
// return a random number pulled from a uniform distribution
// between the two bounds
int rand_number(int min, int max);
//
// Returns a random number between 0 and 1. Numbers are evenly distributed
double rand_percent(void);
//
// Return a random number pulled from N(0, 1)
double rand_gaussian(void);
//
// Returns a sigmoid transformation of the specified number
double sigmoid(double val);
//
// return the rd, th, nd, for a number
const char *numth(int num);
//*****************************************************************************
// Utilities for characters
//*****************************************************************************
#define IS_ADMIN(ch) (bitIsOneSet(charGetUserGroups(ch), "admin"))
#define HIMHER(ch) (charGetSex(ch) == SEX_MALE ? "him" : \
(charGetSex(ch) == SEX_FEMALE ? "her" : "it"))
#define HISHER(ch) (charGetSex(ch) == SEX_MALE ? "his" : \
(charGetSex(ch) == SEX_FEMALE ? "her" : "its"))
#define HESHE(ch) (charGetSex(ch) == SEX_MALE ? "he" : \
(charGetSex(ch) == SEX_FEMALE ? "she" : "it"))
bool can_see_char ( CHAR_DATA *ch, CHAR_DATA *target);
bool can_see_obj ( CHAR_DATA *ch, OBJ_DATA *target);
bool can_see_exit ( CHAR_DATA *ch, EXIT_DATA *exit);
bool try_enter_game ( CHAR_DATA *ch);
int can_see_hidden ( CHAR_DATA *ch);
int can_see_invis ( CHAR_DATA *ch);
//
// returns the target's name if the ch can see the target,
// and returns SOMEONE/SOMETHING otherwise.
const char *see_char_as (CHAR_DATA *ch, CHAR_DATA *target);
const char *see_obj_as (CHAR_DATA *ch, OBJ_DATA *target);
void show_prompt(SOCKET_DATA *socket);
const char *custom_prompt (CHAR_DATA *ch);
//*****************************************************************************
// Utilities for bit manipulations and bitvectors
//*****************************************************************************
#define BITS_PER_BITVECTOR 32
#define IS_SET(flag,bit) ((flag) & (bit))
#define SET_BIT(var,bit) ((var) |= (bit))
#define REMOVE_BIT(var,bit) ((var) &= ~(bit))
#define TOGGLE_BIT(var,bit) ((var) ^= (bit))
bitvector_t parse_bits(const char *string);
const char *write_bits(bitvector_t bits);
void print_bits(bitvector_t bits, const char **names, char *buf);
//*****************************************************************************
// String utilities.
//*****************************************************************************
#define CLEAR_SCREEN "\033[H\033[J"
#define AN(string) (strchr("AEIOU", toupper(*string)) ? "an" : "a")
#define strdupsafe(string) strdup(string ? string : "")
LIST *parse_strings (const char *string, char delimeter);
LIST *parse_keywords (const char *keywords);
bool dup_keywords_exist (const char *keywords);
bool is_keyword (const char *keywords, const char *word,
bool abbrev_ok);
int find_keyword (const char *keywords, const char *string);
void add_keyword (char **keywords_ptr, const char *word);
void remove_keyword (char *keywords, const char *word);
void trim (char *string);
void strip_word (char *string, const char *word);
void buf_tag_keywords (BUFFER *buf, const char *keywords,
const char *start_tag, const char *end_tag);
int count_letters (const char *string, const char ch, const int strlen);
int count_occurences (const char *string, const char *word);
char *line_start (char *string, int line);
int fgetline (FILE *file, char *p, int maxlen);
void center_string (char *buf, const char *string, int linelen,
int buflen, bool border);
int next_space_in (const char *string);
int next_letter_in (const char *string, char marker);
int string_hash (const char *key);
bool endswith (const char *string, const char *end);
bool startswith (const char *string, const char *start);
const char *strcpyto (char *to, const char *from, char end);
//*****************************************************************************
// utilities for game functioning
//*****************************************************************************
// remove the thing from the game, and delete it
void extract_mobile(CHAR_DATA *ch);
void extract_obj(OBJ_DATA *obj);
void extract_room(ROOM_DATA *room);
// don't call these. These are for use by gameloop.c only. Use the non-final
// versions, please!!
void extract_mobile_final(CHAR_DATA *ch);
void extract_obj_final(OBJ_DATA *obj);
void extract_room_final(ROOM_DATA *room);
char *get_time ( void );
void communicate ( CHAR_DATA *dMob, char *txt, int range );
void load_muddata ( void );
CHAR_DATA *check_reconnect( const char *player );
// transfers things from one room to another
void do_mass_transfer(ROOM_DATA *from, ROOM_DATA *to, bool chars, bool mobs,
bool objs);
//*****************************************************************************
// misc utils
//*****************************************************************************
//
// a function that breaks a type key into its name and locale (zone). Each key
// must contain its name and zone, separated by an @. For instance:
// sword@bobs_zone
//
// returns true if the name and locale were successfully found. It is assumed
// there will be enough memory in the name and locale buffers to copy data over
bool parse_worldkey(const char *key, char *name, char *locale);
//
// same as parse_worldkey, but if no locale is supplied, use the zone that the
// character is currently in
bool parse_worldkey_relative(CHAR_DATA *ch, const char *key, char *name,
char *locale);
//
// returns the locale of a key, and \0 if none exists
const char *get_key_locale(const char *key);
//
// returns the name of a key, and \0 if none exists
const char *get_key_name(const char *key);
//
// returns the full key of something. A full key is a name and a locale (zone
// key) separated by an @ sign. Assumes name and locale are both valid (i.e.
// neither have an @ sign in them).
const char *get_fullkey(const char *name, const char *locale);
//
// returns the full key of something (name + locale), relative to the supplied
// locale. If the key doesn't already have a locale, this function will build
// the one supplied into the returned value.
const char *get_fullkey_relative(const char *key, const char *locale);
//
// Returns whether or not the command matches the pattern. Patterns are just
// like commands, except they can be terminated with *'s to signify that
// "anything can follow at this point". Example matches might include:
//
// PATTERN MATCHES NON-MATCHES
// go* goto, gossip, go g
// go go g, goss, gossip
bool cmd_matches(const char *pattern, const char *cmd);
//
// returns TRUE if ch1 belongs to more user groups than ch2. By "more", we mean
// that ch2's user groups must be a subset of ch1's
bool charHasMoreUserGroups(CHAR_DATA *ch1, CHAR_DATA *ch2);
//
// returns TRUE if the character can edit the given zone
bool canEditZone(ZONE_DATA *zone, CHAR_DATA *ch);
//
// a function that returns the argument passed into it
void *identity_func(void *data);
//
// returns a copy of the list with everything in reverse order
LIST *reverse_list(LIST *list);
//
// checks to see if a file or directory exists
bool file_exists(const char *fname);
bool dir_exists (const char *dname);
//
// count how many objects are in the list, that meet our critereon.
// If name is not NULL, we search by name. Otherwise, we search by prototype.
// must_see TRUE, a looker must be supplied. Same thing goes for count_letters
int count_objs (CHAR_DATA *looker, LIST *list, const char *name,
const char *prototype, bool must_see);
int count_chars (CHAR_DATA *looker, LIST *list, const char *name,
const char *prototype, bool must_see);
CHAR_DATA *find_char(CHAR_DATA *looker, LIST *list, int num, const char *name,
const char *prototype, bool must_see);
OBJ_DATA *find_obj (CHAR_DATA *looker, LIST *list, int num, const char *name,
const char *prototype, bool must_see);
LIST *find_all_chars(CHAR_DATA *looker, LIST *list, const char *name,
const char *prototype, bool must_see);
LIST *find_all_objs(CHAR_DATA *looker, LIST *list, const char *name,
const char *prototype, bool must_see);
// in the various find() routines, it may sometimes arise that someone
// wants to find multiple things (e.g. all.cookies, all.women). This is
// the numeric marker to represent all.
#define COUNT_ALL (-1)
//
// split a string into it's target and count number.
// e.g. all.cookie splits into cookie and all
// 2.woman splits into woman and 2
void get_count(const char *buf, char *target, int *count);
//
// reverse of get_count
void print_count(char *buf, const char *target, int count);
//
// return a comma-separated list of the list elements, as represented
// by the descriptor function. If there is more than one element in the list,
// the last element is separated by an "and" as well. If there are just two
// elements, then the last comma isn't used. If one element has the same
// descriptor as another element, they are printed as a group - either by
// the description given from multi_descriptor, or with a number before the
// regular descriptor representing how many of the things are present.
//
// e.g. a man, a woman, a dog, and a child.
// a man and a woman
// (5) a man
// a group of 5 men
char *print_list(LIST *list, void *descriptor, void *multi_descriptor);
//
// descriptor is a pointer to the function that gets a copy of the
// thing's description.
//
// multi-descriptor is a pointer to the function that gets a copy of the
// thing's description if there is more than 1 copy of it in the list.
void show_list(CHAR_DATA *ch, LIST *list, void *descriptor,
void *multi_descriptor);
//
// Return a list of all items in the current list that do not have
// people sitting on or at them. The returned list must be deleted
// after use.
LIST *get_unused_items(CHAR_DATA *ch, LIST *list, bool invis_ok);
//
// The opposite of get_unused_items
LIST *get_used_items(CHAR_DATA *ch, LIST *list, bool invis_ok);
//
// returns true if the character has an object that is an instance of the
// specified prototype in his inventory. Returns false otherwise.
bool has_obj(CHAR_DATA *ch, const char *prototype);
//
// 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);
//
// generic xxxlist for listing all the entries of one type for a zone (e.g.
// mprotos, oprotos, scripts...)
void do_list(CHAR_DATA *ch, const char *locale, const char *type,
const char *header, void *informer);
//
// 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);
#endif // __UTILS_H