#include #include #include #include #include #include #include "attack.h" #include "defs.h" #include "flag.h" #include "lf.h" #include "map.h" #include "move.h" #include "nexus.h" #include "objects.h" #include "text.h" extern long curtime; extern lifeform_t *player; int needan(char *text) { if (isvowel(tolower(text[0]))) { return B_TRUE; } return B_FALSE; } char *capitalise(char *text) { if (strlen(text)) { char *p; p = text; while (*p == '^') { p++; // go past the ^ if (!(*p)) return text; // do nothing p++; // go past the colour char if (!(*p)) return text; // do nothing } *p = toupper(*p); } return text; } // capitalise all words char *capitaliseall(char *text) { if (strlen(text) > 0) { char *p; for (p = text ; *p; p++) { if (p == text) { // first letter *p = toupper(*p); } else if (*(p-1) == ' ') { // first letter after a space *p = toupper(*p); } } } return text; } enum COLOUR chartocol(char ch) { switch (ch) { case 'w': // warning return C_YELLOW; case 'W': // extra warning return C_BOLDMAGENTA; case 'b': // bad return C_BROWN; case 'B': // v.bad return C_RED; case 'T': // terrible return C_ORANGE; case 'g': // good return C_GREEN; case 'G': // v.good return C_CYAN; case 'E': // excllent return C_BOLDCYAN; case 'h': // 'hilite' return C_WHITE; case 'l': // 'bLue' return C_BLUE; case 'n': // normal default: break; } return C_GREY; } char *construct_hit_string(lifeform_t *lf, lifeform_t *victim, char *attackername, char *victimname, char *victimbpname, object_t *wep, enum DAMTYPE damtype, int dam, int maxhp, int idx, int backstab, int critical, int fatal, int isunarmed, char *retbuf) { int usecrittext = B_FALSE; char wepname[BUFLEN],buf[BUFLEN]; // default strcpy(retbuf, ""); getobname(wep, wepname, 1); // initial hit... if (idx == 0) { if (critical && !fatal) usecrittext = B_TRUE; if (isplayer(lf)) { char extradambuf[BUFLEN]; char withwep[BUFLEN]; char *verb; int needfree = B_FALSE; strcpy(extradambuf, ""); if (wep && !ismeleeweapon(wep)) { snprintf(withwep, BUFLEN, " with %s", wepname); } else { strcpy(withwep, ""); } strcpy(extradambuf, ""); if (dam == 0) { if (!victim || getlorelevel(lf, victim->race->raceclass->id)) { //strcpy(extradambuf, " but do no damage"); strcpy(extradambuf, " ineffectually"); } } else if (lfhasflag(player, F_EXTRAINFO) || lfhasflag(player, F_OMNIPOTENT) ) { snprintf(extradambuf, BUFLEN, " [%d dmg]",dam); } if (backstab && (idx == 0)) { verb = strdup("backstab"); needfree = B_TRUE; } else if (fatal) { verb = getkillverb(victim, wep, damtype, dam, maxhp); } else { if (!victim || // atacking an object (getlorelevel(lf, victim->race->raceclass->id) >= PR_BEGINNER) || // know about the race !ismeleedam(damtype)) { // non-physical damage verb = getattackverb(lf, wep, damtype, dam, maxhp); } else { // always use verb for 10% verb = getattackverb(lf, wep, damtype, pctof(10, maxhp), maxhp); } } snprintf(retbuf, BUFLEN, "^%cYou %s%s %s%s%s%s", fatal ? 'g' : 'n', usecrittext ? "critically " : "", verb, usecrittext ? victimbpname : victimname, withwep,extradambuf, (fatal || backstab) ? "!" : "."); if (needfree) { free(verb); } } else { // ie. the attacker is a monster if (cansee(player, lf) || (victim && isplayer(victim))) { char withwep[BUFLEN]; char attackverb[BUFLEN]; char nodamstr[BUFLEN]; int nodam = B_FALSE; // capitalise first letter strcpy(buf, attackername); capitalise(buf); if (wep && !isunarmed && (lf->race->id != R_DANCINGWEAPON) && cansee(player, lf)) { snprintf(withwep, BUFLEN, " with %s", wepname); } else { strcpy(withwep, ""); } strcpy(attackverb, getattackverb(lf, wep, damtype,dam,maxhp)); if ((dam == 0) && (damtype != DT_TOUCH)) { nodam = B_TRUE; strcpy(nodamstr, " ineffectually"); } else { strcpy(nodamstr, ""); } snprintf(retbuf, BUFLEN, "^%c%s %s%s%s %s%s%s.", (victim && isplayer(victim) && !nodam) ? 'b' : 'n', buf, usecrittext ? "critically " : "", attackverb, needses(attackverb) ? "es" : "s", usecrittext ? victimbpname : victimname,withwep, nodamstr); } } } else { // follow-up weapon damage (ie from a flaming sword etc) if (victim && cansee(player, victim)) { if (dam == 0) { // ineffectual switch (damtype) { case DT_COLD: snprintf(retbuf, BUFLEN, "^n%s %s cold.", victimname, isplayer(victim) ? "don't feel" : "doesn't look"); break; case DT_HEAT: case DT_FIRE: snprintf(retbuf, BUFLEN, "^n%s %s hot.", victimname, isplayer(victim) ? "don't feel" : "doesn't look"); break; case DT_MAGIC: strcpy(retbuf, ""); break; default: snprintf(retbuf, BUFLEN, "^n%s shrug%s off the effects.", victimname, isplayer(victim) ? "" : "s"); break; } } else if (fatal) { // fatal switch (damtype) { case DT_COLD: snprintf(retbuf, BUFLEN, "^%c%s %s chilled to the bone!", getlfcol(victim, CC_BAD), victimname, is(victim)); break; case DT_HEAT: case DT_FIRE: snprintf(retbuf, BUFLEN, "^%c%s %s incinerated!", getlfcol(victim, CC_BAD), victimname, is(victim)); break; case DT_MAGIC: snprintf(retbuf, BUFLEN, "^%c%s %s blasted with magic!", getlfcol(victim, CC_BAD), victimname, is(victim)); break; default: snprintf(retbuf, BUFLEN, "^%c%s %s killed!", getlfcol(victim, CC_BAD), victimname, is(victim)); break; } } else { // normal switch (damtype) { case DT_COLD: snprintf(retbuf, BUFLEN, "^n%s %s chilled!", victimname, is(victim)); break; case DT_HEAT: case DT_FIRE: snprintf(retbuf, BUFLEN, "^n%s %s burned!", victimname, is(victim)); break; case DT_MAGIC: snprintf(retbuf, BUFLEN, "^nMagical energy sears %s!", victimname); break; default: snprintf(retbuf, BUFLEN, "^n%s %s hurt!", victimname, is(victim)); break; } } } } capitalise(retbuf); return retbuf; } char *dicetotext(int ndice, int nsides, int bonus, int *min, int *max, char *dicebuf, char *minmaxbuf) { int localmin, localmax; if (ndice == NA) ndice = 0; if (nsides == NA) nsides = 0; if (bonus == NA) bonus = 0; // ie. rolled a 1 on all dice localmin = (ndice * 1) + bonus; // ie. rolled max on all dice localmax = (ndice * nsides) + bonus; if (min) { *min = localmin; } if (max) { *max = localmax; } if (dicebuf) { if ((ndice == 0) || (nsides == 0)) { snprintf(dicebuf, BUFLEN, "%d", bonus); } else { if (bonus) { snprintf(dicebuf, BUFLEN, "%dd%d%c%d", ndice, nsides, (bonus > 0) ? '+' : '-', abs(bonus)); } else { snprintf(dicebuf, BUFLEN, "%dd%d", ndice, nsides); } } } if (minmaxbuf) { if (localmin == localmax) { snprintf(minmaxbuf, BUFLEN, "%d", localmin); } else { snprintf(minmaxbuf, BUFLEN, "%d-%d", localmin, localmax); } } return dicebuf; } int flip(int ch) { switch (ch) { case 'a': return 0x0250; case 'b': return 'q'; case 'c': return 0x0254; case 'd': return 'p'; case 'e': return 0x01dd; case 'f': return 0x025f; case 'g': return 0x0183; case 'h': return 0x0265; case 'i': return 0x0131; case 'j': return 0x027e; case 'k': return 0x029e; case 'l': return 0x0283; case 'm': return 0x026f; case 'n': return 'u'; case 'r': return 0x0279; case 't': return 0x0287; case 'v': return 0x028c; case 'w': return 0x028d; case 'y': return 0x028e; case '.': return 0x02d9; case '[': return ']'; case '(': return ')'; case '{': return '}'; case '?': return 0x00bf; case '!': return 0x00a1; case '<': return '>'; case '_': return 0x203e; } return ch; } // ie. "it has xxx accuracy" char *getaccuracyname(int accpct) { if (accpct >= 200) { return "incredible"; } else if (accpct >= 150) { return "excellent"; } else if (accpct >= 120) { return "great"; } else if (accpct >= 100) { return "good"; } else if (accpct >= 80) { return "average"; } else if (accpct >= 70) { return "mediocre"; } else if (accpct >= 50) { return "poor"; } else if (accpct >= 30) { return "very poor"; } else if (accpct >= 20) { return "extremely poor"; } else { return "a complete lack of"; } } int getaccuracymodnum(int accpctmod) { return accpctmod / 5; } int getaccuracynum(int accpct) { int num; num = (accpct - 100) / 5; // return num; } // returns a const char * char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam, int maxhp) { float pct; enum LFSIZE ownersize = SZ_HUMAN; flag_t *retflag[MAXCANDIDATES]; int nretflags = 0; if (lf) { ownersize = getlfsize(lf); } pct = (int)(((float) dam / (float) maxhp) * 100.0); if (wep) { int i; flag_t *f; getflags(wep->flags, retflag, &nretflags, F_ATTACKVERB, F_NONE); for (i = 0; i < nretflags; i++) { f = retflag[i]; if ((f->val[0] == NA) && (f->val[1] == NA)) { return f->text; } else if (f->val[0]) { if (pct >= f->val[0]) { if (f->val[1] == NA) { return f->text; } else if (pct <= f->val[1]) { return f->text; } } } else if (f->val[1]) { if (pct <= f->val[1]) { return f->text; } } } } if (damtype == DT_ACID) { return "burn"; } else if (damtype == DT_BASH) { if (pct <= 5) { return "whack"; } else if (pct <= 15) { if (onein(2)) { return "hit"; } else { return "bash"; } } else if (pct <= 25) { return "pummel"; } else if (pct <= 35) { return "slam"; } else { return "clobber"; } } else if (damtype == DT_BITE) { if (lf && (ownersize <= SZ_SMALL)) { if (pct <= 5) { return "nip"; } else { return "bite"; } } else { if (pct <= 5) { return "gnaw"; } else if (pct <= 30) { return "bite"; } else { return "savage"; } } } else if (damtype == DT_CHOP) { if (pct <= 5) { return "hit"; } else if (pct <= 15) { return "hack"; } else { return "chop"; } } else if (damtype == DT_COLD) { if (pct <= 10) { return "chill"; } else { return "freeze"; } } else if (damtype == DT_CRUSH) { return "crush"; } else if (damtype == DT_ELECTRIC) { if (pct <= 5) { return "zap"; } else if (pct <= 15) { return "jolt"; } else if (pct <= 20) { return "shock"; } else if (pct <= 30) { return "electrify"; } else { return "electrocute"; } } else if ((damtype == DT_FIRE) || (damtype == DT_HEAT)) { if (pct <= 5) { return "scorch"; } else if (pct <= 20) { return "burn"; } else if (pct <= 40) { return "scald"; } else { return "incinerate"; } } else if (damtype == DT_HOLY) { switch (rnd(1,3)) { case 1: return "smite"; case 2: return "cleanse"; case 3: return "purify"; } } else if (damtype == DT_MAGIC) { if (pct <= 5) { return "zap"; } else if (pct <= 15) { return "sear"; } else if (pct <= 40) { return "blast"; } } else if (damtype == DT_PIERCE) { if (pct <= 5) { return "poke"; } else if (pct <= 15) { return "stab"; } else if (pct <= 30) { return "pierce"; } else if (pct <= 40) { return "spear"; } else { return "deeply stab"; } } else if (damtype == DT_POISONGAS) { return "poison"; } else if (damtype == DT_PROJECTILE) { return "hit"; } else if (damtype == DT_SLASH) { if (pct <= 5) { return "scratch"; } else if (pct <= 15) { return "hit"; } else if (pct <= 30) { return "slash"; } else { return "slice"; } } else if (damtype == DT_TOUCH) { return "touch"; } else if (damtype == DT_WATER) { // for when water-vulnerable things go into water return "hurt"; } else if (damtype == DT_UNARMED) { if (onein(2)) { return "punch"; } else { return "hit"; } } return "hit"; } char *getattrabbrev(enum ATTRIB att) { switch (att) { case A_NONE: return "??"; case A_CHA: return "Ch"; case A_CON: return "Ft"; case A_AGI: return "Ag"; case A_IQ: return "Iq"; case A_STR: return "St"; case A_WIS: return "Wi"; } return "??"; } char *getattrname(enum ATTRIB att) { switch (att) { case A_NONE: return "?attrib_none?"; case A_CHA: return "charisma"; case A_CON: return "fitness"; case A_AGI: return "agility"; case A_IQ: return "intellect"; case A_STR: return "strength"; case A_WIS: return "wisdom"; } return "?badattrib?"; } char *getdirname(int dir) { switch (dir) { case D_N: return "North"; case D_E: return "East"; case D_S: return "South"; case D_W: return "West"; case D_UP: return "up"; case D_DOWN: return "down"; case D_UNKNOWN: return "D_UNKNOWN"; case D_NONE: return "D_NONE"; case DC_N: return "North"; case DC_NE: return "Northeast"; case DC_E: return "East"; case DC_SE: return "Southeast"; case DC_S: return "South"; case DC_SW: return "Southwest"; case DC_W: return "West"; case DC_NW: return "Northwest"; } return "?errordir?"; } char *getdirnameshort(int dir) { switch (dir) { case D_N: return "N"; case D_E: return "E"; case D_S: return "S"; case D_W: return "W"; case D_UP: return "U"; case D_DOWN: return "D"; case D_UNKNOWN: return "?"; case D_NONE: return "-"; case DC_N: return "N"; case DC_NE: return "NE"; case DC_E: return "E"; case DC_SE: return "SE"; case DC_S: return "S"; case DC_SW: return "SW"; case DC_W: return "W"; case DC_NW: return "NW"; } return "?"; } void getdisttext(cell_t *src, cell_t *dst,char *distbuf, char *distbufapprox, char *dirbuf) { int dist; int dir; dist = getcelldist(src, dst); dir = getdirtowards(src, dst, NULL, B_FALSE, DT_COMPASS); if (dirbuf) { strcpy(dirbuf, getdirname(dir)); dirbuf[0] = tolower(dirbuf[0]); } if (dist >= 20) { // 20+ if (distbuf) strcpy(distbuf, " very far away"); if (distbufapprox) strcpy(distbufapprox, " far away"); } else if (dist >= 10) { // 10 - 19 if (distbuf) strcpy(distbuf, " far away"); if (distbufapprox) strcpy(distbufapprox, " far away"); } else if (dist >= 5) { // 5 - 9 if (distbuf) strcpy(distbuf, " nearby"); if (distbufapprox) strcpy(distbufapprox, " nearby"); } else if (dist >= 2) { // 2 - 4 if (distbuf) strcpy(distbuf, " very nearby"); if (distbufapprox) strcpy(distbufapprox, " nearby"); } else { // 1 if (distbuf) strcpy(distbuf, " right beside you"); if (distbufapprox) strcpy(distbufapprox, " nearby"); } } int gethitconferlifetime(char *text, int *min, int *max) { int howlong; int localmin = -1,localmax = -1; if (text) { char loctext[BUFLEN]; char *word, *dummy; strcpy(loctext,text); word = strtok_r(loctext, "-", &dummy); if (word) { localmin = atoi(word); word = strtok_r(NULL, "-", &dummy); if (word) { localmax = atoi(word); howlong = rnd(localmin,localmax); } else { howlong = PERMENANT; } } else { localmin = -1; localmax = -1; howlong = PERMENANT; } } else { localmin = -1; localmax = -1; howlong = PERMENANT; } if (min) *min = localmin; if (max) *max = localmax; return howlong; } char *getkillverb(lifeform_t *victim, object_t *wep, enum DAMTYPE damtype, int dam, int maxhp) { float pct; pct = (int)(((float) dam / (float) maxhp) * 100.0); if (wep && hasflag(wep->flags, F_MERCIFUL)) { return "knock out"; } if (victim->race->id == R_DANCINGWEAPON) { return "defeat"; } if (getraceclass(victim) == RC_PLANT) { return "destroy"; } if (wep) { flag_t *f; int i; flag_t *retflag[MAXCANDIDATES]; int nretflags = 0; getflags(wep->flags, retflag, &nretflags, F_KILLVERB, F_NONE); for (i = 0; i < nretflags; i++) { f = retflag[i]; if (f->id == F_KILLVERB) { if ((f->val[0] == NA) && (f->val[1] == NA)) { return f->text; } else if (f->val[0]) { if (pct >= f->val[0]) { if (f->val[1] == NA) { return f->text; } else if (pct <= f->val[1]) { return f->text; } } } else if (f->val[1]) { if (pct <= f->val[1]) { return f->text; } } } } } if ((damtype == DT_BASH) && ismadeofice(victim)) { return "shatter"; } if (damtype == DT_CRUSH) { return "crush"; } if (damtype == DT_HOLY) { return "smite"; } if (pct >= 70) { if (damtype == DT_PIERCE) return "impale"; if (damtype == DT_BASH) { if (isunconscious(victim)) { return "kill"; } else { return "flatten"; } } if (damtype == DT_BITE) return "gore"; if (damtype == DT_SLASH) { if (lfhasflagval(victim, F_NOBODYPART, BP_HEAD, NA, NA, NULL)) { return "bisect"; } else { if ((getlfsize(victim) >= SZ_MEDIUM) && onein(3)) { return "behead"; } else { return "bisect"; } } } } if (getraceclass(victim) == RC_UNDEAD) { // can't "kill" the undead return "destroy"; } // never use 'kill' for bashing since you might just knock them out if (damtype == DT_BASH) { return "clobber"; } return "kill"; } char *getpoisondamverb(enum POISONTYPE ptype) { switch (ptype) { case P_FOOD: case P_VENOM: return "vomit"; case P_GAS: case P_COLD: return "cough"; default: break; } return ""; } char *getpoisondesc(enum POISONTYPE ptype) { switch (ptype) { case P_FOOD: case P_VENOM: case P_GAS: case P_WEAKNESS: return "Poisoned"; case P_COLD: return "Sick"; default: break; } return "Poisoned"; } char *getpoisonname(enum POISONTYPE ptype) { switch (ptype) { case P_COLD: return "hypothermia"; case P_FOOD: return "food poisoning"; case P_GAS: return "gas inhalation"; case P_VENOM: return "venom poisoning"; case P_WEAKNESS: return "weakening poison"; default: break; } return ""; } char *getpossessive(char *text) { char lastchar; // you -> your if (!strcasecmp(text, "you")) { return "r"; } // xxxs -> xxxs' lastchar = text[strlen(text)-1]; if (tolower(lastchar) == 's') { return "'"; } // default: 's return "'s"; } char *getdrunktext(flag_t *drunkflag) { int bracket; bracket = (drunkflag->lifetime / TM_DRUNKTIME) + 1; if (bracket == 1) { return "tipsy"; } else if (bracket == 2) { return "drunk"; } else { return "very drunk"; } return "??drunk??"; } char *getinjuredbpname(enum BODYPART bp) { switch (bp) { case BP_HEAD: return "head"; case BP_HANDS: return "arm"; case BP_LEGS: return "leg"; default: break; } return "body"; } char *getinjuryname(enum DAMTYPE dt) { switch (dt) { case DT_BASH: return "bruised"; case DT_SLASH: return "bleeding"; default: break; } return "injured"; } char *getinjurydesc(enum BODYPART where, enum DAMTYPE dt) { if (dt == DT_SLASH) { if (where == BP_LEGS) { return " (moving causes damage)"; } else if (where == BP_HANDS) { return " (attacking causes damage)"; } else if (where == BP_BODY) { return " (take extra damage from melee hits)"; } } else if (dt == DT_BASH) { if (where == BP_LEGS) { return " (penalty to movement speed)"; } else if (where == BP_HANDS) { return " (penalty to attack accuracy)"; } } return ""; } char *getrarityname(enum RARITY rr) { switch (rr) { case RR_UNIQUE: return "Unique"; case RR_NEVER: return "Never"; case RR_VERYRARE: return "Very Rare"; case RR_RARE: return "Rare"; case RR_UNCOMMON: return "Uncommon"; case RR_COMMON: return "Common"; case RR_NONE: return "None"; } return "?unknownrarity?"; } char *getsizetext(enum LFSIZE sz) { switch (sz) { case SZ_MAX: case SZ_ENORMOUS: return "enormous"; case SZ_HUGE: return "huge"; case SZ_LARGE: return "large"; case SZ_HUMAN: return "human"; case SZ_MEDIUM: return "medium"; case SZ_SMALL: return "small"; case SZ_TINY: return "tiny"; case SZ_MIN: case SZ_MINI: return "miniscule"; default: return "unknown-sized"; } return "unknown-sized"; } char *gettimetext(char *retbuf) { int hours,mins,secs; splittime(&hours, &mins, &secs); snprintf(retbuf, BUFLEN, "%02d:%02d:%02d",hours,mins,secs); return retbuf; } char *gettimetextfuzzy(char *retbuf, int wantpm) { int hours,mins,secs; int pm = B_FALSE; splittime(&hours, &mins, &secs); if (hours > 12) { hours -= 12; pm = B_TRUE; } if (hours == 0) hours = 12; if (mins == 0) { snprintf(retbuf, BUFLEN, "exactly %d o'clock", hours); } else if (mins <= 15) { snprintf(retbuf, BUFLEN, "a little after %d o'clock", hours); } else if (mins <= 25) { snprintf(retbuf, BUFLEN, "nearly half past %d", hours); } else if (mins <= 35) { snprintf(retbuf, BUFLEN, "around half past %d", hours); } else if (mins <= 45) { snprintf(retbuf, BUFLEN, "coming up to %d o'clock", (hours == 12) ? 1 : (hours+1)); } else { snprintf(retbuf, BUFLEN, "nearly %d o'clock", (hours == 12) ? 1 : (hours+1)); } if (wantpm) { strcat(retbuf, " in the "); if (pm) { strcat(retbuf, "afternoon"); } else { strcat(retbuf, "morning"); } } return retbuf; } char *getwaterdepthname(enum DEPTH d) { switch (d) { case DP_NONE: return "shallow"; case DP_TOE: return "toe-deep"; case DP_ANKLE: return "ankle-deep"; case DP_FEET: return "foot-deep"; case DP_CALF: return "calf-deep"; case DP_KNEE: return "knee-deep"; case DP_THIGH: return "thigh-deep"; case DP_WAIST: return "waist-deep"; case DP_BELLY: return "belly-deep"; case DP_CHEST: return "chest-deep"; case DP_SHOULDERS: return "shoulder-deep"; default: return "very deep"; } return "?unknowndepth?"; } char *getweighttext(float weight, char *buf, int shortfmt) { if (weight == 0) { if (shortfmt) snprintf(buf, BUFLEN, "0kg"); else snprintf(buf, BUFLEN, "nothing"); } else if (weight >= 1) { if ((int)weight == weight) { // ie. is weight an integer? snprintf(buf, BUFLEN, "%0.0f%skg",weight, shortfmt ? "" : " "); } else { snprintf(buf, BUFLEN, "%0.1f%skg",weight, shortfmt ? "" : " "); } } else { snprintf(buf, BUFLEN, "%0.0f%s", weight * 1000, shortfmt ? "g" : " grams"); } return buf; } char *is(lifeform_t *lf) { if (isplayer(lf)) return "are"; else return "is"; } int isvowel (char c) { switch (c) { case 'a': case 'e': case 'i': case 'o': case 'u': return B_TRUE; } return B_FALSE; } char *makekillertext(char *retbuf, char *killverb, char *lastdam, int wantextra) { char *p, *dummy; p = strtok_r(lastdam,"^", &dummy); if (p) { if (!strcmp(p, "you")) { strcpy(retbuf, "Committed suicide."); } else { snprintf(retbuf, BUFLEN, "%s by %s.",killverb, p); } if (wantextra) { p = strtok_r(NULL, "^", &dummy); while (p) { strcat(retbuf, "\n("); strcat(retbuf, p); strcat(retbuf, ")"); p = strtok_r(NULL, "^", &dummy); } } } else { sprintf(retbuf, "%s by something unknown.", killverb); } return retbuf; } // allocates and returns new string char *makeplural(char *text) { char lastlet; char *newtext; int rv; newtext = strdup(text); // scrolls newtext = strrep(newtext, "bag ", "bags ", &rv); if (rv) return newtext; newtext = strrep(newtext, "berry ", "berries ", &rv); if (rv) return newtext; newtext = strrep(newtext, "block ", "blocks ", &rv); if (rv) return newtext; newtext = strrep(newtext, "can ", "cans ", &rv); if (rv) return newtext; newtext = strrep(newtext, "chunk ", "chunks ", &rv); if (rv) return newtext; newtext = strrep(newtext, "clove ", "cloves ", &rv); if (rv) return newtext; newtext = strrep(newtext, "flask ", "flasks ", &rv); if (rv) return newtext; newtext = strrep(newtext, "gem ", "gems ", &rv); if (rv) return newtext; newtext = strrep(newtext, "leaf", "leaves", &rv); if (rv) return newtext; newtext = strrep(newtext, "loaf ", "loaves ", &rv); if (rv) return newtext; newtext = strrep(newtext, "lump ", "lumps ", &rv); if (rv) return newtext; newtext = strrep(newtext, "piece ", "pieces ", &rv); if (rv) return newtext; newtext = strrep(newtext, "pile ", "piles ", &rv); if (rv) return newtext; newtext = strrep(newtext, "pool ", "pools ", &rv); if (rv) return newtext; newtext = strrep(newtext, "potion ", "potions ", &rv); if (rv) return newtext; newtext = strrep(newtext, "puddle ", "puddles ", &rv); if (rv) return newtext; newtext = strrep(newtext, "ring ", "rings ", &rv); if (rv) return newtext; newtext = strrep(newtext, "scroll ", "scrolls ", &rv); if (rv) return newtext; newtext = strrep(newtext, "splash ", "splashes ", &rv); if (rv) return newtext; newtext = strrep(newtext, "set ", "sets ", &rv); if (rv) return newtext; newtext = strrep(newtext, "sprig ", "sprigs ", &rv); if (rv) return newtext; newtext = strrep(newtext, "suit ", "suits ", &rv); if (rv) return newtext; newtext = strrep(newtext, "vial ", "vials ", &rv); if (rv) return newtext; // newtext = strrep(newtext, "pair ", "pairs ", &rv); // don't return // default lastlet = text[strlen(text)-1]; switch (lastlet) { char *temptext; case 'y': // change to 'ies' temptext = strdup(text); temptext[strlen(temptext)-1] = '\0'; asprintf(&newtext, "%sies",temptext); free(temptext); break; case 's': case 'o': // append "es" asprintf(&newtext, "%ses",text); break; default: // append "s" asprintf(&newtext, "%ss",text); break; } return newtext; } char *makeuppercase(char *text) { if (strlen(text) > 0) { char *p; for (p = text ; *p; p++) { *p = toupper(*p); } } return text; } int needses(char *text) { if (text[strlen(text)-1] == 's') { return B_TRUE; } if (strlen(text) >= 2) { if ((text[strlen(text)-2] == 'c') && (text[strlen(text)-1] == 'h')) { return B_TRUE; } } return B_FALSE; } char *noprefix(char *obname) { char *p; p = strchr(obname, ' '); if (p) { p++; return p; } else { return obname; } } char *numtotext(int num, char *buf) { switch (num) { case 1: snprintf(buf, BUFLEN, "a"); break; case 2: snprintf(buf, BUFLEN, "two"); break; case 3: snprintf(buf, BUFLEN, "three"); break; case 4: snprintf(buf, BUFLEN, "four"); break; case 5: snprintf(buf, BUFLEN, "five"); break; case 6: snprintf(buf, BUFLEN, "six"); break; case 7: snprintf(buf, BUFLEN, "seven"); break; case 8: snprintf(buf, BUFLEN, "eight"); break; case 9: snprintf(buf, BUFLEN, "nine"); break; case 10: snprintf(buf, BUFLEN, "ten"); break; default: snprintf(buf, BUFLEN, "%d",num); break; } return buf; } // returns posiiton AFTER end of copied text, or NULL on failure. char *readuntil(char *retbuf, char *src, char delim) { char *bp,*p; bp = retbuf; for (p=src; *p && (*p != delim); p++) { *bp = *p; bp++; } *bp = '\0'; // nul-terminate buffer if (*p == delim) { p++; // go past delimiter } return p; } // convert number to roman numerals // only copes with 1-10 char *roman(int num) { switch (num) { case 1: return "I"; case 2: return "II"; case 3: return "III"; case 4: return "IV"; case 5: return "V"; case 6: return "VI"; case 7: return "VII"; case 8: return "VIII"; case 9: return "IX"; case 10: return "X"; } return ""; } int speedtokph(int speed) { return speed * speed; } void splittime(int *hours, int *mins, int *secs) { long left; left = curtime; *hours = left / 3600; left -= (*hours * 3600); *mins = left / 60; left -= (*mins * 60); *secs = left; } char *strrep(char *text, char *oldtok, char *newtok, int *rv) { char *temp; temp = strdup(" "); // ooooooo is this bad?? dostrrep(text, &temp, oldtok, newtok, rv); // swap text = realloc(text, strlen(temp)+1); // extra space for NUL strcpy(text, temp); free(temp); return text; } // returns TRUE if any replacements made char *dostrrep(char* in, char** out, char* oldtok, char* newtok, int *rv) { char *temp; char *found = strstr(in, oldtok); int idx; if(!found) { *out = realloc(*out, strlen(in) + 1); // oooooooo crashing in realloc strcpy(*out, in); if (rv) *rv = B_FALSE; return *out; } idx = found - in; *out = realloc(*out, strlen(in) - strlen(oldtok) + strlen(newtok) + 1); strncpy(*out, in, idx); strcpy(*out + idx, newtok); strcpy(*out + idx + strlen(newtok), in + idx + strlen(oldtok)); temp = malloc(idx+strlen(newtok)+1); strncpy(temp,*out,idx+strlen(newtok)); temp[idx + strlen(newtok)] = '\0'; dostrrep(found + strlen(oldtok), out, oldtok, newtok, rv); temp = realloc(temp, strlen(temp) + strlen(*out) + 1); strcat(temp,*out); free(*out); *out = temp; if (rv) *rv = B_TRUE; return *out; } int streq(char *a, char *b) { if (!a || !b) return B_FALSE; return !strcmp(a,b); } char *strends(char *a, char *suffix) { char *ep; if (!a || !suffix) return NULL; ep = strstr(a, suffix); if (ep) { if ((ep - a) + strlen(ep) == strlen(a)) { return ep; } } return NULL; } char *strstarts(char *a, char *prefix) { if (!a || !prefix) return NULL; if (strstr(a, prefix) == a) { return a; } return NULL; } int strpixmatch(char *haystack, char *needle) { int matched = B_FALSE; char *hword, *nword, *hcont,*ncont; if (strchr(needle, ' ') || strchr(haystack, ' ')) { char lochaystack[BUFLEN], locneedle[BUFLEN]; strcpy(lochaystack, haystack); strcpy(locneedle, needle); // match word for word nword = strtok_r(locneedle, " ", &ncont); hword = strtok_r(lochaystack, " ", &hcont); while (nword && hword) { // all typed words must match if (strcasestr(hword, nword)) { matched = B_TRUE; } else { matched = B_FALSE; break; } nword = strtok_r(NULL, " ", &ncont); hword = strtok_r(NULL, " ", &hcont); if (nword && !hword) { matched = B_FALSE; } } /* if (!matched && !strchr(needle, ' ')) { // now try matching typed word against second word in spellname strcpy(lochaystack, haystack); hword = strtok_r(lochaystack, " ", &hcont); while (hword) { if (strcasestr(hword, needle)) { matched = B_TRUE; break; } else { matched = B_FALSE; } hword = strtok_r(NULL, " ", &hcont); if (!hword) { matched = B_FALSE; } } } */ } else { if (strcasestr(haystack, needle)) { matched = B_TRUE; } } return matched; } int texttodice(char *text, int *ndice, int *nsides, int *bonus) { char *dummy; char *localtext; char *p,*plusloc; localtext = strdup(text); // number of dice p = strtok_r(localtext, "d", &dummy); if (!p) { return B_TRUE; } if (ndice) { *ndice = atoi(p); } // sides on each die p = strtok_r(NULL, "d", &dummy); if (!p) { return B_TRUE; } // strip out bonus plusloc = strchr(p, '+'); if (plusloc) *plusloc = '\0'; plusloc = strchr(p, '-'); if (plusloc) *plusloc = '\0'; if (nsides) { *nsides = atoi(p); } free(localtext); localtext = strdup(text); // bonus/plus if (bonus) { p = strchr(localtext, '+'); if (p) { *bonus = atoi(p+1); } else { p = strchr(localtext, '-'); if (p) { *bonus = -(atoi(p+1)); } else { *bonus = 0; } } } free(localtext); return B_FALSE; } /* void texttospellopts(char *text, int *power, char *damstr, int *needgrab, int *range, char *racestr) { char *p; int n; char *argname[] = { "pw:", "dam:", "needgrab:", "range:", "race:", NULL, }; void *argval[] = { power, damstr, needgrab, range, racestr, NULL, }; char argtype[] = { 'i', 's', 'b', 'i', 's', '\0', }; // defaults if (power) *power = 0; if (damstr) strcpy(damstr, ""); if (needgrab) *needgrab = B_FALSE; if (range) *range = 0; if (racestr) strcpy(racestr, ""); if (!strlen(text)) { return; } // for each arg for (n = 0; argname[n]; n++) { // search for it in text... for (p = text ; *p ; p++) { if (!strncmp(p, argname[n], strlen(argname[n])) ) { char localval[BUFLEN]; char *valfull; strcpy(localval, p + strlen(argname[n])); valfull = strtok(localval, ";"); if (valfull) { if (argval[n]) { if (argtype[n] == 'i') { *((int *)argval[n]) = atoi(valfull); } else if (argtype[n] == 'b') { *((int *)argval[n]) = atoi(valfull) ? B_TRUE : B_FALSE; } else if (argtype[n] == 's') { strcpy((char *)argval[n], valfull); } } break; } } } } } */ void texttospellopts(char *text, ... ) { char *p; va_list args; char *validname[] = { "pw:", "dam:", "needgrab:", "range:", "race:", NULL, }; char argtype[] = { 'i', 's', 'b', 'i', 's', '\0', }; char *wantname = NULL; void *writeto = NULL; va_start(args, text); wantname = va_arg(args, char *); if (wantname) writeto = va_arg(args, void *); while (wantname) { // process this one int foundidx = -1,i; // validate 'wantname' - must match one of 'validname[]' for (i = 0; validname[i]; i++) { if (streq(validname[i], wantname)) { foundidx = i; break; } } assert(foundidx != -1); // blank our dest buffer if (argtype[foundidx] == 'i') { *((int *)writeto) = 0; } else if (argtype[foundidx] == 'b') { *((int *)writeto) = B_FALSE; } else if (argtype[foundidx] == 's') { strcpy((char *)writeto, ""); } // look for 'wantname' within 'text' for (p = text ; *p ; p++) { if (!strncmp(p, wantname, strlen(wantname)) ) { // found it! char localval[BUFLEN]; char *valfull; // extract value from text // p will point to "pw:xxx;" strcpy(localval, p + strlen(wantname)); // localval is "xxx;" valfull = strtok(localval, ";"); // valfull is "xxx" if (valfull) { // if it's there, write the value into 'writeto' if (argtype[foundidx] == 'i') { *((int *)writeto) = atoi(valfull); } else if (argtype[foundidx] == 'b') { *((int *)writeto) = atoi(valfull) ? B_TRUE : B_FALSE; } else if (argtype[foundidx] == 's') { strcpy((char *)writeto, valfull); } } } } // get next one wantname = va_arg(args, char *); if (wantname) writeto = va_arg(args, void *); } va_end(args); } char *you(lifeform_t *lf) { if (isplayer(lf)) { return "You"; } return "It"; } char *you_l(lifeform_t *lf) { if (isplayer(lf)) { return "you"; } return "it"; } char *your(lifeform_t *lf) { if (isplayer(lf)) { return "Your"; } return "Its"; } char *your_l(lifeform_t *lf) { if (isplayer(lf)) { return "your"; } return "its"; }