/* ************************************************************************ * file: modify.c Part of DIKUMUD * * Usage: Run-time modification (by users) of game variables * * Copyright (C) 1990, 1991 - see 'license.doc' for complete information. * ************************************************************************ */ #include "os.h" #include "structs.h" #include "utils.h" #include "interpreter.h" #include "handler.h" #include "db.h" #include "comm.h" #include "prototypes.h" #define REBOOT_AT 10 /* 0-23, time of optional reboot if -e lib/reboot */ #define TP_MOB 0 #define TP_OBJ 1 #define TP_ERROR 2 void show_string (struct descriptor_data *d, char *input); char *string_fields[] = { "name", "short", "long", "description", "title", "delete-description", "\n" }; /* maximum length for text field x+1 */ int length[] = { 15, 60, 256, 240, 60 }; char *skill_fields[] = { "learned", "recognize", "\n" }; /* ************************************************************************ * modification of malloc'ed strings * ************************************************************************ */ /* Add user input to the 'current' string (as defined by d->str) */ void string_add (struct descriptor_data *d, char *str) { char *scan; int terminator = 0; /* determine if this is the terminal string, and truncate if so */ for (scan = str; *scan; scan++) if (terminator = (*scan == '@')) { *scan = '\0'; break; } if (!(*d->str)) { if ((int)strlen (str) > d->max_str) { send_to_char ("String too long - Truncated.\n\r", d->character); *(str + d->max_str) = '\0'; terminator = 1; } CREATE (*d->str, char, strlen (str) + 3); strcpy (*d->str, str); } else { if ((int)strlen (str) + (int)strlen (*d->str) > d->max_str) { send_to_char ("String too long. Last line skipped.\n\r", d->character); terminator = 1; } else { if (!(*d->str = (char *) realloc (*d->str, strlen (*d->str) + strlen (str) + 3))) { perror ("string_add"); WIN32CLEANUP exit (1); } strcat (*d->str, str); } } if (terminator) { d->str = 0; if (d->connected == CON_EXDSCR) { SEND_TO_Q (MENU, d); d->connected = CON_SLCT; } } else strcat (*d->str, "\n\r"); } #undef MAX_STR /* interpret an argument for do_string */ void quad_arg (char *arg, int *type, char *name, int *field, char *string) { char buf[MAX_STRING_LENGTH]; int i; /* determine type */ arg = one_argument (arg, buf); if (is_abbrev (buf, "char")) *type = TP_MOB; else if (is_abbrev (buf, "obj")) *type = TP_OBJ; else { *type = TP_ERROR; return; } /* find name */ arg = one_argument (arg, name); /* field name and number */ arg = one_argument (arg, buf); if (!(*field = old_search_block (buf, 0, strlen (buf), string_fields, 0))) return; /* string */ for (; isspace ((int)*arg); arg++); for (; *string = *arg; arg++, string++); return; } /* modification of malloc'ed strings in chars/objects */ void do_string (struct char_data *ch, char *arg, int cmd) { char name[MAX_STRING_LENGTH], string[MAX_STRING_LENGTH]; int field, type; struct char_data *mob; struct obj_data *obj; struct extra_descr_data *ed, *tmp; if (IS_NPC (ch)) return; quad_arg (arg, &type, name, &field, string); if (type == TP_ERROR) { send_to_char ("Syntax:\n\rstring ('obj'|'char') <name> <field> [<string>].", ch); return; } if (!field) { send_to_char ("No field by that name. Try 'help string'.\n\r", ch); return; } if (type == TP_MOB) { /* locate the beast */ if (!(mob = get_char_vis (ch, name))) { send_to_char ("I don't know anyone by that name...\n\r", ch); return; } switch (field) { case 1: if (!IS_NPC (mob) && GET_LEVEL (ch) < 24) { send_to_char ("You can't change that field for players.", ch); return; } ch->desc->str = &GET_NAME (mob); if (!IS_NPC (mob)) send_to_char ("WARNING: You have changed the name of a player.\n\r", ch); break; case 2: if (!IS_NPC (mob)) { send_to_char ("That field is for monsters only.\n\r", ch); return; } ch->desc->str = &mob->player.short_descr; break; case 3: if (!IS_NPC (mob)) { send_to_char ("That field is for monsters only.\n\r", ch); return; } ch->desc->str = &mob->player.long_descr; break; case 4: ch->desc->str = &mob->player.description; break; case 5: if (IS_NPC (mob)) { send_to_char ("Monsters have no titles.\n\r", ch); return; } ch->desc->str = &mob->player.title; break; default: send_to_char ("That field is undefined for monsters.\n\r", ch); return; break; } } else { /* type == TP_OBJ */ /* locate the object */ if (!(obj = get_obj_vis (ch, name))) { send_to_char ("Can't find such a thing here..\n\r", ch); return; } switch (field) { case 1: ch->desc->str = &obj->name; break; case 2: ch->desc->str = &obj->short_description; break; case 3: ch->desc->str = &obj->description; break; case 4: if (!*string) { send_to_char ("You have to supply a keyword.\n\r", ch); return; } /* try to locate extra description */ for (ed = obj->ex_description;; ed = ed->next) if (!ed) { /* the field was not found. create a new one. */ CREATE (ed, struct extra_descr_data, 1); ed->next = obj->ex_description; obj->ex_description = ed; CREATE (ed->keyword, char, strlen (string) + 1); strcpy (ed->keyword, string); ed->description = 0; ch->desc->str = &ed->description; send_to_char ("New field.\n\r", ch); break; } else if (!str_cmp (ed->keyword, string)) { /* the field exists */ free (ed->description); ed->description = 0; ch->desc->str = &ed->description; send_to_char ("Modifying description.\n\r", ch); break; } ch->desc->max_str = MAX_STRING_LENGTH; return; /* the stndrd (see below) procedure does not apply here */ break; case 6: if (!*string) { send_to_char ("You must supply a field name.\n\r", ch); return; } /* try to locate field */ for (ed = obj->ex_description;; ed = ed->next) if (!ed) { send_to_char ("No field with that keyword.\n\r", ch); return; } else if (!str_cmp (ed->keyword, string)) { free (ed->keyword); if (ed->description) free (ed->description); /* delete the entry in the desr list */ if (ed == obj->ex_description) obj->ex_description = ed->next; else { for (tmp = obj->ex_description; tmp->next != ed; tmp = tmp->next); tmp->next = ed->next; } free (ed); send_to_char ("Field deleted.\n\r", ch); return; } break; default: send_to_char ("That field is undefined for objects.\n\r", ch); return; break; } } if (*ch->desc->str) { free (*ch->desc->str); } if (*string) { /* there was a string in the argument array */ if ((int)strlen (string) > length[field - 1]) { send_to_char ("String too long - truncated.\n\r", ch); *(string + length[field - 1]) = '\0'; } CREATE (*ch->desc->str, char, strlen (string) + 1); strcpy (*ch->desc->str, string); ch->desc->str = 0; send_to_char ("Ok.\n\r", ch); } else { /* there was no string. enter string mode */ send_to_char ("Enter string. terminate with '@'.\n\r", ch); *ch->desc->str = 0; ch->desc->max_str = length[field - 1]; } } /* db stuff *********************************************** */ /* One_Word is like one_argument, execpt that words in quotes "" are */ /* regarded as ONE word */ char *one_word (char *argument, char *first_arg) { int found, begin, look_at; found = begin = 0; do { for (; isspace ((int)*(argument + begin)); begin++); if (*(argument + begin) == '\"') { /* is it a quote */ begin++; for (look_at = 0; (*(argument + begin + look_at) >= ' ') && (*(argument + begin + look_at) != '\"'); look_at++) *(first_arg + look_at) = LOWER (*(argument + begin + look_at)); if (*(argument + begin + look_at) == '\"') begin++; } else { for (look_at = 0; *(argument + begin + look_at) > ' '; look_at++) *(first_arg + look_at) = LOWER (*(argument + begin + look_at)); } *(first_arg + look_at) = '\0'; begin += look_at; } while (fill_word (first_arg)); return (argument + begin); } struct help_index_element *build_help_index (FILE * fl, int *num) { int nr = -1, issorted, i; struct help_index_element *list = 0, mem; char buf[81], tmp[81], *scan; long pos; for (;;) { pos = ftell (fl); FGETS (buf, 81, fl); *(buf + strlen (buf) - 1) = '\0'; scan = buf; for (;;) { /* extract the keywords */ scan = one_word (scan, tmp); if (!*tmp) break; if (!list) { CREATE (list, struct help_index_element, 1); nr = 0; } else RECREATE (list, struct help_index_element, ++nr + 1); list[nr].pos = pos; CREATE (list[nr].keyword, char, strlen (tmp) + 1); strcpy (list[nr].keyword, tmp); } /* skip the text */ do FGETS (buf, 81, fl); while (*buf != '#'); if (*(buf + 1) == '~') break; } /* we might as well sort the stuff */ do { issorted = 1; for (i = 0; i < nr; i++) if (str_cmp (list[i].keyword, list[i + 1].keyword) > 0) { mem = list[i]; list[i] = list[i + 1]; list[i + 1] = mem; issorted = 0; } } while (!issorted); *num = nr; return (list); } void page_string (struct descriptor_data *d, char *str, int keep_internal) { if (!d) return; if (keep_internal) { CREATE (d->showstr_head, char, strlen (str) + 1); strcpy (d->showstr_head, str); d->showstr_point = d->showstr_head; } else d->showstr_point = str; show_string (d, ""); } void show_string (struct descriptor_data *d, char *input) { char buffer[MAX_STRING_LENGTH], buf[MAX_INPUT_LENGTH]; register char *scan, *chk; int lines = 0, toggle = 1; one_argument (input, buf); if (*buf) { if (d->showstr_head) { free (d->showstr_head); d->showstr_head = 0; } d->showstr_point = 0; return; } /* show a chunk */ for (scan = buffer;; scan++, d->showstr_point++) if ((((*scan = *d->showstr_point) == '\n') || (*scan == '\r')) && ((toggle = -toggle) < 0)) lines++; else if (!*scan || (lines >= 22)) { *scan = '\0'; SEND_TO_Q (buffer, d); /* see if this is the end (or near the end) of the string */ for (chk = d->showstr_point; isspace ((int)*chk); chk++); if (!*chk) { if (d->showstr_head) { free (d->showstr_head); d->showstr_head = 0; } d->showstr_point = 0; } return; } } void night_watchman (void) { time_t tc; struct tm *t_info; extern int shutdown_server; void send_to_all (char *messg); tc = time (0); t_info = localtime (&tc); if ((t_info->tm_hour == 8) && (t_info->tm_wday > 0) && (t_info->tm_wday < 6)) if (t_info->tm_min > 50) { log ("Leaving the scene for the serious folks."); send_to_all ("Closing down. Thank you for flying DikuMUD.\n\r"); shutdown_server = 1; } else if (t_info->tm_min > 40) send_to_all ("ATTENTION: DikuMUD will shut down in 10 minutes.\n\r"); else if (t_info->tm_min > 30) send_to_all ("Warning: The game will close in 20 minutes.\n\r"); } void check_reboot (void) { time_t tc; struct tm *t_info; char dummy; FILE *boot; #ifdef __FreeBSD__ extern int shutdown_server, greboot; #else extern int shutdown_server, reboot; #endif tc = time (0); t_info = localtime (&tc); if ((t_info->tm_hour + 1) == REBOOT_AT && t_info->tm_min > 30) if (boot = fopen ("./reboot", "rb")) { if (t_info->tm_min > 50) { log ("Reboot exists."); fread (&dummy, sizeof (dummy), 1, boot); if (!feof (boot)) { /* the file is nonepty */ log ("Reboot is nonempty."); /* the script can't handle the signals */ block_signals(); if (system ("./reboot")) { log ("Reboot script terminated abnormally"); send_to_all ("The reboot was cancelled.\n\r"); system ("mv ./reboot reboot.FAILED"); fclose (boot); restore_signals(); return; } else system ("mv ./reboot reboot.SUCCEEDED"); restore_signals(); } send_to_all ("Automatic reboot. Come back in a little while.\n\r"); #ifdef __FreeBSD__ shutdown_server = greboot = 1; #else shutdown_server = reboot = 1; #endif } else if (t_info->tm_min > 40) send_to_all ("ATTENTION: DikuMUD will reboot in 10 minutes.\n\r"); else if (t_info->tm_min > 30) send_to_all ("Warning: The game will close and reboot in 20 minutes.\n\r"); fclose (boot); } } #define GR #define NEW #ifdef GR int workhours (void) { time_t tc; struct tm *t_info; tc = time (0); t_info = localtime (&tc); return ((t_info->tm_wday > 0) && (t_info->tm_wday < 6) && (t_info->tm_hour >= 9) && (t_info->tm_hour < 17)); } /* * This procedure is *heavily* system dependent. If your system is not set up * properly for this particular way of reading the system load (It's weird all * right - but I couldn't think of anything better), change it, or don't use -l. * It shouldn't be necessary to use -l anyhow. It's oppressive and unchristian * to harness man's desire to play. Who needs a friggin' degree, anyhow? */ int load (void) { struct syslinfo { char sl_date[12]; /* "Tue Sep 16\0" */ char sl_time[8]; /* "11:10\0" */ char sl_load1[6]; /* "12.0\0" */ char sl_load2[10]; /* "+2.3 14u\0" */ } info; FILE *fl; int ld, i, sum; static int previous[5]; static int p_point = -1; extern int slow_death; if (!(fl = fopen ("/tmp/.sysline", "rb"))) { perror ("sysline. (dying)"); slow_death = 1; return (-1); } if (!fread (&info, sizeof (info), 1, fl)) { perror ("fread sysline (dying)"); slow_death = 1; return (-1); } fclose (fl); if (p_point < 0) { previous[0] = atoi (info.sl_load1); for (i = 1; i < 5; i++) previous[i] = previous[0]; p_point = 1; return (previous[0]); } else { /* put new figure in table */ previous[p_point] = atoi (info.sl_load1); if (++p_point > 4) p_point = 0; for (i = 0, sum = 0; i < 5; i++) sum += previous[i]; return ((int) sum / 5); } } char *nogames (void) { static char text[200]; FILE *fl; if (fl = fopen ("lib/nogames", "rb")) { log ("/usr/games/nogames exists"); FGETS (text, 200, fl); return (text); fclose (fl); } return (0); } #ifdef OLD_COMA void coma (void) { extern struct descriptor_data *descriptor_list; extern int tics; void close_socket (struct descriptor_data *d); log ("Entering comatose state"); while (descriptor_list) close_socket (descriptor_list); do { #if defined WIN32 Sleep (300000); #else sleep (300); #endif tics = 1; if (workhours ()) { log ("Working hours collision during coma. Exit."); WIN32CLEANUP exit (0); } } while (load () >= 6); log ("Leaving coma"); } #endif /* emulate the game regulator */ void gr (SOCKET s) { char *txt = 0, buf[1024]; int ld = 0; static char *warnings[3] = { "If things don't look better within 3 minutes, the game will pause.\n\r", "The game will close temporarily 2 minutes from now.\n\r", "WARNING: The game will close in 1 minute.\n\r" }; static int wnr = 0; extern int slow_death, shutdown_server; void send_to_all (char *messg); void coma (int s); if (((ld = load ()) >= 6) || (txt = nogames ()) || slow_death) { if (ld >= 6) { sprintf (buf, "The system load is greater than 6.0 (%d)\n\r", ld); send_to_all (buf); } else if (slow_death) send_to_all ("The game is dying.\n\r"); else { strcpy (buf, "Game playing is no longer permitted on this machine:\n\r"); strcat (buf, txt); strcat (buf, "\n\r"); send_to_all (buf); } if (wnr < 3) send_to_all (warnings[wnr++]); else if (ld >= 6) { coma (s); wnr = 0; } else shutdown_server = 1; } else if (workhours ()) shutdown_server = 1; /* this shouldn't happen */ else if (wnr) { send_to_all ("Things look brighter now - you can continue playing.\n\r"); wnr = 0; } } #endif