/* ************************************************************************
* File: comm.c Part of CircleMUD *
* Usage: Communication, socket handling, main(), central game loop *
* *
* All rights reserved. See license.doc for complete information. *
* *
* Copyright (C) 1993 by the Trustees of the Johns Hopkins University *
* CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. *
************************************************************************ */
/* Archipelago changes by Alastair J. Neil Copyright (C) 1993, 94, 95, 96 */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <netinet/in.h>
#include <unistd.h>
#include <netdb.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#include "structs.h"
#include "utils.h"
#include "comm.h"
#include "interpreter.h"
#include "handler.h"
#include "db.h"
#include "limits.h"
#include "screen.h"
#include "spells.h"
#define MAX_HOSTNAME 256
#define OPT_USEC 250000 /* time delay corresponding to 4 passes/sec */
/* externs */
extern int restrict;
extern int mini_mud;
extern int no_rent_check;
extern FILE *player_fl;
extern int DFLT_PORT;
extern char *DFLT_DIR;
extern int MAX_PLAYERS;
extern int MAX_DESCRIPTORS_AVAILABLE;
extern struct index_data *mob_index;
extern char *revdirs[];
extern char *dirs[];
extern struct room_data *world;
extern int top_of_world;
extern struct time_info_data time_info;
extern char help[];
extern int slave_socket;
extern pid_t slave_pid;
struct spell_info_type spell_info[MAX_SPL_LIST];
/* local globals */
struct descriptor_data *descriptor_list, *next_to_process;
struct txt_block *bufpool = 0; /* pool of large output buffers */
int buf_largecount; /* # of large buffers which exist */
int buf_overflows; /* # of overflows of output */
int buf_switches; /* # of switches from small to large buf */
int circle_shutdown = 0; /* clean shutdown*/
int circle_reboot = 0; /* reboot the game after a shutdown */
int no_specials = 0; /* Suppress ass. of special routines */
int no_limited_check = 0; /* Suppress ass. of special routines */
int last_desc = 0; /* last unique num assigned to a desc. */
int mother_desc = 0; /* file desc of the mother connection */
int maxdesc; /* highest desc num used */
int avail_descs; /* max descriptors available */
int tics = 0; /* for extern checkpointing */
int pulse =0; /* for fine grained event management */
int port;
extern int nameserver_is_slow; /* see config.c */
extern int auto_save; /* see config.c */
extern int autosave_time; /* see config.c */
struct event_type *events[301];
/* functions in this file */
void parse_prompt(struct char_data *ch, char *pmt);
void parse_text(struct char_data *c,struct char_data *vict, int mode, char *pmt);
int get_from_q(struct txt_q *queue, char *dest);
void run_the_game(int port);
void game_loop(int s);
int init_socket(int port);
int new_connection(int s);
int new_descriptor(int s);
int process_output(struct descriptor_data *t);
int process_input(struct descriptor_data *t);
void close_sockets(int s);
void close_socket(struct descriptor_data *d);
struct timeval timediff(struct timeval *a, struct timeval *b);
void flush_queues(struct descriptor_data *d);
void nonblock(int s);
int perform_subst(struct descriptor_data *t, char *orig, char *subst);
void cmpact(char *input);
void extract_event(struct char_data *ch);
void add_event(int plse, int event, int inf1, int inf2, int inf3
, int inf4, char *arg, void *subj, void *vict);
void process_events(int pulse);
static int get_slave_result(void);
/* extern fcnts */
char *pluralise_string(char *arg);
void boot_db(void);
void zone_update(void);
void affect_update(void); /* In spells.c */
void point_update(void); /* In limits.c */
void mobile_activity(void);
void room_activity(void);
void string_add(struct descriptor_data *d, char *str);
void perform_violence(void);
void show_string(struct descriptor_data *d, char *input);
void check_reboot(void);
int isbanned(char *hostname);
void weather_and_time(int mode);
void shopedit(struct descriptor_data *d, char *str);
void roomedit(struct descriptor_data *d, char *str);
void mobedit(struct descriptor_data *d, char *str);
void objedit(struct descriptor_data *d, char *str);
void assign_levels();
char *report_cost(int gold);
void death_cry(struct char_data *ch);
int spell_lev(struct char_data *caster, int spell);
char *first_name(char *buf);
int is_goditem(struct obj_data *j);
void clear_queue(struct txt_q *queue);
/* *********************************************************************
* main game loop and related stuff *
********************************************************************* */
int main(int argc, char **argv)
{
char buf[512];
int pos = 1;
char *dir;
port = DFLT_PORT;
dir = DFLT_DIR;
if (strstr(argv[0], "test")){
no_limited_check = 1;
logg("Suppressing check of limited equipment.");
}
while ((pos < argc) && (*(argv[pos]) == '-')) {
switch (*(argv[pos] + 1)){
case 'd':
if (*(argv[pos] + 2))
dir = argv[pos] + 2;
else if (++pos < argc)
dir = argv[pos];
else {
logg("Directory arg expected after option -d.");
exit(0);
}
break;
case 'm':
mini_mud = 1;
no_rent_check = 1;
logg("Running in minimized mode & with no rent check.");
break;
case 'q':
no_rent_check = 1;
logg("Quick boot mode -- rent check suppressed.");
break;
case 'r':
restrict = 1;
logg("Restricting game -- no new players allowed.");
break;
case 's':
no_specials = 1;
logg("Suppressing assignment of special routines.");
break;
default:
sprintf(buf, "SYSERR: Unknown option -%c in argument string.", *(argv[pos] + 1));
logg(buf);
break;
}
pos++;
}
if (pos < argc)
if (!isdigit(*argv[pos])) {
fprintf(stderr, "Usage: %s [-m] [-q] [-r] [-s] [-d pathname] [ port # ]\n", argv[0]);
exit(0);
}
if (argv[pos])
port = atoi(argv[pos]);
assign_levels();
sprintf(buf, "loading levels table");
logg(buf);
sprintf(buf, "Running game on port %d.", port);
logg(buf);
if (chdir(dir) < 0) {
perror("Fatal error changing to data directory");
exit(0);
}
sprintf(buf, "Using %s as data directory.", dir);
logg(buf);
srandom(time(0));
run_the_game(port);
return(0);
}
/* Init sockets, run game, and cleanup sockets */
void run_the_game(int port)
{
int s;
void signal_setup(void);
descriptor_list = NULL;
logg("Signal trapping.");
signal_setup();
logg("Opening mother connection.");
mother_desc = s = init_socket(port);
boot_db();
logg("Entering game loop.");
game_loop(s);
close_sockets(s);
fclose(player_fl);
if (circle_reboot) {
logg("Rebooting.");
exit(52); /* what's so great about HHGTTG, anyhow? */
}
logg("Normal termination of game.");
}
/* Accept new connects, relay commands, and call 'heartbeat-functs' */
void game_loop(int s)
{
fd_set input_set, output_set, exc_set;
struct timeval last_time, now, timespent, timeout, null_time;
static struct timeval opt_time;
char comm[MAX_INPUT_LENGTH];
char prompt[MAX_INPUT_LENGTH];
struct descriptor_data *point, *next_point;
int mins_since_crashsave = 0, mask;
int i,sockets_connected, sockets_playing;
char buf[100];
null_time.tv_sec = 0;
null_time.tv_usec = 0;
opt_time.tv_usec = OPT_USEC; /* Init time values */
opt_time.tv_sec = 0;
gettimeofday(&last_time, (struct timezone *) 0);
maxdesc = s;
#if defined (OPEN_MAX)
avail_descs = OPEN_MAX - 8;
#elif defined (USE_TABLE_SIZE)
{
int retval;
retval = setdtablesize(64);
if (retval == -1)
logg("SYSERR: unable to set table size");
else {
sprintf(buf, "%s %d\n", "dtablesize set to: ", retval);
logg(buf);
}
avail_descs = getdtablesize() - 8;
}
#else
avail_descs = MAX_DESCRIPTORS_AVAILABLE;
#endif
avail_descs = MIN(avail_descs, MAX_PLAYERS);
mask = sigmask(SIGUSR1) | sigmask(SIGUSR2) | sigmask(SIGINT) |
sigmask(SIGPIPE) | sigmask(SIGALRM) | sigmask(SIGTERM) |
sigmask(SIGURG) | sigmask(SIGXCPU) | sigmask(SIGHUP) |
sigmask(SIGSEGV) | sigmask(SIGBUS);
for (i=0;i<=300;i++)
events[i] = 0;
/* Main loop */
while (!circle_shutdown) {
/* Check what's happening out there */
FD_ZERO(&input_set);
FD_ZERO(&output_set);
FD_ZERO(&exc_set);
FD_SET(s, &input_set);
if (slave_socket != -1)
FD_SET(slave_socket, &input_set);
for (point = descriptor_list; point; point = point->next) {
FD_SET(point->descriptor, &input_set);
FD_SET(point->descriptor, &exc_set);
FD_SET(point->descriptor, &output_set);
}
/* check out the time */
gettimeofday(&now, (struct timezone *) 0);
timespent = timediff(&now, &last_time);
timeout = timediff(&opt_time, ×pent);
last_time.tv_sec = now.tv_sec + timeout.tv_sec;
last_time.tv_usec = now.tv_usec + timeout.tv_usec;
if (last_time.tv_usec >= 1000000) {
last_time.tv_usec -= 1000000;
last_time.tv_sec++;
}
sigsetmask(mask);
if (select(maxdesc + 1, &input_set, &output_set, &exc_set, &null_time)
< 0) {
perror("Select poll");
return;
}
if (select(0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &timeout) < 0) {
perror("Select sleep");
exit(1);
}
/* sigsetmask(0); changed AJN 28th Sept. 94 */
sigsetmask(sigmask(SIGPIPE));
/* Respond to whatver might be happening */
if (slave_socket != -1 && FD_ISSET( slave_socket, &input_set)) {
while (get_slave_result() == 0)
;
}
/* New connection? */
if (FD_ISSET(s, &input_set))
if (new_descriptor(s) < 0)
perror("New connection");
/* kick out the freaky folks */
for (point = descriptor_list; point; point = next_point) {
next_point = point->next;
if (FD_ISSET(point->descriptor, &exc_set)) {
FD_CLR(point->descriptor, &input_set);
FD_CLR(point->descriptor, &output_set);
close_socket(point);
}
}
for (point = descriptor_list; point; point = next_point) {
next_point = point->next;
if (FD_ISSET(point->descriptor, &input_set))
if (process_input(point) < 0)
close_socket(point);
}
/* process_commands; */
for (point = descriptor_list; point; point = next_to_process) {
next_to_process = point->next;
if ((--(point->wait) <= 0) && get_from_q(&point->input, comm)) {
if (point->character && point->connected == CON_PLYNG &&
point->character->specials.was_in_room != NOWHERE) {
if (point->character->in_room != NOWHERE)
char_from_room(point->character);
char_to_room(point->character,
point->character->specials.was_in_room, FALSE);
point->character->specials.was_in_room = NOWHERE;
act("$n has returned.", TRUE, point->character, 0, 0, TO_ROOM);
}
point->wait = 1;
if (point->character)
point->character->specials.timer = 0;
point->prompt_mode = 1;
if (point->str)
string_add(point, comm);
else if (point->mob_edit)
mobedit(point, comm);
else if (point->obj_edit)
objedit(point, comm);
else if (point->room_edit)
roomedit(point, comm);
else if (point->shop_edit)
shopedit(point, comm);
else if (point->zone_edit)
zoneedit(point, comm);
else if (!point->connected)
if (point->showstr_point)
show_string(point, comm);
else
command_interpreter(point->character, comm);
else
nanny(point, comm);
}
}
for (point = descriptor_list; point; point = next_point) {
next_point = point->next;
if (FD_ISSET(point->descriptor, &output_set) && *(point->output))
if (process_output(point) < 0)
close_socket(point);
else
point->prompt_mode = 1;
}
/* kick out the Phreaky Pholks II -JE */
for (point = descriptor_list; point; point = next_to_process) {
next_to_process = point->next;
if (STATE(point) == CON_CLOSE)
close_socket(point);
}
/* give the people some prompts */
for (point = descriptor_list; point; point = point->next){
if (point->prompt_mode) {
if (point->str) {
write_to_descriptor(point->descriptor, "] ");
}
else if (point->mob_edit
|| point->shop_edit
|| point->obj_edit
|| point->room_edit)
strcpy(prompt, "**Enter Q to quit**");
else if (!point->connected) {
if (point->showstr_point) {
strcpy(prompt, "[*** Press return to continue, q to quit ***]");
}
else {
parse_prompt(point->character, prompt);
}
write_to_descriptor(point->descriptor, prompt);
SET_BIT(PLR_FLAGS(point->character), PLR_NEEDCRLF);
}
point->prompt_mode = 0;
}
}
/* handle heartbeat stuff */
/* Note: pulse now changes every 1/4 sec */
process_events(pulse);
pulse++;
if (!(pulse % PULSE_ZONE)) zone_update();
if (!(pulse % (2*PULSE_VIOLENCE))) mobile_activity();
if (!(pulse % PULSE_ROOM)) room_activity();
if (!(pulse % PULSE_ROOM)) object_activity();
if (!(pulse % PULSE_VIOLENCE)) perform_violence();
if (!(pulse % (SECS_PER_MUD_HOUR * 4))) {
weather_and_time(1);
affect_update();
point_update();
fflush(player_fl);
}
if (auto_save)
if (!(pulse % (60 * 4))) /* one minute */
if (++mins_since_crashsave >= autosave_time) {
mins_since_crashsave = 0;
Crash_save_all();
}
if (time_info.hours && !((time_info.hours*SECS_PER_MUD_HOUR*4 + pulse) % 1200)) {
sockets_connected = sockets_playing = 0;
for (point = descriptor_list; point; point = next_point) {
next_point = point->next;
sockets_connected++;
if (!point->connected)
sockets_playing++;
}
sprintf(buf, "nusage: %-3d sockets connected, %-3d sockets playing",
sockets_connected,
sockets_playing);
logg(buf);
#ifdef RUSAGE
{
struct rusage rusagedata;
getrusage(0, &rusagedata);
sprintf(buf, "rusage: %d %d %d %d %d %d %d",
rusagedata.ru_utime.tv_sec,
rusagedata.ru_stime.tv_sec,
rusagedata.ru_maxrss,
rusagedata.ru_ixrss,
rusagedata.ru_ismrss,
rusagedata.ru_idrss,
rusagedata.ru_isrss);
logg(buf);
}
#endif
}
if (pulse >= 300) {
pulse = 0;
check_reboot();
}
tics++; /* tics since last checkpoint signal */
}
}
/* ******************************************************************
* general utility stuff (for local use) *
****************************************************************** */
void parse_prompt(struct char_data *ch, char *pmt)
{
static const char *default_prompt = "H: %1%h%0/%H V: %5%v%0/%V Ex: %X%n>";
char bff[512];
char bff2[512];
const char *string;
const char *i;
char *point;
int percent, slev;
if( ch->player.prmpt == NULL || ch->player.prmpt[0] == '\0' ) {
string = default_prompt;
}
else{
string = ch->player.prmpt;
}
bzero(bff,512);
bzero(bff2,512);
point = bff;
while( *string != '\0' )
{
if( *string != '%' )
{
*point++ = *string++;
continue;
}
++string;
switch( *string )
{
default:
i = " "; break;
case '0' :
sprintf(bff2,CCNRM(ch, C_NRM));
i = bff2; break;
case '1' :
sprintf(bff2,CCRED(ch, C_NRM));
i = bff2; break;
case '2' :
sprintf(bff2,CCGRN(ch, C_NRM));
i = bff2; break;
case '3' :
sprintf(bff2,CCYEL(ch, C_NRM));
i = bff2; break;
case '4' :
sprintf(bff2,CCBLU(ch, C_NRM));
i = bff2; break;
case '5' :
sprintf(bff2,CCMAG(ch, C_NRM));
i = bff2; break;
case '6' :
sprintf(bff2,CCCYN(ch, C_NRM));
i = bff2; break;
case '7' :
sprintf(bff2,CCWHT(ch, C_NRM));
i = bff2; break;
case '8' :
sprintf(bff2,CCBLK(ch, C_NRM));
i = bff2; break;
case 'b' :
sprintf(bff2,CCBLD(ch, C_NRM));
i = bff2; break;
case 'u' :
sprintf(bff2,CCUND(ch, C_NRM));
i = bff2; break;
case 'n':
sprintf(bff2,"\r\n");
i = bff2; break;
case 'i':
if (IS_AFFECTED(ch,AFF_INVISIBLE)){
sprintf(bff2,"*invis*");
i=bff2;break;}
else if (GET_INVIS_LEV(ch)){
sprintf(bff2,"<i%d>",GET_INVIS_LEV(ch));
i = bff2; break;}
*bff2 = '\0';
i = bff2;
break;
case 'f':
if (IS_AFFECTED(ch,AFF_FLY)){
sprintf(bff2,"*fly*");
i = bff2; break;}
break;
case 'w':
if (IS_AFFECTED(ch,AFF_WATER_BREATH)){
sprintf(bff2,"*water*");
i = bff2; break;}
break;
case 'h' :
sprintf( bff2, "%d", ch->points.hit );
i = bff2; break;
case 'H' :
sprintf( bff2, "%d", ch->points.max_hit );
i = bff2; break;
case 'm' :
break;
case 'M' :
break;
case 'p' :
break;
case 'P' :
break;
case 'v' :
sprintf( bff2, "%d", ch->points.move );
i = bff2; break;
case 'V' :
sprintf( bff2, "%d", ch->points.max_move );
i = bff2; break;
case 'x' :
sprintf( bff2, "%d", ch->points.exp );
i = bff2; break;
case 'X' :
slev = (levels_table[GET_LEVEL(ch)+1]
- levels_table[GET_LEVEL(ch)])/10;
sprintf( bff2, "%d",levels_table[GET_LEVEL(ch)] +
slev*(GET_SUB_LEVEL(ch) +1)
- GET_EXP(ch) );
i = bff2; break;
case 'l':
if(ch->master && !IS_NPC(ch))
sprintf( bff2, "%s",GET_NAME(ch->master));
else if (ch->master && !IS_NPC(ch))
sprintf( bff2, "%s",PERS(ch->master, ch));
else
sprintf( bff2,"%s", "nobody");
i = bff2; break;
case 'L':
if (ch->master)
sprintf( bff2, "%d",100*GET_HIT(ch->master)
/GET_MAX_HIT(ch->master));
else
sprintf( bff2, " ");
i = bff2; break;
case 'o' :
if (ch->specials.fighting)
sprintf( bff2,"%s",PERS(ch->specials.fighting, ch));
else
sprintf( bff2,"%s","nobody");
i = bff2; break;
case 'O':
if (ch->specials.fighting){
if (GET_MAX_HIT(ch->specials.fighting) >0)
percent = (100 * GET_HIT(ch->specials.fighting)/
GET_MAX_HIT(ch->specials.fighting));
else
percent = -1;
if (percent >= 100)
sprintf(bff2,"%s","unhurt");
else if (percent >= 90)
sprintf(bff2,"%s","a few scratches");
else if (percent >= 75)
sprintf(bff2,"%s","small wounds");
else if (percent >= 50)
sprintf(bff2,"%s","quite a few wounds");
else if (percent >= 30)
sprintf(bff2,"%s","big nasty wounds");
else if (percent >= 15)
sprintf(bff2,"%s","pretty hurt");
else if (percent >= 0)
sprintf(bff2,"%s","awful");
else
sprintf(bff2,"%s","unconscious"); }
else
sprintf(bff2,"%s"," ");
i = bff2; break;
case 'g' :
sprintf( bff2, "%s",report_cost(ch->points.gold) );
i = bff2; break;
case 'G' :
sprintf( bff2, "%s",report_cost(GET_BANK_GOLD(ch)));
i = bff2; break;
case 'a' :
if( ch->player.level < 5 )
sprintf( bff2, "%d", ch->specials2.alignment );
else
sprintf( bff2, "%s", IS_GOOD(ch) ? "good" : IS_EVIL(ch) ?
"evil" : "neutral" );
i = bff2; break;
case 'r' :
if( world[ch->in_room].name != NULL ){
if (IS_DARK(ch->in_room) &&
!PRF_FLAGGED(ch, PRF_HOLYLIGHT))
sprintf( bff2, "Pitch Black");
else
sprintf( bff2, "%s", world[ch->in_room].name );
}
else
sprintf( bff2, " " );
i = bff2; break;
case 'R' :
if( GET_LEVEL( ch ) >= LEVEL_BUILDER && world[ch->in_room].name != NULL )
sprintf( bff2, "%d", world[ch->in_room].number );
else
sprintf( bff2, " " );
i = bff2; break;
case '%' :
sprintf( bff2, "%%" );
i = bff2; break;
}
if (strlen(bff) + strlen(bff2) >= 510){
strcpy(pmt,bff);
return;}
++string;
while( (*point = *i) != '\0')
++point, ++i;
}
point = bff;
for ( ; *point != '\0'; point++ )
{
if ( *point == '~' )
*point = '-';
}
strcpy(pmt,bff);
return;
}
void parse_text(struct char_data *ch, struct char_data *vict, int mode,char *text)
{
char bff[1024];
char bff2[1024];
char bff4[1024];
char def[512];
char defi[512];
const char *string;
const char *i,*j;
char *point,*pmt;
bool start = TRUE, include = TRUE;
int len=0;
switch(mode){
case 0:
strcpy(defi,"%n the %R %l");
strcpy(def,"%n the %l %c");
if( ch->player.title == NULL || ch->player.title[0] == '\0')
if ( GET_LEVEL(ch) < LEVEL_BUILDER)
{
CREATE(GET_TITLE(ch), char, strlen(def) + 1);
strcpy(GET_TITLE(ch), def);
}
else
{
CREATE(GET_TITLE(ch), char, strlen(defi) + 1);
strcpy(GET_TITLE(ch), defi);
}
string = ch->player.title;
break;
case 1:
strcpy(defi,"%n appears with an ear-splitting %bbang!%0");
if( ch->specials.poofIn == NULL || ch->specials.poofIn[0] == '\0')
{
CREATE(ch->specials.poofIn, char, strlen(defi) + 1);
strcpy(ch->specials.poofIn, defi);
}
string = ch->specials.poofIn;
break;
case 2:
strcpy(defi,"%n disappears in a puff of logic.");
if( ch->specials.poofOut == NULL || ch->specials.poofOut[0] == '\0')
{
CREATE(ch->specials.poofOut, char, strlen(defi) + 1);
strcpy(ch->specials.poofOut, defi);
}
string = ch->specials.poofOut;
break;
}
bzero(bff,1024);
bzero(bff2,1024);
point = bff;
pmt = bff4;
while( *string != '\0' )
{
if( *string != '%' )
{
*point++ = *string++;
len++;
continue;
}
while(*(++string) == '%')
;
include = TRUE;
switch( *string )
{
default:
i = " "; break;
case '0' :
sprintf(bff2,CCNRM(vict, C_NRM));
include = FALSE;
i = bff2; break;
case '1' :
sprintf(bff2,CCRED(vict, C_NRM));
include = FALSE;
i = bff2; break;
case '2' :
sprintf(bff2,CCGRN(vict, C_NRM));
include = FALSE;
i = bff2; break;
case '3' :
sprintf(bff2,CCYEL(vict, C_NRM));
include = FALSE;
i = bff2; break;
case '4' :
sprintf(bff2,CCBLU(vict, C_NRM));
include = FALSE;
i = bff2; break;
case '5' :
sprintf(bff2,CCMAG(vict, C_NRM));
include = FALSE;
i = bff2; break;
case '6' :
sprintf(bff2,CCCYN(vict, C_NRM));
include = FALSE;
i = bff2; break;
case '7' :
sprintf(bff2,CCWHT(vict, C_NRM));
include = FALSE;
i = bff2; break;
case '8' :
sprintf(bff2,CCBLK(vict, C_NRM));
include = FALSE;
i = bff2; break;
case 'b' :
sprintf(bff2,CCBLD(vict, C_NRM));
include = FALSE;
i = bff2; break;
case 'u' :
sprintf(bff2,CCUND(vict, C_NRM));
include = FALSE;
i = bff2; break;
case 'n':
if (GET_LEVEL(ch) < LEVEL_BUILDER)
sprintf(bff2,"%s",GET_NAME(ch));
else if (GET_INVIS_LEV(ch) > GET_LEVEL(vict))
{
for (j = bff;*j != '\0';j++)
if (*j != ' ')
start = FALSE;
sprintf(bff2,(start ? "Someone": "someone"));
}
else
sprintf(bff2,"%s",GET_NAME(ch));
i = bff2; break;
case 'o' :
if (ch->specials.fighting)
sprintf( bff2,"%s",PERS(ch->specials.fighting, ch));
else
sprintf( bff2,"%s","nobody");
i = bff2; break;
case 'r' :
if( world[ch->in_room].name != NULL ){
if (IS_DARK(ch->in_room) &&
!PRF_FLAGGED(ch, PRF_HOLYLIGHT))
sprintf( bff2, "Pitch Black");
else
sprintf( bff2, "%s", world[ch->in_room].name );
}
else
sprintf( bff2, " " );
i = bff2; break;
case 'l':
if (GET_LEVEL(ch) < 4)
sprintf( bff2, "newbie");
else if (GET_LEVEL(ch) < 20)
sprintf( bff2, "wily");
else if (GET_LEVEL(ch) < 50)
sprintf( bff2, "tough");
else if (GET_LEVEL(ch) < 100)
sprintf( bff2, "experienced");
else if (GET_LEVEL(ch) < 150)
sprintf( bff2, "hardened");
else if (GET_LEVEL(ch) < LEVEL_IMMORT)
sprintf( bff2, "veteran");
else if (GET_LEVEL(ch) >= LEVEL_IMPL)
sprintf( bff2, "%s","Implementor");
else if (GET_LEVEL(ch) >= LEVEL_ASS_IMPL)
sprintf( bff2, "%s","Overlord");
else if (GET_LEVEL(ch) >= LEVEL_GRGOD)
sprintf( bff2, "%s","Djinn");
else if (GET_LEVEL(ch) >= LEVEL_GOD)
sprintf( bff2, "%s","Daemon");
else if (GET_LEVEL(ch) >= LEVEL_MBUILDER)
sprintf( bff2, "%s","Bodhisattva");
else if (GET_LEVEL(ch) >= LEVEL_BUILDER)
sprintf( bff2, "%s","Builder");
else if (GET_LEVEL(ch) >= LEVEL_IMMORT)
sprintf( bff2, "%s","Avatar");
else
sprintf( bff2, "%s","bug");
i = bff2; break;
case 'c' :
switch(GET_RACE(ch)){
case 0:
sprintf( bff2, "%s", "error");
break;
case 1:
sprintf( bff2, "%s", "Human");
break;
case 2:
sprintf( bff2, "%s", "Elf");
break;
case 3:
sprintf( bff2, "%s", "Halfling");
break;
case 4:
sprintf( bff2, "%s", "Giant");
break;
case 5:
sprintf( bff2, "%s", "Gnome");
break;
case 6:
sprintf( bff2, "%s", "Half-elf");
break;
case 7:
sprintf( bff2, "%s", "Ogier");
break;
case 8:
sprintf( bff2, "%s", "Dwarf");
break;
case 9:
sprintf( bff2, "%s", "Selkie");
break;
case 10:
sprintf( bff2, "%s", "Pixie");
break;
case 11:
sprintf( bff2, "%s", "Amarya");
break;
case 12:
sprintf( bff2, "%s", "Troll");
break;
}
i = bff2; break;
case 'R' :
switch(GET_RACE(ch)){
case 0:
sprintf( bff2, "%s", "error");
break;
case 1:
sprintf( bff2, "%s", "Human");
break;
case 2:
sprintf( bff2, "%s", "Elven");
break;
case 3:
sprintf( bff2, "%s", "Halfling");
break;
case 4:
sprintf( bff2, "%s", "Gargantuan");
break;
case 5:
sprintf( bff2, "%s", "Gnomish");
break;
case 6:
sprintf( bff2, "%s", "Half-elven");
break;
case 7:
sprintf( bff2, "%s", "Ogier");
break;
case 8:
sprintf( bff2, "%s", "Dwarven");
break;
case 9:
sprintf( bff2, "%s", "Selkan");
break;
case 10:
sprintf( bff2, "%s", "Pixie");
break;
case 11:
sprintf( bff2, "%s", "Amaryan");
break;
case 12:
sprintf( bff2, "%s", "Trollan");
break;
}
i = bff2; break;
case '%' :
sprintf( bff2, "%%" );
i = bff2; break;
}
if (len + (include ? strlen(bff2) : 0) > 79){
sprintf(text,"%s%s",bff,CCNRM(vict, C_NRM));
return;
}
++string;
while( (*point = *i) != '\0'){
++point, ++i;
if (include)
++len;
}
}
point = bff;
for ( ; *point != '\0'; point++ )
{
if ( *point == '~' )
*point = '-';
}
sprintf(text,"%s%s",bff,CCNRM(vict, C_NRM));
}
int get_from_q(struct txt_q *queue, char *dest)
{
struct txt_block *tmp;
/* Q empty? */
if (!queue->head)
return(0);
tmp = queue->head;
strcpy(dest, queue->head->text);
queue->head = queue->head->next;
free(tmp->text);
free(tmp);
return(1);
}
void clear_queue(struct txt_q *queue)
{
struct txt_block *tmp, *tmp2;
for (tmp = queue->head; tmp; tmp = tmp2){
tmp2 = tmp->next;
free(tmp->text);
free(tmp);
}
}
void cmpact(char *input)
{
int count=0, size;
char j[24576],priv_buf[4096],*pp, *end;
if ((size = strlen(input)) < 80)
return; /* don't compact one liners */
*j = '\0';
end = input + strlen(input);
bzero(priv_buf,4096);
if (!(pp = (char *) strtok(input,"\n")))
return;
strcpy(priv_buf,pp);
while ((pp = strtok(0,"\n"))){
if (strcmp(priv_buf,pp) != 0)
{
if ((count > 0)){
if (!strcmp(priv_buf,"\r"))
while (1 + count--)
strcat(j,"\r\n");
else
sprintf(j,"%s(%i*)%s\n",j,++count,priv_buf);
strcpy(priv_buf,pp);
count=0;
}
else {
sprintf(j,"%s%s\n",j,priv_buf);
strcpy(priv_buf,pp);
count = 0;
}
}
else {
strcpy(priv_buf,pp);
count++;
}
}
sprintf(input,"%s", j);
if (count) {
if (!strcmp(priv_buf,"\r"))
while (1 + count--)
strcat(input,"\r\n");
else
sprintf(input,"%s(%i*)%s\n",input,++count,priv_buf);
}
else {
if (!strcmp(priv_buf,"\r"))
strcat(input,"\r\n");
else {
size = strlen(priv_buf);
if (*(priv_buf + size - 1 ) == '\r')
sprintf(input,"%s%s\n",input,priv_buf);
else
sprintf(input,"%s%s",input,priv_buf);
}
}
}
void write_to_output(char *txt, struct descriptor_data *t)
{
int size = 0;
if (!txt)
return;
size = strlen(txt);
if (t->character && PLR_FLAGGED(t->character, PLR_NEEDCRLF))
size += 2;
/* if we're in the overflow state already, ignore this */
if (t->bufptr < 0)
return;
/* if we have enough space, just write to buffer and that's it! */
if (t->bufspace >= size) {
if (t->character && PLR_FLAGGED(t->character, PLR_NEEDCRLF)){
sprintf(t->output+t->bufptr,"\r\n%s", txt);
}
else
strcpy(t->output+t->bufptr, txt);
t->bufspace -= size;
t->bufptr += size;
} else { /* otherwise, try to switch to a large buffer */
if (t->large_outbuf || ((size + strlen(t->output)) > LARGE_BUFSIZE)) {
/* we're already using large buffer, or even the large buffer
in't big enough -- switch to overflow state */
t->bufptr = -1;
buf_overflows++;
return;
}
buf_switches++;
/* if the pool has a buffer in it, grab it */
if (bufpool) {
t->large_outbuf = bufpool;
bufpool = bufpool->next;
} else { /* else create one */
CREATE(t->large_outbuf, struct txt_block, 1);
CREATE(t->large_outbuf->text, char, LARGE_BUFSIZE);
buf_largecount++;
}
strcpy(t->large_outbuf->text, t->output);
t->output = t->large_outbuf->text;
strcat(t->output, txt);
t->bufspace = LARGE_BUFSIZE-1 - strlen(t->output);
t->bufptr = strlen(t->output);
}
if (t->character && PLR_FLAGGED(t->character, PLR_NEEDCRLF))
REMOVE_BIT(PLR_FLAGS(t->character), PLR_NEEDCRLF);
}
void write_to_q(char *txt, struct txt_q *queue)
{
struct txt_block *new;
if (!txt)
return;
CREATE(new, struct txt_block, 1);
CREATE(new->text, char, strlen(txt) + 1);
strcpy(new->text, txt);
/* Q empty? */
if (!queue->head) {
new->next = NULL;
queue->head = queue->tail = new;
} else {
queue->tail->next = new;
queue->tail = new;
new->next = NULL;
}
}
struct timeval timediff(struct timeval *a, struct timeval *b)
{
struct timeval rslt, tmp;
tmp = *a;
if ((rslt.tv_usec = tmp.tv_usec - b->tv_usec) < 0) {
rslt.tv_usec += 1000000;
--(tmp.tv_sec);
}
if ((rslt.tv_sec = tmp.tv_sec - b->tv_sec) < 0) {
rslt.tv_usec = 0;
rslt.tv_sec = 0;
}
return(rslt);
}
/* Empty the queues before closing connection */
void flush_queues(struct descriptor_data *d)
{
if (d->large_outbuf) {
d->large_outbuf->next = bufpool;
bufpool = d->large_outbuf;
}
while (get_from_q(&d->input, buf2))
;
}
/* ******************************************************************
* socket handling *
****************************************************************** */
int init_socket(int port)
{
int s;
int opt = 1;
char hostname[MAX_HOSTNAME+1];
struct sockaddr_in sa;
struct hostent *hp;
bzero(&sa, sizeof(struct sockaddr_in ));
gethostname(hostname, MAX_HOSTNAME);
hp = gethostbyname(hostname);
if (hp == NULL) {
perror("gethostbyname");
exit(1);
}
sa.sin_family = hp->h_addrtype;
sa.sin_port = htons(port);
if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
perror("Init-socket");
exit(1);
}
if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof (opt)) < 0) {
perror ("setsockopt REUSEADDR");
exit (1);
}
#ifdef USE_LINGER
{
struct linger ld;
ld.l_onoff = 0;
ld.l_linger = 1000;
if (setsockopt(s, SOL_SOCKET, SO_LINGER, &ld, sizeof(ld)) < 0) {
perror("setsockopt LINGER");
exit(1);
}
}
#endif
if (bind(s, (struct sockaddr *) & sa, sizeof(sa)) < 0) {
perror("bind");
close(s);
exit(1);
}
listen(s, 5);
return(s);
}
int new_connection(int s)
{
struct sockaddr_in isa;
int i, t;
i = sizeof(isa);
getsockname(s, (struct sockaddr *) & isa, &i);
if ((t = accept(s, (struct sockaddr *)(&isa), &i)) < 0) {
perror("Accept");
return(-1);
}
nonblock(t);
return(t);
}
char *format_inet_addr( char *dest, long addr )
{
dest += sprintf( dest, "%ld.%ld.%ld.%ld",
(addr & 0xFF000000) >> 24,
(addr & 0x00FF0000) >> 16,
(addr & 0x0000FF00) >> 8,
(addr & 0x000000FF) );
return( dest );
}
int new_descriptor(int s)
{
int desc;
char *pbuf;
struct descriptor_data *newd, *point, *next_point;
int size, sockets_connected, sockets_playing, i;
struct sockaddr_in sock;
struct hostent *from, *p;
char buf[4097];
if ((desc = new_connection(s)) < 0)
return (-1);
sockets_connected = sockets_playing = 0;
for (point = descriptor_list; point; point = next_point) {
next_point = point->next;
sockets_connected++;
if (!point->connected)
sockets_playing++;
}
/* if ((maxdesc + 1) >= avail_descs)
if (sockets_connected >= avail_descs) {
write_to_descriptor(desc, "Sorry, Archipelago is full right now... try again later!\r\n");
close(desc);
return(0);
} else */
if (desc > maxdesc)
maxdesc = desc;
CREATE(newd, struct descriptor_data, 1);
/* find info */
size = sizeof(sock);
if (getpeername(desc, (struct sockaddr *) &sock, &size) < 0) {
perror("getpeername");
*newd->host = '\0';
}
else if (nameserver_is_slow ||!(from = gethostbyaddr((char *)&sock.sin_addr,
sizeof(sock.sin_addr), PF_INET))) {
if (!nameserver_is_slow)
perror("gethostbyaddr");
i = sock.sin_addr.s_addr;
sprintf(newd->host, "%d.%d.%d.%d", (i & 0x000000FF),
(i & 0x0000FF00) >> 8, (i & 0x00FF0000) >> 16,
(i & 0xFF000000) >> 24 );
}
else {
strncpy(newd->host, from->h_name, 49);
*(newd->host + 49) = '\0';
}
if (slave_socket != -1) {
buf[0] = 'i';
pbuf = format_inet_addr(buf+1, ntohl(sock.sin_addr.s_addr));
pbuf += sprintf(pbuf, ",%d,%d\n", ntohs(sock.sin_port), port);
if (write(slave_socket, buf, pbuf - buf + 1) != (pbuf - buf + 1)) {
logg("[SLAVE] loosing slave on write:");
close(slave_socket);
slave_socket = -1;
}
}
if (isbanned(newd->host) == BAN_ALL) {
close(desc);
/* sprintf(buf2, "Connection attempt denied from [%s]", newd->host);
mudlog(buf2, CMP, LEVEL_GOD, TRUE);*/
free(newd);
return(0);
}
/* Uncomment this if you want new connections logged. It's usually not
necessary, and just adds a lot of unnecessary bulk to the logs.
*/
newd->port = ntohs(sock.sin_port);
sprintf(buf2, "New connection from [%s], port: %d", newd->host,
newd->port);
mudlog(buf2, CMP, LEVEL_IMPL, TRUE);
/* logg(buf2);*/
/* init desc data */
newd->addr = ntohl(sock.sin_addr.s_addr);
newd->user_id[0] = '\0';
newd->descriptor = desc;
newd->connected = CON_QCOLOR;
newd->bad_pws = 0;
newd->pos = -1;
newd->wait = 1;
newd->color = TRUE;
newd->prompt_mode = 0;
*newd->buf = '\0';
newd->str = 0;
newd->replace = 0;
newd->with = 0;
newd->showstr_head = 0;
newd->showstr_point = 0;
*newd->last_input = '\0';
newd->output = newd->small_outbuf;
*(newd->output) = '\0';
newd->bufspace = SMALL_BUFSIZE-1;
newd->large_outbuf = NULL;
newd->input.head = NULL;
newd->next = descriptor_list;
newd->character = 0;
newd->original = 0;
newd->snoop.snooping = 0;
newd->snoop.snoop_by = 0;
newd->login_time = time(0);
if (++last_desc == 1000)
last_desc = 1;
newd->desc_num = last_desc;
newd->mob_edit = 0;
newd->medit_mode = 0;
newd->obj_edit = 0;
newd->oedit_mode = 0;
newd->room_edit = 0;
newd->redit_mode = 0;
newd->zone_edit = 0;
newd->zedit_mode = 0;
newd->shop_edit = 0;
newd->sedit_mode = 0;
/* prepend to list */
descriptor_list = newd;
SEND_TO_Q("***Colour [Y/n]? (default is yes)\r\n*Note colour is not recommended if your connection is slow/laggy*: ", newd);
return(0);
}
static int get_slave_result(void)
{
char *p, buf[4097], token[4096], os[4096], userid[4096];
int octet[4], local_port, remote_port, len;
struct descriptor_data *d;
long addr;
len = read(slave_socket, buf, 4096);
if (len < 0) {
if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
return(-1);
logg("[SLAVE] loosing slave on read");
close(slave_socket);
slave_socket = -1;
return(-1);
}
else if (len==0)
return(-1);
buf[len] = 0;
if (sscanf(buf + 1, "%d.%d.%d.%d %d , %d : %[^: ] : %[^: ] : %s",
&octet[0], &octet[1], &octet[2], &octet[3],
&remote_port, &local_port, token, os, userid) != 9) {
if((sscanf(buf + 1, "%d.%d.%d.%d %d , %d : %[^: ] : %s",
&octet[0], &octet[1], &octet[2], &octet[3],
&remote_port, &local_port, token, userid) != 8) ||
strncmp(token, "ERROR", 5)) {
logg("[SLAVE] invalid");
}
return(0);
}
if (local_port != port) {
logg ("[SLAVE] local port != game port");
return(0);
}
addr = (octet[0] << 24) + (octet[1] << 16) + (octet[2] << 8) + octet[3];
for (d = descriptor_list; d; d = d->next) {
if (d->port != remote_port ) continue;
if (d->addr != addr) continue;
strncpy(d->user_id, userid, (MAX_USER_ID - 1));
d->user_id[MAX_USER_ID-1] = '\0';
return(0);
}
}
int process_output(struct descriptor_data *t)
{
static char i[LARGE_BUFSIZE + 20];
/* start writing at the 2nd space so we can prepend "% " for snoop */
if (t->character &&
!t->connected &&
!(!IS_NPC(t->character) &&
(PRF_FLAGGED(t->character, PRF_COMPACT)))){
strcpy(i+2, "\r\n");
strcpy(i+2, t->output);}
else
strcpy(i+2, t->output);
if (t->bufptr < 0)
strcat(i+2, "**OVERFLOW**");
if (t->character &&
!t->connected &&
!(!IS_NPC(t->character) &&
(PRF_FLAGGED(t->character, PRF_COMPACT))))
strcat(i+2, "\r\n");
if (write_to_descriptor(t->descriptor, i+2) < 0)
return -1;
if (t->snoop.snoop_by) {
i[0] = '%';
i[1] = ' ';
SEND_TO_Q(i, t->snoop.snoop_by->desc);
}
/* if we were using a large buffer, put the large buffer on the buffer
pool and switch back to the small one */
if (t->large_outbuf) {
t->large_outbuf->next = bufpool;
bufpool = t->large_outbuf;
t->large_outbuf = NULL;
t->output = t->small_outbuf;
}
/* reset total bufspace back to that of a small buffer */
t->bufspace = SMALL_BUFSIZE-1;
t->bufptr = 0;
*(t->output) = '\0';
return 1;
}
int write_to_descriptor(int desc, char *txt)
{
int sofar, thisround, total;
if (!txt)
return(0);
cmpact(txt);
total = strlen(txt);
sofar = 0;
do {
thisround = write(desc, txt + sofar, total - sofar);
if (thisround < 0) {
perror("Write to socket");
return(-1);
}
sofar += thisround;
} while (sofar < total);
return(0);
}
int process_input(struct descriptor_data *t)
{
int sofar, thisround, begin, squelch, i, k, flag, failed_subst = 0;
char tmp[MAX_INPUT_LENGTH+2], buffer[MAX_INPUT_LENGTH + 60];
sofar = 0;
flag = 0;
begin = strlen(t->buf);
/* Read in some stuff */
do {
if ((thisround = read(t->descriptor, t->buf + begin + sofar,
MAX_STRING_LENGTH - (begin + sofar) - 1)) > 0)
sofar += thisround;
else if (thisround < 0)
if (errno != EWOULDBLOCK) {
perror("Read1 - ERROR");
return(-1);
}
else
break;
else {
logg("EOF encountered on socket read.");
return(-1);
}
} while (!ISNEWL(*(t->buf + begin + sofar - 1)));
*(t->buf + begin + sofar) = 0;
/* if no newline is contained in input, return without proc'ing */
for (i = begin; !ISNEWL(*(t->buf + i)); i++)
if (!*(t->buf + i))
return(0);
/* input contains 1 or more newlines; process the stuff */
for (i = 0, k = 0; *(t->buf + i); ) {
if (!ISNEWL(*(t->buf + i)) && !(flag = (k >= (MAX_INPUT_LENGTH - 2))))
if (*(t->buf + i) == '\b') /* backspace */
if (k) { /* more than one char ? */
if (*(tmp + --k) == '$')
k--;
i++;
}
else
i++; /* no or just one char.. Skip backsp */
else if (isascii(*(t->buf + i)) && isprint(*(t->buf + i))) {
/* trans char, double for '$' (printf) */
if ((*(tmp + k) = *(t->buf + i)) == '$' && !t->str)
*(tmp + ++k) = '$';
k++;
i++;
}
else
i++;
else {
*(tmp + k) = 0;
if (*tmp == '!')
strcpy(tmp, t->last_input);
else if (*tmp == '^') {
if (!(failed_subst = perform_subst(t, t->last_input, tmp)))
strcpy(t->last_input, tmp);
} else
strcpy(t->last_input, tmp);
if (!failed_subst)
{
if (!strncmp(tmp, "abort",5) || !strncmp(tmp, "flee",4))
while(get_from_q(&t->input, buf2))
;
write_to_q(tmp, &t->input);
}
if (t->snoop.snoop_by) {
SEND_TO_Q("% ", t->snoop.snoop_by->desc);
SEND_TO_Q(tmp, t->snoop.snoop_by->desc);
SEND_TO_Q("\r\n", t->snoop.snoop_by->desc);
}
if (flag) {
sprintf(buffer, "Line too long. Truncated to:\r\n%s\r\n", tmp);
if (write_to_descriptor(t->descriptor, buffer) < 0)
return(-1);
/* skip the rest of the line */
for (; !ISNEWL(*(t->buf + i)); i++)
;
}
/* find end of entry */
for (; ISNEWL(*(t->buf + i)); i++)
;
/* squelch the entry from the buffer */
for (squelch = 0; ; squelch++)
if ((*(t->buf + squelch) = *(t->buf + i + squelch)) == '\0')
break;
k = 0;
i = 0;
}
}
return(1);
}
int perform_subst(struct descriptor_data *t, char *orig, char *subst)
{
char new[MAX_INPUT_LENGTH+5];
char *first, *second, *strpos;
first = subst+1;
if (!(second = strchr(first, '^'))) {
SEND_TO_Q("Invalid substitution.\r\n", t);
return 1;
}
*(second++) = '\0';
if (!(strpos = strstr(orig, first))) {
SEND_TO_Q("Invalid substitution.\r\n", t);
return 1;
}
strncpy(new, orig, (strpos-orig));
new[(strpos-orig)] = '\0';
strcat(new, second);
if (((strpos-orig) + strlen(first)) < strlen(orig))
strcat(new, strpos+strlen(first));
strcpy(subst, new);
return 0;
}
void close_sockets(int s)
{
logg("Killing Slave");
if (slave_socket != -1)
kill( slave_pid, SIGKILL);
logg("Closing all sockets.");
while (descriptor_list)
close_socket(descriptor_list);
close(s);
}
void close_socket(struct descriptor_data *d)
{
struct descriptor_data *tmp;
char buf[100];
close(d->descriptor);
flush_queues(d);
if (d->descriptor == maxdesc)
--maxdesc;
/* Forget snooping */
if (d->snoop.snooping)
d->snoop.snooping->desc->snoop.snoop_by = 0;
if (d->snoop.snoop_by) {
send_to_char("Your victim is no longer among us.\r\n", d->snoop.snoop_by);
d->snoop.snoop_by->desc->snoop.snooping = 0;
}
if (d->character)
if (d->connected == CON_PLYNG) {
save_char(d->character, NOWHERE);
act("$n has lost $s link.", TRUE, d->character, 0, 0, TO_ROOM);
sprintf(buf, "Closing link to: %s.", GET_NAME(d->character));
mudlog(buf, NRM, MAX(LEVEL_BUILDER, GET_INVIS_LEV(d->character)), TRUE);
d->character->desc = 0;
}
else {
sprintf(buf, "Losing player: %s.", GET_NAME(d->character));
mudlog(buf, CMP, MAX(LEVEL_BUILDER, GET_INVIS_LEV(d->character)), TRUE);
free_char(d->character);
}
else
mudlog("Losing descriptor without char.", CMP, LEVEL_BUILDER, TRUE);
if (next_to_process == d) /* to avoid crashing the process loop */
next_to_process = next_to_process->next;
if (d == descriptor_list) /* this is the head of the list */
descriptor_list = descriptor_list->next;
else { /* This is somewhere inside the list */
/* Locate the previous element */
for (tmp = descriptor_list; (tmp->next != d) && tmp; tmp = tmp->next)
;
tmp->next = d->next;
}
if (d->showstr_head)
free(d->showstr_head);
if (d->name)
free(d->name);
if (d->replace)
free(d->replace);
if (d->with)
free(d->with);
free(d);
}
#if defined(SVR4) || defined(LINUX)
void nonblock(int s)
{
int flags;
flags = fcntl(s, F_GETFL);
flags |= O_NONBLOCK;
if (fcntl(s, F_SETFL, flags) < 0) {
perror("Fatal error executing nonblock (comm.c)");
exit(1);
}
}
#else
void nonblock(int s)
{
if (fcntl(s, F_SETFL, FNDELAY) == -1) {
perror("Fatal error executing nonblock (comm.c)");
exit(1);
}
}
#endif
/* ****************************************************************
* Public routines for system-to-player-communication *
*******************************************************************/
void send_to_char(char *messg, struct char_data *ch)
{
if (ch->desc && messg)
SEND_TO_Q(messg, ch->desc);
}
void send_to_all(char *messg)
{
struct descriptor_data *i;
if (messg)
for (i = descriptor_list; i; i = i->next)
if (!i->connected)
SEND_TO_Q(messg, i);
}
void send_to_outdoor(char *messg)
{
struct descriptor_data *i;
if (messg)
for (i = descriptor_list; i; i = i->next)
if (!i->connected)
if (OUTSIDE(i->character) &&
(world[i->character->in_room].sector_type != SECT_UNDER_WATER)
&& !PLR_FLAGGED(i->character, PLR_WRITING) &&
!PLR_FLAGGED(i->character, PLR_BUILDING) && AWAKE(i->character))
SEND_TO_Q(messg, i);
}
void send_to_except(char *messg, struct char_data *ch)
{
struct descriptor_data *i;
if (messg)
for (i = descriptor_list; i; i = i->next)
if (ch->desc != i && !i->connected
&& !PLR_FLAGGED(i->character, PLR_WRITING) &&
!PLR_FLAGGED(i->character, PLR_BUILDING))
SEND_TO_Q(messg, i);
}
void send_to_room(char *messg, int room, bool virtual)
{
struct char_data *i;
if (virtual)
room = real_room(room);
if (messg)
for (i = world[room].people; i; i = i->next_in_room)
if (i->desc && !PLR_FLAGGED(i, PLR_WRITING) &&
!PLR_FLAGGED(i, PLR_BUILDING))
SEND_TO_Q(messg, i->desc);
}
void send_to_room_except(char *messg, int room, struct char_data *ch, bool virtual)
{
struct char_data *i;
if (virtual)
room = real_room(room);
if (messg)
for (i = world[room].people; i; i = i->next_in_room)
if (i != ch && i->desc && !PLR_FLAGGED(i, PLR_WRITING) &&
!PLR_FLAGGED(i, PLR_BUILDING))
SEND_TO_Q(messg, i->desc);
}
void send_to_room_except_two
(char *messg, int room, struct char_data *ch1, struct char_data *ch2, bool virtual)
{
struct char_data *i;
if (virtual)
room = real_room(room);
if (messg)
for (i = world[room].people; i; i = i->next_in_room)
if (i != ch1 && i != ch2 && i->desc
&& !PLR_FLAGGED(i, PLR_WRITING) &&
!PLR_FLAGGED(i, PLR_BUILDING))
SEND_TO_Q(messg, i->desc);
}
/* higher-level communication */
void act(char *str, int hide_invisible, struct char_data *ch,
struct obj_data *obj, void *vict_obj, int type)
{
register char *strp, *point, *i;
struct char_data *to, *ignore=0;
static char buf[MAX_STRING_LENGTH];
if (!str || !*str)
return;
if (!ch && !obj && !vict_obj)
return;
if (type == TO_VICT)
to = (struct char_data *) vict_obj;
else if (type == TO_CHAR)
to = ch;
else if (type == TO_ROOM){
if (ch){
if (ch->in_room >= 0)
to = world[ch->in_room].people;
else
return;
}
else if (obj){
if (obj->in_room >=0)
to = world[obj->in_room].people;
else if (obj->worn_by)
to = world[obj->worn_by->in_room].people;
else if (obj->carried_by)
to = world[obj->carried_by->in_room].people;
else
return;
}
}
if (vict_obj && type == TO_NOTVICT){
ignore = (struct char_data *) vict_obj;
if (ignore->in_room >= 0)
to = world[ignore->in_room].people;
else
return;
}
if (ch && type == TO_NOTCHAR){
to = world[ch->in_room].people;
ignore = ch;
}
if (!to)
return;
for (; to; to = to->next_in_room) {
if (to && to->desc && ((to != ch) || (type == TO_CHAR)) &&
((ch && CAN_SEE(to, ch)) || !hide_invisible || (type == TO_VICT)) &&
AWAKE(to) && !PLR_FLAGGED(to, PLR_WRITING) &&
!PLR_FLAGGED(to, PLR_BUILDING) && !(to == ignore))
{
for (strp = str, point = buf; ; )
if (*strp == '$') {
switch (*(++strp)) {
case 'n':
i = PERS(ch, to);
break;
case 'N':
i = PERS((struct char_data *) vict_obj, to);
break;
case 'm':
i = HMHR(ch);
break;
case 'M':
i = HMHR((struct char_data *) vict_obj);
break;
case 's':
i = HSHR(ch);
break;
case 'S':
i = HSHR((struct char_data *) vict_obj);
break;
case 'e':
i = HSSH(ch);
break;
case 'E':
i = HSSH((struct char_data *) vict_obj);
break;
case 'o':
i = OBJN(obj, to);
break;
case 'O':
i = OBJN((struct obj_data *) vict_obj, to);
break;
case 'p':
i = OBJS(obj, to);
break;
case 'P':
i = OBJS((struct obj_data *) vict_obj, to);
break;
case 'a':
i = SANA(obj);
break;
case 'A':
i = SANA((struct obj_data *) vict_obj);
break;
case 'T':
i = (char *) vict_obj;
break;
case 'F':
i = fname((char *) vict_obj);
if (!(strcmp(i,"")))
strcpy(i,"hidden passage");
break;
case '$':
i = "$";
break;
default:
logg("SYSERR: Illegal $-code to act():");
strcpy(buf1, "SYSERR: ");
strcat(buf1, str);
logg(buf1);
break;
}
while ((*point = *(i++)))
++point;
++strp;
}
else if (!(*(point++) = *(strp++)))
break;
*(--point) = '\n';
*(++point) = '\r';
*(++point) = '\0';
SEND_TO_Q(CAP(buf), to->desc);
}
if ((type == TO_VICT) || (type == TO_CHAR))
return;
}
}
void process_events(int pulse)
{
ACMD(do_look);
ACMD(do_wear);
ACMD(do_get);
struct event_type *tmp,*tmp2;
struct char_data *subj, *vict, *next_vict;
struct obj_data *obj_vict, *obj_subj;
struct room_data *rm_subj;
int spl, to_room, n = 0;
struct follow_type *k;
char buf_loc[256];
tmp = events[pulse];
while (tmp)
{
switch(tmp->event){
case EVENT_IGNORE:
break;
case EVENT_REBOOT:
subj = (struct char_data *) tmp->subject;
tmp->info1--;
if (tmp->info1 < 1) {
if (tmp->info3 > 0) {
circle_shutdown = 1;
break;
}
else {
do_force(subj, "all save",0,0);
sprintf(buf,"\007\007(GC) Shutdown by %s, now.\r\n",
GET_NAME(subj),tmp->info1-1);
send_to_all(buf);
logg(buf);
if (tmp->info2 > 0)
send_to_all("Rebooting.. come back in a minute or two.\r\n");
add_event(1, EVENT_REBOOT, tmp->info1,tmp->info2,1,0,"",subj,0);
}
}
else {
sprintf(buf,"\007\007(GC) %s by %s, in %d %s.\r\n",
(tmp->info2 ? "Reboot" : "Shutdown"),
GET_NAME(subj),tmp->info1,
((tmp->info1 == 1) ? "minute" : "minutes"));
send_to_all(buf);
logg(buf);
add_event(250, EVENT_REBOOT, tmp->info1,tmp->info2,0,0,"",subj,0);
}
break;
case EVENT_ATTACK:
subj = (struct char_data *) tmp->subject;
vict = (struct char_data *) tmp->target;
if (CAN_SPEAK(subj) && (GET_INT(subj) < 15))
act("$n screams, '$N! I'm gonna kill you'",FALSE,subj,0,vict,TO_ROOM);
else if (CAN_SPEAK(subj) && (GET_INT(subj) >= 15))
act("$n says, '$N! Time to die!'",FALSE,subj,0,vict,TO_ROOM);
else if (!CAN_SPEAK(subj))
act("$n roars! and attacks $N!",FALSE,subj,0,vict, TO_NOTVICT);
if (vict->in_room == subj->in_room)
hit(subj, vict,0);
break;
case EVENT_OBJTIMER:
obj_subj = (struct obj_data *) tmp->subject;
subj = obj_subj->worn_by;
if (is_goditem(obj_subj))
break;
if (obj_subj->obj_flags2.aff_timer == 1){
if (subj){
affect_modify(subj, APPLY_NONE,0,
obj_subj->obj_flags2.bitvector_aff,
FALSE);
obj_subj->obj_flags2.bitvector_aff = 0;
SET_BIT(PLR_FLAGS(subj), PLR_CRASH);
}
else
obj_subj->obj_flags2.bitvector_aff = 0;
obj_subj->obj_flags2.aff_timer = 0;
if (obj_subj->obj_flags2.no_use_timer > 0)
obj_subj->obj_flags2.no_use_timer--;
}
else{
if (obj_subj->obj_flags2.aff_timer > 0)
obj_subj->obj_flags2.aff_timer--;
switch (GET_ITEM_TYPE(obj_subj))
{
case ITEM_WAND:
obj_subj->obj_flags2.no_use_timer -= 3;
break;
case ITEM_STAFF:
obj_subj->obj_flags2.no_use_timer -= 2;
break;
default:
obj_subj->obj_flags2.no_use_timer--;
break;
}
obj_subj->obj_flags2.no_use_timer
=MAX(0,obj_subj->obj_flags2.no_use_timer);
}
if (obj_subj->obj_flags2.no_use_timer > 0)
if (GET_ITEM_TYPE(obj_subj) != ITEM_WAND &&
GET_ITEM_TYPE(obj_subj) != ITEM_STAFF )
add_event(-1,EVENT_OBJTIMER,0,0,0,0,0,obj_subj,0);
else
add_event(2,EVENT_OBJTIMER,0,0,0,0,0,obj_subj,0);
break;
case EVENT_LOOT:
subj = (struct char_data *) tmp->subject;
obj_vict = (struct obj_data *) tmp->target;
if (obj_vict && (GET_ITEM_TYPE(obj_vict) == ITEM_CONTAINER)
&& obj_vict->obj_flags.value[3] < 0
&& obj_vict->contains){
do_get(subj,"all corpse", 0,0);
if (GET_INT(subj) > 10)
do_wear(subj,"all",0,0);
}
break;
case EVENT_LEAVE:
if (!tmp->subject)
break;
subj = (struct char_data *) tmp->subject;
if (subj->specials.fighting)
break;
if (!IS_AFFECTED(subj, AFF_SNEAK) && !(subj->specials.mount)
&& !(subj->specials.rider) && !(subj->specials.carried_by)){
if (IS_CLIMB(subj,tmp->info1)
&& !IS_AFFECTED(subj,AFF_FLY))
{
sprintf(buf2, "$n starts to climb %s.", dirs[tmp->info1]);
act(buf2, TRUE, subj, 0, 0, TO_ROOM);
sprintf(buf2, "You start to climb.");
act(buf2, TRUE, subj, 0, 0, TO_CHAR);
}
else if (world[subj->in_room].sector_type
== SECT_UNDER_WATER
|| world[subj->in_room].sector_type
== SECT_WATER_SWIM
|| (world[subj->in_room].sector_type
== SECT_WATER_NOSWIM && !tmp->info2)) {
sprintf(buf2, "$n swims %s.",dirs[tmp->info1]);
act(buf2, TRUE, subj,0,0,TO_ROOM);
sprintf(buf2, "You swim %s.",dirs[tmp->info1]);
act(buf2, TRUE, subj,0,0,TO_CHAR);
}
else if (IS_AFFECTED(subj,AFF_FLY)) {
sprintf(buf2, "$n flies %s.",dirs[tmp->info1]);
act(buf2, TRUE, subj,0,0,TO_ROOM);
sprintf(buf2, "You fly %s.",dirs[tmp->info1]);
act(buf2, TRUE, subj,0,0,TO_CHAR);
}
else {
sprintf(buf2, "$n sets off %s.",dirs[tmp->info1]);
act(buf2, TRUE, subj,0,0,TO_ROOM);
sprintf(buf2, "You set off %s.",dirs[tmp->info1]);
act(buf2, TRUE, subj,0,0,TO_CHAR);
}
}
else if (subj->specials.mount)
{
if (world[subj->in_room].sector_type
== SECT_UNDER_WATER
|| world[subj->in_room].sector_type
== SECT_WATER_SWIM
|| (world[subj->in_room].sector_type
== SECT_WATER_NOSWIM && !tmp->info2)) {
sprintf(buf2, "$n swims %s on $N.",dirs[tmp->info1]);
act(buf2, TRUE, subj,0,subj->specials.mount,TO_ROOM);
sprintf(buf2, "You swim %s on $N.",dirs[tmp->info1]);
act(buf2, TRUE, subj,0,subj->specials.mount,TO_CHAR);
}
else if (IS_AFFECTED(subj->specials.mount,AFF_FLY)) {
sprintf(buf2, "$n flies %s on $N.",dirs[tmp->info1]);
act(buf2, TRUE, subj,0,subj->specials.mount,TO_ROOM);
sprintf(buf2, "You fly %s on $N.",dirs[tmp->info1]);
act(buf2, TRUE, subj,0,subj->specials.mount,TO_CHAR);
}
else {
sprintf(buf2, "$n rides off %s on $N.",dirs[tmp->info1]);
act(buf2, TRUE, subj,0,subj->specials.mount,TO_ROOM);
sprintf(buf2, "You ride off %s on $N.",dirs[tmp->info1]);
act(buf2, TRUE, subj,0,subj->specials.mount,TO_CHAR);
}
}
break;
case EVENT_CART_LEAVE:
if (!tmp->subject)
break;
obj_subj = (struct obj_data *) tmp->subject;
bzero(buf_loc,256);
for (k = obj_subj->pulled_by;k;k = k->next){
strcat(buf_loc,
first_name(k->follower->player.name ? k->follower->player.name :
k->follower->player.short_descr));
strcat(buf_loc, " ");
n++;}
if (n > 1)
sprintf(buf2,"The %s pull $p %s.",pluralise_string(buf_loc),dirs[tmp->info1]);
else{
half_chop(buf_loc,buf,buf1);
sprintf(buf2,"The %s pulls $p %s.",buf,dirs[tmp->info1]);}
act(buf2,TRUE,world[obj_subj->in_room].people,obj_subj,0,TO_ROOM);
act(buf2,TRUE,world[obj_subj->in_room].people,obj_subj,0,TO_CHAR);
to_room = -1;
if (GET_ITEM_TYPE(obj_subj) == ITEM_CONTAINER)
to_room = real_room(obj_subj->obj_flags.value[3]);
if (world[to_room].people)
if (!IS_SET(obj_subj->obj_flags.value[1],CONT_CLOSED)){
if (to_room > 0 && to_room <= top_of_world){
sprintf(buf1,"The %s moves off %s.",
first_name(obj_subj->name)
,dirs[tmp->info1]);
act(buf1,TRUE,world[to_room].people
,obj_subj,0
,TO_CHAR);
act(buf1,TRUE,world[to_room].people
,obj_subj,0
,TO_ROOM);
}
}
else if (to_room > 0 && to_room <= top_of_world){
sprintf(buf1,"The %s rattles and bumps about."
,first_name(obj_subj->name));
act(buf1,TRUE,world[to_room].people
,obj_subj,0
,TO_CHAR);
act(buf1,TRUE,world[to_room].people
,obj_subj,0
,TO_ROOM);
}
break;
case EVENT_CART_ARRIVE:
if (!tmp->subject)
break;
obj_subj = (struct obj_data *) tmp->subject;
if (!obj_subj->pulled_by)
break;
obj_from_room(obj_subj);
obj_to_room(obj_subj, tmp->info2, TRUE);
sprintf(buf2, "$p arrives from %s.",revdirs[tmp->info1]);
act(buf2,FALSE, 0,obj_subj,0,TO_ROOM);
break;
case EVENT_ARRIVE:
if (!tmp->subject)
break;
subj = (struct char_data *) tmp->subject;
if (subj->specials.fighting)
break;
if (subj->desc)
subj->desc->prompt_mode =1;
if (subj->specials.cart
&& (subj->specials.cart->in_room == subj->in_room)){
obj_from_room(subj->specials.cart);
obj_to_room(subj->specials.cart, tmp->info2, TRUE);
}
char_from_room(subj);
char_to_room(subj,tmp->info2, TRUE);
if (subj->specials.carrying){
char_from_room(subj->specials.carrying);
char_to_room(subj->specials.carrying,tmp->info2, TRUE);
}
if (!IS_AFFECTED(subj, AFF_SNEAK) && !subj->specials.mount
&& !subj->specials.rider && !subj->specials.carried_by) {
sprintf(buf2, "$n arrives from %s.",revdirs[tmp->info1]);
act(buf2, TRUE, subj,0,0,TO_ROOM);}
else if (subj->specials.mount) {
sprintf(buf2, "$n rides in from %s on $N.",revdirs[tmp->info1]);
act(buf2, TRUE, subj,0,subj->specials.mount,TO_ROOM);}
do_look(subj,"",0,0);
if (IS_SET(world[subj->in_room].room_flags, DEATH) &&
GET_LEVEL(subj) < LEVEL_BUILDER) {
log_death_trap(subj);
death_cry(subj);
extract_char(subj, TRUE);
break;
}
for (vict = world[subj->in_room].people;
vict;vict = vict->next_in_room){
if (IS_MOB(vict) && mob_index[vict->nr].func)
(*mob_index[vict->nr].func)(subj,vict,SPEC_ARRIVE,"");
}
break;
case EVENT_TELEPORT:
rm_subj = (struct room_data *) tmp->subject;
vict = (struct char_data *) tmp->target;
if (!(rm_subj) || !(vict)){
tmp->event = EVENT_IGNORE;
break;}
if (rm_subj->number != world[vict->in_room].number){
tmp->event = EVENT_IGNORE;
break;}
if (rm_subj->tele_mesg1)
act(rm_subj->tele_mesg1,FALSE,vict,0,0,TO_CHAR);
if (real_room(rm_subj->tele_to_room) != vict->in_room){
if (rm_subj->tele_mesg2)
act(rm_subj->tele_mesg2,FALSE,vict,0,0,TO_ROOM);
char_from_room(vict);
char_to_room(vict,rm_subj->tele_to_room, TRUE);
do_look(vict,"",0,0);
if (rm_subj->tele_mesg3)
act(rm_subj->tele_mesg3,FALSE,vict,0,0,TO_ROOM);}
tmp->event = EVENT_IGNORE;
break;
case EVENT_COMBAT:
if (tmp->subject)
subj = (struct char_data *) tmp->subject;
else
break;
if (GET_POS(subj) <= POSITION_SLEEPING)
break;
vict = (struct char_data *) tmp->target;
if (vict->in_room != subj->in_room)
break;
if (vict)
if (affected_by_spell(vict, SPELL_ENCASE_IN_ICE)){
if (!number(0,3) && (tmp->info1 > 5)){
act("$n's blow shatters the ice encasing $N!",
TRUE,subj,0,vict,TO_NOTVICT);
act("$n's blow shatters the ice encasing you!",
TRUE,subj,0,vict,TO_VICT);
act("Your blow shatters the ice encasing $N.",
TRUE,subj,0,vict,TO_CHAR);
damage(subj,vict,tmp->info1/4,tmp->info2,tmp->info3,0);
affect_from_char(vict, SPELL_ENCASE_IN_ICE);
}
else {
act("$n's blow glances off the ice encasing $N!",
TRUE,subj,0,vict,TO_NOTVICT);
act("$n's blow glances off the ice encasing you!",
TRUE,subj,0,vict,TO_VICT);
act("Your blow glances off the ice encasing $N.",
TRUE,subj,0,vict,TO_CHAR);
}
}
else
damage(subj, vict, tmp->info1, tmp->info2, tmp->info3,0);
tmp->event = EVENT_IGNORE;
break;
case EVENT_ROOM_DAMAGE:
{
int dam, damtype;
if (tmp->info3 == SPELL_BREATH_OF_VULCAN)
damtype = SKILL_IGNEM;
else
damtype = tmp->info3;
if (real_room(tmp->info2)){
rm_subj = world + real_room(tmp->info2);
if ((tmp->info3 < SPELL_FROST_BREATH) &&
IS_SET(rm_subj->room_flags, PEACEFULL)
|| IS_SET(rm_subj->room_flags, NO_MAGIC)){
tmp->event = EVENT_IGNORE;
break;
}
}
else{
tmp->event = EVENT_IGNORE;
break;
}
subj = (struct char_data *) tmp->subject;
vict = rm_subj->people;
next_vict = ((vict) ? vict->next_in_room : 0);
for (; next_vict; vict= next_vict){
next_vict = vict->next_in_room;
act(tmp->arg,FALSE,subj,0,vict,TO_ROOM);
dam = tmp->info1;
if (!tmp->info4 && vict == subj)
dam = 0;
if (((tmp->info3 == SPELL_BREATH_OF_VULCAN) ||
(tmp->info3 == SPELL_FIRE_BREATH)) &&
(affected_by_spell(vict, SPELL_ENCASE_IN_ICE))){
reduce_ice(vict, dam);
dam = 0;
}
if (tmp->info3 == SPELL_CALL_OF_THE_WATERY_GRAVE
&& IS_AFFECTED(vict, AFF_WATER_BREATH))
dam = 0;
else if (((tmp->info3 == SPELL_BREATH_OF_VULCAN) ||
(tmp->info3 == SPELL_FIRE_BREATH)) &&
IS_AFFECTED(vict, AFF_RESIST_HEAT))
dam /= 2;
else if (((tmp->info3 == SPELL_BREATH_OF_VULCAN) ||
(tmp->info3 == SPELL_FIRE_BREATH)) &&
IS_AFFECTED(vict, AFF_RESIST_COLD))
dam *= 2;
if (saves_spell(vict, SAVING_SPELL, GET_LEVEL(subj))) {
dam /= 3;
damage(subj,vict,dam,tmp->info3,-1,1);
if ((IS_MOB(subj) &&
!IS_MOB(vict))
|| (!IS_MOB(subj) && IS_MOB(vict)))
spell_damage_equipment(subj, vict, damtype, 3*dam);
}
else{
damage(subj,vict,dam,tmp->info3,-1,0);
if ((IS_MOB(subj) &&
!IS_MOB(vict))
|| (!IS_MOB(subj) && IS_MOB(vict)))
spell_damage_equipment(subj, vict, damtype, 2*dam);
}
}
tmp->event = EVENT_IGNORE;
}
break;
case EVENT_SPELL:
spl = tmp->info4;
if ((!(spell_info[spl].spell_pointer) && !tmp->info2)
|| (!(spell_info[spl].spll_pointer) && tmp->info2))
break;
if (tmp->subject)
subj = (struct char_data *) tmp->subject;
else
break;
if (tmp->target)
switch(tmp->info3){
case 0:
vict = (struct char_data *) tmp->target;
obj_vict =0;
break;
case 1:
vict = 0;
obj_vict = (struct obj_data *) tmp->target;
break;
}
else{
vict =0;
obj_vict = 0;
if (!IS_SET(spell_info[spl].targets,TAR_IGNORE)){
send_to_char("Your target seems to have wandered off.\r\n",subj);
break;
}
}
if (vict)
if (vict->in_room != subj->in_room
&& spell_info[spl].targets != TAR_CHAR_WORLD ){
send_to_char("Your target seems to have wandered off.\r\n",subj);
tmp->event = EVENT_IGNORE;
break;
}
if (tmp->info2){
if (spell_info[spl].spll_pointer)
((*spell_info[spl].spll_pointer) (spl, tmp->info2, subj, tmp->arg, SPELL_TYPE_SPELL, vict, obj_vict));
break;
}
break;
default:
break;
}
tmp = tmp->next;
}
tmp = events[pulse];
while (tmp){
tmp2 = tmp->next;
free(tmp);
tmp = tmp2;}
events[pulse] = 0;
return;
}
void add_event(int plse, int event, int inf1, int inf2, int inf3
, int inf4, char *arg, void *subj, void *vict)
{
struct event_type *evnt,*tmp;
CREATE(evnt, struct event_type, 1);
evnt->event = event;
evnt->info1 = inf1;
evnt->info2 = inf2;
evnt->info3 = inf3;
evnt->info4 = inf4;
evnt->arg = arg;
evnt->subject = subj;
evnt->target = vict;
evnt->next = 0;
plse += pulse;
plse = plse % 300;
/* now locate end of event stack
and add the event on the end */
if (events[plse]){
tmp = events[plse];
while(tmp->next)
tmp = tmp->next;
tmp->next = evnt;}
else
events[plse] = evnt;
return;
}
void extract_event(struct char_data *ch)
{
int i;
struct event_type *tmp;
for (i=0;i< 300; i++)
if ((tmp = events[i]) != NULL)
while(tmp)
{
if(tmp->event != EVENT_IGNORE)
if ((ch == (struct char_data *) tmp->subject)
|| (ch == (struct char_data *) tmp->target))
tmp->event = EVENT_IGNORE;
tmp = tmp->next;
}
}