/******************************************************
Thy Quest mud - By Volk, 2006
http://www.thyquest.com
******************************************************/
#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "h/mud.h"
#include "h/files.h"
#include "h/key.h"
#include "h/clans.h"
QUEST_DATA *first_quest;
QUEST_DATA *last_quest;
void add_quest(QUEST_DATA * quest);
char *show_timeleft(int time);
void add_chapter(QUEST_DATA * quest, CHAP_DATA * chap);
bool in_hash_table(const char *str);
void unlink_chapter(QUEST_DATA * quest, CHAP_DATA * chap)
{
UNLINK(chap, quest->first_chapter, quest->last_chapter, next, prev);
}
void unlink_quest(QUEST_DATA * quest)
{
UNLINK(quest, first_quest, last_quest, next, prev);
}
void free_chapter(QUEST_DATA * quest, CHAP_DATA * chapter)
{
if(!chapter || !quest)
return;
unlink_chapter(quest, chapter);
STRFREE(chapter->desc);
STRFREE(chapter->bio);
STRFREE(chapter->phrase);
DISPOSE(chapter);
}
void free_quest(QUEST_DATA * quest)
{
CHAP_DATA *chapter, *chapter_next;
if(!quest)
return;
unlink_quest(quest);
STRFREE(quest->name);
STRFREE(quest->desc);
for(chapter = quest->first_chapter; chapter; chapter = chapter_next)
{
chapter_next = chapter->next;
free_chapter(quest, chapter);
}
DISPOSE(quest);
}
void free_all_quest(void)
{
while(last_quest)
free_quest(last_quest);
}
QUEST_DATA *get_quest_from_number(int x)
{
QUEST_DATA *quest;
for(quest = first_quest; quest; quest = quest->next)
{
if(quest->number == x)
return quest;
}
return NULL;
}
CHAP_DATA *get_chap_from_quest(int x, QUEST_DATA * quest)
{
CHAP_DATA *chap;
for(chap = quest->first_chapter; chap; chap = chap->next)
{
if(chap->number == x)
return chap;
}
return NULL;
}
QUEST_DATA *get_quest_from_name(const char *name)
{
QUEST_DATA *quest;
for(quest = first_quest; quest; quest = quest->next)
{
if(!str_cmp(quest->name, name))
return quest;
}
return NULL;
}
int get_number_from_quest(QUEST_DATA * quest)
{
if(quest)
return quest->number;
return -1;
}
void add_chapter(QUEST_DATA * quest, CHAP_DATA * chap)
{
CHAP_DATA *tmp;
if(!chap)
{
bug("%s", "Add_chapter: NULL chap");
return;
}
if(!quest)
{
bug("%s", "ADD_chapter: NULL quest");
return;
}
for(tmp = quest->first_chapter; tmp; tmp = tmp->next)
{
if(chap->number < tmp->number)
{
INSERT(chap, tmp, quest->first_chapter, next, prev);
return;
}
}
LINK(chap, quest->first_chapter, quest->last_chapter, next, prev);
}
void add_new_quest(CHAR_DATA *ch, QUEST_DATA * quest)
{
send_to_char("New quest added.\r\n", ch);
add_quest(quest);
}
void add_quest(QUEST_DATA * quest)
{
QUEST_DATA *tmp;
int qcount = 0;
if(!quest)
{
bug("%s", "Add_quest: NULL quest");
return;
}
if(!quest->name)
{
bug("%s", "Add_quest: NULL quest->name");
return;
}
if(quest->number != -1 && get_quest_from_number(quest->number) != NULL)
{
bug("%s: Already a quest numbered %d!", __FUNCTION__, quest->number);
return;
}
for(tmp = first_quest; tmp; tmp = tmp->next)
{
/*
* Get the highest number used so far and use the one after that
*/
if(qcount < tmp->number)
qcount = tmp->number;
if(quest->number != -1 && quest->number < tmp->number)
{
INSERT(quest, tmp, first_quest, next, prev);
return;
}
}
if(quest->number == -1)
quest->number = (qcount + 1);
LINK(quest, first_quest, last_quest, next, prev);
}
void fwrite_chap(CHAP_DATA * chap, FILE * fp)
{
if(!chap)
return;
fprintf(fp, "%s", "#NCHAPTER\n");
fprintf(fp, "Number %d\n", chap->number);
if(chap->desc)
fprintf(fp, "Desc %s~\n", strip_cr(chap->desc));
if(chap->bio)
fprintf(fp, "Bio %s~\n", chap->bio);
fprintf(fp, "Timelimit %d\n", chap->timelimit);
fprintf(fp, "Level %d\n", chap->level);
fprintf(fp, "KAmount %d\n", chap->kamount);
if(chap->phrase)
fprintf(fp, "Phrase %s~\n", chap->phrase);
fprintf(fp, "#CHAPEND\n");
}
/* Write the quest. */
void fwrite_quest(QUEST_DATA * quest, FILE * fp)
{
CHAP_DATA *chap;
if(!quest)
return;
fprintf(fp, "%s", "#NQUEST\n");
fprintf(fp, "Number %d\n", quest->number);
fprintf(fp, "SType %d\n", quest->stype);
fprintf(fp, "SVnum %d\n", quest->svnum);
fprintf(fp, "Glory %d\n", quest->glory);
fprintf(fp, "Name %s~\n", quest->name);
fprintf(fp, "Desc %s~\n", strip_cr(quest->desc));
fprintf(fp, "Timelimit %d\n", quest->timelimit);
fprintf(fp, "Level %d\n", quest->level);
fprintf(fp, "Chapters %d\n", quest->chapters);
if(quest->skipchapters)
fprintf(fp, "%s", "SkipChapters\n");
for(chap = quest->first_chapter; chap; chap = chap->next)
fwrite_chap(chap, fp);
fprintf(fp, "End\n\n");
}
void write_quest_list(void)
{
FILE *fpout;
QUEST_DATA *quest;
char filename[256];
snprintf(filename, 256, "%s", QUESTS_FILE);
fpout = FileOpen(filename, "w");
if(!fpout)
{
bug("Cannot open %s for writing!\r\n", QUESTS_FILE);
return;
}
for(quest = first_quest; quest; quest = quest->next)
fwrite_quest(quest, fpout);
fprintf(fpout, "#END\n");
FileClose(fpout);
}
void fread_chap(bool cnew, QUEST_DATA * quest, FILE * fp)
{
const char *word;
bool fMatch;
CHAP_DATA *chap;
CREATE(chap, CHAP_DATA, 1);
if(!cnew)
chap->number = fread_number(fp);
for(;;)
{
word = feof(fp) ? "#CHAPEND" : fread_word(fp);
fMatch = FALSE;
switch (UPPER(word[0]))
{
case '*':
fMatch = TRUE;
fread_to_eol(fp);
break;
case '#':
if(!str_cmp(word, "#CHAPEND"))
{
add_chapter(quest, chap);
return;
}
break;
case 'C':
if(!str_cmp(word, "Bio"))
{
chap->bio = fread_string(fp);
fMatch = TRUE;
break;
}
break;
case 'D':
if(!str_cmp(word, "Desc"))
{
chap->desc = fread_string(fp);
fMatch = TRUE;
break;
}
break;
case 'K':
KEY("KAmount", chap->kamount, fread_number(fp));
break;
case 'L':
KEY("Level", chap->level, fread_number(fp));
break;
case 'N':
KEY("Number", chap->number, fread_number(fp));
break;
case 'P':
if(!str_cmp(word, "Phrase"))
{
chap->phrase = fread_string(fp);
fMatch = TRUE;
break;
}
break;
case 'T':
KEY("Timelimit", chap->timelimit, fread_number(fp));
break;
}
if(!fMatch)
bug("%s: no match: %s", __FUNCTION__, word);
}
DISPOSE( chap );
}
/* Read in a quest. */
void fread_quest(bool cnew, FILE * fp)
{
const char *word;
bool fMatch;
QUEST_DATA *quest;
CREATE(quest, QUEST_DATA, 1);
quest->skipchapters = FALSE;
if(!cnew)
quest->number = fread_number(fp);
else
quest->number = -1;
for(;;)
{
word = feof(fp) ? "End" : fread_word(fp);
fMatch = FALSE;
switch (UPPER(word[0]))
{
case '*':
fMatch = TRUE;
fread_to_eol(fp);
break;
case '#':
if(!strcmp(word, "#CHAPTER"))
{
fread_chap(FALSE, quest, fp);
fMatch = TRUE;
break;
}
if(!strcmp(word, "#NCHAPTER"))
{
fread_chap(TRUE, quest, fp);
fMatch = TRUE;
break;
}
break;
case 'C':
KEY("Chapters", quest->chapters, fread_number(fp));
break;
case 'D':
if(!str_cmp(word, "Desc"))
{
KEY("Desc", quest->desc, fread_string(fp));
fMatch = TRUE;
break;
}
break;
case 'E':
if(!str_cmp(word, "End"))
{
add_quest(quest);
return;
}
break;
case 'G':
KEY("Glory", quest->glory, fread_number(fp));
break;
case 'L':
KEY("Level", quest->level, fread_number(fp));
break;
case 'N':
/*
if ( !quest->name )
DISPOSE( quest );
*/
KEY("Name", quest->name, fread_string(fp));
KEY("Number", quest->number, fread_number(fp));
break;
case 'S':
KEY("SType", quest->stype, fread_number(fp));
KEY("SVnum", quest->svnum, fread_number(fp));
if(!str_cmp(word, "SkipChapters"))
{
quest->skipchapters = TRUE;
fMatch = TRUE;
break;
}
break;
case 'T':
KEY("Timelimit", quest->timelimit, fread_number(fp));
break;
}
if(!fMatch)
bug("Fread_quest: no match: %s", word);
}
DISPOSE( quest );
}
void load_quest_list(void)
{
FILE *fp;
if((fp = FileOpen(QUESTS_FILE, "r")) != NULL)
{
for(;;)
{
char letter;
char *word;
letter = fread_letter(fp);
if(letter == '*')
{
fread_to_eol(fp);
continue;
}
if(letter != '#')
{
bug("%s", "Load_quest_list: # not found.");
break;
}
word = fread_word(fp);
if(!str_cmp(word, "QUEST"))
{
fread_quest(FALSE, fp);
continue;
}
else if(!str_cmp(word, "NQUEST"))
{
fread_quest(TRUE, fp);
continue;
}
else if(!str_cmp(word, "END"))
break;
else
{
bug("%s", "Load_quest_list: bad section.");
continue;
}
}
FileClose(fp);
}
else
{
perror(QUESTS_FILE);
bug("%s", "Cannot open quests.dat");
exit(0);
}
}
void do_setquest(CHAR_DATA *ch, char *argument)
{
char arg1[MIL], arg2[MIL], arg3[MIL], arg4[MIL], arg5[MIL];
QUEST_DATA *quest;
int x = 0;
set_char_color(AT_PLAIN, ch);
if(IS_NPC(ch))
{
error(ch);
return;
}
if(!IS_IMMORTAL(ch))
{
error(ch);
return;
}
if(!ch->desc)
{
bug("%s", "do_setquest (desc): no descriptor");
return;
}
switch (ch->substate)
{
default:
break;
case SUB_QUEST_DESC:
if(!ch->dest_buf || !(quest = (QUEST_DATA *) ch->dest_buf))
{
bug("%s: sub_quest_desc: NULL ch->dest_buf", __FUNCTION__);
ch->substate = SUB_NONE;
return;
}
ch->dest_buf = NULL;
if(VLD_STR(quest->desc))
STRFREE(quest->desc);
quest->desc = copy_buffer(ch);
stop_editing(ch);
write_quest_list();
ch->substate = SUB_NONE;
return;
}
argument = one_argument(argument, arg1);
argument = one_argument(argument, arg2);
if(arg1[0] == '\0')
{
send_to_char("&cUsage: setquest save all\r\n", ch);
send_to_char(" setquest <&Cqname&c> create\r\n", ch);
send_to_char(" setquest <&Cqname&c> delete\r\n", ch);
send_to_char(" setquest <&Cqname&c> chapter <#> delete\r\n", ch);
send_to_char(" setquest <&Cqname&c> chapter <#> phrase\r\n", ch);
send_to_char(" setquest <&Cqname&c> desc\r\n", ch);
send_to_char(" setquest <&Cqname&c> <&Cfield&c>\r\n", ch);
send_to_char(" setquest <&Cquest&c> remove <&Cplayer&c>\r\n", ch);
send_to_char(" showquest <&Cqname&c>\r\n", ch);
send_to_char(" Field being one of:\r\n", ch);
send_to_char("level svnum stype chapters chapter timelimit skipchapters glory\r\n", ch);
send_to_char("\r\nchapter <n> <field2>\r\n", ch);
send_to_char(" Field2 being one of:\r\n", ch);
send_to_char("create delete svnum stype phrase\r\n", ch);
send_to_char("name timelimit level kamount\r\n", ch);
send_to_char("Note: 3600 = 1 hour timelimit\r\n", ch);
return;
}
if((!str_cmp(arg1, "tutorial") && ch->level < 108) || (!str_cmp(arg1, "etutorial") && ch->level < 108) || (!str_cmp(arg1, "dtutorial") && ch->level < 108))
{
send_to_char("You need Vladaar's permission to change anything with tutorials.\r\n", ch);
return;
}
if(!str_cmp(arg1, "save"))
{
if(!str_cmp(arg2, "all"))
{
write_quest_list();
send_to_char("All quests saved.\r\n", ch);
return;
}
}
quest = get_quest_from_name(arg1);
if(!str_cmp(arg2, "create"))
{
if(quest && VLD_STR(quest->name) && !str_cmp(quest->name, arg1))
{
ch_printf(ch, "(%s): quest already exists!\r\n", quest->name);
return;
}
CREATE(quest, QUEST_DATA, 1);
quest->name = STRALLOC(arg1);
quest->number = -1;
add_new_quest(ch, quest);
write_quest_list();
return;
}
if(!quest)
{
send_to_char("No quest by that name.\r\n", ch);
return;
}
if(!str_cmp(arg2, "desc"))
{
if(!ch->desc)
{
bug("%s", "do_setquest (desc): no descriptor");
return;
}
ch->substate = SUB_QUEST_DESC;
ch->dest_buf = quest;
start_editing(ch, quest->desc);
return;
}
if(!str_cmp(arg2, "delete"))
{
free_quest(quest);
send_to_char("Deleted.\r\n", ch);
return;
}
if(!str_cmp(arg2, "skipchapters"))
{
quest->skipchapters = !quest->skipchapters;
ch_printf(ch, "That quest will %s allow chapters to be skipped.\r\n", quest->skipchapters ? "now" : "no longer");
return;
}
if(!str_cmp(arg2, "chapters"))
{
x = atoi(argument);
if(x < 0 || x > 30)
{
send_to_char("Chapters must be between 0 and 30.\r\n", ch);
return;
}
quest->chapters = x;
send_to_char("Done.\r\n", ch);
return;
}
if(!str_cmp(arg2, "svnum"))
{
quest->svnum = atoi(argument);
ch_printf(ch, "That quest's svnum (starting vnum) is set to %d.\r\n", quest->svnum);
return;
}
if(!str_cmp(arg2, "stype"))
{
x = atoi(argument);
if(x < 0 || x > 2)
{
send_to_char("Can only set stype (starting type) to 0 for Mobiles, 1 for Objects, 2 for Rooms.\r\n", ch);
return;
}
quest->stype = x;
ch_printf(ch, "That quest's stype (starting type) is set to %d[%s].\r\n", quest->stype, (quest->stype == 0) ? "Mobile" : (quest->stype == 1) ? "Object" : (quest->stype == 2) ? "Room" : "Unknown");
return;
}
if(!str_cmp(arg2, "glory"))
{
x = atoi(argument);
if(x < 0 || x > 1)
{
send_to_char("Can only set 0 for no glory, or 1 for glory.\r\n", ch);
return;
}
quest->glory = x;
return;
}
if(!str_cmp(arg2, "chapter"))
{
CHAP_DATA *chap = NULL;
argument = one_argument(argument, arg3);
argument = one_argument(argument, arg4);
argument = one_argument(argument, arg5);
int chapno = atoi(arg3);
if(chapno < 1 || chapno > MAX_CHAPTERS)
{
ch_printf(ch, "Chapter range is 1 to %d.\r\n", MAX_CHAPTERS);
return;
}
if(!str_cmp(arg4, "create"))
{
if(get_chap_from_quest(chapno, quest))
{
send_to_char("That chapter already exists!\r\n", ch);
return;
}
if(!get_chap_from_quest((chapno - 1), quest) && chapno > 1)
{
ch_printf(ch, "How can you create chapter %d before chapter %d even exists?\r\n", chapno, chapno - 1);
return;
}
if(chapno > quest->chapters)
{
ch_printf(ch, "How can you create chapter %d when there are only %d chapters?\r\n", chapno, quest->chapters);
send_to_char("Set more - 'setquest (questname) chapters (number)'.\r\n", ch);
return;
}
CREATE(chap, CHAP_DATA, 1);
chap->number = chapno;
add_chapter(quest, chap);
send_to_char("New chapter added.\r\n", ch);
write_quest_list();
return;
}
chap = get_chap_from_quest(chapno, quest);
if(!chap)
{
send_to_char("No such chapter.\r\n", ch);
return;
}
if(!str_cmp(arg4, "phrase") && arg5)
{
chap->phrase = STRALLOC(arg5);
send_to_char("Chapter phrase created.\r\n", ch);
return;
}
if(!str_cmp(arg4, "delete"))
{
free_chapter(quest, chap);
send_to_char("Chapter Deleted.\r\n", ch);
return;
}
if(!str_cmp(arg4, "name"))
{
if(VLD_STR(chap->desc))
STRFREE(chap->desc);
if(VLD_STR(argument))
{
if(strlen(argument) > 50)
argument[50] = '\0';
chap->desc = STRALLOC(argument);
}
write_quest_list();
send_to_char("Done.\r\n", ch);
return;
}
if(!str_cmp(arg4, "timelimit"))
{
x = atoi(argument);
if(x < 0 || x > 3600)
{
send_to_char("Time limit is between 0 and 3600 (one hour).\r\n", ch);
return;
}
chap->timelimit = x;
send_to_char("Done.\r\n", ch);
return;
}
if(!str_cmp(arg4, "kamount"))
{
int kamount = atoi(argument);
if(kamount < 0)
{
send_to_char("You have to set kamount to 0 or higher.\r\n", ch);
return;
}
chap->kamount = kamount;
send_to_char("Done.\r\n", ch);
return;
}
if(!str_cmp(arg4, "level"))
{
int level = atoi(argument);
if(level < 0 || level > MAX_LEVEL)
{
ch_printf(ch, "Level range is between 0 and %d.\r\n", MAX_LEVEL);
return;
}
chap->level = level;
send_to_char("Done.\r\n", ch);
return;
}
do_setquest(ch, (char *)"");
return;
}
if(!str_cmp(arg2, "level"))
{
x = atoi(argument);
if(x < 1 || x > MAX_LEVEL)
{
send_to_char("Quest level must be between 1 and max.\r\n", ch);
return;
}
quest->level = x;
send_to_char("Done.\r\n", ch);
return;
}
if(!str_cmp(arg2, "timelimit"))
{
x = atoi(argument);
if(x < 0 || x > 3600)
{
send_to_char("Quest time limit must be between 0 (no timer) and 3600 seconds (1 hour).\r\n", ch);
return;
}
quest->timelimit = x;
send_to_char("Done.\r\n", ch);
return;
}
if(!str_cmp(arg2, "remove"))
{
CHAR_DATA *victim;
CHQUEST_DATA *chquest;
if((victim = get_char_world(ch, argument)) != NULL && !IS_NPC(victim))
{
x = get_number_from_quest(quest);
for(chquest = victim->pcdata->first_quest; chquest; chquest = chquest->next)
{
if(chquest->questnum != quest->number)
continue;
UNLINK(chquest, victim->pcdata->first_quest, victim->pcdata->last_quest, next, prev);
DISPOSE(chquest);
ch_printf(ch, "You remove quest %s from %s.\r\n", quest->name, victim->name);
ch_printf(victim, "Quest %s has been removed from your journal.\r\n", quest->name);
return;
}
send_to_char("That player isn't currently on that quest.\r\n", ch);
return;
}
else
send_to_char("That player isn't currently online.\r\n", ch);
return;
}
do_setquest(ch, (char *)"");
return;
}
void do_showquest(CHAR_DATA *ch, char *argument)
{
char arg[MSL], arg2[MSL];
CHAP_DATA *chap;
int count = 0;
QUEST_DATA *quest;
int x, y;
if(!ch || IS_NPC(ch))
return;
argument = one_argument(argument, arg);
argument = one_argument(argument, arg2);
if(!arg || arg[0] == '\0')
{
ch_printf(ch, "&Y%4s %3s %20s %4s %3s %5s %6s %s&D\r\n", "Num", "Lvl", "Name", "Desc", "Cha", "Lmt", "Type", "Vnum");
for(quest = first_quest; quest; quest = quest->next)
{
count++;
ch_printf(ch, "&G%4d &R%3d &W%20s %s &R%3d %5d &W%6s &w%d%s &w%d&D\r\n", quest->number,
quest->level, quest->name, quest->desc ? " &GY" : " &RN",
quest->chapters, quest->timelimit,
(quest->stype == 0) ? "Mobile" : (quest->stype == 1) ? "Object" : (quest->stype == 2) ? "Room" : "Unknown", quest->svnum, quest->skipchapters ? " &GCan Skip" : "", quest->glory);
}
ch_printf(ch, "\r\n&G%d &wquests.&D\r\n", count);
return;
}
quest = get_quest_from_name(arg);
if(!quest)
{
send_to_char("No such quest. Use 'showquest [(questname)] [(chapter #)]'.\r\n", ch);
return;
}
ch_printf(ch, "\r\n&zName:&w %s\r\n", quest->name);
ch_printf(ch, "&zMin Level:&w %-3d &zChapters:&w %-3d &zTime Limit:&w %-5d\r\n", quest->level, quest->chapters, quest->timelimit);
ch_printf(ch, "&zSkipChapters: &w%s\r\n", quest->skipchapters ? "Yes" : "No");
ch_printf(ch, "&zGlory: %d\r\n", quest->glory);
if(!arg2 || arg2[0] == '\0')
{
for(chap = quest->first_chapter; chap; chap = chap->next)
ch_printf(ch, "&c - Chapter &C%d&c - Minlev: &C%d &cTLimit: &C%d &cKAmount: &C%d &cName:&C %s\r\n", chap->number, chap->level, chap->timelimit, chap->kamount, chap->desc);
return;
}
if(!is_number(arg2))
{
send_to_char("Use 'showquest [(questname)] [(chapter #)]'.\r\n", ch);
return;
}
chap = get_chap_from_quest(atoi(arg2), quest);
if(!chap)
{
send_to_char("No such chapter to display.\r\n", ch);
return;
}
ch_printf(ch, "&c - Chapter &C%d&c - Name:&C %s\r\n\r\n&cDESC - &C%s %s", chap->number, chap->desc, chap->bio ? chap->bio : "(not yet entered)", chap->phrase ? chap->phrase : "(not yet entered)");
}
void do_journal(CHAR_DATA *ch, char *argument)
{
QUEST_DATA *quest;
CHQUEST_DATA *chquest;
CHAP_DATA *chap;
char arg1[MIL], arg2[MIL];
char *chapdesc;
int x = 0, total = 0, cando = 0, done = 0, num = 0, progress = 0, avail = 0;
bool found = FALSE, completed = FALSE;
set_char_color(AT_PLAIN, ch);
if(IS_NPC(ch))
{
error(ch);
return;
}
argument = one_argument(argument, arg1);
if(VLD_STR(arg1) && !str_cmp(arg1, "completed"))
{
completed = TRUE;
argument = one_argument(argument, arg1);
}
argument = one_argument(argument, arg2);
if(!arg1 || arg1[0] == '\0')
{
char questtime[MSL] = "";
char chaptime[MSL] = "";
char minsecs[MSL] = "";
int time = 0, mins = 0, secs = 0;
ch_printf(ch, "\r\n&YCLASSIC &C6D Quest Journal for %s&D\r\n\r\n", ch->name);
send_to_char("&cLvl Quest Name Chapter Quest Progress&D\r\n", ch);
for(quest = first_quest; quest; quest = quest->next)
{
num = quest->number;
total++;
if(ch->level < quest->level)
continue;
cando++;
for(chquest = ch->pcdata->first_quest; chquest; chquest = chquest->next)
{
if(chquest->questnum == quest->number)
{
progress = chquest->progress;
break;
}
}
if(!progress || !chquest)
continue;
chap = get_chap_from_quest(progress, quest);
if(!completed)
{
if(progress > quest->chapters)
{
done++;
continue;
}
if(!chap)
continue;
if(chap && chap->desc)
chapdesc = chap->desc;
else
chapdesc = (char *)"NULL: No desc for this chapter.";
}
else
{ /* Only show completed quest */
if(progress > quest->chapters)
{
chapdesc = (char *)"Quest Finished!";
done++;
}
else
continue;
}
avail++;
if(ch->level == quest->level)
send_to_char("&Y", ch);
else if(quest->level >= (ch->level - 3))
send_to_char("&G", ch);
else
send_to_char("&z", ch);
ch_printf(ch, "%3d %20s %7d %s", quest->level, capitalize(quest->name), progress, chapdesc);
if(chquest->kamount > 0)
ch_printf(ch, "&R(%d)&D", chquest->kamount);
send_to_char("\r\n", ch);
if(chquest->chaplimit > 0)
ch_printf(ch, "You have %s remaining to finish the above chapter.\r\n", show_timeleft(chquest->chaplimit));
if(chquest->questlimit > 0)
ch_printf(ch, "You have %s remaining to finish the above quest.\r\n", show_timeleft(chquest->questlimit));
}
if(avail == 0 && done == 0)
send_to_char("&BYou haven't yet found any quests! Go explore!&D", ch);
send_to_char("\r\n\r\n", ch);
if(IS_IMMORTAL(ch))
ch_printf(ch, "&cQuests Made: &C%d\r\n", total);
ch_printf(ch, "&cQuests Found: &C%d &cQuests Finished: &C%d&D\r\n", avail, done);
send_to_char("\r\n&GMore overall quest info: &WJournal <quest name>&D", ch);
send_to_char("&G\r\nFor specific quest info: &WJournal <quest name> number - to learn more.&D\r\n", ch);
send_to_char("\r\n>o see completed quest: &WJournal completed&D\r\n", ch);
return;
}
quest = get_quest_from_name(arg1);
if(!quest)
{
send_to_char("&GProper Syntax : journal\r\n journal <quest name>&D\r\n", ch);
return;
}
for(chquest = ch->pcdata->first_quest; chquest; chquest = chquest->next)
{
if(chquest->questnum != quest->number)
continue;
if(atoi(arg2))
{
chap = get_chap_from_quest(atoi(arg2), quest);
if(quest->chapters < atoi(arg2))
{
send_to_char(">here is no such chapter in this quest.\r\n", ch);
found = TRUE;
break;
}
if(chap->number == atoi(arg2))
{
send_to_char("&GReading the current quest chapter description...\r\n", ch);
pager_printf(ch, "&W%s&D\r\n", chap->phrase ? chap->phrase : "(Not created!)");
found = TRUE;
break;
}
}
send_to_char("&GReading the overall quest description...\r\n", ch);
pager_printf(ch, "&W%s&D\r\n", quest->desc ? quest->desc : "(Not created!)");
found = TRUE;
break;
}
if(!found)
send_to_char("That is not a quest in your journal!\r\n", ch);
}
bool remove_chquest(CHAR_DATA *ch, QUEST_DATA * quest)
{
CHQUEST_DATA *chquest;
if(!ch || !quest || !ch->pcdata)
return FALSE;
for(chquest = ch->pcdata->first_quest; chquest; chquest = chquest->next)
{
if(chquest->questnum == quest->number)
{
UNLINK(chquest, ch->pcdata->first_quest, ch->pcdata->last_quest, next, prev);
DISPOSE(chquest);
return TRUE;
}
}
return FALSE;
}
void link_chquest(CHAR_DATA *ch, CHQUEST_DATA * chquest)
{
CHQUEST_DATA *tmp;
if(!chquest || !ch || !ch->pcdata)
return;
for(tmp = ch->pcdata->first_quest; tmp; tmp = tmp->next)
{
if(chquest->questnum < tmp->questnum)
{
INSERT(chquest, tmp, ch->pcdata->first_quest, next, prev);
return;
}
}
LINK(chquest, ch->pcdata->first_quest, ch->pcdata->last_quest, next, prev);
}
char *show_timeleft(int time)
{
static char buf[MSL];
int mins, seconds;
mins = (time / 60);
seconds = (time - (mins * 60));
snprintf(buf, sizeof(MSL), "%s", "");
if(mins > 0)
{
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%d minute%s ", mins, mins == 1 ? "" : "s");
if(seconds > 0)
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s", "and ");
}
if(seconds > 0)
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%d second%s", seconds, seconds == 1 ? "" : "s");
return buf;
}
/* Used to update where people are in the quest */
void update_chquest(CHAR_DATA *ch, QUEST_DATA * quest, int nchapter)
{
CHQUEST_DATA *chquest;
CHAP_DATA *chapter;
int mins, seconds;
bool skipped = FALSE;
if(!quest || !ch || !ch->pcdata)
return;
for(chquest = ch->pcdata->first_quest; chquest; chquest = chquest->next)
{
if(chquest->questnum == quest->number)
break;
}
/*
* If no quest need to start it for them
*/
if(!chquest)
{
if(nchapter != 1)
{
send_to_char("&GYou have to do the quest in order. Check your &WJOURNAL&D.\r\n", ch);
return;
}
chapter = get_chap_from_quest(1, quest);
if(!chapter)
{
send_to_char("For now this is all you can do on this quest. Try back another time.\r\n", ch);
return;
}
CREATE(chquest, CHQUEST_DATA, 1);
chquest->questnum = quest->number;
chquest->questlimit = quest->timelimit;
chquest->progress = 1;
chquest->times = 1;
chquest->kamount = 0;
chquest->chaplimit = chapter->timelimit;
link_chquest(ch, chquest);
send_to_char("\r\n&GYou have started a new quest!&D\r\n", ch);
if(xIS_SET(ch->act, PLR_BATTLE))
send_to_char("!!SOUND(sound/quest.wav)\r\n", ch);
send_to_char(">ype &WJOURNAL &Gto see the quests you have to date.&D\r\n", ch);
if(chquest->chaplimit > 0)
ch_printf(ch, "&RYou have %s left to finish this chapter.&D\r\n", show_timeleft(chquest->chaplimit));
if(chquest->questlimit > 0)
ch_printf(ch, "&RYou have %s left to finish this quest.&D\r\n", show_timeleft(chquest->questlimit));
return;
}
if(!quest->skipchapters)
{
if(nchapter != (chquest->progress + 1))
{
send_to_char("&GYou have to do the quest in order. Check your &WJOURNAL&D.\r\n", ch);
return;
}
/*
* Ok so we have the chquest so lets increase it
*/
++chquest->progress;
}
else
{
chquest->progress = nchapter; /* If we skip need to set it to the new chapter */
skipped = TRUE;
}
/*
* Ok redoing it?
*/
if(chquest->progress == 1)
{
int times = chquest->times;
chapter = get_chap_from_quest(1, quest);
if(!chapter)
{
send_to_char("For now this is all you can do on this quest. Try back another time.\r\n", ch);
return;
}
chquest->questlimit = quest->timelimit;
chquest->chaplimit = chapter->timelimit;
chquest->kamount = 0;
send_to_char("\r\n&GYou have started a new quest!&D\r\n", ch);
send_to_char(">ype &WJOURNAL &Gto see the quests you have to date.&D\r\n", ch);
if(chquest->chaplimit > 0)
ch_printf(ch, "&RYou have %s left to finish this chapter.&D\r\n", show_timeleft(chquest->chaplimit));
if(chquest->questlimit > 0)
ch_printf(ch, "&RYou have %s left to finish this quest.&D\r\n", show_timeleft(chquest->questlimit));
ch_printf(ch, "&BYou have already attempted this quest %d time%s&D\r\n", times, times >= 5 ? "s!" : times == 1 ? "s." : ".");
chquest->times++;
return;
}
/*
* Was this the end of the quest?
*/
if(chquest->progress == (quest->chapters + 1))
{
send_to_char("&GYou have finished your quest!&D\r\n", ch);
if(quest->glory == 1)
{
ch->quest_curr += (quest->level + get_curr_con(ch));
ch->quest_accum += (quest->level + get_curr_con(ch));
ch_printf(ch, "&YYour glory has been increased by %d.&D\r\n", quest->level + get_curr_con(ch));
gain_exp(ch, 0 + ch->level * 100 + quest->level * 2000);
}
else
{
gain_exp(ch, 0 + ch->level * 100 + quest->level * 2000);
}
if(ch->pcdata->clan)
{
CLAN_DATA *clan;
clan = ch->pcdata->clan;
ch->pcdata->clanpoints += 1;
clan->totalpoints += 1;
ch_printf(ch, "&G%s clan has gained 1 point from your quest, now totaling %d clan status points!\r\n", clan->name, clan->totalpoints);
save_clan(clan);
}
if(chquest->questlimit)
ch_printf(ch, "&RYou had %s left when you completed the quest.&D\r\n", show_timeleft(chquest->questlimit));
chquest->chaplimit = 0;
chquest->questlimit = 0;
chquest->kamount = 0;
return;
}
chapter = get_chap_from_quest(chquest->progress, quest);
if(!chapter)
{
send_to_char("For now this is all you can do on this quest. Try back another time.\r\n", ch);
return;
}
chquest->chaplimit = chapter->timelimit;
chquest->kamount = 0;
/*
* If they aren't skipping show this message
*/
// if( !quest->skipchapters && skipped )
send_to_char("&GYou continue the quest, type &WJOURNAL &Gto see the update.&D\r\n", ch);
if(chquest->chaplimit > 0)
ch_printf(ch, "&RYou have %s left to finish this chapter.&D\r\n", show_timeleft(chquest->chaplimit));
if(chquest->questlimit > 0)
ch_printf(ch, "&RYou have %s left to finish this quest.&D\r\n", show_timeleft(chquest->questlimit));
}
int get_chapter(CHAR_DATA *ch, QUEST_DATA * quest)
{
CHQUEST_DATA *chquest;
if(!ch || !ch->pcdata || !quest)
return 0;
for(chquest = ch->pcdata->first_quest; chquest; chquest = chquest->next)
{
if(chquest->questnum == quest->number)
return chquest->progress;
}
return 0;
}
int get_chkamount(CHAR_DATA *ch, QUEST_DATA * quest)
{
CHQUEST_DATA *chquest;
if(!ch || !ch->pcdata || !quest)
return -1;
for(chquest = ch->pcdata->first_quest; chquest; chquest = chquest->next)
{
if(chquest->questnum == quest->number)
return chquest->kamount;
}
return -1;
}
/* The kamount is set to 0 and worked up */
void update_chquest_kamount(CHAR_DATA *ch, QUEST_DATA * quest, int nchapter)
{
CHQUEST_DATA *chquest;
CHAP_DATA *chapter;
int mins, seconds;
if(!quest || !ch || !ch->pcdata)
return;
for(chquest = ch->pcdata->first_quest; chquest; chquest = chquest->next)
{
if(chquest->questnum == quest->number)
break;
}
if(!chquest)
{
send_to_char("You aren't currently on that quest.\r\n", ch);
return;
}
/*
* Only update if we are on the right chapter
*/
if(nchapter != chquest->progress)
{
send_to_char("&GYou have to do the quest in order. Check your &WJOURNAL&D.\r\n", ch);
return;
}
++chquest->kamount;
}