/* * misc.c * Miscellaneous string, file and data structure manipulation routines * ____ _ * | _ \ ___ __ _| |_ __ ___ ___ * | |_) / _ \/ _` | | '_ ` _ \/ __| * | _ < __/ (_| | | | | | | \__ \ * |_| \_\___|\__,_|_|_| |_| |_|___/ * * Copyright (C) 2007-2009 Jason Mitchell, Randi Mitchell * Contributions by Tim Callahan, Jonathan Hseu * Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman * */ //#include <stdio.h> //#include <sys/types.h> //#include <ctype.h> //#include <stdarg.h> #include <math.h> #include "mud.h" #include "commands.h" #include "login.h" //********************************************************************* // validId functions //********************************************************************* bool validMobId(const CatRef cr) { return(!cr.isArea("") && cr.id > 0 && cr.id < MMAX); } bool validObjId(const CatRef cr) { // 0 = coins return(!cr.isArea("") && cr.id >= 0 && cr.id < OMAX); } bool validRoomId(const CatRef cr) { // 0 = void return(!cr.isArea("") && cr.id >= 0 && cr.id < RMAX); } //********************************************************************* // nameEqual //********************************************************************* // we need to remove colors that might be in the name! bstring removeColor(bstring obj) { int i=0, len=0; bstring name = ""; for(len = obj.length(); i<len; i++) { while(i<len && obj.at(i) == '^') i += 2; if(i<len) name += obj.at(i); } return(name); } //********************************************************************* // nameEqual //********************************************************************* // checks to see if the names are equal. bool nameEqual(bstring obj, bstring str) { if(obj=="" || str=="") return(false); if(!strncasecmp(removeColor(obj).c_str(), str.c_str(), str.length())) return(true); return(false); } //********************************************************************* // addhp //********************************************************************* // adds hp to the given player void addhp(struct Creature* player, int addhp) { player->hp.increase(addhp); } //********************************************************************* // addmp //********************************************************************* // adds mp to the given player void addmp(struct Creature* player, int addmp) { player->mp.increase(addmp); } //********************************************************************* // lowercize //********************************************************************* // This function takes the string passed in as the first parameter and // converts it to lowercase. If the flag in the second parameter has // its first bit set, then the first letter is capitalized. void lowercize(char *str, int flag ) { int i, n; n = (str) ? strlen(str) : 0; for(i=0; i<n; i++) str[i] = (str[i] >= 'A' && str[i] <= 'Z') ? str[i]+32:str[i]; if(flag & 1) str[0] = (str[0] >= 'a' && str[0] <= 'z') ? str[0]-32:str[0]; } //********************************************************************* // low //********************************************************************* // If the character passed in as the first parameter is an uppercase // alphabetic character, then it is converted to lowercase and returned // Otherwise, it is unchanged. int low(char ch) { if(ch >= 'A' && ch <= 'Z') return(ch+32); else return(ch); } int up(char ch) { if(ch >= 'a' && ch <= 'z') return(ch-32); else return(ch); } int bonus(int num) { return(statBonus[num/10]); } int crtWisdom(Creature* creature) { return(bonus(creature->intelligence.getCur()) + bonus(creature->piety.getCur()))/2; } int crtAwareness(Creature* creature) { return(bonus(creature->intelligence.getCur()) + bonus(creature->dexterity.getCur()))/2; } //********************************************************************* // zero //********************************************************************* // This function zeroes a block of bytes at the given pointer and the // given length. void zero( void *ptr, int size ) { char *chptr; int i; chptr = (char *)ptr; for(i=0; i<size; i++) chptr[i] = 0; } // Temporary (but static) data for the next several functions static char xstr[5][80]; static int xnum=0; #ifdef __CYGWIN__ char *obj_str(const Object *obj, int num, int flag ) { char *str; bstring tmp = obj->getObjStr(NULL, flag, num); str = xstr[xnum]; xnum = (xnum + 1)%5; strncpy(str, tmp.c_str(), 80); return(str); } #endif //********************************************************************* // crt_str //********************************************************************* // This function takes the creature given it in the first parameter, // and forms the appropriate singularized or pluralized version of the // creature's name using certain flags. char *crt_str(const Creature *crt, int num, int flag ) { char ch; char *str; char pform[80]; char sform[80]; char pfile[80]; int found, mobNum=0; FILE *plural; if(!crt) return("(NULL CRT)"); const Player* pCrt = crt->getConstPlayer(); str = xstr[xnum]; xnum = (xnum + 1)%5; // Player if(crt->isPlayer()) { // Target is possessing a monster -- Show the monsters name if invis if(crt->flagIsSet(P_ALIASING) && crt->flagIsSet(P_DM_INVIS)) { if(!pCrt->getAlias()->flagIsSet(M_NO_PREFIX)) { strcpy(str, "A "); strcat(str, pCrt->getAlias()->name); } else strcpy(str, pCrt->getAlias()->name); } // Target is a dm, is dm invis, and viewer is not a dm else if(crt->getClass() == DUNGEONMASTER && crt->flagIsSet(P_DM_INVIS) && !(flag & ISDM) ) { strcpy(str, "Someone"); } // Target is a ct, is dm invis, and viewer is not a dm or ct else if( crt->getClass() == CARETAKER && (crt->flagIsSet(P_DM_INVIS) && !(flag & ISDM) && !(flag & ISCT))) { strcpy(str, "Someone"); } // Target is staff less than a ct and is dm invis, viewier is less than a builder else if( crt->flagIsSet(P_DM_INVIS) && !(flag & ISDM) && !(flag & ISCT) && !(flag & ISBD)) { strcpy(str, "Someone"); } // Target is misted, viewer can't detect mist, or isn't staff else if( crt->flagIsSet(P_MISTED) && !(flag & MIST) && !(flag & ISDM) && !(flag & ISCT) && !(flag & ISBD)) { strcpy(str, "A light mist"); } // Target is invisible and viewer doesn't have detect-invis or isn't staff else if(crt->isInvisible() && !(flag & INV) && !(flag & ISDM) && !(flag & ISCT) && !(flag & ISBD)) { strcpy(str, "Someone"); // Can be seen } else { strcpy(str, crt->name); // Dm Invis if(crt->flagIsSet(P_DM_INVIS)) strcat(str, " (+)"); // Invis else if(crt->isInvisible()) strcat(str, " (*)"); // Misted else if(crt->flagIsSet(P_MISTED)) strcat(str, " (m)"); } return(str); } // Monster // Target is a monster, is invisible, and viewer doesn't have detect-invis or is not staff if(crt->isMonster() && crt->isInvisible() && !(flag & INV) && !(flag & ISDM) && !(flag & ISCT) && !(flag & ISBD)) { strcpy(str, "Something"); return(str); } else { if(num == 0) { if(!crt->flagIsSet(M_NO_PREFIX)) { strcpy(str, "the "); if(!(flag & NONUM)) { mobNum = ((Monster*)crt)->getNumMobs(); if(mobNum>1) { strcat(str, getOrdinal(mobNum).c_str()); strcat(str, " "); } } strcat(str, crt->name); } else strcpy(str, crt->name); } else if(num == 1) { if(crt->flagIsSet(M_NO_PREFIX)) strcpy(str, ""); else { ch = low(crt->name[0]); if(ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') strcpy(str, "an "); else strcpy(str, "a "); } strcat(str, crt->name); } else { strcpy(str, int_to_text(num)); strcat(str, " "); strcat(str, crt->name); if(crt->flagIsSet(M_REN_ON_PLURAL)) { strcat(str, "ren"); } else if(crt->flagIsSet(M_MAN_TO_MEN)) { str[strlen(str)-2] = 'e'; } else if(!crt->flagIsSet(M_NO_S_ON_PLURAL)) { str[strlen(str)+1] = 0; str[strlen(str)+2] = 0; if(str[strlen(str)-1] == 's' || str[strlen(str)-1] == 'x') { str[strlen(str)] = 'e'; str[strlen(str)] = 's'; } else { if(crt->flagIsSet(M_F_TO_VE_ON_PLURAL)) { if(str[strlen(str)-2] == 'f' && str[strlen(str)-1] == 'e') { strcat(str, "s"); str[strlen(str)-3] = 'v'; } else { strcat(str, "s"); str[strlen(str)-2] = 'v'; str[strlen(str)-1] = 'e'; str[strlen(str)] = 's'; } } else if(crt->flagIsSet(M_Y_TO_IE_ON_PLURAL)) { strcat(str, "s"); str[strlen(str)-2] = 'i'; str[strlen(str)-1] = 'e'; str[strlen(str)] = 's'; } else str[strlen(str)] = 's'; } } } if(crt->flagIsSet(M_IRREGULAR_PLURAL) && num > 1) { found = 0; sprintf(pfile, "%s/plurals.txt", GAMEPATH); plural = fopen(pfile, "r"); if(plural != NULL) { while(!found && !(feof (plural))) { fflush(plural); // get singular form fgets(sform, sizeof(sform), plural); sform[strlen(sform)-1] = 0; if(sform[strlen(sform)-1] == '\r') sform[strlen(sform)-1] = 0; fflush(plural); // get plural form fgets(pform, sizeof(pform), plural); pform[strlen(pform)-1] = 0; if(pform[strlen(pform)-1] == '\r') pform[strlen(pform)-1] = 0; if(strcmp(crt->name, sform) == 0) { strcpy(str, ""); if(num < 21) strcpy( str, int_to_text(num) ); strcat( str, " " ); strcat(str, pform); found = 1; } } fclose(plural); } } if(flag & CAP) str[0] = up(str[0]); // Target is magic, and viewer has detect magic on if((flag & MAG) && crt->isMonster() && crt->flagIsSet(M_CAN_CAST)) strcat(str, " (M)"); return(str); } } //********************************************************************* // delimit //********************************************************************* // This function takes a given string, and if it is greater than a given // number of characters, then it is split up into several lines. This // is done by replacing spaces with carriage returns before the end of/ // the line. bstring delimit(const char *str, int wrap) { int i=0, j=0, x=0, l=0, len=0, lastspace=0; char* work = strdup(str); std::ostringstream outStr; if(wrap <= 10) wrap = 78; j = (str) ? strlen(str) : 0; if(j < wrap) { free(work); return str; } len = 0; lastspace = -1; l = 0; for(i=0; i<j; i++) { if(work[i] == ' ') lastspace = i; if(work[i] == '\n') { len = 0; lastspace = -1; } if(work[i] == '\033') x+=7; len++; if(len > (wrap + x) && lastspace > -1) { work[lastspace] = 0; outStr << &work[l] << "\n "; l = lastspace + 1; len = i - lastspace + 3; lastspace = -1; x=0; } } outStr << &work[l]; free(work); return(outStr.str()); } //********************************************************************* // viewFile //********************************************************************* // This function views a file whose name is given by the third // parameter. If the file is longer than 20 lines, then the user is // prompted to hit return to continue, thus dividing the output into // several pages. #define FBUF 800 void viewFileReal(Socket* sock, char *str ) { char buf[FBUF+1]; int i, l, n, ff, line; long offset; buf[FBUF] = 0; switch(sock->getParam()) { case 1: offset = 0L; strcpy(sock->tempstr[1], str); ff = open(str, O_RDONLY, 0); if(ff < 0) { sock->print("File could not be opened.\n"); if(sock->getPlayer()) sock->getPlayer()->clearFlag(P_READING_FILE); sock->restoreState(); return; } line = 0; while(1) { n = read(ff, buf, FBUF); l = 0; for(i=0; i<n; i++) { if(buf[i] == '\n') { buf[i] = 0; line++; sock->printColor("%s\n", &buf[l]); offset += (i-l+1); l = i+1; } if(line > 20) break; } if(line > 20) { sprintf(sock->tempstr[0], "%ld", offset); break; } else if(l != n) { sock->printColor("%s", &buf[l]); offset += (i-l); } if(n<FBUF) break; } if(n==FBUF || line>20) { sock->getPlayer()->setFlag(P_READING_FILE); if(!sock->getPlayer()->flagIsSet(P_MIRC)) sock->print("[Hit Return, Q to Quit]: "); else sock->print("[Hit C to continue]: "); gServer->processOutput(); } if(n<FBUF && line <= 20) { close(ff); sock->restoreState(); return; } else { close(ff); sock->getPlayer()->setFlag(P_READING_FILE); sock->setState(CON_VIEWING_FILE, 2); return; } case 2: if(str[0] != 0 && str[0] != 'c' && str[0] != 'C') { sock->print("Aborted.\n"); if(sock->getPlayer()) sock->getPlayer()->clearFlag(P_READING_FILE); sock->restoreState(); return; } offset = atol(sock->tempstr[0]); ff = open(sock->tempstr[1], O_RDONLY, 0); if(ff < 0) { sock->print("File could not be opened [%s].\n", sock->tempstr); if(sock->getPlayer()) sock->getPlayer()->clearFlag(P_READING_FILE); sock->restoreState(); return; } lseek(ff, offset, 0); line = 0; while(1) { n = read(ff, buf, FBUF); l = 0; for(i=0; i<n; i++) { if(buf[i] == '\n') { buf[i] = 0; line++; sock->printColor("%s\n", &buf[l]); offset += (i-l+1); l = i+1; } if(line > 20) break; } if(line > 20) { sprintf(sock->tempstr[0], "%ld", offset); break; } else if(l != n) { sock->printColor("%s", &buf[l]); offset += (i-l); } if(n<FBUF) break; } if(n==FBUF || line > 20) { if(sock->getPlayer()) sock->getPlayer()->setFlag(P_READING_FILE); sock->print("[Hit Return, Q to Quit]: "); gServer->processOutput(); } if(n<FBUF && line <= 20) { close(ff); if(sock->getPlayer()) sock->getPlayer()->clearFlag(P_READING_FILE); sock->restoreState(); return; } else { close(ff); sock->setState(CON_VIEWING_FILE, 2); } } } // Wrapper function for viewFile_real that will set the correct connected state void viewFile(Socket* sock, char *str) { if(sock->getState() != CON_VIEWING_FILE) sock->setState(CON_VIEWING_FILE); viewFileReal(sock, str); } //********************************************************************* // viewLoginFile //********************************************************************* // This function views a file whose name is given by the third // parameter. If the file is longer than 20 lines, then the user is // prompted to hit return to continue, thus dividing the output into // several pages. #define FBUF 800 void viewLoginFile(Socket* sock, char *str, bool showError) { char buf[FBUF + 1]; int i, l, n, ff, line; long offset; zero(buf, sizeof(buf)); buf[FBUF] = 0; { offset = 0L; strcpy(sock->tempstr[1], str); ff = open(str, O_RDONLY, 0); if(ff < 0) { if(showError) { sock->print("File could not be opened.\n"); broadcast(isCt, "^yCan't open file: %s.\n", str); // nothing to put into (%m)? } return; } line = 0; while(1) { n = read(ff, buf, FBUF); l = 0; for(i=0; i<n; i++) { if(buf[i] == '\n') { buf[i] = 0; if(i != 0 && buf[i-1] == '\r') buf[i-1] = 0; line++; sock->printColor("%s\n", &buf[l]); offset += (i - l + 1); l = i + 1; } } if(l != n) { sock->printColor("%s", &buf[l]); offset += (i - l); } if(n < FBUF) { close(ff); return; } } // Never makes it out of the while loop to get here // close(ff); } } //********************************************************************* // viewFileReverseReal //********************************************************************* // displays a file, line by line starting with the last // similar to unix 'tac' command void viewFileReverseReal(Socket* sock, char *str) { off_t oldpos; off_t newpos; off_t temppos; int i,more_file=1,count,amount=1621; char string[1622]; char search[80]; long offset; FILE *ff; int TACBUF = ( (81 * 20 * sizeof(char)) + 1 ); if(strlen(sock->tempstr[3]) > 0) strcpy(search, sock->tempstr[3]); else strcpy(search, "\0"); switch(sock->getParam()) { case 1: strcpy(sock->tempstr[1], str); if((ff = fopen(str, "r")) == NULL) { sock->print("error opening file\n"); sock->restoreState(); return; } fseek(ff, 0L, SEEK_END); oldpos = ftell(ff); if(oldpos < 1) { sock->print("Error opening file\n"); sock->restoreState(); return; } break; case 2: if(str[0] != 0) { sock->print("Aborted.\n"); sock->getPlayer()->clearFlag(P_READING_FILE); sock->restoreState(); return; } if((ff = fopen(sock->tempstr[1], "r")) == NULL) { sock->print("error opening file\n"); sock->getPlayer()->clearFlag(P_READING_FILE); sock->restoreState(); return; } offset = atol(sock->tempstr[0]); fseek(ff, offset, SEEK_SET); oldpos = ftell(ff); if(oldpos < 1) { sock->print("Error opening file\n"); sock->restoreState(); return; } } nomatch: temppos = oldpos - TACBUF; if(temppos > 0) fseek(ff, temppos, SEEK_SET); else { fseek(ff, 0L, SEEK_SET); amount = oldpos; } newpos = ftell(ff); fread(string, amount,1, ff); string[amount] = '\0'; i = strlen(string); i--; count = 0; while(count < 21 && i > 0) { if(string[i] == '\n') { if((strlen(search) > 0 && strstr(&string[i], search)) || search[0] == '\0') { sock->printColor("%s", &string[i]); count++; } string[i]='\0'; if(string[i-1] == '\r') string[i-1]='\0'; } i--; } oldpos = newpos + i + 2; if(oldpos < 3) more_file = 0; sprintf(sock->tempstr[0], "%ld", (long) oldpos); if(more_file && count == 0) goto nomatch; // didnt find a match within a screenful else if(more_file) { sock->print("\n[Hit Return, Q to Quit]: "); gServer->processOutput(); sock->intrpt &= ~1; fclose(ff); sock->getPlayer()->setFlag(P_READING_FILE); sock->setState(CON_VIEWING_FILE_REVERSE, 2); return; } else { if((strlen(search) > 0 && strstr(string, search)) || search[0] == '\0') { sock->print("\n%s\n", string); } fclose(ff); sock->getPlayer()->clearFlag(P_READING_FILE); sock->restoreState(); return; } } // Wrapper for viewFileReverse_real that properly sets the connected state void viewFileReverse(Socket* sock, char *str) { if(sock->getState() != CON_VIEWING_FILE_REVERSE) sock->setState(CON_VIEWING_FILE_REVERSE); viewFileReverseReal(sock, str); } //********************************************************************* // dice //********************************************************************* // This function rolls n s-sided dice and adds p to the total. int dice(int n, int s, int p) { int i; if(n==0 || s== 0) return(p); for(i=0; i<n; i++) p += mrand(1,s); return(p); } //********************************************************************* // exp_to_lev //********************************************************************* // This function takes a given amount of experience as its first // argument returns the level that the experience reflects. int exp_to_lev(unsigned long exp) { int level = 1; while(exp >= gConfig->expNeeded(level) && level < MAXALVL) level++; if(level == MAXALVL) { level = exp/(needed_exp[MAXALVL-1]); level++; level= MAX(MAXALVL, level); } return(MAX(1,level)); } //********************************************************************* // dec_daily //********************************************************************* // This function is called whenever a daily-use item or operation is // used or performed. If the number of daily uses are used, up then // a 0 is returned. Otherwise, the number of uses is decremented and // a 1 is returned. int dec_daily(struct daily *dly_ptr) { long t; struct tm *tm, time1, time2; t = time(0); tm = localtime(&t); time1 = *tm; tm = localtime(&dly_ptr->ltime); time2 = *tm; if(time1.tm_yday != time2.tm_yday) { dly_ptr->cur = dly_ptr->max; dly_ptr->ltime = t; } if(dly_ptr->cur == 0) return(0); dly_ptr->cur--; return(1); } //********************************************************************* // update_daily //********************************************************************* int update_daily(struct daily *dly_ptr) { long t = time(0); struct tm *tm, time1, time2; tm = localtime(&t); time1 = *tm; tm = localtime(&dly_ptr->ltime); time2 = *tm; if(time1.tm_yday != time2.tm_yday) { dly_ptr->cur = dly_ptr->max; dly_ptr->ltime = t; } return(0); } //********************************************************************* // file_exists //********************************************************************* // This function returns 1 if the filename specified by the first // parameter exists, 0 if it doesn't. bool file_exists(char *filename) { int ff=0; ff = open(filename, O_RDONLY); if(ff > -1) { close(ff); return(true); } return(false); } /*====================================================================*/ // checks if the given str contains all digits bool is_num(char *str ) { int len, i; len = strlen(str); for(i=0;i < len; i++) if(!isdigit(str[i])) return(false); return(true); } void clean_str(char *str, int strip_count ) { char str_buf[2048]; char *pnew; char *porg; int nPlusCount; int ndx; pnew = str_buf; porg = str; nPlusCount = 0; // strip strip_count words from the beginning for( ndx = 0; ndx < strip_count; ndx++ ) { /* strip leading space */ while( *porg != '\0' && *porg == ' ') porg++; /* skip word */ while( *porg != '\0' && *porg != ' ') porg++; } // strip spaces after last stripped word while( *porg != '\0' && *porg == ' ') porg++; // copy the rest of the string in to the clean buffer // removing offensive chars while( *porg != '\0' ) { switch( *porg ) { case '+': nPlusCount++; if( nPlusCount < 3 ) { *(pnew++) = *porg; } break; default: nPlusCount = 0; *(pnew++) = *porg; break; } porg++; } *pnew = '\0'; // now copy it back into the original buffer strcpy(str, str_buf ); } //********************************************************************* // isdm //********************************************************************* // returns 1 if the given player name is a dm int isdm(char *player) { char **s = dmname; while(*s) { if(0 == strcmp(*s, player)) return(1); s++; } return(0); } //********************************************************************* // smashInvis //********************************************************************* int Creature::smashInvis() { if(isPlayer()) { unhide(); removeEffect("invisibility"); unmist(); } return(0); } //********************************************************************* // parse_name //********************************************************************* // Determine if a given name is acceptable bool parse_name(char *name) { FILE *fp=0; int i = strlen(name)-1; char str[80], path[80], forbid[20]; strcpy(str, name); if(isTitle(str) || isClass(str)) return(false); if(gConfig->racetoNum(str) >= 0) return(false); if(gConfig->deitytoNum(str) >= 0) return(false); // don't allow names with all the same char str[0] = tolower(str[0]); for(; i>0; i--) if(str[i] != str[0]) break; if(!i) return(false); str[0] = toupper(str[0]); // check the DM names i=0; while(dmname[i]) { // don't forbid names directly equal to DM if(strcmp(dmname[i], str)) { if(!strncmp(dmname[i], str, strlen(str))) return(false); if(!strncmp(str, dmname[i], strlen(dmname[i]))) return(false); } i++; } sprintf(path, "%s/forbidden_name.txt", CONFPATH); fp = fopen(path, "r"); if(!fp) merror("ERROR - forbidden name.txt", NONFATAL); else { while(!feof(fp)) { fscanf(fp, "%s", forbid); if(!strcmp(forbid, str)) { fclose(fp); return(false); } } fclose(fp); } lowercize(str, 0); if(strstr(str, "fuck")) return(false); if(strstr(str, "shit")) return(false); if(strstr(str, "suck")) return(false); if(strstr(str, "gay")) return(false); if(strstr(str, "isen")) return(false); if(strstr(str, "cock")) return(false); if(strstr(str, "realm")) return(false); if(strstr(str, "piss")) return(false); if(strstr(str, "dick")) return(false); if(strstr(str, "pussy")) return(false); if(strstr(str, "dollar")) return(false); if(strstr(str, "cunt")) return(false); return(true); } //********************************************************************* // dmIson //********************************************************************* int dmIson() { std::pair<bstring, Player*> p; Player* player=0; int idle=0; long t = time(0); foreach(p, gServer->players) { player = p.second; if(!player->isConnected()) continue; idle = t - player->getSock()->ltime; if(player->isDm() && idle < 600) return(1); } return(0); } //********************************************************************* // bug //********************************************************************* void Player::bug(const char *fmt, ...) const { char file[80]; char str[2048]; int fd; long t = time(0); va_list ap; if(!flagIsSet(P_BUGGED)) return; va_start(ap, fmt); sprintf(file, "%s/player.bug/%s.txt", LOGPATH, name); fd = open(file, O_RDWR | O_APPEND, 0); if(fd < 0) { fd = open(file, O_RDWR | O_CREAT, ACC); if(fd < 0) return; } lseek(fd, 0L, 2); // prevent string overruns with vsn strcpy(str, ctime(&t)); str[24] = ':'; str[25] = ' '; vsnprintf(str + 26, 2000, fmt, ap); va_end(ap); write(fd, str, strlen(str)); close(fd); } //********************************************************************* // autosplit //********************************************************************* int autosplit(Creature* player, long amount) { ctag *cp=0; int remain=0, split=0, party=0; Creature *leader=0; if(player->isStaff()) return(0); if(!player->ableToDoCommand()) return(0); if(amount <= 5) return(0); if(player->following) leader = player->following; // Find the leader. else leader = player; cp = leader->first_fol; party = 1; // The leader. // Staff members are not included in the split while(cp) { if(cp->crt->isPlayer() && !cp->crt->isStaff()) // Count up how many in group. party += 1; cp = cp->next_tag; } // If group is 1, return with no split. if(party < 2) return(0); // If less gold then people, there is no split. if(amount < party) return(0); remain = amount % party; // Find remaining odd coins. split = ((amount - remain) / party); // Determine split minus the remaining odd coins. if(leader == player) { // Player picking up gets the odd coins. leader->print("You received %d gold as your split.\n", split+remain); leader->coins.add(split+remain, GOLD); } else { leader->print("You received %d gold as your split from %N.\n", split, player); leader->coins.add(split, GOLD); leader->print("You now have %d gold coins.\n", leader->coins[GOLD]); } cp = leader->first_fol; while(cp) { if(!cp->crt->isPet() && cp->crt != player && !cp->crt->isStaff()) { cp->crt->print("You received %d gold as your split from %N.\n", split, player); cp->crt->coins.add(split, GOLD); cp->crt->print("You now have %d gold coins.\n", cp->crt->coins[GOLD]); } if(cp->crt == player) { cp->crt->print("You received %d gold as your split.\n", split+remain); cp->crt->coins.add(split+remain, GOLD); } cp = cp->next_tag; } return(1); } //********************************************************************* // in_group //********************************************************************* int in_group(Creature* player, char *name) { ctag *cp=0; Creature *leader=0, *creature=0; if(player->following) leader = player->following; else leader = player; cp = leader->first_fol; while(cp) { creature = cp->crt; if(creature->isPet()) { cp=cp->next_tag; continue; } if(!strcmp(name, creature->name) && (player != creature) ) { return(1); } cp = cp->next_tag; } return(0); } //********************************************************************* // strPrefix //********************************************************************* // Determines if needle is a prefix to haystack // Returns 1 if it is, 0 otherwise int strPrefix(const char *haystack, const char *needle) { if(!haystack) return(0); if(!needle) return(0); for(; *haystack && *needle; haystack++, needle++) if(*haystack != *needle) return(0); return(1); } //********************************************************************* // strSuffix //********************************************************************* // Determines if needle is a suffix of haystack // Returns 1 if it is, 0 otherwise int strSuffix(const char *haystack, const char *needle) { int hayLen = strlen(haystack); int needleLen = strlen(needle); if(hayLen >= needleLen && !strcmp(needle, haystack + hayLen - needleLen)) return(1); return(0); } //********************************************************************* // pkillPercent //********************************************************************* int pkillPercent(int pkillsWon, int pkillsIn) { double percent=0; double pkWon = pkillsWon * 1.0, pkIn = pkillsIn * 1.0; if(pkillsIn == pkillsWon) { percent = 100; } else { // if(pkillsWon == 0) // pkillsWon = 1; if(pkillsIn == 0) pkIn = 1.0; if(pkillsWon > pkillsIn) pkWon = pkIn; percent = (pkWon/pkIn) * 100.0; } return((int)percent); } //********************************************************************* // stun //********************************************************************* // stops a creature or player from attacking, casting a spell, or reading // a scroll for <delay> seconds. Used by stun (befuddle), circle void Creature::stun(int delay) { if(!delay) return; updateAttackTimer(true, (delay+1)*10); lasttime[LT_KICK].ltime = time(0); lasttime[LT_SPELL].ltime = time(0); lasttime[LT_READ_SCROLL].ltime = time(0); lasttime[LT_KICK].interval = delay+1; lasttime[LT_SPELL].interval = delay+1; lasttime[LT_READ_SCROLL].interval = delay+1; if(isPlayer()) { lasttime[LT_PLAYER_STUNNED].ltime = time(0); lasttime[LT_PLAYER_STUNNED].interval = delay+1; setFlag(P_STUNNED); } } //********************************************************************* // numEnemyMonInRoom //********************************************************************* int numEnemyMonInRoom(Creature* player) { int count=0; ctag *cp = player->getRoom()->first_mon; while(cp) { if(cp->crt->getMonster()->isEnmCrt(player->name)) count++; cp = cp->next_tag; } return(count); } //********************************************************************* // numInGroup //********************************************************************* int numInGroup(Creature* player) { int count=0; ctag *cp=0; Creature *leader=0; if(player->following) leader = player->following; else leader = player; cp = leader->first_fol; while(cp) { if(player->inSameRoom(cp->crt)) count++; cp = cp->next_tag; } return(count); } //********************************************************************* // stripLineFeeds //********************************************************************* char *stripLineFeeds(char *str) { int n=0, i=0; char *name=0; name = str; n = strlen(name); for(i = n; i > 0; i--) { if(name[i] == '\n') { name[i] = ' '; break; } } return(name); } //********************************************************************* // stripBadChars //********************************************************************* void stripBadChars(char *str) { int n=0, i=0; // char *name=0; // str = str; n = (str) ? strlen(str) : 0; // n = strlen(str); for(i = 0; i < n; i++) { if(str[i] == '/') { str[i] = ' '; } /*if(str[i] == '.') { str[i] = ' '; } */ } } //********************************************************************* // getLastDigit //********************************************************************* // This function returns the last digits of any integer n sent // to it. digits specifies how many. -Tim C. int getLastDigit(int n, int digits) { double num=0.0, sub=0.0; int a=0, temp=0, digit=0; digits = MAX(1,MIN(4,digits)); num = (double)n; for(a=5; a>digits-1; a--) // start with 10^5th power (100000) { sub = pow(10,a); if(num - sub < 0) continue; else { temp = (int)num; temp %= (int)sub; num = (double)temp; } } digit = (int)num; return(digit); } //********************************************************************* // ltoa //********************************************************************* char *ltoa( long val, // value to be converted char *buf, // output string int base) // conversion base { ldiv_t r; // result of val / base // no conversion if wrong base if(base > 36 || base < 2) { *buf = '\0'; return buf; } if(val < 0) *buf++ = '-'; r = ldiv (labs(val), base); // output digits of val/base first if(r.quot > 0) buf = ltoa ( r.quot, buf, base); // output last digit *buf++ = "0123456789abcdefghijklmnopqrstuvwxyz"[(int)r.rem]; *buf = '\0'; return(buf); } //********************************************************************* // findTarget //********************************************************************* bool findTarget(Creature * player, int findWhere, int findFlags, char *str, int val, void** target, int* targetType) { int match=0; bool found=false; do { if(findWhere & FIND_OBJ_INVENTORY) { if(findObj(player, player->first_obj, findFlags, str, val, &match, (Object**)target)) { *targetType = OBJECT; found = true; break; } } // See if we should look for a match in the player's equipment // -- Do this after looking for the object in their inventory if(findWhere & FIND_OBJ_EQUIPMENT) { int n; for(n=0; n<MAXWEAR; n++) { if(!player->ready[n]) continue; if(keyTxtEqual(player->ready[n], str)) match++; else continue; if(val == match) { *targetType = OBJECT; *target = player->ready[n]; found = true; break; } } if(found) break; } if(findWhere & FIND_OBJ_ROOM) { if(findObj(player, player->getRoom()->first_obj, findFlags, str, val, &match, (Object**)target)) { *targetType = OBJECT; found = true; break; } } if(findWhere & FIND_MON_ROOM) { if(findCrt(player, player->getRoom()->first_mon, findFlags, str, val, &match, (Creature **)target)) { *targetType = MONSTER; found = true; break; } } if(findWhere & FIND_PLY_ROOM) { if(findCrt(player, player->getRoom()->first_ply, findFlags, str, val, &match, (Creature **)target)) { *targetType = PLAYER; found = true; break; } } } while(0); return(found); } //********************************************************************** // new_merror //********************************************************************** // merror is called whenever an error message should be output to the // log file. If the error is fatal, then the program is aborted void new_merror(const char *str, char errtype, const char *file, const int line) { printf("\nError: %s @ %s %d.\n", str, file, line); logn("error.log", "Error occured in %s in file %s line %d\n", str, file, line); if(errtype == FATAL) { abort(); } // exit(-1); } //********************************************************************* // timeStr //********************************************************************* bstring timeStr(int secs) { int hours = 0; int minutes = 0; int seconds = 0; hours = secs / 3600; secs -= hours * 3600; minutes = secs / 60; seconds = secs - minutes * 60; std::ostringstream timeStr; if(hours) timeStr << hours << " hour(s) "; if(minutes) timeStr << minutes << " minutes(s) "; // Always show seconds timeStr << seconds << " second(s)"; return(timeStr.str()); } //********************************************************************* // progressBar //********************************************************************* bstring progressBar(int barLength, float percentFull, bstring text, char progressChar, bool enclosed) { bstring str = ""; int i=0, progress = (int)(barLength * percentFull); int lowTextBound=-1, highTextBound=-1; if(text.getLength()) { if(text.getLength() >= barLength) return(text); lowTextBound = (barLength - text.getLength())/2; highTextBound = lowTextBound + text.getLength(); } if(enclosed) str += "["; for(i=0; i<barLength; i++) { // if we're in the range of the text we want to include, skip if(i == lowTextBound) { str += text; continue; } if(i > lowTextBound && i < highTextBound) continue; // otherwise give us a character if(i < progress) str += progressChar; else str += " "; } if(enclosed) str += "]"; return(str); }