/***************************************************************************
* 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. *
* *
* Dystopia Mud improvements copyright (C) 2000, 2001 by Brian Graversen *
* *
* 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. *
***************************************************************************/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <ctype.h>
#include "merc.h"
POLL_DATA * poll_list = NULL;
CHANGE_DATA * change_list = NULL;
CHANGE_DATA * change_last = NULL;
CHANGE_DATA * change_free = NULL;
ALIAS_DATA * alias_free = NULL;
ACCOUNT_DATA * account_free = NULL;
bool gFound;
#define RID ROOM_INDEX_DATA
bool examine_room args (( RID *pRoom, RID *tRoom, AREA_DATA *pArea, int steps ));
void dijkstra args (( RID *chRoom, RID *victRoom ));
RID *heap_getMinElement args (( HEAP *heap ));
HEAP *init_heap args (( RID *root ));
/*
* Knuth-Morris-Pratt Pattern Matching Algorithm (sensitive)
*/
bool is_contained2(const char *astr, const char *bstr)
{
int n, m;
m = strlen(astr);
n = strlen(bstr);
/* if the pattern is longer than the string */
if (m > n) return FALSE;
{
int f[m], i = 1, j = 0;
f[0] = 0;
/* calculating the error fuction f[] */
while (i < m)
{
if (astr[j] == astr[i])
{
f[i] = j + 1;
i++; j++;
}
else if (j > 0) j = f[j - 1];
else
{
f[i] = 0;
i++;
}
}
j = 0;
/* KMP algorith */
for (i = 0; i < n; i++)
{
while (j > 0 && astr[j] != bstr[i])
j = f[j-1];
if (astr[j] == bstr[i]) j++;
if (j == m) return TRUE;
}
}
return FALSE;
}
/*
* Knuth-Morris-Pratt Pattern Matching Algorithm (insensitive)
*/
bool is_contained(const char *astr, const char *bstr)
{
int n, m;
m = strlen(astr);
n = strlen(bstr);
/* if the pattern is longer than the string */
if (m > n) return FALSE;
{
int f[m], i = 1, j = 0;
f[0] = 0;
/* calculating the error fuction f[] */
while (i < m)
{
if (UPPER(astr[j]) == UPPER(astr[i]))
{
f[i] = j + 1;
i++; j++;
}
else if (j > 0) j = f[j - 1];
else
{
f[i] = 0;
i++;
}
}
j = 0;
/* KMP algorith */
for (i = 0; i < n; i++)
{
while (j > 0 && UPPER(astr[j]) != UPPER(bstr[i]))
j = f[j-1];
if (UPPER(astr[j]) == UPPER(bstr[i])) j++;
if (j == m) return TRUE;
}
}
return FALSE;
}
int strlen2(const char *s)
{
int i, b, count=0;
if (s[0] == '\0') return 0;
b = strlen(s);
for (i = 0; i < b; i++)
{
if (s[i] == '#') count++;
}
return (b + 7 * count);
}
void win_prize( CHAR_DATA *ch )
{
int i,vnum;
OBJ_DATA *obj;
OBJ_INDEX_DATA *pIndex;
if (IS_NPC(ch)) return;
i = number_range(1,100);
if (i < 90) vnum = OBJ_VNUM_PROTOPLASM;
else if (i < 95) vnum = 221;
else vnum = 222;
if ((pIndex = get_obj_index(vnum)) == NULL)
{
bug("BAD PRIZE!!",0);
return;
}
obj = create_object(pIndex, 50);
if (vnum == OBJ_VNUM_PROTOPLASM)
{
obj->level = 1;
free_string(obj->short_descr);
free_string(obj->name);
free_string(obj->description);
obj->short_descr = str_dup("A prize token");
obj->description = str_dup("A token lies on the floor");
obj->name = str_dup("prize token");
obj->value[0] = number_range(100,300);
obj->item_type = ITEM_QUEST;
}
obj_to_char(obj,ch);
return;
}
void do_clearstats2( CHAR_DATA *ch, char *argument )
{
OBJ_DATA *obj;
OBJ_DATA *obj_next;
if (IS_NPC(ch)) return;
for ( obj = ch->carrying; obj != NULL; obj = obj_next )
{
obj_next = obj->next_content;
if ( obj->wear_loc != WEAR_NONE )
{obj_from_char(obj); obj_to_char(obj,ch);}
}
while ( ch->affected )
affect_remove( ch, ch->affected );
REMOVE_BIT(ch->affected_by, AFF_POLYMORPH);
REMOVE_BIT(ch->affected_by, AFF_ETHEREAL);
ch->affected_by = 0;
ch->armor = 100;
ch->hit = UMAX( 1, ch->hit );
ch->mana = UMAX( 1, ch->mana );
ch->move = UMAX( 1, ch->move );
ch->hitroll = 0;
ch->damroll = 0;
ch->saving_throw = 0;
ch->pcdata->mod_str = 0;
ch->pcdata->mod_int = 0;
ch->pcdata->mod_wis = 0;
ch->pcdata->mod_dex = 0;
ch->pcdata->mod_con = 0;
ch->pcdata->followers = 0;
if (IS_POLYAFF(ch, POLY_ZULOFORM)) REMOVE_BIT(ch->polyaff, POLY_ZULOFORM);
save_char_obj( ch );
send_to_char("Your stats have been cleared. Please rewear your equipment.\n\r",ch);
return;
}
void ragnarok_stop()
{
DESCRIPTOR_DATA *d;
ragnarok = FALSE;
do_info(NULL,"#CPeace has been restored in the realms, the time of ragnarok is no more#n");
for (d = descriptor_list; d != NULL; d = d->next)
{
if (d->character && d->connected == CON_PLAYING)
{
d->character->fight_timer = 0;
d->character->pcdata->safe_counter = 5;
do_call(d->character,"all");
do_restore(d->character,"self");
}
}
return;
}
void logout_message(CHAR_DATA *ch)
{
static char * const he_she [] = { "XX", "he", "she" };
static char * const him_her [] = { "XX", "him", "her" };
static char * const his_her [] = { "XX", "his", "her" };
DESCRIPTOR_DATA *d;
char buf[400]; // that should be plenty.
const char *dmess;
const char *i;
char *ptr2;
char *ptr;
int size;
size = strlen2(ch->pcdata->logoutmessage);
if (size > 380)
{
bug("Bad logoutmessage.",0);
return;
}
ptr2 = "#C<- #RLeaves #C->#n ";
ptr = buf;
dmess = ch->pcdata->logoutmessage;
while ((*ptr = *ptr2) != '\0')
++ptr, ++ptr2;
while (*dmess != '\0')
{
if ( *dmess != '$' )
{
*ptr++ = *dmess++;
continue;
}
++dmess;
switch (*dmess)
{
default: i = ""; break;
case 'n': i = ch->name; break;
case 'e': i = he_she [URANGE(1, ch->sex, 2)]; break;
case 'm': i = him_her [URANGE(1, ch->sex, 2)]; break;
case 's': i = his_her [URANGE(1, ch->sex, 2)]; break;
}
++dmess;
/* copying the data into the pointer */
while ((*ptr = *i) != '\0')
++ptr, ++i;
}
*ptr++ = '\n';
*ptr++ = '\r';
for (d = descriptor_list; d; d = d->next)
{
if (d->lookup_status != STATUS_DONE) continue;
if (d->connected != CON_PLAYING ) continue;
write_to_buffer( d, buf, ptr - buf );
}
return;
}
void tie_message(CHAR_DATA *ch, CHAR_DATA *victim)
{
static char * const he_she [] = { "XX", "he", "she" };
static char * const him_her [] = { "XX", "him", "her" };
static char * const his_her [] = { "XX", "his", "her" };
DESCRIPTOR_DATA *d;
char buf[400]; // that should be plenty.
const char *dmess;
const char *i;
char *ptr2;
char *ptr;
int size;
size = strlen2(ch->pcdata->tiemessage);
if (size > 380)
{
bug("Bad tiemessage.",0);
return;
}
ptr2 = "#C<- #RTie #C->#n ";
ptr = buf;
dmess = ch->pcdata->tiemessage;
while ((*ptr = *ptr2) != '\0')
++ptr, ++ptr2;
while (*dmess != '\0')
{
if ( *dmess != '$' )
{
*ptr++ = *dmess++;
continue;
}
++dmess;
switch (*dmess)
{
default: i = ""; break;
case 'n': i = ch->name; break;
case 'e': i = he_she [URANGE(1, ch->sex, 2)]; break;
case 'm': i = him_her [URANGE(1, ch->sex, 2)]; break;
case 's': i = his_her [URANGE(1, ch->sex, 2)]; break;
case 'N': i = victim->name; break;
case 'S': i = his_her [URANGE(1, victim->sex, 2)]; break;
case 'M': i = him_her [URANGE(1, victim->sex, 2)]; break;
case 'E': i = he_she [URANGE(1, victim->sex, 2)]; break;
}
++dmess;
/* copying the data into the pointer */
while ((*ptr = *i) != '\0')
++ptr, ++i;
}
*ptr++ = '\n';
*ptr++ = '\r';
for (d = descriptor_list; d; d = d->next)
{
if (d->lookup_status != STATUS_DONE) continue;
if (d->connected != CON_PLAYING ) continue;
write_to_buffer( d, buf, ptr - buf );
}
return;
}
void login_message(CHAR_DATA *ch)
{
static char * const he_she [] = { "XX", "he", "she" };
static char * const him_her [] = { "XX", "him", "her" };
static char * const his_her [] = { "XX", "his", "her" };
DESCRIPTOR_DATA *d;
char buf[400]; // that should be plenty.
const char *dmess;
const char *i;
char *ptr2;
char *ptr;
int size;
size = strlen2(ch->pcdata->loginmessage);
if (size > 380)
{
bug("Bad loginmessage.",0);
return;
}
ptr2 = "#C<- #REnters #C->#n ";
ptr = buf;
dmess = ch->pcdata->loginmessage;
while ((*ptr = *ptr2) != '\0')
++ptr, ++ptr2;
while (*dmess != '\0')
{
if ( *dmess != '$' )
{
*ptr++ = *dmess++;
continue;
}
++dmess;
switch (*dmess)
{
default: i = ""; break;
case 'n': i = ch->name; break;
case 'e': i = he_she [URANGE(1, ch->sex, 2)]; break;
case 'm': i = him_her [URANGE(1, ch->sex, 2)]; break;
case 's': i = his_her [URANGE(1, ch->sex, 2)]; break;
}
++dmess;
/* copying the data into the pointer */
while ((*ptr = *i) != '\0')
++ptr, ++i;
}
*ptr++ = '\n';
*ptr++ = '\r';
for (d = descriptor_list; d; d = d->next)
{
if (d->lookup_status != STATUS_DONE) continue;
if (d->connected != CON_PLAYING ) continue;
write_to_buffer( d, buf, ptr - buf );
}
return;
}
void avatar_message(CHAR_DATA *ch)
{
static char * const he_she [] = { "XX", "he", "she" };
static char * const him_her [] = { "XX", "him", "her" };
static char * const his_her [] = { "XX", "his", "her" };
DESCRIPTOR_DATA *d;
char buf[400]; // that should be plenty.
const char *dmess;
const char *i;
char *ptr2;
char *ptr;
int size;
size = strlen2(ch->pcdata->avatarmessage);
if (size > 380)
{
bug("Bad loginmessage.",0);
return;
}
ptr2 = "#C<- #RAvatar #C->#n ";
ptr = buf;
dmess = ch->pcdata->avatarmessage;
while ((*ptr = *ptr2) != '\0')
++ptr, ++ptr2;
while (*dmess != '\0')
{
if ( *dmess != '$' )
{
*ptr++ = *dmess++;
continue;
}
++dmess;
switch (*dmess)
{
default: i = ""; break;
case 'n': i = ch->name; break;
case 'e': i = he_she [URANGE(1, ch->sex, 2)]; break;
case 'm': i = him_her [URANGE(1, ch->sex, 2)]; break;
case 's': i = his_her [URANGE(1, ch->sex, 2)]; break;
}
++dmess;
/* copying the data into the pointer */
while ((*ptr = *i) != '\0')
++ptr, ++i;
}
*ptr++ = '\n';
*ptr++ = '\r';
for (d = descriptor_list; d; d = d->next)
{
if (d->lookup_status != STATUS_DONE) continue;
if (d->connected != CON_PLAYING ) continue;
write_to_buffer( d, buf, ptr - buf );
}
return;
}
int get_ratio(CHAR_DATA *ch)
{
long ratio;
if (IS_NPC(ch)) return 0;
if ((ch->pkill + ch->pdeath) == 0) ratio = 0; // to avoid divide by zero.
else if (ch->pkill > ch->pdeath)
ratio = ch->pkill * 100 * ((ch->pkill * ch->pkill) - (ch->pdeath * ch->pdeath))/((ch->pkill + ch->pdeath) * (ch->pkill + ch->pdeath));
else if (ch->pkill > 0)
ratio = (-100) * (ch->pdeath - ch->pkill) / ch->pkill;
else
ratio = (-100) * ch->pdeath;
return (int) ratio;
}
bool reachedDecapLimit( CHAR_DATA *ch )
{
AFFECT_DATA *paf;
OBJ_DATA *obj;
int limit = 0, objhps = 0, spellhps = 0;
int hps, i;
if (IS_NPC(ch)) return TRUE;
if (ch->level > 6) return FALSE;
for (i = 0; i < MAX_WEAR; i++)
{
if ((obj = get_eq_char(ch, i)) == NULL) continue;
for (paf = obj->pIndexData->affected; paf; paf = paf->next)
{
if (paf->location == APPLY_HIT)
objhps += paf->modifier;
}
for (paf = obj->affected; paf; paf = paf->next)
{
if (paf->location == APPLY_HIT)
objhps += paf->modifier;
}
}
hps = (ch->max_hit - (spellhps + objhps));
if (hps > 10000) limit += 10;
else limit += hps/1000;
if ((hps -= 10000) > 10000) limit += 20;
else if (hps > 0) limit += 2 * hps/1000;
if ((hps -= 10000) > 10000) limit += 30;
else if (hps > 0) limit += 3 * hps/1000;
if ((hps -= 10000) > 10000) limit += 40;
else if (hps > 0) limit += 4 * hps/1000;
if ((hps -= 10000) > 10000) limit += 50;
else if (hps > 0) limit += 5 * hps/1000;
if ((hps -= 10000) > 10000) limit += 60;
else if (hps > 0) limit += 6 * hps/1000;
/*
* For those with no skill
*/
limit += ch->pdeath;
if (limit > ch->pkill) return FALSE;
else return TRUE;
}
void death_info(char *str)
{
DESCRIPTOR_DATA *d;
char buf[MAX_STRING_LENGTH];
if (str[0] == '\0') return;
sprintf(buf, "#C<- #RDeath #C->#n %s\n\r", str);
for (d = descriptor_list; d != NULL; d = d->next)
{
if (d->connected == CON_PLAYING && d->character != NULL)
send_to_char(buf, d->character);
}
return;
}
void avatar_info(char *str)
{
DESCRIPTOR_DATA *d;
char buf[MAX_STRING_LENGTH];
if (str[0] == '\0') return;
sprintf(buf, "#C<- #RAvatar #C->#n %s\n\r", str);
for (d = descriptor_list; d != NULL; d = d->next)
{
if (d->connected == CON_PLAYING && d->character != NULL)
send_to_char(buf, d->character);
}
return;
}
void leave_info(char *str)
{
DESCRIPTOR_DATA *d;
char buf[MAX_STRING_LENGTH];
if (str[0] == '\0') return;
sprintf(buf, "#C<- #RLeaves #C->#n %s\n\r", str);
for (d = descriptor_list; d != NULL; d = d->next)
{
if (d->connected == CON_PLAYING && d->character != NULL)
send_to_char(buf, d->character);
}
return;
}
void enter_info(char *str)
{
DESCRIPTOR_DATA *d;
char buf[MAX_STRING_LENGTH];
if (str[0] == '\0') return;
sprintf(buf, "#C<- #REnters #C->#n %s\n\r", str);
for (d = descriptor_list; d != NULL; d = d->next)
{
if (d->connected == CON_PLAYING && d->character != NULL)
send_to_char(buf, d->character);
}
return;
}
int getMight(CHAR_DATA *ch)
{
AFFECT_DATA *paf;
OBJ_DATA *obj;
int spellhps = 0;
int objhps = 0;
int might, temp, i;
for (i = 0; i < MAX_WEAR; i++)
{
if ((obj = get_eq_char(ch, i)) == NULL) continue;
for (paf = obj->pIndexData->affected; paf != NULL; paf = paf->next)
{
if (paf->location == APPLY_HIT)
objhps += paf->modifier;
}
for (paf = obj->affected; paf; paf = paf->next)
{
if (paf->location == APPLY_HIT)
objhps += paf->modifier;
}
}
might = (ch->max_hit - (spellhps + objhps))/100;
for (i = 0; i < 5; i++) might += UMIN(2, ch->spl[i]/100);
for (i = 0; i < 13; i++) might += UMIN(4, ch->wpn[i]/50);
for (i = 1; i < 11; i++) might += UMIN(4, ch->stance[i]/50);
if (IS_SET(ch->newbits, NEW_MASTERY)) might += 2;
if (IS_SET(ch->pcdata->jflags, JFLAG_SS5)) might += 250;
else if (IS_SET(ch->pcdata->jflags, JFLAG_SS4)) might += 200;
else if (IS_SET(ch->pcdata->jflags, JFLAG_SS3)) might += 150;
else if (IS_SET(ch->pcdata->jflags, JFLAG_SS2)) might += 100;
else if (IS_SET(ch->pcdata->jflags, JFLAG_SS1)) might += 50;
if (might >= 150)
{
if ((temp = get_ratio(ch)) >= 500) might += UMIN(100, temp / 50); // 10 points for each pkpower.
}
return might;
}
int getMightMod(CHAR_DATA *ch)
{
int might;
if (IS_NPC(ch)) return 0;
might = getMight(ch);
if (might < 150) return 0;
else if (might <= 350) return 10;
else if (might <= 500) return 20;
else if (might <= 750) return 30;
else if (might <= 1000) return 40;
else if (might <= 1250) return 50;
else if (might <= 1500) return 60;
else if (might <= 1750) return 70;
else if (might <= 2000) return 80;
else if (might <= 2250) return 90;
else if (might <= 2500) return 100;
else if (might <= 2750) return 110;
else if (might <= 3000) return 120;
else if (might <= 3250) return 130;
else if (might <= 3500) return 140;
else return 150;
}
void forge_affect(OBJ_DATA *obj, int value)
{
AFFECT_DATA paf;
paf.type = 0;
paf.duration = -1;
paf.location = APPLY_HITROLL;
paf.modifier = value;
paf.bitvector = 0;
affect_to_obj(obj, &paf);
paf.type = 0;
paf.duration = -1;
paf.location = APPLY_DAMROLL;
paf.modifier = value;
paf.bitvector = 0;
affect_to_obj(obj, &paf);
}
void dump_last_command()
{
FILE *fp;
char buf[MAX_STRING_LENGTH];
fp = fopen("../txt/crash.txt","a");
if (cmd_done)
fprintf (fp,"Last command typed : %s (thread count : %d) (command executed without flaws)\n",last_command, thread_count);
else
fprintf (fp,"Last command typed : %s (thread count : %d) (crash happended during this command)\n",last_command, thread_count);
fflush(fp);
fclose(fp);
/*
* creates a note to the immortals
*/
sprintf(buf, "It seems we have crashed, the last command typed was\n\r\n\r");
strcat(buf, last_command);
strcat(buf, "\n\r\n\rPlease remember that this doesn't mean that this caused the crash.\n\r\n\rRegards,\n\r\n\rThe Crash Code");
make_note("Immortal", "Crash Code", "imm", "We Crashed", 7, buf);
}
void update_revision(CHAR_DATA *ch)
{
if (IS_NPC(ch)) return;
if (ch->pcdata->revision == CURRENT_REVISION) return;
/*
* We don't end cases with break, since we want the player to be fully updated.
*/
switch (ch->pcdata->revision)
{
/*
case 0:
for (i = 0; i < MAX_WEAR; i++)
{
if ((obj = get_eq_char(ch, i)) == NULL) continue;
}
ch->pcdata->revision++;
break;
*/
}
return;
}
bool in_fortress(CHAR_DATA *ch)
{
if (!ch->in_room) return FALSE;
if (ch->in_room->vnum >= 151 && ch->in_room->vnum <= 170) return TRUE;
return FALSE;
}
bool in_arena(CHAR_DATA *ch)
{
if (!ch->in_room) return FALSE;
if (ch->in_room->vnum >= 101 && ch->in_room->vnum <= 150) return TRUE;
return FALSE;
}
void increase_total_output(int clenght)
{
total_output += clenght;
}
void update_mudinfo()
{
DESCRIPTOR_DATA *d;
int i, pcount = 0;
/*
* Each week, the data is stored to a file, and
* the variable cleared.
*/
if (mudinfo[MUDINFO_UPDATED] > 20160)
{
write_mudinfo_database();
for (i = 0; i < (MUDINFO_MAX - 2); i++)
{
mudinfo[i] = 0;
}
log_string("Mudinfo database updated.");
}
/* Increase update count */
mudinfo[MUDINFO_UPDATED]++;
/* Outdate the output data */
if (total_output > mudinfo[MUDINFO_DATA_PEAK]) mudinfo[MUDINFO_DATA_PEAK] = total_output;
/* The stored data */
if (mudinfo[MUDINFO_BYTE] > 1048576) // 1 megabyte
{
mudinfo[MUDINFO_MBYTE]++;
mudinfo[MUDINFO_BYTE] -= 1048576;
}
mudinfo[MUDINFO_BYTE] += total_output;
/* The temp data */
if (mudinfo[MUDINFO_BYTE_S] > 1048576) // 1 megabyte
{
mudinfo[MUDINFO_MBYTE_S]++;
mudinfo[MUDINFO_BYTE_S] -= 1048576;
}
mudinfo[MUDINFO_BYTE_S] += total_output;
/* We clear the counter */
total_output = 0;
for (d = descriptor_list; d; d = d->next)
{
if (d->connected == CON_PLAYING && d->lookup_status == STATUS_DONE)
{
if (d->character)
{
if (d->character->level < 7)
{
pcount++;
if (d->out_compress) mudinfo[MUDINFO_MCCP_USERS]++;
else mudinfo[MUDINFO_OTHER_USERS]++;
if (IS_SET(d->character->act, PLR_SOUND)) mudinfo[MUDINFO_MSP_USERS]++;
}
}
}
}
if (pcount > mudinfo[MUDINFO_PEAK_USERS]) mudinfo[MUDINFO_PEAK_USERS] = pcount;
save_mudinfo();
}
void recycle_descriptors()
{
DESCRIPTOR_DATA *dclose;
DESCRIPTOR_DATA *dclose_next;
for (dclose = descriptor_list; dclose; dclose = dclose_next)
{
dclose_next = dclose->next;
if (dclose->lookup_status != STATUS_CLOSED) continue;
/*
* First let's get it out of the descriptor list.
*/
if ( dclose == descriptor_list )
{
descriptor_list = descriptor_list->next;
}
else
{
DESCRIPTOR_DATA *d;
for (d = descriptor_list; d && d->next != dclose; d = d->next)
;
if (d != NULL)
d->next = dclose->next;
else
{
bug( "Recycle_descriptors: dclose not found.", 0 );
continue;
}
}
/*
* Clear out that memory
*/
free_string( dclose->host );
free_mem( dclose->outbuf, dclose->outsize );
/*
* Mccp
*/
if (dclose->out_compress)
{
deflateEnd(dclose->out_compress);
free_mem(dclose->out_compress_buf, COMPRESS_BUF_SIZE);
free_mem(dclose->out_compress, sizeof(z_stream));
}
/*
* Bye bye mr. Descriptor.
*/
close( dclose->descriptor );
/*
* And then we recycle
*/
dclose->next = descriptor_free;
descriptor_free = dclose;
}
}
int get_next_playerid()
{
top_playerid++;
save_coreinfo();
return top_playerid;
}
/*
* Writes a string straight to stderr
*/
void log_string2(const char *str)
{
char *strtime;
strtime = ctime(¤t_time);
strtime[strlen(strtime)-1] = '\0';
fprintf(stderr, "%s :: %s\n", strtime, str);
return;
}
void recycle_dummys()
{
DUMMY_ARG *dummy;
DUMMY_ARG *dummy_next;
for (dummy = dummy_list; dummy; dummy = dummy_next)
{
dummy_next = dummy->next;
if (dummy->status == 1) continue; // being used
if (dummy == dummy_list)
{
dummy_list = dummy_list->next;
}
else
{
DUMMY_ARG *prev;
/* we find the prev dummy arg */
for (prev = dummy_list; prev && prev->next != dummy; prev = prev->next)
;
if (prev != NULL)
prev->next = dummy->next;
else
{
bug( "Recycle_dymmys: dummy not found.", 0 );
continue;
}
/* recycle */
dummy->next = dummy_free;
dummy_free = dummy;
}
}
}
void check_help_soundex(char *argument, CHAR_DATA *ch)
{
HELP_DATA *pHelp;
char buf[MAX_STRING_LENGTH];
char tbuf[MAX_STRING_LENGTH];
char arg[MAX_INPUT_LENGTH];
char keyword[MAX_INPUT_LENGTH];
char *str;
bool found = FALSE;
one_argument(argument, arg);
if (arg[0] == '\0') return;
sprintf(buf, "\n\r[Perhaps:");
for (pHelp = first_help; pHelp; pHelp = pHelp->next)
{
if (pHelp->level > ch->level) continue;
str = pHelp->keyword;
str = one_argument(str, keyword);
while (keyword[0] != '\0')
{
if (SoundexMatch(GetSoundexKey(arg), GetSoundexKey(keyword)) > 75)
{
found = TRUE;
sprintf(tbuf, " %s", keyword);
strcat(buf, tbuf);
}
str = one_argument(str, keyword);
}
}
strcat(buf, "]\n\r");
if (found) send_to_char(buf, ch);
}
/*
* New system to replace status, called fair fight, it measures the
* difference between two players, giving them points for their
* stances, powers, and stats. If they are within each others range,
* the call will return TRUE, if not FALSE. Call for fair_fight when
* you need to see if a fight is fair (ie. decapping).
*/
bool fair_fight(CHAR_DATA *ch, CHAR_DATA *victim)
{
int iAggr, iDef;
if (IS_NPC(ch) || IS_NPC(victim)) return TRUE;
/*
* All the people that shouldn't be fighting anyway
*/
if (ch == victim) return FALSE;
if (ch->level != 3 || victim->level != 3) return FALSE;
iAggr = getMight(ch);
iDef = getMight(victim);
/* This is the lower limit for pk */
if (iDef < 150 || iAggr < 150) return FALSE;
if (reachedDecapLimit(ch)) return FALSE;
if (!str_cmp(ch->pcdata->retaliation, victim->name)) return TRUE;
if (!str_cmp(ch->pcdata->last_decap[0], victim->name)) return FALSE;
/* 2000 extra hps per paradox counter */
if (iAggr >= 150) iAggr += ch->pcdata->mean_paradox_counter * 20;
if (iDef >= 150) iDef += victim->pcdata->mean_paradox_counter * 20;
/*
* Checking to see if they are in range.
*/
if (iAggr * 0.80 > iDef) return FALSE;
/*
* They passed the test, FIGHT children.
*/
return TRUE;
}
void special_decap_message(CHAR_DATA *ch, CHAR_DATA *victim)
{
static char * const he_she [] = { "XX", "he", "she" };
static char * const him_her [] = { "XX", "him", "her" };
static char * const his_her [] = { "XX", "his", "her" };
DESCRIPTOR_DATA *d;
char buf[400]; // that should be plenty.
const char *dmess;
const char *i;
char *ptr2;
char *ptr;
int size;
size = strlen2(ch->pcdata->decapmessage);
if (size > 380)
{
bug("Bad decapmessage.",0);
return;
}
ptr2 = "#C<- #RDeath #C->#n ";
ptr = buf;
dmess = ch->pcdata->decapmessage;
while ((*ptr = *ptr2) != '\0')
++ptr, ++ptr2;
while (*dmess != '\0')
{
if ( *dmess != '$' )
{
*ptr++ = *dmess++;
continue;
}
++dmess;
switch (*dmess)
{
default: i = ""; break;
case 'n': i = ch->name; break;
case 'e': i = he_she [URANGE(1, ch->sex, 2)]; break;
case 'm': i = him_her [URANGE(1, ch->sex, 2)]; break;
case 's': i = his_her [URANGE(1, ch->sex, 2)]; break;
case 'N': i = victim->name; break;
case 'S': i = his_her [URANGE(1, victim->sex, 2)]; break;
case 'M': i = him_her [URANGE(1, victim->sex, 2)]; break;
case 'E': i = he_she [URANGE(1, victim->sex, 2)]; break;
}
++dmess;
/* copying the data into the pointer */
while ((*ptr = *i) != '\0')
++ptr, ++i;
}
*ptr++ = '\n';
*ptr++ = '\r';
for (d = descriptor_list; d; d = d->next)
{
if (d->lookup_status != STATUS_DONE) continue;
if (d->connected != CON_PLAYING ) continue;
write_to_buffer( d, buf, ptr - buf );
}
return;
}
void update_polls()
{
POLL_DATA *poll;
POLL_DATA *poll_next;
for (poll = poll_list; poll; poll = poll_next)
{
poll_next = poll->next;
if (poll->expire < current_time) complete_poll(poll);
}
}
/*
* It's not perfect, but it will do - Jobo
*/
void complete_poll(POLL_DATA *poll)
{
VOTE_DATA *vote;
POLL_DATA *prev;
char buf[MAX_STRING_LENGTH];
char buf2[MAX_STRING_LENGTH];
bool found = FALSE;
int i;
for (vote = poll->votes; vote; vote = vote->next)
{
free_string(vote->phost);
free_string(vote->pname);
}
if (poll == poll_list)
{
poll_list = poll->next;
found = TRUE;
}
else
{
for (prev = poll_list; prev; prev = prev->next)
{
if (prev->next != poll) continue;
found = TRUE;
prev->next = poll->next;
}
}
if (!found)
{
bug("Poll_complete: poll not found", 0);
return;
}
sprintf(buf, "Polling on %s completed.\n\r\n\r", poll->name);
for (i = 0; i < MAX_VOTE_OPTIONS; i++)
{
if (str_cmp(poll->options[i], "<null>"))
{
sprintf(buf2, "Option '%s' got %d votes.\n\r", poll->options[i], poll->vcount[i]);
strcat(buf, buf2);
}
free_string(poll->options[i]);
}
strcat(buf, "\n\rRegards, The Polling Code\n\r");
make_note("Announce", "Polling Code", "all", "Poll Completed", 7, buf);
free_string(poll->name);
save_polls();
do_info(NULL, "Poll completed, check the announce board for details.");
}
/*
* This function handles the actual removing of the change
*/
bool remove_change(int i)
{
CHANGE_DATA *change;
bool found = FALSE;
for (change = change_list; change; change = change->next)
{
if (--i > 0) continue;
found = TRUE;
/* clearing out the strings */
free_string(change->imm);
free_string(change->text);
free_string(change->date);
/* update the pointer to the last change if needed */
if (change == change_last) change_last = change->prev;
/* handle the special case of the first change */
if (change == change_list)
{
change_list = change->next;
if (change->next) change->next->prev = NULL;
}
else
{
change->prev->next = change->next;
if (change->next)
change->next->prev = change->prev;
}
/* Handle the free list */
change->next = change_free;
change->prev = NULL;
if (change_free) change_free->prev = change;
change_free = change;
/* terminate the loop */
break;
}
/* did we remove anything ? */
return found;
}
/*
* should always be called with a size that's 0 mod 4
*/
char *get_dystopia_banner(char *title, int size)
{
int tSize = strlen(title);
int patternsize, bufferspaces = 2, i, blcks;
static char buf[200];
/* just so we can use strcat */
buf[0] = '\0';
/* comment this out if you feel like it... */
if (size % 4)
log_string("Warning, calling get_dystopia_banner with a weird size");
/* if we dont want a title, let's fix that quick */
if (tSize == 0)
{
blcks = size / 4;
strcat(buf, "#0");
for (i = 0; i < blcks/2; i++)
strcat(buf, "<>==");
if (blcks % 2)
strcat(buf, "====");
for (i = 0; i < blcks/2; i++)
strcat(buf, "==<>");
strcat(buf, "#n");
return buf;
}
/* how much do we spend on patterns, and how much on spaces */
patternsize = size - (tSize + 2);
bufferspaces += patternsize % 8;
patternsize -= patternsize % 8;
blcks = patternsize / 4;
if (blcks < 1)
{
strcat(buf, "#0<>== #G");
strcat(buf, title);
strcat(buf, " #0==<>#n");
}
else
{
/* first add patterns */
strcat(buf, "#0");
for (i = 0; i < blcks/2; i++)
strcat(buf, "<>==");
/* add spaces, title, spaces */
for (i = 0; i < bufferspaces/2; i++)
strcat(buf, " ");
strcat(buf, "#G");
strcat(buf, title);
strcat(buf, "#0");
if (bufferspaces % 2)
strcat(buf, " ");
for (i = 0; i < bufferspaces/2; i++)
strcat(buf, " ");
/* then add the rest of the pattern */
for (i = 0; i < blcks/2; i++)
strcat(buf, "==<>");
strcat(buf, "#n");
}
return buf;
}
int calc_ratio(int a, int b)
{
int ratio;
if (b == 0 && a > 0) ratio = 100;
else if ((a + b) != 0) ratio = (100*a)/(a+b);
else ratio = 0;
return ratio;
}
char *strip_ansi(char *str)
{
static char buf[MAX_STRING_LENGTH];
char *ptr;
buf[0] = '\0';
ptr = buf;
while (*str != '\0')
{
if (*str != '#') *ptr++ = *str++;
else if (*(++str) != '\0') str++;
}
*ptr = '\0';
return buf;
}
char *line_indent(char *text, int wBegin, int wMax)
{
static char buf[MAX_STRING_LENGTH];
char *ptr;
char *ptr2;
int count = 0;
bool stop = FALSE;
int wEnd;
buf[0] = '\0';
ptr = text;
ptr2 = buf;
while (!stop)
{
if (count == 0)
{
if (*ptr == '\0') wEnd = wMax - wBegin;
else if (strlen(ptr) < (wMax - wBegin)) wEnd = wMax - wBegin;
else
{
int x = 0;
while (*(ptr + (wMax - wBegin - x)) != ' ') x++;
wEnd = wMax - wBegin - (x - 1);
if (wEnd < 1) wEnd = wMax - wBegin;
}
}
if (count == 0 && *ptr == ' ') ptr++;
else if (++count != wEnd)
{
if ((*ptr2++ = *ptr++) == '\0') stop = TRUE;
}
else if (*ptr == '\0')
{
stop = TRUE;
*ptr2 = '\0';
}
else
{
int k;
count = 0;
*ptr2++ = '\n';
*ptr2++ = '\r';
for (k = 0; k < wBegin; k++)
*ptr2++ = ' ';
}
}
return buf;
}
char *get_exits(CHAR_DATA *ch)
{
extern char *const dir_name[];
static char buf[MAX_STRING_LENGTH];
EXIT_DATA *pexit;
bool found;
int door;
buf[0] = '\0';
if (!check_blind(ch)) return "";
sprintf(buf, "#0[#GExits#9:#C");
found = FALSE;
for (door = 0; door <= 5; door++)
{
if ((pexit = ch->in_room->exit[door]) != NULL && pexit->to_room != NULL)
{
found = TRUE;
if (IS_SET(pexit->exit_info, EX_CLOSED))
{
strcat(buf, " #0(#C");
strcat(buf, dir_name[door]);
strcat(buf, "#0)#C");
}
else
{
strcat(buf, " ");
strcat(buf, dir_name[door]);
}
}
}
if (!found)
strcat(buf, " none");
strcat(buf, "#0]#n\n\r");
return buf;
}
void init_vt100(DESCRIPTOR_DATA *d, char *xbuf)
{
CHAR_DATA *ch;
char buf[MAX_STRING_LENGTH];
int i;
if ((ch = d->character) == NULL)
{
bug("Init_vt100: No character", 0);
return;
}
if ((i = atoi(xbuf)) < 10)
{
send_to_char("VT100 Failed.\n\r", ch);
return;
}
ch->pcdata->vt100_size = i;
SET_BIT(ch->pcdata->tempflag, TEMP_VT100);
sprintf(buf, "\e[%d;1H%s%s\e[1;1H%s%s\e[1;%dr",
i, VT_CLEAR_LINE, VT_SAVECURSOR, VT_SETWIN_CLEAR, VT_CLEAR_SCREEN, i - 2);
send_to_char(buf, ch);
send_to_char("VT100 Initialized.\n\r", ch);
return;
}
bool examine_room(RID *pRoom, RID *tRoom, AREA_DATA *pArea, int steps)
{
int door;
/* been here before, out of the area or can we get here faster */
if (pRoom->area != pArea) return FALSE;
if (pRoom->visited) return FALSE;
if (pRoom->steps < steps) return FALSE;
/* Have we found the room we are searching for */
if (pRoom == tRoom)
return TRUE;
/* mark the room so we know we have been here */
pRoom->visited = TRUE;
/* Depth first traversel of all exits */
for (door = 0; door < 6; door++)
{
if (pRoom->exit[door] == NULL) continue;
if (pRoom->exit[door]->to_room == NULL) continue;
/* assume we are walking the right way */
pRoom->exit[door]->color = TRUE;
/* recursive return */
if (examine_room(pRoom->exit[door]->to_room, tRoom, pArea, steps + 1))
return TRUE;
/* it seems we did not walk the right way */
pRoom->exit[door]->color = FALSE;
}
return FALSE;
}
HEAP *init_heap(RID *root)
{
AREA_DATA *pArea;
RID *pRoom;
HEAP * heap;
int i, size, vnum;
if ((pArea = root->area) == NULL) return NULL;
size = pArea->uvnum - pArea->lvnum;
if (size >= MAX_KNUDE)
{
bug("Init_heap: Size %d exceeds MAX_KNUDE", size);
return NULL;
}
heap = calloc(1, sizeof(*heap));
/* we want the root at the beginning */
heap->knude[1] = root;
heap->knude[1]->steps = 0;
heap->knude[1]->heap_index = 1;
/* initializing the rest of the heap */
for (i = 2, vnum = pArea->lvnum; vnum < pArea->uvnum; vnum++)
{
if ((pRoom = get_room_index(vnum)))
{
if (pRoom == root) continue;
heap->knude[i] = pRoom;
heap->knude[i]->steps = 2 * MAX_KNUDE;
heap->knude[i]->heap_index = i;
i++;
}
}
heap->iVertice = i-1;
/* setting the rest to NULL */
for (; i < MAX_KNUDE; i++)
heap->knude[i] = NULL;
return heap;
}
/*
* Finds the smallest element and returns it after
* making sure the heap is in perfect order after
* the removal of the vertice with the smallest
* element.
*/
RID *heap_getMinElement(HEAP *heap)
{
RID *tRoom;
RID *pRoom;
bool done = FALSE;
int i = 1;
/* this is the element we wish to return */
pRoom = heap->knude[1];
if (pRoom->steps == 2 * MAX_KNUDE)
bug("Removing room with max steps : %d", pRoom->vnum);
/* We move the last vertice to the front */
heap->knude[1] = heap->knude[heap->iVertice];
heap->knude[1]->heap_index = 1;
/* Decrease the size of the heap and remove the last entry */
heap->knude[heap->iVertice] = NULL;
heap->iVertice--;
/* Swap places till it fits */
while(!done)
{
if (heap->knude[i] == NULL)
done = TRUE;
else if (heap->knude[2*i] == NULL)
done = TRUE;
else if (heap->knude[2*i+1] == NULL)
{
if (heap->knude[i]->steps > heap->knude[2*i]->steps)
{
tRoom = heap->knude[i];
heap->knude[i] = heap->knude[2*i];
heap->knude[i]->heap_index = i;
heap->knude[2*i] = tRoom;
heap->knude[2*i]->heap_index = 2*i;
i = 2*i;
}
done = TRUE;
}
else if (heap->knude[i]->steps <= heap->knude[2*i]->steps &&
heap->knude[i]->steps <= heap->knude[2*i+1]->steps)
done = TRUE;
else if (heap->knude[2*i]->steps <= heap->knude[2*i+1]->steps)
{
tRoom = heap->knude[i];
heap->knude[i] = heap->knude[2*i];
heap->knude[i]->heap_index = i;
heap->knude[2*i] = tRoom;
heap->knude[2*i]->heap_index = 2*i;
i = 2*i;
}
else
{
tRoom = heap->knude[i];
heap->knude[i] = heap->knude[2*i+1];
heap->knude[i]->heap_index = i;
heap->knude[2*i+1] = tRoom;
heap->knude[2*i+1]->heap_index = 2*i+1;
i = 2*i+1;
}
}
/* return the element */
return pRoom;
}
void dijkstra(RID *chRoom, RID *victRoom)
{
RID *pRoom;
RID *tRoom;
RID *xRoom;
HEAP *heap;
int door, x;
bool stop;
/* allocate a new heap */
heap = init_heap(chRoom);
/* find shortest amounts of steps to each room */
while (heap->iVertice)
{
if ((pRoom = heap_getMinElement(heap)) == NULL)
{
bug("Dijstra: Getting NULL room", 0);
return;
}
if (pRoom == victRoom)
gFound = TRUE;
/* update all exits */
for (door = 0; door < 6; door++)
{
if (pRoom->exit[door] == NULL) continue;
if (pRoom->exit[door]->to_room == NULL) continue;
/* update step count, and swap in the heap */
if (pRoom->exit[door]->to_room->steps > pRoom->steps + 1)
{
xRoom = pRoom->exit[door]->to_room;
xRoom->steps = pRoom->steps + 1;
stop = FALSE;
while ((x = xRoom->heap_index) != 1 && !stop)
{
if (heap->knude[x/2]->steps > xRoom->steps)
{
tRoom = heap->knude[x/2];
heap->knude[x/2] = xRoom;
xRoom->heap_index = xRoom->heap_index/2;
heap->knude[x] = tRoom;
heap->knude[x]->heap_index = x;
}
else stop = TRUE;
}
}
}
}
/* free the heap */
free(heap);
}
char *pathfind(CHAR_DATA *ch, CHAR_DATA *victim)
{
int const exit_names [] = { 'n', 'e', 's', 'w', 'u', 'd' };
RID *pRoom;
AREA_DATA *pArea;
static char path[MAX_STRING_LENGTH]; // should be plenty.
int iPath = 0, vnum, door;
bool found;
if (!ch->in_room || !victim->in_room) return NULL;
if (ch->in_room == victim->in_room) return NULL;
if ((pArea = ch->in_room->area) != victim->in_room->area) return NULL;
/* initialize all rooms in the area */
for (vnum = pArea->lvnum; vnum < pArea->uvnum; vnum++)
{
if ((pRoom = get_room_index(vnum)))
{
pRoom->visited = FALSE;
for (door = 0; door < 6; door++)
{
if (pRoom->exit[door] == NULL) continue;
pRoom->exit[door]->color = FALSE;
}
}
}
/* initialize variables */
pRoom = ch->in_room;
gFound = FALSE;
/* In the first run, we only count steps, no coloring is done */
dijkstra(pRoom, victim->in_room);
/* If the target room was never found, we return NULL */
if (!gFound) return NULL;
/* in the second run, we color the shortest path using the step counts */
if (!examine_room(pRoom, victim->in_room, pArea, 0))
return NULL;
/* then we follow the trace */
while (pRoom != victim->in_room)
{
found = FALSE;
for (door = 0; door < 6 && !found; door++)
{
if (pRoom->exit[door] == NULL) continue;
if (pRoom->exit[door]->to_room == NULL) continue;
if (!pRoom->exit[door]->color) continue;
pRoom->exit[door]->color = FALSE;
found = TRUE;
path[iPath] = exit_names[door];
iPath++;
pRoom = pRoom->exit[door]->to_room;
}
if (!found)
{
bug("Pathfind: Fatal Error in %d.", pRoom->vnum);
return NULL;
}
}
path[iPath] = '\0';
return path;
}
/*
* Takes the expanded, unparsed string that makes up an alias,
* and the set of arguments given to this alias, which we must
* parse into the expanded string. It will also set a counter
* on the socket, preventing aliases from being used for the
* next X input lines, where X is the amount of lines this alias
* expands to. Anything beyond the first line in the alias is
* then stored in output_rest and only the first line is returned.
*
* It is assumed that output_rest has a size of MAX_STRING_LENGTH for
* bound checking. The code might be a bit dirty, but it gets
* the job done, and if I can live with it, so can you :)
*/
char *parse_alias(char *pString, char *argument, char *output_rest, DESCRIPTOR_DATA *dsock)
{
static char buf[MAX_STRING_LENGTH];
char argX[MAX_STRING_LENGTH];
char *pStr, *skipper;
bool first_line = TRUE;
int i, size_1 = 0, size_2 = 0;
buf[0] = '\0';
pStr = buf;
while (*pString != '\0')
{
if (*pString == '%' || *pString == '@')
{
if (isdigit(*(++pString)) && (i = *pString - '0') > 0)
{
/* find the Xth argument */
if (*(pString-1) == '%')
{
skipper = one_argument(argument, argX);
while (--i > 0)
skipper = one_argument(skipper, argX);
}
else
{
if (i == 1)
strcpy(argX, argument);
else
{
i--;
skipper = one_argument(argument, argX);
while (--i > 0)
skipper = one_argument(skipper, argX);
/* we want the tail, remember */
strcpy(argX, skipper);
}
}
if (first_line)
{
/* bounds checking */
*pStr = '\0';
size_1 += strlen(argX);
if (size_1 >= MAX_STRING_LENGTH - 1)
{
output_rest = "";
return ("\n\r");
}
i = 0;
while ((*pStr++ = argX[i++]) != '\0') ;
pStr--;
}
else
{
/* bounds checking */
*output_rest = '\0';
size_2 += strlen(argX);
if (size_2 >= MAX_STRING_LENGTH - 1)
{
output_rest = "";
return buf; /* we are so nice */
}
i = 0;
while ((*output_rest++ = argX[i++]) != '\0') ;
output_rest--;
}
pString++;
}
else if (first_line)
{
if (++size_1 < MAX_STRING_LENGTH - 1) /* safe bounds checking */
*pStr++ = *(pString-1);
}
else
{
if (++size_2 < MAX_STRING_LENGTH - 1) /* safe bounds checking */
*output_rest++ = *(pString-1);
}
}
else if (*pString == '\n' || *pString == '\r')
{
if (first_line)
{
/* scan past this initial linebreak, we will add our own */
while (*pString == '\n' || *pString == '\r') pString++;
/* add a terminator to the first line and stop adding to this line */
*pStr = '\0';
first_line = FALSE;
}
else
{
/* scan past this initial linebreak, we will add our own */
while (*pString == '\n' || *pString == '\r') pString++;
size_2 += 2;
if (size_2 < MAX_STRING_LENGTH - 1)
{
*output_rest++ = '\n';
*output_rest++ = '\r';
}
}
dsock->alias_block++;
}
else if (first_line)
{
if (++size_1 < MAX_STRING_LENGTH - 1) /* safe bounds checking */
*pStr++ = *pString++;
}
else
{
if (++size_2 < MAX_STRING_LENGTH - 1) /* safe bounds checking */
*output_rest++ = *pString++;
}
}
*output_rest = '\0';
return buf;
}
/*
* takes something like "Say hello:get %1 %2:snicker %3" and
* changes it to something like this
*
* Say hello\nget %1 %2\nsnicker %3\n
*/
void create_alias_string(char *arg)
{
while (*arg != '\0')
{
if (*arg == ':')
*arg = '\n';
arg++;
}
*arg++ = '\n';
*arg = '\0';
}
bool check_alias(char *incom, DESCRIPTOR_DATA *dsock)
{
ALIAS_DATA *alias;
CHAR_DATA *dMob;
char first_word[MAX_STRING_LENGTH];
char output_rest[MAX_STRING_LENGTH];
char *argument, *output_first;
/* let's see what we can do with this line of input */
argument = one_argument(incom, first_word);
/* if there are no player, we don't do anything at all */
if ((dMob = dsock->character) == NULL)
return FALSE;
/* check to see if we want to parse the input */
for (alias = dMob->pcdata->alias; alias; alias = alias->next)
{
/* does this alias match ? */
if (!str_cmp(first_word, alias->name))
{
/* let's parse this, and put the rest in the leftover department */
output_first = parse_alias(alias->expand_string, argument, output_rest, dsock);
/* copy this rounds output */
strcpy(dsock->incomm, output_first);
/* move the rest into a waiting position */
if ((strlen(output_rest) + strlen(dsock->inbuf)) > MAX_STRING_LENGTH - 2)
write_to_buffer(dsock, "\n\r!!!ALIAS OVERFLOW!!!\n\n\r", 0);
else
{
char buf[MAX_STRING_LENGTH];
sprintf(buf, "%s%s", output_rest, dsock->inbuf);
strcpy(dsock->inbuf, buf);
}
return TRUE;
}
}
/* we didn't find any matching aliases */
return FALSE;
}
ALIAS_DATA *alloc_alias()
{
ALIAS_DATA *alias;
if (alias_free)
{
alias = alias_free;
alias_free = alias_free->next;
}
else
{
if ((alias = alloc_perm(sizeof(*alias))) == NULL)
{
bug("Alloc_alias: Cannot allocate memory.", 0);
abort();
}
}
/* clearing the alias */
alias->name = NULL;
alias->expand_string = NULL;
alias->next = NULL;
return alias;
}
void alias_from_player(CHAR_DATA *ch, ALIAS_DATA *alias)
{
ALIAS_DATA *prev;
if (ch->pcdata->alias == alias)
ch->pcdata->alias = ch->pcdata->alias->next;
else
{
for (prev = ch->pcdata->alias; prev != NULL && prev->next != alias; prev = prev->next) ;
if (!prev)
{
bug("Alias_from_player: Alias not attached to player.", 0);
return;
}
prev->next = alias->next;
}
ch->pcdata->alias_count--;
free_string(alias->name);
free_string(alias->expand_string);
alias->next = alias_free;
alias_free = alias;
}
ACCOUNT_DATA *alloc_account()
{
static ACCOUNT_DATA clear_account;
ACCOUNT_DATA *account;
if (account_free)
{
account = account_free;
account_free = account_free->next;
}
else
{
if ((account = alloc_perm(sizeof(*account))) == NULL)
{
bug("Alloc_account: Cannot allocate memory.", 0);
abort();
}
}
*account = clear_account;
account->owner = str_dup("");
account->password = str_dup("");
account->new_password = str_dup("");
account->players = str_dup("");
account->level = PLAYER_ACCOUNT;
account->denied = (time_t) 0;
account->p_count = 0;
return account;
}
void close_account(ACCOUNT_DATA *account)
{
/* free the memory */
free_string(account->players);
free_string(account->password);
free_string(account->owner);
free_string(account->new_password);
/* attach to free list */
account->next = account_free;
account_free = account;
}
void show_options(DESCRIPTOR_DATA *dsock)
{
char buf[MAX_STRING_LENGTH];
struct plist *p_list;
p_list = parse_player_list(dsock->account->players);
sprintf(buf, "\n\n\rWelcome %s. What's your game today ?\n\n\r", dsock->account->owner);
write_to_buffer(dsock, buf, 0);
if (p_list->count > 0)
{
write_to_buffer(dsock, " #W#uName Class Hours #n\n\r", 0);
sprintf(buf, "%s", p_list->text);
write_to_buffer(dsock, buf, 0);
}
sprintf(buf, " [C] Create new player\n\r [D] Delete player\n\r [P] Change Password\n\r"
" [Q] Quit\n\n\r");
write_to_buffer(dsock, buf, 0);
write_to_buffer(dsock, "What will it be? ", 0);
free(p_list);
}
struct plist *parse_player_list(char *list)
{
CHAR_DATA *dMob;
struct plist *p_list;
char tempbuf[MAX_STRING_LENGTH];
bool first = TRUE;
int total_time = 0;
if ((p_list = malloc(sizeof(*p_list))) == NULL)
{
bug("Parse_player_list: Cannot allocate memory", 0);
abort();
}
p_list->count = 0;
while (*list != '\0')
{
char name[20];
char race[20];
char *ptr1, *ptr2;
int played = 0;
bool in_game = FALSE;
name[0] = '\0'; ptr1 = name;
race[0] = '\0'; ptr2 = race;
/* get the name */
while (*list != ' ')
*ptr1++ = *list++;
*ptr1 = '\0'; list++;
/* is that player already logged on ?? */
for (dMob = char_list; dMob; dMob = dMob->next)
{
if (IS_NPC(dMob)) continue;
if (!str_cmp(dMob->name, name))
in_game = TRUE;
}
/* get the race */
while (*list != ' ')
*ptr2++ = *list++;
*ptr2 = '\0'; list++;
/* get the hours */
while (*list != ' ' && *list != '\0')
{
played *= 10;
played += *list++ - '0';
}
if (*list == ' ') list++;
p_list->count++;
sprintf(tempbuf, " [%d] %-12s %-12s %5d hour%s%s\n\r",
p_list->count, name, race, played, (played == 1) ? "" : "s",
(in_game) ? " (active)" : "");
/* add up */
total_time += played;
if (first)
{
first = FALSE;
sprintf(p_list->text, "%s", tempbuf);
}
else strcat(p_list->text, tempbuf);
}
/* should we add a line with the total time ? */
if (!first)
{
sprintf(tempbuf, "%34s %5d hour%s total\n\r", " ", total_time, (total_time == 1) ? "" : "s");
strcat(p_list->text, tempbuf);
}
return p_list;
}
char *get_option_login(char *list, int option)
{
static char buf[MAX_STRING_LENGTH];
int current = 1, i = 0;
buf[0] = '\0';
/* saves some time */
if (option < 1) return NULL;
while (*list != '\0')
{
/* get the name */
while (*list != ' ')
{
if (current == option) buf[i++] = *list;
list++;
}
if (current == option)
{
buf[i] = '\0';
return buf;
}
list++;
/* scan past race */
while (*list++ != ' ') ;
/* scan past hours */
while (*list != '\0' && *list++ != ' ') ;
current++;
}
if (buf[0] == '\0')
return NULL;
else
return buf;
}
/*
* check reconnect is called before this procedure,
* so we don't have to worry about this being the
* same char as the one trying to logon.
*/
bool already_logged(char *name)
{
CHAR_DATA *dMob;
for (dMob = char_list; dMob; dMob = dMob->next)
{
if (IS_NPC(dMob)) continue;
if (!str_cmp(dMob->pcdata->account, name))
return TRUE;
}
return FALSE;
}
void account_update(ACCOUNT_DATA *account, CHAR_DATA *dMob)
{
char buf[MAX_STRING_LENGTH], name[MAX_STRING_LENGTH];
char *ptr, *list;
int i = 0, j = 0;
buf[0] = '\0';
ptr = buf;
list = account->players;
/* first we error check */
if (!is_full_name(dMob->name, account->players))
{
sprintf(buf, "Account_update: %s not in %s's playerlist", dMob->name, account->owner);
bug(buf, 0);
return;
}
/* then we parse */
while (1)
{
one_argument(list + i, name);
if (!str_cmp(name, dMob->name))
{
/* scan past name */
while ((buf[i + j] = *(list+i)) != ' ')
i++;
i++;
/* scan past race */
while ((buf[i + j] = *(list+i)) != ' ')
i++;
i++;
/* parse correct time */
{
char tempbuf[MAX_STRING_LENGTH];
int count = 0;
sprintf(tempbuf, "%d",
(dMob->played + (int) (current_time - dMob->logon))/3600);
while ((buf[i + j] = tempbuf[count++]) != '\0')
j++;
/* change that to a space */
buf[i + j] = ' ';
/* skip past the old time entry */
while (*(list+i) != '\0' && *(list+i) != ' ')
i++, j--;
if (*(list + (i++)) == '\0')
{
buf[i + j - 1] = '\0';
break;
}
}
}
else // scan forward one entry
{
/* scan past name */
while ((buf[i + j] = *(list+i)) != ' ')
i++;
i++;
/* scan past race */
while ((buf[i + j] = *(list+i)) != ' ')
i++;
i++;
/* scan past hours */
while ((buf[i + j] = *(list+i)) != '\0' && *(list+i) != ' ')
i++;
/* found the end */
if (*(list + (i++)) == '\0')
break;
}
}
/* then we copy */
free_string(account->players);
account->players = str_dup(buf);
/* and finally we save */
save_account(account);
}
void account_new_player(ACCOUNT_DATA *account, CHAR_DATA *dMob)
{
char buf[MAX_STRING_LENGTH];
sprintf(buf, "%s%s%s %s %d",
account->players, (account->players[0] == '\0') ? "" : " ",
dMob->name, class_lookup(dMob), dMob->played/3600);
free_string(account->players);
account->players = str_dup(buf);
save_account(account);
}
void create_new_account(ACCOUNT_DATA *account)
{
char buf[MAX_STRING_LENGTH];
/* create the directory */
sprintf(buf, "mkdir ../accounts/%s", account->owner);
system(buf);
/* save the account */
save_account(account);
}
char *class_lookup(CHAR_DATA *ch)
{
static char buf[MAX_STRING_LENGTH];
int i;
for (i = 0; class_table[i].class_name[0] != '\0'; i++)
{
if (ch->class != class_table[i].class_num) continue;
sprintf(buf, "%s", class_table[i].class_name);
return buf;
}
sprintf(buf, "None");
return buf;
}
bool is_valid_class_choice(char *choice, CHAR_DATA *ch)
{
int i = atoi(choice), j;
/* let's see if it's in the table */
for (j = 1; class_table[j].class_name[0] != '\0'; j++)
{
if (i == j || !str_cmp(class_table[j].class_name, choice))
{
ch->class = class_table[j].class_num;
return TRUE;
}
}
/* nope, wasn't here */
return FALSE;
}
void show_class_options(DESCRIPTOR_DATA *d)
{
char buf[MAX_STRING_LENGTH];
int i;
write_to_buffer(d, "\n\r#uThese classes are available:#n\n\n\r", 0);
for (i = 1; class_table[i].class_name[0] != '\0'; i++)
{
sprintf(buf, " [%2d] %s\n\r", i, class_table[i].class_name);
write_to_buffer(d, buf, 0);
}
write_to_buffer(d, "\n\rWhat is your pick? ", 0);
}