/************************************************************************** * 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 * *************************************************************************** * 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 * * address. Quest Code v2.03. Please do not remove this notice from this * * file. * *************************************************************************** * 1stMud ROM Derivative (c) 2001-2004 by Markanth * * http://www.firstmud.com/ <markanth@firstmud.com> * * By using this code you have agreed to follow the term of * * the 1stMud license in ../doc/1stMud/LICENSE * ***************************************************************************/ #include "merc.h" #include "magic.h" #include "interp.h" #include "recycle.h" #include "vnums.h" #include "special.h" #include "olc.h" Proto(bool quest_complete, (CharData *, CharData *)); struct quest_type { char *name; char *descr; int vnum; int cost; }; const struct quest_type quest_table[] = { {"nohunger", "No Hunger/Thirst (quest buy nohunger)", 0, 3000}, {"aura", NULL, OBJ_VNUM_QUEST_AURA, 2600}, {"sword", NULL, OBJ_VNUM_QUEST_SWORD, 2500}, {"breastplate", NULL, OBJ_VNUM_QUEST_BPLATE, 2500}, {"boots", NULL, OBJ_VNUM_QUEST_BOOTS, 2500}, {"gloves", NULL, OBJ_VNUM_QUEST_GLOVES, 2500}, {"flame", NULL, OBJ_VNUM_QUEST_FLAME, 2500}, {"helm", NULL, OBJ_VNUM_QUEST_HELM, 2300}, {"bag", NULL, OBJ_VNUM_QUEST_BAG, 1000}, {"shield", NULL, OBJ_VNUM_QUEST_SHIELD, 750}, {"regeneration", NULL, OBJ_VNUM_QUEST_REGEN, 700}, {"invisibility", NULL, OBJ_VNUM_QUEST_INVIS, 500}, {"trivia", NULL, OBJ_VNUM_QUEST_TRIVIA, 100}, {NULL, NULL, 0, 0} }; bool chance(int num) { return number_range(1, 100) <= num; } int add_qp(CharData * ch, int qp) { if (!ch || IsNPC(ch)) return qp; if (mud_info.bonus.status == BONUS_QP) { qp *= mud_info.bonus.mod; } ch->pcdata->quest.points += qp; return qp; } int qobj_lookup(ObjData * 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; } Lookup_Fun(quest_lookup) { int i; if (NullStr(name)) return -1; for (i = 0; quest_table[i].name != NULL; i++) { if (is_name(name, quest_table[i].name)) return i; } return -1; } money_t obj_cost(ObjData * 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 obj->cost; } void affect_join_obj(ObjData * obj, AffectData * paf) { AffectData *paf_old; bool found; found = false; for (paf_old = obj->affect_first; 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(ObjData * obj, apply_t loc, int mod, where_t where, int type, int dur, flag_t bit, int level) { AffectData 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; } void update_questobj(CharData * ch, ObjData * obj) { int bonus, pbonus; money_t cost; if (obj == NULL) { bug("update_questobj: NULL obj"); return; } if (ch == NULL) { bug("update_questobj: NULL ch"); return; } if (!IsObjStat(obj, ITEM_QUEST)) return; bonus = Max(5, ch->level / 10); pbonus = Max(5, ch->level / 5); cost = obj_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 (!CanWear(obj, ITEM_NO_SAC)) SetBit(obj->wear_flags, ITEM_NO_SAC); if (!IsObjStat(obj, ITEM_BURN_PROOF)) SetBit(obj->extra_flags, ITEM_BURN_PROOF); switch (obj->pIndexData->vnum) { case OBJ_VNUM_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 OBJ_VNUM_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 OBJ_VNUM_QUEST_AURA: add_apply(obj, APPLY_HIT, Max(50, ch->level), TO_OBJECT, 0, -1, 0, ch->level); add_apply(obj, APPLY_MANA, Max(50, ch->level), TO_OBJECT, 0, -1, 0, ch->level); add_apply(obj, APPLY_MOVE, Max(50, ch->level), TO_OBJECT, 0, -1, 0, ch->level); break; } switch (obj->item_type) { case ITEM_CONTAINER: 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: obj->value[1] = Max(15, ch->level); obj->value[2] = ch->level < (MAX_LEVEL / (25 / 10)) ? 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: obj->value[0] = Max(20, ch->level); obj->value[1] = Max(20, ch->level); obj->value[2] = Max(20, ch->level); obj->value[3] = (5 * Max(20, ch->level)) / 6; break; case ITEM_STAFF: obj->value[0] = Max(40, ch->level / 3); break; case ITEM_LIGHT: obj->value[2] = -1; break; case ITEM_PORTAL: if (!IsSet(obj->value[2], GATE_NOCURSE)) SetBit(obj->value[2], GATE_NOCURSE); if (!IsSet(obj->value[2], GATE_GOWITH)) SetBit(obj->value[2], GATE_GOWITH); break; default: break; } return; } void update_all_qobjs(CharData * ch) { ObjData *obj; wloc_t iWear; for (obj = ch->carrying_first; obj != NULL; obj = obj->next_content) { if (IsObjStat(obj, ITEM_QUEST)) { update_questobj(ch, obj); if ((iWear = obj->wear_loc) != WEAR_NONE) { unequip_char(ch, obj); equip_char(ch, obj, iWear); } } } } void unfinished_quest(CharData * ch) { if (!ch->pcdata) return; if (ch->pcdata->quest.status == QUEST_NONE || !ch->pcdata->quest.giver || !ch->pcdata->quest.room) { end_quest(ch, ch->pcdata->quest.time); return; } if (ch->pcdata->quest.mob) { ch->pcdata->quest.room = ch->pcdata->quest.mob->in_room; } if (ch->pcdata->quest.obj) { if (ch->pcdata->quest.status == QUEST_DELIVER) obj_to_char(ch->pcdata->quest.obj, ch); else obj_to_room(ch->pcdata->quest.obj, ch->pcdata->quest.room); } do_function(ch, &do_quest, "info"); } char *const qmob_desc[] = { "fiend", "criminal", "monster", "traitor", "outcast" }; char *const qobj_desc[] = { "treasure", "artifact", "item", "keepsake" }; int maxqmobdesc = sizeof(qmob_desc) / sizeof(qmob_desc[0]) - 1; int maxqobjdesc = sizeof(qobj_desc) / sizeof(qobj_desc[0]) - 1; Do_Fun(do_quest) { CharData *questman; ObjData *obj = NULL; char buf[MAX_STRING_LENGTH]; char arg1[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; int i = 0; if (IsNPC(ch)) { chprintln(ch, "I'm sorry, you can't quest."); return; } argument = one_argument(argument, arg1); argument = one_argument(argument, arg2); if (NullStr(arg1)) { cmd_syntax(ch, NULL, n_fun, "info", "request", "complate", "list", "buy", "quit", "sell", "identify", NULL); if (IsImmortal(ch)) cmd_syntax(ch, NULL, n_fun, "reset <player>", NULL); chprintln(ch, "For more information, see 'HELP QUEST'."); return; } else if (!str_prefix(arg1, "info")) { chprintln(ch, NULL); switch (ch->pcdata->quest.status) { default: chprintln(ch, "{RYour quest is {5ALMOST{x{R complete!{x"); act ("{RYou have $t to get back to %s{Rbefore your time runs out!{x", ch, intstr(ch->pcdata->quest.time, "minute"), ch->pcdata->quest.giver, TO_CHAR); return; case QUEST_NONE: chprintln(ch, "You aren't currently on a quest."); chprintlnf(ch, "There are %s remaining until you can go on another quest.", intstr(ch->pcdata->quest.time, "minute")); chprintlnf(ch, "You have %s.", intstr(ch->pcdata->quest.points, "quest point")); return; case QUEST_RETRIEVE: if (ch->pcdata->quest.obj != NULL) { act("You are on a quest to recover the fabled $p!", ch, ch->pcdata->quest.obj, NULL, TO_CHAR); chprintlnf(ch, "Rumor has it this %s was last seen in the area known as %s, near %s.", qobj_desc[number_range(0, maxqobjdesc)], ch->pcdata->quest.room->area->name, ch->pcdata->quest.room->name); return; } break; case QUEST_DELIVER: if (ch->pcdata->quest.obj != NULL && ch->pcdata->quest.mob != NULL) { act("You are on a quest to deliver $p to $N.", ch, ch->pcdata->quest.obj, ch->pcdata->quest.mob, TO_CHAR); chprintlnf(ch, "Rumor has it %s was last seen in the area known area %s, near %s.", GetName(ch->pcdata->quest.mob), ch->pcdata->quest.room->area->name, ch->pcdata->quest.room->name); return; } break; case QUEST_KILL: if (ch->pcdata->quest.mob != NULL) { act("You are on a quest to slay $N!", ch, NULL, ch->pcdata->quest.mob, TO_CHAR); chprintlnf(ch, "Rumor has it this %s was last seen in the area known as %s, near %s.", qmob_desc[number_range(0, maxqmobdesc)], ch->pcdata->quest.room->area->name, ch->pcdata->quest.room->name); return; } break; case QUEST_FINDROOM: if (ch->pcdata->quest.room != NULL) { chprintlnf(ch, "You are on a quest to find %s in %s!", ch->pcdata->quest.room->name, ch->pcdata->quest.room->area->name); return; } break; case QUEST_FINDMOB: if (ch->pcdata->quest.room != NULL && ch->pcdata->quest.mob != NULL) { chprintlnf(ch, "You are on a quest to find %s near %s in %s!", GetName(ch->pcdata->quest.mob), ch->pcdata->quest.room->name, ch->pcdata->quest.room->area->name); return; } break; } return; } else if (!str_prefix(arg1, "reset") && IsImmortal(ch)) { CharData *victim; if (NullStr(arg2)) { chprintln(ch, "Reset which player?"); return; } if ((victim = get_char_world(ch, arg2)) == NULL) { chprintln(ch, "They aren't here."); return; } if (IsNPC(victim)) { chprintln(ch, "Mobs dont quest."); return; } end_quest(victim, 0); if (victim == ch) chprintln(ch, "You clear your quest."); else act("$n has cleared your quest.", ch, NULL, victim, TO_VICT); return; } for (questman = ch->in_room->person_first; questman != NULL; questman = questman->next_in_room) { if (!IsNPC(questman)) continue; if (questman->spec_fun == spec_questmaster) break; } if (questman == NULL) { chprintln(ch, "You can't do that here."); return; } if (questman->fighting != NULL) { chprintln(ch, "Wait until the fighting stops."); return; } if (!str_prefix(arg1, "list")) { ObjIndex *test; 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].name != NULL; i++) { test = get_obj_index(quest_table[i].vnum); chprintlnf(ch, "\t%-4dqp ........ %s", quest_table[i].cost, test ? test->short_descr : quest_table[i].descr != NULL ? quest_table[i].descr : "Unavailable"); } chprintlnf(ch, "\tTo buy an item, type '%s buy <item>'.", n_fun); return; } else if (!str_prefix(arg1, "buy")) { if (NullStr(arg2)) { chprintlnf(ch, "To buy an item, type '%s buy <item>'.", n_fun); return; } if ((i = quest_lookup(arg2)) == -1) { mob_tell(ch, questman, "I don't have that item, %s.", ch->name); return; } if (ch->pcdata->quest.points < quest_table[i].cost) { mob_tell(ch, questman, "You need %s for that.", intstr(quest_table[i].cost, "questpoint")); return; } if (quest_table[i].vnum == 0) { ch->pcdata->quest.points -= quest_table[i].cost; ch->pcdata->condition[COND_FULL] = -1; ch->pcdata->condition[COND_HUNGER] = -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; } ch->pcdata->quest.points -= quest_table[i].cost; 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 if (!str_prefix(arg1, "sell")) { if (NullStr(arg2)) { chprintlnf(ch, "To sell an item, type '%s sell <item>'.", n_fun); return; } if ((obj = get_obj_carry(ch, arg2, ch)) == NULL) { chprintln(ch, "Which item is that?"); return; } if (!IsObjStat(obj, ITEM_QUEST)) { mob_tell(ch, questman, "That is not a quest item."); return; } if ((i = qobj_lookup(obj)) == -1) { mob_tell(ch, questman, "I only take items I sell, %s.", ch->name); return; } ch->pcdata->quest.points += quest_table[i].cost / 3; act("$N takes $p from $n.", ch, obj, questman, TO_ROOM); sprintf(buf, "$N takes $p from you for %s.", intstr(quest_table[i].cost / 3, "questpoint")); act(buf, ch, obj, questman, TO_CHAR); extract_obj(obj); save_char_obj(ch); return; } else if (!str_prefix(arg1, "identify")) { if (NullStr(arg2)) { chprintlnf(ch, "To identify an item, type '%s identify <item>'.", n_fun); return; } if ((i = quest_lookup(arg2)) == -1) { mob_tell(ch, questman, "I don't have that item."); return; } if (quest_table[i].vnum == 0) { chprintln(ch, "That isn't a quest item."); return; } 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; } obj_to_char(obj, ch); act("$p costs $T.", ch, obj, intstr(quest_table[i].cost, "questpoint"), TO_CHAR); spell_identify(0, ch->level, ch, obj, TAR_OBJ_INV); extract_obj(obj); return; } else if (!str_prefix(arg1, "request")) { quest_t type = QUEST_NONE; if (IsImmortal(ch)) { if (NullStr(arg2)) { chprintlnf(ch, "{W%s{x" NEWLINE " {GAvailable Quests" NEWLINE "{W%s{x" NEWLINE " {Y1{D. {GFind a room in the realm" NEWLINE " {Y2{D. {GFind a person" NEWLINE " {Y3{D. {GRetrieve stolen property" NEWLINE " {Y4{D. {GDeliver priceless artifact" NEWLINE " {Y5{D. {GHunt down heinous criminal" NEWLINE " {Y6{D. {GRandom quest 1-5" NEWLINE "{W%s{x" NEWLINE "{xTo get a quest, type {WQUEST REQUEST {D<{Ynumber{D>" NEWLINE "{W%s{x", draw_line(ch, NULL, 58), draw_line(ch, NULL, 58), draw_line(ch, NULL, 58), draw_line(ch, NULL, 58)); return; } if (!is_number(arg2)) { chprintln(ch, "{xTo get a quest, type {WQUEST REQUEST {D<{Ynumber{D>"); return; } switch (atoi(arg2)) { case 1: type = QUEST_FINDROOM; break; case 2: type = QUEST_FINDMOB; break; case 3: type = QUEST_RETRIEVE; break; case 4: type = QUEST_DELIVER; break; case 5: type = QUEST_KILL; break; case 6: break; default: chprintln(ch, "Invalid quest request."); 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 (IsQuester(ch)) { act("$N rejects $n's request.", ch, NULL, questman, TO_ROOM); mob_tell(ch, questman, "But you're already on a quest!"); return; } if (IsImmortal(ch)) end_quest(ch, 0); if (ch->pcdata->quest.time > 0) { mob_tell(ch, questman, "You're very brave, %s, but let someone else have a chance.", ch->name); mob_tell(ch, questman, "Come back later."); return; } mob_tell(ch, questman, "Thank you, brave %s!", ch->name); generate_quest(ch, questman, type); if (IsQuester(ch)) mud_info.stats.quests++; return; } else if (!str_prefix(arg1, "complete")) { if (ch->pcdata->quest.giver != questman) { mob_tell(ch, questman, "I never sent you on a quest! Perhaps you're thinking of someone else."); return; } if (IsQuester(ch)) { if (quest_complete(ch, questman)) return; else if (ch->pcdata->quest.status > QUEST_NONE && ch->pcdata->quest.time > 0) { mob_tell(ch, questman, "You haven't completed the quest yet, but there is still time!"); return; } } else mob_tell(ch, questman, "You have to REQUEST a quest first."); return; } else if (!str_prefix(arg1, "quit") || !str_prefix(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->quest.giver != questman) { mob_tell(ch, questman, "I never sent you on a quest! Perhaps you're thinking of someone else."); return; } if (IsQuester(ch)) { end_quest(ch, QUEST_TIME * 3 / 2); 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; } } do_quest(n_fun, ch, ""); return; } #define MAX_QMOB_COUNT mobile_count CharData *random_quest_mob(CharData * ch, CharData * questman) { CharData *victim; CharData **mobs; int mob_count; int mrange; alloc_mem(mobs, CharData *, MAX_QMOB_COUNT); mob_count = 0; for (victim = char_first; victim; victim = victim->next) { if (!IsNPC(victim) || !quest_level_diff(ch, victim) || victim->pIndexData == NULL || victim->in_room == NULL || victim->pIndexData->pShop != NULL || (IsEvil(victim) && IsEvil(ch) && chance(50)) || (IsGood(victim) && IsGood(ch) && chance(50)) || victim->pIndexData->vnum < 100 || victim->in_room->area->clan != NULL || IsSet(victim->imm_flags, IMM_WEAPON | IMM_MAGIC) || IsSet(victim->act, ACT_TRAIN | ACT_PRACTICE | ACT_IS_HEALER | ACT_PET | ACT_PET | ACT_GAIN) || IsSet(victim->affected_by, AFF_CHARM) || IsSet(victim->in_room->room_flags, ROOM_PET_SHOP) || questman->pIndexData == victim->pIndexData || (IsSet(victim->act, ACT_SENTINEL) && IsSet(victim->in_room->room_flags, ROOM_PRIVATE | ROOM_SOLITARY | ROOM_SAFE))) continue; mobs[mob_count++] = victim; if (mob_count >= MAX_QMOB_COUNT) break; } do { mrange = number_range(0, mob_count - 1); } while ((victim = mobs[mrange]) == NULL); free_mem(mobs); return victim; } void generate_quest(CharData * ch, CharData * questman, quest_t type) { CharData *victim; if ((victim = random_quest_mob(ch, questman)) == NULL) { mob_tell(ch, questman, "I'm sorry, but I don't have any quests for you at this time."); mob_tell(ch, questman, "Try again later."); end_quest(ch, QUEST_TIME / 10); return; } ch->pcdata->quest.giver = questman; ch->pcdata->quest.room = victim->in_room; ch->pcdata->quest.time = number_range(15, 30); ch->pcdata->quest.status = type > QUEST_NONE ? type : chance(10) ? (chance(50) ? QUEST_FINDMOB : QUEST_FINDROOM) : chance(20) ? (chance(50) ? QUEST_RETRIEVE : QUEST_DELIVER) : QUEST_KILL; switch (ch->pcdata->quest.status) { case QUEST_RETRIEVE: ch->pcdata->quest.obj = create_quest_obj(ch, -1); obj_to_room(ch->pcdata->quest.obj, ch->pcdata->quest.room); replace_str(&ch->pcdata->quest.obj->owner, ch->name); ch->pcdata->quest.obj->cost = 0; ch->pcdata->quest.obj->timer = (4 * ch->pcdata->quest.time + 10) / 3; ch->pcdata->quest.mob = NULL; switch (number_range(0, 1)) { default: case 0: mob_tell(ch, questman, "Vile pilferers have stolen %s from the royal treasury!", ch->pcdata->quest.obj->short_descr); mob_tell(ch, questman, "My court wizardess, with her magic mirror, has pinpointed its location."); break; case 1: mob_tell(ch, questman, "A powerful wizard has stolen %s for his personal power!", ch->pcdata->quest.obj->short_descr); break; } mob_tell(ch, questman, "This %s was last seen somewhere in the vicinity of %s!", qobj_desc[number_range(0, maxqobjdesc)], victim->in_room->name); break; case QUEST_KILL: ch->pcdata->quest.mob = victim; ch->pcdata->quest.obj = NULL; switch (number_range(0, 3)) { default: case 0: mob_tell(ch, questman, "An enemy of mine, %s, is making vile threats against the crown.", GetName(victim)); mob_tell(ch, questman, "This threat must be eliminated!"); break; case 1: mob_tell(ch, questman, "{n's most heinous criminal, %s, has escaped from the dungeon!", GetName(victim)); mob_tell(ch, questman, "Since the escape, %s has murdered %d civillians!", GetName(victim), number_range(2, 20)); mob_tell(ch, questman, "The penalty for this crime is death, and you are to deliver the sentence!"); break; case 2: mob_tell(ch, questman, "The Mayor of Midgaard has recently been attacked by %s. This is an act of war!", GetName(victim)); mob_tell(ch, questman, "%s must be severly dealt with for this injustice.", GetName(victim)); break; case 3: mob_tell(ch, questman, "%s has been stealing valuables from the citizens of %s.", GetName(victim), victim->in_room->area->name); mob_tell(ch, questman, "Make sure that %s never has the chance to steal again.", GetName(victim)); break; } mob_tell(ch, questman, "Seek this %s out somewhere in the vicinity of %s!", qmob_desc[number_range(0, maxqmobdesc)], victim->in_room->name); break; case QUEST_DELIVER: RemBit(victim->act, ACT_AGGRESSIVE); victim->position = POS_STANDING; victim->spec_fun = NULL; ch->pcdata->quest.obj = create_quest_obj(ch, -1); ch->pcdata->quest.mob = victim; ch->pcdata->quest.room = victim->in_room; obj_to_char(ch->pcdata->quest.obj, ch); mob_tell(ch, questman, "Please deliver this %s to my friend - %s. Time is the essence, please hurry.", ch->pcdata->quest.obj->short_descr, victim->short_descr); mob_tell(ch, questman, "Seek %s out somewhere in the vicinity of {W%s{x!", victim->short_descr, victim->in_room->name); act("$n gives $p to $N.", questman, ch->pcdata->quest.obj, ch, TO_NOTVICT); act("$n gives you $p.", questman, ch->pcdata->quest.obj, ch, TO_VICT); act("You give $p to $N.", questman, ch->pcdata->quest.obj, ch, TO_CHAR); break; case QUEST_FINDROOM: ch->pcdata->quest.mob = NULL; ch->pcdata->quest.obj = NULL; ch->pcdata->quest.room = victim->in_room; mob_tell(ch, questman, "This quest tests your knowledge of {n. Your goal is simple, seek out"); mob_tell(ch, questman, "the location '{W%s{x' and return to me.", victim->in_room->name); mob_tell(ch, questman, "You will be told when you find the right place."); break; case QUEST_FINDMOB: ch->pcdata->quest.mob = victim; ch->pcdata->quest.obj = NULL; ch->pcdata->quest.room = victim->in_room; mob_tell(ch, questman, "This quest tests your knowledge of {n. Your goal is simple, seek out"); mob_tell(ch, questman, "'{W%s{x' in vicinity of {W%s{x, and return to me.", victim->short_descr, victim->in_room->name); mob_tell(ch, questman, "You will be told when you find the right person."); break; default: bug("generate_quest(): bad quest type"); end_quest(ch, QUEST_TIME / 5); return; } mob_tell(ch, questman, "The location is in the general area of %s.", victim->in_room->area->name); mob_tell(ch, questman, "You have %s to complete this quest.", intstr(ch->pcdata->quest.time, "minute")); mob_tell(ch, questman, "May %s go with you!", ch->deity->name); return; } bool quest_level_diff(CharData * ch, CharData * mob) { int bonus = 10 + lvl_bonus(ch); if (IsImmortal(ch)) return true; else if (ch->level > (mob->level + bonus) || ch->level < (mob->level - bonus)) return false; else return true; } void quest_update(void) { CharData *ch; for (ch = player_first; ch != NULL; ch = ch->next_player) { if (!ch->desc || ch->desc->connected != CON_PLAYING || ch->pcdata->quest.time <= 0) continue; if (ch->pcdata->quest.status != QUEST_NONE) { if (--ch->pcdata->quest.time <= 0) { end_quest(ch, QUEST_TIME - 2); chprintlnf(ch, "{RYou have run out of time for your quest!" " You may quest again in %d minutes.{x", ch->pcdata->quest.time); } else if (ch->pcdata->quest.time < 6) { chprintln(ch, "{pBetter hurry, you're almost out of time for your quest!"); return; } } else { if (--ch->pcdata->quest.time <= 0) { chprintln(ch, "{WYou may now {?quest{W again.{x"); return; } } } return; } void end_quest(CharData * ch, int time) { if (!ch || IsNPC(ch)) return; ch->pcdata->quest.status = QUEST_NONE; ch->pcdata->quest.giver = 0; ch->pcdata->quest.time = time; ch->pcdata->quest.mob = 0; ch->pcdata->quest.obj = 0; ch->pcdata->quest.room = 0; } void quest_reward(CharData * ch, CharData * questman, quest_t type) { money_t reward = 0; int pointreward = 0; int time = 0; switch (type) { case QUEST_RETURN_KILL: pointreward = 50; reward = ch->level * 4; break; case QUEST_RETURN_DELIVER: pointreward = 40; reward = ch->level * 3; break; case QUEST_RETURN_RETRIEVE: pointreward = 30; reward = ch->level * 2; break; case QUEST_RETURN_FINDMOB: pointreward = 25; reward = ch->level * 2; time = -4; break; case QUEST_RETURN_FINDROOM: pointreward = 20; reward = ch->level * 2; time = -5; break; default: pointreward = 20; reward = ch->level; break; } pointreward = number_range(pointreward * 4 / 5, pointreward); reward = number_range(reward * 4 / 5, reward); if (pointreward + ch->pcdata->quest.points > 32000) { unsigned int t = 0; t = (pointreward + ch->pcdata->quest.points) - 32000; pointreward -= t; reward += t; } if (ch->pcdata->quest.obj != NULL) extract_obj(ch->pcdata->quest.obj); if (ch->pcdata->quest.mob != NULL) { if (IsNPC(ch->pcdata->quest.mob)) { ch->pcdata->quest.mob->master = NULL; extract_char(ch->pcdata->quest.mob, true); } } end_quest(ch, QUEST_TIME + time); ch->gold += reward; pointreward = add_qp(ch, pointreward); act("$N congratulates $n.", ch, NULL, questman, TO_ROOM); mob_tell(ch, questman, "Congratulations on completing your quest! As a reward, I am giving you {W%s{x, and {Y%ld{x gold.", intstr(pointreward, "quest point"), reward); if (chance(pointreward / 5)) { chprintln(ch, "You gain an extra {YTrivia {RPoint{x!"); ch->pcdata->trivia += 1; } mud_info.stats.qcomplete++; save_char_obj(ch); return; } bool quest_complete(CharData * ch, CharData * questman) { ObjData *obj = NULL, *obj_next; if (ch->pcdata->quest.time <= 0) { act("$N informs $n about returning too late.", ch, NULL, questman, TO_ROOM); chprintln(ch, NEWLINE "But you didn't complete your quest in time!"); end_quest(ch, QUEST_TIME + 5); return true; } switch (ch->pcdata->quest.status) { case QUEST_NONE: act("$N explains $n how to request quest.", ch, NULL, questman, TO_ROOM); chprintln(ch, NEWLINE "You have to REQUEST a quest first."); return true; break; case QUEST_KILL: case QUEST_RETRIEVE: case QUEST_DELIVER: case QUEST_FINDMOB: case QUEST_FINDROOM: return false; break; case QUEST_RETURN_KILL: case QUEST_RETURN_FINDMOB: case QUEST_RETURN_FINDROOM: case QUEST_RETURN_DELIVER: quest_reward(ch, questman, ch->pcdata->quest.status); return true; break; case QUEST_RETURN_RETRIEVE: { bool obj_found = false; for (obj = ch->carrying_first; obj != NULL; obj = obj_next) { obj_next = obj->next_content; if (obj == ch->pcdata->quest.obj) { if (is_name(ch->name, obj->owner)) { obj_found = true; break; } else { chprintln(ch, "Cheating is not nice, you know?"); act("$N calls $n cheater!", ch, NULL, questman, TO_ROOM); act("$N calls You cheater!", ch, NULL, questman, TO_CHAR); obj->timer = 1; } } } if (obj_found == true) { quest_reward(ch, questman, ch->pcdata->quest.status); } else { act("$N sends $n to complete his quest.", ch, NULL, questman, TO_ROOM); chprintln(ch, NEWLINE "You haven't completed the quest yet, but there is still time!"); } return true; } break; default: return false; } } void quest_room_check(CharData * ch) { CharData *victim; if (!IsQuester(ch) || ch->in_room != ch->pcdata->quest.room) return; switch (ch->pcdata->quest.status) { case QUEST_FINDROOM: chprintln(ch, NEWLINE "{5+RYou have almost completed your QUEST!{x"); act("{RReturn to $N{R before your time runs out!{x", ch, NULL, ch->pcdata->quest.giver, TO_CHAR); ch->pcdata->quest.status = QUEST_RETURN_FINDROOM; ch->pcdata->quest.room = NULL; break; case QUEST_FINDMOB: for (victim = ch->in_room->person_first; victim != NULL; victim = victim->next_in_room) { if (victim != ch->pcdata->quest.mob) continue; do_function(victim, &do_say, "Excellent! You have found me. Good job!"); chprintln(ch, NEWLINE "{5+RYou have almost completed your QUEST!"); act("{RReturn to $N{R before your time runs out!{x", ch, NULL, ch->pcdata->quest.giver, TO_CHAR); ch->pcdata->quest.status = QUEST_RETURN_FINDMOB; ch->pcdata->quest.mob = NULL; break; } break; case QUEST_KILL: for (victim = ch->in_room->person_first; victim != NULL; victim = victim->next_in_room) { if (victim != ch->pcdata->quest.mob) continue; act("$N eye's you warily...", ch, NULL, victim, TO_CHAR); act("$N eye's $n warily...", ch, NULL, victim, TO_ROOM); break; } break; case QUEST_DELIVER: for (victim = ch->in_room->person_first; victim != NULL; victim = victim->next_in_room) { if (victim != ch->pcdata->quest.mob) continue; act("$N smiles at you...", ch, NULL, victim, TO_CHAR); act("$N smiles at $n...", ch, NULL, victim, TO_ROOM); break; } break; default: break; } } void mob_tell(CharData * ch, CharData * victim, const char *argument, ...) { char buf[MSL]; va_list args; if (!victim || NullStr(argument)) return; va_start(args, argument); vsnprintf(buf, sizeof(buf), argument, args); va_end(args); chprintlnf(ch, CTAG(_TELLS1) "%s " CTAG(_TELLS1) "tells you '" CTAG(_TELLS2) "%s" CTAG(_TELLS1) "'{x", GetName(victim), str_rep(buf, "{x", CTAG (_TELLS2))); return; } Do_Fun(do_tpspend) { CharData *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 || IsNPC(ch)) return; if (NullStr(arg1)) { cmd_syntax(ch, NULL, n_fun, "<item>", "list", NULL); return; } if (is_name(arg1, "list")) { chprintln(ch, "Trivia Point Options"); chprintln(ch, "Pretitle.............5tp"); chprintln(ch, "PK Flag..............5tp"); 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 (ch->pcdata->trivia >= 1) { if (is_name(arg1, "corpse")) { ObjData *c; int count = 0; for (c = obj_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 if (is_name(arg1, "transfer")) { RoomIndex *oldroom; if (NullStr(arg2)) { chprintln(ch, "Transfer you where? [recall/room name/character name]"); return; } else if (!str_prefix(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->person_first; triviamob != NULL; triviamob = triviamob->next_in_room) { if (!IsNPC(triviamob)) continue; if (triviamob->spec_fun == spec_triviamob) break; } if (triviamob == NULL) { chprintln(ch, "You can't do that here."); return; } if (triviamob->fighting != NULL) { chprintln(ch, "Wait until the fighting stops."); return; } if (ch->pcdata->trivia >= 1) { if (is_name(arg1, "practices pracs practice")) { 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 if (is_name(arg1, "trains train")) { 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 if (is_name(arg1, "questpoints points")) { ch->pcdata->trivia -= 1; ch->pcdata->quest.points += 75; 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 if (is_name(arg1, "pill")) { ObjData *obj = NULL; 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 { mob_tell(ch, triviamob, "I don't any more trivia pills to give."); } return; } else if (is_name(arg1, "restore")) { sav_trust = ch->trust; ch->trust = MAX_LEVEL; do_function(ch, &do_restore, "all"); ch->trust = sav_trust; ch->pcdata->trivia -= 1; return; } else { mob_tell(ch, triviamob, "You don't have enough trivia points for that."); return; } } else if (ch->pcdata->trivia >= 5) { if (is_name(arg1, "pretitle")) { if (NullStr(argument)) { cmd_syntax(ch, NULL, "trivia pretitle", "clear - remove a pretitle free of charge.", "<string> - set your pretitle.", NULL); return; } else if (is_name(argument, "none reset clear")) { if (NullStr(ch->pcdata->pretit)) { mob_tell(ch, triviamob, "You have no pretitle to remove!"); return; } replace_str(&ch->pcdata->pretit, ""); mob_tell(ch, triviamob, "OK, your pretitle has been removed."); } else { if (validate_pretit(ch, &argument)) { ch->pcdata->trivia -= 5; replace_str(&ch->pcdata->pretit, argument); mob_tell(ch, triviamob, "Ok, you are now %s %s", ch->pcdata->pretit, ch->name); } return; } } else if (is_name(arg1, "pkiller")) { if (is_clan(ch)) { chprintlnf(ch, "You are in a clan, try the '%s' command.", cmd_name(do_pk)); return; } if (PlrFlag(ch, PLR_PK) && GetTimer(ch, TIMER_PK) > current_time) { chprintlnf(ch, "You are already a player killer for %s.", timestr(GetTimer(ch, TIMER_PK) - current_time, false)); return; } SetBit(ch->act, PLR_PK); SetTimer(ch, TIMER_PK, current_time + (HOUR * 100)); ch->pcdata->trivia -= 5; chprintlnf(ch, "You are now a player killer for %s.", timestr(GetTimer(ch, TIMER_PK) - current_time, false)); new_wiznet(ch, NULL, WIZ_DEATHS, true, get_trust(ch), "$N is now a player killer."); return; } else { mob_tell(ch, triviamob, "You don't have enough trivia points for that."); return; } } else do_tpspend(n_fun, ch, "list"); } Do_Fun(do_qpgive) { CharData *victim; char arg[MAX_INPUT_LENGTH], buf[MAX_INPUT_LENGTH]; int amount; if (!ch || IsNPC(ch)) return; argument = one_argument(argument, arg); if (NullStr(argument) || !is_number(arg)) { cmd_syntax(ch, NULL, n_fun, "<amount> <person>", NULL); return; } if ((amount = atoi(arg)) <= 0) { chprintln(ch, "Give how many questpoints?"); return; } if (amount > ch->pcdata->quest.points) { 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 (IsNPC(victim)) { chprintln(ch, "NPC's don't need quest points."); return; } if (victim == ch) { chprintlnf(ch, "You give yourself %s..... don't you feel better?", intstr(amount, "questpoint")); return; } ch->pcdata->quest.points -= amount; victim->pcdata->quest.points += 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; } Do_Fun(do_tpgive) { CharData *victim; char arg[MAX_INPUT_LENGTH], buf[MAX_INPUT_LENGTH]; int amount; if (!ch || IsNPC(ch)) return; argument = one_argument(argument, arg); if (NullStr(argument) || !is_number(arg)) { cmd_syntax(ch, NULL, n_fun, "<amount> <person>", NULL); 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 (IsNPC(victim)) { chprintln(ch, "NPC's don't need trivia points."); return; } if (victim == ch) { chprintlnf(ch, "You give yourself %s..... don't you feel better?", intstr(amount, "trivia point")); 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; } CharData *find_quest_char(CharData * ch, vnum_t vnum) { CharData *mob, *found = NULL; if (ch->pcdata->quest.mob) return ch->pcdata->quest.mob; for (mob = char_first; mob; mob = mob->next) { if ((IsNPC(mob) ? mob->pIndexData->vnum : mob->id) != vnum) continue; found = mob; if (!IsNPC(mob) || mob->pIndexData->spec_fun == spec_lookup("spec_questmaster") || mob->in_room == ch->pcdata->quest.room) break; } if (!found) { CharIndex *pMob = get_char_index(vnum); if (!pMob || (found = create_mobile(pMob)) == NULL) { if ((found = random_quest_mob(ch, ch->pcdata->quest.giver)) == NULL) { end_quest(ch, ch->pcdata->quest.time); return NULL; } } } return found; } vnum_t random_quest_piece(void) { vnum_t objvnum = 0; switch (number_range(0, 3)) { case 0: objvnum = OBJ_VNUM_QUEST1; break; case 1: objvnum = OBJ_VNUM_QUEST2; break; case 2: objvnum = OBJ_VNUM_QUEST3; break; case 3: objvnum = OBJ_VNUM_QUEST4; break; } return objvnum; } ObjData *create_quest_obj(CharData * ch, vnum_t vnum) { ObjData *obj; int check = 0; if (ch->pcdata->quest.obj != NULL) return ch->pcdata->quest.obj; if (vnum <= 0) vnum = random_quest_piece(); while ((obj = create_object(get_obj_index(vnum), ch->level)) == NULL) { vnum = random_quest_piece(); if (++check >= 10) { bug("Bad vnum"); return NULL; } } replace_str(&obj->owner, ch->name); obj->cost = 0; obj->timer = (4 * ch->pcdata->quest.time + 10) / 3; return obj; } void extract_quest(CharData * ch) { if (IsNPC(ch)) return; if (ch->pcdata->quest.obj) extract_obj(ch->pcdata->quest.obj); }