#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 args( ( 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)) { bug ("Arena doesn't exist.",0); 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; } 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 ) { char errmsg[MAX_STRING_LENGTH]; int i; challenge_t *pc; sprintf(errmsg,"Arena Check 3"); log_string( errmsg ); // 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; } /*=======================================================================*/