Mercurial > ~darius > hgwebdir.cgi > paradise_client
view 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 source
/* $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); } }