/* ************************************************************************
* File: utils.c EmpireMUD AD 1.0 *
* Usage: various internal functions of a utility nature *
* *
* All rights reserved. See license.doc for complete information. *
* *
* Code base by Paul Clarke. EmpireMUD Project, a tbgMUD Production. *
* Based upon CircleMUD 3.0, beta patch level 17, by Jeremy Elson. *
* *
* Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University *
* CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. *
************************************************************************ */
#include "conf.h"
#include "sysdep.h"
#include "structs.h"
#include "utils.h"
#include "db.h"
#include "comm.h"
#include "handler.h"
#include "interpreter.h"
#include "skills.h"
#include "empire.h"
#include "vnums.h"
extern struct time_data time_info;
int last_action_rotation = 0;
/* creates a random number in interval [from;to] */
int number(int from, int to) {
unsigned long empire_random();
/* error checking in case people call number() incorrectly */
if (from > to) {
int tmp = from;
from = to;
to = tmp;
}
return ((empire_random() % (to - from + 1)) + from);
}
/* simulates dice roll */
int dice(int number, int size) {
unsigned long empire_random();
int sum = 0;
if (size <= 0 || number <= 0)
return (0);
while (number-- > 0)
sum += ((empire_random() % size) + 1);
return (sum);
}
/*
* simulates White Wolf 10-sided dice roll
* It rolls num 10-sided dice and returns the number
* of dice with results >= diff. diff is, by default,
* max 10, min 2. Each result of 1 subtracts one
* "success" so the function may return 0 or a negative
* number
*/
int ww_dice(int num, int diff) {
int result = 0;
int i, n;
for (i = 0; i < num; i++)
if ((n = number(1, 13)) == 1)
result -= 1;
else if (((n) > 10 ? (n - 5) : (n)) >= MIN(10, MAX(2, diff)))
result += 1;
return (result);
}
char *CAP(char *txt) {
*txt = UPPER(*txt);
return (txt);
}
/* Create a duplicate of a string */
char *str_dup(const char *source) {
char *new_z;
CREATE(new_z, char, strlen(source) + 1);
return (strcpy(new_z, source));
}
/*
* Strips \r\n from end of string.
*/
void prune_crlf(char *txt) {
int i = strlen(txt) - 1;
while (txt[i] == '\n' || txt[i] == '\r')
txt[i--] = '\0';
}
/*
* str_cmp: a case-insensitive version of strcmp().
* Returns: 0 if equal, > 0 if arg1 > arg2, or < 0 if arg1 < arg2.
*
* Scan until strings are found different or we reach the end of both.
*/
int str_cmp(const char *arg1, const char *arg2) {
int chk, i;
if (arg1 == NULL || arg2 == NULL) {
log("SYSERR: str_cmp() passed a NULL pointer, %p or %p.", arg1, arg2);
return (0);
}
for (i = 0; arg1[i] || arg2[i]; i++)
if ((chk = LOWER(arg1[i]) - LOWER(arg2[i])) != 0)
return (chk); /* not equal */
return (0);
}
/*
* strn_cmp: a case-insensitive version of strncmp().
* Returns: 0 if equal, > 0 if arg1 > arg2, or < 0 if arg1 < arg2.
*
* Scan until strings are found different, the end of both, or n is 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_str: a case-insensitive version of strstr().
* One note is that it doesn't return a pointer like strstr, just
* 1 or 0 where 1 is found, 0 is not
*/
bool str_str(const char *arg1, const char *arg2) {
char *new1, *new2;
int i;
if (!arg1 || !arg2 || !*arg1 || !*arg2)
return 0;
CREATE(new1, char, strlen(arg1) + 1);
strncpy(new1, arg1, strlen(arg1));
CREATE(new2, char, strlen(arg2) + 1);
strncpy(new2, arg2, strlen(arg2));
for (i = 0; i < strlen(new1); i++)
new1[i] = LOWER(new1[i]);
for (i = 0; i < strlen(new2); i++)
new2[i] = LOWER(new2[i]);
if (strstr(new1, new2))
return 1;
return 0;
}
/*
* New variable argument log() function. Works the same as the old for
* previously written code but is very nice for new code.
*/
void basic_mud_log(const char *format, ...) {
va_list args;
time_t ct = time(0);
char *time_s = asctime(localtime(&ct));
if (logfile == NULL)
puts("SYSERR: Using log() before stream was initialized!");
if (format == NULL)
format = "SYSERR: log() received a NULL format.";
time_s[strlen(time_s) - 1] = '\0';
fprintf(logfile, "%-15.15s :: ", time_s + 4);
va_start(args, format);
vfprintf(logfile, format, args);
va_end(args);
fprintf(logfile, "\n");
fflush(logfile);
}
/* the "touch" command, essentially. */
int touch(const char *path) {
FILE *fl;
if (!(fl = fopen(path, "a"))) {
log("SYSERR: %s: %s", path, strerror(errno));
return (-1);
}
else {
fclose(fl);
return (0);
}
}
void syslog(int level, bool file, const char *str, ...) {
char output[MAX_STRING_LENGTH];
Descr i;
va_list tArgList;
if (!str)
return;
va_start(tArgList, str);
vsprintf(output, str, tArgList);
if (file)
log(output);
for (i = descriptor_list; i; i = i->next) {
if (STATE(i) != CON_PLAYING || IS_NPC(i->character)) /* switch */
continue;
if (PLR_FLAGGED(i->character, PLR_WRITING))
continue;
if (GET_LEVEL(i->character) < LVL_START_IMM)
continue;
if (GET_LEVEL(i->character) < level)
continue;
msg_to_char(i->character, "&2[ %s ]&0\r\n", output);
}
}
void mortlog(Creature ch, const char *str, ...) {
char output[MAX_STRING_LENGTH];
Descr i;
va_list tArgList;
if (!str)
return;
va_start(tArgList, str);
vsprintf(output, str, tArgList);
for (i = descriptor_list; i; i = i->next) {
if (STATE(i) != CON_PLAYING || IS_NPC(i->character)) /* switch */
continue;
if (PLR_FLAGGED(i->character, PLR_WRITING))
continue;
if (!PRF_FLAGGED(i->character, PRF_MORTLOG))
continue;
msg_to_char(i->character, "&6[ %s ]&0\r\n", output);
}
va_end(tArgList);
}
/*
* If you don't have a 'const' array, just cast it as such. It's safer
* to cast a non-const array as const than to cast a const one as non-const.
* Doesn't really matter since this function doesn't change the array though.
*/
void sprintbit(bitvector_t bitvector, const char *names[], char *result, byte space) {
long nr;
*result = '\0';
for (nr = 0; bitvector; bitvector >>= 1) {
if (IS_SET(bitvector, 1)) {
if (*names[nr] != '\n') {
strcat(result, names[nr]);
if (space)
strcat(result, " ");
}
else
strcat(result, "UNDEFINED ");
}
if (*names[nr] != '\n')
nr++;
}
if (!*result && space)
strcpy(result, "NOBITS ");
}
void sprinttype(int type, const char *names[], char *result) {
int nr = 0;
while (type && *names[nr] != '\n') {
type--;
nr++;
}
if (*names[nr] != '\n')
strcpy(result, names[nr]);
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;
static 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..29 days */
/* secs -= SECS_PER_REAL_DAY * now.day; - Not used. */
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;
static 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..29 days */
secs -= SECS_PER_MUD_DAY * now.day;
now.month = (secs / SECS_PER_MUD_MONTH) % 12; /* 0..11 months */
secs -= SECS_PER_MUD_MONTH * now.month;
now.year = YEAR_ADD + (secs / SECS_PER_MUD_YEAR); /* YEAR_ADD..XX? years */
return (&now);
}
struct time_info_data *age(Creature ch) {
static struct time_info_data player_age;
player_age = *mud_time_passed(time(0), ch->player.time.birth);
player_age.year += 17; /* All players start at 17 */
player_age.year -= YEAR_ADD;
return (&player_age);
}
/* Check if making CH follow VICTIM will create an illegal */
/* Follow "Loop/circle" */
bool circle_follow(Creature ch, Creature victim) {
Creature 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(Creature ch) {
struct follow_type *j, *k;
if (ch->master == NULL)
return;
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;
free(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;
free(j);
}
ch->master = NULL;
REMOVE_BIT(AFF_FLAGS(ch), AFF_CHARM | AFF_PARTY);
}
/* Called when a character that follows/is followed dies */
void die_follower(Creature 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);
}
}
/*
* Do NOT call this before having checked if a circle of followers
* will arise. CH will follow leader
*/
void add_follower(Creature ch, Creature leader) {
struct follow_type *k;
if (ch->master)
return;
ch->master = leader;
CREATE(k, struct follow_type, 1);
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 {
fgets(temp, 256, fl);
if (feof(fl))
return (0);
lines++;
} while (*temp == '*' || *temp == '\n');
temp[strlen(temp) - 1] = '\0';
strcpy(buf, temp);
return (lines);
}
int get_filename(char *orig_name, char *filename, int mode) {
const char *prefix, *middle, *suffix;
char name[64], *ptr;
if (orig_name == NULL || *orig_name == '\0' || filename == NULL) {
log("SYSERR: NULL pointer or empty string passed to get_filename(), %p or %p.", orig_name, filename);
return (0);
}
switch (mode) {
case CRASH_FILE:
prefix = LIB_PLROBJS;
suffix = SUF_OBJS;
break;
case ALIAS_FILE:
prefix = LIB_PLRALIAS;
suffix = SUF_ALIAS;
break;
case ETEXT_FILE:
prefix = LIB_PLRTEXT;
suffix = SUF_TEXT;
break;
case REC_FILE:
prefix = LIB_PLRREC;
suffix = SUF_REC;
break;
case LORE_FILE:
prefix = LIB_PLRLORE;
suffix = SUF_LORE;
break;
default:
return (0);
}
strcpy(name, orig_name);
for (ptr = name; *ptr; ptr++)
*ptr = LOWER(*ptr);
if (LOWER(*name) <= 'e')
middle = "A-E";
else if (LOWER(*name) <= 'j')
middle = "F-J";
else if (LOWER(*name) <= 'o')
middle = "K-O";
else if (LOWER(*name) <= 't')
middle = "P-T";
else if (LOWER(*name) <= 'z')
middle = "U-Z";
else
middle = "ZZZ";
/* If your compiler gives you shit about <= '', use this switch:
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(Room room) {
int i = 0;
Creature ch;
for (ch = room->people; ch != NULL; ch = ch->next_in_room)
if (!IS_NPC(ch))
i++;
return (i);
}
char *PERS(Creature ch, Creature vict, bool real) {
static char output[MAX_INPUT_LENGTH];
if (!CAN_SEE(vict, ch))
return "someone";
if (!IS_NPC(ch) && GET_MORPH(ch) && !real)
return morph_string(ch, MORPH_STRING_NAME);
strcpy(output, GET_NAME(ch));
if (!IS_NPC(ch) && GET_LASTNAME(ch))
sprintf(output + strlen(output), " %s", GET_LASTNAME(ch));
return output;
}
int shift_room(int origin, int x, int y) {
int o = origin;
if (X_COORD(origin) + x < 0)
o = origin + x + MAP_WIDTH;
else if (X_COORD(origin) + x >= MAP_WIDTH)
o = origin + x - MAP_WIDTH;
else
o = origin + x;
if ((o + y * MAP_HEIGHT) >= MAP_SIZE)
o = o + y * MAP_HEIGHT - MAP_SIZE;
else if ((o + y * MAP_HEIGHT) < 0)
o = o + y * MAP_HEIGHT + MAP_WIDTH * MAP_HEIGHT;
else
o = o + y * MAP_HEIGHT;
if (o < 0)
return 0;
return o;
}
/* Return resources? */
void cancel_action(Creature ch) {
void cancel_forging(Creature ch);
void cancel_melting(Creature ch);
switch (GET_ACTION(ch)) {
case ACT_FORGING:
cancel_forging(ch);
break;
case ACT_MILLING:
obj_to_char(read_object(o_WHEAT, VIRTUAL), ch);
break;
case ACT_MELTING:
cancel_melting(ch);
break;
case ACT_CRAFTING:
obj_to_char(read_object(GET_ACTION_VNUM(ch, 0), VIRTUAL), ch);
break;
case ACT_SCRAPING:
obj_to_char(read_object(o_TREE, VIRTUAL), ch);
break;
case ACT_CHIPPING:
obj_to_char(read_object(GET_ACTION_VNUM(ch, 0), VIRTUAL), ch);
break;
}
GET_ACTION(ch) = ACT_NONE;
}
void update_actions(void) {
void finish_forging(Creature ch);
void finish_melting(Creature ch);
void process_dismantling(Creature ch, room_rnum room);
void process_build(Creature ch, room_rnum room);
void process_manufacturing(Creature ch);
void cancel_forging(Creature ch);
void embrace_char(Creature ch, Creature victim);
extern Object make_corpse(Creature ch);
extern const char *crops[];
extern const int dam_type[];
Descr d;
Creature ch, c;
Object obj = NULL, obj2 = NULL;
int i, j, vnum = NOTHING, count;
bool found = FALSE;
last_action_rotation++;
if (last_action_rotation > 4)
last_action_rotation = 0;
for (d = descriptor_list; d; d = d->next) {
if (STATE(d) != CON_PLAYING || !(ch = d->character) || IS_NPC(ch) || GET_ACTION(ch) == ACT_NONE)
continue;
if ((GET_ACTION_ROOM(ch) != ch->in_room && GET_ACTION_ROOM(ch) != NOWHERE) || ((GET_FEEDING_FROM(ch) || GET_FED_ON_BY(ch)) && GET_ACTION(ch) != ACT_EMBRACE) || FIGHTING(ch) || GET_POS(ch) < POS_STANDING || IS_WRITING(ch)) {
cancel_action(ch);
continue;
}
if (GET_ACTION_ROTATION(ch) != last_action_rotation)
continue;
switch (GET_ACTION(ch)) {
case ACT_BATHING:
if (GET_DAYS_SINCE_BATHING(ch) > 0) {
if (SECT(ch->in_room) == SECT_RIVER && !number(0, 2))
GET_DAYS_SINCE_BATHING(ch) -= 1;
else if ((BUILDING_TYPE(ch->in_room) == BUILDING_BATHS || ROOM_TYPE(ch->in_room) == RTYPE_BATHS) && !number(0, 1))
GET_DAYS_SINCE_BATHING(ch) -= 1;
}
if (GET_DAYS_SINCE_BATHING(ch) == 0 && !IS_GOD(ch) && !IS_IMMORTAL(ch)) {
msg_to_char(ch, "You finish bathing and climb out of the water to dry off.\r\n");
act("$n finishes bathing and climbs out of the water to dry off.", FALSE, ch, 0, 0, TO_ROOM);
GET_ACTION(ch) = ACT_NONE;
}
else {
switch(number(0, 2)) {
case 0:
msg_to_char(ch, "You wash yourself off...\r\n");
act("$n washes $mself carefully...", FALSE, ch, 0, 0, TO_ROOM);
break;
case 1:
msg_to_char(ch, "You scrub your hair to get out any dirt and insects...\r\n");
act("$n scrubs $s hair to get out any dirt and insects...", FALSE, ch, 0, 0, TO_ROOM);
break;
case 2:
msg_to_char(ch, "You swim through the water...\r\n");
act("$n swims through the water...", FALSE, ch, 0, 0, TO_ROOM);
break;
}
}
break;
case ACT_EMBRACE:
if (!GET_FEEDING_FROM(ch))
GET_ACTION(ch) = ACT_NONE;
else if (GET_BLOOD(GET_FEEDING_FROM(ch)) <= 0)
embrace_char(ch, GET_FEEDING_FROM(ch));
break;
case ACT_DIGGING:
vnum = NOTHING;
if (GET_EQ(ch, WEAR_WIELD) && GET_OBJ_VNUM(GET_EQ(ch, WEAR_WIELD)) == f_SHOVEL)
found = TRUE;
else if (GET_EQ(ch, WEAR_HOLD) && GET_OBJ_VNUM(GET_EQ(ch, WEAR_HOLD)) == f_SHOVEL)
found = TRUE;
GET_ACTION_TIMER(ch) -= ww_dice(GET_STRENGTH(ch) + GET_ATHLETICS(ch) + found, 6);
if (GET_ACTION_TIMER(ch) <= 0) {
GET_ACTION(ch) = 0;
if (vnum == NOTHING)
for (i = 0; i < NUM_2D_DIRS; i++)
if (SECT(real_shift(ch->in_room, shift_dir[i][0], shift_dir[i][1])) == SECT_RIVER)
if (!number(0, 3)) {
vnum = o_CLAY;
break;
}
if (vnum == NOTHING)
vnum = !number(0, 10) ? o_FLINT : o_ROCK;
obj = read_object(vnum, VIRTUAL);
if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch) || GET_OBJ_WEIGHT(obj) + IS_CARRYING_W(ch) > CAN_CARRY_W(ch))
obj_to_room(obj, ch->in_room);
else
obj_to_char(obj, ch);
act("You pull $p from the ground!", FALSE, ch, obj, 0, TO_CHAR);
act("$n pulls $p from the ground!", FALSE, ch, obj, 0, TO_ROOM);
break;
}
send_to_char("You dig vigorously at the ground.\r\n", ch);
act("$n digs vigorously at the ground.", FALSE, ch, 0, 0, TO_ROOM);
break;
case ACT_MORPHING:
GET_ACTION_TIMER(ch) -= 1;
if (GET_ACTION_TIMER(ch) <= 0) {
sprintf(buf, "%s has become $n!", PERS(ch, ch, 0));
perform_morph(ch, (ubyte) GET_ACTION_VNUM(ch, 0));
act(buf, TRUE, ch, 0, 0, TO_ROOM);
act("You have become $n!", FALSE, ch, 0, 0, TO_CHAR);
GET_ACTION(ch) = ACT_NONE;
}
else {
msg_to_char(ch, "Your body warps and distorts painfully!\r\n");
act("$n's body warps and distorts hideously!", TRUE, ch, 0, 0, TO_ROOM);
}
break;
case ACT_GATHERING:
send_to_char("You search the ground for sticks...\r\n", ch);
act("$n searches around on the ground...", TRUE, ch, 0, 0, TO_ROOM);
GET_ACTION_TIMER(ch) -= ww_dice(GET_PERCEPTION(ch) + GET_ALERTNESS(ch), 5 - SENSES_BONUS(ch));
if (GET_ACTION_TIMER(ch) <= 0) {
if (SECT(ch->in_room) == SECT_FOREST_1 || SECT(ch->in_room) == SECT_FOREST_2 || SECT(ch->in_room) == SECT_FOREST_3 || SECT(ch->in_room) == SECT_FOREST_4 || (SECT(ch->in_room) == SECT_CROP && world[ch->in_room].type == CROP_FRUIT))
GET_ACTION_TIMER(ch) = number(5, 9);
else
GET_ACTION(ch) = ACT_NONE;
obj = read_object(o_STICK, VIRTUAL);
if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch) || GET_OBJ_WEIGHT(obj) + IS_CARRYING_W(ch) > CAN_CARRY_W(ch))
obj_to_room(obj, ch->in_room);
else
obj_to_char(obj, ch);
act("You find $p!", FALSE, ch, obj, 0, TO_CHAR);
act("$n finds $p!", TRUE, ch, obj, 0, TO_ROOM);
break;
}
break;
case ACT_PICKING:
if (SECT(ch->in_room) == SECT_CROP && world[ch->in_room].type == CROP_FRUIT) {
send_to_char("You search the trees for apples...\r\n", ch);
act("$n searches the trees for apples...", TRUE, ch, 0, 0, TO_ROOM);
}
else {
send_to_char("You search the ground for nice flowers...\r\n", ch);
act("$n searches around the ground...", TRUE, ch, 0, 0, TO_ROOM);
}
GET_ACTION_TIMER(ch) -= ww_dice(GET_PERCEPTION(ch) + GET_ALERTNESS(ch), 5 - SENSES_BONUS(ch));
if (GET_ACTION_TIMER(ch) <= 0) {
if (SECT(ch->in_room) == SECT_FIELD || (SECT(ch->in_room) == SECT_CROP && world[ch->in_room].type == CROP_FRUIT))
GET_ACTION_TIMER(ch) = number(5, 9);
else
GET_ACTION(ch) = ACT_NONE;
if (SECT(ch->in_room) == SECT_CROP && world[ch->in_room].type == CROP_FRUIT)
obj = read_object(o_APPLES, VIRTUAL);
else
obj = read_object(o_FLOWER, VIRTUAL);
if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch) || GET_OBJ_WEIGHT(obj) + IS_CARRYING_W(ch) > CAN_CARRY_W(ch))
obj_to_room(obj, ch->in_room);
else
obj_to_char(obj, ch);
act("You find $p!", FALSE, ch, obj, 0, TO_CHAR);
act("$n finds $p!", TRUE, ch, obj, 0, TO_ROOM);
break;
}
break;
case ACT_CRAFTING:
if ((!(obj = GET_EQ(ch, WEAR_WIELD)) || dam_type[GET_OBJ_VAL(obj, 2)] < DAM_LETHAL) && (obj || !(obj = GET_EQ(ch, WEAR_HOLD)) || dam_type[GET_OBJ_VAL(obj, 2)] < DAM_LETHAL)) {
msg_to_char(ch, "You need to be using a sharp tool to scrape it.\r\n");
obj_to_char(read_object(GET_ACTION_VNUM(ch, 0), VIRTUAL), ch);
GET_ACTION(ch) = ACT_NONE;
break;
}
msg_to_char(ch, "You scrape at %s...\r\n", GET_OBJ_NAME_BY_PROTO(real_object(GET_ACTION_VNUM(ch, 0))));
GET_ACTION_TIMER(ch) -= ww_dice(GET_DEXTERITY(ch) + GET_CRAFTS(ch), 5);
if (GET_ACTION_TIMER(ch) <= 0) {
GET_ACTION(ch) = 0;
obj_to_char((obj = read_object(GET_ACTION_VNUM(ch, 1), VIRTUAL)), ch);
act("You craft $p!", FALSE, ch, obj, 0, TO_CHAR);
act("$n crafts $p!", TRUE, ch, obj, 0, TO_ROOM);
}
break;
case ACT_SCRAPING:
if ((!(obj = GET_EQ(ch, WEAR_WIELD)) || dam_type[GET_OBJ_VAL(obj, 2)] < DAM_LETHAL) && (obj || !(obj = GET_EQ(ch, WEAR_HOLD)) || dam_type[GET_OBJ_VAL(obj, 2)] < DAM_LETHAL)) {
msg_to_char(ch, "You need to be using a sharp tool to scrape it.\r\n");
obj_to_char(read_object(o_TREE, VIRTUAL), ch);
GET_ACTION(ch) = ACT_NONE;
break;
}
msg_to_char(ch, "You scrape at %s...\r\n", GET_OBJ_NAME_BY_PROTO(real_object(o_TREE)));
GET_ACTION_TIMER(ch) -= 1;
if (GET_ACTION_TIMER(ch) <= 0) {
GET_ACTION(ch) = 0;
obj_to_char((obj = read_object(o_LOG, VIRTUAL)), ch);
for (i = 0; i < number(2, 5); i++)
obj_to_char((obj2 = read_object(o_STICK, VIRTUAL)), ch);
sprintf(buf, "You finish scraping off $p and manage to get $P (%dx)!", i);
act(buf, FALSE, ch, obj, obj2, TO_CHAR);
act("$n finishes scraping off $p!", TRUE, ch, obj, 0, TO_ROOM);
}
break;
case ACT_CHIPPING:
if ((!(obj = GET_EQ(ch, WEAR_WIELD)) || GET_OBJ_VAL(obj, 2) != TYPE_HAMMER) && (obj || !(obj = GET_EQ(ch, WEAR_HOLD)) || GET_OBJ_VAL(obj, 2) != TYPE_HAMMER)) {
msg_to_char(ch, "You need to be using some kind of hammer to chip it.\r\n");
obj_to_char(read_object(GET_ACTION_VNUM(ch, 0), VIRTUAL), ch);
GET_ACTION(ch) = ACT_NONE;
break;
}
msg_to_char(ch, "You chip away at the piece of rock...\r\n");
GET_ACTION_TIMER(ch) -= ww_dice(GET_STRENGTH(ch) + GET_CRAFTS(ch), 5);
if (GET_ACTION_TIMER(ch) <= 0) {
GET_ACTION(ch) = 0;
switch (GET_ACTION_VNUM(ch, 0)) {
case o_ROCK:
obj_to_char((obj = read_object(o_CHIPPED, VIRTUAL)), ch);
msg_to_char(ch, "It splits open!\r\n");
break;
case o_CHIPPED:
obj_to_char((obj = read_object(o_HANDAXE, VIRTUAL)), ch);
act("You have crafted $p!", FALSE, ch, obj, 0, TO_CHAR);
break;
case o_HANDAXE:
obj_to_char((obj = read_object(o_SPEARHEAD, VIRTUAL)), ch);
act("You have crafted $p!", FALSE, ch, obj, 0, TO_CHAR);
break;
}
}
break;
case ACT_CHOPPING:
for (count = 0; count < 1 + ATTACK_BONUS(ch) && GET_ACTION(ch) == ACT_CHOPPING; count++) {
if (!GET_EQ(ch, WEAR_WIELD) || GET_OBJ_VAL(GET_EQ(ch, WEAR_WIELD), 2) != TYPE_SLICE) {
send_to_char("You need to be using an axe to chop.\r\n", ch);
GET_ACTION(ch) = ACT_NONE;
break;
}
if ((i = ww_dice(GET_DEXTERITY(ch) + GET_MELEE(ch), 6)) > 0) {
GET_BUILD_VALUE(ch->in_room) -= (ww_dice(GET_STRENGTH(ch) + GET_OBJ_VAL(GET_EQ(ch, WEAR_WIELD), 1) + i, 6) + GET_POTENCE(ch));
act("You swing $p hard into the tree!", FALSE, ch, GET_EQ(ch, WEAR_WIELD), 0, TO_CHAR);
act("$n swings $p hard into the tree!", FALSE, ch, GET_EQ(ch, WEAR_WIELD), 0, TO_ROOM);
}
else {
act("You swing $p, but miss the tree!", FALSE, ch, GET_EQ(ch, WEAR_WIELD), 0, TO_CHAR);
act("$n swings $p, but misses the tree!", FALSE, ch, GET_EQ(ch, WEAR_WIELD), 0, TO_ROOM);
}
if (GET_BUILD_VALUE(ch->in_room) > 0)
continue;
GET_BUILD_VALUE(ch->in_room) = 0;
for (c = world[ch->in_room].people; c; c = c->next_in_room)
if (!IS_NPC(c) && GET_ACTION(c) == ACT_CHOPPING)
GET_ACTION(c) = ACT_NONE;
obj_to_room(read_object(o_TREE, VIRTUAL), ch->in_room);
SECT(ch->in_room)--;
if (SECT(ch->in_room) < SECT_FIELD) {
SECT(ch->in_room) = SECT_FIELD;
act("With a loud crack, it falls to the ground and the area is depleted!", FALSE, ch, 0, 0, TO_CHAR);
act("With a loud crack, it falls to the ground and the area is depleted!", FALSE, ch, 0, 0, TO_ROOM);
}
else {
act("With a loud crack, it falls to the ground!", FALSE, ch, 0, 0, TO_CHAR);
act("With a loud crack, it falls to the ground!", FALSE, ch, 0, 0, TO_ROOM);
}
if (world[ch->in_room].type2 && SECT(ch->in_room) == SECT_FIELD) {
SECT(ch->in_room) = SECT_DESERT;
world[ch->in_room].type2 = 0;
}
}
break;
case ACT_BUILDING:
for (count = 0; count < 1 + ATTACK_BONUS(ch) && GET_ACTION(ch) == ACT_BUILDING; count++)
process_build(ch, ch->in_room);
break;
case ACT_DISMANTLING:
for (count = 0; count < 1 + ATTACK_BONUS(ch) && GET_ACTION(ch) == ACT_DISMANTLING; count++)
process_dismantling(ch, ch->in_room);
break;
case ACT_HARVESTING:
if (!GET_EQ(ch, WEAR_WIELD) || (GET_OBJ_VAL(GET_EQ(ch, WEAR_WIELD), 2) != TYPE_SLICE && GET_OBJ_VAL(GET_EQ(ch, WEAR_WIELD), 2) != TYPE_SLASH)) {
send_to_char("You're not using the proper tool for harvesting.\r\n", ch);
GET_ACTION(ch) = ACT_NONE;
break;
}
switch(number(0, 2)) {
case 0:
msg_to_char(ch, "You walk through the field, harvesting the %s.\r\n", crops[(int) world[ch->in_room].type]);
sprintf(buf, "$n walks through the field, harvesting the %s.", crops[(int) world[ch->in_room].type]);
act(buf, FALSE, ch, 0, 0, TO_ROOM);
break;
case 1:
msg_to_char(ch, "You carefully harvest the %s.\r\n", crops[(int) world[ch->in_room].type]);
sprintf(buf, "$n carefully harvests the %s.", crops[(int) world[ch->in_room].type]);
act(buf, FALSE, ch, 0, 0, TO_ROOM);
break;
}
GET_BUILD_VALUE(ch->in_room) -= ww_dice(GET_DEXTERITY(ch) + GET_MELEE(ch), 6);
if (GET_BUILD_VALUE(ch->in_room) > 0)
break;
GET_BUILD_VALUE(ch->in_room) = 0;
for (c = world[ch->in_room].people; c; c = c->next_in_room)
if (!IS_NPC(c) && GET_ACTION(c) == ACT_HARVESTING)
GET_ACTION(c) = ACT_NONE;
act("You finish harvesting the crop!", FALSE, ch, 0, 0, TO_CHAR);
act("$n finished harvesting the crop!", FALSE, ch, 0, 0, TO_ROOM);
switch (world[ch->in_room].type) {
case CROP_FRUIT: vnum = o_APPLES; break;
case CROP_WHEAT: vnum = o_WHEAT; break;
case CROP_CORN: vnum = o_CORN; break;
default: vnum = o_APPLES; break;
}
j = number(1, 5);
/* Give three trees for harvesting an orchard */
if(world[ch->in_room].type == CROP_FRUIT){
for(i =0; i<=3; i++){
obj_to_room(read_object(o_TREE, VIRTUAL), ch->in_room);
}
}
for (i = 0; i <= j; i++)
obj_to_room(read_object(vnum, VIRTUAL), ch->in_room);
SECT(ch->in_room) = SECT_FIELD;
world[ch->in_room].type = 0;
break;
case ACT_PLANTING:
GET_ACTION_TIMER(ch)--;
if (GET_ACTION_TIMER(ch))
GET_BUILD_VALUE(ch->in_room) /= 2;
else {
msg_to_char(ch, "You finish planting!\r\n");
act("$n finishes planting!", FALSE, ch, 0, 0, TO_ROOM);
GET_ACTION(ch) = ACT_NONE;
}
break;
case ACT_MINING:
for (count = 0; count < 1 + ATTACK_BONUS(ch) && GET_ACTION(ch) == ACT_MINING; count++) {
if (!GET_EQ(ch, WEAR_WIELD) || ((GET_OBJ_VAL(GET_EQ(ch, WEAR_WIELD), 2) != TYPE_PICK) && GET_OBJ_VNUM(GET_EQ(ch, WEAR_WIELD)) != o_HANDAXE)) {
send_to_char("You're not using the proper tool for mining!\r\n", ch);
GET_ACTION(ch) = ACT_NONE;
break;
}
GET_ACTION_TIMER(ch) -= ww_dice(GET_STRENGTH(ch) + GET_ATHLETICS(ch), 6) + GET_POTENCE(ch);
act("You pick at the walls with $p, looking for ore.", FALSE, ch, GET_EQ(ch, WEAR_WIELD), 0, TO_CHAR);
act("$n picks at the walls with $p, looking for ore.", FALSE, ch, GET_EQ(ch, WEAR_WIELD), 0, TO_ROOM);
if (GET_ACTION_TIMER(ch) > 0)
continue;
switch(world[ch->in_room].type2) {
case ITEM_MAT_SILVER: vnum = o_SILVER; break;
case ITEM_MAT_IRON: vnum = o_IRON; break;
default: vnum = o_IRON; break;
}
/* Gold is now found at random *only* */
if (!number(0, 100))
vnum = o_GOLD;
obj = read_object(vnum, VIRTUAL);
world[ch->in_room].spare -= 1;
if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch) || GET_OBJ_WEIGHT(obj) + IS_CARRYING_W(ch) > CAN_CARRY_W(ch))
obj_to_room(obj, ch->in_room);
else
obj_to_char(obj, ch);
act("With that last stroke, $p falls from the wall!", FALSE, ch, obj, 0, TO_CHAR);
act("With $s last stroke, $p falls from the wall where $n was picking!", FALSE, ch, obj, 0, TO_ROOM);
GET_ACTION(ch) = ACT_NONE;
}
break;
case ACT_MILLING:
GET_ACTION_TIMER(ch) -= ww_dice(GET_INTELLIGENCE(ch) + GET_CRAFTS(ch), 5);
if (GET_ACTION_TIMER(ch) > 0) {
if (!number(0, 4)) {
msg_to_char(ch, "You grind the millstone hard against the grain.\r\n");
act("$n grinds the millstone hard against the grain.", FALSE, ch, 0, 0, TO_ROOM);
}
break;
}
GET_ACTION(ch) = 0;
msg_to_char(ch, "You finish grinding the wheat.\r\n");
act("$n finishes grinding the wheat.", FALSE, ch, 0, 0, TO_ROOM);
obj_to_char(read_object(o_FLOUR, VIRTUAL), ch);
break;
case ACT_BAKING:
GET_ACTION_TIMER(ch) -= ww_dice(GET_INTELLIGENCE(ch) + GET_CRAFTS(ch), 5);
if (GET_ACTION_TIMER(ch) > 0) {
if (!number(0, 4))
msg_to_char(ch, "Your bread is baking...\r\n");
break;
}
GET_ACTION(ch) = 0;
msg_to_char(ch, "You pull the bread from the oven!\r\n");
act("$n pulls a loaf of bread from the oven!", FALSE, ch, 0, 0, TO_ROOM);
obj_to_char(read_object(o_BREAD, VIRTUAL), ch);
break;
case ACT_FORGING:
if (!GET_EQ(ch, WEAR_WIELD) || GET_OBJ_VAL(GET_EQ(ch, WEAR_WIELD), 2) != TYPE_HAMMER) {
send_to_char("You need to be using a hammer to forge.\r\n", ch);
cancel_forging(ch);
break;
}
GET_ACTION_TIMER(ch) -= ww_dice(GET_DEXTERITY(ch) + GET_CRAFTS(ch), 6);
if (GET_ACTION_TIMER(ch) <= 0)
finish_forging(ch);
else {
act("You hit the anvil hard with $p!", FALSE, ch, GET_EQ(ch, WEAR_WIELD), 0, TO_CHAR);
act("$n hits the anvil hard with $p!", FALSE, ch, GET_EQ(ch, WEAR_WIELD), 0, TO_ROOM);
}
break;
case ACT_FISHING:
if (!GET_EQ(ch, WEAR_WIELD) || GET_OBJ_TYPE(GET_EQ(ch, WEAR_WIELD)) != ITEM_WEAPON || GET_OBJ_VAL(GET_EQ(ch, WEAR_WIELD), 2) != TYPE_STING) {
msg_to_char(ch, "You'll need a spear to fish.\r\n");
GET_ACTION(ch) = ACT_NONE;
break;
}
GET_ACTION_TIMER(ch) -= ww_dice(GET_DEXTERITY(ch) + GET_ATHLETICS(ch), 6);
if (GET_ACTION_TIMER(ch) > 0) {
switch(number(0, 5)) {
case 0:
msg_to_char(ch, "A fish darts past you, but you narrowly miss it!\r\n");
break;
case 1:
msg_to_char(ch, "The water waves peacefully, but you don't see any fish..\r\n");
break;
case 2:
msg_to_char(ch, "The fish are jumping off in the distance, but you can't seem to catch one!\r\n");
break;
}
}
else {
GET_ACTION(ch) = ACT_NONE;
char_to_room((c = read_mobile(GET_ACTION_VNUM(ch, 0) == 1 ? OCEAN_FISH : RIVER_FISH, VIRTUAL)), ch->in_room);
obj_to_char((obj = make_corpse(c)), ch);
SET_BIT(GET_OBJ_VAL(obj, 2), CORPSE_SKINNED);
extract_char(c);
msg_to_char(ch, "A fish darts past you..\r\n");
act("You jab your spear into the water and when you extract it you find $p on the end!", FALSE, ch, obj, 0, TO_CHAR);
act("$n jabs $s spear into the water and when $e draws it out, it has $p on the end!", TRUE, ch, obj, 0, TO_ROOM);
}
break;
case ACT_MELTING:
GET_ACTION_TIMER(ch) -= 1;
if (GET_ACTION_TIMER(ch) > 0) {
if (!number(0, 2))
msg_to_char(ch, "You watch as it melts in the fire.\r\n");
break;
}
finish_melting(ch);
break;
case ACT_GLASS:
GET_ACTION_TIMER(ch) -= 1;
strcpy(buf1, GET_OBJ_NAME_BY_PROTO(real_object(GET_ACTION_VNUM(ch, 0))));
switch (GET_ACTION_TIMER(ch)) {
case 0:
obj_to_char((obj = read_object(GET_ACTION_VNUM(ch, 0), VIRTUAL)), ch);
act("You complete $p.", FALSE, ch, obj, 0, TO_CHAR);
act("$n has made $p.", TRUE, ch, obj, 0, TO_ROOM);
GET_ACTION(ch) = ACT_NONE;
break;
case 1:
msg_to_char(ch, "You set the glass on the table to cool.\r\n");
act("$n sets the glass on the table to cool.", TRUE, ch, 0, 0, TO_ROOM);
break;
case 2:
msg_to_char(ch, "You roll the glass into the shape of %s.\r\n", buf1);
sprintf(buf, "$n rolls the glass into the shape of %s.", buf1);
act(buf, TRUE, ch, 0, 0, TO_ROOM);
break;
case 3:
msg_to_char(ch, "You blow into the tube and inflate the glass.\r\n");
act("$n blows into the tube and inflates the glass.", TRUE, ch, 0, 0, TO_ROOM);
break;
case 4:
msg_to_char(ch, "You roll the glass into the shape of a ball.\r\n");
act("$n rolls the glass into the shape of a ball.", TRUE, ch, 0, 0, TO_ROOM);
break;
case 5:
msg_to_char(ch, "You blow into the tube and inflate the glass.\r\n");
act("$n blows into the tube and inflates the glass.", TRUE, ch, 0, 0, TO_ROOM);
break;
case 6:
msg_to_char(ch, "You pull a wad of molten glass from the oven.\r\n");
act("$n pulls a wad of molten glass from the oven.", TRUE, ch, 0, 0, TO_ROOM);
break;
case 8:
msg_to_char(ch, "You place a pile of sand in the oven.\r\n");
act("$n places a pile of sand in the oven.", TRUE, ch, 0, 0, TO_ROOM);
break;
}
break;
case ACT_MANUFACTURING:
process_manufacturing(ch);
break;
case ACT_PANNING:
if (!GET_EQ(ch, WEAR_HOLD) || GET_OBJ_VNUM(GET_EQ(ch, WEAR_HOLD)) != f_PAN) {
msg_to_char(ch, "You need to be holding a pan to do that.\r\n");
GET_ACTION(ch) = ACT_NONE;
break;
}
GET_ACTION_TIMER(ch) -= 1;
msg_to_char(ch, "You sift through the sand and pebbles, looking for gold...\r\n");
act("$n sifts through the river bed, looking for gold...", TRUE, ch, 0, 0, TO_ROOM);
if (GET_ACTION_TIMER(ch) <= 0) {
GET_ACTION(ch) = 0;
if (!number(0, 19)) {
obj_to_char((obj = read_object(o_GOLD_SMALL, VIRTUAL)), ch);
act("You find $p!", FALSE, ch, obj, 0, TO_CHAR);
break;
}
msg_to_char(ch, "You find nothing of value.\r\n");
}
break;
case ACT_MUSIC:
if (!(obj = GET_EQ(ch, WEAR_HOLD)) || GET_OBJ_TYPE(obj) != ITEM_INSTRUMENT) {
msg_to_char(ch, "You need to hold an instrument to play music!\r\n");
GET_ACTION(ch) = ACT_NONE;
break;
}
switch (GET_MUSIC(ch)) {
case 1:
strcpy(buf, " very poorly.");
break;
case 2:
strcpy(buf, ".");
break;
case 3:
strcpy(buf, " with flair.");
break;
case 4:
strcpy(buf, " exceptionally well.");
break;
case 5:
strcpy(buf, " majestically.");
break;
default:
strcpy(buf, " angelically!");
break;
}
switch (GET_OBJ_VAL(obj, 0)) {
case INSTR_LYRE:
act("You strum at $p and hum to the tune.", FALSE, ch, obj, 0, TO_CHAR);
if (number(0, 1))
sprintf(buf1, "$n hums a tune and strums at $p%s", buf);
else
sprintf(buf1, "$n plucks at $p%s", buf);
act(buf1, FALSE, ch, obj, 0, TO_ROOM);
break;
case INSTR_FLUTE:
if (number(0, 1))
act("You whistle a tune through $p.", FALSE, ch, obj, 0, TO_CHAR);
else
act("You play $p.", FALSE, ch, obj, 0, TO_CHAR);
if (number(0, 1))
sprintf(buf1, "$n plays $p%s", buf);
else {
sprintf(buf1, "$n whistles a tune on $p.");
if (GET_MUSIC(ch) != 2)
sprintf(buf1 + strlen(buf1), "\r\nYou think $e plays it%s", buf);
}
act(buf1, FALSE, ch, obj, 0, TO_ROOM);
break;
default:
msg_to_char(ch, "This instrument type is uncoded.\r\n");
GET_ACTION(ch) = ACT_NONE;
break;
}
break;
case ACT_EXCAVATING:
for (count = 0; count < 1 + ATTACK_BONUS(ch) && GET_ACTION(ch) == ACT_EXCAVATING; count++) {
if ((!GET_EQ(ch, WEAR_HOLD) || GET_OBJ_VNUM(GET_EQ(ch, WEAR_HOLD)) != f_SHOVEL) && (!GET_EQ(ch, WEAR_WIELD) || GET_OBJ_VNUM(GET_EQ(ch, WEAR_WIELD)) != f_SHOVEL)) {
msg_to_char(ch, "You need a shovel to excavate.\r\n");
GET_ACTION(ch) = ACT_NONE;
break;
}
if (!number(0, 1)) {
msg_to_char(ch, "You jab your shovel into the dirt..\r\n");
act("$n jabs $s shovel into the dirt..", FALSE, ch, 0, 0, TO_ROOM);
}
else {
msg_to_char(ch, "You toss a shovel-full of dirt out of the trench.\r\n");
act("$n tosses a shovel-full of dirt out of the trench.", FALSE, ch, 0, 0, TO_ROOM);
}
GET_BUILD_VALUE(ch->in_room) += 1;
if (GET_BUILD_VALUE(ch->in_room) >= 0) {
msg_to_char(ch, "You finish excavating the trench!\r\n");
act("$n finishes excavating the trench!", FALSE, ch, 0, 0, TO_ROOM);
for (c = world[ch->in_room].people; c; c = c->next_in_room)
if (!IS_NPC(c) && GET_ACTION(c) == ACT_EXCAVATING)
GET_ACTION(c) = ACT_NONE;
}
}
break;
}
}
}
/* strips \r's from line */
char *stripcr(char *dest, const char *src) {
int i, length;
char *temp;
if (!dest || !src) return NULL;
temp = &dest[0];
length = strlen(src);
for (i = 0; *src && (i < length); i++, src++)
if (*src != '\r') *(temp++) = *src;
*temp = '\0';
return dest;
}
void update_reboot(void) {
extern const char *reboot_type[];
ACMD(do_reboot);
ACMD(do_confirm);
extern int wizlock_level;
extern char *wizlock_message;
if (reboot.time < 0)
return;
reboot.time -= 1;
if (reboot.time <= 0) {
do_reboot(NULL, "", 0, reboot.type);
return;
}
if (reboot.time <= 5) {
wizlock_level = 1;
sprintf(buf, "This mud is preparing to %s. The %s will happen in about %d minutes.\r\n", reboot_type[(int) reboot.type], reboot_type[(int) reboot.type], reboot.time);
wizlock_message = str_dup(buf);
}
if (reboot.time <= 5 || (reboot.time <= 15 && (reboot.time % 2))) {
syslog(0, FALSE, "The mud will %s in %d minute%s", reboot_type[(int) reboot.type], reboot.time, reboot.time != 1 ? "s" : "");
syslog(0, FALSE, "This may be accelerated if all players type 'confirm'");
mortlog(0, "The mud will %s in %d minute%s", reboot_type[(int) reboot.type], reboot.time, reboot.time != 1 ? "s" : "");
mortlog(0, "This may be accelerated if all players type 'confirm'");
}
do_confirm(NULL, "", 0, 0);
}
struct new_eq_set_data new_eq[] = {
{ "\r", -1, -1, -1, -1, -1, -1, -1, -1 },
{ "Archer", o_HAT, o_SHIRT, NOTHING, o_PANTS, o_SHOES, f_SHORTSWORD, o_SHORTBOW, o_QUIVER},
{ "Bandit", o_HOOD, o_SHIRT, NOTHING, o_PANTS, o_SHOES, f_DAGGER, f_DIRK, NOTHING },
{ "Civilian", o_HAT, o_SHIRT, NOTHING, o_PANTS, o_SHOES, f_PICK, f_DIRK, NOTHING },
{ "Knight", o_HAT, o_SHIRT, o_TUNIC, o_PANTS, o_SHOES, f_SWORD, f_SWORD, NOTHING },
{ "Maiden", o_HOOD, o_DRESS, NOTHING, NOTHING, o_SHOES, o_TORCH, NOTHING, NOTHING },
{ "Woodsman", o_HAT, o_SHIRT, NOTHING, o_PANTS, o_SHOES, f_AXE, o_TORCH, NOTHING },
{ "\n", -1, -1, -1, -1, -1, -1, -1, -1 }
};
/* Some initializations for characters, including initial skills */
void do_start(Creature ch) {
void set_title(Creature ch, char *title);
extern int siteok_everyone;
int i;
Object obj;
set_title(ch, NULL);
/* Default Flags */
SET_BIT(PRF_FLAGS(ch), PRF_MORTLOG);
if (siteok_everyone)
SET_BIT(PLR_FLAGS(ch), PLR_SITEOK);
GET_DAMAGE(ch) = 0;
GET_MOVE(ch) = GET_MAX_MOVE(ch);
/* Standard conditions */
GET_COND(ch, THIRST) = 0;
GET_COND(ch, FULL) = 0;
GET_COND(ch, DRUNK) = 0;
GET_COND(ch, TIRED) = 0;
/* Start playtime */
ch->player.time.played = 0;
ch->player.time.logon = time(0);
/* Set up initial lore */
if (IS_VAMPIRE(ch))
add_lore(ch, LORE_START_VAMPIRE, -1);
/* Give EQ, if applicable */
if (GET_NEW_EQ_SET(ch) != 0) {
if (new_eq[(int) GET_NEW_EQ_SET(ch)].head != NOTHING)
equip_char(ch, read_object(new_eq[(int) GET_NEW_EQ_SET(ch)].head, VIRTUAL), WEAR_HEAD);
if (new_eq[(int) GET_NEW_EQ_SET(ch)].body != NOTHING)
equip_char(ch, read_object(new_eq[(int) GET_NEW_EQ_SET(ch)].body, VIRTUAL), WEAR_BODY);
if (new_eq[(int) GET_NEW_EQ_SET(ch)].armor != NOTHING)
equip_char(ch, read_object(new_eq[(int) GET_NEW_EQ_SET(ch)].armor, VIRTUAL), WEAR_ARMOR);
if (new_eq[(int) GET_NEW_EQ_SET(ch)].legs != NOTHING)
equip_char(ch, read_object(new_eq[(int) GET_NEW_EQ_SET(ch)].legs, VIRTUAL), WEAR_LEGS);
if (new_eq[(int) GET_NEW_EQ_SET(ch)].feet != NOTHING)
equip_char(ch, read_object(new_eq[(int) GET_NEW_EQ_SET(ch)].feet, VIRTUAL), WEAR_FEET);
if (new_eq[(int) GET_NEW_EQ_SET(ch)].wield != NOTHING)
equip_char(ch, read_object(new_eq[(int) GET_NEW_EQ_SET(ch)].wield, VIRTUAL), WEAR_WIELD);
if (new_eq[(int) GET_NEW_EQ_SET(ch)].hold != NOTHING)
equip_char(ch, read_object(new_eq[(int) GET_NEW_EQ_SET(ch)].hold, VIRTUAL), WEAR_HOLD);
if (new_eq[(int) GET_NEW_EQ_SET(ch)].quiver != NOTHING) {
equip_char(ch, read_object(new_eq[(int) GET_NEW_EQ_SET(ch)].quiver, VIRTUAL), WEAR_QUIVER);
for (i = 0; i < GET_OBJ_VAL(GET_EQ(ch, WEAR_QUIVER), 0); i++)
obj_to_obj(read_object(o_ARROW, VIRTUAL), GET_EQ(ch, WEAR_QUIVER));
}
/* Food/Water */
obj_to_char(read_object(o_BREAD, VIRTUAL), ch);
obj_to_char(read_object(o_BREAD, VIRTUAL), ch);
obj = read_object(c_BOWL, VIRTUAL);
GET_OBJ_VAL(obj, 1) = GET_OBJ_VAL(obj, 0);
GET_OBJ_VAL(obj, 2) = LIQ_WATER;
obj_to_char(obj, ch);
}
}
void update_rooms(void) {
extern int last_zone_rotation;
int i, j, update;
room_rnum room;
update = last_zone_rotation + 1;
if (update > NUM_ZONE_UPDATES)
update = 0;
for (i = 0; i <= NUM_MAP_ZONES; i++) {
if (zone_table[i].rotation != update)
continue;
for (room = i * SIZE_MAP_ZONES; room < (i+1) * SIZE_MAP_ZONES; room++) {
if (room > top_of_world)
break;
/* Growing Seeds */
if (SECT(room) == SECT_SEEDED) {
GET_BUILD_VALUE(room)--;
if (GET_BUILD_VALUE(room) <= 0) {
GET_BUILD_VALUE(room) = 0;
SECT(room) = SECT_CROP;
}
}
/* Regrowing forests */
if (SECT(room) == SECT_FOREST_3 || SECT(room) == SECT_FOREST_2 || SECT(room) == SECT_FOREST_1)
if (!number(0, 99) && !world[room].type2 && !ROOM_AFF_FLAGGED(room, ROOM_AFF_NO_GROW))
SECT(room)++;
/* Growing new forests */
if (SECT(room) == SECT_FOREST_4)
for (j = 0; j < NUM_2D_DIRS; j++)
if (SECT(real_shift(room, shift_dir[j][0], shift_dir[j][1])) == SECT_FIELD)
if (!number(0, 249) && !ROOM_AFF_FLAGGED(room, ROOM_AFF_NO_GROW)) {
SECT(real_shift(room, shift_dir[j][0], shift_dir[j][1])) = SECT_FOREST_1;
GET_BUILD_VALUE(real_shift(room, shift_dir[j][0], shift_dir[j][1])) = 0;
}
}
}
}
void display_statistics_to_char(Creature ch) {
extern int calculate_wealth(int e);
extern int top_of_p_table;
extern time_t boot_time;
Creature vict;
Object obj;
int e, i, j;
int best_empire = -1, wealthiest_empire = -1, famous_empire = -1;
bool found = 0;
char *tmstr;
time_t mytime;
int d, h, m;
if (!ch)
return;
msg_to_char(ch, "\r\nEmpireMUD Statistics:\r\n");
mytime = boot_time;
tmstr = (char *) asctime(localtime(&mytime));
*(tmstr + strlen(tmstr) - 1) = '\0';
mytime = time(0) - boot_time;
d = mytime / 86400;
h = (mytime / 3600) % 24;
m = (mytime / 60) % 60;
msg_to_char(ch, "Current uptime: Up since %s: %d day%s, %d:%02d\r\n", tmstr, d, ((d == 1) ? "" : "s"), h, m);
/* Find best scores.. */
for (e = 0; e <= top_of_empiret; e++) {
if (empire[e].imm_only)
continue;
if (empire[e].members > best_empire)
best_empire = empire[e].members;
if (calculate_wealth(e) > wealthiest_empire)
wealthiest_empire = calculate_wealth(e);
if (empire[e].fame > famous_empire)
famous_empire = empire[e].fame;
}
if (best_empire > 1) {
for (found = 0, e = 0; e <= top_of_empiret; e++)
if (empire[e].members >= best_empire && !empire[e].imm_only) {
msg_to_char(ch, "%s %s%s&0", found ? "," : "Most powerful empire:", empire[e].banner, empire[e].name);
found = 1;
}
msg_to_char(ch, "\r\n");
}
if (wealthiest_empire > 0) {
for (found = 0, e = 0; e <= top_of_empiret; e++)
if (calculate_wealth(e) >= wealthiest_empire && !empire[e].imm_only) {
msg_to_char(ch, "%s %s%s&0", found ? "," : "Most wealthy empire:", empire[e].banner, empire[e].name);
found = 1;
}
msg_to_char(ch, "\r\n");
}
if (famous_empire > 0) {
for (found = 0, e = 0; e <= top_of_empiret; e++)
if (empire[e].fame >= famous_empire && !empire[e].imm_only) {
msg_to_char(ch, "%s %s%s&0", found ? "," : "Most famous empire:", empire[e].banner, empire[e].name);
found = 1;
}
msg_to_char(ch, "\r\n");
}
for (e = 0, i = 0, j = 0; e <= top_of_empiret; e++) {
i += empire[e].territory;
j += empire[e].members;
}
msg_to_char(ch, "Total Empires: %3d Claimed Area: %d\r\n", top_of_empiret + 1, i);
msg_to_char(ch, "Total Players: %5d Players in Empires: %d\r\n", top_of_p_table + 1, j);
for (vict = character_list, i = 0; vict; vict = vict->next)
if (IS_NPC(vict))
i++;
msg_to_char(ch, "Unique Creatures: %3d Total Mobs: %d\r\n", top_of_mobt + 1, i);
for (obj = object_list, i = 0; obj; obj = obj->next)
i++;
msg_to_char(ch, "Unique Objects: %3d Total Objects: %d\r\n", top_of_objt + 1, i);
}
/* Count total bits in a bitvector_t */
int count_bits(bitvector_t bits) {
bitvector_t b = bits, count = 0;
for (; b; b >>= 1)
if (IS_SET(b, 1))
count++;
return count;
}
/* Finds total number of mobs in the game */
int total_mobs(void) {
int count, i;
for (i = 0, count = 0; i <= top_of_mobt; i++)
count += mob_index[i].number;
return count;
}
/* find out if a person has resources available */
bool has_resources(Creature ch, Resource list[], bool ground) {
Object obj;
int i, total = 0;
bool skin = FALSE;
for (i = 0; list[i].vnum != -1; i++, skin = FALSE, total = 0) {
if (list[i].vnum == o_SKIN)
skin = TRUE;
for (obj = ch->carrying; obj; obj = obj->next_content)
if (GET_OBJ_VNUM(obj) == list[i].vnum) {
if (skin)
total += GET_OBJ_VAL(obj, 0);
else
total++;
}
if (ground)
for (obj = world[ch->in_room].contents; obj; obj = obj->next_content)
if (GET_OBJ_VNUM(obj) == list[i].vnum) {
if (skin)
total += GET_OBJ_VAL(obj, 0);
else
total++;
}
if (total < list[i].amount) {
msg_to_char(ch, "You need %d more of: %s\r\n", list[i].amount - total, GET_OBJ_NAME_BY_PROTO(real_object(list[i].vnum)));
return 0;
}
}
return 1;
}
/* extract resources from the list, hopefully having checked has_resources */
void extract_resources(Creature ch, Resource list[], bool ground) {
Object obj, next_obj;
int i, remaining;
bool skin = FALSE;
for (i = 0; list[i].vnum != -1; i++, skin = FALSE) {
if (list[i].vnum == o_SKIN)
skin = TRUE;
remaining = list[i].amount;
for (obj = ch->carrying; obj && remaining > 0; obj = next_obj) {
next_obj = obj->next_content;
if (GET_OBJ_VNUM(obj) == list[i].vnum) {
if (skin)
remaining -= GET_OBJ_VAL(obj, 0);
else
remaining--;
extract_obj(obj);
}
}
if (ground)
for (obj = world[ch->in_room].contents; obj && remaining > 0; obj = next_obj) {
next_obj = obj->next_content;
if (GET_OBJ_VNUM(obj) == list[i].vnum) {
if (skin)
remaining -= GET_OBJ_VAL(obj, 0);
else
remaining--;
extract_obj(obj);
}
}
}
}
/* give resources from a resource list */
void give_resources(Creature ch, Resource list[], bool split) {
Object obj;
int i, j, remaining;
for (i = 0; list[i].vnum != -1; i++) {
remaining = list[i].amount;
if (list[i].vnum == o_SKIN) {
obj_to_char((obj = read_object(o_SKIN, VIRTUAL)), ch);
GET_OBJ_VAL(obj, 0) = remaining;
continue;
}
if (split)
remaining /= 2;
for (j = 0; j < remaining; j++) {
obj = read_object(list[i].vnum, VIRTUAL);
if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch) || GET_OBJ_WEIGHT(obj) + IS_CARRYING_W(ch) > CAN_CARRY_W(ch))
obj_to_room(obj, ch->in_room);
else
obj_to_char(obj, ch);
}
}
}
/* finds the amount of a certain resource in a list */
int get_amount_of_resource(Resource list[], obj_vnum vnum) {
int i;
for (i = 0; list[i].vnum != -1; i++)
if (list[i].vnum == vnum)
return list[i].amount;
return 0;
}
/* gets the total amount of resources (used for timers */
int get_total_resources(Resource list[]) {
int i, total = 0;
for (i = 0; list[i].vnum != -1; i++)
total += list[i].amount;
return total;
}