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