/* * MusicMUD - Missions module * Copyright (C) 1998-2003 Abigail Brady * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "musicmud.h" #include "verbs.h" #include "util.h" #include "pflags.h" #include "Mission.h" #include "misc.h" #include "hooks.h" #include "trap.h" #include "events.h" #include "prep.h" #include "shared.h" #include "musictok.h" #include "nations.h" #define MODULE "mission" static bool same_nation(MudObject *o1, MudObject *o2) { const char *n1 = nation(o1); const char *n2 = nation(o2); if (n1 == n2) return 1; if (!n1 || !n2) return 0; if (streq(n1, n2)) return 1; if (strchr(n1, ':')) { char *raw=strdup(n1); *strchr(raw, ':')=0; int yes = streq(raw, n2); free(raw); if (yes) return yes; } StrTok a(n1); while ((n1=a.next(","))) { if (streq(n1, n2)) return 1; n1 = a.next(","); } return 0; } static MudObject *tocontact(MudObject *who) { MudObject *w = who->get_object("contact"); if (!w) return 0; if (!is_player(w)) return 0; Player *p = (Player*)w; if (p->get_idle() < (now - 10 * 60)) return 0; return w; } static bool can_access(MudObject *board, MudObject *who, MudObject *what, const char **reason=0, int domutex=1) { if (tocontact(who)) { if (reason) *reason = " you have an urgent mission to do"; return false; } if (what->owner == who) { if (reason) *reason = " as you are already doing it"; return false; } if (!same_nation(board, what)) { if (reason) *reason = " it is not available here"; return false; } if (what->owner != who && is_player(what->owner)) { if (reason) *reason = " someone else is doing it"; return false; } if (what->get_flag(FL_PRIVATE)) { if (reason) *reason = " because it is not open to the public"; return false; } if (what->get_flag(FL_INVISIBLE)) { if (reason) *reason = " because it doesn't exist"; return false; } if (what->get_flag(FL_DONE)) { if (reason) *reason = " because it has already been done : wait a while for it to become available"; return false; } if (what->owner == planet->get("empty")) { if (reason) *reason = " because it has been ruined : wait a while for it to become available"; return false; } if (domutex) { if (MudObject *quest_needed=what->get_object("quest_needed")) { if (!quest_done(who, quest_needed)) { if (reason) *reason = " because you have not done all the prerequisites for it"; return false; } } if (what->get_flag(FL_QUEST) && quest_done(who, what)) { if (reason) *reason = " as you have already done it"; return false; } MudObject *mutex = what->get_object("mutex"); if (mutex) { if (!can_access(board, who, mutex, reason, 0)) { return false; } } } return true; } static void mins(char *str, int when) { if (when <= 0) sprintf(str, "Now"); else if (when <= 60) sprintf(str, "%i m", when/60+1); else sprintf(str, "%i m", when/60+1); } static int mission_id(const void *first, const void *second) { MudObject *a = *((Player **)first); MudObject *b = *((Player **)second); if (a->get_flag(FL_QUEST) && !b->get_flag(FL_QUEST)) return 1; if (b->get_flag(FL_QUEST) && !a->get_flag(FL_QUEST)) return -1; int p1 = a->get_int("m_id", 100); int p2 = b->get_int("m_id", 100); if (p1>p2) return 1; if (p1==p2) { return strcmp(a->get("mname"), b->get("mname")); return 0; } return -1; } static bool verb_mmlist(MudObject *who, int argc, const char **argv) { MudObject *board = get_flagged_object(who->owner, FL_MISSIONSBOARD); if (!board) { who->printf("There is no board here.\n"); return true; } MudObject *minis = MUD_MISSIONSBOARD; if (board->get_object("board")) minis = board->get_object("board"); int size = minis ? minis->children->getsize() : 0; MudObject *what = planet->get("quest_zone"); if (what) size += what->children->getsize(); if (!size) { who->printf("No minimissions avilable.\n"); return true; } Divert d(who, "mmlist"); MudObject *moo[size]; int footnote = 0; int pc = 0; MudObject *o; int i; if (minis) foreach(minis->children, o, i) { moo[pc] = o; pc++; } if (what) foreach(what->children, o, i) { moo[pc] = o; pc++; } qsort(moo, pc, sizeof (MudObject *), mission_id); who->printf("^W%10s %4s %4s %s^n\n\n", "ID", "Pts", "Life", "Description"); if (MudObject *c=tocontact(who)) { who->printf("^B%10s ^Y %2i ^R%-7s ^{g^ZReport to %M immediately.^}\n", "99", 0, "", c); } for (int j=0;j<pc;j++) { o = moo[j]; const char *b=o->get("bzone"); if (b && !streq(b, board->get("zone")) && !streq(b, "*")) continue; if (is_player(o)) continue; if (can_access(board, who, o) || (IS_CAPTAIN(who) && (same_nation(board, o)))) { time_t when = o->get_int("deadline"); char tim[100]; if (when == -1) strcpy(tim, ""); else mins(tim, when - now); if (o->get_flag(FL_PRIVATE)) { strcpy(tim, "^RPriv^n"); } else if (o->get_flag(FL_TAMPERED)) { strcpy(tim, "^R[*]^n"); footnote = 1; } int pts = o->get_int("questpoints", quest_done(who, o) ? 0 : 1); string link = ""; if (o->get("mname")) { link = ssprintf("\3send href='accept %s'\4^M%s^n\3/send\4", o->get("mname"), o->get("mname")); } else { link = ssprintf("\3send href='accept %i'\4%i\3/send\4", o->get_int("m_id"), o->get_int("m_id")); } string str = ssprintf("%10s ^Y%3i ^R%-4s ^{g^Z%s^}\n", link.c_str(), pts, tim, o->get("short_brief") ? o->get("short_brief") : o->get("desc")); who->printf("%s", str.c_str()); } } if (privs_of(who)<10) { who->printf("\nSee '^Winfo missions^n' for details on this system.\n"); } if (footnote) { who->printf("^R[*]^n - mission might have been ruined.\n"); } return true; } static bool verb_mmtimeout(MudObject *who, int argc, const char **argv) { if (who->get_flag(FL_SLEEPING)) { who->printf("You toss and turn in your sleep.\n"); who->oprintf(cansee, "%#M tosses and turns in %s sleep.\n",who, his_or_her(who)); return true; } MudObject *board = get_flagged_object(who->owner, FL_MISSIONSBOARD); int removed = 0; if (!board) { who->printf("No board here.\n"); return true; } if (board->children->getsize()) { MudObject *o; int i; foreach(board->children, o, i) { int when = o->get_int("deadline"); if (when != -1 && now>when) { if (o->get(KEY_ACCEPTER)) { MudObject *what = o->get_object(KEY_ACCEPTER); if (what) { what->unset("mission"); what->printf("Your mission deadline has been reached.\n"); } } mission_cleanup(o); removed++; } } } if (removed==1) who->oprintf(cansee, "%#M pulls a notice from the ^omissions^n board.\n", who); else if (removed>1) who->oprintf(cansee, "%#M removes %s notices from the ^nmissions^n board.\n", who, numbertostring(removed)); return true; } //! make /who/ accept /quest/ static void accept_mission(MudObject *who, MudObject *quest) { who->set("mission", quest->id); quest->set(KEY_ACCEPTER, who->id); quest->set("!acceptedat", now); quest->set_flag(FL_TAMPERED, 1); set_owner(quest, who); if (quest->get("mname")) { who->printf("You accept ^M%s^n.\n", quest->get("mname")); log(PFL_SEEINFO, 0, "game", "accepted ^M%s^n", quest->get("mname")); } else { who->printf("You accept mission %i.\n", quest->get_int("m_id")); if (quest->get_int("deadline")==-1) { quest->set("deadline", now+(20*60)); } } who->oprintf(cansee, "%#M accepts a ^omission^n.\n", who); who->printf("%s\n", title_for("Mission Briefing", who).c_str()); who->printf("%s\n", quest->get("desc")?quest->get("desc"):quest->get("short_brief")); who->printf("%s\n", footer_for(who).c_str()); } MudObject *find_mission_for(const char *str) { if (MudObject *m=find_questob(str)) return m; MudObject *board = MUD_MISSIONSBOARD; if (board) { MudObject *o; int i; foreach(board->children, o, i) { if (o->get_int("m_id")==atoi(str)) return o; } } return 0; } static bool verb_accept(MudObject *who, int argc, const char **argv) { int justdoit = who->get_priv(PFL_CODER); MudObject *a = get_flagged_object(who->owner, FL_MISSIONSBOARD); if (!a && !justdoit) { who->printf("No missions board here.\n"); return true; } if (argc < 2) { who->printf("You what?\n"); return true; } if (who->get_priv(PFL_REMORT) && who->get_int("remort")==-1 && !who->get_priv(PFL_REMORTANYWHERE)) { who->printf("You cannot accept a mission until you remort.\n"); return true; } MudObject * miss = who->get_object("mission"); if (miss && miss->owner != who) { who->unset("mission"); MudObject *a = miss->get_object(KEY_ACCEPTER); if (a == who) { miss->unset(KEY_ACCEPTER); } miss = 0; } if (miss && miss->get_object(KEY_ACCEPTER) == who) { who->printf("You've already accepted a mission.\n"); return true; } if (streq(argv[1], "99") && tocontact(who)) { who->printf("You need not accept that : just go ahead and do it.\n"); return true; } MudObject *o = find_mission_for(argv[1]); if (!o) { who->printf("Accept what?\n"); return true; } const char *reason = " yet"; if (o && !justdoit && !can_access(a, who, o, &reason)) { who->printf("You cannot do that mission%s.\n", reason); return true; } accept_mission(who, o); return true; } static void do_mission_stuff(MudObject *who) { int deadline = who->get_int("deadline"); if ((deadline != -1) && (deadline+120) < now) { if (who->get(KEY_ACCEPTER)) { const char *acceptee = who->get(KEY_ACCEPTER); MudObject *what = planet->get(acceptee); if (what) { what->unset("mission"); what->printf("Your mission deadline has been reached.\n"); } } mission_cleanup(who); return; } } #define CLEANUP MISSION_ROUTINE = 0; #include "verbmodule.h" void startup() { MISSION_ROUTINE = do_mission_stuff; AUTO_VERB(accept, 5, 0, PFL_AWAKE); AUTO_VERB(mmlist, 6, 0, PFL_AWAKE); AUTO_VERB(mmtimeout, 5, 0, PFL_MINIMISSIONS); }