Corrected more files not under SVN control.

This commit is contained in:
Rumble 2008-04-14 20:32:21 +00:00
parent 73e8b58bee
commit 700d74bfcd
5 changed files with 2354 additions and 1 deletions

541
src/asciimap.c Normal file
View file

@ -0,0 +1,541 @@
/**************************************************************************
* File: asciimap.c Part of tbaMUD *
* Usage: Generates an ASCII map of the player's surroundings. *
* *
* All rights reserved. See license for complete information. *
* *
* Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University *
* CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. *
**************************************************************************/
#include "conf.h"
#include "sysdep.h"
#include "structs.h"
#include "utils.h"
#include "comm.h"
#include "interpreter.h"
#include "handler.h"
#include "db.h"
#include "spells.h"
#include "house.h"
#include "constants.h"
#include "dg_scripts.h"
#include "asciimap.h"
/******************************************************************************
* Begin Local (File Scope) Defines and Global Variables
*****************************************************************************/
/* Do not blindly change these values, as many values cause the map to stop working - backup first */
#define CANVAS_HEIGHT 19
#define CANVAS_WIDTH 51
#define LEGEND_WIDTH 15
#define DEFAULT_MAP_SIZE CONFIG_MAP_SIZE
#define MAX_MAP_SIZE (CANVAS_WIDTH - 1)/4
#define MAX_MAP CANVAS_WIDTH
#define MAX_MAP_DIR 6
#define MAX_MAP_FOLLOW 4
#define SECT_EMPTY 30 /* anything greater than num sect types */
#define SECT_STRANGE (SECT_EMPTY + 1)
#define SECT_HERE (SECT_STRANGE + 1)
#define DOOR_NS -1
#define DOOR_EW -2
#define DOOR_UP -3
#define DOOR_DOWN -4
#define VDOOR_NS -5
#define VDOOR_EW -6
#define DOOR_NONE -7
#define NUM_DOOR_TYPES 7
#define MAP_CIRCLE 0
#define MAP_RECTANGLE 1
#define MAP_NORMAL 0
#define MAP_COMPACT 1
struct map_info_type
{
int sector_type;
char disp[20];
};
static struct map_info_type door_info[] =
{
{ DOOR_NONE, " " },
{ VDOOR_EW, " @m+@n " },
{ VDOOR_NS, " @m+@n "},
{ DOOR_DOWN, "@r-@n " },
{ DOOR_UP, "@r+@n " },
{ DOOR_EW, " - " },
{ DOOR_NS, " | " }
};
static struct map_info_type compact_door_info[] =
{
{ DOOR_NONE, " " },
{ VDOOR_EW, " @m+@n " },
{ VDOOR_NS, " @m+@n "},
{ DOOR_DOWN, "@r-@n" },
{ DOOR_UP, "@r+@n" },
{ DOOR_EW, "-" },
{ DOOR_NS, " | " }
};
/* Add new sector types below for both map_info and world_map_info */
/* The last 3 MUST remain the same, although the symbol can be changed */
/* New sectors also need to be added to the perform_map function below */
static struct map_info_type map_info[] =
{
{ SECT_INSIDE, "@c[@n.@c]@n" }, /* 0 */
{ SECT_CITY, "@c[@wC@c]@n" },
{ SECT_FIELD, "@c[@g,@c]@n" },
{ SECT_FOREST, "@c[@gY@c]@n" },
{ SECT_HILLS, "@c[@Mm@c]@n" },
{ SECT_MOUNTAIN, "@c[@rM@c]@n" }, /* 5 */
{ SECT_WATER_SWIM, "@c[@c~@c]@n" },
{ SECT_WATER_NOSWIM, "@c[@b=@c]@n" },
{ SECT_FLYING, "@c[@C^@c]@n" },
{ SECT_UNDERWATER, "@c[@bU@c]@n" },
{ -1, "" }, /* 10 */
{ -1, "" },
{ -1, "" },
{ -1, "" },
{ -1, "" },
{ -1, "" }, /* 15 */
{ -1, "" },
{ -1, "" },
{ -1, "" },
{ -1, "" },
{ -1, "" }, /* 20 */
{ -1, "" },
{ -1, "" },
{ -1, "" },
{ -1, "" },
{ -1, "" }, /* 25 */
{ -1, "" },
{ -1, "" },
{ -1, "" },
{ -1, "" },
{ SECT_EMPTY, " " }, /* 30 */
{ SECT_STRANGE, "@c[@R?@c]@n" },
{ SECT_HERE, "@c[@B!@c]@n" },
};
static struct map_info_type world_map_info[] =
{
{ SECT_INSIDE, "@n." }, /* 0 */
{ SECT_CITY, "@wC" },
{ SECT_FIELD, "@g," },
{ SECT_FOREST, "@gY" },
{ SECT_HILLS, "@Mm" },
{ SECT_MOUNTAIN, "@rM" }, /* 5 */
{ SECT_WATER_SWIM, "@c~" },
{ SECT_WATER_NOSWIM, "@b=" },
{ SECT_FLYING, "@C^" },
{ SECT_UNDERWATER, "@bU" },
{ -1, "" }, /* 10 */
{ -1, "" },
{ -1, "" },
{ -1, "" },
{ -1, "" },
{ -1, "" }, /* 15 */
{ -1, "" },
{ -1, "" },
{ -1, "" },
{ -1, "" },
{ -1, "" }, /* 20 */
{ -1, "" },
{ -1, "" },
{ -1, "" },
{ -1, "" },
{ -1, "" }, /* 25 */
{ -1, "" },
{ -1, "" },
{ -1, "" },
{ -1, "" },
{ SECT_EMPTY, " " }, /* 30 */
{ SECT_STRANGE, "@R?" },
{ SECT_HERE, "@B!" },
};
static int map[MAX_MAP][MAX_MAP];
static int offsets[4][2] ={ {-2, 0},{ 0, 2},{ 2, 0},{ 0, -2} };
static int offsets_worldmap[4][2] ={ {-1, 0},{ 0, 1},{ 1, 0},{ 0, -1} };
static int door_offsets[6][2] ={ {-1, 0},{ 0, 1},{ 1, 0},{ 0, -1},{ -1, 1},{ 1, 1} };
static int door_marks[6] = { DOOR_NS, DOOR_EW, DOOR_NS, DOOR_EW, DOOR_UP, DOOR_DOWN };
static int vdoor_marks[4] = { VDOOR_NS, VDOOR_EW, VDOOR_NS, VDOOR_EW };
/******************************************************************************
* End Local (File Scope) Defines and Global Variables
*****************************************************************************/
/******************************************************************************
* Begin Local (File Scope) Function Prototypes
*****************************************************************************/
static void MapArea(room_rnum room, struct char_data *ch, int x, int y, int min, int max, sh_int xpos, sh_int ypos, bool worldmap);
static char *StringMap(int centre, int size);
static char *WorldMap(int centre, int size, int mapshape, int maptype );
static char *CompactStringMap(int centre, int size);
static void perform_map( struct char_data *ch, char *argument, bool worldmap );
/******************************************************************************
* End Local (File Scope) Function Prototypes
*****************************************************************************/
bool can_see_map(struct char_data *ch) {
/* Is the map funcionality disabled? */
if (CONFIG_MAP == MAP_OFF)
return FALSE;
else if ((CONFIG_MAP == MAP_IMM_ONLY) && (GET_LEVEL(ch) < LVL_IMMORT))
return FALSE;
return TRUE;
}
/* MapArea function - create the actual map */
static void MapArea(room_rnum room, struct char_data *ch, int x, int y, int min, int max, sh_int xpos, sh_int ypos, bool worldmap)
{
room_rnum prospect_room;
struct room_direction_data *pexit;
int door, ew_size=0, ns_size=0, x_exit_pos=0, y_exit_pos=0;
sh_int prospect_xpos, prospect_ypos;
if (map[x][y] < 0)
return; /* this is a door */
/* marks the room as visited */
if(room == IN_ROOM(ch))
map[x][y] = SECT_HERE;
else
map[x][y] = SECT(room);
if ( (x < min) || ( y < min) || ( x > max ) || ( y > max) ) return;
/* Check for exits */
for ( door = 0; door < MAX_MAP_DIR; door++ ) {
if( door < MAX_MAP_FOLLOW &&
xpos+door_offsets[door][0] >= 0 &&
xpos+door_offsets[door][0] <= ns_size &&
ypos+door_offsets[door][1] >= 0 &&
ypos+door_offsets[door][1] <= ew_size)
{ /* Virtual exit */
map[x+door_offsets[door][0]][y+door_offsets[door][1]] = vdoor_marks[door] ;
if (map[x+offsets[door][0]][y+offsets[door][1]] == SECT_EMPTY )
MapArea(room,ch,x + offsets[door][0], y + offsets[door][1], min, max, xpos+door_offsets[door][0], ypos+door_offsets[door][1], worldmap);
continue;
}
if ( (pexit = world[room].dir_option[door]) > 0 &&
(pexit->to_room > 0 ) && (pexit->to_room != NOWHERE) &&
(!IS_SET(pexit->exit_info, EX_CLOSED))) { /* A real exit */
/* But is the door here... */
switch (door) {
case NORTH:
if(xpos > 0 || ypos!=y_exit_pos) continue;
break;
case SOUTH:
if(xpos < ns_size || ypos!=y_exit_pos) continue;
break;
case EAST:
if(ypos < ew_size || xpos!=x_exit_pos) continue;
break;
case WEST:
if(ypos > 0 || xpos!=x_exit_pos) continue;
break;
}
/* if ( (x < min) || ( y < min) || ( x > max ) || ( y > max) ) return;*/
prospect_room = pexit->to_room;
/* one way into area OR maze */
if ( world[prospect_room].dir_option[rev_dir[door]] &&
world[prospect_room].dir_option[rev_dir[door]]->to_room != room) {
map[x][y] = SECT_STRANGE;
return;
}
if(!worldmap)
map[x+door_offsets[door][0]][y+door_offsets[door][1]] = door_marks[door] ;
prospect_xpos = prospect_ypos = 0;
switch (door) {
case NORTH:
prospect_xpos = ns_size;
case SOUTH:
prospect_ypos = world[prospect_room].dir_option[rev_dir[door]] ? y_exit_pos : ew_size/2;
break;
case WEST:
prospect_ypos = ew_size;
case EAST:
prospect_xpos = world[prospect_room].dir_option[rev_dir[door]] ? x_exit_pos : ns_size/2;
}
if(worldmap) {
if ( door < MAX_MAP_FOLLOW && map[x+offsets_worldmap[door][0]][y+offsets_worldmap[door][1]] == SECT_EMPTY )
MapArea(pexit->to_room,ch,x + offsets_worldmap[door][0], y + offsets_worldmap[door][1], min, max, prospect_xpos, prospect_ypos, worldmap);
} else {
if ( door < MAX_MAP_FOLLOW && map[x+offsets[door][0]][y+offsets[door][1]] == SECT_EMPTY )
MapArea(pexit->to_room,ch,x + offsets[door][0], y + offsets[door][1], min, max, prospect_xpos, prospect_ypos, worldmap);
}
} /* end if exit there */
}
return;
}
/* Returns a string representation of the map */
static char *StringMap(int centre, int size)
{
static char strmap[MAX_MAP*MAX_MAP*11 + MAX_MAP*2 + 1];
char *mp = strmap;
char *tmp;
int x, y;
/* every row */
for (x = centre - CANVAS_HEIGHT/2; x <= centre + CANVAS_HEIGHT/2; x++) {
/* every column */
for (y = centre - CANVAS_WIDTH/6; y <= centre + CANVAS_WIDTH/6; y++) {
if (abs(centre - x)<=size && abs(centre-y)<=size)
tmp = (map[x][y]<0) ? \
door_info[NUM_DOOR_TYPES + map[x][y]].disp : \
map_info[map[x][y]].disp ;
else
tmp = map_info[SECT_EMPTY].disp;
strcpy(mp, tmp);
mp += strlen(tmp);
}
strcpy(mp, "\r\n");
mp+=2;
}
*mp='\0';
return strmap;
}
static char *WorldMap(int centre, int size, int mapshape, int maptype )
{
static char strmap[MAX_MAP*MAX_MAP*4 + MAX_MAP*2 + 1];
char *mp = strmap;
int x, y;
int xmin, xmax, ymin, ymax;
switch(maptype) {
case MAP_COMPACT:
xmin = centre - size;
xmax = centre + size;
ymin = centre - 2*size;
ymax = centre + 2*size;
break;
default:
xmin = centre - CANVAS_HEIGHT/2;
xmax = centre + CANVAS_HEIGHT/2;
ymin = centre - CANVAS_WIDTH/2;
ymax = centre + CANVAS_WIDTH/2;
}
/* every row */
/* for (x = centre - size; x <= centre + size; x++) { */
for (x = xmin; x <= xmax; x++) {
/* every column */
/* for (y = centre - (2*size) ; y <= centre + (2*size) ; y++) { */
for (y = ymin ; y <= ymax ; y++) {
if((mapshape == MAP_RECTANGLE && abs(centre - y) <= size*2 && abs(centre - x) <= size ) ||
((mapshape == MAP_CIRCLE) && (centre-x)*(centre-x) + (centre-y)*(centre-y)/4 <= (size * size + 1))) {
strcpy(mp, world_map_info[map[x][y]].disp);
mp += strlen(world_map_info[map[x][y]].disp);
} else {
strcpy(mp++, " ");
}
}
strcpy(mp, "@n\r\n");
mp+=4;
}
*mp='\0';
return strmap;
}
static char *CompactStringMap(int centre, int size)
{
static char strmap[MAX_MAP*MAX_MAP*12 + MAX_MAP*2 + 1];
char *mp = strmap;
int x, y;
/* every row */
for (x = centre - size; x <= centre + size; x++) {
/* every column */
for (y = centre - size; y <= centre + size; y++) {
strcpy(mp, (map[x][y]<0) ? \
compact_door_info[NUM_DOOR_TYPES + map[x][y]].disp : \
map_info[map[x][y]].disp);
mp += strlen((map[x][y]<0) ? \
compact_door_info[NUM_DOOR_TYPES + map[x][y]].disp : \
map_info[map[x][y]].disp);
}
strcpy(mp, "\r\n");
mp+=2;
}
*mp='\0';
return strmap;
}
/* Display a nicely formatted map with a legend */
static void perform_map( struct char_data *ch, char *argument, bool worldmap )
{
int size = DEFAULT_MAP_SIZE;
int centre, x, y, min, max;
char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH], buf[MAX_STRING_LENGTH], buf1[MAX_STRING_LENGTH], buf2[MAX_STRING_LENGTH];
int count = 0;
int ew_size=0, ns_size=0;
int mapshape = MAP_CIRCLE;
two_arguments( argument, arg1 , arg2 );
if(*arg1)
{
size = atoi(arg1);
}
if (*arg2)
{
if (is_abbrev(arg2, "normal")) worldmap=FALSE;
else if (is_abbrev(arg2, "world")) worldmap=TRUE;
else {
send_to_char(ch, "Usage: @ymap <distance> [ normal | world ]@n");
return;
}
}
if(size<0) {
size = -size;
mapshape = MAP_RECTANGLE;
}
size = URANGE(1,size,MAX_MAP_SIZE);
centre = MAX_MAP/2;
if(worldmap) {
min = centre - 2*size;
max = centre + 2*size;
} else {
min = centre - size;
max = centre + size;
}
/* Blank the map */
for (x = 0; x < MAX_MAP; ++x)
for (y = 0; y < MAX_MAP; ++y)
map[x][y]= (!(y%2) && !worldmap) ? DOOR_NONE : SECT_EMPTY;
/* starts the mapping with the centre room */
MapArea(IN_ROOM(ch), ch, centre, centre, min, max, ns_size/2, ew_size/2, worldmap);
/* marks the center, where ch is */
map[centre][centre] = SECT_HERE;
/* Feel free to put your own MUD name or header in here */
send_to_char(ch, " @Y-@ytbaMUD Map System@Y-@n\r\n"
"@D .-.__--.,--.__.-.@n\r\n" );
count += sprintf(buf + count, "@n@n@n%s Up\\\\", door_info[NUM_DOOR_TYPES + DOOR_UP].disp);
count += sprintf(buf + count, "@n@n@n%s Down\\\\", door_info[NUM_DOOR_TYPES + DOOR_DOWN].disp);
count += sprintf(buf + count, "@n%s You\\\\", map_info[SECT_HERE].disp);
count += sprintf(buf + count, "@n%s Inside\\\\", map_info[SECT_INSIDE].disp);
count += sprintf(buf + count, "@n%s City\\\\", map_info[SECT_CITY].disp);
count += sprintf(buf + count, "@n%s Field\\\\", map_info[SECT_FIELD].disp);
count += sprintf(buf + count, "@n%s Forest\\\\", map_info[SECT_FOREST].disp);
count += sprintf(buf + count, "@n%s Hills\\\\", map_info[SECT_HILLS].disp);
count += sprintf(buf + count, "@n%s Mountain\\\\", map_info[SECT_MOUNTAIN].disp);
count += sprintf(buf + count, "@n%s Swim\\\\", map_info[SECT_WATER_SWIM].disp);
count += sprintf(buf + count, "@n%s Boat\\\\", map_info[SECT_WATER_NOSWIM].disp);
count += sprintf(buf + count, "@n%s Flying\\\\", map_info[SECT_FLYING].disp);
count += sprintf(buf + count, "@n%s Underwater\\\\", map_info[SECT_UNDERWATER].disp);
strcpy(buf, strfrmt(buf, LEGEND_WIDTH, CANVAS_HEIGHT + 2, FALSE, TRUE, TRUE));
/* Start with an empty column */
strcpy(buf1, strfrmt("",0, CANVAS_HEIGHT + 2, FALSE, FALSE, TRUE));
/* Paste the legend */
strcpy(buf2, strpaste(buf1, buf, "@D | @n"));
/* Set up the map */
memset(buf, ' ', CANVAS_WIDTH);
count = (CANVAS_WIDTH);
if(worldmap)
count += sprintf(buf + count , "\r\n%s", WorldMap(centre, size, mapshape, MAP_NORMAL));
else
count += sprintf(buf + count , "\r\n%s", StringMap(centre, size));
memset(buf + count, ' ', CANVAS_WIDTH);
strcpy(buf + count + CANVAS_WIDTH, "\r\n");
/* Paste it on */
strcpy(buf2, strpaste(buf2, buf, "@D | @n"));
/* Paste on the right border */
strcpy(buf2, strpaste(buf2, buf1, " "));
/* Print it all out */
send_to_char(ch, buf2);
send_to_char(ch, "@D `.-.__--.,-.__.-.-'@n\r\n");
return;
}
/* Display a string with the map beside it */
void str_and_map(char *str, struct char_data *ch ) {
int size, centre, x, y, min, max, char_size;
int ew_size=0, ns_size=0;
bool worldmap;
/* Check MUDs map config options - if disabled, just show room decsription */
if (!can_see_map(ch)) {
send_to_char(ch, strfrmt(str, GET_SCREEN_WIDTH(ch), 1, FALSE, FALSE, FALSE));
return;
}
worldmap = ROOM_FLAGGED(IN_ROOM(ch), ROOM_WORLDMAP) ? TRUE : FALSE ;
if(!PRF_FLAGGED(ch, PRF_AUTOMAP)) {
send_to_char(ch, strfrmt(str, GET_SCREEN_WIDTH(ch), 1, FALSE, FALSE, FALSE));
return;
}
size = CONFIG_MINIMAP_SIZE;
centre = MAX_MAP/2;
min = centre - 2*size;
max = centre + 2*size;
for (x = 0; x < MAX_MAP; ++x)
for (y = 0; y < MAX_MAP; ++y)
map[x][y]= (!(y%2) && !worldmap) ? DOOR_NONE : SECT_EMPTY;
/* starts the mapping with the center room */
MapArea(IN_ROOM(ch), ch, centre, centre, min, max, ns_size/2, ew_size/2, worldmap );
map[centre][centre] = SECT_HERE;
/* char_size = rooms + doors + padding */
if(worldmap)
char_size = size * 4 + 5;
else
char_size = 3*(size+1) + (size) + 4;
if(worldmap)
send_to_char(ch, strpaste(strfrmt(str, GET_SCREEN_WIDTH(ch) - char_size, size*2 + 1, FALSE, TRUE, TRUE), WorldMap(centre, size, MAP_CIRCLE, MAP_COMPACT), " "));
else
send_to_char(ch, strpaste(strfrmt(str, GET_SCREEN_WIDTH(ch) - char_size, size*2 + 1, FALSE, TRUE, TRUE), CompactStringMap(centre, size), " "));
}
ACMD(do_map) {
if (!can_see_map(ch)) {
send_to_char(ch, "Sorry, the map is disabled!\r\n");
return;
}
perform_map(ch, argument, ROOM_FLAGGED(IN_ROOM(ch), ROOM_WORLDMAP) ? 1 : 0 );
}

265
src/genqst.c Normal file
View file

@ -0,0 +1,265 @@
/* ***********************************************************************
* File: genqst.c Part of CircleMUD *
* Version: 2.0 (November 2005) Written for CircleMud CWG / Suntzu *
* Purpose: To provide special quest-related code. *
* Copyright: Kenneth Ray *
* Original Version Details: *
* Copyright 1996 by Harvey Gilpin *
* Copyright 1997-2001 by George Greer (greerga@circlemud.org) *
************************************************************************ */
#include "conf.h"
#include "sysdep.h"
#include "structs.h"
#include "utils.h"
#include "db.h"
#include "quest.h"
#include "genolc.h"
#include "genzon.h"
#include "genzon.h" /* for create_world_index */
/*-------------------------------------------------------------------*/
int copy_quest(struct aq_data *to, struct aq_data *from, int free_old_strings)
{
int i;
if (free_old_strings)
free_quest_strings(to);
to->vnum = from->vnum;
to->flags = from->flags;
to->type = from->type;
to->qm = from->qm;
to->target = from->target;
to->prereq = from->prereq;
to->prev_quest = from->prev_quest;
to->next_quest = from->next_quest;
for (i = 0; i < 7; i++){
to->value[i] = from->value[i];
}
to->gold_reward = from->gold_reward;
to->exp_reward = from->exp_reward;
to->obj_reward = from->obj_reward;
to->func = from->func;
return copy_quest_strings(to, from);
}
int copy_quest_strings(struct aq_data *to, struct aq_data *from)
{
if (from == NULL || to == NULL) {
log("SYSERR: GenQST: copy_quest_strings: Null values passed.");
return FALSE;
}
to->name = str_udup(from->name);
to->desc = str_udup(from->desc);
to->info = str_udup(from->info);
to->done = str_udup(from->done);
to->quit = str_udup(from->quit);
return TRUE;
}
void free_quest_strings(struct aq_data *quest)
{
if (quest->name)
free(quest->name);
if (quest->desc)
free(quest->desc);
if (quest->info)
free(quest->info);
if (quest->done)
free(quest->done);
if (quest->quit)
free(quest->quit);
}
void free_quest(struct aq_data *quest)
{
free_quest_strings(quest);
free(quest);
}
/*-------------------------------------------------------------------*/
int add_quest(struct aq_data *nqst)
{
qst_rnum rnum;
zone_rnum rznum = real_zone_by_thing(nqst->vnum);
/* The quest already exists, just update it. */
if ((rnum = real_quest(nqst->vnum)) != NOWHERE) {
copy_quest(&aquest_table[rnum], nqst, TRUE);
} else {
/* increase the number of quest table entries */
total_quests++;
RECREATE(aquest_table, struct aq_data, total_quests );
/* Initialise top quest strings to null */
QST_NAME(total_quests - 1) = NULL;
QST_DESC(total_quests - 1) = NULL;
QST_INFO(total_quests - 1) = NULL;
QST_DONE(total_quests - 1) = NULL;
QST_QUIT(total_quests - 1) = NULL;
/* Now process enties from the top down to see where the new one goes */
for (rnum = total_quests - 1; rnum > 0; rnum--) {
if (nqst->vnum > QST_NUM(rnum - 1))
break; //found the place
aquest_table[rnum] = aquest_table[rnum - 1]; //shift quest up one
}
copy_quest(&aquest_table[rnum], nqst, FALSE);
}
/* Make sure we assign spec procs to the questmaster */
if (mob_index[QST_MASTER(rnum)].func &&
mob_index[QST_MASTER(rnum)].func != questmaster)
QST_FUNC(rnum) = mob_index[QST_MASTER(rnum)].func;
mob_index[QST_MASTER(rnum)].func = questmaster;
/* And make sure we save the updated quest information to disk */
if (rznum != NOWHERE)
add_to_save_list(zone_table[rznum].number, SL_QST);
else
mudlog(BRF, LVL_BUILDER, TRUE,
"SYSERR: GenOLC: Cannot determine quest zone.");
return rnum;
}
/*-------------------------------------------------------------------*/
int delete_quest(qst_rnum rnum)
{
qst_rnum i;
zone_rnum rznum = real_zone_by_thing(QST_NUM(rnum));
mob_rnum qm = QST_MASTER(rnum);
SPECIAL (*tempfunc);
int quests_remaining = 0;
if (rnum >= total_quests)
return FALSE;
log("GenOLC: delete_quest: Deleting quest #%d (%s).",
QST_NUM(rnum), QST_NAME(rnum));
/* make a note of the quest master's secondary spec proc */
tempfunc = QST_FUNC(rnum);
free_quest_strings(&aquest_table[rnum]);
for (i = rnum; i < total_quests - 1; i++) {
aquest_table[i] = aquest_table[i + 1];
}
total_quests--;
RECREATE(aquest_table, struct aq_data, total_quests);
if (rznum != NOWHERE)
add_to_save_list(zone_table[rznum].number, SL_QST);
else
mudlog(BRF, LVL_BUILDER, TRUE,
"SYSERR: GenOLC: Cannot determine quest zone.");
/* does the questmaster mob have any quests left? */
if (qm != NOBODY) {
for (i = 0; i < total_quests; i++) {
if (QST_MASTER(i) == qm)
quests_remaining++;
}
if (quests_remaining == 0)
mob_index[qm].func = tempfunc; // point back to original spec proc
}
return TRUE;
}
/*-------------------------------------------------------------------*/
int save_quests(zone_rnum zone_num)
{
FILE *sf;
char filename[128], oldname[128], quest_flags[MAX_STRING_LENGTH];
char quest_desc[MAX_STRING_LENGTH], quest_info[MAX_STRING_LENGTH];
char quest_done[MAX_STRING_LENGTH], quest_quit[MAX_STRING_LENGTH];
int i, num_quests = 0;
#if CIRCLE_UNSIGNED_INDEX
if (zone_num == NOWHERE || zone_num > top_of_zone_table) {
#else
if (zone_num < 0 || zone_num > top_of_zone_table) {
#endif
log("SYSERR: GenOLC: save_quests: Invalid zone number %d passed! (0-%d)",
zone_num, top_of_zone_table);
return FALSE;
}
log("GenOLC: save_quests: Saving quests in zone #%d (%d-%d).",
zone_table[zone_num].number,
genolc_zone_bottom(zone_num), zone_table[zone_num].top);
snprintf(filename, sizeof(filename), "%s/%d.new",
QST_PREFIX, zone_table[zone_num].number);
if (!(sf = fopen(filename, "w"))) {
perror("SYSERR: save_quests");
return FALSE;
}
for (i = genolc_zone_bottom(zone_num); i <= zone_table[zone_num].top; i++) {
qst_rnum rnum;
if ((rnum = real_quest(i)) != NOTHING) {
/* Copy the text strings and strip off trailing newlines. */
strncpy(quest_desc, QST_DESC(rnum) ? QST_DESC(rnum) : "undefined",
sizeof(quest_desc)-1 );
strncpy(quest_info, QST_INFO(rnum) ? QST_INFO(rnum) : "undefined",
sizeof(quest_info)-1 );
strncpy(quest_done, QST_DONE(rnum) ? QST_DONE(rnum) : "undefined",
sizeof(quest_done)-1 );
strncpy(quest_quit, QST_QUIT(rnum) ? QST_QUIT(rnum) : "undefined",
sizeof(quest_quit)-1 );
strip_cr(quest_desc);
strip_cr(quest_info);
strip_cr(quest_done);
strip_cr(quest_quit);
/* Save the quest details to the file. */
sprintascii(quest_flags, QST_FLAGS(rnum));
fprintf(sf,
"#%d\n"
"%s%c\n"
"%s%c\n"
"%s%c\n"
"%s%c\n"
"%s%c\n"
"%d %d %s %d %d %d %d\n"
"%d %d %d %d %d %d %d\n"
"%d %d %d\n"
"S\n",
QST_NUM(rnum),
QST_NAME(rnum) ? QST_NAME(rnum) : "Untitled", STRING_TERMINATOR,
quest_desc, STRING_TERMINATOR,
quest_info, STRING_TERMINATOR,
quest_done, STRING_TERMINATOR,
quest_quit, STRING_TERMINATOR,
QST_TYPE(rnum),
QST_MASTER(rnum) == NOBODY ? -1 : mob_index[QST_MASTER(rnum)].vnum,
quest_flags,
QST_TARGET(rnum) == NOTHING ? -1 : QST_TARGET(rnum),
QST_PREV(rnum) == NOTHING ? -1 : QST_PREV(rnum),
QST_NEXT(rnum) == NOTHING ? -1 : QST_NEXT(rnum),
QST_PREREQ(rnum) == NOTHING ? -1 : QST_PREREQ(rnum),
QST_POINTS(rnum), QST_PENALTY(rnum), QST_MINLEVEL(rnum),
QST_MAXLEVEL(rnum), QST_TIME(rnum),
QST_RETURNMOB(rnum) == NOBODY ? -1 : QST_RETURNMOB(rnum),
QST_QUANTITY(rnum), QST_GOLD(rnum), QST_EXP(rnum), QST_OBJ(rnum)
);
num_quests++;
}
}
/* Write the final line and close it. */
fprintf(sf, "$~\n");
fclose(sf);
/* Old file we're replacing. */
snprintf(oldname, sizeof(oldname), "%s/%d.qst",
QST_PREFIX, zone_table[zone_num].number);
remove(oldname);
rename(filename, oldname);
/* Do we need to update the index file? */
if (num_quests > 0)
create_world_index(zone_table[zone_num].number, "qst");
if (in_save_list(zone_table[zone_num].number, SL_QST))
remove_from_save_list(zone_table[zone_num].number, SL_QST);
return TRUE;
}

View file

@ -85,7 +85,7 @@ void mobile_activity(void)
(world[EXIT(ch, door)->to_room].zone == world[IN_ROOM(ch)].zone))) (world[EXIT(ch, door)->to_room].zone == world[IN_ROOM(ch)].zone)))
{ {
/* If the mob is charmed, do not move the mob. */ /* If the mob is charmed, do not move the mob. */
if (ch->master != NULL) if (ch->master == NULL)
perform_move(ch, door, 1); perform_move(ch, door, 1);
} }

742
src/qedit.c Normal file
View file

@ -0,0 +1,742 @@
/* ***********************************************************************
* File: qedit.c Part of CircleMUD *
* Version: 2.0 (November 2005) Written for CircleMud CWG / Suntzu *
* Purpose: To provide special quest-related code. *
* Copyright: Kenneth Ray *
* *
* Made for Oasis OLC *
* Copyright 1996 Harvey Gilpin. *
*********************************************************************** */
#include "conf.h"
#include "sysdep.h"
#include "structs.h"
#include "utils.h"
#include "comm.h"
#include "db.h"
#include "oasis.h"
#include "improved-edit.h"
#include "screen.h"
#include "genolc.h"
#include "genzon.h"
#include "interpreter.h"
#include "modify.h"
#include "quest.h"
/*-------------------------------------------------------------------*/
/*. Function prototypes . */
static void qedit_setup_new(struct descriptor_data *d);
static void qedit_setup_existing(struct descriptor_data *d, qst_rnum rnum);
static void qedit_disp_menu(struct descriptor_data *d);
static void qedit_save_internally(struct descriptor_data *d);
static void qedit_save_to_disk(int num);
/*-------------------------------------------------------------------*/
static void qedit_save_internally(struct descriptor_data *d)
{
add_quest(OLC_QUEST(d));
}
static void qedit_save_to_disk(int num)
{
save_quests(num);
}
/*-------------------------------------------------------------------*\
utility functions
\*-------------------------------------------------------------------*/
ACMD(do_oasis_qedit)
{
int save = 0;
qst_rnum real_num;
qst_vnum number = NOWHERE;
struct descriptor_data *d;
char *buf3;
char buf1[MAX_INPUT_LENGTH];
char buf2[MAX_INPUT_LENGTH];
/****************************************************************************/
/** Parse any arguments. **/
/****************************************************************************/
buf3 = two_arguments(argument, buf1, buf2);
if (!*buf1) {
send_to_char(ch, "Specify a quest VNUM to edit.\r\n");
return;
} else if (!isdigit(*buf1)) {
if (str_cmp("save", buf1) != 0) {
send_to_char(ch, "Yikes! Stop that, someone will get hurt!\r\n");
return;
}
save = TRUE;
if (is_number(buf2))
number = atoi(buf2);
else if (GET_OLC_ZONE(ch) > 0) {
zone_rnum zlok;
if ((zlok = real_zone(GET_OLC_ZONE(ch))) == NOWHERE)
number = NOWHERE;
else
number = genolc_zone_bottom(zlok);
}
if (number == NOWHERE) {
send_to_char(ch, "Save which zone?\r\n");
return;
}
}
/****************************************************************************/
/** If a numeric argument was given, get it. **/
/****************************************************************************/
if (number == NOWHERE)
number = atoi(buf1);
/****************************************************************************/
/** Check that the guild isn't already being edited. **/
/****************************************************************************/
for (d = descriptor_list; d; d = d->next) {
if (STATE(d) == CON_QEDIT) {
if (d->olc && OLC_NUM(d) == number) {
send_to_char(ch, "That quest is currently being edited by %s.\r\n",
PERS(d->character, ch));
return;
}
}
}
/****************************************************************************/
/** Point d to the builder's descriptor. **/
/****************************************************************************/
d = ch->desc;
/****************************************************************************/
/** Give the descriptor an OLC structure. **/
/****************************************************************************/
if (d->olc) {
mudlog(BRF, LVL_IMMORT, TRUE,
"SYSERR: do_oasis_quest: Player already had olc structure.");
free(d->olc);
}
CREATE(d->olc, struct oasis_olc_data, 1);
/****************************************************************************/
/** Find the zone. **/
/****************************************************************************/
if ((OLC_ZNUM(d) = real_zone_by_thing(number)) == NOWHERE) {
send_to_char(ch, "Sorry, there is no zone for that number!\r\n");
free(d->olc);
d->olc = NULL;
return;
}
/****************************************************************************/
/** Everyone but IMPLs can only edit zones they have been assigned. **/
/****************************************************************************/
if (!can_edit_zone(ch, OLC_ZNUM(d))) {
send_to_char(ch, "You do not have permission to edit this zone.\r\n");
/**************************************************************************/
/** Free the OLC structure. **/
/**************************************************************************/
free(d->olc);
d->olc = NULL;
return;
}
if (save) {
send_to_char(ch, "Saving all quests in zone %d.\r\n",
zone_table[OLC_ZNUM(d)].number);
mudlog(CMP, MAX(LVL_BUILDER, GET_INVIS_LEV(ch)), TRUE,
"OLC: %s saves quest info for zone %d.",
GET_NAME(ch), zone_table[OLC_ZNUM(d)].number);
/**************************************************************************/
/** Save the quest to the quest file. **/
/**************************************************************************/
qedit_save_to_disk(OLC_ZNUM(d));
/**************************************************************************/
/** Free the OLC structure. **/
/**************************************************************************/
free(d->olc);
d->olc = NULL;
return;
}
OLC_NUM(d) = number;
if ((real_num = real_quest(number)) != NOTHING)
qedit_setup_existing(d, real_num);
else
qedit_setup_new(d);
STATE(d) = CON_QEDIT;
act("$n starts using OLC.", TRUE, d->character, 0, 0, TO_ROOM);
SET_BIT_AR(PLR_FLAGS(ch), PLR_WRITING);
mudlog(BRF, LVL_IMMORT, TRUE,
"OLC: %s starts editing zone %d allowed zone %d",
GET_NAME(ch), zone_table[OLC_ZNUM(d)].number, GET_OLC_ZONE(ch));
}
static void qedit_setup_new(struct descriptor_data *d)
{
struct aq_data *quest;
/* Allociate some quest shaped space */
CREATE(quest, struct aq_data, 1);
/* Set default values */
quest->vnum = OLC_NUM(d); /* Quest vnum */
quest->qm = NOBODY; /* Questmaster rnum */
quest->flags = 0; /* Quest bitflags */
quest->type = AQ_UNDEFINED; /* Quest type */
quest->target = NOTHING; /* Quest target */
quest->prereq = NOTHING; /* Prerequisite object */
quest->value[0] = 0; /* Points for completing */
quest->value[1] = 0; /* Points for abandoning */
quest->value[2] = 0; /* Minimum level */
quest->value[3] = LVL_IMPL; /* Maximim level */
quest->value[4] = -1; /* Time limit */
quest->value[5] = NOBODY; /* Mob to return object */
quest->value[6] = 1; /* Quantity of targets */
quest->prev_quest = NOTHING; /* Previous quest */
quest->next_quest = NOTHING; /* Next quest */
quest->gold_reward= 0; /* Prize in gold coins */
quest->exp_reward = 0; /* Prize in exp points */
quest->obj_reward = NOTHING; /* vnum of reward object */
quest->name = strdup("Undefined Quest");
quest->desc = strdup("Quest definition is incomplete.");
quest->info = strdup("There is no information on this quest.\r\n");
quest->done = strdup("You have completed the quest.\r\n");
quest->quit = strdup("You have abandoned the quest.\r\n");
quest->func = NULL; /* Secondary qm spec proc */
/* Set the descriptor OLC structure to point to this quest */
OLC_QUEST(d) = quest;
/* Show the main quest edit menu */
qedit_disp_menu(d);
}
/*-------------------------------------------------------------------*/
static void qedit_setup_existing(struct descriptor_data *d, qst_rnum r_num)
{
/*. Alloc some quest shaped space . */
CREATE(OLC_QUEST(d), struct aq_data, 1);
copy_quest(OLC_QUEST(d), aquest_table + r_num, FALSE);
qedit_disp_menu(d);
}
/*-------------------------------------------------------------------*/
/**************************************************************************
Menu functions
**************************************************************************/
/*-------------------------------------------------------------------*/
/*. Display main menu . */
static void qedit_disp_menu(struct descriptor_data *d)
{
struct aq_data *quest;
char quest_flags[MAX_STRING_LENGTH], buf2[MAX_STRING_LENGTH];
char targetname[MAX_STRING_LENGTH];
mob_vnum return_mob;
quest = OLC_QUEST(d);
clear_screen(d);
sprintbit(quest->flags, aq_flags, quest_flags, sizeof(quest_flags));
if (quest->type == AQ_OBJ_RETURN) {
if ((return_mob = real_mobile(quest->value[5])) != NOBODY)
snprintf(buf2, sizeof(buf2), "to %s [%d]",
mob_proto[return_mob].player.short_descr,
quest->value[5]);
else
snprintf(buf2, sizeof(buf2), "to an unknown mob [%d].",
quest->value[5]);
}
switch (quest->type) {
case AQ_OBJ_FIND:
case AQ_OBJ_RETURN:
snprintf(targetname, sizeof(targetname), "%s",
real_object(quest->target) == NOTHING ?
"An unknown object" :
obj_proto[real_object(quest->target)].short_description);
break;
case AQ_ROOM_FIND:
case AQ_ROOM_CLEAR:
snprintf(targetname, sizeof(targetname), "%s",
real_room(quest->target) == NOWHERE ?
"An unknown room" :
world[real_room(quest->target)].name);
break;
case AQ_MOB_FIND:
case AQ_MOB_KILL:
case AQ_MOB_SAVE:
snprintf(targetname, sizeof(targetname), "%s",
real_mobile(quest->target) == NOBODY ?
"An unknown mobile" :
GET_NAME(&mob_proto[real_mobile(quest->target)]));
break;
default:
snprintf(targetname, sizeof(targetname), "Unknown");
break;
}
write_to_output(d,
"-- Quest Number : @n[@c%6d@n]\r\n"
"@g 1@n) Quest Name : @y%s\r\n"
"@g 2@n) Description : @y%s\r\n"
"@g 3@n) Accept Message\r\n@y%s"
"@g 4@n) Completion Message\r\n@y%s"
"@g 5@n) Quit Message\r\n@y%s"
"@g 6@n) Quest Flags : @c%s\r\n"
"@g 7@n) Quest Type : @c%s %s\r\n"
"@g 8@n) Quest Master : [@c%6d@n] @y%s\r\n"
"@g 9@n) Quest Target : [@c%6d@n] @y%s\r\n"
"@g A@n) Quantity : [@c%6d@n]\r\n"
"@n Quest Point Rewards\r\n"
"@g B@n) Completed : [@c%6d@n] @g C@n) Abandoned : [@c%6d@n]\r\n"
"@n Other Rewards Rewards\r\n"
"@g G@n) Gold Coins : [@c%6d@n] @g T@n) Exp Points : [@c%6d@n] @g O@n) Object : [@c%6d@n]\r\n"
"@n Level Limits to Accept Quest\r\n"
"@g D@n) Lower Level : [@c%6d@n] @g E@n) Upper Level : [@c%6d@n]\r\n"
"@g F@n) Prerequisite : [@c%6d@n] @y%s\r\n"
"@g L@n) Time Limit : [@c%6d@n]\r\n"
"@g N@n) Next Quest : [@c%6d@n] @y%s\r\n"
"@g P@n) Previous Quest : [@c%6d@n] @y%s\r\n"
"@g X@n) Delete Quest\r\n"
"@g Q@n) Quit\r\n"
"Enter Choice : ",
quest->vnum,
quest->name,
quest->desc,
quest->info && (str_cmp(quest->info, "undefined"))
? quest->info : "Nothing\r\n",
quest->done && (str_cmp(quest->done, "undefined"))
? quest->done : "Nothing\r\n",
quest->quit && (str_cmp(quest->quit, "undefined"))
? quest->quit : "Nothing\r\n",
quest_flags,
quest_types[quest->type],
quest->type == AQ_OBJ_RETURN ? buf2 : "",
quest->qm == NOBODY ? -1 : mob_index[quest->qm].vnum,
quest->qm == NOBODY ? "none" : mob_proto[quest->qm].player.short_descr,
quest->target == NOBODY ? -1 : quest->target, targetname,
quest->value[6],
quest->value[0], quest->value[1],
quest->gold_reward, quest->exp_reward, quest->obj_reward == NOTHING ? -1 : quest->obj_reward,
quest->value[2], quest->value[3],
quest->prereq == NOTHING ? -1 : quest->prereq,
quest->prereq == NOTHING ? "" :
real_object(quest->prereq) == NOTHING ? "an unknown object" :
obj_proto[real_object(quest->prereq)].short_description,
quest->value[4],
quest->next_quest == NOTHING ? -1 : quest->next_quest,
quest->next_quest == NOTHING ? "" : QST_DESC(real_quest(quest->next_quest)),
quest->prev_quest == NOTHING ? -1 : quest->prev_quest,
quest->prev_quest == NOTHING ? "" : QST_DESC(real_quest(quest->prev_quest))
);
OLC_MODE(d) = QEDIT_MAIN_MENU;
}
/* For sector type. */
void qedit_disp_type_menu(struct descriptor_data *d)
{
int counter, columns = 0;
clear_screen(d);
for (counter = 0; counter < NUM_AQ_TYPES; counter++) {
write_to_output(d, "@g%2d@n) %-20.20s %s", counter,
quest_types[counter], !(++columns % 2) ? "\r\n" : "");
}
write_to_output(d, "\r\nEnter Quest type : ");
OLC_MODE(d) = QEDIT_TYPES;
}
/* For quest flags. */
void qedit_disp_flag_menu(struct descriptor_data *d)
{
char bits[MAX_STRING_LENGTH];
int counter, columns = 0;
get_char_colors(d->character);
clear_screen(d);
for (counter = 0; counter < NUM_AQ_FLAGS; counter++) {
write_to_output(d, "%s%2d%s) %-20.20s %s", grn, counter + 1, nrm,
aq_flags[counter], !(++columns % 2) ? "\r\n" : "");
}
sprintbit(OLC_QUEST(d)->flags, aq_flags, bits, sizeof(bits));
write_to_output(d, "\r\nQuest flags: @c%s@n\r\n"
"Enter quest flags, 0 to quit : ", bits);
OLC_MODE(d) = QEDIT_FLAGS;
}
/**************************************************************************
The GARGANTUAN event handler
**************************************************************************/
void qedit_parse(struct descriptor_data *d, char *arg)
{
int number = atoi(arg);
char *oldtext = NULL;
switch (OLC_MODE(d)) {
/*-------------------------------------------------------------------*/
case QEDIT_CONFIRM_SAVESTRING:
switch (*arg) {
case 'y':
case 'Y':
send_to_char(d->character, "Saving Quest to memory.\r\n");
qedit_save_internally(d);
mudlog(CMP, MAX(LVL_BUILDER, GET_INVIS_LEV(d->character)), TRUE,
"OLC: %s edits quest %d", GET_NAME(d->character), OLC_NUM(d));
if (CONFIG_OLC_SAVE) {
qedit_save_to_disk(real_zone_by_thing(OLC_NUM(d)));
write_to_output(d, "Quest %d saved to disk.\r\n", OLC_NUM(d));
} else
write_to_output(d, "Quest %d saved to memory.\r\n", OLC_NUM(d));
cleanup_olc(d, CLEANUP_STRUCTS);
return;
case 'n':
case 'N':
cleanup_olc(d, CLEANUP_ALL);
return;
default:
write_to_output(d,
"Invalid choice!\r\nDo you wish to save the quest? : ");
return;
}
break;
/*-------------------------------------------------------------------*/
case QEDIT_CONFIRM_DELETE:
switch (*arg) {
case 'y':
case 'Y':
if (delete_quest(real_quest(OLC_NUM(d))))
write_to_output(d, "Quest deleted.\r\n");
else
write_to_output(d, "Couldn't delete the quest!\r\n");
if (CONFIG_OLC_SAVE) {
qedit_save_to_disk(real_zone_by_thing(OLC_NUM(d)));
write_to_output(d, "Quest file saved to disk.\r\n");
} else
write_to_output(d, "Quest file saved to memory.\r\n");
cleanup_olc(d, CLEANUP_ALL);
return;
case 'n':
case 'N':
qedit_disp_menu(d);
return;
default:
write_to_output(d,
"Invalid choice!\r\nDo you wish to delete the quest? : ");
return;
}
break;
/*-------------------------------------------------------------------*/
case QEDIT_MAIN_MENU:
switch (*arg) {
case 'q':
case 'Q':
if (OLC_VAL(d)) { /*. Anything been changed? . */
write_to_output(d,
"Do you wish to save the changes to the Quest? (y/n) : ");
OLC_MODE(d) = QEDIT_CONFIRM_SAVESTRING;
} else
cleanup_olc(d, CLEANUP_ALL);
return;
case 'x':
case 'X':
OLC_MODE(d) = QEDIT_CONFIRM_DELETE;
write_to_output(d, "Do you wish to delete the Quest? (y/n) : ");
break;
case '1':
OLC_MODE(d) = QEDIT_NAME;
write_to_output(d, "Enter the quest name : ");
break;
case '2':
OLC_MODE(d) = QEDIT_DESC;
write_to_output(d, "Enter the quest description :-\r\n] ");
break;
case '3':
OLC_MODE(d) = QEDIT_INFO;
clear_screen(d);
send_editor_help(d);
write_to_output(d, "Enter quest acceptance message:\r\n\r\n");
if (OLC_QUEST(d)->info) {
write_to_output(d, "%s", OLC_QUEST(d)->info);
oldtext = strdup(OLC_QUEST(d)->info);
}
string_write(d, &OLC_QUEST(d)->info, MAX_QUEST_MSG, 0, oldtext);
OLC_VAL(d) = 1;
break;
case '4':
OLC_MODE(d) = QEDIT_COMPLETE;
clear_screen(d);
send_editor_help(d);
write_to_output(d, "Enter quest completion message:\r\n\r\n");
if (OLC_QUEST(d)->done) {
write_to_output(d, "%s", OLC_QUEST(d)->done);
oldtext = strdup(OLC_QUEST(d)->done);
}
string_write(d, &OLC_QUEST(d)->done, MAX_QUEST_MSG, 0, oldtext);
OLC_VAL(d) = 1;
break;
case '5':
OLC_MODE(d) = QEDIT_ABANDON;
clear_screen(d);
send_editor_help(d);
write_to_output(d, "Enter quest quit message:\r\n\r\n");
if (OLC_QUEST(d)->quit) {
write_to_output(d, "%s", OLC_QUEST(d)->quit);
oldtext = strdup(OLC_QUEST(d)->quit);
}
string_write(d, &OLC_QUEST(d)->quit, MAX_QUEST_MSG, 0, oldtext);
OLC_VAL(d) = 1;
break;
case '6':
OLC_MODE(d) = QEDIT_FLAGS;
qedit_disp_flag_menu(d);
break;
case '7':
OLC_MODE(d) = QEDIT_TYPES;
qedit_disp_type_menu(d);
break;
case '8':
OLC_MODE(d) = QEDIT_QUESTMASTER;
write_to_output(d, "Enter vnum of quest master : ");
break;
case '9':
OLC_MODE(d) = QEDIT_TARGET;
write_to_output(d, "Enter target vnum : ");
break;
case 'a':
case 'A':
OLC_MODE(d) = QEDIT_QUANTITY;
write_to_output(d, "Enter quantity of target : ");
break;
case 'b':
case 'B':
OLC_MODE(d) = QEDIT_POINTSCOMP;
write_to_output(d, "Enter points for completing the quest : " );
break;
case 'c':
case 'C':
OLC_MODE(d) = QEDIT_POINTSQUIT;
write_to_output(d, "Enter points for quitting the quest : " );
break;
case 'd':
case 'D':
OLC_MODE(d) = QEDIT_LEVELMIN;
write_to_output(d, "Enter minimum level to accept the quest : " );
break;
case 'e':
case 'E':
OLC_MODE(d) = QEDIT_LEVELMAX;
write_to_output(d, "Enter maximum level to accept the quest : " );
break;
case 'f':
case 'F':
OLC_MODE(d) = QEDIT_PREREQ;
write_to_output(d, "Enter a prerequisite object vnum (-1 for none) : ");
break;
case 'g':
case 'G':
OLC_MODE(d) = QEDIT_GOLD;
write_to_output(d, "Enter the number of gold coins (0 for none) : ");
break;
case 't':
case 'T':
OLC_MODE(d) = QEDIT_EXP;
write_to_output(d, "Enter a number of experience points (0 for none) : ");
break;
case 'o':
case 'O':
OLC_MODE(d) = QEDIT_OBJ;
write_to_output(d, "Enter the prize object vnum (-1 for none) : ");
break;
case 'l':
case 'L':
OLC_MODE(d) = QEDIT_TIMELIMIT;
write_to_output(d, "Enter time limit to complete (-1 for none) : " );
break;
case 'n':
case 'N':
OLC_MODE(d) = QEDIT_NEXTQUEST;
write_to_output(d, "Enter vnum of next quest (-1 for none) : ");
break;
case 'p':
case 'P':
OLC_MODE(d) = QEDIT_PREVQUEST;
write_to_output(d, "Enter vnum of previous quest (-1 for none) : ");
break;
default:
write_to_output(d, "Invalid choice!\r\n");
qedit_disp_menu(d);
break;
}
return;
/*-------------------------------------------------------------------*/
case QEDIT_NAME:
if (!genolc_checkstring(d, arg))
break;
if (OLC_QUEST(d)->name)
free(OLC_QUEST(d)->name);
arg[MAX_QUEST_NAME - 1] = '\0';
OLC_QUEST(d)->name = str_udup(arg);
break;
case QEDIT_DESC:
if (!genolc_checkstring(d, arg))
break;
if (OLC_QUEST(d)->desc)
free(OLC_QUEST(d)->desc);
arg[MAX_QUEST_DESC - 1] = '\0';
OLC_QUEST(d)->desc = str_udup(arg);
break;
case QEDIT_QUESTMASTER:
if (number != -1)
if ((number = real_mobile(number)) == NOBODY) {
write_to_output(d, "That mobile does not exist, try again : ");
return;
}
OLC_QUEST(d)->qm = number;
break;
case QEDIT_TYPES:
if (number < 0 || number >= NUM_AQ_TYPES) {
write_to_output(d, "Invalid choice!\r\n");
qedit_disp_type_menu(d);
return;
}
OLC_QUEST(d)->type = number;
if (number == AQ_OBJ_RETURN) {
OLC_MODE(d) = QEDIT_RETURNMOB;
write_to_output(d, "Enter mob vnum to return object to : ");
return;
}
break;
case QEDIT_FLAGS:
if (number < 0 || number > NUM_AQ_FLAGS) {
write_to_output(d, "That is not a valid choice!\r\n");
qedit_disp_flag_menu(d);
} else if (number == 0)
break;
else {
TOGGLE_BIT(OLC_QUEST(d)->flags, number );
qedit_disp_flag_menu(d);
}
return;
case QEDIT_QUANTITY:
OLC_QUEST(d)->value[6] = LIMIT(number, 1, 50);
break;
case QEDIT_POINTSCOMP:
OLC_QUEST(d)->value[0] = LIMIT(number, 0, 999999);
break;
case QEDIT_POINTSQUIT:
OLC_QUEST(d)->value[1] = LIMIT(number, 0, 999999);
break;
case QEDIT_PREREQ:
if ((number = atoi(arg)) != -1)
if (real_object(number) == NOTHING) {
write_to_output(d, "That object does not exist, try again : ");
return;
}
OLC_QUEST(d)->prereq = number;
break;
case QEDIT_LEVELMIN:
if (number < 0 || number > LVL_IMPL) {
write_to_output(d, "Level must be between 0 and %d!\r\n", LVL_IMPL);
write_to_output(d, "Enter minimum level to accept the quest : " );
return;
} else if (number > OLC_QUEST(d)->value[3]) {
write_to_output(d, "Minimum level can't be above maximum level!\r\n");
write_to_output(d, "Enter minimum level to accept the quest : " );
return;
} else {
OLC_QUEST(d)->value[2] = number;
break;
}
case QEDIT_LEVELMAX:
if (number < 0 || number > LVL_IMPL) {
write_to_output(d, "Level must be between 0 and %d!\r\n", LVL_IMPL);
write_to_output(d, "Enter maximum level to accept the quest : " );
return;
} else if (number < OLC_QUEST(d)->value[2]) {
write_to_output(d, "Maximum level can't be below minimum level!\r\n");
write_to_output(d, "Enter maximum level to accept the quest : " );
return;
} else {
OLC_QUEST(d)->value[3] = number;
break;
}
case QEDIT_TIMELIMIT:
OLC_QUEST(d)->value[4] = LIMIT(number, -1, 100);
break;
case QEDIT_RETURNMOB:
if ((number = atoi(arg)) != -1)
if (real_mobile(number) == NOBODY) {
write_to_output(d, "That mobile does not exist, try again : ");
return;
}
OLC_QUEST(d)->value[5] = number;
break;
case QEDIT_TARGET:
OLC_QUEST(d)->target = number;
break;
case QEDIT_NEXTQUEST:
OLC_QUEST(d)->next_quest = (number == -1 ? NOTHING : atoi(arg));
break;
case QEDIT_PREVQUEST:
OLC_QUEST(d)->prev_quest = (number == -1 ? NOTHING : atoi(arg));
break;
case QEDIT_GOLD:
OLC_QUEST(d)->gold_reward = LIMIT(number, 0, 99999);
break;
case QEDIT_EXP:
OLC_QUEST(d)->exp_reward = LIMIT(number, 0, 99999);
break;
case QEDIT_OBJ:
if ((number = atoi(arg)) != -1)
if (real_object(number) == NOTHING) {
write_to_output(d, "That object does not exist, try again : ");
return;
}
OLC_QUEST(d)->obj_reward = number;
break;
default:
/*. We should never get here . */
cleanup_olc(d, CLEANUP_ALL);
mudlog(BRF, LVL_BUILDER, TRUE, "SYSERR: OLC: qedit_parse(): "
"Reached default case!");
write_to_output(d, "Oops...\r\n");
break;
}
/*-------------------------------------------------------------------*/
/*. END OF CASE
If we get here, we have probably changed something, and now want to
return to main menu. Use OLC_VAL as a 'has changed' flag . */
OLC_VAL(d) = 1;
qedit_disp_menu(d);
}
void qedit_string_cleanup(struct descriptor_data *d, int terminator)
{
switch (OLC_MODE(d)) {
case QEDIT_INFO:
case QEDIT_COMPLETE:
case QEDIT_ABANDON:
qedit_disp_menu(d);
break;
}
}

805
src/quest.c Normal file
View file

@ -0,0 +1,805 @@
/* ***********************************************************************
* File: quest.c Part of CircleMUD *
* Version: 2.1 (December 2005) Written for CircleMud CWG / Suntzu *
* Purpose: To provide special quest-related code. *
* Copyright: Kenneth Ray *
* Original Version Details: *
* Morgaelin - quest.c *
* Copyright (C) 1997 MS *
*********************************************************************** */
#define __QUEST_C__
#include "conf.h"
#include "sysdep.h"
#include "structs.h"
#include "utils.h"
#include "interpreter.h"
#include "handler.h"
#include "db.h"
#include "comm.h"
#include "screen.h"
#include "quest.h"
#include "act.h" /* for do_tell */
/*--------------------------------------------------------------------------
* Exported global variables
*--------------------------------------------------------------------------*/
const char *quest_types[] = {
"Object",
"Room",
"Find mob",
"Kill mob",
"Save mob",
"Return object",
"Clear room",
"\n"
};
const char *aq_flags[] = {
"REPEATABLE",
"\n"
};
/*--------------------------------------------------------------------------
* Local (file scope) global variables
*--------------------------------------------------------------------------*/
static int cmd_tell;
static const char *quest_cmd[] = {
"list", "history", "join", "leave", "progress", "status", "\n"};
static const char *quest_mort_usage =
"Usage: quest list | history | progress | join <nn> | leave";
static const char *quest_imm_usage =
"Usage: quest list | history | progress | join <nn> | leave | status <vnum>";
/*--------------------------------------------------------------------------*/
/* Utility Functions */
/*--------------------------------------------------------------------------*/
qst_rnum real_quest(qst_vnum vnum)
{
int rnum;
for (rnum = 0; rnum < total_quests; rnum++)
if (QST_NUM(rnum) == vnum)
return(rnum);
return(NOTHING);
}
int is_complete(struct char_data *ch, qst_vnum vnum)
{
int i;
for (i = 0; i < GET_NUM_QUESTS(ch); i++)
if (ch->player_specials->saved.completed_quests[i] == vnum)
return TRUE;
return FALSE;
}
qst_vnum find_quest_by_qmnum(struct char_data *ch, mob_rnum qm, int num)
{
qst_rnum rnum;
int found=0;
for (rnum = 0; rnum < total_quests; rnum++) {
if (qm == QST_MASTER(rnum))
if (++found == num)
return (QST_NUM(rnum));
}
return NOTHING;
}
/*--------------------------------------------------------------------------*/
/* Quest Loading and Unloading Functions */
/*--------------------------------------------------------------------------*/
void destroy_quests(void)
{
qst_rnum rnum = 0;
if (!aquest_table)
return;
for (rnum = 0; rnum < total_quests; rnum++){
free_quest_strings(&aquest_table[rnum]);
}
free(aquest_table);
aquest_table = NULL;
total_quests = 0;
return;
}
int count_quests(qst_vnum low, qst_vnum high)
{
int i, j;
for (i = j = 0; QST_NUM(i) <= high; i++)
if (QST_NUM(i) >= low)
j++;
return j;
}
void parse_quest(FILE *quest_f, int nr)
{
static char line[256];
static int i = 0, j;
int retval = 0, t[7];
char f1[128], buf2[MAX_STRING_LENGTH];
aquest_table[i].vnum = nr;
aquest_table[i].qm = NOBODY;
aquest_table[i].name = NULL;
aquest_table[i].desc = NULL;
aquest_table[i].info = NULL;
aquest_table[i].done = NULL;
aquest_table[i].quit = NULL;
aquest_table[i].flags = 0;
aquest_table[i].type = -1;
aquest_table[i].target = -1;
aquest_table[i].prereq = NOTHING;
for (j = 0; j < 7; j++)
aquest_table[i].value[j] = 0;
aquest_table[i].prev_quest = NOTHING;
aquest_table[i].next_quest = NOTHING;
aquest_table[i].func = NULL;
aquest_table[i].gold_reward = 0;
aquest_table[i].exp_reward = 0;
aquest_table[i].obj_reward = NOTHING;
/* begin to parse the data */
aquest_table[i].name = fread_string(quest_f, buf2);
aquest_table[i].desc = fread_string(quest_f, buf2);
aquest_table[i].info = fread_string(quest_f, buf2);
aquest_table[i].done = fread_string(quest_f, buf2);
aquest_table[i].quit = fread_string(quest_f, buf2);
if (!get_line(quest_f, line) ||
(retval = sscanf(line, " %d %d %s %d %d %d %d",
t, t+1, f1, t+2, t+3, t + 4, t + 5)) != 7) {
log("Format error in numeric line (expected 7, got %d), %s\n",
retval, line);
exit(1);
}
aquest_table[i].type = t[0];
aquest_table[i].qm = real_mobile(t[1]);
aquest_table[i].flags = asciiflag_conv(f1);
aquest_table[i].target = (t[2] == -1) ? NOTHING : t[2];
aquest_table[i].prev_quest = (t[3] == -1) ? NOTHING : t[3];
aquest_table[i].next_quest = (t[4] == -1) ? NOTHING : t[4];
aquest_table[i].prereq = (t[5] == -1) ? NOTHING : t[5];
if (!get_line(quest_f, line) ||
(retval = sscanf(line, " %d %d %d %d %d %d %d",
t, t+1, t+2, t+3, t+4, t + 5, t + 6)) != 7) {
log("Format error in numeric line (expected 7, got %d), %s\n",
retval, line);
exit(1);
}
for (j = 0; j < 7; j++)
aquest_table[i].value[j] = t[j];
if (!get_line(quest_f, line) ||
(retval = sscanf(line, " %d %d %d",
t, t+1, t+2)) != 3) {
log("Format error in numeric (rewards) line (expected 3, got %d), %s\n",
retval, line);
exit(1);
}
aquest_table[i].gold_reward = t[0];
aquest_table[i].exp_reward = t[1];
aquest_table[i].obj_reward = (t[2] == -1) ? NOTHING : t[2];
for (;;) {
if (!get_line(quest_f, line)) {
log("Format error in %s\n", line);
exit(1);
}
switch(*line) {
case 'S':
total_quests = ++i;
return;
break;
}
}
} /* parse_quest */
void assign_the_quests(void)
{
qst_rnum rnum;
cmd_tell = find_command("tell");
for (rnum = 0; rnum < total_quests; rnum ++) {
if (QST_MASTER(rnum) == NOBODY) {
log("SYSERR: Quest #%d has no questmaster specified.", QST_NUM(rnum));
continue;
}
if (mob_index[QST_MASTER(rnum)].func &&
mob_index[QST_MASTER(rnum)].func != questmaster)
QST_FUNC(rnum) = mob_index[QST_MASTER(rnum)].func;
mob_index[QST_MASTER(rnum)].func = questmaster;
}
}
/*--------------------------------------------------------------------------*/
/* Quest Completion Functions */
/*--------------------------------------------------------------------------*/
void set_quest(struct char_data *ch, qst_rnum rnum)
{
GET_QUEST(ch) = QST_NUM(rnum);
GET_QUEST_TIME(ch) = QST_TIME(rnum);
GET_QUEST_COUNTER(ch) = QST_QUANTITY(rnum);
SET_BIT_AR(PRF_FLAGS(ch), PRF_QUEST);
return;
}
void clear_quest(struct char_data *ch)
{
GET_QUEST(ch) = NOTHING;
GET_QUEST_TIME(ch) = -1;
GET_QUEST_COUNTER(ch) = 0;
REMOVE_BIT_AR(PRF_FLAGS(ch), PRF_QUEST);
return;
}
void add_completed_quest(struct char_data *ch, qst_vnum vnum)
{
qst_vnum *temp;
int i;
CREATE(temp, qst_vnum, GET_NUM_QUESTS(ch) +1);
for (i=0; i < GET_NUM_QUESTS(ch); i++)
temp[i] = ch->player_specials->saved.completed_quests[i];
temp[GET_NUM_QUESTS(ch)] = vnum;
GET_NUM_QUESTS(ch)++;
if (ch->player_specials->saved.completed_quests)
free(ch->player_specials->saved.completed_quests);
ch->player_specials->saved.completed_quests = temp;
}
void remove_completed_quest(struct char_data *ch, qst_vnum vnum)
{
qst_vnum *temp;
int i, j = 0;
CREATE(temp, qst_vnum, GET_NUM_QUESTS(ch));
for (i = 0; i < GET_NUM_QUESTS(ch); i++)
if (ch->player_specials->saved.completed_quests[i] != vnum)
temp[j++] = ch->player_specials->saved.completed_quests[i];
GET_NUM_QUESTS(ch)--;
if (ch->player_specials->saved.completed_quests)
free(ch->player_specials->saved.completed_quests);
ch->player_specials->saved.completed_quests = temp;
}
void generic_complete_quest(struct char_data *ch)
{
qst_rnum rnum;
qst_vnum vnum = GET_QUEST(ch);
struct obj_data *new_obj;
if (--GET_QUEST_COUNTER(ch) <= 0) {
rnum = real_quest(vnum);
GET_QUESTPOINTS(ch) += QST_POINTS(rnum);
send_to_char(ch,
"%s\r\nYou have been awarded %d quest points for your service.\r\n",
QST_DONE(rnum), QST_POINTS(rnum));
if (QST_GOLD(rnum)) {
GET_GOLD(ch) += QST_GOLD(rnum);
send_to_char(ch,
"You have been awarded %d gold coins for your service.\r\n",
QST_GOLD(rnum));
}
if (QST_EXP(rnum)) {
gain_exp(ch, QST_GOLD(rnum));
send_to_char(ch,
"You have been awarded %d experience points for your service.\r\n",
QST_EXP(rnum));
}
if (QST_OBJ(rnum)) {
if (real_object(QST_OBJ(rnum))) {
if ((new_obj = create_obj()) != NULL) {
new_obj = read_object((QST_OBJ(rnum)),VIRTUAL);
obj_to_char(new_obj, ch);
send_to_char(ch,
"You have been presented with %s%s for your service.\r\n",
GET_OBJ_SHORT(new_obj), CCNRM(ch, C_NRM));
}
}
}
if (!IS_SET(QST_FLAGS(rnum), AQ_REPEATABLE))
add_completed_quest(ch, vnum);
clear_quest(ch);
if ((real_quest(QST_NEXT(rnum)) != NOTHING) &&
(QST_NEXT(rnum) != vnum) &&
!is_complete(ch, QST_NEXT(rnum))) {
rnum = real_quest(QST_NEXT(rnum));
set_quest(ch, rnum);
send_to_char(ch,
"The next stage of your quest awaits:\r\n%s",
QST_INFO(rnum));
}
}
save_char(ch);
}
void autoquest_trigger_check(struct char_data *ch, struct char_data *vict,
struct obj_data *object, int type)
{
struct char_data *i;
qst_rnum rnum;
int found = TRUE;
if (IS_NPC(ch))
return;
if (GET_QUEST(ch) == NOTHING) /* No current quest, skip this */
return;
if (GET_QUEST_TYPE(ch) != type)
return;
if ((rnum = real_quest(GET_QUEST(ch))) == NOTHING)
return;
switch (type) {
case AQ_OBJ_FIND:
if (QST_TARGET(rnum) == GET_OBJ_VNUM(object))
generic_complete_quest(ch);
break;
case AQ_ROOM_FIND:
if (QST_TARGET(rnum) == world[IN_ROOM(ch)].number)
generic_complete_quest(ch);
break;
case AQ_MOB_FIND:
for (i=world[IN_ROOM(ch)].people; i; i = i->next_in_room)
if (IS_NPC(i))
if (QST_TARGET(rnum) == GET_MOB_VNUM(i))
generic_complete_quest(ch);
break;
case AQ_MOB_KILL:
if (!IS_NPC(ch) && IS_NPC(vict) && (ch != vict))
if (QST_TARGET(rnum) == GET_MOB_VNUM(vict))
generic_complete_quest(ch);
break;
case AQ_MOB_SAVE:
if (ch == vict)
found = FALSE;
for (i = world[IN_ROOM(ch)].people; i && found; i = i->next_in_room)
if (i && IS_NPC(i) && !MOB_FLAGGED(i, MOB_NOTDEADYET))
if ((GET_MOB_VNUM(i) != QST_TARGET(rnum)) &&
!AFF_FLAGGED(i, AFF_CHARM))
found = FALSE;
if (found)
generic_complete_quest(ch);
break;
case AQ_OBJ_RETURN:
if (IS_NPC(vict) && (GET_MOB_VNUM(vict) == QST_RETURNMOB(rnum)))
if (object && (GET_OBJ_VNUM(object) == QST_TARGET(rnum)))
generic_complete_quest(ch);
break;
case AQ_ROOM_CLEAR:
if (QST_TARGET(rnum) == world[IN_ROOM(ch)].number) {
for (i = world[IN_ROOM(ch)].people; i && found; i = i->next_in_room)
if (i && IS_NPC(i) && !MOB_FLAGGED(i, MOB_NOTDEADYET))
found = FALSE;
if (found)
generic_complete_quest(ch);
}
break;
default:
log("SYSERR: Invalid quest type passed to autoquest_trigger_check");
break;
}
}
void quest_timeout(struct char_data *ch)
{
if ((GET_QUEST(ch) != NOTHING) && (GET_QUEST_TIME(ch) != -1)) {
clear_quest(ch);
send_to_char(ch, "You have run out of time to complete the quest.\r\n");
}
}
void check_timed_quests(void)
{
struct char_data *ch;
for (ch = character_list; ch; ch = ch->next)
if (!IS_NPC(ch) && (GET_QUEST(ch) != NOTHING) && (GET_QUEST_TIME(ch) != -1))
if (--GET_QUEST_TIME(ch) == 0)
quest_timeout(ch);
}
/*--------------------------------------------------------------------------*/
/* Quest Command Helper Functions */
/*--------------------------------------------------------------------------*/
void list_quests(struct char_data *ch, zone_rnum zone, qst_vnum vmin, qst_vnum vmax)
{
qst_rnum rnum;
qst_vnum bottom, top;
int counter = 0;
if (zone != NOWHERE) {
bottom = zone_table[zone].bot;
top = zone_table[zone].top;
} else {
bottom = vmin;
top = vmax;
}
/* Print the header for the quest listing. */
send_to_char (ch,
"Index VNum Description Questmaster\r\n"
"----- ------- -------------------------------------------- -----------\r\n");
for (rnum = 0; rnum < total_quests ; rnum++)
if (QST_NUM(rnum) >= bottom && QST_NUM(rnum) <= top)
send_to_char(ch, "@g%4d@n) [@g%-5d@n] @c%-44.44s@n @y[%5d]@n\r\n",
++counter,
QST_NUM(rnum), QST_NAME(rnum),
mob_index[QST_MASTER(rnum)].vnum);
if (!counter)
send_to_char(ch, "None found.\r\n");
}
void quest_hist(struct char_data *ch)
{
int i = 0, counter = 0;
qst_rnum rnum = NOTHING;
send_to_char(ch, "Quests that you have completed:\r\n"
"Index Description Questmaster\r\n"
"----- ---------------------------------------------------- -----------\r\n");
for (i = 0; i < GET_NUM_QUESTS(ch); i++) {
if ((rnum = real_quest(ch->player_specials->saved.completed_quests[i])) != NOTHING)
send_to_char(ch, "@g%4d@n) @c%-52.52s@n @y%s@n\r\n",
++counter, QST_DESC(rnum), GET_NAME(&mob_proto[QST_MASTER(rnum)]));
else
send_to_char(ch,
"@g%4d@n) @cUnknown Quest (it no longer exists)@n\r\n", ++counter);
}
if (!counter)
send_to_char(ch, "You haven't completed any quests yet.\r\n");
}
void quest_join(struct char_data *ch, struct char_data *qm, char argument[MAX_INPUT_LENGTH])
{
qst_vnum vnum;
qst_rnum rnum;
char buf[MAX_INPUT_LENGTH];
if (!*argument)
snprintf(buf, sizeof(buf),
"%s What quest did you wish to join?", GET_NAME(ch));
else if (GET_QUEST(ch) != NOTHING)
snprintf(buf, sizeof(buf),
"%s But you are already part of a quest!", GET_NAME(ch));
else if((vnum = find_quest_by_qmnum(ch, qm->nr, atoi(argument))) == NOTHING)
snprintf(buf, sizeof(buf),
"%s I don't know of such a quest!", GET_NAME(ch));
else if ((rnum = real_quest(vnum)) == NOTHING)
snprintf(buf, sizeof(buf),
"%s I don't know of such a quest!", GET_NAME(ch));
else if (GET_LEVEL(ch) < QST_MINLEVEL(rnum))
snprintf(buf, sizeof(buf),
"%s You are not experienced enough for that quest!", GET_NAME(ch));
else if (GET_LEVEL(ch) > QST_MAXLEVEL(rnum))
snprintf(buf, sizeof(buf),
"%s You are too experienced for that quest!", GET_NAME(ch));
else if (is_complete(ch, vnum))
snprintf(buf, sizeof(buf),
"%s You have already completed that quest!", GET_NAME(ch));
else if ((QST_PREV(rnum) != NOTHING) && !is_complete(ch, vnum))
snprintf(buf, sizeof(buf),
"%s That quest is not available to you yet!", GET_NAME(ch));
else if ((QST_PREREQ(rnum) != NOTHING) &&
(real_object(QST_PREREQ(rnum)) != NOTHING) &&
(get_obj_in_list_num(real_object(QST_PREREQ(rnum)),
ch->carrying) == NULL))
snprintf(buf, sizeof(buf),
"%s You need to have %s first!", GET_NAME(ch),
obj_proto[real_object(QST_PREREQ(rnum))].short_description);
else {
act("You join the quest.", TRUE, ch, NULL, NULL, TO_CHAR);
act("$n has joined a quest.", TRUE, ch, NULL, NULL, TO_ROOM);
snprintf(buf, sizeof(buf),
"%s Listen carefully to the instructions.", GET_NAME(ch));
do_tell(qm, buf, cmd_tell, 0);
set_quest(ch, rnum);
send_to_char(ch, QST_INFO(rnum));
if (QST_TIME(rnum) != -1)
snprintf(buf, sizeof(buf),
"%s You have a time limit of %d turn%s to complete the quest.",
GET_NAME(ch), QST_TIME(rnum), QST_TIME(rnum) == 1 ? "" : "s");
else
snprintf(buf, sizeof(buf),
"%s You can take however long you want to complete the quest.",
GET_NAME(ch));
}
do_tell(qm, buf, cmd_tell, 0);
save_char(ch);
}
void quest_list(struct char_data *ch, struct char_data *qm, char argument[MAX_INPUT_LENGTH])
{
qst_vnum vnum;
qst_rnum rnum;
if ((vnum = find_quest_by_qmnum(ch, qm->nr, atoi(argument))) == NOTHING)
send_to_char(ch, "That is not a valid quest!\r\n");
else if ((rnum = real_quest(vnum)) == NOTHING)
send_to_char(ch, "That is not a valid quest!\r\n");
else if (QST_INFO(rnum)) {
send_to_char(ch,"Complete Details on Quest %d @c%s@n:\r\n%s",
vnum,
QST_DESC(rnum),
QST_INFO(rnum));
if (QST_PREV(rnum) != NOTHING)
send_to_char(ch, "You have to have completed quest %s first.\r\n",
QST_NAME(real_quest(QST_PREV(rnum))));
if (QST_TIME(rnum) != -1)
send_to_char(ch,
"There is a time limit of %d turn%s to complete the quest.\r\n",
QST_TIME(rnum),
QST_TIME(rnum) == 1 ? "" : "s");
} else
send_to_char(ch, "There is no further information on that quest.\r\n");
}
void quest_quit(struct char_data *ch)
{
qst_rnum rnum;
if (GET_QUEST(ch) == NOTHING)
send_to_char(ch, "But you currently aren't on a quest!\r\n");
else if ((rnum = real_quest(GET_QUEST(ch))) == NOTHING) {
clear_quest(ch);
send_to_char(ch, "You are now no longer part of the quest.\r\n");
save_char(ch);
} else {
clear_quest(ch);
if (QST_QUIT(rnum) && (str_cmp(QST_QUIT(rnum), "undefined") != 0))
send_to_char(ch, "%s", QST_QUIT(rnum));
else
send_to_char(ch, "You are now no longer part of the quest.\r\n");
if (QST_PENALTY(rnum)) {
GET_QUESTPOINTS(ch) -= QST_PENALTY(rnum);
send_to_char(ch,
"You have lost %d quest points for your cowardice.\r\n",
QST_PENALTY(rnum));
}
save_char(ch);
}
}
void quest_progress(struct char_data *ch)
{
qst_rnum rnum;
if (GET_QUEST(ch) == NOTHING)
send_to_char(ch, "But you currently aren't on a quest!\r\n");
else if ((rnum = real_quest(GET_QUEST(ch))) == NOTHING) {
clear_quest(ch);
send_to_char(ch, "Your quest seems to no longer exist.\r\n");
} else {
send_to_char(ch, "You are on the following quest:\r\n%s\r\n%s",
QST_DESC(rnum), QST_INFO(rnum));
if (QST_QUANTITY(rnum) > 1)
send_to_char(ch,
"You still have to achieve %d out of %d goals for the quest.\r\n",
GET_QUEST_COUNTER(ch), QST_QUANTITY(rnum));
if (GET_QUEST_TIME(ch) > 0)
send_to_char(ch,
"You have %d turn%s remaining to complete the quest.\r\n",
GET_QUEST_TIME(ch),
GET_QUEST_TIME(ch) == 1 ? "" : "s");
}
}
void quest_show(struct char_data *ch, mob_rnum qm)
{
qst_rnum rnum;
int counter = 0;
send_to_char(ch,
"The following quests are available:\r\n"
"Index Description ( Vnum) Done?\r\n"
"----- ---------------------------------------------------- ------- -----\r\n");
for (rnum = 0; rnum < total_quests; rnum++)
if (qm == QST_MASTER(rnum))
send_to_char(ch, "@g%4d@n) @c%-52.52s@n @y(%5d)@n @y(%s)@n\r\n",
++counter, QST_DESC(rnum), QST_NUM(rnum),
(is_complete(ch, QST_NUM(rnum)) ? "Yes" : "No "));
if (!counter)
send_to_char(ch, "There are no quests available here at the moment.\r\n");
}
void quest_stat(struct char_data *ch, char argument[MAX_STRING_LENGTH])
{
qst_rnum rnum;
char buf[MAX_STRING_LENGTH];
char targetname[MAX_STRING_LENGTH];
if (GET_LEVEL(ch) < LVL_IMMORT)
send_to_char(ch, "Huh!?!\r\n");
else if (!*argument)
send_to_char(ch, "%s\r\n", quest_imm_usage);
else if ((rnum = real_quest(atoi(argument))) == NOTHING )
send_to_char(ch, "That quest does not exist.\r\n");
else {
sprintbit(QST_FLAGS(rnum), aq_flags, buf, sizeof(buf));
switch (QST_TYPE(rnum)) {
case AQ_OBJ_FIND:
case AQ_OBJ_RETURN:
snprintf(targetname, sizeof(targetname), "%s",
real_object(QST_TARGET(rnum)) == NOTHING ?
"An unknown object" :
obj_proto[real_object(QST_TARGET(rnum))].short_description);
break;
case AQ_ROOM_FIND:
case AQ_ROOM_CLEAR:
snprintf(targetname, sizeof(targetname), "%s",
real_room(QST_TARGET(rnum)) == NOWHERE ?
"An unknown room" :
world[real_room(QST_TARGET(rnum))].name);
break;
case AQ_MOB_FIND:
case AQ_MOB_KILL:
case AQ_MOB_SAVE:
snprintf(targetname, sizeof(targetname), "%s",
real_mobile(QST_TARGET(rnum)) == NOBODY ?
"An unknown mobile" :
GET_NAME(&mob_proto[real_mobile(QST_TARGET(rnum))]));
break;
default:
snprintf(targetname, sizeof(targetname), "Unknown");
break;
}
send_to_char(ch,
"VNum : [@y%5d@n], RNum: [@y%5d@n] -- Questmaster: [@y%5d@n] @y%s@n\r\n"
"Name : @y%s@n\r\n"
"Desc : @y%s@n\r\n"
"Accept Message:\r\n@c%s@n"
"Completion Message:\r\n@c%s@n"
"Quit Message:\r\n@c%s@n"
"Type : @y%s@n\r\n"
"Target: @y%d@n @y%s@n, Quantity: @y%d@n\r\n"
"Value : @y%d@n, Penalty: @y%d@n, Min Level: @y%2d@n, Max Level: @y%2d@n\r\n"
"Flags : @c%s@n\r\n",
QST_NUM(rnum), rnum,
QST_MASTER(rnum) == NOBODY ? -1 : mob_index[QST_MASTER(rnum)].vnum,
QST_MASTER(rnum) == NOBODY ? "" : GET_NAME(&mob_proto[QST_MASTER(rnum)]),
QST_NAME(rnum), QST_DESC(rnum),
QST_INFO(rnum), QST_DONE(rnum),
(QST_QUIT(rnum) &&
(str_cmp(QST_QUIT(rnum), "undefined") != 0)
? QST_QUIT(rnum) : "Nothing\r\n"),
quest_types[QST_TYPE(rnum)],
QST_TARGET(rnum) == NOBODY ? -1 : QST_TARGET(rnum),
targetname,
QST_QUANTITY(rnum),
QST_POINTS(rnum), QST_PENALTY(rnum), QST_MINLEVEL(rnum),
QST_MAXLEVEL(rnum), buf);
if (QST_PREREQ(rnum) != NOTHING)
send_to_char(ch, "Preq : [@y%5d@n] @y%s@n\r\n",
QST_PREREQ(rnum) == NOTHING ? -1 : QST_PREREQ(rnum),
QST_PREREQ(rnum) == NOTHING ? "" :
real_object(QST_PREREQ(rnum)) == NOTHING ? "an unknown object" :
obj_proto[real_object(QST_PREREQ(rnum))].short_description);
if (QST_TYPE(rnum) == AQ_OBJ_RETURN)
send_to_char(ch, "Mob : [@y%5d@n] @y%s@n\r\n",
QST_RETURNMOB(rnum),
real_mobile(QST_RETURNMOB(rnum)) == NOBODY ? "an unknown mob" :
mob_proto[real_mobile(QST_RETURNMOB(rnum))].player.short_descr);
if (QST_TIME(rnum) != -1)
send_to_char(ch, "Limit : There is a time limit of %d turn%s to complete.\r\n",
QST_TIME(rnum),
QST_TIME(rnum) == 1 ? "" : "s");
else
send_to_char(ch, "Limit : There is no time limit on this quest.\r\n");
send_to_char(ch, "Prior :");
if (QST_PREV(rnum) == NOTHING)
send_to_char(ch, " @yNone.@n\r\n");
else
send_to_char(ch, " [@y%5d@n] @c%s@n\r\n",
QST_PREV(rnum), QST_DESC(real_quest(QST_PREV(rnum))));
send_to_char(ch, "Next :");
if (QST_NEXT(rnum) == NOTHING)
send_to_char(ch, " @yNone.@n\r\n");
else
send_to_char(ch, " [@y%5d@n] @c%s@n\r\n",
QST_NEXT(rnum), QST_DESC(real_quest(QST_NEXT(rnum))));
}
}
/*--------------------------------------------------------------------------*/
/* Quest Command Processing Function and Questmaster Special */
/*--------------------------------------------------------------------------*/
ACMD(do_quest)
{
char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH];
int tp;
two_arguments(argument, arg1, arg2);
if (!*arg1)
send_to_char(ch, "%s\r\n", GET_LEVEL(ch) < LVL_IMMORT ?
quest_mort_usage : quest_imm_usage);
else if (((tp = search_block(arg1, quest_cmd, FALSE)) == -1))
send_to_char(ch, "%s\r\n", GET_LEVEL(ch) < LVL_IMMORT ?
quest_mort_usage : quest_imm_usage);
else {
switch (tp) {
case SCMD_QUEST_LIST:
case SCMD_QUEST_JOIN:
/* list, join should hve been handled by questmaster spec proc */
send_to_char(ch, "Sorry, but you cannot do that here!\r\n");
break;
case SCMD_QUEST_HISTORY:
quest_hist(ch);
break;
case SCMD_QUEST_LEAVE:
quest_quit(ch);
break;
case SCMD_QUEST_PROGRESS:
quest_progress(ch);
break;
case SCMD_QUEST_STATUS:
if (GET_LEVEL(ch) < LVL_IMMORT)
send_to_char(ch, "%s\r\n", quest_mort_usage);
else
quest_stat(ch, arg2);
break;
default: /* Whe should never get here, but... */
send_to_char(ch, "%s\r\n", GET_LEVEL(ch) < LVL_IMMORT ?
quest_mort_usage : quest_imm_usage);
break;
} /* switch on subcmd number */
}
}
SPECIAL(questmaster)
{
qst_rnum rnum;
char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH];
int tp;
struct char_data *qm = (struct char_data *)me;
/* check that qm mob has quests assigned */
for (rnum = 0; (rnum < total_quests &&
QST_MASTER(rnum) != GET_MOB_RNUM(qm)) ; rnum ++);
if (rnum >= total_quests)
return FALSE; /* No quests for this mob */
else if (QST_FUNC(rnum) && (QST_FUNC(rnum) (ch, me, cmd, argument)))
return TRUE; /* The secondary spec proc handled this command */
else if (CMD_IS("quest")) {
two_arguments(argument, arg1, arg2);
if (!*arg1)
return FALSE;
else if (((tp = search_block(arg1, quest_cmd, FALSE)) == -1))
return FALSE;
else {
switch (tp) {
case SCMD_QUEST_LIST:
if (!*arg2)
quest_show(ch, GET_MOB_RNUM(qm));
else
quest_list(ch, qm, arg2);
break;
case SCMD_QUEST_JOIN:
quest_join(ch, qm, arg2);
break;
default:
return FALSE; /* fall through to the do_quest command processor */
} /* switch on subcmd number */
return TRUE;
}
} else {
return FALSE; /* not a questmaster command */
}
}