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