Mercurial > ~darius > hgwebdir.cgi > paradise_client
diff dmessage.c @ 3:5a977ccbc7a9 default tip
Empty changelog
author | darius |
---|---|
date | Sat, 06 Dec 1997 05:41:29 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmessage.c Sat Dec 06 05:41:29 1997 +0000 @@ -0,0 +1,778 @@ +/* $Id: dmessage.c,v 1.1.1.1 1997/12/06 05:41:29 darius Exp $ */ + +/* + * dmessage.c + * + * for the client of a socket based protocol. + * code for message window scrollback added by Bill Dyess 12/7/93 + */ +#include "copyright.h" + +#include <stdio.h> +#include <math.h> +#include <string.h> +#include <ctype.h> +#ifdef __STDC__ +#include <stdlib.h> +#endif +#include "Wlib.h" +#include "defs.h" +#include "struct.h" +#include "data.h" +#include "proto.h" +#ifdef SOUND +#include "Slib.h" +#endif + +#define MESSAGESIZE 20 +#define YOFF 0 + +struct messageData { + char *message; + unsigned char flags, from, to; +}; + +struct messageNode { + struct messageData *line; + struct messageNode *next, *prev; +}; + +/* Prototypes */ +int instr P((char *string1, char *string2)); +void CheckFeatures P((char *m)); +void print_message +P((char *message, unsigned int flags, unsigned int from, + unsigned int to, struct messageData * data, + W_Window winmask, int backwards)); + void evalFlags P((int type, char *flagList)); + + void initMessageWindows() +{ + int i; + char *s; + + messWin[WALL].window = W_MakeScrollingWindow("review_all", WINSIDE + BORDER, + YOFF + WINSIDE + 3 * BORDER + 2 * MESSAGESIZE, 80, 10, 0, "xterm", BORDER); + messWin[WTEAM].window = W_MakeScrollingWindow("review_team", WINSIDE + BORDER, + YOFF + WINSIDE + 4 * BORDER + 2 * MESSAGESIZE + 10 * W_Textheight + 8, + 80, 5, 0, "xterm", BORDER); + messWin[WINDIV].window = W_MakeScrollingWindow("review_your", WINSIDE + BORDER, + YOFF + WINSIDE + 5 * BORDER + 2 * MESSAGESIZE + 15 * W_Textheight + 16, + 80, 4, 0, "xterm", BORDER); + messWin[WKILL].window = W_MakeScrollingWindow("review_kill", WINSIDE + BORDER, + YOFF + WINSIDE + 6 * BORDER + 2 * MESSAGESIZE + 19 * W_Textheight + 24, + 80, 6, 0, "xterm", BORDER); + messWin[WPHASER].window = W_MakeScrollingWindow("review_phaser", WINSIDE + + BORDER, YOFF + WINSIDE + 7 * BORDER + 2 * MESSAGESIZE + 24 * W_Textheight + + 32, 80, 3, 0, "xterm", BORDER); + messWin[WREVIEW].window = W_MakeScrollingWindow("review", WINSIDE + BORDER, + YOFF + WINSIDE + 3 * BORDER + 2 * MESSAGESIZE, + 80, 20, 0, "xterm", BORDER); + + /* + initialize the 'allow' flags. Any window can display any message. + [BDyess] + */ + s = stringDefault("review_all.allow", "MA"); + evalFlags(WALL, s); + s = stringDefault("review_team.allow", "T"); + evalFlags(WTEAM, s); + s = stringDefault("review_your.allow", "I"); + evalFlags(WINDIV, s); + s = stringDefault("review_kill.allow", "K"); + evalFlags(WKILL, s); + s = stringDefault("review_phaser.allow", "P"); + evalFlags(WPHASER, s); + s = stringDefault("review.allow", "MATIKP"); + evalFlags(WREVIEW, s); + + for (i = 0; i < WNUM; i++) { + messWin[i].head = messWin[i].curHead = NULL; + } +} + +void +evalFlags(type, flagList) + int type; + char *flagList; +{ + char *orig=flagList; + + messWin[type].flags = 0; + while (*flagList) { + switch (toupper(*flagList)) { + case 'A': + messWin[type].flags |= WA_ALL; + break; + case 'T': + messWin[type].flags |= WA_TEAM; + break; + case 'I': + messWin[type].flags |= WA_INDIV; + break; + case 'K': + messWin[type].flags |= WA_KILL; + break; + case 'P': + messWin[type].flags |= WA_PHASER; + break; + case 'M': + messWin[type].flags |= WA_MACRO; + break; + default: + printf("Invalid allow flag '%c' in allow list, ignoring\n", + *flagList); + break; + } + flagList++; + } + free(orig); +} + +void +messageWinEvent(evt) + W_Event *evt; +/* handles the mouse and keyboard events that happen in one of the message + windows. For key events, if the event is within the team or all window then + it will automatically start the message for you, with destination to the + player's team or ALL, respectively. If it's a button event, it will scroll + the message window back, forward, or to start (left, right, and middle + button respectively). It beeps if there is no messages to scroll (ie at + the top or bottom already). [BDyess] 12/07/93 */ +{ + struct messageNode **headpntr, *runner, *newcpntr; + struct messageData *j; + int windowHeight; + register int i; + W_Window window = evt->Window; + int key = evt->key; + int scroll=0; + + if (!W_IsMapped(window)) + return; + + if (evt->type == W_EV_KEY) { + if (key == ('e' + 128)) { /* erase window [BDyess] */ + W_ClearWindow(window); + } else if(key == ('p'+128)) { + scroll = -1; + } else if(key == ('n'+128)) { + scroll = 1; + } else if (window == messWin[WALL].window) { + smessage_ahead('A', key); + } else if (window == messWin[WTEAM].window) { + smessage_ahead('T', key); + } else { + smessage(key); + } + if(!scroll) + return; + } + headpntr = NULL; + for (i = 0; i < WNUM; i++) { + if (window == messWin[i].window) { + headpntr = &messWin[i].curHead; + break; + } + } + + runner = *headpntr; + if (runner == NULL) { + if(scrollBeep) + W_Beep(); + return; + } + windowHeight = W_WindowHeight(window); + + if(scroll==-1) { + for (i = 0; (i < windowHeight) && runner; i++, runner = runner->next) + ; + if (runner == NULL) { + if (scrollBeep) + W_Beep(); + return; + } + j=runner->line; + print_message(j->message, j->flags, j->from, j->to, NULL, window, 1); + *headpntr = (*headpntr)->next; + return; + } else if(scroll==1) { + if(runner->prev == NULL) { + if (scrollBeep) + W_Beep(); + return; + } + j=runner->prev->line; + print_message(j->message, j->flags, j->from, j->to, NULL, window, 0); + *headpntr = (*headpntr)->prev; + return; + } + switch (key) { + case W_LBUTTON: + for (i = 0; (i < windowHeight-1) && runner->next; i++, runner = runner->next) + ; + newcpntr=runner; + + if (runner->next == NULL) { + if (scrollBeep) + W_Beep(); + break; + } + runner=runner->next; + for (i = 0; (i < windowHeight-1) && runner; i++, runner = runner->next) { + j=runner->line; + print_message(j->message, j->flags, j->from, j->to, NULL, window, 1); + } + if(i<windowHeight-1) { + for(;i<windowHeight-1;i++) + W_WriteText(window,0,-1,0,"",0,0); + } + *headpntr=newcpntr; + break; + case W_RBUTTON: + if (runner->prev == NULL) { + if (scrollBeep) + W_Beep(); + break; + } + for (i = 0; (i < windowHeight-1) && runner->prev; i++, runner = runner->prev) { + j=runner->prev->line; + print_message(j->message, j->flags, j->from, j->to, NULL, window, 0); + } + *headpntr = runner; + break; + case W_MBUTTON: + if (runner->prev == NULL) { + if (scrollBeep) + W_Beep(); + break; + } + W_ClearWindow(window); + while (runner->prev) + runner = runner->prev; + *headpntr = runner; + for (i = 0; i < windowHeight && runner->next; i++, runner = runner->next); + while (runner) { + j = runner->line; + print_message(j->message, j->flags, j->from, j->to, NULL, window, 0); + runner = runner->prev; + } + break; + } +} + +void +rsvp_borg_call(message, from) + char *message; + int from; +{ +#if 0 + int len, pos; + len = strlen(message); + pos = len - 5; + if (strncmp(message + pos, " ", 5) == 0) +#else + char *chk; + + if (strlen(message) < 15) + return; + for (chk = message + 10; *chk && *chk == ' '; chk++) + /* empty body */ ; + if (*chk) + return; +#endif + { + char buf[120]; + + sprintf(buf, "Paradise Client %s (%s)", CLIENTVERS, +#ifdef __osf__ + "DEC OSF/1" +#else +#ifdef NeXT + "NeXT" +#else +#ifdef ultrix + "DEC Ultrix" +#else +#if defined(sparc) && defined(SVR4) + "Solaris" +#else +#ifdef sparc + "SUN4/Sparc" +#else +#ifdef sun + "SUN3" +#else +#ifdef sequent + "sequent" +#else +#ifdef hpux + "hpux" +#else +#ifdef AIX + "AIX" +#else +#ifdef vax + "vax" +#else +#ifdef sgi + "sgi/IRIX" +#else +#ifdef apollo + "apollo" +#else +#ifdef RS6K + "RS6K" +#else +#ifdef linux + "Linux" +#else +#ifdef __NetBSD__ + "NetBSD" +#else +#ifdef __FreeBSD__ + "FreeBSD" +#else +#ifdef AMIGA + "Amiga" +#else + "generic" +#endif /* Amiga */ +#endif /* linux */ +#endif /* RS6K */ +#endif /* apollo */ +#endif /* sgi */ +#endif /* vax */ +#endif /* AIX */ +#endif /* hpux */ +#endif /* sequent */ +#endif /* sun */ +#endif /* sparc */ +#endif /* solaris */ +#endif /* ultrix */ +#endif /* NeXT */ +#endif /* __osf__ */ +#endif /* FreeBSD */ +#endif /* NetBSD */ + ); + if (from == 255) { + sendMessage(buf, MGOD, 0); + } else + sendMessage(buf, MINDIV, from); + } +} + +void +logit(message) + char *message; +/* logs the given message if the 'logmess' variable is set to one. It send the + message to stdout by default, or to a file if one is defined. [BDyess] */ +{ + if (!logmess) + return; + if (logfilehandle && logFile) { + fprintf(logfilehandle, "%s\n", message); + fflush(logfilehandle); + } else { + printf("%s\n", message); + } +} + +void +writeMessage(data, message, color, len, winmask, type, backwards) + struct messageData *data; + char *message; + W_Color color; + int len; + W_Window winmask; + int type; + int backwards; +{ + struct messageNode *newhead; + struct messageWin *j; + + if (data != NULL) { +#ifdef SPEECH /* was AMIGA... ya never know ;-) */ + if (((S_SpeakYour && type & WA_INDIV) || + (S_SpeakTeam && type & WA_TEAM) || + (S_SpeakAll && type & WA_ALL) || + (S_SpeakKill && type & WA_KILL)) && + ((strncmp(message,"GOD->",5) != 0) || S_SpeakGod) && + ((data->from != me->p_no) || S_SpeakSelf)) { + S_SpeakString(message, len); + } +#endif /* SPEECH */ +#ifdef SOUND + if ((type & WA_INDIV) && data->from != me->p_no) { + S_PlaySound(S_WHISTLE); + } +#endif + for (j = &messWin[0]; j < &messWin[WNUM]; j++) { + if (!(j->flags & type)) + continue; + newhead = (struct messageNode *) malloc(sizeof(struct messageNode)); + newhead->next = j->head; + if (newhead->next) + newhead->next->prev = newhead; + newhead->prev = NULL; + newhead->line = data; + if (j->head == j->curHead) { + /* we aren't currently scrolled back [BDyess] */ + W_WriteText(j->window, 0, 0, color, message, len, 0); + j->curHead = newhead; + } + j->head = newhead; + } + } else { /* we're drawing a new page */ + for (j = &messWin[0]; j < &messWin[WNUM]; j++) { + if (!(j->flags & type)) + continue; + if (j->window != winmask) + continue; + W_WriteText(j->window, 0, (backwards ? -1 : 0), color, message, len, 0); + } + } +} + +void +print_message(message, flags, from, to, data, winmask, backwards) + char *message; + unsigned int flags, from, to; + struct messageData *data; + W_Window winmask; + int backwards; +/* this function determines the color that the given message should be and + then passes it to writeMessage, where the data structure for the scroll + back code is created and also where the winmask test is done. The winmask + determines what window the message is written to, useful when calling this + routine from the scrollback routines. If winmask == NULL it doesn't + limit printing at all, eg team messages will go to the team window and to + the total review window. [BDyess] 12/07/93 */ +{ + register int len; + W_Color color; + W_Window targwin; + +#define take MTEAM + MTAKE + MVALID +#define destroy MTEAM + MDEST + MVALID +#define kill MALL + MKILL + MVALID +#define killp MALL + MKILLP + MVALID +#define killa MALL + MKILLA + MVALID +#define bomb MTEAM + MBOMB + MVALID +#define team MTEAM + MVALID +#define conq MALL + MCONQ + MVALID + + len = strlen(message); + if (from == 254) { /* client passing info around */ + switch (showPhaser) { + case 0: + break; + case 1: + writeMessage(data, message, textColor, len, winmask, WA_KILL | WA_REVIEW, backwards); + break; + case 2: + writeMessage(data, message, textColor, len, winmask, WA_REVIEW | WA_PHASER, backwards); + break; + case 3: + writeMessage(data, message, textColor, len, winmask, WA_REVIEW, backwards); + break; + } + return; + } + if (from == 255) { + if (flags == MCONFIG + MINDIV + MVALID) { +/* printf("Going to checkfeatures\n");*/ + CheckFeatures(message); + return; + } + /* From God */ + color = textColor; + } else { + /* kludge to fix the occasional incorrect color message */ + if (*message == ' ' && from != me->p_no) { + /* XXX fix to handle funky teams */ + switch (*(message + 1)) { + case 'F': + color = W_Yellow; + break; + case 'R': + color = W_Red; + break; + case 'K': + color = W_Green; + break; + case 'O': + color = W_Cyan; + break; + case 'I': + color = W_Grey; + break; + default: + color = playerColor(&(players[from])); + } + } else + color = playerColor(&(players[from])); + } + + /* added/modified to fit with the scrollback feature 1/94 -JR */ + if (!paradise && niftyNewMessages) { + if (flags == conq) { + /* output conquer stuff to stdout in addition to message window */ + fprintf(stdout, "%s\n", message); + if (instr(message, "kill")) { + fprintf(stdout, "NOTE: The server here does not properly set message flags\n"); + fprintf(stdout, "You should probably pester the server god to update....\n"); + } + } + if ((flags == team) || (flags == take) || (flags == destroy)) { + writeMessage(data, message, color, len, winmask, WA_TEAM | WA_REVIEW, backwards); + targwin = messWin[WTEAM].window; + } else if ((flags == kill) || (flags == killp) || (flags == killa) || (flags == bomb)) { + writeMessage(data, message, color, len, winmask, + WA_KILL | (reportKills ? WA_REVIEW : 0), backwards); + targwin = messWin[WKILL].window; + } else if (flags & MINDIV) { + writeMessage(data, message, color, len, winmask, (WA_INDIV | WA_REVIEW), backwards); + targwin = messWin[WINDIV].window; + } else if (flags == (MMACRO | MALL)) { + writeMessage(data, message, color, len, winmask, (WA_MACRO | WA_REVIEW), backwards); + targwin = messWin[WALL].window; + } else { + /* + if we don't know where the message belongs by this time, stick + it in the all board... + */ + writeMessage(data, message, color, len, winmask, (WA_ALL | WA_REVIEW), backwards); + targwin = messWin[WALL].window; + } + } else { + + /* + Kludge stuff for report kills... + */ + if ((strncmp(message, "GOD->ALL", 8) == 0 && + (instr(message, "was kill") || + instr(message, "killed by"))) || + instr(message, "burned to a crisp by") || + instr(message, "shot down by") || + (*message != ' ' && instr(message, "We are being attacked"))) { + writeMessage(data, message, color, len, winmask, + WA_KILL | (reportKills ? WA_REVIEW : 0), backwards); + return; + } + /* + note: messages are kept track of even if the associated window is + not mapped. This allows the window to be later mapped and have + all the past messages. [BDyess] + */ + if (flags & MTEAM) { + writeMessage(data, message, color, len, winmask, WA_TEAM | WA_REVIEW, backwards); + targwin = messWin[WTEAM].window; + } else if (flags & MINDIV) { + writeMessage(data, message, color, len, winmask, WA_INDIV | WA_REVIEW, backwards); + targwin = messWin[WINDIV].window; + } else if (flags == (MMACRO | MALL)) { + writeMessage(data, message, color, len, winmask, WA_MACRO | WA_REVIEW, backwards); + targwin = messWin[WALL].window; + } else { + writeMessage(data, message, color, len, winmask, WA_ALL | WA_REVIEW, backwards); + targwin = messWin[WALL].window; + } + } + /* + send warnings to warning or message window, if player doesn't have + messag es mapped + */ + if ((use_msgw && (targwin == messWin[WINDIV].window || targwin == messWin[WTEAM].window)) || + (!W_IsMapped(targwin) && !W_IsMapped(messWin[WREVIEW].window))) { + if (!messpend && messagew) { /* don't collide with messages being + written! */ + W_ClearWindow(messagew); + W_WriteText(messagew, 5, 5, color, message, len, W_RegularFont); + } else + warning(message); + } +} + +void +dmessage(message, flags, from, to) + char *message; + unsigned int flags, from, to; +/* prints the given message by going though several subroutines. Here, it first + creates the data structure that holds the message info and logs the message, + then sends it on it's subroutine path to print it to the correct window(s). + This is a good place to handle any special-functions that occur due to + incoming messages. The data structure for the scroll back is like this: + each window has a head pointer that points to the top of its message + list. Each list only contains the messages that go to it's window. The + lists have pointers to the message itself, so that only one copy of the + message exists even if it is displayed on several windows. Each list also + has a current head pointer that points to the record that is at the bottom + of that current window. If the current head pointer and the head pointer + are different, then the window must be scrolled back. In such a case, new + messages are still received but not printed. [BDyess] 12/07/93 */ +{ + struct messageData *data; + struct distress dist; + int len; + +#ifdef RC_DISTRESS + /* aha! A new type distress/macro call came in. parse it appropriately */ + if (F_gen_distress && (flags == (MTEAM | MDISTR | MVALID))) { + HandleGenDistr(message, from, to, &dist); + len = makedistress(&dist, message, distmacro[dist.distype].macro); +#ifdef BEEPLITE + if (UseLite) + rcdlite(&dist); +#endif + if (len <= 0) + return; + flags ^= MDISTR; + } +#endif + /* + add create message data struct. Used for message scrollback + capability. [BDyess] + */ + data = (struct messageData *) malloc(sizeof(struct messageData)); + data->message = (char *) strdup(message); + data->flags = flags; + data->from = from; + data->to = to; + /* + keep track of how many queued messages there are for use with the + infoIcon [BDyess] + */ + if (infoIcon) { + if (to == me->p_no && flags & MINDIV) { /* personal message */ + me_messages++; + } else if (flags & MTEAM) { /* team message */ + team_messages++; + } else { /* message for all */ + all_messages++; + } + if (iconified) + drawIcon(); + } + logit(message); + + /* + fix for upgrade bug. Forced UDP would resend numbers, (thinking them + speed changes) screwing up upgrading on those twinkish sturgeon + servers. [BDyess] + */ + if (strncmp(message, "UPG->", 5) == 0) + upgrading = 1; + if (upgrading && !(me->p_flags & PFORBIT)) + upgrading = 0; + + if ((from != me->p_no) || pigSelf) + rsvp_borg_call(message, from); + + /* beep when a personal message is sent while iconified [BDyess] */ + if (to == me->p_no && (flags & MINDIV) && iconified) { + W_Beep(); + } + if (from == 255 && + strcmp(message, "Tractor beam aborted warp engagement") == 0) { + me->p_flags &= ~PFWARPPREP; + } + print_message(message, flags, from, to, data, NULL, 0); +} + + +int +instr(string1, string2) + char *string1, *string2; +{ + char *s; + int length; + + length = strlen(string2); + for (s = string1; *s != 0; s++) { + if (*s == *string2 && strncmp(s, string2, length) == 0) + return (1); + } + return (0); +} + +void +CheckFeatures(m) + char *m; +/* I don't know if this works correctly or not. It is ripped from BRM and has + been modified a bit to fit. Right now it doesn't do anything. [BDyess] */ +{ + char buf[BUFSIZ]; + char *pek = &m[10]; + + if ((int) strlen(m) < 11) + return; + + while ((*pek == ' ') && (*pek != '\0')) + pek++; + + strcpy(buf, "Paradise Client: "); + + if (!strcmp(pek, "NO_VIEW_BOX")) { + allowViewBox = 0; + strcat(buf, pek); + } +#ifdef CONTINUOUS_MOUSE + if (!strcmp(pek, "NO_CONTINUOUS_MOUSE")) { + allowContinuousMouse = 0; + strcat(buf, pek); + } +#endif /* CONTINUOUS_MOUSE */ + if (!strcmp(pek, "NO_SHOW_ALL_TRACTORS")) { + allowShowAllTractorPressor = 0; + strcat(buf, pek); + } + if (!strcmp(pek, "HIDE_PLAYERLIST_ON_ENTRY")) { + allowPlayerlist = 0; + strcat(buf, pek); + } + if (!strcmp(pek, "NO_NEWMACRO")) { +/* UseNewMacro = 0;*/ + strcat(buf, pek); + } + if (!strcmp(pek, "NO_SMARTMACRO")) { +/* UseSmartMacro = 0;*/ + strcat(buf, pek); + } + if (!strcmp(pek, "WHY_DEAD")) { + why_dead = 1; + strcat(buf, pek); + } + if (!strcmp(pek, "RC_DISTRESS")) { +/* gen_distress = 1;*/ +/* distmacro = dist_prefered;*/ + strcat(buf, pek); + } + /* what the hell is this? - jmn */ + if (!strncmp(pek, "INFO", 4)) { + strcat(buf, pek); + } + if (strlen(buf) == strlen("Paradise Client: ")) { + strcat(buf, "UNKNOWN FEATURE: "); + strcat(buf, pek); + } + buf[79] = '\0'; + + printf("%s\n", buf); + + W_WriteText(messWin[WREVIEW].window, 0, 0, W_White, buf, strlen(buf), 0); + W_WriteText(messWin[WALL].window, 0, 0, W_White, buf, strlen(buf), 0); +} + +void +sendVersion() +{ + static int version_sent = 0; + char buf[80]; + + if (!version_sent) { + version_sent = 1; + sprintf(buf, "@%s", CLIENTVERS); + pmessage(buf, me->p_no, MINDIV | MCONFIG); + } +}