// gquest.c #include <sys/types.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include "merc.h" #include "mob_cmds.h" #include "gquest.h" #include "gdl.h" #include "interp.h" DECLARE_DO_FUN( do_say ); ROOM_INDEX_DATA *find_location args( ( CHAR_DATA *ch, char * arg ) ); /* * TODO: * * - * Make mobprog ifcheck for quest step to prevent multiple messages/rewards * and to make more customized messages for greetings * - * Create OLC for creating a new quest * - * Make quest step text modifyable with text data,no more helps */ BEGIN_ELE_LIST(QUEST) STR(name) STR(long_name) STR(description) INT(min_level) INT(steps) INT(reward_qps) INT(reward_gold) INT(reward_obj) INT(number) END_ELE_LIST QUEST *quest_list; /* * load_gquest_text() * * Loads the list into mem */ void load_quest() { LOAD_LIST(quest_list, QUEST, QUEST_FILE); return; } void cmd_gquest(CHAR_DATA * ch, char *argument) { char buf[MSL]; char bufx[MSL]; QUEST * p; QUEST * g; stc("You read your joruanal a little...\n\n", ch); for (p = quest_list; p ; p = p->next) { g = quest_lookup(p->name); if (ch->gquest[g->number] >= 1) { sprintf(buf, "--- {w%s{x\n--- {g%s\n",p->long_name, p->description); stc(buf, ch); if (ch->gquest[g->number] >= 1) { stc(" {WUpdate{g: ", ch); sprintf(bufx, "_%s_%d", p->name, ch->gquest[g->number]); do_help(ch, bufx); stc("\n", ch); } } } return; } /* * do_mpstartquest() * * Begins a quest for a character * * Mobprog keyword: startquest questname $n */ void do_mpstartquest(CHAR_DATA * ch, char *argument) { char arg[MAX_INPUT_LENGTH]; char arg1[MAX_INPUT_LENGTH]; char buf[MSL]; CHAR_DATA *victim; QUEST * questnum; argument = one_argument (argument, arg); argument = one_argument (argument, arg1); log_string("mpstartquest being called"); if (arg[0] == '\0' || arg1[0] == '\0') { bug ("mpstartquest - Bad syntax from vnum %d. Not enough arguments", IS_NPC (ch) ? ch->pIndexData->vnum : 0); return; } questnum = quest_lookup(arg); if (questnum == NULL) { bug ("mpstartquest - Bad syntax from vnum %d. Invalid quest", IS_NPC (ch) ? ch->pIndexData->vnum : 0); return; } if ((victim = get_char_room (ch, arg1)) == NULL) { bug ("mpstartquest - Bad syntax from vnum %d. Null Victim", IS_NPC (ch) ? ch->pIndexData->vnum : 0); return; } sprintf(buf, "mpstartquest: I finished god damn it!"); log_string(buf); /* * best way i can cancel it out is to prevent multiple starts... */ if (victim->gquest[questnum->number] != 0) { do_say(ch, "I'm sorry, but You cannot start this quest agaian.\n"); return; } victim->gquest[questnum->number] = 1; } /* * do_mp_queststep() * * Increment's the steps of the given quest by 1 * * Mobprog keyword: quest_increment questname $n step# * * example: quest_step gilly $n 4 * steps gilly quest to step 4 */ void do_mp_queststep(CHAR_DATA * ch, char *argument) { char arg[MAX_INPUT_LENGTH]; char arg1[MAX_INPUT_LENGTH]; char arg2[MSL]; CHAR_DATA *victim; QUEST * questnum; int step; argument = one_argument (argument, arg); argument = one_argument (argument, arg1); argument = one_argument (argument, arg2); log_string("do_mp_queststep being called"); if (arg[0] == '\0' || arg1[0] == '\0' || arg2[0] == '\0') { bug ("do_mp_queststep - Bad syntax from vnum %d. Not enough arguments", IS_NPC (ch) ? ch->pIndexData->vnum : 0); return; } questnum = quest_lookup(arg); if (questnum == NULL ) { bug ("do_mp_queststep - Bad syntax from vnum %d. Invalid quest", IS_NPC (ch) ? ch->pIndexData->vnum : 0); return; } if ((victim = get_char_room (ch, arg1)) == NULL) { bug ("do_mp_queststept - Bad syntax from vnum %d. Null Victim", IS_NPC (ch) ? ch->pIndexData->vnum : 0); return; } step = atoi(arg2); victim->gquest[questnum->number] = step; } /* * do_mp_setquest() * * Sets mobile's "Quest" to specific quest. This is used for the onstep if check because * For the life of me, I couldn't figure out how to add another argument to the * if check system. Bleh. So this is a hack. Plain and simple. * * Syntax: quest_setquest <quest> * Example: quest_setquest gilly */ void do_mp_setquest (CHAR_DATA * ch, char *argument) { char arg[MAX_INPUT_LENGTH]; QUEST * questnum; argument = one_argument (argument, arg); if (arg[0] == '\0') { bug ("ddo_mp_setquest - Bad syntax from vnum %d. Not enough arguments", IS_NPC (ch) ? ch->pIndexData->vnum : 0); return; } questnum = quest_lookup(arg); if (questnum == NULL ) { bug ("do_mp_queststep - Bad syntax from vnum %d. Invalid quest", IS_NPC (ch) ? ch->pIndexData->vnum : 0); return; } free_string(ch->quest_number_mp); ch->quest_number_mp = str_dup(questnum->name); } /* * do_mp_questreward() * * Doles out the quest rewards and ends scripts for given quest * * Mobprog keyword: questreward questname $n * * example: questreward gilly $n */ void do_mp_questreward(CHAR_DATA * ch, char *argument) { char arg[MAX_INPUT_LENGTH]; char arg1[MAX_INPUT_LENGTH]; CHAR_DATA *victim; QUEST * questnum; argument = one_argument (argument, arg); argument = one_argument (argument, arg1); log_string("do_mp_questreward being called"); if (arg[0] == '\0' || arg1[0] == '\0') { bug ("do_mp_questreward - Bad syntax from vnum %d. Not enough arguments", IS_NPC (ch) ? ch->pIndexData->vnum : 0); return; } questnum = quest_lookup(arg); if (questnum == NULL ) { bug ("do_mp_questreward - Bad syntax from vnum %d. Invalid quest", IS_NPC (ch) ? ch->pIndexData->vnum : 0); return; } if ((victim = get_char_room (ch, arg1)) == NULL) { bug ("do_mp_questrewardt - Bad syntax from vnum %d. Null Victim", IS_NPC (ch) ? ch->pIndexData->vnum : 0); return; } /* TODO: Add in Object reward */ victim->gold += questnum->reward_gold; victim->quest_curr += questnum->reward_qps; victim->quest_accum += questnum->reward_qps; return; } /* * quest_lookup() * * Looks up quest based on name. * Uses INTERNAL name */ QUEST *quest_lookup (char *keyword) { QUEST * pQuest; char temp[MIL], argall[MIL]; argall[0] = '\0'; while (keyword[0] != '\0') { keyword = one_argument (keyword, temp); if (argall[0] != '\0') strcat (argall, " "); strcat (argall, temp); } for (pQuest = quest_list; pQuest; pQuest = pQuest->next) { if (is_name (argall, pQuest->name)) return pQuest; } return NULL; } void cmd_gquest2 (CHAR_DATA * ch, char *argument) { QUEST * p; char buf[MSL]; if (argument[0] == 'S') { for (p = quest_list; p ; p = p->next) { sprintf(buf, "%s\n", p->name); stc(buf, ch); } } p = malloc(sizeof(QUEST)); p->name = argument; p->long_name = "no long name"; p->description = "No description"; p->min_level = 1; p->steps = 1; p->reward_qps = 0; p->reward_gold = 0; p->reward_obj = 0; p->next = quest_list; quest_list = p; SAVE_LIST(quest_list, QUEST, QUEST_FILE); return; } /* * check_queststep() * * Returns true if Queststep == Number */ bool check_queststep (CHAR_DATA * ch, CHAR_DATA * mob) { QUEST * qst; int quest_number; qst = quest_lookup(mob->quest_number_mp); if (qst == NULL) return FALSE; quest_number = qst->number; if (quest_number == ch->gquest[qst->number]) return TRUE; else return FALSE; return FALSE; } /* * qedit_new() * * Creates a new quest */ QEDIT (qedit_new) { QUEST * p; char arg[MSL]; char fullarg[MSL]; strcpy (fullarg, argument); argument = one_argument (argument, arg); p = malloc(sizeof(QUEST)); p->name = argument; p->long_name = "none"; p->min_level = 0; p->steps = 0; p->reward_qps = 0; p->reward_gold = 0; p->reward_obj = 0; p->next = quest_list; quest_list = p; SAVE_LIST(quest_list, QUEST, QUEST_FILE); return FALSE; } /****************************** * Questmaster */ struct reward_type { char *name; char *keyword; int cost; bool object; int value; void * where; }; struct quest_desc_type { char *name; char *long_descr; char *short_descr; }; /* Descriptions of quest items go here: Format is: "keywords", "Short description", "Long description" */ const struct quest_desc_type quest_desc[] = { { "quest vandagard amulet", "The amulet of Vandagard is on the ground here, waiting to be returned to its owner." "The amulet of Vandagard"}, { "quest vandagard ring", "The ring of Vandagard is on the ground here, waiting to be returned to its owner." "The ring of Vandagard"}, { "quest vandagard bracer", "The bracer of Vandagard is on the ground here, waiting to be returned to its owner." "The bracer of Vandagard"}, { "quest vandagard crown", "The crown of Vandagard is on the ground here, waiting to be returned to its owner." "The crown of Vandagard"}, { "quest vandagard cloak", "The cloak of Vandagard is on the ground here, waiting to be returned to its owner." "The cloak of Vandagard"}, {NULL, NULL, NULL} }; /* Local functions */ /* The main quest function */ void do_quest(CHAR_DATA *ch, char *argument) { CHAR_DATA *questman; OBJ_DATA *obj=NULL, *obj_next; OBJ_INDEX_DATA *questinfoobj; MOB_INDEX_DATA *questinfo; char buf [MAX_STRING_LENGTH]; char arg1 [MAX_INPUT_LENGTH]; char arg2 [MAX_INPUT_LENGTH]; int i; /* Add your rewards here. Works as follows: "Obj name shown when quest list is typed", "keywords for buying", "Amount of quest points", Does it load an object?, IF it loads an object, then the vnum, otherwise a value to set in the next thing, This is last field is a part of the char_data to be modified */ const struct reward_type reward_table[]= { { "350,000 Gold Pieces", "500,000 gold", 50, FALSE, 500000, &ch->gold}, { "1 Practice", "practice", 50, FALSE, 1, &ch->practice}, { NULL, NULL, 0, FALSE, 0, 0 } /* Never remove this!!! */ }; argument = one_argument(argument, arg1); argument = one_argument(argument, arg2); if(IS_NPC(ch)) { send_to_char("NPC's can't quest.\n\r",ch); return; } if (arg1[0] == '\0') { send_to_char("Quest commands: Info, Time, Resign, Request, Complete, Quit, List, and Buy.\n\r",ch); send_to_char("For more information, type 'Help Quest'.\n\r",ch); return; } if (!strcmp(arg1, "info")) { if (IS_SET(ch->act,PLR_QUESTING)) { if (ch->questmob == -1 && ch->questgiver->short_descr != NULL) { sprintf(buf,"Your quest is ALMOST complete!\n\rGet back to %s before your time runs out!\n\r",ch->questgiver->short_descr); send_to_char(buf, ch); } else if (ch->questobj > 0) { questinfoobj = get_obj_index(ch->questobj); if (questinfoobj != NULL) { sprintf(buf,"You are on a quest to recover the fabled %s!\n\r",questinfoobj->name); send_to_char(buf, ch); } else send_to_char("You aren't currently on a quest.\n\r",ch); return; } else if (ch->questmob > 0) { questinfo = get_mob_index(ch->questmob); if (questinfo != NULL) { sprintf(buf,"You are on a quest to slay the dreaded %s!\n\r",questinfo->short_descr); send_to_char(buf, ch); } else send_to_char("You aren't currently on a quest.\n\r",ch); return; } } else send_to_char("You aren't currently on a quest.\n\r",ch); return; } else if (!strcmp(arg1, "time")) { if (!IS_SET(ch->act,PLR_QUESTING)) { send_to_char("You aren't currently on a quest.\n\r",ch); if (ch->nextquest > 1) { sprintf(buf,"There are %d minutes remaining until you can go on another quest.\n\r",ch->nextquest); send_to_char(buf, ch); } else if (ch->nextquest == 1) { sprintf(buf, "There is less than a minute remaining until you can go on another quest.\n\r"); send_to_char(buf, ch); } } else if (ch->countdown > 0) { sprintf(buf, "Time left for current quest: %d\n\r",ch->countdown); send_to_char(buf, ch); } return; } else if (!strcmp(arg1, "resign")) { if (!IS_SET(ch->act,PLR_QUESTING)) { stc("You are not currently on a quest!\n", ch); } else { stc("You hang your head in failure.\n", ch); REMOVE_BIT(ch->act,PLR_QUESTING); ch->nextquest = 3; ch->questgiver = NULL; ch->countdown = 0; ch->questmob = 0; ch->questobj = 0; return; } return; } for ( questman = ch->in_room->people; questman != NULL; questman = questman->next_in_room ) { if (!IS_NPC(questman)) continue; if (questman->spec_fun == spec_lookup( "spec_quest_master" )) break; } if (questman == NULL || questman->spec_fun != spec_lookup("spec_quest_master" )) { send_to_char("You can't do that here.\n\r",ch); return; } if ( questman->fighting != NULL) { send_to_char("Wait until the fighting stops.\n\r",ch); return; } ch->questgiver = questman; if (!strcmp(arg1, "list")) { act("$n asks $N for a list of quest items.", ch, NULL, questman, TO_ROOM); act ("You ask $N for a list of quest items.",ch, NULL, questman, TO_CHAR); send_to_char("Current Quest Items available for Purchase:\n\r", ch); if(reward_table[0].name == NULL) send_to_char(" Nothing.\n\r",ch); else { send_to_char(" [{WCost{w] [{BName{w]\n\r",ch); for(i=0;reward_table[i].name != NULL;i++) { sprintf(buf," {W%-4d{w {b%s{w\n\r" ,reward_table[i].cost,reward_table[i].name); send_to_char(buf, ch); } } send_to_char("\n\rTo buy an item, type 'Quest buy <item>'.\n\r",ch); return; } else if (!strcmp(arg1, "buy")) { bool found=FALSE; if (arg2[0] == '\0') { send_to_char("To buy an item, type 'Quest buy <item>'.\n\r",ch); return; } /* Use keywords rather than the name listed in qwest list */ /* Do this to avoid problems with something like 'qwest buy the' */ /* And people getting things they don't want... */ for(i=0;reward_table[i].name != NULL;i++) if (is_name(arg2, reward_table[i].keyword)) { found = TRUE; if (ch->quest_curr >= reward_table[i].cost) { ch->quest_curr -= reward_table[i].cost; if(reward_table[i].object) obj = create_object(get_obj_index(reward_table[i].value),ch->level); else { sprintf(buf,"In exchange for %d quest points, %s gives you %s.\n\r", reward_table[i].cost, questman->short_descr, reward_table[i].name ); send_to_char(buf, ch); *(int *)reward_table[i].where += reward_table[i].value; } break; } else { sprintf(buf, "Sorry, %s, but you don't have enough quest points for that.",ch->name); do_say(questman,buf); return; } } if(!found) { sprintf(buf, "I don't have that item, %s.",ch->name); do_say(questman, buf); } if (obj != NULL) { sprintf(buf,"In exchange for %d quest points, %s gives you %s.\n\r", reward_table[i].cost, questman->short_descr, obj->short_descr); send_to_char(buf, ch); obj_to_char(obj, ch); } return; } else if (!strcmp(arg1, "request")) { act("$n asks $N for a quest.", ch, NULL, questman, TO_ROOM); act("You ask $N for a quest.",ch, NULL, questman, TO_CHAR); if (IS_SET(ch->act,PLR_QUESTING)) { sprintf(buf, "But you're already on a quest!"); do_say(questman, buf); return; } if (ch->nextquest > 0) { sprintf(buf, "You're very brave, %s, but let someone else have a chance.",ch->name); do_say(questman, buf); sprintf(buf, "Come back later."); do_say(questman, buf); return; } sprintf(buf, "Thank you, brave %s!",ch->name); if (!IS_SET(ch->act,PLR_QUESTING)) do_say(questman, buf); ch->questmob = 0; ch->questobj = 0; generate_quest(ch, questman); if (ch->questmob > 0 || ch->questobj > 0) { ch->countdown = number_range(5,10); SET_BIT(ch->act,PLR_QUESTING); sprintf(buf, "You have %d minutes to complete this quest.",ch->countdown); do_say(questman, buf); sprintf(buf, "May the gods go with you!"); do_say(questman, buf); } return; } else if (!strcmp(arg1, "complete")) { act("$n informs $N $e has completed $s quest.", ch, NULL, questman, TO_ROOM); act("You inform $N you have completed $s quest.",ch, NULL, questman, TO_CHAR); if (ch->questgiver != questman) { sprintf(buf, "I never sent you on a quest! Perhaps you're thinking of someone else."); do_say(questman,buf); return; } if (IS_SET(ch->act,PLR_QUESTING)) { bool obj_found = FALSE; if (ch->questobj > 0 && ch->countdown > 0) { for (obj = ch->carrying; obj != NULL; obj= obj_next) { obj_next = obj->next_content; if (obj != NULL && obj->pIndexData->vnum == ch->questobj) { obj_found = TRUE; break; } } } if ((ch->questmob == -1 || (ch->questobj && obj_found)) && ch->countdown > 0) { int reward, pointreward; reward = number_range(50,100); pointreward = number_range(20,30); sprintf(buf, "Congratulations on completing your quest!"); do_say(questman,buf); sprintf(buf,"As a reward, I am giving you %d quest points, and %d gold.",pointreward,reward); do_say(questman,buf); REMOVE_BIT(ch->act,PLR_QUESTING); ch->questgiver = NULL; ch->countdown = 0; ch->questmob = 0; ch->questobj = 0; ch->nextquest = number_range(3, 6); ch->gold += reward; ch->quest_curr += pointreward; ch->quest_accum += pointreward; if(obj_found) extract_obj(obj); return; } else if((ch->questmob > 0 || ch->questobj > 0) && ch->countdown > 0) { sprintf(buf, "You haven't completed the quest yet, but there is still time!"); do_say(questman, buf); return; } } if (ch->nextquest > 0) { sprintf(buf,"But you didn't complete your quest in time!"); } else sprintf(buf, "You have to request a quest first, %s.",ch->name); do_say(questman, buf); return; } else if (!strcmp(arg1, "quit")) { act("$n informs $N $e wishes to quit $s quest.", ch, NULL,questman, TO_ROOM); act ("You inform $N you wish to quit $s quest.",ch, NULL, questman, TO_CHAR); if (ch->questgiver != questman) { sprintf(buf, "I never sent you on a quest! Perhaps you're thinking of someone else."); do_say(questman,buf); return; } if (IS_SET(ch->act,PLR_QUESTING)) { REMOVE_BIT(ch->act,PLR_QUESTING); ch->questgiver = NULL; ch->countdown = 0; ch->questmob = 0; ch->questobj = 0; ch->nextquest = 30; sprintf(buf, "Your quest is over, but for your cowardly behavior, you may not quest again for 30 minutes."); do_say(questman,buf); return; } else { send_to_char("You aren't on a quest!",ch); return; } } send_to_char("Quest commands: Info, Time, Request, Complete, Quit, List, and Buy.\n\r",ch); send_to_char("For more information, type 'Help Quest'.\n\r",ch); return; } void generate_quest(CHAR_DATA *ch, CHAR_DATA *questman) { CHAR_DATA *victim; MOB_INDEX_DATA *vsearch; ROOM_INDEX_DATA *room; OBJ_DATA *questitem; char buf [MAX_STRING_LENGTH]; long mcounter; int mob_vnum; for (mcounter = 0; mcounter < 99999; mcounter ++) { mob_vnum = number_range(50, 32600); if ( (vsearch = get_mob_index(mob_vnum) ) != NULL ) { if (quest_level_diff(ch->level, vsearch->level) == TRUE && vsearch->pShop == NULL && !IS_SET(vsearch->act, ACT_TRAIN) && !IS_SET(vsearch->act, ACT_PRACTICE) && !IS_SET(vsearch->act, ACT_IS_HEALER) && !IS_SET(vsearch->act, ACT_PET) && !IS_SET(vsearch->affected_by, AFF_CHARM) && !IS_SET(vsearch->affected_by, AFF_INVISIBLE) && number_percent() < 40) break; else vsearch = NULL; } } if ( vsearch == NULL || ( victim = get_char_world( ch, vsearch->player_name ) ) == NULL ) { sprintf(buf, "I'm sorry, but I don't have any quests for you at this time."); do_say(questman, buf); sprintf(buf, "Try again later."); do_say(questman, buf); ch->nextquest = 2; return; } if ( ( room = find_location( ch, victim->name ) ) == NULL ) { sprintf(buf, "I'm sorry, but I don't have any quests for you at this time."); do_say(questman, buf); sprintf(buf, "Try again later."); do_say(questman, buf); ch->nextquest = 2; return; } /* 40% chance it will send the player on a 'recover item' quest. */ if (number_percent() < 40) { int numobjs=0; int descnum = 0; for(numobjs=0; quest_desc[numobjs].name != NULL; numobjs++) ; numobjs--; descnum = number_range(0,numobjs); questitem = create_object( get_obj_index(number_range(40, 44)), ch->level ); obj_to_room(questitem, room); ch->questobj = questitem->pIndexData->vnum; sprintf(buf, "Vile pilferers have stolen %s from the royal treasury!",questitem->short_descr); do_say(questman, buf); do_say(questman, "My court wizardess, with her magic mirror, has pinpointed its location."); sprintf(buf, "Look in the general area of %s for %s!",room->area->name, room->name); do_say(questman, buf); return; } /* Quest to kill a mob */ else { switch(number_range(0,1)) { case 0: sprintf(buf, "An enemy of mine, %s, is making vile threats against the crown.",victim->short_descr); do_say(questman, buf); sprintf(buf, "This threat must be eliminated!"); do_say(questman, buf); break; case 1: sprintf(buf, "Vandagard's most heinous criminal, %s, has escaped from the dungeon!",victim->short_descr); do_say(questman, buf); sprintf(buf, "Since the escape, %s has murdered %d civillians!",victim->short_descr, number_range(2,20)); do_say(questman, buf); do_say(questman,"The penalty for this crime is death, and you are to deliver the sentence!"); break; } if (room->name != NULL) { sprintf(buf, "Seek %s out somewhere in the vicinity of %s!",victim->short_descr,room->name); do_say(questman, buf); sprintf(buf, "That location is in the general area of %s.",room->area->name); do_say(questman, buf); } ch->questmob = victim->pIndexData->vnum; } return; } bool quest_level_diff(int clevel, int mlevel) { if (clevel < 9 && mlevel < clevel + 2) return TRUE; else if (clevel <= 9 && mlevel < clevel + 3 && mlevel > clevel - 5) return TRUE; else if (clevel <= 14 && mlevel < clevel + 4 && mlevel > clevel - 5) return TRUE; else if (clevel <= 21 && mlevel < clevel + 5 && mlevel > clevel - 4) return TRUE; else if (clevel <= 29 && mlevel < clevel + 6 && mlevel > clevel - 3) return TRUE; else if (clevel <= 37 && mlevel < clevel + 7 && mlevel > clevel - 2) return TRUE; else if (clevel <= 55 && mlevel < clevel + 8 && mlevel > clevel - 1) return TRUE; else if (clevel <= 65 && mlevel < clevel + 9 && mlevel > clevel - 1) return TRUE; else if (clevel <= 75 && mlevel < clevel + 10 && mlevel > clevel - 1) return TRUE; else if (clevel <= 85 && mlevel < clevel + 11 && mlevel > clevel - 1) return TRUE; else if (clevel <= 95 && mlevel < clevel + 12 && mlevel > clevel - 1) return TRUE; else if (clevel <= 100 && mlevel < clevel + 13 && mlevel > clevel - 1) return TRUE; else if(clevel > 106) return TRUE; /* Imms can get anything :) */ else return FALSE; } /* Called from update_handler() by pulse_area */ void quest_update(void) { DESCRIPTOR_DATA *d; CHAR_DATA *ch; char buf[MAX_STRING_LENGTH]; for ( d = descriptor_list; d != NULL; d = d->next ) { if (d->character != NULL && d->connected == CON_PLAYING) { ch = d->character; if(IS_NPC(ch)) continue; if (ch->nextquest > 0) { ch->nextquest--; if (ch->nextquest == 0) { send_to_char("You may now quest again.\n\r",ch); return; } } else if (IS_SET(ch->act,PLR_QUESTING)) { if (--ch->countdown <= 0) { ch->nextquest = 3; sprintf(buf,"You have run out of time for your quest!\n\rYou may quest again in %d minutes.\n\r",ch->nextquest); send_to_char(buf, ch); REMOVE_BIT(ch->act,PLR_QUESTING); ch->questgiver = NULL; ch->countdown = 0; ch->questmob = 0; ch->questobj = 0; } if (ch->countdown > 0 && ch->countdown < 6) { send_to_char("Better hurry, you're almost out of time for your quest!\n\r",ch); return; } } } } return; }