#include <sys/types.h> #include <sys/time.h> #include <malloc.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <assert.h> #include <ctype.h> #include <time.h> #include "merc.h" DECLARE_DO_FUN(do_look ); #define LESSER(x,y) (((x) < (y)) ? (x) : (y)) #define GREATER(x,y) (((x) > (y)) ? (x) : (y)) #define TEAM_MAX 6 typedef struct _challenge_t { struct _challenge_t *next; int id; int green; int flags; /* CC_???, defined below */ char *team1[TEAM_MAX]; char *team2[TEAM_MAX]; int status1[TEAM_MAX]; int status2[TEAM_MAX]; } challenge_t; /* condition flags */ #define CC_NOPOTIONS 0x001 #define CC_NOSCROLLS 0x002 #define CC_NOWIMPY 0x004 /* status flags */ #define CS_ACCEPT 0x001 #define CS_NORECALL 0x002 #define CS_AFK 0x004 #define CS_CURSE 0x008 // initialize status to CS_INIT // challenge can proceed only when everyone's status is CS_GO #define CS_INIT 0 #define CS_GO CS_ACCEPT challenge_t *chal_head = (challenge_t *) NULL; challenge_t *cur_chal = (challenge_t *) NULL; int challenge_count = 0; int in_current_challenge(char *pname); static int named_in_challenge(char *pname, challenge_t *pchal); static challenge_t *find_challenge(int cnum); static void cleanup_challenge(challenge_t *pchal); static void arena_message(char *message); static void challenge_message(char *message, challenge_t *pchal); static char *challenge_string(challenge_t *pchal, char *msg, int reverse); static char *challenge_flags(challenge_t *pchal); static int player_challenges(char *pname); static int challenge_update(challenge_t *pchal); static void start_duel(challenge_t *pchal); static void challenge_status(int cnum, CHAR_DATA *ch); static int challenge_finished(challenge_t *pchal); static void noncom_check(void); void arena_update( void ); struct _cond { char *keyword; int bit; char *name; char *flag; }; struct _cond cond_table[] = { { "np", CC_NOPOTIONS, "no_potions", "{^P{x" }, { "ns", CC_NOSCROLLS, "no_scrolls", "{!S{x" }, { "nw", CC_NOWIMPY, "no_wimpy", "{$W{x" }, { NULL, 0, NULL, '\0' }, }; /*=======================================================================* * function: arena_update * purpose: called every tick from update.c. check on stuff *=======================================================================*/ void arena_update(void) { challenge_t *pchal, *pnext; char buf[MAX_STRING_LENGTH]; int winner, i; // whichteam; CHAR_DATA *pplayer; // CHAR_DATA *pplayercheck; CHAR_DATA *rch; // update all the individual challenges for (pchal = chal_head; pchal; pchal = pnext) { pnext = pchal->next; challenge_update(pchal); } // scan the arena and boot mortal non-combatants therefrom noncom_check(); // if any challenge is running, see if it's done. You can tell because // one team will be entirely absent from rooms ARENA_LO to ARENA_HI. if ((cur_chal) && ((winner = challenge_finished(cur_chal)))) { // tell everyone about it sprintf(buf, "[{$ARENA{x] Challenge [%d]: ", cur_chal->id); strcat(buf, challenge_string(cur_chal, "DEFEATED ", ((winner == 2)))); strcat(buf, "{x\n\r"); arena_message(buf); // send everyone to lounge for (i = 0; i < (2 * TEAM_MAX); i++) { if (cur_chal->team1[i] == NULL) continue; pplayer = get_char_anyone(NULL, cur_chal->team1[i]); if (pplayer == NULL) continue; for (rch = pplayer->in_room->people; rch != NULL; rch = rch->next_in_room) { if (rch->fighting != NULL) { stop_fighting(rch, TRUE ); } } //Dusk affect_strip(pplayer, skill_lookup("cripple")); affect_strip(pplayer, skill_lookup("siphon energy")); affect_strip(pplayer, skill_lookup("siphon life")); //JLR affect_strip(pplayer, skill_lookup("poison")); affect_strip(pplayer, skill_lookup("chill touch")); affect_strip(pplayer, skill_lookup("fire breath")); affect_strip(pplayer, skill_lookup("slow")); affect_strip(pplayer, skill_lookup("weaken")); affect_strip(pplayer, skill_lookup("curse")); affect_strip(pplayer, skill_lookup("wither")); affect_strip(pplayer, skill_lookup("blindness")); affect_strip(pplayer, skill_lookup("blindness dust")); affect_strip(pplayer, skill_lookup("plague")); affect_strip(pplayer, skill_lookup("shriek")); affect_strip(pplayer, skill_lookup("sleep")); //Tien affect_strip(pplayer, skill_lookup("feeble mind")); affect_strip(pplayer, skill_lookup("dirt kick")); affect_strip(pplayer, skill_lookup("faerie fire")); affect_strip(pplayer, skill_lookup("headache")); affect_strip(pplayer, skill_lookup("adamantium palm")); affect_strip(pplayer, skill_lookup("call lightning")); affect_strip(pplayer, skill_lookup("prismatic spray")); affect_strip(pplayer, skill_lookup("gouge")); affect_strip(pplayer, skill_lookup("charm person")); /* Stheno/Revye */ affect_strip(pplayer, skill_lookup("nerve")); affect_strip(pplayer, skill_lookup("garrote")); affect_strip(pplayer, skill_lookup("fear aura")); affect_strip(pplayer, skill_lookup("burning skin")); affect_strip(pplayer, skill_lookup("smokebomb")); affect_strip(pplayer, skill_lookup("dirt kicking")); affect_strip(pplayer, skill_lookup("voodan curse")); affect_strip(pplayer, skill_lookup("sense vitality")); /* affect_strip(pplayer,skill_lookup("")); */ pplayer->hit = pplayer->max_hit; pplayer->mana = pplayer->max_mana; pplayer->move = pplayer->max_move; //Jair /* This is a hack job to get arena wins and losses working */ /* whichteam=0; for( i = 0; (pchal->team1[i]) && (i<TEAM_MAX); i++ ) { pplayercheck = get_char_anyone( NULL,pchal->team1[i] ); if (pplayercheck == pplayer) whichteam=1; } for( i = 0; (pchal->team1[i]) && (i<TEAM_MAX); i++ ) { pplayercheck = get_char_anyone( NULL,pchal->team1[i] ); if (pplayercheck == pplayer) whichteam=2; } if (whichteam == winner) pplayer->pcdata->awins += 1; else pplayer->pcdata->alosses += 1; */ char_from_room(pplayer); char_to_room(pplayer, get_room_index(ROOM_ARENA_LOUNGE)); act("$n appears in the room.", pplayer, NULL, NULL, TO_ROOM); do_look(pplayer, "auto"); } cleanup_challenge(cur_chal); cur_chal = (challenge_t *) NULL; } // if no challenge is going, look for a green one if (!cur_chal) { for (pchal = chal_head; (pchal) && (!pchal->green); pchal = pchal->next) ; if (pchal) { // we have a green challenge. do it start_duel(pchal); } } } /*=======================================================================* * function: start_duel * purpose: begin a duel. transport everyone to the arena, do everything. *=======================================================================*/ static void start_duel(challenge_t *pchal) { challenge_t *pc; CHAR_DATA *pplayer; char buf[MAX_STRING_LENGTH]; int i, start_pos; ROOM_INDEX_DATA *start1, *start2; assert(pchal); // take pchal off the challenge list if (chal_head == pchal) { // first entry on list chal_head = pchal->next; } else { for (pc = chal_head; (pc->next) && (pc->next != pchal); pc = pc->next) ; if (pc->next == pchal) { pc->next = pchal->next; } else { // not on the list. Bogus. Just return. return; } } // write it to cur_chal cur_chal = pchal; // tell everyone about it sprintf(buf, "[{$ARENA{x] Challenge [%d]%s: ", pchal->id, challenge_flags( pchal)); strcat(buf, challenge_string(pchal, "VERSUS ", FALSE )); strcat(buf, "{Rhas begun!{x\n\r\n\r"); arena_message(buf); start_pos = ROOM_ARENA_LO + 1 + (rand() % (ROOM_ARENA_HI - ROOM_ARENA_LO)); start1 = get_room_index(start_pos); start_pos = ROOM_ARENA_LO + 1 + (rand() % (ROOM_ARENA_HI - ROOM_ARENA_LO)); start2 = get_room_index(start_pos); if ((start1 == NULL) || (start2 == NULL)) { printf_debug("Arena doesn't exist."); cleanup_challenge(pchal); cur_chal = NULL; return; } // here's where we'd send all the people to the arena and stuff for (i = 0; (pchal->team1[i]) && (i < TEAM_MAX); i++) { pplayer = get_char_anyone(NULL, pchal->team1[i]); // pplayer_orig = pplayer; char_from_room(pplayer); char_to_room(pplayer, start1); affect_strip(pplayer, gsn_plague); affect_strip(pplayer, gsn_poison); affect_strip(pplayer, gsn_blindness); affect_strip(pplayer, gsn_sleep); affect_strip(pplayer, gsn_curse); pplayer->hit = pplayer->max_hit; pplayer->mana = pplayer->max_mana; pplayer->move = pplayer->max_move; update_pos(pplayer); send_to_char("You have been Pre-Arena Restored.\n", pplayer); act("$n appears in the room.", pplayer, NULL, NULL, TO_ROOM); do_look(pplayer, "auto"); // send_to_char( "If the arena were working, you'd be sent to the arena " // "now.\n\r", pplayer ); } for (i = 0; (pchal->team2[i]) && (i < TEAM_MAX); i++) { pplayer = get_char_anyone(NULL, pchal->team2[i]); // pplayer_orig = pplayer; char_from_room(pplayer); char_to_room(pplayer, start2); affect_strip(pplayer, gsn_plague); affect_strip(pplayer, gsn_poison); affect_strip(pplayer, gsn_blindness); affect_strip(pplayer, gsn_sleep); affect_strip(pplayer, gsn_curse); pplayer->hit = pplayer->max_hit; pplayer->mana = pplayer->max_mana; pplayer->move = pplayer->max_move; update_pos(pplayer); send_to_char("You have been Pre-Arena Restored.", pplayer); act("$n appears in the room.", pplayer, NULL, NULL, TO_ROOM); do_look(pplayer, "auto"); // send_to_char( "If the arena were working, you'd be sent to the arena " // "now.\n\r", pplayer ); } } /*=======================================================================* * function: do_challenge * purpose: sends initial arena match query *=======================================================================*/ void do_challenge(CHAR_DATA *ch, char *argument) { CHAR_DATA *victim; char buf[MAX_STRING_LENGTH], arg[MAX_INPUT_LENGTH]; int done = FALSE, i; int team = 0; int count = 0; int reuse = FALSE; int hilevel = 0, lowlevel = 0; challenge_t *pchal, *pc; if (IS_NPC(ch)) return; if (arena == FIGHT_LOCK) { send_to_char("Sorry, the arena is currently locked from use.\n\r", ch); return; } if (ch->hit < ch->max_hit * 3 / 4) { send_to_char("You are not healthy enough to fight in the arena.\n\r", ch); return; } if (argument[0] == '{' && argument[1] == '\0') return; if (argument[0] == '-') return; if (argument[0] == '"') return; // challenge block? if (!strcasecmp(argument, "block")) { if (IS_SET(ch->comm,COMM_NOARENA)) { REMOVE_BIT(ch->comm,COMM_NOARENA); send_to_char( "You will now receive arena updates and challenges.\n\r", ch); } else { SET_BIT(ch->comm,COMM_NOARENA); send_to_char( "You will no longer receive arena updates and challenges.\n\r", ch); } return; } // challenge list? if (!strcasecmp(argument, "list")) { if (cur_chal) { sprintf(buf, "Current challenge [%d]%s: ", cur_chal->id, challenge_flags(cur_chal)); strcat(buf, challenge_string(cur_chal, "VERSUS ", FALSE)); strcat(buf, "\n\r"); send_to_char(buf, ch); } if (chal_head) { for (pc = chal_head; pc; pc = pc->next) { sprintf(buf, "{%cChallenge [%d]%s:{x ", pc->green ? 'G' : 'R', pc->id, challenge_flags(pc)); strcat(buf, challenge_string(pc, "VERSUS ", FALSE)); strcat(buf, "\n\r"); send_to_char(buf, ch); } } else send_to_char("No pending challenges.\n\r", ch); return; } // challenge status if (!strncasecmp(argument, "status", 6)) { argument = one_argument(argument, arg); argument = one_argument(argument, arg); if (arg[0] == 0) { send_to_char("Give a challenge number.\n\r", ch); return; } challenge_status(atoi(arg), ch); return; } if (IS_SET(ch->comm,COMM_NOARENA)) { send_to_char("You're configured to ignore the arena.\n\r", ch); return; } if (ch->in_room->vnum == ROOM_VNUM_CORNER) return; if (argument[0] == '\0') { send_to_char( "Usage: challenge [-conditions] <opponent1> [opponent2] ... [with] [teammate1] [teammate2] ....\n\r", ch); return; } // so far so good. allocate. pchal = (challenge_t *) calloc(1L, sizeof(challenge_t)); if (pchal == NULL) return; // write our name to the head of team1 pchal->team1[0] = strdup(ch->name); count = 0; // set challeger accepted pchal->status1[0] |= CS_ACCEPT; // initialize hilevel and lowlevel hilevel = ch->level; lowlevel = ch->level; // now peel off the names, one at a time do { argument = one_argument(argument, arg); // end of args? if (arg[0] == 0) { done = TRUE; continue; } // look for the team separator if ((!strcmp(arg, "with")) && (team == 0)) { if (count == 0) { send_to_char("You need at least one player on the other t" "eam.\n\r", ch); cleanup_challenge(pchal); return; } team++; count = 1; continue; } // condition flag? if (arg[0] == '-') { for (i = 0; cond_table[i].keyword; i++) { if (!strcasecmp(&arg[1], cond_table[i].keyword)) pchal->flags |= cond_table[i].bit; } continue; } // match name victim = get_char_world(ch, arg); // not found? if (victim == NULL) { sprintf(buf, "Bad target: %s\n\r", arg); send_to_char(buf, ch); cleanup_challenge(pchal); return; } // npc, immortal, or self? if (IS_NPC(victim) || victim == ch || victim == NULL) { send_to_char("You cannot challenge NPC's, or yourself.\n\r", ch); cleanup_challenge(pchal); return; } if (victim->hit < victim->max_hit * 2 / 3) { send_to_char( "They are not healthy enough to fight in the arena.\n\r", ch); return; } if (victim->fight_timer > 0) { send_to_char("They cannot fight in the arena right now.\n\r", ch); return; } if (ch->in_room->area->continent != victim->in_room->area->continent) { send_to_char("They are too far away to arena.\n\r", ch); return; } for (i = 0; (pchal->team1[i]) && (i < TEAM_MAX); i++) if (!strcmp(victim->name, pchal->team1[i])) reuse = TRUE; for (i = 0; (pchal->team2[i]) && (i < TEAM_MAX); i++) if (!strcmp(victim->name, pchal->team2[i])) reuse = TRUE; // already named? if (reuse) { send_to_char( "Each player can be named only once in a given challenge.\n\r", ch); cleanup_challenge(pchal); return; } // noarena? if (IS_SET(victim->comm,COMM_NOARENA)) { sprintf(buf, "%s is blocking all challenges.\n\r", victim->name); send_to_char(buf, ch); cleanup_challenge(pchal); return; } // named in too many? if (player_challenges(victim->name) >= 4) { sprintf(buf, "%s is already named in four challenges. That's" " the limit.\n\r", victim->name); send_to_char(buf, ch); return; } // team full? if (count >= TEAM_MAX) { send_to_char("Team size limit exceeded.\n\r", ch); cleanup_challenge(pchal); return; } hilevel = GREATER(hilevel,victim->level); lowlevel = LESSER(hilevel,victim->level); // level range if ((hilevel - lowlevel > 20) && (!IS_IMMORTAL(ch))) { send_to_char( "All players in a challenge must be within 20 levels of one another.\n\r", ch); cleanup_challenge(pchal); return; } if (team) { pchal->status1[count] = CS_INIT; pchal->team1[count++] = strdup(victim->name); } else { pchal->status2[count] = CS_INIT; pchal->team2[count++] = strdup(victim->name); } } while (!done); // valid challenge. Move on. // get an available challenge number pchal->id = ++challenge_count; // add challenge to the queue if (chal_head) { // walk list, append to end for (pc = chal_head; pc->next; pc = pc->next) ; pc->next = pchal; } else { // no entries on list chal_head = pchal; } // announce it sprintf(buf, "[{$ARENA{x] Challenge [%d] issued! ", pchal->id); strcat(buf, challenge_string(pchal, "VERSUS ", FALSE)); strcat(buf, "\n\r"); strcat(buf, "Special Conditions:"); if (pchal->flags) { for (i = 0; cond_table[i].keyword; i++) { if (pchal->flags & cond_table[i].bit) { strcat(buf, " "); strcat(buf, cond_table[i].name); } } } else { strcat(buf, " None"); } strcat(buf, "\n\r"); arena_message(buf); } /*=======================================================================* * function: do_accept * * purpose: to accept the arena match, and move the players to the arena * *=======================================================================*/ void do_accept(CHAR_DATA *ch, char *argument) { int cnum, index; char buf[MAX_STRING_LENGTH]; challenge_t *pc; if (argument[0] == '\0') { send_to_char("Accept challenges by number.\n\r", ch); return; } if (ch->fight_timer > 0) { send_to_char( "You cannot fight in the arena until your fight timer expires.\n\r", ch); return; } cnum = atoi(argument); pc = find_challenge(cnum); if (!pc) { send_to_char("No such challenge.\n\r", ch); return; } if (!(index = named_in_challenge(ch->name, pc))) { send_to_char("You're not named in that challenge.\n\r", ch); return; } // already accepted? if (pc->status1[index - 1] & CS_ACCEPT) { send_to_char("You've already accepted that challenge.\n\r", ch); return; } sprintf(buf, "[{$ARENA{x] Challenge %d accepted by %s.\n\r", cnum, ch->name); arena_message(buf); pc->status1[index - 1] |= CS_ACCEPT; // if this results in the challenge going green, do an update, so that // the challenge may launch immediately. if (challenge_update(pc)) { arena_update(); } return; } /*=======================================================================* * function: do_decline * * purpose: to chicken out from a sent arena challenge * *=======================================================================*/ void do_decline(CHAR_DATA *ch, char *argument) { int cnum; char buf[MAX_STRING_LENGTH]; challenge_t *pc; if (argument[0] == '\0') { send_to_char("Decline challenges by number.\n\r", ch); return; } cnum = atoi(argument); pc = find_challenge(cnum); if (!pc) { send_to_char("No such challenge.\n\r", ch); return; } if ((!named_in_challenge(ch->name, pc)) && (!IS_IMMORTAL(ch))) { send_to_char("You're not named in that challenge.\n\r", ch); return; } sprintf(buf, "[{$ARENA{x] Challenge %d declined by %s.\n\r", cnum, ch->name); arena_message(buf); cleanup_challenge(pc); return; } /*======================================================================* * function: do_bet * * purpose: to allow players to wager on the outcome of arena battles * *======================================================================*/ void do_bet(CHAR_DATA *ch, char *argument) { return; } /*=======================================================================* * function: in_current_challenge * purpose: returns 0 if player isn't in current challenge (or if there * isn't one.) Returns 1 if he's on team 1, 2 if he's on team 2 *=======================================================================*/ int in_current_challenge(char *pname) { int index; index = named_in_challenge(pname, cur_chal); if (index > TEAM_MAX) return 2; if (index) return 1; return 0; } /*=======================================================================* * function: named_in_challenge * * purpose: returns TRUE if pname is named in challenge pchal * *=======================================================================*/ static int named_in_challenge(char *pname, challenge_t *pchal) { int i; if (pchal == (challenge_t *) NULL) return 0; for (i = 0; (pchal->team1[i]) && (i < TEAM_MAX); i++) if (!strcasecmp(pname, pchal->team1[i])) return i + 1; for (i = 0; (pchal->team2[i]) && (i < TEAM_MAX); i++) if (!strcasecmp(pname, pchal->team2[i])) return i + 1 + TEAM_MAX; return FALSE; } /*=======================================================================* * function: player_challenges * purpose: counts the number of challenges in which a player is named *=======================================================================*/ static int player_challenges(char *pname) { challenge_t *pc; int count = 0; for (pc = chal_head; pc; pc = pc->next) { if (named_in_challenge(pname, pc)) count++; } return count; } /*=======================================================================* * function: find_challenge * purpose: returns a pointer to the challenge with id cnum, NULL if none *=======================================================================*/ static challenge_t *find_challenge(int cnum) { challenge_t *pc; for (pc = chal_head; pc; pc = pc->next) if (pc->id == cnum) return pc; return (challenge_t *) NULL; } /*=======================================================================* * function: arena_message * purpose: send message to everyone who isn't NO_ARENA *=======================================================================*/ static void arena_message(char *message) { DESCRIPTOR_DATA *d; for (d = descriptor_list; d; d = d->next) { if ((d->connected == CON_PLAYING) && (!IS_SET(d->character->comm,COMM_NOARENA))) send_to_char(message, d->character); } } /*=======================================================================* * function: challenge_message * purpose: send message to everyone named in a given challenge *=======================================================================*/ static void challenge_message(char *message, challenge_t *pchal) { int team, count; CHAR_DATA *pplayer; char **names; // int *status; // loop through the players for (team = 0; team < 2; team++) { names = (team) ? pchal->team2 : pchal->team1; // status = (team) ? pchal->status2 : pchal->status1; for (count = 0; (count < TEAM_MAX) && (names[count]); count++) { // match name pplayer = get_char_anyone(NULL, names[count]); // connected? if (pplayer != NULL) send_to_char(message, pplayer); } } } /*=======================================================================* * function: challenge_status * purpose: send status of challenge number cnum to player ch *=======================================================================*/ static void challenge_status(int cnum, CHAR_DATA *ch) { challenge_t *pc; char buf[MAX_STRING_LENGTH]; CHAR_DATA *pplayer; int i; pc = find_challenge(cnum); if (pc == NULL) { send_to_char("No such challenge.\n\r", ch); return; } // print the title line sprintf(buf, "{%cChallenge [%d]:{x ", pc->green ? 'G' : 'R', pc->id); strcat(buf, challenge_string(pc, "VERSUS ", FALSE)); strcat(buf, "\n\r"); strcat(buf, "Special Conditions:"); if (pc->flags) { for (i = 0; cond_table[i].keyword; i++) { if (pc->flags & cond_table[i].bit) { strcat(buf, " "); strcat(buf, cond_table[i].name); } } } else { strcat(buf, " None"); } strcat(buf, "\n\r"); send_to_char(buf, ch); if (pc->green) { send_to_char("Challenge is {GREADY{x.\n\r", ch); return; } send_to_char("Challenge is {RBLOCKED{x because:\n\r", ch); // now list each problem for (i = 0; i < 2 * TEAM_MAX; i++) { if (!(pc->team1[i])) continue; // match the player pplayer = get_char_anyone(NULL, pc->team1[i]); // player found? (should never happen) if (pplayer == NULL) { sprintf(buf, "> %s isn't connected.\n\r", pplayer->name); send_to_char(buf, ch); } // hasn't accepted? if (!(pc->status1[i] & CS_ACCEPT)) { sprintf(buf, "> %s hasn't accepted yet.\n\r", pplayer->name); send_to_char(buf, ch); } // cursed? if (pc->status1[i] & CS_CURSE) { sprintf(buf, "> %s hasn't accepted yet.\n\r", pplayer->name); send_to_char(buf, ch); } // afk? if (pc->status1[i] & CS_AFK) { sprintf(buf, "> %s is AFK.\n\r", pplayer->name); send_to_char(buf, ch); } // no-recall? if (pc->status1[i] & CS_NORECALL) { sprintf(buf, "> %s is in a no-recall area.\n\r", pplayer->name); send_to_char(buf, ch); } } } /*=======================================================================* * function: cleanup_challenge * purpose: frees all memory associated with a given challenge and * removes it from the queue *=======================================================================*/ static void cleanup_challenge(challenge_t *pchal) { int i; challenge_t *pc; printf_debug( "Arena check 3"); // free up names for (i = 0; (pchal->team1[i]) && (i < TEAM_MAX); i++) { free(pchal->team1[i]); pchal->team1[i] = NULL; } for (i = 0; (pchal->team2[i]) && (i < TEAM_MAX); i++) { free(pchal->team2[i]); pchal->team2[i] = NULL; } // take it off the list (if it's on) if (chal_head == pchal) { // first entry on list chal_head = pchal->next; } else if (chal_head) { for (pc = chal_head; (pc->next) && (pc->next != pchal); pc = pc->next) ; if (pc->next == pchal) pc->next = pchal->next; } // now free the challenge itself free(pchal); return; } /*=======================================================================* * function: challenge_string * purpose: write a brief description of a challenge to a static buffer * and return a pointer thereto. *=======================================================================*/ static char *challenge_string(challenge_t *pchal, char *msg, int reverse) { static char buf[MAX_STRING_LENGTH]; int i; char **first, **second; if (reverse) { first = pchal->team2; second = pchal->team1; } else { first = pchal->team1; second = pchal->team2; } buf[0] = '\0'; // announce it for (i = 0; (first[i]) && (i < TEAM_MAX); i++) { strcat(buf, first[i]); strcat(buf, " "); } strcat(buf, msg); for (i = 0; (second[i]) && (i < TEAM_MAX); i++) { strcat(buf, second[i]); strcat(buf, " "); } return buf; } /*=======================================================================* * function: challenge_flags * purpose: write a short string containing challenge flags *=======================================================================*/ static char *challenge_flags(challenge_t *pchal) { static char buf[MAX_STRING_LENGTH]; int i = 0, j; sprintf(buf, "{x("); for (j = 0; cond_table[j].keyword; j++) { if (pchal->flags & cond_table[j].bit) { strcat(buf, cond_table[j].flag); i++; } } strcat(buf, ")"); if (i == 0) buf[0] = '\0'; return buf; } /*=======================================================================* * function: challenge_update * purpose: updates the status bits of a given challenge * returns TRUE if the challenge goes green as of this update *=======================================================================*/ static int challenge_update(challenge_t *pchal) { static char buf[MAX_STRING_LENGTH]; int team, count; CHAR_DATA *pplayer; char **names; int *status; int green, retval = FALSE; green = TRUE; // loop through the players for (team = 0; team < 2; team++) { names = (team) ? pchal->team2 : pchal->team1; status = (team) ? pchal->status2 : pchal->status1; for (count = 0; (count < TEAM_MAX) && (names[count]); count++) { // match name pplayer = get_char_anyone(NULL, names[count]); // connected? if (pplayer == NULL) { sprintf(buf, "Challenge [%d] expires - %s has quit.\n", pchal->id, names[count]); challenge_message(buf, pchal); cleanup_challenge(pchal); return FALSE; } // no recall? if (IS_SET(pplayer->in_room->room_flags,ROOM_NO_RECALL)) status[count] |= CS_NORECALL; else status[count] &= ~CS_NORECALL; // afk? if (IS_SET(pplayer->comm,COMM_AFK)) status[count] |= CS_AFK; else status[count] &= ~CS_AFK; // curse? if (IS_AFFECTED(pplayer,AFF_CURSE)) status[count] |= CS_CURSE; else status[count] &= ~CS_CURSE; // still green? if (status[count] != CS_GO) green = FALSE; } } if (green != pchal->green) { sprintf(buf, "Challenge [%d] is now %s.\n", pchal->id, green ? "{GREADY{x" : "{RBLOCKED{x"); challenge_message(buf, pchal); if (green) retval = TRUE; } pchal->green = green; return retval; } /*=======================================================================* * function: challenge_finished * purpose: returns 0 if challenge isn't done yet, 1 if team 1 won, 2 if * team 2 won. *=======================================================================*/ static int challenge_finished(challenge_t *pchal) { int i, found; CHAR_DATA *pc; found = FALSE; // is team 1 entirely absent from rooms ARENA_LO to ARENA_HI? for (i = 0; (pchal->team1[i]) && (i < TEAM_MAX) && (!found); i++) { pc = get_char_anyone(NULL, pchal->team1[i]); if ((pc) && (pc->in_room->vnum >= ROOM_ARENA_LO) && (pc->in_room->vnum <= ROOM_ARENA_HI)) found = TRUE; } if (!found) return 2; found = FALSE; // is team 2 entirely absent from rooms ARENA_LO to ARENA_HI? for (i = 0; (pchal->team2[i]) && (i < TEAM_MAX) && (!found); i++) { pc = get_char_anyone(NULL, pchal->team2[i]); if ((pc) && (pc->in_room->vnum >= ROOM_ARENA_LO) && (pc->in_room->vnum <= ROOM_ARENA_HI)) found = TRUE; } if (!found) return 1; return 0; } /*=======================================================================* * function: noncom_check * purpose: scan arena for mortals who shouldn't be there & remove them. *=======================================================================*/ static void noncom_check(void) { DESCRIPTOR_DATA *d; for (d = descriptor_list; d; d = d->next) { // ignore them if they're disconnected if (d->connected != CON_PLAYING) continue; // ignore them if they're not in the arena if ((d->character->in_room->vnum < ROOM_ARENA_LO) || (d->character->in_room->vnum > ROOM_ARENA_MORGUE)) continue; // ignore if they're in the arena lounge if (d->character->in_room->vnum == ROOM_ARENA_LOUNGE) continue; // ignore them if they're named in the current challenge if ((cur_chal) && (named_in_challenge(d->character->name, cur_chal))) continue; // let immortals hang around if they want if (IS_IMMORTAL(d->character)) continue; // boot 'em to lounge send_to_char("You've been auto-removed from the arena.\n\r", d->character); char_from_room(d->character); char_to_room(d->character, get_room_index(ROOM_ARENA_LOUNGE)); act("$n appears in the room.", d->character, NULL, NULL, TO_ROOM); do_look(d->character, "auto"); } } /*=======================================================================* * function: arena_can_quaff * purpose: returns FALSE if ch is in arena during a challenge that forbids * use of potions, true otherwise *=======================================================================*/ int arena_can_quaff(CHAR_DATA *ch) { if (!cur_chal) return TRUE; if (!IN_ARENA(ch)) return TRUE; if (!(cur_chal->flags & CC_NOPOTIONS)) return TRUE; send_to_char("No potions may be used during this duel.\n\r", ch); return FALSE; } /*=======================================================================* * function: arena_can_recite * purpose: returns FALSE if ch is in arena during a challenge that forbids * use of scrolls, true otherwise *=======================================================================*/ int arena_can_recite(CHAR_DATA *ch) { if (!cur_chal) return TRUE; if (!IN_ARENA(ch)) return TRUE; if (!(cur_chal->flags & CC_NOSCROLLS)) return TRUE; send_to_char("No scrolls may be used during this duel.\n\r", ch); return FALSE; } /*=======================================================================* * function: arena_can_wimpy * purpose: returns FALSE if ch is in arena during a challenge that forbids * use of wimpy, true otherwise *=======================================================================*/ int arena_can_wimpy(CHAR_DATA *ch) { if (!cur_chal) return TRUE; if (!IN_ARENA(ch)) return TRUE; if (!(cur_chal->flags & CC_NOWIMPY)) return TRUE; return FALSE; } /*=======================================================================*/