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 Daemon, version 1.0
 * Copyright (C) 1999-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, writ<e to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 * 
 */
#include <string.h>
#include <ctype.h>
#include <unistd.h>

#include "musicmud.h"
#include "misc.h"
#include "util.h"
#include "rooms.h"
#include "Player.h"
#include "events.h"
#include "trap.h"
#include "pflags.h"
#include "death.h"
#include "Mission.h"
#include "zoneload.h"
#include "msi.h"
#include "paths.h"
#include "privs.h"
#include "vsprintf.h"
#include "prep.h"
#include "units.h"
#include "shared.h"
#include "musictok.h"
#include "format.h"
#include "pos.h"
#include "body.h"
#include "levels.h"
#include "missions.h"
#include "nations.h"

int mission_counter = 0;
int overflow_counter = 1000;

set<int> used;

Mission::Mission(const char *i) : MudObject(i), mission_objs() {

  bool set = 0;
  for (int i=1;i<=900;i++) 
    if (used.find((i+mission_counter)%900)==used.end()) {
      mission_counter = (i+mission_counter)%900;
      Mission::set("m_id", mission_counter+100);
      set = 1;
      break;
    }

  if (!set) {
    MudObject::set("m_id", overflow_counter);
    overflow_counter++;
  }

  set_flag(FL_MISSION, 1);
  used.insert(get_int("m_id"));
}

void Mission::add(MudObject *a) {
  mission_objs.add(*a);
}

void Mission::remove(MudObject *a) {
  mission_objs.remove(*a);
}

Mission::~Mission() {
  used.erase(get_int("m_id"));

  if (get_object("toreset")) {
    get_object("toreset")->reset();
  }

  MudObject *o;
  int i;
  foreach((&mission_objs), o, i) {
    if (!o->get_flag(FL_SILENTQUIT)) {
      if (o->get("timeoutmsg"))
	o->oprintf(cansee, "%#M %s.\n", o, o->get("timeoutmsg"));
	else
	  o->oprintf(cansee, "%#M departs.\n", o);
    }
    o->mission = 0;
    vanish(o);
  }
}

void empty_ship(MudObject *ship) {
  if (!ship) return;

  if (ship->get_object("ship"))
    ship = ship->get_object("ship");
  
  int roomcount = ship->array_size("room");
  
  for (int i=0;i<roomcount;i++) {
    MudObject *room = ship->array_get_object("room", i);
    if (!room) continue;
    MudObject *o;
    int i;
    foreach(room->children, o, i) {
      if (is_player(o) || (is_mobile(o) && (o->mission != ship->mission))) {
	set_owner(o, ship->owner);
	i--;
	o->printf("You are escorted from the ship.\n");
	o->oprintf(cansee, "%#M %[is/are] escorted from the ship.\n", o);
	o->interpret("look");
      }
    }
  }
  return;
}

void mission_cleanup(MudObject *m)
{
  MudObject *o;
  int i;

  if (IS_OF(m, Mission)) {
    Mission *mission = (Mission*)m;

    foreach((&mission->mission_objs), o, i) {
      if (o->follows) 
	o->interpret("leave");	
    }

    foreach((&mission->mission_objs), o, i) {
      empty_ship(m);
    }
  }

  m->nuke_me = 1;
}

bool quest_done(const MudObject *who, const string &id) {
  return who->quests.find(id)!=who->quests.end();
}

bool quest_done(const MudObject *who, MudObject *qu) {
  string id = ssprintf("Quest%i", qu->get_int("miniid")+32);

  if (qu->get_flag(FL_QUEST) && qu->get("mname"))
    id = qu->get("mname");
  if (qu->get_flag(FL_MISSION)) {
    id = qu->get("minitag");
  }

  return who->quests.find(id)!=who->quests.end();
}

void quest_set(MudObject *who, const string &id) {
  who->quests.insert(id);
}

void quest_unset(MudObject *who, const string &id) {
  who->quests.erase(id);
}

string nicepname(const char *id) 
{
  MudObject * p = planet->get(id);
  if (p) {
    return name(p)?:"";
  }
  return ssprintf("^p%#s^n", id);
}

void questrec(MudObject *who, MudObject *quest) 
{
  if (who->get_priv(PFL_IMMORTAL))
    return;

  int at = quest->get_int("!acceptedat");
  if (at != -1) {
    time_t secs = now - at;
    int rec = quest->get_int("$recordtime");
    if (rec==-1) {
      quest->set("$recordtime", secs);
      quest->set("$recordholder", who->id);
    } else if (rec>secs) {
      quest->set("$recordtime", secs);
      quest->set("$recordholder", who->id);
   }
  }
}

void grant_quest(MudObject *who, MudObject *q, bool reward)
{
  if (!is_player(who))
    return;

  if (!q->get_flag(FL_QUEST)) {
    log(PFL_SEEINFO, 0, "mission", "trying to call grant_quest on a non-Quest %s", q->id);
    return;
  }
  
  const char *name = 0;
  if (q) name = q->get("mname");
  if (!q) name = "???";

  if (quest_done(who, q)) {
    who->printf("You have completed the ^G%s^n mission again.\n", name);
    broadcast(avoid(who), "%#M %[has/have] completed the ^G%s^n mission again.\n", who, name);
  } else {
    who->printf("Congratulations, you have completed the ^G%s^n mission.\n", name);
    broadcast(avoid(who), "%#M ^Y%[has/have] completed the ^G%s^Y mission.\n", who, name);
  }
  
  if (reward) {
    int value = q->get_int("questpoints", 0) * 200;
    if (!value)
      value = 500;

    MudObject *cur = currency(q);

    value = convertcash(value, 0, cur);
    cash_credit(who, cur, value);

    who->printf("You have been rewarded with %s.\n", formatcash(value, cur, 0));
  }

  quest_set(who, q->get("mname"));

  if (q)
    questrec(who, q);

  if (q) {
    q->set_flag(FL_DONE, 1);
    q->set("$doneby", who->id);
    if (q->owner == who)
      vanish(q);
  }

  who->interpret("calc_level");
  who->interpret("save");
}


void fail_mission(MudObject *p, MudObject *m) {
  if (m->owner == p && is_player(p)) {
    if (m->get("mname")) {
      p->printf("You have mucked up the ^M%s^n mission.\n", m->get("mname"));
      log(p, PFL_SEEINFO, 0, "mission", "failed %s mission", m->get("mname"));
    } else {
      if (m->get("type"))
	log(p, PFL_SEEINFO, 0, "mission", "failed a %s mission", m->get("type"));

      p->printf("You have mucked up the mission.\n");
    }
    if (m->get("zone"))
      p->printf("If you want to try it again, leave the area and dispose of all objects from it.\n");
    set_owner(m, "empty");
    if (p->get_object(KEY_ACCEPTED)==m)
      p->unset(KEY_ACCEPTED);
  } else {
    set_owner(m, "empty");
    if (p->get("mname"))
      log(PFL_SEEINFO, 0, "mission", "%s mission failed", m->get("mname"));
    else if (p->get("type"))
      log(PFL_SEEINFO, 0, "mission", "a %s mission failed", m->get("type"));
  }
}

void grudge_mission(MudObject *p, MudObject *q) {
  grant_quest(p, q, 0);
}

void complete_mission(MudObject *p, MudObject *m) {
  if (!m) {
    p->printf("This is a bug in ^Wcomplete_mission^n, please report it.\n");
    return;
  }

  if (m->get_flag(FL_QUEST))
    {
      grant_quest(p, m, 1);
      return;
    }

  Mission *mis = dynamic_cast<Mission*>(m);
  if (!mis) {
    log(PFL_SEEINFO, 0, "mission", "trying to call complete_mission on a non-Mission %s", m->id);
    return;
  }

  empty_ship(m);

  int acc = p->get_object("mission")==m;
  
  if (!is_player(p)) {
    mission_cleanup(m);
    return;
  }

  if (acc) {
    int reward = (m->get_int("reward", 100));
    p->unset("mission");

    MudObject *cur = currency(m);
    reward = convertcash(reward, 0, cur);

    cash_credit(p, cur, reward);

    string quest_id = m->get("minitag");

    if (!quest_done(p, quest_id)) {
      quest_set(p, quest_id);
      p->printf("You have been rewarded with ^Y1^n mission point and %s.\n", formatcash(reward, cur, 1));
      log(p, PFL_SEEINFO, 0, "mission", "completed a ^G%s^n mission for the first time",
	  m->get("type"));
      p->interpret("calc_level");
      p->interpret("save");
    } else {
      log(p, PFL_SEEINFO, 0, "mission", "completed a ^G%s^n mission again",
	  m->get("type"));
      p->printf("You have been rewarded with ^Y%i^n %s.\n", reward, formatcash(reward, cur, 1));
    }
  } else {
    log(PFL_SEEINFO, 0, "mission", "completed a ^G%s^n mission without having accepted it. not rewarding.",
	m->get("type"));
  }

  mission_cleanup(m);
}