/************************************************************************** * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvements 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 * * benefiting. We hope that you share your changes too. What goes * * around, comes around. * *************************************************************************** * ROM 2.4 is copyright 1993-1998 Russ Taylor * * ROM has been brought to you by the ROM consortium * * Russ Taylor (rtaylor@hypercube.org) * * Gabrielle Taylor (gtaylor@hypercube.org) * * Brian Moore (zump@rom.org) * * By using this code, you have agreed to follow the terms of the * * ROM license, in the file Rom24/doc/rom.license * *************************************************************************** * 1stMUD ROM Derivative (c) 2001-2002 by Ryan Jennings * * http://1stmud.dlmud.com/ <r-jenn@shaw.ca> * ***************************************************************************/ /**************************************************************************** * 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. * ****************************************************************************/ /**************************************************************************** * Updated Quest Code copyright 1999-2001 * * Markanth : dlmud@dlmud.com * * Devil's Lament : dlmud.com port 3778 * * Web Page : http://www.dlmud.com * ***************************************************************************/ #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "merc.h" #include "magic.h" #include "interp.h" #include "recycle.h" struct quest_type { char *name; char *descr; int vnum; int cost; }; #define QUEST_TIME 20 /* * Object vnums for Quest Rewards */ const struct quest_type quest_table[] = { /*name *//*short description *//*vnum *//*cost */ {"nohunger", "No Hunger/Thirst (quest buy nohunger)", 0, 3000}, {"aura", "Aura of Sanctuary", QUEST_AURA, 2600}, {"sword", "Sword of the Ancients", QUEST_SWORD, 2500}, {"breastplate", "BreastPlate of the Ancients", QUEST_BPLATE, 2500}, {"boots", "Boots of the Ancients", QUEST_BOOTS, 2500}, {"gloves", "Gloves of Protection", QUEST_GLOVES, 2500}, {"flame", "Flame of the Ancients", QUEST_FLAME, 2500}, {"helm", "Helm of True Sight", QUEST_HELM, 2300}, {"bag", "Bag of the Ancients", QUEST_BAG, 1000}, {"shield", "Shield of the Ancients", QUEST_SHIELD, 750}, {"regeneration", "Ring of Regeneration", QUEST_REGEN, 700}, {"invisibility", "Ring of Invisibility", QUEST_INVIS, 500}, {"trivia", "Trivia Pill", QUEST_TRIVIA, 100}, {NULL, NULL, 0, 0} }; /* Quests to find objects */ #define QUEST_OBJQUEST1 214 #define QUEST_OBJQUEST2 215 #define QUEST_OBJQUEST3 216 #define QUEST_OBJQUEST4 217 /* * 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; } /* is object in quest table? */ int is_qobj(OBJ_DATA * obj) { int i; if (!obj || !obj->pIndexData) return -1; for (i = 0; quest_table[i].name != NULL; i++) { if (obj->pIndexData->vnum == quest_table[i].vnum) return i; } return -1; } int qobj_cost(OBJ_DATA * obj) { int i; if (!obj || !obj->pIndexData) return 0; for (i = 0; quest_table[i].name != NULL; i++) { if (obj->pIndexData->vnum == quest_table[i].vnum) return quest_table[i].cost; } return 0; } /* * * Add or enhance an obj affect. */ void affect_join_obj(OBJ_DATA * obj, AFFECT_DATA * paf) { AFFECT_DATA *paf_old; bool found; found = FALSE; for (paf_old = obj->first_affect; paf_old != NULL; paf_old = paf_old->next) { if (paf_old->location == paf->location && paf_old->type == paf->type && paf_old->bitvector == paf->bitvector && paf_old->where == paf->where) { paf_old->level = paf->level; paf_old->modifier = paf->modifier; found = TRUE; } } if (!found) affect_to_obj(obj, paf); return; } void add_apply(OBJ_DATA * obj, int loc, int mod, int where, int type, int dur, flag_t bit, int level) { AFFECT_DATA pAf; if (obj == NULL) return; pAf.location = loc; pAf.modifier = mod; pAf.where = where; pAf.type = type; pAf.duration = dur; pAf.bitvector = bit; pAf.level = level; affect_join_obj(obj, &pAf); return; } /* Updates a quest object. AFFECTS like sanctuary ect.. are done in game or on area file. (Anything not level based) */ void update_questobjs(CHAR_DATA * ch, OBJ_DATA * obj) { int bonus, pbonus, cost; if (obj == NULL || obj->pIndexData == NULL) { bug("update_questobjs: NULL obj", 0); return; } if (ch == NULL) { bug("update_questobjs: NULL ch", 0); return; } if (!IS_OBJ_STAT(obj, ITEM_QUEST) && is_qobj(obj) == -1) return; bonus = UMAX(5, ch->level / 10); pbonus = UMAX(5, ch->level / 5); cost = qobj_cost(obj); if (obj->level != ch->level) obj->level = ch->level; if (obj->condition != -1) obj->condition = -1; if (obj->cost != cost) obj->cost = cost; if (!CAN_WEAR(obj, ITEM_NO_SAC)) SET_BIT(obj->wear_flags, ITEM_NO_SAC); if (!IS_OBJ_STAT(obj, ITEM_BURN_PROOF)) SET_BIT(obj->extra_flags, ITEM_BURN_PROOF); /* Bonuses could get fun here */ switch (obj->pIndexData->vnum) { case QUEST_BPLATE: add_apply(obj, APPLY_DAMROLL, pbonus, TO_OBJECT, 0, -1, 0, ch->level); add_apply(obj, APPLY_HITROLL, pbonus, TO_OBJECT, 0, -1, 0, ch->level); break; case QUEST_SHIELD: add_apply(obj, APPLY_DAMROLL, pbonus, TO_OBJECT, 0, -1, 0, ch->level); add_apply(obj, APPLY_HITROLL, pbonus, TO_OBJECT, 0, -1, 0, ch->level); break; case QUEST_AURA: add_apply(obj, APPLY_HIT, UMAX(50, ch->level), TO_OBJECT, 0, -1, 0, ch->level); add_apply(obj, APPLY_MANA, UMAX(50, ch->level), TO_OBJECT, 0, -1, 0, ch->level); add_apply(obj, APPLY_MOVE, UMAX(50, ch->level), TO_OBJECT, 0, -1, 0, ch->level); break; } switch (obj->item_type) { case ITEM_CONTAINER: /* weight modifiers */ obj->weight = -1 * (50 + (ch->level * 15 / 10)); obj->value[0] = 1000 + (20 * ch->level); obj->value[3] = 1000 + (20 * ch->level); break; case ITEM_WEAPON: /* weapon values of levelD5 */ obj->value[1] = UMAX(15, ch->level); obj->value[2] = ch->level < 80 ? 4 : 5; add_apply(obj, APPLY_DAMROLL, bonus, TO_OBJECT, 0, -1, 0, ch->level); add_apply(obj, APPLY_HITROLL, bonus, TO_OBJECT, 0, -1, 0, ch->level); break; case ITEM_ARMOR: /* AC value of player level */ obj->value[0] = UMAX(20, ch->level); obj->value[1] = UMAX(20, ch->level); obj->value[2] = UMAX(20, ch->level); obj->value[3] = (5 * UMAX(20, ch->level)) / 6; break; } return; } /* why not check non-quest items as well - M. */ void update_all_qobjs(CHAR_DATA * ch) { OBJ_DATA *obj; int iWear; for (obj = ch->first_carrying; obj != NULL; obj = obj->next_content) { if (IS_OBJ_STAT(obj, ITEM_QUEST)) { update_questobjs(ch, obj); if ((iWear = obj->wear_loc) != WEAR_NONE) { unequip_char(ch, obj); equip_char(ch, obj, iWear); } } } } void unfinished_quest(CHAR_DATA * ch) { if (IS_QUESTOR(ch)) { bool found = FALSE; sprintf(log_buf, "Creating unfinished quest for %s.", ch->name); log_string(log_buf); wiznet(log_buf, NULL, NULL, 0, 0, 0); if (ch->pcdata->questobj > 0) { OBJ_DATA *obj = NULL; ROOM_INDEX_DATA *pRoom = NULL; for (obj = object_first; obj != NULL; obj = obj->next) if (obj->pIndexData->vnum == ch->pcdata->questobj && is_name(ch->name, obj->owner)) found = TRUE; if (!found) { if ((obj = create_object(get_obj_index (ch->pcdata->questobj), ch->level)) == NULL) end_quest(ch, 0); else { if ((pRoom = get_room_index(ch->pcdata->questloc)) == NULL) { pRoom = get_random_room(ch); ch->pcdata->questobj = pRoom->vnum; } obj_to_room(obj, pRoom); } do_quest(ch, "info"); chprintln(ch, ""); } } else if (ch->pcdata->questmob > 0) { CHAR_DATA *mob; for (mob = char_first; mob != NULL; mob = mob->next) if (IS_NPC(mob) && mob->pIndexData->vnum == ch->pcdata->questmob) break; if (!mob) end_quest(ch, QUEST_TIME / 4); else { ch->pcdata->questloc = mob->in_room->vnum; do_quest(ch, "info"); chprintln(ch, ""); } } } } /* Usage info on the QUEST commands*/ /* Keep this in line with the do_quest function's keywords */ void quest_usage(CHAR_DATA * ch) { chprintln(ch, "QUEST commands: INFO, REQUEST, COMPLETE, LIST,\n\r" " BUY, QUIT, SELL, IDENTIFY."); if (IS_IMMORTAL(ch)) chprintln(ch, "QUEST RESET (player): resets players quest."); chprintln(ch, "For more information, type 'HELP QUEST'."); return; } /* Obtain additional location information about sought item/mob */ void quest_where(CHAR_DATA * ch, char *what) { ROOM_INDEX_DATA *room; if (!ch || IS_NPC(ch)) return; if (ch->pcdata->questloc <= 0) { bug("QUEST INFO: ch->questloc = %d", ch->pcdata->questloc); return; } if (ch->in_room == NULL) return; room = get_room_index(ch->pcdata->questloc); if (room->area == NULL) { bug("QUEST INFO: room(%d)->area == NULL", ch->pcdata->questloc); return; } if (room->area->name == NULL) { bug("QUEST INFO: area->name == NULL", 0); return; } chprintlnf(ch, "Rumor has it this %s was last seen in the area known as %s,", what, room->area->name); if (room->name == NULL) { bug("QUEST INFO: room(%d)->name == NULL", ch->pcdata->questloc); return; } chprintlnf(ch, "near %s.", room->name); } /* end quest_where() */ OBJ_DATA *has_questobj(CHAR_DATA * ch) { OBJ_DATA *obj; OBJ_INDEX_DATA *pObj; if (!ch || IS_NPC(ch) || ch->pcdata->questobj <= 0) return NULL; if ((pObj = get_obj_index(ch->pcdata->questobj)) == NULL) return NULL; for (obj = ch->first_carrying; obj != NULL; obj = obj->next_content) if (obj != NULL && obj->pIndexData == pObj) return obj; return NULL; } /* * The main quest function */ CH_CMD(do_quest) { CHAR_DATA *questman; OBJ_DATA *obj = NULL; char buf[MAX_STRING_LENGTH]; char arg1[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; int i = 0; if (IS_NPC(ch)) { chprintln(ch, "I'm sorry, you can't quest."); return; } argument = one_argument(argument, arg1); argument = one_argument(argument, arg2); if (arg1[0] == '\0') { quest_usage(ch); return; } if (!str_prefix(arg1, "info")) { MOB_INDEX_DATA *qm_mob; OBJ_DATA *qinfoobj; CHAR_DATA *qinfomob; if (!IS_QUESTOR(ch)) { chprintln(ch, "You aren't currently on a quest."); if (ch->pcdata->nextquest > 1) { chprintlnf(ch, "There are %d minutes remaining until you can go on another quest.", ch->pcdata->nextquest); } else if (ch->pcdata->nextquest == 1) { chprintln(ch, "There is less than a minute remaining until you can go on another quest."); } chprintlnf(ch, "You have %d quest points.", ch->pcdata->questpoints); return; } chprintln(ch, ""); if ((qm_mob = get_mob_index(ch->pcdata->questgiver)) == NULL) { chprintln(ch, "Your quest master has fallen very ill. Please contact an imm!"); end_quest(ch, QUEST_TIME / 4); return; } if (ch->pcdata->questmob == -1 || has_questobj(ch) != NULL) { chprintln(ch, "Your quest is ALMOST complete!"); chprintlnf(ch, "You have %d minute%s to get back to %s\n\rbefore your time runs out!", ch->pcdata->countdown, ch->pcdata->countdown > 1 ? "s" : "", qm_mob->short_descr); return; } else if (ch->pcdata->questobj > 0) { for (qinfoobj = object_first; qinfoobj != NULL; qinfoobj = qinfoobj->next) { if (qinfoobj->pIndexData->vnum == ch->pcdata->questobj) { act("$n recalls the quest $N gave $m.", ch, NULL, qm_mob, TO_ROOM); chprintlnf(ch, "You recall the quest which the %s gave you.", qm_mob->short_descr); chprintlnf(ch, "You are on a quest to recover the fabled %s!", qinfoobj->short_descr); quest_where(ch, "treasure"); if (ch->pcdata->countdown > 0) { chprintlnf(ch, "You have %d minute%s to complete this quest.", ch->pcdata->countdown, ch->pcdata->countdown > 1 ? "s" : ""); } return; } } } else if (ch->pcdata->questmob > 0) { for (qinfomob = char_first; qinfomob != NULL; qinfomob = qinfomob->next) { if (IS_NPC(qinfomob) && qinfomob->pIndexData->vnum == ch->pcdata->questmob) { act("$n recalls the quest $N gave $s.", ch, NULL, qm_mob, TO_ROOM); chprintlnf(ch, "You recall the quest which the %s gave you.", qm_mob->short_descr); chprintlnf(ch, "You are on a quest to slay the dreaded %s!", qinfomob->short_descr); quest_where(ch, "fiend"); if (ch->pcdata->countdown > 0) { chprintlnf(ch, "You have %d minute%s to complete this quest.", ch->pcdata->countdown, ch->pcdata->countdown > 1 ? "s" : ""); } return; } } } bug("QUEST INFO: Questor with no kill, mob or obj", 0); end_quest(ch, QUEST_TIME / 4); return; } else if (!str_prefix(arg1, "reset")) { CHAR_DATA *victim; if (!IS_IMMORTAL(ch)) { quest_usage(ch); return; } if (arg2[0] == '\0') { chprintln(ch, "Syntax: quest reset <player>"); return; } if ((victim = get_char_world(ch, arg2)) == NULL) { chprintln(ch, "They aren't here."); return; } if (IS_NPC(victim)) { chprintln(ch, "Mobs dont quest."); return; } end_quest(victim, 0); if (victim != ch) chprintln(ch, "You clear thier quest."); chprintlnf(victim, "%s has cleared your quest.", PERS(ch, victim)); return; } /* * Checks for a character in the room with spec_questmaster set. This * special procedure must be defined in special.c. You could instead use * an ACT_QUESTMASTER flag instead of a special procedure. */ for (questman = ch->in_room->first_person; 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")) { chprintln(ch, "You can't do that here."); return; } if (questman->fighting != NULL) { chprintln(ch, "Wait until the fighting stops."); return; } /* * And, of course, you will need to change the following lines for YOUR * quest item information. Quest items on Moongate are unbalanced, very * very nice items, and no one has one yet, because it takes awhile to * build up quest points :> Make the item worth their while. */ if (!strcmp(arg1, "list")) { act("$n asks $N for a list of quest items.", ch, NULL, questman, TO_ROOM); chprintln(ch, "\tCurrent Quest Items available for Purchase:"); for (i = 0; quest_table[i].descr != NULL; i++) { chprintlnf(ch, "\t%-4dqp ........ %s", quest_table[i].cost, quest_table[i].descr); } chprintln(ch, "\tTo buy an item, type 'QUEST BUY <item>'."); chprintln(ch, "\tFor more info on quest items type 'help questitems'"); return; } else if (!strcmp(arg1, "buy")) { if (arg2[0] == '\0') { chprintln(ch, "To buy an item, type 'QUEST BUY <item>'."); return; } for (i = 0; quest_table[i].name != NULL; i++) { if (is_name(arg2, quest_table[i].name)) { if (ch->pcdata->questpoints >= quest_table[i].cost) { if (quest_table[i].vnum == 0) { ch->pcdata->questpoints -= quest_table[i].cost; ch->pcdata->condition[COND_FULL] = -1; ch->pcdata->condition[COND_THIRST] = -1; act ("$N calls upon the power of the gods to relieve your mortal burdens.", ch, NULL, questman, TO_CHAR); act ("$N calls upon the power of the gods to relieve $n's mortal burdens.", ch, NULL, questman, TO_ROOM); return; } else if ((obj = create_object(get_obj_index (quest_table [i].vnum), ch->level)) == NULL) { chprintln(ch, "That object could not be found, contact an immortal."); return; } else { ch->pcdata->questpoints -= quest_table[i].cost; } if (!IS_SET(obj->pIndexData->extra_flags, ITEM_QUEST)) { SET_BIT(obj->pIndexData->extra_flags, ITEM_QUEST); SET_BIT(obj->extra_flags, ITEM_QUEST); } act("$N gives $p to $n.", ch, obj, questman, TO_ROOM); act("$N gives you $p.", ch, obj, questman, TO_CHAR); obj_to_char(obj, ch); save_char_obj(ch); return; } else { sprintf(buf, "Sorry, %s, but you need %d quest points for that.", ch->name, quest_table[i].cost); do_mob_tell(ch, questman, buf); return; } } } sprintf(buf, "I don't have that item, %s.", ch->name); do_mob_tell(ch, questman, buf); return; } else if (!strcmp(arg1, "sell")) { if (arg2[0] == '\0') { chprintln(ch, "To sell an item, type 'QUEST SELL <item>'."); return; } if ((obj = get_obj_carry(ch, arg2, ch)) == NULL) { chprintln(ch, "Which item is that?"); return; } if (!IS_OBJ_STAT(obj, ITEM_QUEST)) { sprintf(buf, "That is not a quest item, %s.", ch->name); do_mob_tell(ch, questman, buf); return; } for (i = 0; quest_table[i].name != NULL; i++) { if (quest_table[i].vnum <= 0) continue; if (quest_table[i].vnum == obj->pIndexData->vnum) { ch->pcdata->questpoints += quest_table[i].cost / 3; act("$N takes $p from $n.", ch, obj, questman, TO_ROOM); sprintf(buf, "$N takes $p from you for %d quest points.", quest_table[i].cost / 3); act(buf, ch, obj, questman, TO_CHAR); extract_obj(obj); save_char_obj(ch); return; } } sprintf(buf, "I only take items I sell, %s.", ch->name); do_mob_tell(ch, questman, buf); return; } else if (!strcmp(arg1, "identify")) { if (arg2[0] == '\0') { chprintln(ch, "To identify an item, type 'QUEST IDENTIFY <item>'."); return; } for (i = 0; quest_table[i].name != NULL; i++) { if (is_name(arg2, quest_table[i].name)) { if (quest_table[i].vnum == 0) { chprintln(ch, "That isn't a quest item."); return; } else if ((obj = create_object(get_obj_index (quest_table[i].vnum), ch->level)) == NULL) { chprintln(ch, "That object could not be found, contact an immortal."); return; } else { if (!IS_SET(obj->pIndexData->extra_flags, ITEM_QUEST)) { SET_BIT(obj->pIndexData->extra_flags, ITEM_QUEST); SET_BIT(obj->extra_flags, ITEM_QUEST); } obj_to_char(obj, ch); chprintlnf(ch, "%s costs %d questpoints.", obj->short_descr, quest_table[i].cost); spell_identify(0, ch->level, ch, obj, TAR_OBJ_INV); extract_obj(obj); return; } } } sprintf(buf, "I don't have that item, %s.", ch->name); do_mob_tell(ch, questman, buf); 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_QUESTOR)) { do_mob_tell(ch, questman, "But you're already on a quest!"); return; } if (ch->pcdata->nextquest > 0) { sprintf(buf, "You're very brave, %s, but let someone else have a chance.", ch->name); do_mob_tell(ch, questman, buf); do_mob_tell(ch, questman, "Come back later."); return; } sprintf(buf, "Thank you, brave %s!", ch->name); do_mob_tell(ch, questman, buf); ch->pcdata->questmob = 0; ch->pcdata->questobj = 0; generate_quest(ch, questman); return; } else if (!strcmp(arg1, "complete")) { if (ch->pcdata->questgiver != questman->pIndexData->vnum) { do_mob_tell(ch, questman, "I never sent you on a quest! Perhaps you're thinking of someone else."); return; } if (IS_SET(ch->act, PLR_QUESTOR)) { int reward, points; if (ch->pcdata->questmob == -1 && ch->pcdata->countdown > 0) { reward = number_range(125, 375); points = number_range(25, 70); 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); do_mob_tell(ch, questman, "Congratulations on completing your quest!"); sprintf(buf, "As a reward, I am giving you %d quest points, and %d gold.", points, reward); do_mob_tell(ch, questman, buf); if (chance(points / 5)) { chprintln(ch, "You gain an extra Trivia Point!"); ch->pcdata->trivia += 1; } end_quest(ch, QUEST_TIME); ch->gold += reward; ch->pcdata->questpoints += points; save_char_obj(ch); return; } else if (ch->pcdata->questobj > 0 && ch->pcdata->countdown > 0) { if ((obj = has_questobj(ch)) != NULL) { reward = number_range(125, 375); points = number_range(25, 75); 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); act("You hand $p to $N.", ch, obj, questman, TO_CHAR); act("$n hands $p to $N.", ch, obj, questman, TO_ROOM); do_mob_tell(ch, questman, "Congratulations on completing your quest!"); sprintf(buf, "As a reward, I am giving you %d quest points, and %d gold.", points, reward); do_mob_tell(ch, questman, buf); if (chance(points / 5)) { chprintln(ch, "You gain an extra Trivia Point!"); ch->pcdata->trivia += 1; } end_quest(ch, QUEST_TIME); ch->gold += reward; ch->pcdata->questpoints += points; extract_obj(obj); save_char_obj(ch); return; } else { do_mob_tell(ch, questman, "You haven't completed the quest yet, but there is still time!"); return; } return; } else if ((ch->pcdata->questmob > 0 || ch->pcdata->questobj > 0) && ch->pcdata->countdown > 0) { do_mob_tell(ch, questman, "You haven't completed the quest yet, but there is still time!"); return; } } if (ch->pcdata->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_mob_tell(ch, questman, buf); return; } else if (!strcmp(arg1, "quit") || !strcmp(arg1, "fail")) { 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->pcdata->questgiver != questman->pIndexData->vnum) { do_mob_tell(ch, questman, "I never sent you on a quest! Perhaps you're thinking of someone else."); return; } if (IS_SET(ch->act, PLR_QUESTOR)) { end_quest(ch, QUEST_TIME - 2); do_mob_tell(ch, questman, "Your quest is over, but for your cowardly behavior, you may not quest again for 15 minutes."); return; } else { chprintln(ch, "You aren't on a quest!"); return; } } quest_usage(ch); return; } #define MAX_QMOB_COUNT mobile_count void generate_quest(CHAR_DATA * ch, CHAR_DATA * questman) { CHAR_DATA *victim = NULL; ROOM_INDEX_DATA *room = NULL; CHAR_DATA **mobs; int mob_count; OBJ_DATA *questitem = NULL; char buf[MAX_STRING_LENGTH]; int mrange; /* * * find MAX_QMOB_COUNT quest mobs and store their vnums in mob_buf */ alloc_mem(mobs, CHAR_DATA *, MAX_QMOB_COUNT); mob_count = 0; for (victim = char_first; victim; victim = victim->next) { if (!IS_NPC(victim) || !quest_level_diff(ch, victim) || victim->pIndexData == NULL || victim->in_room == NULL || victim->pIndexData->pShop != NULL || (IS_EVIL(victim) && IS_EVIL(ch) && chance(50)) || (IS_GOOD(victim) && IS_GOOD(ch) && chance(50)) || victim->pIndexData->vnum < 100 || victim->in_room->clan != NULL || IS_SET(victim->imm_flags, IMM_WEAPON | IMM_MAGIC) || IS_SET(victim->act, ACT_TRAIN | ACT_PRACTICE | ACT_IS_HEALER | ACT_PET | ACT_PET | ACT_GAIN) || IS_SET(victim->affected_by, AFF_CHARM) || IS_SET(victim->in_room->room_flags, ROOM_PET_SHOP) || questman->pIndexData == victim->pIndexData || (IS_SET(victim->act, ACT_SENTINEL) && IS_SET(victim->in_room->room_flags, ROOM_PRIVATE | ROOM_SOLITARY | ROOM_SAFE))) continue; mobs[mob_count++] = victim; if (mob_count >= MAX_QMOB_COUNT) break; } if (mob_count == 0) /* not likely but just in case */ { do_mob_tell(ch, questman, "I'm sorry, but I don't have any quests for you at this time."); do_mob_tell(ch, questman, "Try again later."); end_quest(ch, QUEST_TIME / 10); free_mem(mobs); return; } /* * at this point the player is sure to get a quest */ ch->pcdata->questgiver = questman->pIndexData->vnum; mrange = number_range(0, mob_count - 1); while ((victim = mobs[mrange]) == NULL) mrange = number_range(0, mob_count - 1); room = victim->in_room; ch->pcdata->questloc = room->vnum; /* countdown set here so we can use it for object timers */ ch->pcdata->countdown = number_range(12, 30); /* * 20% chance it will send the player on a 'recover item' quest. */ if (chance(20)) { vnum_t objvnum = 0; switch (number_range(0, 3)) { case 0: objvnum = QUEST_OBJQUEST1; break; case 1: objvnum = QUEST_OBJQUEST2; break; case 2: objvnum = QUEST_OBJQUEST3; break; case 3: objvnum = QUEST_OBJQUEST4; break; } questitem = create_object(get_obj_index(objvnum), ch->level); obj_to_room(questitem, room); REMOVE_BIT(ch->act, PLR_CANLOOT); free_string(questitem->owner); questitem->owner = str_dup(ch->name); questitem->cost = 0; questitem->timer = (4 * ch->pcdata->countdown + 10) / 3; ch->pcdata->questobj = questitem->pIndexData->vnum; switch (number_range(0, 1)) { default: case 0: sprintf(buf, "Vile pilferers have stolen %s from the royal treasury!", questitem->short_descr); do_mob_tell(ch, questman, buf); do_mob_tell(ch, questman, "My court wizardess, with her magic mirror, has pinpointed its location."); break; case 1: sprintf(buf, "A powerful wizard has stolen %s for his personal power!", questitem->short_descr); do_mob_tell(ch, questman, buf); break; } if (room->name != NULL) { sprintf(buf, "Look for %s somewhere in the vicinity of %s!", questitem->short_descr, room->name); do_mob_tell(ch, questman, buf); sprintf(buf, "That location is in the general area of %s.", room->area->name); do_mob_tell(ch, questman, buf); } } /* * Quest to kill a mob */ else { switch (number_range(0, 3)) { default: case 0: sprintf(buf, "An enemy of mine, %s, is making vile threats against the crown.", victim->short_descr); do_mob_tell(ch, questman, buf); do_mob_tell(ch, questman, "This threat must be eliminated!"); break; case 1: sprintf(buf, "Thera's most heinous criminal, %s, has escaped from the dungeon!", victim->short_descr); do_mob_tell(ch, questman, buf); sprintf(buf, "Since the escape, %s has murdered %d civillians!", victim->short_descr, number_range(2, 20)); do_mob_tell(ch, questman, buf); do_mob_tell(ch, questman, "The penalty for this crime is death, and you are to deliver the sentence!"); break; case 2: sprintf(buf, "The Mayor of Midgaard has recently been attacked by %s. This is an act of war!", victim->short_descr); do_mob_tell(ch, questman, buf); sprintf(buf, "%s must be severly dealt with for this injustice.", victim->short_descr); do_mob_tell(ch, questman, buf); break; case 3: sprintf(buf, "%s has been stealing valuables from the citizens of Arkham.", victim->short_descr); do_mob_tell(ch, questman, buf); sprintf(buf, "Make sure that %s never has the chance to steal again.", victim->short_descr); do_mob_tell(ch, questman, buf); break; } if (room->name != NULL) { sprintf(buf, "Seek %s out somewhere in the vicinity of %s!", victim->short_descr, room->name); do_mob_tell(ch, questman, buf); sprintf(buf, "That location is in the general area of %s.", room->area->name); do_mob_tell(ch, questman, buf); } ch->pcdata->questmob = victim->pIndexData->vnum; } if (ch->pcdata->questmob > 0 || ch->pcdata->questobj > 0) { SET_BIT(ch->act, PLR_QUESTOR); sprintf(buf, "You have %d minutes to complete this quest.", ch->pcdata->countdown); do_mob_tell(ch, questman, buf); do_mob_tell(ch, questman, "May the gods go with you!"); } else end_quest(ch, QUEST_TIME / 10); free_mem(mobs); return; } bool quest_level_diff(CHAR_DATA * ch, CHAR_DATA * mob) { int bonus = 20; /* can modify this */ if (IS_IMMORTAL(ch)) return TRUE; else if (ch->level > (mob->level + bonus) || ch->level < (mob->level - bonus)) return FALSE; else return TRUE; } void quest_update(void) { DESCRIPTOR_DATA *d; CHAR_DATA *ch; for (d = descriptor_first; d != NULL; d = d->next) { if (d->connected == CON_PLAYING && (ch = d->original ? d->original : d->character) != NULL) { if (ch->pcdata->nextquest > 0) { ch->pcdata->nextquest--; if (ch->pcdata->nextquest == 0) { chprintln(ch, "You may now quest again."); return; } } else if (IS_SET(ch->act, PLR_QUESTOR)) { if (--ch->pcdata->countdown <= 0) { end_quest(ch, QUEST_TIME - 2); chprintlnf(ch, "You have run out of time for your quest!\n\rYou may quest again in %d minutes.", ch->pcdata->nextquest); } if (ch->pcdata->countdown > 0 && ch->pcdata->countdown < 6) { chprintln(ch, "Better hurry, you're almost out of time for your quest!"); return; } } } } return; } void end_quest(CHAR_DATA * ch, int time) { REMOVE_BIT(ch->act, PLR_QUESTOR); ch->pcdata->questgiver = 0; ch->pcdata->countdown = 0; ch->pcdata->questmob = 0; ch->pcdata->questobj = 0; ch->pcdata->questloc = 0; ch->pcdata->nextquest = time; } /* handy dandy, victim must be an NPC */ void do_mob_tell(CHAR_DATA * ch, CHAR_DATA * victim, char *argument) { if (!victim) return; chprintlnf(ch, "%s tells you '%s'", victim->short_descr, argument); return; } CH_CMD(do_tpspend) { CHAR_DATA *triviamob; char buf[MAX_STRING_LENGTH]; char arg1[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; int sav_trust; argument = one_argument(argument, arg1); strcpy(arg2, argument); if (!ch || IS_NPC(ch)) return; if (arg1[0] == '\0') { chprintln(ch, "Syntax: Tpspend <item>"); chprintln(ch, " Tpspend list"); return; } if (is_name(arg1, "list")) { chprintln(ch, "Trivia Point Options"); chprintln(ch, "corpse retrival......1tp"); chprintln(ch, "transfer.............1tp"); chprintln(ch, "restore..............1tp"); chprintln(ch, "5 trains.............1tp"); chprintln(ch, "40 practices.........1tp"); chprintln(ch, "75 questpoints.......1tp"); chprintln(ch, "1 Trivia Pill........1tp"); chprintln(ch, "See HELP TRIVIA for important info before buying."); chprintln(ch, "For transfers and corpses, you do not have to be at a trivia shop."); return; } else if (is_name(arg1, "corpse")) { if (ch->pcdata->trivia >= 1) { OBJ_DATA *c; int count = 0; for (c = object_first; c != NULL; c = c->next) { if (is_name(ch->name, c->owner) && c->item_type == ITEM_CORPSE_PC) { if (c->in_room) obj_from_room(c); else if (c->carried_by) obj_from_char(c); else if (c->in_obj) obj_from_obj(c->in_obj); obj_to_room(c, ch->in_room); count++; } } if (count == 0) chprintln(ch, "You have no corpses in the game."); else { ch->pcdata->trivia -= 1; if (count == 1) { chprintln(ch, "Your corpse appears in the room."); act("$n's corpse appears in the room.", ch, NULL, NULL, TO_ROOM); } else { chprintln(ch, "All your corpses appear in the room."); act("All of $n's corpses appear in the room.", ch, NULL, NULL, TO_ROOM); } } return; } else { chprintln(ch, "You don't have enough trivia points for that."); return; } } else if (is_name(arg1, "transfer")) { if (ch->pcdata->trivia >= 1) { ROOM_INDEX_DATA *oldroom; if (arg2[0] == '\0') { chprintln(ch, "Transfer you where? [recall/room name/character name]"); return; } else if (!str_cmp(arg2, "recall")) sprintf(arg2, "%d", ROOM_VNUM_TEMPLE); oldroom = ch->in_room; sprintf(buf, "self '%s'", arg2); sav_trust = ch->trust; ch->trust = MAX_LEVEL; do_function(ch, &do_transfer, buf); ch->trust = sav_trust; if (oldroom != ch->in_room) ch->pcdata->trivia -= 1; else chprintln(ch, "Whoops! You were not charged for that transfer."); return; } else { chprintln(ch, "You don't have enough trivia points for that."); return; } } for (triviamob = ch->in_room->first_person; triviamob != NULL; triviamob = triviamob->next_in_room) { if (!IS_NPC(triviamob)) continue; if (triviamob->spec_fun == spec_lookup("spec_triviamob")) break; } if (triviamob == NULL || triviamob->spec_fun != spec_lookup("spec_triviamob")) { chprintln(ch, "You can't do that here."); return; } if (triviamob->fighting != NULL) { chprintln(ch, "Wait until the fighting stops."); return; } if (is_name(arg1, "practices pracs practice")) { if (ch->pcdata->trivia >= 1) { ch->pcdata->trivia -= 1; ch->practice += 40; act("$N gives 40 practices to $n.", ch, NULL, triviamob, TO_ROOM); act("$N gives you 40 practices.", ch, NULL, triviamob, TO_CHAR); return; } else { sprintf(buf, "Sorry, %s, but you don't have enough trivia points for that.", ch->name); do_mob_tell(ch, triviamob, buf); return; } } else if (is_name(arg1, "trains train")) { if (ch->pcdata->trivia >= 1) { ch->pcdata->trivia -= 1; ch->train += 5; act("$N gives 5 training sessions to $n.", ch, NULL, triviamob, TO_ROOM); act("$N gives you 5 training sessions.", ch, NULL, triviamob, TO_CHAR); return; } else { sprintf(buf, "Sorry, %s, but you don't have enough trivia points for that.", ch->name); do_mob_tell(ch, triviamob, buf); return; } } else if (is_name(arg1, "questpoints points")) { if (ch->pcdata->trivia >= 1) { ch->pcdata->trivia -= 1; ch->pcdata->questpoints += 75; /* a trivia point costs 100 quest points 25% conversion */ act("$N gives 75 questpoints to $n.", ch, NULL, triviamob, TO_ROOM); act("$N gives you 75 questpoints.", ch, NULL, triviamob, TO_CHAR); return; } else { sprintf(buf, "Sorry, %s, but you don't have enough trivia points for that.", ch->name); do_mob_tell(ch, triviamob, buf); return; } } else if (is_name(arg1, "pill")) { OBJ_DATA *obj = NULL; if (ch->pcdata->trivia >= 1) { obj = create_object(get_obj_index(OBJ_VNUM_TRIVIA_PILL), 1); if (obj != NULL) { act("$N gives $p to $n.", ch, obj, triviamob, TO_ROOM); act("$N gives you $p.", ch, obj, triviamob, TO_CHAR); obj_to_char(obj, ch); ch->pcdata->trivia -= 1; return; } else { sprintf(buf, "I don't any more trivia pills to give, %s.", ch->name); do_mob_tell(ch, triviamob, buf); } return; } else { sprintf(buf, "Sorry, %s, but you don't have enough trivia points for that.", ch->name); do_mob_tell(ch, triviamob, buf); return; } } else if (is_name(arg1, "restore")) { if (ch->pcdata->trivia >= 1) { sav_trust = ch->trust; ch->trust = MAX_LEVEL; do_function(ch, &do_restore, "all"); ch->trust = sav_trust; ch->pcdata->trivia -= 1; return; } else { sprintf(buf, "Sorry, %s, but you don't have enough trivia points for that.", ch->name); do_mob_tell(ch, triviamob, buf); return; } } else do_tpspend(ch, "list"); } CH_CMD(do_qpgive) { CHAR_DATA *victim; char arg[MAX_INPUT_LENGTH], buf[MAX_INPUT_LENGTH]; int amount; if (!ch || IS_NPC(ch)) return; argument = one_argument(argument, arg); if (argument[0] == '\0' || !is_number(arg)) { chprintln(ch, "Syntax: qpgive [amount] [person]"); return; } if ((amount = atoi(arg)) <= 0) { chprintln(ch, "Give how many questpoints?"); return; } if (amount > ch->pcdata->questpoints) { chprintln(ch, "You don't have that many questpoints to give."); return; } if ((victim = get_char_room(ch, NULL, argument)) == NULL) { chprintln(ch, "That person is not here."); return; } if (IS_NPC(victim)) { chprintln(ch, "NPC's don't need quest points."); return; } if (victim == ch) { sprintf(buf, "You give yourself %d questpoints..... don't you feel better?\n\r", amount); return; } ch->pcdata->questpoints -= amount; victim->pcdata->questpoints += amount; sprintf(buf, "%d", amount); act("$n gives you $t questpoints.", ch, buf, victim, TO_VICT); act("You give $N $t questpoints.", ch, buf, victim, TO_CHAR); act("$n gives $N $t questpoints.", ch, buf, victim, TO_ROOM); return; } CH_CMD(do_tpgive) { CHAR_DATA *victim; char arg[MAX_INPUT_LENGTH], buf[MAX_INPUT_LENGTH]; int amount; if (!ch || IS_NPC(ch)) return; argument = one_argument(argument, arg); if (argument[0] == '\0' || !is_number(arg)) { chprintln(ch, "Syntax: tpgive [amount] [person]"); return; } if ((amount = atoi(arg)) <= 0) { chprintln(ch, "Give how many trivia points?"); return; } if (amount > ch->pcdata->trivia) { chprintln(ch, "You don't have that many trivia points to give!!"); return; } if ((victim = get_char_room(ch, NULL, argument)) == NULL) { chprintln(ch, "That person is not here."); return; } if (IS_NPC(victim)) { chprintln(ch, "NPC's don't need trivia points."); return; } if (victim == ch) { sprintf(buf, "You give yourself %d trivia points..... don't you feel better?\n\r", amount); return; } ch->pcdata->trivia -= amount; victim->pcdata->trivia += amount; sprintf(buf, "%d", amount); act("$n gives you $t questpoints.", ch, buf, victim, TO_VICT); act("You give $N $t questpoints.", ch, buf, victim, TO_CHAR); act("$n gives $N $t questpoints.", ch, buf, victim, TO_ROOM); return; }