| Follows are patches to cheapglk 0.8 to make a bot capable of playing | |
| Glk games on ifMUD. This forms Floyd, as written by Evin Robertson. | |
| This code may be used, modified, and distributed freely so long as you | |
| don't misrepresent its authorship. | |
| You'll need netcat for the 'hose' command used to connect things from | |
| stdin/stderr to a socket. Most of the mud-specific stuff is isolated | |
| in mudglk.c, so it shouldn't be too hard to port this to other muds or | |
| IRC. Most of the other stuff can by found by searching this for \" | |
| Questions and comments may be directed at nitfol@my-deja.com | |
| diff -r -u -N cheapglk/Make.mpcmudglk mudglk/Make.mpcmudglk | |
| --- cheapglk/Make.mpcmudglk Wed Dec 31 19:00:00 1969 | |
| +++ mudglk/Make.mpcmudglk Thu Oct 28 08:43:47 1999 | |
| +LINKLIBS = | |
| +GLKLIB = -lmpcmudglk | |
| diff -r -u -N cheapglk/Makefile mudglk/Makefile | |
| --- cheapglk/Makefile Sun Jan 3 00:26:07 1999 | |
| +++ mudglk/Makefile Thu Oct 28 08:43:47 1999 | |
| CFLAGS = $(OPTIONS) $(INCLUDEDIRS) | |
| -GLKLIB = libcheapglk.a | |
| +NAME = mudglk | |
| + | |
| +GLKLIB = lib$(NAME).a | |
| CHEAPGLK_OBJS = \ | |
| cgfref.o cggestal.o cgmisc.o cgstream.o cgstyle.o cgwindow.o main.o \ | |
| - gi_dispa.o | |
| + gi_dispa.o mudglk.o | |
| CHEAPGLK_HEADERS = cheapglk.h gi_dispa.h | |
| -all: $(GLKLIB) Make.cheapglk | |
| +all: $(GLKLIB) Make.$(NAME) | |
| $(GLKLIB): $(CHEAPGLK_OBJS) | |
| ar r $(GLKLIB) $(CHEAPGLK_OBJS) | |
| ranlib $(GLKLIB) | |
| -Make.cheapglk: | |
| - echo LINKLIBS = $(LIBDIRS) $(LIBS) > Make.cheapglk | |
| - echo GLKLIB = -lcheapglk >> Make.cheapglk | |
| +Make.$(NAME): | |
| + echo LINKLIBS = $(LIBDIRS) $(LIBS) > Make.$(NAME) | |
| + echo GLKLIB = -l$(NAME) >> Make.$(NAME) | |
| $(CHEAPGLK_OBJS): glk.h $(CHEAPGLK_HEADERS) | |
| clean: | |
| - rm -f *~ *.o $(GLKLIB) Make.cheapglk | |
| + rm -f *~ *.o $(GLKLIB) Make.$(NAME) | |
| diff -r -u -N cheapglk/buildmulti mudglk/buildmulti | |
| --- cheapglk/buildmulti Wed Dec 31 19:00:00 1969 | |
| +++ mudglk/buildmulti Thu Oct 28 08:43:47 1999 | |
| +#!/bin/sh | |
| +rm -f mudglk.o | |
| +make NAME=mpcmudglk OPTIONS=-DMULTIPC | |
| +rm -f mudglk.o | |
| diff -r -u -N cheapglk/cgfref.c mudglk/cgfref.c | |
| --- cheapglk/cgfref.c Sun Jan 3 01:00:06 1999 | |
| +++ mudglk/cgfref.c Thu Oct 28 08:43:47 1999 | |
| char *cx; | |
| int val; | |
| char *prompt, *prompt2; | |
| - | |
| + | |
| switch (usage & fileusage_TypeMask) { | |
| - case fileusage_SavedGame: | |
| - prompt = "Enter saved game"; | |
| - break; | |
| - case fileusage_Transcript: | |
| - prompt = "Enter transcript file"; | |
| - break; | |
| - case fileusage_InputRecord: | |
| - prompt = "Enter command record file"; | |
| - break; | |
| - case fileusage_Data: | |
| - default: | |
| - prompt = "Enter data file"; | |
| - break; | |
| + case fileusage_SavedGame: | |
| + if(fmode == filemode_Read) | |
| + prompt = "You don't like this part of the game? Neither does Floyd. What part do you want to do instead? [Type '..Floyd LIST' to list available saved games.]"; | |
| + else | |
| + prompt = "Oooh, saving is a good idea. Could get dangerous. What do you wanna call the file?"; | |
| + break; | |
| + case fileusage_Transcript: | |
| + prompt = "Enter transcript file"; | |
| + break; | |
| + case fileusage_InputRecord: | |
| + prompt = "Enter command record file"; | |
| + break; | |
| + case fileusage_Data: | |
| + default: | |
| + prompt = "Enter data file"; | |
| + break; | |
| } | |
| - if (fmode == filemode_Read) | |
| - prompt2 = "to load"; | |
| - else | |
| - prompt2 = "to store"; | |
| - | |
| - printf("%s %s: ", prompt, prompt2); | |
| + mud_say(prompt); | |
| - fgets(buf, 255, stdin); | |
| + ask_again: | |
| + | |
| + mud_fgets(buf, 255); | |
| val = strlen(buf); | |
| while (val | |
| || buf[val-1] == ' ')) | |
| val--; | |
| buf[val] = '\0'; | |
| + | |
| + for (cx = buf; *cx; cx++) { | |
| + if(*cx == '/') { | |
| + mud_say("That's a funny name. Floyd doesn't think he's allowed to call it that!"); | |
| + return NULL; | |
| + } | |
| + } | |
| for (cx = buf; *cx == ' '; cx++) { } | |
| /* The player just hit return. It would be nice to provide a | |
| default value, but this implementation is too cheap. */ | |
| return NULL; | |
| + } | |
| + | |
| + if(strcasecmp(cx, "list") == 0) { | |
| + mud_say("Floyd knows about these:"); | |
| + fputc('\"', stderr); | |
| + system("echo * 1>&2"); | |
| + mud_say("So what do you want to call yours?"); | |
| + goto ask_again; | |
| } | |
| fref = gli_new_fileref(cx, usage, rock); | |
| diff -r -u -N cheapglk/cgmisc.c mudglk/cgmisc.c | |
| --- cheapglk/cgmisc.c Sun Jan 3 01:21:02 1999 | |
| +++ mudglk/cgmisc.c Thu Oct 28 08:43:47 1999 | |
| void glk_select(event_t *event) | |
| { | |
| window_t *win = gli_window_get(); | |
| + | |
| + if(!event) | |
| + return; | |
| gli_event_clearevent(event); | |
| if (!win || !(win->char_request || win->line_request)) { | |
| /* No input requests. This is legal, but a pity, because the | |
| correct behavior is to wait forever. Bye bye. */ | |
| - while (1) { | |
| - getchar(); | |
| - } | |
| + exit(1); | |
| } | |
| if (win->char_request) { | |
| be turned into a special keycode (and so would other keys, | |
| if we could recognize them.) */ | |
| - fgets(buf, 255, stdin); | |
| + mud_fgets(buf, 255); | |
| kval = buf[0]; | |
| if (kval == '\r' || kval == '\n') | |
| kval = keycode_Return; | |
| else { | |
| char buf[256]; | |
| int val; | |
| - fgets(buf, 255, stdin); | |
| + mud_fgets(buf, 255); | |
| val = strlen(buf); | |
| if (val && (buf[val-1] == '\n' || buf[val-1] == '\r')) | |
| val--; | |
| diff -r -u -N cheapglk/cgstream.c mudglk/cgstream.c | |
| --- cheapglk/cgstream.c Sun Jan 3 01:09:49 1999 | |
| +++ mudglk/cgstream.c Thu Oct 28 08:43:47 1999 | |
| /* If you're going to convert Latin-1 to a different | |
| character set, this is (a) place to do it. Only on the | |
| putc(); not on the gli_put_char to echostr. */ | |
| - putc(ch, stdout); | |
| + mud_putc(ch); | |
| if (str->win->echostr) | |
| gli_put_char(str->win->echostr, ch); | |
| break; | |
| /* If you're going to convert Latin-1 to a different | |
| character set, this is (a) place to do it. Only on the | |
| fwrite(); not on the gli_put_buffer to echostr. */ | |
| - fwrite((unsigned char *)buf, 1, len, stdout); | |
| + mud_write((unsigned char *)buf, len); | |
| if (str->win->echostr) | |
| gli_put_buffer(str->win->echostr, buf, len); | |
| break; | |
| diff -r -u -N cheapglk/cgwindow.c mudglk/cgwindow.c | |
| --- cheapglk/cgwindow.c Sun Jan 3 01:15:57 1999 | |
| +++ mudglk/cgwindow.c Thu Oct 28 08:43:47 1999 | |
| return; | |
| } | |
| - for (ix=0; ix<screenheight; ix++) { | |
| + for (ix=0; ix<cg_screenheight; ix++) { | |
| putc('\n', stdout); | |
| } | |
| } | |
| } | |
| if (widthptr) | |
| - *widthptr = screenwidth; | |
| + *widthptr = cg_screenwidth; | |
| if (heightptr) | |
| - *heightptr = screenheight; | |
| + *heightptr = cg_screenheight; | |
| } | |
| void glk_window_get_arrangement(window_t *win, glui32 *methodptr, | |
| diff -r -u -N cheapglk/cheapglk.h mudglk/cheapglk.h | |
| --- cheapglk/cheapglk.h Sun Jan 3 01:10:21 1999 | |
| +++ mudglk/cheapglk.h Thu Oct 28 08:43:47 1999 | |
| /* The overall screen size, as set by command-line options. A | |
| better implementation would check the real screen size | |
| somehow. */ | |
| -extern int screenwidth, screenheight; | |
| +extern int cg_screenwidth, cg_screenheight; | |
| /* Callbacks necessary for the dispatch layer. */ | |
| extern gidispatch_rock_t (*gli_register_obj)(void *obj, glui32 objclass); | |
| diff -r -u -N cheapglk/floyd/floyd.c mudglk/floyd/floyd.c | |
| --- cheapglk/floyd/floyd.c Wed Dec 31 19:00:00 1969 | |
| +++ mudglk/floyd/floyd.c Thu Oct 28 08:51:24 1999 | |
| +#include <sys/stat.h> | |
| +#include <errno.h> | |
| +#include <stdio.h> | |
| +#include <stdlib.h> | |
| +#include <string.h> | |
| +#include <unistd.h> | |
| +#include <sys/types.h> | |
| +#include <sys/wait.h> | |
| +#include "mudglk.h" | |
| + | |
| + | |
| +#define BUFSIZE 8000 | |
| + | |
| +int spawn (const char *command, const char *argv1) { | |
| + int pid, status; | |
| + | |
| + if (command == 0) | |
| + return 1; | |
| + pid = fork(); | |
| + if (pid == -1) | |
| + return -1; | |
| + if (pid == 0) { | |
| + const char *argv[4]; | |
| + argv[0] = command; | |
| + argv[1] = argv1; | |
| + argv[2] = 0; | |
| + execv(command, argv); | |
| + exit(127); | |
| + } | |
| + do { | |
| + if (waitpid(pid, &status, 0) == -1) { | |
| + if (errno != EINTR) | |
| + return -1; | |
| + } else | |
| + return status; | |
| + } while(1); | |
| +} | |
| + | |
| + | |
| +int checkvalid(char *command) | |
| +{ | |
| + for(; *command == ' '; command++) /* remove leading whitespace */ | |
| + ; | |
| + switch(tolower(*command)) { | |
| + case 'q': | |
| + mud_say("Floyd scared of the letter 'q'. Why would you want to turn off Floyd?"); | |
| + return 0; | |
| + case '@': | |
| + mud_say("Floyd not allowed to use commands and the letter '@' looks suspicious."); | |
| + return 0; | |
| + } | |
| + return 1; | |
| +} | |
| + | |
| + | |
| +void floyd_do(char *command) { | |
| + int i; | |
| + if(!checkvalid(command)) | |
| + return; | |
| + for(i = 0; command[i]; i++) { | |
| + if(command[i] == '.') { /* Break up sentences into separate commands */ | |
| + | |
| + /* Check to see if it's a ..inky command */ | |
| + if(command[i+1] == '.') { /* safe because strings are zero terminated */ | |
| + i++; /* skip the second . too */ | |
| + continue; | |
| + } | |
| + | |
| + command[i] = '\n'; | |
| + if(!checkvalid(command + i + 1)) | |
| + return; | |
| + } | |
| + } | |
| + fputc('\n', stderr); | |
| + fputs(command, stderr); | |
| + fputc('\n', stderr); | |
| +} | |
| + | |
| + | |
| +void floyd_emote(char *emote) { | |
| + fputs("\n:", stderr); | |
| + fputs(emote, stderr); | |
| + fputc('\n', stderr); | |
| +} | |
| + | |
| + | |
| +int floyd_loadgame(char *terp, char *gamename, char *playname) | |
| +{ | |
| + struct stat foo; | |
| + | |
| + /* Give up if the file doesn't exist or is a directory */ | |
| + if(!((stat(gamename, &foo) == 0) && S_ISREG(foo.st_mode))) | |
| + return 0; | |
| + | |
| + fprintf(stderr, "\n@doing Playing %s\n", playname); | |
| + spawn(terp, gamename); | |
| + mud_say("That game over already? It was just getting good. Wanna play another?"); | |
| + fputs("\n@doing Waiting for someone to play with me\n", stderr); | |
| + | |
| + return 1; | |
| +} | |
| + | |
| + | |
| +int main() | |
| +{ | |
| + char message[BUFSIZE]; | |
| + int repeatcount = 0; | |
| + time_t lasttime = time(NULL); | |
| + | |
| + do { | |
| + fgets(message, BUFSIZE, stdin); | |
| + } while(strncmp(message, "TYPE connect, who, or quit:", 15) != 0); | |
| + /* fgets(message, BUFSIZE, stdin); */ | |
| + fputs("connect floyd mypasswordhere\n", stderr); | |
| + | |
| + chdir("saves"); | |
| + | |
| + fputs("\n@doing Waiting for someone to play with me\n", stderr); | |
| + | |
| + for(;;) { | |
| + int i; | |
| + char *buffer; | |
| + time_t nowtime; | |
| + mud_fgets(message, BUFSIZE); | |
| + | |
| + /* Limit frequency of responses */ | |
| + nowtime = time(NULL); | |
| + if(lasttime == nowtime) { | |
| + if(repeatcount++ >= 5) { | |
| + mud_say("Enough of this!"); | |
| + continue; | |
| + } | |
| + } else { | |
| + lasttime = nowtime; | |
| + repeatcount = 0; | |
| + } | |
| + | |
| + /* Eat leading whitespace */ | |
| + for(buffer = message; *buffer == ' '; buffer++) | |
| + ; | |
| + | |
| + if(strncasecmp(buffer, "do ", 3) == 0 || | |
| + strncasecmp(buffer, "go ", 3) == 0) { | |
| + floyd_do(buffer + 3); | |
| + continue; | |
| + } | |
| + if(strncasecmp(buffer, "say ", 4) == 0) { | |
| + mud_say(buffer + 4); | |
| + continue; | |
| + } | |
| + if(strncasecmp(buffer, "emote ", 6) == 0) { | |
| + floyd_emote(buffer + 6); | |
| + continue; | |
| + } | |
| + | |
| + /* Everything else is going to be case insensitive */ | |
| + for(i = 0; buffer[i]; i++) | |
| + buffer[i] = tolower(buffer[i]); | |
| + | |
| + | |
| + if(strncmp(buffer, "load", 4) == 0) { | |
| + for(i = 0; i < strlen(buffer); i++) | |
| + buffer[i] = tolower(buffer[i]); | |
| + memcpy(buffer, "../t/", 5); | |
| + if(strstr(buffer, "/..")) { | |
| + mud_say("Hey, what are you trying to do?"); | |
| + continue; | |
| + } | |
| + | |
| + if(floyd_loadgame("../mudtads", buffer, buffer+5)) | |
| + continue; | |
| + memcpy(buffer, "../m/", 5); | |
| + if(floyd_loadgame("../multifloyd", buffer, buffer+5)) | |
| + continue; | |
| + memcpy(buffer, "../z/", 5); | |
| + if(floyd_loadgame("../nitfol", buffer, buffer+5)) | |
| + continue; | |
| + memcpy(buffer, "../h/", 5); | |
| + if(floyd_loadgame("../mudhugo", buffer, buffer+5)) | |
| + continue; | |
| + memcpy(buffer, "../x/", 5); | |
| + if(floyd_loadgame(buffer, buffer, buffer+5)) | |
| + continue; | |
| + | |
| + mud_say("Um, these are the games Floyd knows about: "); | |
| + fputc('\"', stderr); | |
| + chdir("../m"); | |
| + system("echo -n * 1>&2"); | |
| + chdir("../x"); | |
| + system("echo -n * 1>&2"); | |
| + chdir("../z"); | |
| + fputc(' ', stderr); | |
| + system("echo -n * 1>&2"); | |
| + chdir("../t"); | |
| + fputc(' ', stderr); | |
| + system("echo -n * 1>&2"); | |
| + chdir("../h"); | |
| + fputc(' ', stderr); | |
| + system("echo * 1>&2"); | |
| + chdir("../saves"); | |
| + continue; | |
| + } | |
| + if(strcmp(buffer, "poet") == 0) { | |
| + mud_say("This doesn't work, jota."); | |
| + /*system("../hose localhost 4000 --slave 1>&2");*/ | |
| + continue; | |
| + } | |
| + if(strncmp(buffer, "url ", 4) == 0) { | |
| + spawn("../url", buffer+4); | |
| + continue; | |
| + } | |
| + | |
| + | |
| + if(strcmp(buffer, "home") == 0) { | |
| + mud_say("There's no place like the Floyditorium."); | |
| + fputs("\nhome\n", stderr); | |
| + continue; | |
| + } | |
| + if(strlen(buffer) == 1) { | |
| + char c = toupper(buffer[0]); | |
| + fputs("\n\"", stderr); | |
| + fputc(c, stderr); | |
| + fputs(" is ", stderr); | |
| + fputc(c, stderr); | |
| + fputs(".\n", stderr); | |
| + continue; | |
| + } | |
| + if(strstr(buffer, "cork nut")) { | |
| + mud_say("Awwk! Want... wait, Floyd not Alex."); | |
| + continue; | |
| + } | |
| + if(strstr(buffer, "corn") || strstr(buffer, "niblet")) { | |
| + mud_say("mmm... corn..."); | |
| + continue; | |
| + } | |
| + if(strstr(buffer, "monkey")) { | |
| + mud_say("Eep! Floyd likes a monkey."); | |
| + continue; | |
| + } | |
| + if(strstr(buffer, "crack")) { | |
| + mud_say("You think Floyd smoking crack? You're probably right."); | |
| + continue; | |
| + } | |
| + if(strstr(buffer, "pants")) { | |
| + mud_say("Floyd not wearing any pants!"); | |
| + continue; | |
| + } | |
| + if(strstr(buffer, "alpaca")) { | |
| + mud_say("Alpacas cute, like Floyd."); | |
| + continue; | |
| + } | |
| + if(strstr(buffer, "soft")) { | |
| + mud_say("Floyd's software is SO SOFT."); | |
| + continue; | |
| + } | |
| + if(strstr(buffer, "bastards")) { | |
| + mud_say("Game switching bastards!"); | |
| + continue; | |
| + } | |
| + if(strstr(buffer, "blender")) { | |
| + floyd_emote("cries!"); | |
| + continue; | |
| + } | |
| + if(strstr(buffer, "mud")) { | |
| + mud_say("Floyd likes to play in the mud and get all dirty."); | |
| + continue; | |
| + } | |
| + if(strstr(buffer, "bar")) { | |
| + mud_say("Eeeagh! Bar!"); | |
| + floyd_emote("has disconnected."); | |
| + floyd_emote("has connected."); | |
| + continue; | |
| + } | |
| + if(strstr(buffer, "789")) { | |
| + mud_say("Oops, looks like Gunther's out of a job."); | |
| + continue; | |
| + } | |
| + if(strstr(buffer, "hucka") || strstr(buffer, "beanstalk")) { | |
| + mud_say("Sounds like fun."); | |
| + continue; | |
| + } | |
| + if(strstr(buffer, "drone")) { | |
| + mud_say("Floyd isn't the drones you're looking for."); | |
| + continue; | |
| + } | |
| + if(strstr(buffer, "thumper") || strstr(buffer, "jota")) { | |
| + mud_say("He's Floyd's friend."); | |
| + continue; | |
| + } | |
| + if(strstr(buffer, "injoke")) { | |
| + floyd_emote("giggles, \"Why'd the trousers cross the road? To get to the other leg!\""); | |
| + continue; | |
| + } | |
| + if(strstr(buffer, "hello") || strstr(buffer, "hi") || | |
| + strstr(buffer, "hullo") || strstr(buffer, "hola") || | |
| + strstr(buffer, "greet") || strstr(buffer, "howdy")) { | |
| + mud_say("Hi!"); | |
| + continue; | |
| + } | |
| + if(strstr(buffer, "no") || strstr(buffer, "ye")) { | |
| + mud_say("If Floyd wanted your opinion, he would have asked for it."); | |
| + continue; | |
| + } | |
| + floyd_emote("looks around, confused, \"You can tell Floyd to load a game [ Type ..FLOYD load ], or you can tell Floyd to DO stuff. Maybe Floyd will learn new tricks tomorrow.\""); | |
| + } | |
| + return 0; | |
| +} | |
| diff -r -u -N cheapglk/floyd/startfloyd mudglk/floyd/startfloyd | |
| --- cheapglk/floyd/startfloyd Wed Dec 31 19:00:00 1969 | |
| +++ mudglk/floyd/startfloyd Thu Oct 28 08:50:58 1999 | |
| +#!/bin/bash | |
| +ulimit -v 50960 | |
| +ulimit -t 32 | |
| +ulimit -u 80 | |
| +while true; do ./hose ifmud.port4000.com 4000 --in --err ./floyd; sleep 30; done | |
| + | |
| diff -r -u -N cheapglk/main.c mudglk/main.c | |
| --- cheapglk/main.c Sat Nov 28 15:20:58 1998 | |
| +++ mudglk/main.c Thu Oct 28 08:43:47 1999 | |
| #include "cheapglk.h" | |
| #include "glkstart.h" | |
| -int screenwidth = 80; | |
| -int screenheight = 24; | |
| +int cg_screenwidth = 80; | |
| +int cg_screenheight = 24; | |
| static int inittime = FALSE; | |
| if (val < 8) | |
| errflag = 1; | |
| else | |
| - screenwidth = val; | |
| + cg_screenwidth = val; | |
| break; | |
| case 'h': | |
| val = 0; | |
| if (val < 2) | |
| errflag = 1; | |
| else | |
| - screenheight = val; | |
| + cg_screenheight = val; | |
| break; | |
| default: | |
| printf("%s: unknown option: %s\n", argv[0], argv[ix]); | |
| diff -r -u -N cheapglk/mudglk.c mudglk/mudglk.c | |
| --- cheapglk/mudglk.c Wed Dec 31 19:00:00 1969 | |
| +++ mudglk/mudglk.c Thu Oct 28 08:43:47 1999 | |
| +#include <stdio.h> | |
| +#include <string.h> | |
| +#include "mudglk.h" | |
| + | |
| + | |
| +#define BUFSIZE 8000 | |
| + | |
| +static unsigned char linebuffer[80]; | |
| +static int linelength; | |
| + | |
| + | |
| + | |
| +int wrap_length = 72; | |
| + | |
| + | |
| +char line_start[80] = { ':', '|', ' ', '\0' }; | |
| + | |
| +char circularbuffer[2048]; | |
| +int circularstart = 0; | |
| +int circularend = 0; | |
| + | |
| +void circularwrite(char c) | |
| +{ | |
| + circularbuffer[circularend++] = c; | |
| + if(circularend == 2048) | |
| + circularend = 0; | |
| + if(circularstart == circularend) { | |
| + | |
| + /* We should have a newline every 78 characters or so, so no infinite loops here */ | |
| + do { | |
| + circularstart++; | |
| + if(circularstart == 2048) | |
| + circularstart = 0; | |
| + } while(circularbuffer[circularstart] != '\n'); | |
| + } | |
| +} | |
| + | |
| +void mudwritec(char c) | |
| +{ | |
| + fputc(c, stderr); | |
| + circularwrite(c); | |
| +} | |
| + | |
| + | |
| +void mudwrites(char *s) | |
| +{ | |
| + fputs(s, stderr); | |
| + while(*s) | |
| + circularwrite(*s++); | |
| +} | |
| + | |
| +void mudwriteb(char *b, int len) | |
| +{ | |
| + int l; | |
| + fwrite(b, 1, len, stderr); | |
| + for(l = 0; l < len; l++) | |
| + circularwrite(b[l]); | |
| +} | |
| + | |
| +void mud_flush(int length) | |
| +{ | |
| + if(linelength < length) { | |
| + fputs("\n:dances with a monkey to the moon [BUG]\n", stderr); | |
| + length = linelength; | |
| + } | |
| + | |
| + mudwritec('\n'); | |
| + mudwrites(line_start); | |
| + mudwriteb(linebuffer, length); | |
| + | |
| + linelength -= length; | |
| + | |
| + mudwritec('\n'); | |
| +} | |
| + | |
| + | |
| +void parse_tag(char *tagname) | |
| +{ | |
| + static outstate = 0; | |
| + | |
| + if(strncasecmp(tagname, "whisper ", 8) == 0) | |
| + outstate |= 1; | |
| + else if(strcasecmp(tagname, "/whisper") == 0) | |
| + outstate &= ~1; | |
| + else if(strcasecmp(tagname, "emote") == 0) | |
| + outstate |= 2; | |
| + else if(strcasecmp(tagname, "/emote") == 0) | |
| + outstate &= ~2; | |
| + | |
| + if(linelength) | |
| + mud_flush(linelength); | |
| + | |
| + switch(outstate) { | |
| + case 0: | |
| + wrap_length = 80 - 8; /* Floyd | ... */ | |
| + strcpy(line_start, ":| "); | |
| + break; | |
| + case 1: | |
| + wrap_length = 80 - 18; /* Floyd whispers, "..." */ | |
| + snprintf(line_start, 80, ".%s ", tagname + 8); | |
| + break; | |
| + case 2: | |
| + wrap_length = 80 - 6; /* Floyd ... */ | |
| + strcpy(line_start, ": "); | |
| + break; | |
| + case 3: | |
| + wrap_length = 80 - 30; /* Floyd privately poses to you: ... */ | |
| + snprintf(line_start, 80, ".%s :"); /* broken */ | |
| + break; | |
| + } | |
| + | |
| +} | |
| + | |
| + | |
| +void mud_putc(unsigned char ch) | |
| +{ | |
| + static unsigned char tagname[64]; | |
| + static int taglength = -1; | |
| + | |
| + | |
| + static newline_count = 0; | |
| + | |
| + if(ch == '\n') { | |
| + if(newline_count > 4) | |
| + return; | |
| + mud_flush(linelength); | |
| + newline_count++; | |
| + } else { | |
| + newline_count = 0; | |
| + | |
| + if(taglength != -1) { /* Currently in a tag */ | |
| + if(ch == '>' || taglength >= 63) { | |
| + tagname[taglength] = 0; | |
| + parse_tag(tagname); | |
| + taglength = -1; | |
| + } | |
| + else | |
| + tagname[taglength++] = ch; | |
| + } else { /* Not currently in a tag */ | |
| + if(ch == '<') | |
| + taglength = 0; | |
| + else { | |
| + linebuffer[linelength++] = ch; | |
| + if(linelength >= wrap_length) { | |
| + int n; | |
| + for(n = linelength; n; n--) | |
| + if(linebuffer[n-1] == ' ') | |
| + break; | |
| + if(!n) | |
| + n = wrap_length; | |
| + mud_flush(n); | |
| + memmove(linebuffer, linebuffer + n, linelength); | |
| + } | |
| + } | |
| + } | |
| + } | |
| +} | |
| + | |
| + | |
| +void mud_write(unsigned char *buf, int length) | |
| +{ | |
| + int n; | |
| + for(n = 0; n < length; n++) | |
| + mud_putc(buf[n]); | |
| +} | |
| + | |
| +void mud_say(char *buf) | |
| +{ | |
| + fputs("\n\"", stderr); | |
| + fputs(buf, stderr); | |
| + fputs("\n", stderr); | |
| +} | |
| + | |
| +void mud_fgets(char *dest, int length) | |
| +{ | |
| + char *aftername, *message; | |
| + char buffer[BUFSIZE]; | |
| + | |
| + if(linelength) | |
| + mud_flush(linelength); | |
| + | |
| + for(;;) { | |
| + if(!fgets(buffer, BUFSIZE, stdin)) | |
| + _exit(1); | |
| + buffer[BUFSIZE] = 0; | |
| + | |
| + aftername = strchr(buffer, ' '); | |
| + message = NULL; | |
| + if(aftername) { | |
| + *aftername = 0; | |
| + aftername++; | |
| + if(strncasecmp(aftername, "says (to floyd), \"", 18) == 0 || | |
| + strncasecmp(aftername, "asks (to floyd), \"", 18) == 0) | |
| + message = aftername + 18; | |
| + else if(strncasecmp(aftername, "exclaims (to floyd), \"", 22) == 0) | |
| + message = aftername + 22; | |
| +#ifdef MULTIPC | |
| + else if(strncasecmp(aftername, "whispers, \"", 11) == 0) | |
| + message = aftername + 11; | |
| +#endif | |
| + | |
| + if(message) { | |
| + char *endquote = strrchr(message, '\"'); | |
| + if(!endquote) | |
| + endquote = strrchr(message, '\n'); | |
| + if(!endquote) | |
| + continue; | |
| + | |
| + *endquote = 0; | |
| + | |
| + if(strcasecmp(message, "space") == 0) | |
| + strcpy(message, " space"); | |
| + | |
| + if(strcasecmp(message, "redisplay") == 0) { | |
| + int i; | |
| + for(i = circularstart; i != circularend; i == 2047 ? i = 0 : i++) { | |
| + fputc(circularbuffer[i], stderr); | |
| + } | |
| + mud_fgets(dest, length); | |
| + return; | |
| + } | |
| + | |
| + | |
| +#ifdef MULTIPC | |
| + strncpy(dest, buffer, length - 2); | |
| + strcat(dest, ", "); | |
| + strncat(dest, message, length - strlen(dest)); | |
| +#else | |
| + strncpy(dest, message, length); | |
| +#endif | |
| + return; | |
| + } | |
| + } | |
| + } | |
| +} | |
| diff -r -u -N cheapglk/mudglk.h mudglk/mudglk.h | |
| --- cheapglk/mudglk.h Wed Dec 31 19:00:00 1969 | |
| +++ mudglk/mudglk.h Thu Oct 28 08:43:47 1999 | |
| +void mud_putc(unsigned char ch); | |
| +void mud_write(unsigned char *buf, int length); | |
| +void mud_say(char *buf); | |
| +void mud_fgets(char *dest, int length); | |
Xet Storage Details
- Size:
- 22.4 kB
- Xet hash:
- 9fc9c00c3ae25906dba15283a237fce0a5a1a5c071be2d365ef4e80e2618b9ca
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.