AwakeMUD-0.84B/.ssh/
AwakeMUD-0.84B/doc/
AwakeMUD-0.84B/lib/
AwakeMUD-0.84B/lib/etc/pfiles/
AwakeMUD-0.84B/lib/fixer_data/
AwakeMUD-0.84B/lib/misc/
AwakeMUD-0.84B/lib/text/
AwakeMUD-0.84B/lib/text/help/
AwakeMUD-0.84B/lib/text/wizhelp/
AwakeMUD-0.84B/lib/veh/
AwakeMUD-0.84B/lib/world/
AwakeMUD-0.84B/lib/world/mob/
AwakeMUD-0.84B/lib/world/mtx/
AwakeMUD-0.84B/lib/world/qst/
AwakeMUD-0.84B/lib/world/shp/
AwakeMUD-0.84B/lib/world/veh/
/* ************************************************************************
*   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 <limits.h>
#include <time.h>
#include <sys/types.h>
#include <stdarg.h>
#include <iostream>

using namespace std;

#if defined(WIN32) && !defined(__CYGWIN__)
#include <winsock.h>
#define random() rand()
#define srandom(x) srand(x)
#else
#include <netinet/in.h>
#include <unistd.h>
#endif

#include "telnet.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"
#include "db.h"
#include "constants.h"

extern class memoryClass *Mem;
extern struct time_info_data time_info;

extern void die(struct char_data * ch);
extern int damage_array[];
extern const struct target_type target_array[];
extern const char *log_types[];
extern long beginning_of_time;


// 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 should not happen, but if it does...
    int temp = to;
    to = from;
    from = temp;
  }
  return ((random() % (to - from + 1)) + from);
}

/* 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, roll, one = 0;
  register int i;

  target = MAX(target, 2);

  for (i = 1; i <= number; i++) {
    if ((roll = srdice()) == 1)
      one++;
    else if (roll >= target)
      total++;
  }

  if (one == number)
    return -1;
  return total;
}

int resisted_test(int num4ch, int tar4ch, int num4vict, int tar4vict)
{
  return (success_test(num4ch, tar4ch) - success_test(num4vict, tar4vict));
}

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 modify_target_rbuf(struct char_data *ch, char *rbuf)
{
  extern time_info_data time_info;
  int base_target = 0, 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_POWER(ch, ADEPT_PAIN_RESISTANCE) > 0)
  {
    temp = (int)(GET_MAX_PHYSICAL(ch) - GET_PHYSICAL(ch) / 100);
    if (temp <= GET_POWER(ch, ADEPT_PAIN_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_POWER(ch, ADEPT_PAIN_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 (ch->in_room != NOWHERE)
    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 (PLR_FLAGGED(ch, PLR_PERCEIVE))
  {
    base_target += 2;
    buf_mod(rbuf, "AstralPercep", 2);
  }
  if (GET_RACE(ch) == RACE_NIGHTONE && ((time_info.hours > 6) || (time_info.hours < 19)) && OUTSIDE(ch))
  {
    base_target += 1;
    buf_mod( rbuf, "Sunlight", 1);
  }
  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 );
      }
    }
  }

  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:
            case SKILL_MACHINE_GUNS:
            case SKILL_MISSILE_LAUNCHERS:
            case SKILL_ASSAULT_CANNON:
            case SKILL_ARTILLERY:
              return (SKILL_FIREARMS);
              break;
            case SKILL_EDGED_WEAPONS:
            case SKILL_POLE_ARMS:
            case SKILL_WHIPS_FLAILS:
            case SKILL_CLUBS:
              return (SKILL_ARMED_COMBAT);
              break;
            default:
              return (skill_num);
            }
          }

          int reverse_web(struct char_data *ch, int &skill, int &target)
          {
            target += 4;
            return GET_ATT(ch, skills[skill].attribute);
          }

          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)
{
  if (!source)
    return NULL;

  char *New = new char[strlen(source) + 1];
  sprintf(New, "%s", source);
  return New;
}

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

/* str_cmp: a case-insensitive version of strcmp */
/* returns: 0 if equal, pos if arg1 > arg2, neg if arg1 < arg2  */
/* scan 'till found different or end of both                 */
int str_cmp(const char *one, const char *two)
{
  for (; *one; one++, two++) {
    int diff = LOWER(*one) - LOWER(*two);

    if (diff!= 0)
      return diff;
  }

  return (LOWER(*one) - LOWER(*two));
}


/* str_str: A case-insensitive version of strstr */
/* returns: A pointer to the first occurance of str2 in str1 */
/* or a null pointer if it isn't found.                      */
char *str_str( const char *str1, const char *str2 )
{
  int i;
  char temp1[MAX_INPUT_LENGTH], temp2[MAX_INPUT_LENGTH];

  for ( i = 0; *(str1 + i); i++ ) {
    temp1[i] = LOWER(*(str1 + i));
  }

  temp1[i] = '\0';

  for ( i = 0; *(str2 + i); i++ ) {
    temp2[i] = LOWER(*(str2 + i));
  }

  temp2[i] = '\0';

  return (strstr(temp1, temp2));
}


/* 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(const char *arg1, const char *arg2, int n)
{
  int chk, i;

  if (arg1 == NULL || arg2 == NULL) {
    log("SYSERR: strn_cmp() passed a NULL pointer, %p or %p.", arg1, arg2);
    return (0);
  }

  for (i = 0; (arg1[i] || arg2[i]) && (n > 0); i++, n--)
    if ((chk = LOWER(arg1[i]) - LOWER(arg2[i])) != 0)
      return (chk); /* not equal */

  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);
}
/* returns 1 if the character has a cyberweapon; 0 otherwise */
int has_cyberweapon(struct char_data * ch)
{
  struct obj_data *obj = NULL;
  for (obj = ch->cyberware;
       obj ;
       obj = obj->next_content)
  {
    /* is the cyberware object a weapon? */
    switch(GET_OBJ_VAL(obj,2)) {
    case 19:
    case 21:
      return 1;
    }
  }
  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 #%ld (%s)", GET_CHAR_NAME(ch),
          world[ch->in_room].number, world[ch->in_room].name);
  mudlog(buf, ch, LOG_DEATHLOG, TRUE);
}

void log(const char *format, ...)
{
  va_list args;
  time_t ct = time(0);
  char *tmstr;

  tmstr = asctime(localtime(&ct));
  *(tmstr + strlen(tmstr) - 1) = '\0';
  fprintf(stderr, "%-15.15s :: ", tmstr + 4);

  va_start(args, format);
  vfprintf(stderr, format, args);
  va_end(args);

  fprintf(stderr, "\n");
}

void time_stamp(char *str, time_t when)
{
  struct tm *newtime;

  newtime = localtime(&when);
  newtime->tm_year = newtime->tm_year % 100;

  sprintf(str, "(%s%d:%s%d:%s%d/%s%d-%s%d-%s%d)",
          newtime->tm_hour < 10 ? "0" : "", newtime->tm_hour,
          newtime->tm_min < 10 ? "0" : "", newtime->tm_min,
          newtime->tm_sec < 10 ? "0" : "", newtime->tm_sec,
          newtime->tm_mon < 9 ? "0" : "", newtime->tm_mon + 1,
          newtime->tm_mday < 10 ? "0" : "", newtime->tm_mday,
          newtime->tm_year < 10 ? "0" : "", newtime->tm_year);
}

/*
 * 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[MAX_STRING_LENGTH], buf2[MAX_STRING_LENGTH];
  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 ( ch && ch->desc && ch->desc->original )
    sprintf(buf2, "[%5ld] (%s) ",
            world[ch->in_room].number,
            GET_CHAR_NAME(ch));
  else if (ch && ch->in_room != NOWHERE)
    sprintf(buf2, "[%5ld] ", world[ch->in_room].number);
  else
    strcpy(buf2, "");

  if (file)
    fprintf(stderr, "%-19.19s :: %s: %s%s\n", tmp, log_types[log], buf2, str);

  ct = ct;
  sprintf(buf, "^g[%s: %s%s]^n\r\n", log_types[log], buf2, 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_FLAGS(tch).AreAnySet(PLR_WRITING, PLR_MAILING,
                                   PLR_EDITING, ENDBIT))
        continue;

      if (ch
          && !access_level(tch, GET_INVIS_LEV(ch))
          && !access_level(tch, LVL_VICEPRES))
        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;
      case LOG_CHEATLOG:
        check_log = PRF_CHEATLOG;
        break;
      case LOG_WIZITEMLOG:
        check_log = PRF_CHEATLOG;
        break;
      case LOG_BANLOG:
        check_log = PRF_BANLOG;
        break;
      case LOG_GRIDLOG:
        check_log = PRF_GRIDLOG;
        break;
      case LOG_WRECKLOG:
        check_log = PRF_WRECKLOG;
        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)
{
  sprintf(result, "%s", names[type]);

  if (result == "(null")
    result = "UNDEFINED";

}

void sprint_obj_mods(struct obj_data *obj, char *result)
{
  *result = 0;
  if (obj->obj_flags.bitvector.GetNumSet() > 0)
  {
    char xbuf[MAX_STRING_LENGTH];
    obj->obj_flags.bitvector.PrintBits(xbuf, MAX_STRING_LENGTH,
                                       affected_bits, AFF_MAX);
    sprintf(result,"%s %s", result, xbuf);
  }

  for (register int i = 0; i < MAX_OBJ_AFFECT; i++)
    if (obj->affected[i].modifier != 0)
    {
      char xbuf[MAX_STRING_LENGTH];
      sprinttype(obj->affected[i].location, apply_types, xbuf);
      sprintf(result,"%s (%+d %s)",
              result, obj->affected[i].modifier, xbuf);
    }
  return;
}


/* 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 = 0;
  now.year = 0;

  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 aaaage(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)
{
  ch = ch->desc && ch->desc->original ? ch->desc->original : ch;

  return (!IS_NPC(ch)
          && (GET_LEVEL(ch) >= level ));
}

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

  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;
  AFF_FLAGS(ch).RemoveBits(AFF_CHARM, AFF_GROUP, ENDBIT);
}

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

  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;
  }
}

bool PRF_TOG_CHK(char_data *ch, dword offset)
{
  PRF_FLAGS(ch).ToggleBit(offset);

  return PRF_FLAGS(ch).IsSet(offset);
}

bool PLR_TOG_CHK(char_data *ch, dword offset)
{
  PLR_FLAGS(ch).ToggleBit(offset);

  return PLR_FLAGS(ch).IsSet(offset);
}

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;
}

int get_speed(struct veh_data *veh)
{
  int speed = 0;

  switch (veh->cspeed)
  {
  case SPEED_OFF:
  case SPEED_IDLE:
    speed = 0;
    break;
  case SPEED_CRUISING:
    if (ROOM_FLAGGED(veh->in_room, ROOM_INDOORS))
      speed = MIN(veh->speed, 3);
    else
      speed = MIN(veh->speed, 55);
    break;
  case SPEED_SPEEDING:
    if (ROOM_FLAGGED(veh->in_room, ROOM_INDOORS))
      speed = MIN(veh->speed, MAX(5, (int)(veh->speed * .7)));
    else
      speed = MIN(veh->speed, MAX(55, (int)(veh->speed * .7)));
    break;
  case SPEED_MAX:
    if (ROOM_FLAGGED(veh->in_room, ROOM_INDOORS))
      speed = MIN(veh->speed, 8);
    else
      speed = veh->speed;
    break;
  }
  return (speed);
}

int negotiate(struct char_data *ch, struct char_data *tch, int comp, int basevalue, int mod, bool buy)
{
  struct obj_data *bio;
  int cskill = GET_SKILL(ch, SKILL_NEGOTIATION);
  for (bio = ch->bioware; bio; bio = bio->next_content)
    if (GET_OBJ_VAL(bio, 2) == 3)
    {
      cskill += GET_OBJ_VAL(bio, 0);
      break;
    }
  int tskill = GET_SKILL(tch, SKILL_NEGOTIATION);
  for (bio = tch->bioware; bio; bio = bio->next_content)
    if (GET_OBJ_VAL(bio, 2) == 3)
    {
      tskill += GET_OBJ_VAL(bio, 0);
      break;
    }
  int chnego = success_test(cskill, GET_INT(tch)+mod);
  int tchnego = success_test(tskill, GET_INT(ch)+mod);
  if (comp)
  {
    chnego += success_test(GET_SKILL(ch, comp), GET_INT(tch)+mod) / 2;
    tchnego += success_test(GET_SKILL(tch, comp), GET_INT(ch)+mod) / 2;
  }
  int num = chnego - tchnego;
  if (num > 0)
  {
    if (buy)
      basevalue = MAX((int)(basevalue * 3/4), basevalue - (num * (basevalue / 20)));
    else
      basevalue = MIN((int)(basevalue * 5/4), basevalue + (num * (basevalue / 15)));
  } else
  {
    if (buy)
      basevalue = MIN((int)(basevalue * 5/4), basevalue + (num * (basevalue / 15)));
    else
      basevalue = MAX((int)(basevalue * 3/4), basevalue - (num * (basevalue / 20)));
  }
  return basevalue;

}