/*  -*- LPC -*-  */
/*
 * $Locker:  $
 * $Id: quest_handler.c,v 1.9 2000/07/29 14:49:21 taffyd Exp $
 * $Log: quest_handler.c,v $
 * Revision 1.9  2000/07/29 14:49:21  taffyd
 * Actually did what I said I did in 1.7 ;)
 *
 * Revision 1.8  2000/07/29 14:40:33  taffyd
 * Changed logging so that if there is no this_player() it uses
previous_object().  So that the web interface to the quests command works.
 *
 * Revision 1.7  2000/07/29 14:34:29  presto
 *  Forcibly unlocked by taffyd
 *
 * Revision 1.6  2000/07/29 02:18:20  pinkfish
 *  Forcibly unlocked by presto
 *
 * Revision 1.5  2000/03/17 20:55:07  ceres
 * Removed references to the old team handler
 *
 * Revision 1.4  1999/09/27 21:19:29  wodan
 * fixed ancient bug in query_fame_str and removed line that did nothing.
 *
 * Revision 1.3  1999/09/27 21:13:25  terano
 * Got it working.
 *
 * Revision 1.2  1999/05/20 01:02:27  ceres
 * Added status for quests
 *
 * Revision 1.1  1998/01/06 05:03:33  ceres
 * Initial revision
 * 
*/
/**
 * This class keeps track of the current set of quests availabe in the
 * game.
 * @author Furball
 */
#include <player_handler.h>
#define LIBRARY "/obj/handlers/nlibrary"
#define QUEST_LOG "QUESTS"
#define SAVE_FILE "/save/quests"
#define BACKUP_FILE "/save/quests/quests"
inherit "/std/object";
private int *quest_level;
private int *num_times_done;
private int *quest_status;
private string *quest_name;
private string *quest_title;
private string *quest_story;
private string *last_done_by;
private nosave int total_qp;
/**
 * This method reloads the quests from the save file.
 * @see save_quests()
 */
void load_quests() { unguarded( (: restore_object, SAVE_FILE :) ); }
/**
 * This method saves the current set of quests to the save file.
 * @see load_quests()
 */
void save_quests() { unguarded( (: save_object, SAVE_FILE :) ); }
void create() {
   int i;
   ::create();
   load_quests();
   if ( !quest_name ) {
      quest_name = ({ });
   }
   if ( !quest_level ) {
      quest_level = ({ });
   }
   if ( !quest_title ) {
      quest_title = ({ });
   }
   if ( !quest_story ) {
      quest_story = ({ });
   }
   if ( !last_done_by ) {
      last_done_by = ({ });
   }
   if ( !num_times_done ) {
      num_times_done = ({ });
   }
   if ( !quest_status ) {
     if(sizeof(quest_name)) {
       quest_status = allocate(sizeof(quest_name));
       for(i=0; i<sizeof(quest_name); i++) {
         quest_status[i] = 1;
       }
     } else {
       quest_status = ({ });
     }
   }
   
   for(i = 0; i<sizeof(quest_level); i++) {
     if(quest_status[i]) {
       total_qp += quest_level[i];
     }
   }
   
} /* create() */
/**
 * This returns the current total gp for all of the current quests.
 * @return the total gp
 */
int query_total_qp() { return total_qp; }
/**
 * This method adds a new quest into the system.  You only need to call
 * this ONCE.  The name of the quest must be unique.  The story is
 * what can be seen in the players books about the player.
 * @param name the name of the quest
 * @param level the level of the quest 0-100
 * @param title the title for finishing the quest, 0 for none
 * @param story the story about the quest
 * @return 1 if successful, 0 if not
 * @see delete_quest()
 * @see query_quest_level()
 * @see query_quest_title()
 * @see query_quest_story()
 */
int add_quest( string name, int level, string title, string story ) {
   string log_name;
    
   if ( member_array( name, quest_name ) != -1 )
      return 0;
      
   quest_name += ({ name });
   quest_level += ({ level });
   quest_title += ({ title });
   quest_story += ({ story });
   last_done_by += ({ "nobody" });
   num_times_done += ({ 0 });
   quest_status += ({ 1 }); //Make it active!   
   
   if ( this_player() ) {
      log_name = this_player()->query_name();
   }
   else {
      log_name = file_name( previous_object() );
   }
   
   log_file( QUEST_LOG, log_name +
         " added: "+ name +", "+ level +", "+ title +", "+ story +"\n" );
   save_quests();
   unguarded( (: cp, SAVE_FILE +".o", BACKUP_FILE +"."+ time() :) );
   total_qp += level;
   return 1;
} /* add_quest() */
/**
 * Change the status of a quest from active to inactive
 * and vice versa.
 * @param the name of a quest.
 */
int change_quest_status(string name) {
  int temp;
  temp = member_array(name, quest_name);
  if(temp == -1) {
    return -1;
  }
  quest_status[temp] = !quest_status[temp];
  return quest_status[temp];
}
/**
 * This method returns the status of a quest.
 * @param the name of a quest
 * @return 1 for active, 0 for inactive.
 */
int query_quest_status(string name) {
  int temp;
  temp = member_array(name, quest_name);
  if(temp == -1) {
    return -1;
  }
  return quest_status[temp];
}
/**
 * This method returns the level of the quest.
 * @param name the name of the quest
 * @return the level of the quest, -1 on failure
 * @see add_quest()
 * @see set_quest_level()
 */
int query_quest_level(string name) {
  int temp;
  temp = member_array(name, quest_name);
  if(temp == -1) {
    return -1;
  }
  return quest_level[temp];
} /* query_quest_level() */
/**
 * This method sets the level of the quest.
 * @param name the name of the quest
 * @param level the level of the quest
 * @return 0 on failure, 1 on success
 * @see add_quest()
 * @see query_quest_level()
 */
int set_quest_level(string name, int level) {
   int temp;
   string log_name;
   temp = member_array(name, quest_name);
   if(temp == -1) {
      return 0;
   }
   
   if ( this_player() ) {
      log_name = this_player()->query_name();
   }
   else {
      log_name = file_name( previous_object() );
   }
   
   log_file(QUEST_LOG, "%s : level set for %s to %d\n\n",
            log_name, name, level);
   quest_level[ temp ] = level;
   save_quests();
   return 1;
} /* set_quest_level() */
/**
 * This method returns the story associated with the quest.
 * @param name of the quest
 * @return the story of the quest
 * @see add_quest()
 * @see set_quest_story()
 */
string query_quest_story(string name) {
  int temp;
  temp = member_array(name, quest_name);
  if(temp == -1) {
    return "did nothing";
  }
  return quest_story[temp];
} /* query_quest_story() */
/**
 * This method sets the story associated with the quest.
 * @param name of the quest
 * @param story the new story of the quest
 * @see add_quest()
 * @see query_quest_story()
 */
int set_quest_story(string name, string story) {
   int temp;
   string log_name;
   temp = member_array(name, quest_name);
   if(temp == -1) {
      return 0;
   }
   
   if ( this_player() ) {
      log_name = this_player()->query_name();
   }
   else {
      log_name = file_name( previous_object() );
   }
   
   log_file(QUEST_LOG, "%s : story set for %s to %s\n\n",
            log_name, name, story);
   quest_story[ temp ] = story;
   save_quests();
   return 1;
} /* set_quest_story() */
/**
 * This method returns the title associated with the quest.
 * @param name of the quest
 * @return the title of the quest
 * @see add_quest()
 * @see set_quest_title()
 */
string query_quest_title(string name) {
  int temp;
  temp = member_array(name, quest_name);
  if(temp == -1 || quest_title[temp] == "") {
    return "Unknown Quester";
  }
  return quest_title[temp];
} /* query_quest_title() */
/**
 * This method sets the title associated with the quest.
 * @param name of the quest
 * @param title the new title of the quest
 * @see add_quest()
 * @see query_quest_title()
 */
int set_quest_title(string name, string title) {
   int temp;
   string log_name;
   temp = member_array(name, quest_name);
   if(temp == -1) {
      return 0;
   }
   
   if ( this_player() ) {
      log_name = this_player()->query_name();
   }
   else {
      log_name = file_name( previous_object() );
   }
   
   log_file(QUEST_LOG, "%s : title set for %s to %s\n\n",
            log_name, name, title);
   quest_title[ temp ] = title;
   save_quests();
   return 1;
} /* set_quest_title() */
/**
 * This method returns the number of times the quest has been
 * completed.
 * @param name thre name of the quest
 * @return the number of times completed
 * @see quest_completed()
 * @see add_quest()
 * @see query_quest_done()
 */
int query_quest_times( string name ) {
   int i;
   i = member_array( name, quest_name );
   if ( i == -1 )
      return -1;
   return num_times_done[ i ];
} /* query_quest_times() */
/**
 * This method returns the name of the last person to complete the
 * quest.
 * @param name thre name of the quest
 * @return the last person to complete the quest
 * @see quest_completed()
 * @see add_quest()
 * @see query_quest_times()
 */
mixed query_quest_done( string name ) {
   int i; 
   i = member_array( name, quest_name );
   if ( i == -1 )
      return -1;
   return last_done_by[ i ];
} /* query_quest_done() */
/**
 * This method removes the given quest from the system.
 * @see name the name of the quest to remove
 * @return 0 on failure, 1 on success
 * @see add_quest()
 */
int delete_quest(string name) {
   int temp;
   string log_name;
   
   if ( this_player() ) {
      log_name = this_player()->query_name();
   }
   else {
      log_name = file_name( previous_object() );
   }
   
   log_file(QUEST_LOG, log_name + " removed : " +
            name + "\n\n");
   temp = member_array(name, quest_name);
   if(temp == -1) {
      return 0;
   }
   total_qp -= quest_level[temp];
   quest_name = delete(quest_name, temp, 1);
   quest_level = delete(quest_level, temp, 1);
   quest_title = delete(quest_title, temp, 1);
   quest_story = delete(quest_story, temp, 1);
   last_done_by = delete( last_done_by, temp, 1 );
   num_times_done = delete( num_times_done, temp, 1 );
   save_quests();
   return 1;
} /* delete_quest() */
/**
 * This method returns the names of all the quests.
 * @return the names of all the quests
 * @see add_quest()
 * @see delete_quest()
 */
string *query_quest_names() {
  return quest_name + ({ });
} /* query_quest_names() */
/**
 * This method returns the levels of all the quests.
 * @return the levels of all the quests
 * @see add_quest()
 * @see delete_quest()
 */
int *query_quest_levels() {
  return quest_level + ({ });
} /* query_quest_levels() */
/**
 * This method returns the titles of all the quests.
 * @return the titles of all the quests
 * @see add_quest()
 * @see delete_quest()
 */
string *query_quest_titles() {
  return quest_title + ({ });
} /* query_quest_titles() */
/**
 * This method returns the stories of all the quests.
 * @return the stories of all the quests
 * @see add_quest()
 * @see delete_quest()
 */
string *query_quest_stories() {
  return quest_story + ({ });
} /* query_quest_stories() */
/**
 * This method should be called in the code when a quest is complete.
 * @param name name of the player
 * @param quest the quest completed
 * @param prev_ob the object which completed the quest
 * @see add_quest()
 * @see delete_quest()
 */
void quest_completed( string name, string quest, object prev_ob ) {
   int i;
   string word;
   log_file( QUEST_LOG, ctime( time() ) +" "+ name +" completed "+
         quest +"\n" );
   user_event( "inform", name +" completes "+ quest, "quest" );
   if ( file_name( previous_object() ) != LIBRARY ) {
      prev_ob = previous_object();
   }
   word = (string)prev_ob->query_name();
   if ( !word ) {
      word = file_name( prev_ob );
   } else {
      word += " ("+ file_name( prev_ob ) +")";
   }
   log_file( QUEST_LOG, "given by "+ word +"\n" );
   i = member_array( quest, quest_name );
   if ( i == -1 ) {
      log_file( QUEST_LOG, "non existent quest\n" );
      return;
   }
   last_done_by[ i ] = name;
   num_times_done[ i ]++;
   save_quests();
} /* query_completed() */
/* Fame functions - for use in halls of fame / libraries etc. */
/* Piecemaker 25/3/93                                         */
/**
 * This method returns the fame of the player.
 * Gets the fame percentage of the player. Quest points / total quest points
 * @param name the name of the player
 * @return the fame as a percentage (0-100)
 * @see query_player_story()
 * @see query_fame_string()
 * @see query_total_qp()
 */
int query_player_fame(string name){
   int playerqp, rank;
   /* do checking on the names */
   if (!name){
      return 0;
   }
   /* expand the nicknames if there are any */
   if (this_player()){
      name = (string)this_player()->expand_nickname(name);
   }
   /* are they a valid player ? */
   if (!PLAYER_HANDLER->test_user(name)){ 
      return 0;
   }   
   /* do the calculations */
   playerqp = (int)LIBRARY->query_quest_points(name);
   rank = ( playerqp * 125 ) / query_total_qp();
   return rank;
} /* query_player_fame() */
/**
 * This method returns a string associated with the fame level of the
 * player.
 * @param name the name of the player
 * @return the fame string
 * @see query_player_fame()
 * @see query_player_story()
 */
string query_fame_str( string name ) {
   switch ( query_player_fame( name ) ) {
      case 0 .. 4 :
         return "completely unknown";
      case 5 .. 14 :
         return "unknown";
      case 15 .. 24 :
         return "unknown";
      case 25 .. 34 :
         return "moderately well known";
      case 35 .. 44 :
         return "well known";
      case 45 .. 54 :
         return "very well known";
      case 55 .. 64 :
         return "known throughout the region";
      case 65 .. 74 :
         return "famous";
      case 75 .. 84 :
         return "renowned";
      case 85 .. 94 :
         return "Disc renowned";
      default :
         return "so renowned that no introduction is needed";
   }
} /* query_fame_str() */
/**
 * This method lists the stories for the quests the player has done.
 * @param name the name of the player
 * @return the story of the player
 * @see query_fame_string()
 * @see query_player_fame()
 */
string *query_player_story(string name){
   string *quests; 
   string *story;
   int i;
   story = ({ });
   /* do checking on the names */
   if (!name){
      return ({ });
   }
   /* expand the nicknames if there are any */
   if (this_player()){
      name = (string)this_player()->expand_nickname(name);
   }
   /* are they a valid player ? */
   if (!PLAYER_HANDLER->test_user(name)){ 
      return 0;
   }   
   /* right, we checked everything now. Lets do some real work. */
   quests = query_quest_names();
   if (sizeof(quests) == 1){
      story = ({"Is an under achiever."});
   }
   else{  
      for(i=0;i<sizeof(quests);i++){
         if (LIBRARY->query_quest_done(name, quests[i])){
            story = ({ query_quest_story( quests[ i ] ) }) + story;
         }
      }
   }
   return story;
} /* query_player_story() */
/**
 * This method prints out a lot of quest stats. For debugging purpsoes
 * only.
 */
void print_some_stats()  {
   int i;
   for (i = 0; i < sizeof(quest_name); i++)
      printf("%s: %6d, %3d\n", quest_name[i], num_times_done[i], quest_level[i]);
} /* print_some_stats() */