/* * XPilot NG, a multiplayer space war game. * * Copyright (C) 1991-2001 by * * Bjørn Stabell * Ken Ronny Schouten * Bert Gijsbers * Dick Balaska * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "xpclient.h" char *talk_fast_msgs[TALK_FAST_NR_OF_MSGS]; /* talk macros */ /* * Abandon your hope, all you enter here */ /* The final string, sent to the server */ static char final_str[MAX_CHARS]; #define MSG_PARSED_FIELD_LEN 20 /* * Returns a pointer to the first character after the fields */ static char *Talk_macro_fields_info(char *buf, int *n_fields) { int end_found = 0, level = 0; *n_fields = 0; while (!end_found) { switch (*buf) { case TALK_FAST_START_DELIMITER: if (level++ == 0) (*n_fields)++; break; case TALK_FAST_MIDDLE_DELIMITER: if (level == 1) (*n_fields)++; break; case TALK_FAST_END_DELIMITER: level--; if (level == 0) end_found = 1; else if (level < 0) return NULL; break; case '\0': return NULL; break; default: break; } buf++; } return buf; } /* Returns a string pointer to the wanted_field * This pointer must be freed after using it */ static char *Talk_macro_get_field(char *buf, int wanted_field) { int finished = 0, level = 0, field = 0; size_t len; char *field_ptr, *start_ptr = NULL, *end_ptr = NULL; while (!finished) { switch (*buf) { case TALK_FAST_START_DELIMITER: if (level == 0) { field++; if (field == wanted_field) start_ptr = buf + 1; } level++; break; case TALK_FAST_MIDDLE_DELIMITER: if (level == 1) { field++; if (field == wanted_field) start_ptr = buf + 1; else if (field == wanted_field + 1) { end_ptr = buf; finished = 1; } } break; case TALK_FAST_END_DELIMITER: level--; if (level == 0) { if (field == wanted_field) end_ptr = buf; finished = 1; } else if (level < 0) return NULL; break; case '\0': return NULL; break; default: break; } buf++; } len = (size_t) (end_ptr - start_ptr); if ((field_ptr = XMALLOC(char, len + 1)) == NULL) { error("Can't allocate memory for talk macro"); return NULL; } strlcpy(field_ptr, start_ptr, len + 1); return field_ptr; } static int Talk_macro_parse_mesg(char *outbuf, char *inbuf, long pos, long max) { FILE *fp; char c; size_t fsize; int i; int done = 0; int n_fields; char *tmpptr; char *tmpptr1; char *tmpptr2; char *tmpptr3 = 0; char *nextpos; char *filename; other_t *player = NULL; while (!done && (c = *inbuf++) != '\0') { if (pos >= max - 2) { if (outbuf == final_str) { /* parsing to the talk buffer */ outbuf[pos] = '\0'; if (Net_talk(outbuf) == -1) return -1; pos = 0; } else break; } if (player != NULL) { switch (c) { case 'l': if (BIT(Setup->mode, LIMITED_LIVES)) outbuf[pos++] = player->life + '0'; break; case 'n': tmpptr = player->nick_name; for (i = 0; tmpptr[i] != '\0' && pos < max - 2; ++i) outbuf[pos++] = tmpptr[i]; break; case 's': if (pos < max - 1 - 6) /* short - "-16535" max no of chars */ pos += sprintf(outbuf + pos, "%.2f", player->score); break; case 't': if (BIT(Setup->mode, TEAM_PLAY)) outbuf[pos++] = player->team + '0'; break; default: break; } player = NULL; } else { switch (c) { case TALK_FAST_SPECIAL_TALK_CHAR: if ((c = *inbuf++) == '\0') { done = 1; break; } switch (c) { case '=': /* String comparison */ nextpos = Talk_macro_fields_info(inbuf, &n_fields); if (n_fields < 3 || n_fields > 4 || nextpos == NULL) break; /* parse field 1 */ if ((tmpptr = Talk_macro_get_field(inbuf, 1)) == NULL) { error("Talk_macro_get_field (1) error!"); break; } if ((tmpptr1 = XMALLOC(char, MSG_PARSED_FIELD_LEN)) == NULL) { error("Can't allocate memory for talk macro."); free(tmpptr); /* successful malloc from before */ break; } Talk_macro_parse_mesg(tmpptr1, tmpptr, 0, MSG_PARSED_FIELD_LEN); free(tmpptr); /* parse field 2 */ if ((tmpptr = Talk_macro_get_field(inbuf, 2)) == NULL) { error("Talk_macro_get_field (2) error!"); break; } if ((tmpptr2 = XMALLOC(char, MSG_PARSED_FIELD_LEN)) == NULL) { error("Can't allocate memory for talk macro."); free(tmpptr); /* successful malloc from before */ break; } Talk_macro_parse_mesg(tmpptr2, tmpptr, 0, MSG_PARSED_FIELD_LEN); free(tmpptr); if (!strcmp(tmpptr1, tmpptr2)) { /* True */ if ((tmpptr3 = Talk_macro_get_field(inbuf, 3)) == NULL) { error("Talk_macro_get_field (3) error!"); free(tmpptr1); free(tmpptr2); break; } pos = Talk_macro_parse_mesg(outbuf, tmpptr3, pos, max); } else if (n_fields == 4) { /* False */ if ((tmpptr3 = Talk_macro_get_field(inbuf, 4)) == NULL) { error("Talk_macro_get_field (4) error!"); free(tmpptr1); free(tmpptr2); break; } pos = Talk_macro_parse_mesg(outbuf, tmpptr3, pos, max); } inbuf = nextpos; free(tmpptr1); free(tmpptr2); free(tmpptr3); break; case 'f': nextpos = Talk_macro_fields_info(inbuf, &n_fields); if (n_fields != 1 || nextpos == NULL) break; if ((tmpptr = Talk_macro_get_field(inbuf, 1)) == NULL) { error("Talk_macro_get_field error!"); break; } inbuf = nextpos; if ((filename = XMALLOC(char, TALK_FAST_MSG_FNLEN)) == NULL) { error("Can't allocate memory for talk macro."); break; } Talk_macro_parse_mesg(filename, tmpptr, 0, TALK_FAST_MSG_FNLEN); free(tmpptr); if ((fp = fopen(filename, "r")) == NULL) { error("Couldn't open file %s", tmpptr); free(filename); break; } free(filename); /* Get filesize */ fseek(fp, 0L, SEEK_END); fsize = ftell(fp); rewind(fp); if ((tmpptr = XMALLOC(char, fsize + 1)) == NULL) { fclose(fp); break; } fread(tmpptr, 1, fsize, fp); tmpptr[fsize] = '\0'; fclose(fp); pos = Talk_macro_parse_mesg(outbuf, tmpptr, pos, max); free(tmpptr); break; case 'h': tmpptr = getenv("HOME"); if (tmpptr != NULL) { while (*tmpptr != '\0' && pos < max - 2) outbuf[pos++] = *tmpptr++; } break; case 'r': nextpos = Talk_macro_fields_info(inbuf, &n_fields); if (n_fields <= 0 || nextpos == NULL) break; if ((tmpptr = Talk_macro_get_field (inbuf, (int)(randomMT() % n_fields + 1))) == NULL) { error("Talk_macro_get_field error (random)"); break; } inbuf = nextpos; pos = Talk_macro_parse_mesg(outbuf, tmpptr, pos, max); free(tmpptr); break; case 'n': outbuf[pos] = '\0'; if (Net_talk(outbuf) == -1) return -1; pos = 0; break; case 'l': if (!snooping) { if ((player = Other_by_id(lock_id)) == NULL) { pos = 0; done = 1; break; } } else { if ((player = Other_by_id(eyesId)) == NULL) { pos = 0; done = 1; break; } } break; case 's': player = self; break; case 't': if (BIT(Setup->mode, TEAM_PLAY)) outbuf[pos++] = self->team + '0'; break; case TALK_FAST_SPECIAL_TALK_CHAR: outbuf[pos++] = c; break; default: break; } /* case TALK_FAST_SPECIAL_TALK_CHAR: switch (c) */ break; case '\n': break; default: outbuf[pos++] = c; break; } /* (player != NULL) switch(c) */ } } outbuf[pos] = '\0'; return pos; } int Talk_macro(int i) { char *str; assert(i >= 0); assert(i < TALK_FAST_NR_OF_MSGS); str = talk_fast_msgs[i]; if (str == NULL) return 1; if (Talk_macro_parse_mesg(final_str, str, 0L, MAX_CHARS) > 0) Net_talk(final_str); return 0; } static inline int index_by_option(xp_option_t *opt) { return atoi(Option_get_name(opt) + strlen("msg")) - 1; } static bool Set_talk_macro(xp_option_t *opt, const char *value) { int i = index_by_option(opt); /*printf("Set_talk_macro: i = %d\n", i);*/ assert(i >= 0); assert(i < TALK_FAST_NR_OF_MSGS); XFREE(talk_fast_msgs[i]); talk_fast_msgs[i] = xp_safe_strdup(value); return true; } static const char *Get_talk_macro(xp_option_t *opt) { int i = index_by_option(opt); /*printf("Get_talk_macro: i = %d\n", i);*/ assert(i >= 0); assert(i < TALK_FAST_NR_OF_MSGS); return talk_fast_msgs[i]; } xp_option_t talk_macro_options[] = { /* * Default warning macros for newbies. */ XP_STRING_OPTION( "msg1", "#t:*** BALL! Our ball is gone! Save it! ***", NULL, 0, Set_talk_macro, NULL, Get_talk_macro, XP_OPTFLAG_DEFAULT, "Talkmessage 1.\n"), XP_STRING_OPTION( "msg2", "#t:*** SAFE! Our ball is safe. ***", NULL, 0, Set_talk_macro, NULL, Get_talk_macro, XP_OPTFLAG_DEFAULT, "Talkmessage 2.\n"), XP_STRING_OPTION( "msg3", "#t:*** COVER! The enemy ball is approaching our base. ***", NULL, 0, Set_talk_macro, NULL, Get_talk_macro, XP_OPTFLAG_DEFAULT, "Talkmessage 3.\n"), XP_STRING_OPTION( "msg4", "#t:*** POP! The enemy ball is back at the enemy base. ***", NULL, 0, Set_talk_macro, NULL, Get_talk_macro, XP_OPTFLAG_DEFAULT, "Talkmessage 4.\n"), /* * This macro swaps between teams 2 and 4, useful on Blood's Music * maps. */ XP_STRING_OPTION( "msg5", "#=[#t|2|/team 4|/team 2]", NULL, 0, Set_talk_macro, NULL, Get_talk_macro, XP_OPTFLAG_DEFAULT, "Talkmessage 5.\n"), XP_STRING_OPTION( "msg6", "", NULL, 0, Set_talk_macro, NULL, Get_talk_macro, XP_OPTFLAG_DEFAULT, "Talkmessage 6.\n"), XP_STRING_OPTION( "msg7", "", NULL, 0, Set_talk_macro, NULL, Get_talk_macro, XP_OPTFLAG_DEFAULT, "Talkmessage 7.\n"), XP_STRING_OPTION( "msg8", "", NULL, 0, Set_talk_macro, NULL, Get_talk_macro, XP_OPTFLAG_DEFAULT, "Talkmessage 8.\n"), XP_STRING_OPTION( "msg9", "", NULL, 0, Set_talk_macro, NULL, Get_talk_macro, XP_OPTFLAG_DEFAULT, "Talkmessage 9.\n"), XP_STRING_OPTION( "msg10", "", NULL, 0, Set_talk_macro, NULL, Get_talk_macro, XP_OPTFLAG_DEFAULT, "Talkmessage 10.\n"), XP_STRING_OPTION( "msg11", "", NULL, 0, Set_talk_macro, NULL, Get_talk_macro, XP_OPTFLAG_DEFAULT, "Talkmessage 11.\n"), XP_STRING_OPTION( "msg12", "", NULL, 0, Set_talk_macro, NULL, Get_talk_macro, XP_OPTFLAG_DEFAULT, "Talkmessage 12.\n"), XP_STRING_OPTION( "msg13", "", NULL, 0, Set_talk_macro, NULL, Get_talk_macro, XP_OPTFLAG_DEFAULT, "Talkmessage 13.\n"), XP_STRING_OPTION( "msg14", "", NULL, 0, Set_talk_macro, NULL, Get_talk_macro, XP_OPTFLAG_DEFAULT, "Talkmessage 14.\n"), XP_STRING_OPTION( "msg15", "", NULL, 0, Set_talk_macro, NULL, Get_talk_macro, XP_OPTFLAG_DEFAULT, "Talkmessage 15.\n"), XP_STRING_OPTION( "msg16", "", NULL, 0, Set_talk_macro, NULL, Get_talk_macro, XP_OPTFLAG_DEFAULT, "Talkmessage 16.\n"), XP_STRING_OPTION( "msg17", "", NULL, 0, Set_talk_macro, NULL, Get_talk_macro, XP_OPTFLAG_DEFAULT, "Talkmessage 17.\n"), XP_STRING_OPTION( "msg18", "", NULL, 0, Set_talk_macro, NULL, Get_talk_macro, XP_OPTFLAG_DEFAULT, "Talkmessage 18.\n"), XP_STRING_OPTION( "msg19", "", NULL, 0, Set_talk_macro, NULL, Get_talk_macro, XP_OPTFLAG_DEFAULT, "Talkmessage 19.\n"), XP_STRING_OPTION( "msg20", "", NULL, 0, Set_talk_macro, NULL, Get_talk_macro, XP_OPTFLAG_DEFAULT, "Talkmessage 20.\n"), }; void Store_talk_macro_options(void) { STORE_OPTIONS(talk_macro_options); }