musicmud-2.1.6/data/
musicmud-2.1.6/data/help/
musicmud-2.1.6/data/policy/
musicmud-2.1.6/data/wild/
musicmud-2.1.6/data/world/
musicmud-2.1.6/doc/
musicmud-2.1.6/src/ident/
musicmud-2.1.6/src/lua/
musicmud-2.1.6/src/lua/include/
musicmud-2.1.6/src/lua/src/lib/
musicmud-2.1.6/src/lua/src/lua/
musicmud-2.1.6/src/lua/src/luac/
/* 
 * 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);


}