/*************************************************************************** * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * * * In order to use any part of this Merc Diku Mud, you must comply with * * both the original Diku license in 'license.doc' as well the Merc * * license in 'license.txt'. In particular, you may not remove either of * * these copyright notices. * * * * Much time and thought has gone into this software and you are * * benefitting. We hope that you share your changes too. What goes * * around, comes around. * ***************************************************************************/ /*************************************************************************** * ROM 2.4 is copyright 1993-1995 Russ Taylor * * ROM has been brought to you by the ROM consortium * * Russ Taylor (rtaylor@pacinfo.com) * * Gabrielle Taylor (gtaylor@pacinfo.com) * * Brian Moore (rom@rom.efn.org) * * By using this code, you have agreed to follow the terms of the * * ROM license, in the file 'rom.license' * ***************************************************************************/ /*************************************************************************** * ROT 2.0 is copyright 1996-1999 by Russ Walsh * * By using this code, you have agreed to follow the terms of the * * ROT license, in the file 'rot.license' * ***************************************************************************/ /**************************************************************************** * Automated Quest code written by Vassago of MOONGATE, moongate.ams.com * * 4000. Copyright (c) 1996 Ryan Addams, All Rights Reserved. Use of this * * code is allowed provided you add a credit line to the effect of: * * "Quest Code (c) 1996 Ryan Addams" to your logon screen with the rest * * of the standard diku/rom credits. If you use this or a modified version * * of this code, let me know via email: moongate@moongate.ams.com. Further * * updates will be posted to the rom mailing list. If you'd like to get * * the latest version of quest.c, please send a request to the above add- * * ress. Quest Code v2.03. Please do not remove this notice from this file. * ****************************************************************************/ #if defined(macintosh) #include <types.h> #else #include <sys/types.h> #endif #include <sys/types.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <time.h> #include "merc.h" #include "tables.h" #include "interp.h" #define QUEST_OBJQUEST1 20200 #define QUEST_OBJQUEST2 20201 #define QUEST_OBJQUEST3 20202 #define QUEST_OBJQUEST4 20203 #define QUEST_OBJQUEST5 20204 struct quest_item { int vnum; int price; }; #define MAX_QUEST_ITEMS 21 struct quest_item quest_items[MAX_QUEST_ITEMS] = { {20206,169}, {20207,150}, {20208,302}, {20209,129}, {20210,119}, {20211,177}, {20212,184}, {20213,160}, {20214,139}, {20215,357}, {20135,155}, {20136,173}, {20137,355}, {20221,150}, {20222,309}, {20225,357}, {20226,158}, {20227,133}, {20228,168}, {20223,100}, {20224,50}, }; /* * Local functions. */ char * find_quest_mob args( ( CHAR_DATA *ch, bool lquest ) ); char * make_lquest_obj args( ( CHAR_DATA *ch ) ); bool is_suitable_qmob args( ( CHAR_DATA *ch, CHAR_DATA *victim, bool lquest ) ); void generate_quest args(( CHAR_DATA *ch, CHAR_DATA *questman )); bool quest_level_diff args(( int clevel, int mlevel)); bool chance args(( int num )); ROOM_INDEX_DATA *find_location( CHAR_DATA *ch, char *arg ); /* CHANCE function. I use this everywhere in my code, very handy :> */ bool chance(int num) { if (number_range(1,100) <= num) return TRUE; else return FALSE; } /* The main quest function */ void do_quest(CHAR_DATA *ch, char *argument) { CHAR_DATA *questman; // ,*nextquest 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]; char arg3 [9]; int i=0; argument = one_argument(argument, arg1); argument = one_argument(argument, arg2); argument = one_argument(argument, arg3); if (arg1[0] == '\0') { send_to_char("{CQ{cUES{CT{c commands: {DPOINTS INFO TIME REQUEST COMPLETE LIST\n\r",ch); send_to_char(" BUY IDENTIFY QUIT CONVERT REVERT SELL\n\r{x",ch); send_to_char("{cFor more information, type {D'{WHELP QUEST{D'{c.{x\n\r",ch); return; } if (!strcmp(arg1, "convert")) { if(ch->qps<=0) { send_to_char("You don't have any iquest points to convert.\n\r",ch); return; } ch->qps--; ch->questpoints+=20; send_to_char("One iquest point converted into 20 aquest points.\n\r",ch); return; } if (!strcmp(arg1,"revert")) { if(ch->questpoints<20) { send_to_char("You don't have enough aquest points to revert.\n\r",ch); return; } ch->qps++; ch->questpoints-=20; send_to_char("20 aquest points reverted into one iquest point.\n\r",ch); return; } if (!strcmp(arg1, "info")) { if (IS_SET(ch->exbit1, PLR_QUESTOR)) { 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; } if (!strcmp(arg1, "points")) { sprintf(buf, "You have %d quest points.\n\r",ch->questpoints); send_to_char(buf, ch); return; } else if (!strcmp(arg1, "time")) { if (!IS_SET(ch->exbit1, PLR_QUESTOR)) { 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; } 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_questmaster" )) break; } if (questman == NULL || questman->spec_fun != spec_lookup( "spec_questmaster" )) { 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("{cNumber Price ({DAQP{c) Name{x\n\r",ch); for(i=0;i<MAX_QUEST_ITEMS;i++) { questinfoobj = get_obj_index(quest_items[i].vnum); sprintf(buf,"{D%-6d{c {D%-11d{x %-40s\n\r", i+1,quest_items[i].price,questinfoobj->short_descr); send_to_char(buf,ch); } return; } else if (!strcmp(arg1, "identify")) { int number; if(arg2[0]=='\0') { send_to_char("Syntax: 'QUEST IDENTIFY <number>'\n\r",ch); return; } number = atoi(arg2); if(number<1 || number>MAX_QUEST_ITEMS) { sprintf(buf,"Number out of range (1 to %d).\n\r",MAX_QUEST_ITEMS); send_to_char(buf,ch); return; } obj = create_object(get_obj_index(quest_items[number-1].vnum),-1); (*skill_table[skill_lookup("identify")].spell_fun)(skill_lookup("identify"),101,ch,(void*)obj,TAR_IGNORE); extract_obj(obj); return; } else if (!strcmp(arg1, "buy")) { int number; if (arg2[0] == '\0') { send_to_char("To buy an item, type 'QUEST BUY <number>'.\n\r",ch); return; } number = atoi(arg2); if(number<1||number>MAX_QUEST_ITEMS) { sprintf(buf,"Number out of range (1 to %d).\n\r",MAX_QUEST_ITEMS); send_to_char(buf,ch); return; } if(ch->questpoints-quest_items[number-1].price<0) { send_to_char("Not enough questpoints.\n\r",ch); return; } obj = create_object(get_obj_index(quest_items[number-1].vnum),-1); act("$n hands $N $p.",questman,obj,ch,TO_NOTVICT); act("$n hands you $p.",questman,obj,ch,TO_VICT); ch->questpoints -= quest_items[number-1].price; obj_to_char(obj,ch); printf_log("%s buys %s [Q] at %d.", ch->name,obj->short_descr,ch->in_room->vnum); return; } else if (!strcmp(arg1, "sell")) { int i; bool fIsQuest=FALSE; if(arg2[0]=='\0') { send_to_char("Quest sell what?\n\r",ch); return; } if((obj=get_obj_carry(ch,arg2))==NULL) { send_to_char("You are not carrying that.\n\r",ch); return; } if(!IS_OBJ_STAT(obj,ITEM_QUEST)) { send_to_char("You can only sell quest items here.\n\r",ch); return; } for(i=0;i<MAX_QUEST_ITEMS;i++) { if(quest_items[i].vnum==obj->pIndexData->vnum) { fIsQuest=TRUE; break; } } if(!fIsQuest) { send_to_char("You can only sell quest items you could also buy here.\n\r",ch); return; } act("$n sells $p to $N.",ch,obj,questman,TO_NOTVICT); act("You sell $p to $N.",ch,obj,questman,TO_CHAR); sprintf(buf,"You receive %d questpoins.\n\r",quest_items[i].price/2); send_to_char(buf,ch); ch->questpoints+=(quest_items[i].price/2); printf_log("%s sells %s [Q] at %d.", ch->name,obj->short_descr,ch->in_room->vnum); obj_from_char(obj); extract_obj(obj); return; } else if (!strcmp(arg1, "request") && !IS_NPC(ch)) { if(ch->level<21) { send_to_char("Get to level 21 first.\n\r",ch); return; } if(ch->on_quest==TRUE) { send_to_char("You are not allowed to aquest while iquesting.\n\r",ch); return; } 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->exbit1, PLR_QUESTOR)) { send_to_char("But you're already on a quest!\n\r",ch); return; } if (ch->nextquest > 0) { sprintf(buf, "Now, don't be so greedy, %s, wait a little longer, will you?\n\r",ch->name); send_to_char( buf,ch); send_to_char("Come back later.\n\r",ch); return; } sprintf(buf, "Thank you, brave %s!\n\r",ch->name); send_to_char(buf,ch); ch->questmob = 0; ch->questobj = 0; generate_quest(ch, questman); if (ch->questmob > 0 || ch->questobj > 0) { ch->countdown = number_range(7,15); SET_BIT(ch->exbit1, PLR_QUESTOR); sprintf(buf, "You have %d minutes to complete this quest.\n\r",ch->countdown); send_to_char(buf,ch); send_to_char("May the gods go with you!\n\r",ch); } 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) { send_to_char( "I never sent you on a quest! Perhaps you're thinking of someone else.\n\r",ch); return; } if (IS_SET(ch->exbit1, PLR_QUESTOR)) { if(ch->on_quest==TRUE) { send_to_char("You are not allowed to aquest while iquesting.\n\r",ch); return; } if (ch->questmob == -1 && ch->countdown > 0) { int reward, pointreward, pracreward; reward = number_range(25,50); pointreward = number_range(1,10); sprintf(buf, "Congratulations on completing your quest!\n\r"); send_to_char(buf,ch); sprintf(buf, "As a reward, I am giving you %d aquest points, and %d platinum.\n\r",pointreward,reward); send_to_char(buf,ch); if (chance(10)) { pracreward = number_range(2,6); sprintf(buf, "You gain %d practices!\n\r",pracreward); send_to_char(buf, ch); ch->practice += pracreward; } REMOVE_BIT(ch->exbit1, PLR_QUESTOR); ch->questgiver = NULL; ch->countdown = 0; ch->questmob = 0; ch->questobj = 0; ch->nextquest = 15; ch->platinum += reward; ch->questpoints += pointreward; return; } else if (ch->questobj > 0 && ch->countdown > 0) { bool obj_found = FALSE; 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 (obj_found == TRUE) { int reward, pointreward, pracreward; reward = number_range(25,50); pointreward = number_range(1,10); act("You hand $p to $N.",ch, obj, questman, TO_CHAR); act("$n hands $p to $N.",ch, obj, questman, TO_ROOM); sprintf(buf, "Congratulations on completing your quest!\n\r"); send_to_char(buf,ch); sprintf(buf,"As a reward, I am giving you %d aquest points, and %d platinum.\n\r",pointreward,reward); send_to_char(buf,ch); if (chance(15)) { pracreward = number_range(2,6); sprintf(buf, "You gain %d practices!\n\r",pracreward); send_to_char(buf, ch); ch->practice += pracreward; } REMOVE_BIT(ch->exbit1, PLR_QUESTOR); extract_obj(obj); ch->questgiver = NULL; ch->countdown = 0; ch->questmob = 0; ch->questobj = 0; ch->nextquest = 15; ch->platinum += reward; ch->questpoints += pointreward; return; } else { sprintf(buf, "You haven't completed the quest yet, hurry there is still time!\n\r"); send_to_char(buf,ch); return; } return; } if ((ch->questmob > 0 || ch->questobj > 0) && ch->countdown > 0) { sprintf(buf, "You haven't completed the quest yet, but there is still time!\n\r"); send_to_char(buf,ch); return; } } if (ch->countdown > 0) sprintf(buf,"But you didn't complete your quest in time!\n\r"); else if (!IS_SET(ch->exbit1, PLR_QUESTOR)) sprintf(buf, "You have to REQUEST a quest first, %s.\n\r",ch->name); send_to_char( buf,ch); return; } else if(!strcmp(arg1,"quit")) { if(!IS_SET(ch->exbit1,PLR_QUESTOR)) { send_to_char("But you aren't even on a quest!\n\r",ch); return; } act("$n informs $N that $e wants to quit $s quest.",ch,NULL,questman,TO_ROOM); act("You inform $N that you want to quit your quest.",ch,NULL,questman,TO_CHAR); ch->questgiver=NULL; ch->questmob=0; ch->questobj=0; ch->countdown=0; ch->nextquest=5; REMOVE_BIT(ch->exbit1,PLR_QUESTOR); send_to_char("Ok, quest quit, come back later and try again.\n\r",ch); return; } send_to_char("{CQ{cUES{CT{c commands: {DPOINTS INFO TIME REQUEST COMPLETE LIST\n\r",ch); send_to_char(" BUY IDENTIFY QUIT CONVERT REVERT SELL\n\r{x",ch); send_to_char("{cFor more information, type {D'{WHELP QUEST{D'{c.{x\n\r",ch); return; } void generate_quest(CHAR_DATA *ch, CHAR_DATA *questman) { CHAR_DATA *victim; ROOM_INDEX_DATA *room; OBJ_DATA *questitem; char buf [MAX_STRING_LENGTH]; for (victim = char_list; victim != NULL; victim = victim->next ) { if (!IS_NPC(victim)) continue; if (quest_level_diff(ch->level, victim->level) == TRUE && victim->pIndexData != NULL && victim->pIndexData->pShop == NULL && !IS_SET(victim->imm_flags, IMM_SUMMON) && !IS_SET(victim->act, ACT_TRAIN) && !IS_SET(victim->act, ACT_PRACTICE) && !IS_SET(victim->act, ACT_IS_HEALER) && !IS_SET(victim->act, ACT_PET) && !IS_SET(victim->affected_by, AFF_CHARM) && !IS_SET(victim->affected_by, SHD_INVISIBLE) && !strstr(victim->in_room->area->builders,"Unlinked") && !IS_SET(victim->in_room->room_flags,ROOM_NO_RECALL) && chance(15) ) break; } if ( victim == NULL ) { send_to_char("I'm sorry, but I don't have any quests for you at this time.\n\r",ch); send_to_char("Try again later.\n\r",ch); ch->nextquest = 1; 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.\n\r"); send_to_char(buf,ch); sprintf(buf, "Try again later.\n\r"); send_to_char(buf,ch); ch->nextquest = 1; return; } if (chance(40)) { int objvnum = 0; switch(number_range(0,4)) { case 0: objvnum = QUEST_OBJQUEST1; break; case 1: objvnum = QUEST_OBJQUEST2; break; case 2: objvnum = QUEST_OBJQUEST3; break; case 3: objvnum = QUEST_OBJQUEST4; break; case 4: objvnum = QUEST_OBJQUEST5; break; } questitem = create_object( get_obj_index(objvnum), ch->level ); obj_to_room(questitem, room); ch->questobj = questitem->pIndexData->vnum; sprintf(buf, "Vile pilferers have stolen %s from the royal treasury!\n\r",questitem->short_descr); send_to_char(buf,ch); send_to_char("My court wizardess, with her magic mirror, has pinpointed its location.\n\r",ch); sprintf(buf, "Look in the general area of %s for %s!\n\r",room->area->name, room->name); send_to_char(buf,ch); return; } else { switch(number_range(0,1)) { case 0: sprintf(buf, "An enemy of mine, %s, is making vile threats against the crown.\n\r",victim->short_descr); send_to_char(buf,ch); send_to_char("This threat must be eliminated!\n\r",ch); break; case 1: sprintf(buf,"One of the most heinous criminals, %s, has escaped from the prison!\n\r",victim->short_descr); send_to_char(buf,ch); sprintf(buf, "Since the escape, %s has murdered %d civillians!\n\r",victim->short_descr, number_range(2,20)); send_to_char( buf,ch); send_to_char("The penalty for this crime is death and you are to deliver the sentence!\n\r",ch); break; } if (room->name != NULL) { sprintf(buf, "Seek %s out somewhere in the vicinity of %s!\n\r",victim->short_descr,room->name); send_to_char( buf,ch); sprintf(buf, "That location is in the general area of %s.\n\r",room->area->name); send_to_char( buf,ch); } ch->questmob = victim->pIndexData->vnum; } return; } bool quest_level_diff(int clevel, int mlevel) { if (clevel < 5 && mlevel < 9) return TRUE; else if (clevel > 4 && clevel < 11 && mlevel < 16) return TRUE; else if (clevel > 10 && clevel < 15 && mlevel > 5 && mlevel < 20) return TRUE; else if (clevel > 14 && clevel < 25 && mlevel > 10 && mlevel < 30) return TRUE; else if (clevel > 24 && clevel < 35 && mlevel > 15 && mlevel < 40) return TRUE; else if (clevel > 34 && clevel < 45 && mlevel > 20 && mlevel < 50) return TRUE; else if (clevel > 44 && clevel < 55 && mlevel > 25 && mlevel < 60) return TRUE; else if (clevel > 54 && clevel < 65 && mlevel > 30 && mlevel < 70) return TRUE; else if (clevel > 64 && clevel < 75 && mlevel > 35 && mlevel < 80) return TRUE; else if (clevel > 74 && clevel < 85 && mlevel > 40 && mlevel < 90) return TRUE; else if (clevel > 84 && clevel < 95 && mlevel > 45 && mlevel < 100) return TRUE; else if (clevel > 94 && clevel < 105 && mlevel >50 && mlevel < 110) return TRUE; else if (clevel > 104 && clevel < 115 && mlevel > 55 && mlevel < 120) return TRUE; else return FALSE; }