Mercurial > ~darius > hgwebdir.cgi > paradise_server
diff src/cluecheck.c @ 2:2719a89505ba
First entry of Paradise Server 2.9 patch 10 Beta
author | darius |
---|---|
date | Sat, 06 Dec 1997 04:37:01 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cluecheck.c Sat Dec 06 04:37:01 1997 +0000 @@ -0,0 +1,871 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation, or any derivative works thereof, for any NON-COMMERCIAL +purpose and without fee is hereby granted, provided that this copyright +notice appear in all copies. No representations are made about the +suitability of this software for any purpose. This software is provided +"as is" without express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie +--------------------------------------------------------------------------*/ + +#include "config.h" +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "defs.h" +#include "data.h" +#include "struct.h" +#include "shmem.h" + +#ifdef CLUECHECK1 + +/* ----------------- ROBS CLUECHECK -------------------- */ + +static char clueword[40]; + +void +set_clue_word(word) + char *word; +{ + strncpy(clueword, word, sizeof(clueword)); + clueword[sizeof(clueword) - 1] = 0; +} + +#ifdef MOTD_SUPPORT +static char *motdstring = 0; +static int motdlen = 0; + +void free_motdstruct(); +#endif + +/* read the MOTD into core so we can parse it later */ +void +init_motdbuf(fname) + char *fname; +{ +#ifdef MOTD_SUPPORT + struct stat stats; + FILE *fp; + + if (motdstring != 0) + { + free_motdstruct(); + free(motdstring); + motdstring = 0; + motdlen = 0; + } + + if (!configvals->cluecheck || + configvals->cluecheck != CC_MOTD) + return; /* don't waste the memory if we're not clue + * checking from the MOTD */ + + if (0 > stat(fname, &stats)) + { + perror("statting file"); + return; + } + + motdlen = stats.st_size; + + motdstring = (char *) malloc(motdlen + 1); + fp = fopen(fname, "r"); + if (0 == fp) + { + perror("opening file"); + exit(1); + } + fread(motdstring, motdlen, 1, fp); +#endif +} + +static int page; +static int isfirst; + +#ifdef MOTD_SUPPORT + +static int line, wordn; + +/* structures for the internal representation of the MOTD */ +#define LINESPERPAGE 38 + +struct word +{ + char *s; +}; + +struct line +{ + struct word *words; + int nwords; +}; + +struct page +{ + struct line lines[LINESPERPAGE]; + int nlines; + struct page *next; +}; + +struct page *motdhead = 0; + + + +#define MAXATTEMPTS 10 +void +find_suitable_motd_word() +{ + int attempts; + int pagecount; + int i; + struct page *currp; + + + for (pagecount = 0, currp = motdhead; + currp; + pagecount++, currp = currp->next) + ; + + if (pagecount > 10) + pagecount = 10; + + for (attempts = 0; pagecount > 1 && attempts < MAXATTEMPTS; attempts++) + { + /* the first page is excluded. Everybody sees that */ + page = 1 + lrand48() % (pagecount - 1); + + for (i = 0, currp = motdhead; i < page; i++, currp = currp->next) + ; + if (currp->nlines < 1) + continue; + if (lrand48() & 1) + { + /* get first word */ + isfirst = 1; + for (line = 0; line < currp->nlines; line++) + if (currp->lines[line].nwords > 0) + break; + if (line >= currp->nlines) + continue; + wordn = 0; + } + else + { + /* get last word */ + isfirst = 0; + for (line = currp->nlines - 1; line >= 0; line--) + if (currp->lines[line].nwords > 0) + break; + if (line < 0) + continue; + wordn = currp->lines[line].nwords - 1; + } + set_clue_word(currp->lines[line].words[wordn].s); + /* + * printf("%s word on page %d (line %d word %d) is %s\n", + * isfirst?"first":"last", page+1, line+1, wordn+1, clueword); + */ + return; + } + page = -1; +} + +#if 0 +/* for the day when we have line numbers in the MOTD. */ +void +find_suitable_word2() +{ + int attempts; + int pagecount; + int i; + struct page *currp; + + + for (pagecount = 0, currp = motdhead; currp; pagecount++, currp = currp->next) + ; + + for (attempts = 0; attempts < 10; attempts++) + { + page = lrand48() % pagecount; + for (i = 0, currp = motdhead; i < page; i++, currp = currp->next) + ; + if (currp->nlines < 1) + continue; + line = lrand48() % currp->nlines; + if (currp->lines[line].nwords < 1) + continue; + wordn = lrand48() % currp->lines[line].nwords; + set_clue_word(currp->lines[line].words[wordn].s); + printf("word on page %d line %d word %d is %s\n", + page + 1, line + 1, wordn + 1, clueword); + return; + } + clueword[0] = 0; +} +#endif + +#if 0 +/* useful for debugging the MOTD parsing routine */ +void +printout_motd() +{ + struct page *currp; + int i, j; + for (currp = motdhead; currp; currp = currp->next) + { + for (i = 0; i < currp->nlines; i++) + { + for (j = 0; j < currp->lines[i].nwords; j++) + { + printf("%s ", currp->lines[i].words[j].s); + } + printf("\n"); + } + printf("\014"); + } +} +#endif + + +void +parse_motd() +{ + struct page **currp; + int idx; + + if (motdhead) + return; + + currp = &motdhead; + + idx = 0; + while (idx < motdlen) + { + int validword; + char *wordbegin; + + validword = 1; + + /* skip whitespace */ + while (!isalpha(motdstring[idx]) && motdstring[idx] != '\n' && idx < motdlen) + idx++; + if (idx >= motdlen) + break; + + if (0 == *currp) + { + *currp = malloc(sizeof(**currp)); + (*currp)->nlines = 1; + (*currp)->lines[0].nwords = 0; + (*currp)->next = 0; + } + + if (motdstring[idx] == '\n') + { + idx++; + if (0 == strncmp(&motdstring[idx], "\t@@@", 4)) + break; + else if (0 == strncmp(&motdstring[idx], "\t@@b", 4)) + { + if (*currp) + currp = &(*currp)->next; + idx += 4; + } + else + { + struct line *currl = &(*currp)->lines[(*currp)->nlines - 1]; + currl->words = realloc(currl->words, sizeof(*currl->words) * currl->nwords); + if ((*currp)->nlines >= LINESPERPAGE) + currp = &(*currp)->next; + else + { + (*currp)->lines[(*currp)->nlines].nwords = 0; + (*currp)->nlines++; + } + } + continue; + } + wordbegin = &motdstring[idx]; + while (isalpha(motdstring[idx]) && idx < motdlen) + { +#if 0 + if (!isalpha(motdstring[idx])) + validword = 0; +#endif + idx++; + } + + if (0 && !validword) + continue; + + { + struct line *currl = &(*currp)->lines[(*currp)->nlines - 1]; + int len; + + if (currl->nwords == 0) + { + int size = 40; + int j; + currl->words = malloc(sizeof(struct word) * size); + for (j = 0; j < size; j++) + { + currl->words[j].s = 0; + } + } + len = (&motdstring[idx]) - wordbegin; + currl->words[currl->nwords].s = malloc(len + 1); + strncpy(currl->words[currl->nwords].s, wordbegin, len); + currl->words[currl->nwords].s[len] = 0; + currl->nwords++; + } + } +} +#endif + +/**********************************************************************/ + +char **phrases = 0; +int num_phrases = 0; + +void +parse_clue_phrases() +{ + char *s; + int size; + + if (phrases) + return; + + phrases = (char **) malloc(sizeof(*phrases) * (size = 20)); + + for (s = cluephrase_storage; *s; s += strlen(s) + 1) + { + phrases[num_phrases] = s; + num_phrases++; + if (num_phrases >= size) + phrases = (char **) realloc(phrases, sizeof(*phrases) * (size *= 2)); + } + + phrases = (char **) realloc(phrases, sizeof(*phrases) * num_phrases); +} + +/**********************************************************************/ + + +#define BERATE(msg) pmessage( (msg), me->p_no, MINDIV, " CC") + +/* print the message that tells the person how to respond to the clue check */ +void +remind_cluecheck() +{ + char buf[120]; + BERATE("This is a clue check! You must send yourself the message"); + BERATE(" cluecheck [phrase]"); + if (page >= 0) + { + sprintf(buf, "where [phrase] is the %s word on page %d of the MOTD.", + isfirst ? "first" : "last", page + 1); + } + else + { + /* man, the MOTD had no good words */ + sprintf(buf, "where [phrase] is %s", clueword); + } + BERATE(buf); + if (me->p_cluecountdown > 60) + sprintf(buf, "If you don't answer within %g minutes, you will be kicked out of", me->p_cluecountdown / (60.0 * 10)); + else + sprintf(buf, "If you don't answer within %d seconds, you will be kicked out of", me->p_cluecountdown / 10); + BERATE(buf); + BERATE("the game and publicly humiliated."); +#if 0 + BERATE("If you are a complete newbie, then"); + BERATE("you probably don't even realize that you can read the MOTD while"); + BERATE("playing (shift-M)."); +#endif +} + +/* + * if other methods of getting clue words fail, then we've always got this + * list of words + */ +static char *fallback_cluewords[] = { + + /* terms: */ + "bomb", "ogg", "scum", "stoneage", "scout", "taxi", "base", + "buttorp", "flee", "planet", "star", "warp", "impulse", "hive", + "repair", "shipyard", "fuel", "arable", "metal", "dilithium", + "standard", "thin", "tainted", "toxic", "phaser", "torp", "photon", + "plasma", "missile", "fighter", "tractor", "pressor", + + /* what quarks are made of: */ + "satan", "beer", "jesus", "sex", "cthulhu", + + /* two food groups: */ + /* "grilledcheesesandwich", annoyed too many people */ "ketchup", "caffeine", + + /* the men: */ + /* "a fungusamongus", people have difficulty with this one */ + "Bubbles", "Hammor", "Key", "Kaos", "Lynx", + "Thought", "Brazilian", "Ogre", + + /* the big five: */ + "Paradise", "Arctica", "Aedile", "Eden", "Minuet", + + /* what you are: */ + "twink" +}; + +#define NUM_CLUEWORDS ( sizeof(fallback_cluewords) \ + / sizeof(*fallback_cluewords)) + +/* + * Once in a great while (hour?) the server demands a clue check from the + * player. This makes sure you are paying attention. + */ +void +demand_clue() +{ + clueword[0] = 0; + page = -1; + switch (configvals->cluesource) + { + case CC_MOTD: +#ifdef MOTD_SUPPORT + parse_motd(); + + find_suitable_motd_word(); +#endif + break; + case CC_PHRASE_LIST_FILE: + parse_clue_phrases(); + + if (num_phrases) + { + set_clue_word(phrases[lrand48() % num_phrases]); + } + break; /* uh, NYI */ + case CC_COMPILED_IN_PHRASE_LIST: + break; /* that's actually the fallback case below: */ + } + if (*clueword == 0) /* didn't find one! */ + set_clue_word(fallback_cluewords[lrand48() % NUM_CLUEWORDS]); + + me->p_cluecountdown = configvals->cluetime * TICKSPERSEC; + + remind_cluecheck(); +} + +/* every tick, check the person's clue status */ +void +countdown_clue() +{ + if (me->p_status == POUTFIT || me->p_status == PTQUEUE) + return; + if (me->p_cluedelay > 0) + { + me->p_cluedelay--; + if (me->p_cluedelay < 1 + && (me->p_stats.st_cluesuccess < 25 + || lrand48() % 20 < 1)) + { + /* uhoh, time for another cluecheck */ + demand_clue(); + } + } + else if (me->p_cluecountdown > 0) + { + char buf[120]; + + /* under the gun here */ + me->p_cluecountdown--; + if (me->p_cluecountdown > 0) + return; + + /* uhoh, we have a twink */ + + me->p_status = PEXPLODE; + me->p_explode = 10; + me->p_whydead = KQUIT; + + sprintf(buf, "%s (%s) was blasted out of existence due to terminal", + me->p_name, twoletters(me)); + pmessage(buf, -1, MALL, MSERVA); + pmessage("stupidity (failure to read messages).", -1, MALL, MSERVA); + pmessage("Let this be a lesson to the rest of you twinks!", -1, MALL, MSERVA); + } + else + { + me->p_cluedelay = 40; + } +} + +/* the person sent themselves the message "cluecheck..." */ +int +accept_cluecheck(word) + char *word; +{ + int i; + char buf[120]; + + if (me->p_cluedelay > 0) + { + sprintf(buf, "Don't worry %s. You aren't under a clue check yet.", + me->p_name); + BERATE(buf); + } + else if (*word) + { + for (i = 0; word[i] && clueword[i]; i++) + { + if (tolower(word[i]) != tolower(clueword[i])) + break; + } + + if (word[i] || clueword[i]) + { + sprintf(buf, "Nice try, %s. Guess again. It's not %s.", + me->p_name, word); + BERATE(buf); + BERATE("Send yourself the message `cluecheck' if you need another hint."); + } + else + { + sprintf(buf, "Good show, %s. I won't bother you again for a while.", + me->p_name); + BERATE(buf); + me->p_cluedelay = (configvals->cluedelay / 2) + + lrand48() % (configvals->cluedelay / 2); + me->p_cluedelay *= TICKSPERSEC; + + me->p_stats.st_cluesuccess++; + } + } + else + { + remind_cluecheck(); + } + return 1; +} + +/**********************************************************************/ + +#ifdef MOTD_SUPPORT +void +free_word(wd) + struct word *wd; +{ + free(wd->s); +} + +void +free_line(ln) + struct line *ln; +{ + int i; + for (i = 0; i < ln->nwords; i++) + free_word(&ln->words[i]); + free(ln->words); +} + +void +free_page(pg) + struct page *pg; +{ + int i; + for (i = 0; i < LINESPERPAGE; i++) + { + free_line(&pg->lines[i]); + } +} + +void +free_motdstruct() +{ + struct page *temp; + while (motdhead) + { + temp = motdhead; + motdhead = temp->next; + + free_page(temp); + free(temp); + } +} +#endif + +#endif /* CLUECHECK1 */ + +#ifdef CLUECHECK2 + +/* ---------[ CLUECHECK2 -> Brandons hacked version of CLUECHECK1 ]--------- */ + +/* + * // I munged this (sorry Rob). Using me->p_cluecountdown: // if it is + * 0 you have not been checked yet // if it is 1 your time is up. // + * if it is -1 you should not be checked. // if it is anything greater + * than one you are under the timer + */ + +/* -------------------------[ Globals (eep) ]------------------------- */ + +#define TellLINE { pmessage("", me->p_no, MINDIV, "***! Cluecheck !**! Cluecheck !**! Cluecheck !**! Cluecheck !**! Cluecheck !***"); } + +#define NUM_CLUEWORDS (sizeof(fallback_cluewords) / \ + sizeof(*fallback_cluewords)) +#define CLUE_GETOUTOFIT 7 + +char **phrases = 0; +int num_phrases = 0; +static char clueword[40]; + +/* + * // if other methods of getting clue words fail, then we've always got // + * this list of words + */ + +static char *fallback_cluewords[] = { + /* make it simple, if they want more they can make a .cluecheck file */ + "bomb", "ogg", "scum", "stoneage", "scout", "taxi", "base", + "buttorp", "flee", "planet", "star", "warp", "impulse", "hive", + "repair", "shipyard", "fuel", "arable", "metal", "dilithium", + "standard", "thin", "tainted", "toxic", "phaser", "torp", "photon", + "plasma", "missile", "fighter", "tractor", "pressor", +}; + +/* -------------------------[ Functions ]------------------------- */ + +void +set_clue_word(char *word) +{ + strncpy(clueword, word, sizeof(clueword)); + clueword[sizeof(clueword) - 1] = 0; +} + +void +parse_clue_phrases() +{ + char *s; + int size; + + if (phrases) + return; + + phrases = (char **) malloc(sizeof(*phrases) * (size = 20)); + + for (s = cluephrase_storage; *s; s += strlen(s) + 1) + { + phrases[num_phrases] = s; + num_phrases++; + if (num_phrases >= size) + phrases = (char **) realloc(phrases, sizeof(*phrases) * (size *= 2)); + } + + phrases = (char **) realloc(phrases, sizeof(*phrases) * num_phrases); +} + +/* + * // print the message that tells the person how to respond to the clue + * check + */ +void +remind_cluecheck() +{ + char buf[120]; + + pmessage("", me->p_no, MINDIV, "*******************************************************************************"); + TellLINE; + sprintf(buf, " Send yourself: \"cluecheck %s\"", clueword); + pmessage(buf, me->p_no, MINDIV, ""); + + if (me->p_cluecountdown > (60 * TICKSPERSEC)) + { + sprintf(buf, + " Answer within %.2g minutes or be ejected from the game.", + (me->p_cluecountdown / (60.0 * TICKSPERSEC))); + pmessage(buf, me->p_no, MINDIV, ""); + } + else + { + sprintf(buf, + "** ANSWER ** within %d seconds or be ejected from the game.", + (me->p_cluecountdown / 10)); + pmessage(buf, me->p_no, MINDIV, ""); + } + pmessage("", me->p_no, MINDIV, "*******************************************************************************"); + +} + +/* called the first time */ +void +demand_clue() +{ + char buf[255]; + char syou[32]; + clueword[0] = 0; + + sprintf(syou, "%s->YOU", SERVNAME); + /* higher than rank CLUE_GETOUTOFIT get ... out of it */ + if (me->p_stats.st_rank > CLUE_GETOUTOFIT /* if my rank is high enough */ + || me->p_stats.st_royal == GODLIKE + 1 /* or I'm Q */ ) + { + TellLINE; + pmessage("Due to your ranking status, I will let you off the hook.", + me->p_no, MINDIV, syou); + me->p_cluecountdown = -1; + return; + } + else if (me->p_stats.st_cluesuccess > configvals->cluecheck) + { + TellLINE; + sprintf(buf, "You have passed the cluecheck the required %d times.", + configvals->cluecheck); + pmessage(buf, me->p_no, MINDIV, syou); + me->p_cluecountdown = -1; + return; + } + + parse_clue_phrases(); + + if (num_phrases) + set_clue_word(phrases[lrand48() % num_phrases]); + if (*clueword == 0) /* didn't find one! */ + set_clue_word(fallback_cluewords[lrand48() % NUM_CLUEWORDS]); + me->p_cluecountdown = configvals->cluetime * TICKSPERSEC; + + remind_cluecheck(); +} + + +/* every tick, check the person's clue status */ +void +countdown_clue() +{ + if (me->p_cluecountdown != -1) + { + if (me->p_status == POUTFIT + || me->p_status == PTQUEUE + || me->p_status == POBSERVE) + return; + + /* let bases off the hook */ + if (me->p_ship.s_type == 5 || me->p_ship.s_type == 9) + return; + + if (me->p_cluedelay > 0) + { + me->p_cluedelay--; + return; + } + + /* is it greater than one? */ + if (me->p_cluecountdown > 0) + { + char buf[255]; + + /* under the gun here */ + me->p_cluecountdown--; + + if (me->p_cluecountdown == 150 * TICKSPERSEC + || me->p_cluecountdown == 60 * TICKSPERSEC + || me->p_cluecountdown == 10 * TICKSPERSEC) + { + remind_cluecheck(); + return; + } + + /* is it still greater than 1? */ + else if (me->p_cluecountdown > 0) + return; + + /* uhoh, we have a twink */ + me->p_status = PEXPLODE; + me->p_explode = 10; + me->p_whydead = KQUIT; + me->p_cluecountdown = -1; + + sprintf(buf, "%s (%s) was ejected for failing a cluecheck.", + me->p_name, twoletters(me)); + pmessage(buf, SERVNAME, MALL, " ** CLUECHECK **"); + +#ifdef MAIL_CLUELETTER + sprintf(buf, "%s %s %s", build_path(MAILCLUECHECK), + me->p_login, me->p_full_hostname); + system(buf); +#endif + } + else + { + /* + * they aren't -1, they are greater than 1, so they havn't been checked + * yet + */ + demand_clue(); + } + } +} + + +/* + * // the person sent themselves the message "cluecheck..." // called in + * controls (message.c) + */ +int +accept_cluecheck(char *word) +{ + int i; + char buf[120]; + char syou[32]; + + sprintf(syou, "%s->YOU", SERVNAME); + if (me->p_cluecountdown == -1 || !me->p_cluecountdown) + { + pmessage("You are not under a cluecheck.", + me->p_no, MINDIV, syou); + return; + } + else if (*word) + { + for (i = 0; word[i] && clueword[i]; i++) + { + if (tolower(word[i]) != tolower(clueword[i])) + break; + } + + if (word[i] || clueword[i]) + { + sprintf(buf, "Nice try, guess again. It is not \"%s\".", word); + pmessage(buf, me->p_no, MINDIV, syou); + pmessage( + "Send the message \"cluecheck\" to yourself for another hint.", + me->p_no, MINDIV, syou); + } + else + { + sprintf(buf, + "Good show %s. I won't bother you again for a while.", + me->p_name); + pmessage(buf, me->p_no, MINDIV, syou); + me->p_stats.st_cluesuccess++; + me->p_cluecountdown = -1; + } + } + else + { + remind_cluecheck(); + } + sprintf(buf, "You have passed the cluecheck %d times.", + me->p_stats.st_cluesuccess); + pmessage(buf, me->p_no, MINDIV, syou); + return 1; +} + +#endif /* CLUECHECK2 */