/**************************************************************************
* # # # ## # # ### ## ## ### http://www.lyonesse.it *
* # # # # # ## # # # # # *
* # # # # # ## ## # # ## ## ## # # ## *
* # # # # # ## # # # # # # # # # # # *
* ### # ## # # ### ## ## ### # # #### ## Ver. 1.0 *
* *
* -Based on CircleMud & Smaug- Copyright (c) 2001-2002 by Mithrandir *
* *
* ********************************************************************** *
* *
* File: buildings.c *
* *
* Buildings code *
* *
**************************************************************************/
#include "conf.h"
#include "sysdep.h"
#include "structs.h"
#include "utils.h"
#include "comm.h"
#include "db.h"
#include "constants.h"
#include "screen.h"
#include "interpreter.h"
#include "handler.h"
#include "clan.h"
#if defined(KEY)
#undef KEY
#endif
#define KEY( literal, field, value ) \
if ( !strcmp( word, literal ) ) \
{ \
field = value; \
fMatch = TRUE; \
break; \
}
/* external functions */
SPECIAL(tradingpost);
ROOM_DATA *create_wild_room(COORD_DATA *coord, bool Static);
OBJ_DATA *fread_one_obj(FILE *fp, int *location);
TRADING_POST *find_trading_post(int vnum);
bitvector_t asciiflag_conv(char *flag);
int save_objs(OBJ_DATA *obj, FILE *fp, int mode, int location);
int sprintascii(char *out, bitvector_t bits);
void strip_cr(char *buffer);
void setup_trigger( ROOM_DATA *pRoom, FILE *fl );
/* globals */
BUILDING_TYPE *building_template[NUM_BUILDING_TYPE]; /* array of building templates */
BUILDING_DATA *building_list[BLD_HASH]; /* global hash table */
BLD_WORKS *first_build_work = NULL;
BLD_WORKS *last_build_work = NULL;
int num_of_bld_templ = 0;
int top_of_buildings = 0;
int last_works_num = 0;
bool building_loaded = FALSE;
/* local functions */
void SaveBuildings(void);
/* ================================================================= */
/* ***************************************************************** */
/* Code for Display Informations of a building */
/* ***************************************************************** */
/* display the condition of a building */
void show_building_cond(CHAR_DATA *ch, BUILDING_DATA *bld)
{
int stat, cond = percentage(bld->curr_val.health, bld->max_val.health);
const char *building_health_descr[] =
{
"is in perfect conditions", // 0
"looks normal", // 1
"is slightly damaged", // 2
"looks damaged", // 3
"is heavily damaged", // 4
"needs immediate repairings", // 5
"is almost ruined", // 6
"seems that could collapse at any time" // 7
};
if (cond < 5) stat = 7;
else if (cond < 10) stat = 6;
else if (cond < 20) stat = 5;
else if (cond < 35) stat = 4;
else if (cond < 50) stat = 3;
else if (cond < 70) stat = 2;
else if (cond < 85) stat = 1;
else stat = 0;
ch_printf(ch, "%s %s (%d / %d).\r\n",
bld->description,
building_health_descr[stat], bld->curr_val.health, bld->max_val.health);
}
/* show a list of buildings in the room */
void list_building_to_char(BUILDING_DATA *bldlist, CHAR_DATA *ch)
{
BUILDING_DATA *bld, *blist[20];
int num = 0, counter, locate_list[20];
bool found;
if (!ch) return;
for (bld = bldlist; bld; bld = bld->next_in_room)
{
if (!bld->type || !bld->type->name || !bld->description)
continue;
if (num < 20)
{
found = FALSE;
for (counter = 0; counter < num && !found; counter++)
{
if (bld->type->vnum == blist[counter]->type->vnum &&
BUILDING_FLAGS(bld) == BUILDING_FLAGS(blist[counter]))
{
locate_list[counter]++;
found = TRUE;
}
}
if (!found)
{
blist[num] = bld;
locate_list[num] = 1;
num++;
}
}
else
ch_printf(ch, "You see %s.\r\n", bld->description);
}
if (num)
{
for (counter = 0; counter < num; counter++)
{
if (locate_list[counter] > 1)
ch_printf(ch, "You see %s (%d).\r\n", blist[counter]->description, locate_list[counter]);
else
ch_printf(ch, "You see %s.\r\n", blist[counter]->description);
}
}
if (ROOM_FLAGGED(ch->in_room, ROOM_BUILDING_WORKS))
send_to_char("There are building works here.\r\n", ch);
}
/* ================================================================= */
/* Code for handling chars in & out of a building */
/* ================================================================= */
/* place a char inside a building */
void char_to_building(CHAR_DATA *ch, BUILDING_DATA *bld, int room)
{
int room_num = room;
if (room_num < 0 || room_num >= bld->size)
room_num = bld->type->entrance;
ch->in_building = bld;
char_to_room(ch, bld->rooms[room_num]);
ch->next_in_building = bld->people;
bld->people = ch;
}
/* take out a char from the building he's inside */
void char_from_building(CHAR_DATA *ch)
{
CHAR_DATA *temp;
if (!ch || !ch->in_building)
return;
REMOVE_FROM_LIST(ch, ch->in_building->people, next_in_building);
ch->in_building = NULL;
ch->next_in_building = NULL;
}
/* ================================================================= */
/* Code for handling authorization */
/* ================================================================= */
/* search the authorized ppl array for the idnum */
AUTH_DATA *get_bld_auth(BUILDING_DATA *bld, long idnum)
{
AUTH_DATA *bAuth;
if (!bld || !bld->auth)
return (NULL);
for (bAuth = bld->auth; bAuth != NULL; bAuth = bAuth->next)
{
if (bAuth->id_num == idnum)
break;
}
return (bAuth);
}
/*
* if bCanAuthCheck is FALSE, check if char can enter the building
*
* if bCanAuthCheck is TRUE, check if char can toggle entrance authorization
* to other people
*
*/
bool can_enter_bld(CHAR_DATA *ch, BUILDING_DATA *bld, bool bCanAuthCheck)
{
if ( !ch || !bld )
return (FALSE);
if (IS_IMMORTAL(ch))
return (TRUE);
if (bld->can_enter == BLD_ENT_FREE)
{
if (bCanAuthCheck)
{
send_to_char("You don't need to set/revoke authorization for free entrance buildings.\r\n", ch);
return (FALSE);
}
return (TRUE);
}
/* owner of the building */
if (bld->owner_type == BLD_OWN_CHAR && GET_IDNUM(ch) == bld->owner_id)
return (TRUE);
/* member of the clan */
if (bld->owner_type == BLD_OWN_CLAN && GET_CLAN(ch) == bld->owner_id)
{
if (bCanAuthCheck)
{
// only privileged members can authorize to enter
if (GET_CLAN_RANK(ch) >= RANK_PRIVILEGES)
return (TRUE);
else
return (FALSE);
}
if (GET_CLAN_RANK(ch) < RANK_MEMBER_FIRST)
return (FALSE);
return (TRUE);
}
if (bCanAuthCheck)
return (FALSE);
/* ppl authorized to enter */
if (get_bld_auth(bld, GET_IDNUM(ch)))
return (TRUE);
return (FALSE);
}
/* entering a building.. called from do_enter in act.movement.c */
void enter_building(CHAR_DATA *ch, BUILDING_DATA *bld)
{
EXIT_DATA *pexit;
if (!ch || !bld)
return;
if (BUILDING_FLAGGED(bld, BLD_F_RUIN))
{
send_to_char("You cannot enter in a ruined building.\r\n", ch);
return;
}
// special case
if (bld->type->vnum != BLD_STABLE)
{
if (RIDING(ch))
{
send_to_char("You cannot enter a building while mounted.\r\n", ch );
return;
}
if (WAGONER(ch))
{
send_to_char("You cannot enter a building while driving a vehicle.\r\n", ch );
return;
}
}
if (!(pexit = get_exit(bld->rooms[bld->type->entrance], SOUTH)))
{
log( "SYSERR: enter_building() - cannot find entrance to building %d.", bld->vnum );
return;
}
if (EXIT_FLAGGED(pexit, EX_CLOSED))
{
if (pexit->keyword)
ch_printf(ch, "The %s is closed.\r\n", pexit->keyword );
else
send_to_char("It's closed.\r\n", ch );
return;
}
if (!can_enter_bld(ch, bld, FALSE))
{
ch_printf(ch, "You are not authorized to enter %s.\r\n", bld->description);
return;
}
act("You enter $b.\r\n", FALSE, ch, NULL, bld, TO_CHAR);
act("$n enters $b.", FALSE, ch, NULL, bld, TO_ROOM);
char_from_room(ch);
char_to_building(ch, bld, NOWHERE);
if (RIDING(ch))
{
char_from_room(RIDING(ch));
char_to_building(RIDING(ch), bld, NOWHERE);
}
act("$n enters.", FALSE, ch, NULL, NULL, TO_ROOM);
look_at_room(ch, TRUE);
}
/*
* give vict the authorization to enter bld
* or
* revoke to vict the authorization to enter bld
*/
void auth_enter(BUILDING_DATA *bld, CHAR_DATA *ch, CHAR_DATA *vict, int mode)
{
AUTH_DATA *bAuth;
if ( !bld || !vict )
return;
if (bld->can_enter == BLD_ENT_FREE)
{
send_to_char("You don't need to set/revoke authorization for free entrance buildings.\r\n", ch);
return;
}
/* authorize */
if (mode == 1)
{
if (get_bld_auth(bld, GET_IDNUM(vict)))
{
ch_printf(ch, "%s is already authorized to enter.\r\n", PERS(vict, ch));
return;
}
CREATE(bAuth, AUTH_DATA, 1);
bAuth->id_num = GET_IDNUM(vict);
bAuth->name = str_dup(GET_NAME(vict));
// add to the list
bAuth->next = bld->auth;
bld->auth = bAuth;
ch_printf(ch, "%s is now authorized to enter %s.\r\n",
PERS(vict, ch), bld->description);
act("You are now authorized to enter $b.", FALSE, vict, NULL, bld, TO_CHAR);
}
/* revoke authorization */
else
{
AUTH_DATA *temp;
if (!(bAuth = get_bld_auth(bld, GET_IDNUM(vict))))
{
ch_printf(ch, "%s is already not authorized to enter.\r\n", PERS(vict, ch));
return;
}
if (vict->in_building && vict->in_building->vnum == bld->vnum)
{
send_to_char("You cannot revoke authorization to someone that's currently inside.\r\n", ch);
return;
}
REMOVE_FROM_LIST(bAuth, bld->auth, next);
STRFREE(bAuth->name);
DISPOSE(bAuth);
ch_printf(ch, "%s now is not authorized to enter %s.\r\n",
PERS(vict, ch), bld->description);
act("You no longer can enter $b.", FALSE, vict, NULL, bld, TO_CHAR);
}
}
/* ================================================================= */
/* Code for finding buildings, buildings rooms, buildings doors, etc */
/* ================================================================= */
/* find a building in the entire world, by vnum */
BUILDING_DATA *find_building(int vnum)
{
BUILDING_DATA *bld;
int iHash;
if (vnum < 0)
return (NULL);
iHash = vnum % BLD_HASH;
for (bld = building_list[iHash]; bld; bld = bld->next)
{
if (bld->vnum == vnum)
break;
}
return (bld);
}
/* find a building in the given room, by building name */
BUILDING_DATA *find_building_in_room_by_name(ROOM_DATA *pRoom, char *arg)
{
BUILDING_DATA *bld = NULL;
int fnum = 1;
if (!pRoom || !pRoom->buildings || !*arg)
return (NULL);
if (!(fnum = get_number(&arg)))
return (NULL);
for (bld = pRoom->buildings; bld; bld = bld->next_in_room)
{
if (bld->keyword)
if (isname(arg, bld->keyword))
if (--fnum == 0)
break;
}
return (bld);
}
/* find the first building owned by char in char room */
BUILDING_DATA *find_char_owned_building(CHAR_DATA *ch)
{
BUILDING_DATA *bld;
if (!ch || !ch->in_room || !ch->in_room->buildings)
return (NULL);
for (bld = ch->in_room->buildings; bld; bld = bld->next_in_room)
{
if (bld->owner_type == BLD_OWN_CHAR)
if (bld->owner_id == GET_IDNUM(ch))
break;
}
return (bld);
}
/* find a room inside a building */
ROOM_DATA *find_room_building(BUILDING_DATA *bld, int room)
{
if (room < 0 || room > bld->size)
return (NULL);
if (BUILDING_FLAGGED(bld, BLD_F_RUIN))
return (NULL);
return (bld->rooms[room]);
}
/* find the room that has the entrance/exit from the building */
EXIT_DATA *find_building_door(CHAR_DATA *ch, char *doorname, char *building)
{
BUILDING_DATA *bld;
EXIT_DATA *pexit;
if (!ch || !ch->in_room->buildings)
return (NULL);
if (!(bld = find_building_in_room_by_name(ch->in_room, building)))
return (NULL);
if (BUILDING_FLAGGED(bld, BLD_F_RUIN))
return (NULL);
pexit = find_exit(bld->rooms[bld->type->entrance], SOUTH);
if (pexit && isname(doorname, pexit->keyword))
return (pexit);
return (NULL);
}
/* find the coord of the room where the building is placed */
COORD_DATA *get_bld_coord(int vnum)
{
COORD_DATA *here;
BUILDING_DATA *bld = find_building(vnum);
if (!bld)
return (NULL);
CREATE(here, COORD_DATA, 1);
if (IS_WILD(bld->in_room))
*here = *bld->in_room->coord;
else
{
*here = zone_table[bld->in_room->zone].wild.z_start;
if (here->y == 0 && here->x == 0)
here = NULL;
}
return (here);
}
/* ================================================================= */
/* Code for managing building templates */
/* ================================================================= */
/* display a list of valid buildings templates */
void show_valid_list(CHAR_DATA *ch)
{
char buf[MAX_STRING_LENGTH];
int t;
strcpy(buf, "Valids building type names are:\r\n");
for (t = 0; t < num_of_bld_templ; t++)
sprintf(buf + strlen(buf), "%s\r\n", building_template[t]->name);
send_to_char(buf, ch);
}
/* get the building template, by vnum */
BUILDING_TYPE *get_bld_template(int tnum)
{
int t;
for (t = 0; t < num_of_bld_templ; t++)
{
if (building_template[t])
if (building_template[t]->vnum == tnum)
break;
}
if (t >= num_of_bld_templ)
return (NULL);
return (building_template[t]);
}
/* get the building template index, by name */
int get_bld_template_by_name(char *bname)
{
int t;
for (t = 0; t < num_of_bld_templ; t++)
{
if (building_template[t])
if (is_abbrev(bname, building_template[t]->name))
break;
}
if (t >= num_of_bld_templ)
return (NOTHING);
return (t);
}
/* read from file one building template */
BUILDING_TYPE *fread_bld_template(FILE *fp)
{
BUILDING_TYPE *bType;
char *word;
bool fMatch;
sh_int vnmob;
CREATE(bType, BUILDING_TYPE, 1);
bType->name = NULL;
bType->cmds_list = NULL;
bType->cost = 0;
bType->entrance = 0;
bType->size = 0;
bType->vnum = NOTHING;
for (vnmob = 0; vnmob < BLD_MAX_MOB; vnmob++)
bType->vmob[vnmob] = NOBODY;
vnmob = 0;
for ( ; ; )
{
word = feof( fp ) ? "End" : fread_word( fp );
fMatch = FALSE;
switch (UPPER(word[0]))
{
case '*':
fMatch = TRUE;
fread_to_eol(fp);
break;
case 'C':
KEY("Cost", bType->cost, fread_number(fp));
if (!strcmp(word, "Cmd"))
{
BUILDING_CMD *bCmd;
fMatch = TRUE;
CREATE(bCmd, BUILDING_CMD, 1);
bCmd->cmd = fread_letter(fp);
if (strchr("MO", bCmd->cmd) == NULL)
{
log("SYSERR: fread_bld_template() - invalid command in building template %d.", bType->vnum);
exit(1);
}
bCmd->arg[0] = fread_number(fp);
bCmd->arg[1] = fread_number(fp);
bCmd->arg[2] = fread_number(fp);
bCmd->arg[3] = fread_number(fp);
// add to the list
bCmd->next = bType->cmds_list;
bType->cmds_list = bCmd;
break;
}
break;
case 'E':
KEY("Entrance", bType->entrance, fread_number(fp));
if (!strcmp(word, "End"))
{
if (!bType->name || !bType->size || bType->vnum == NOTHING)
{
if (bType->name)
free(bType->name);
DISPOSE(bType);
return (NULL);
}
return (bType);
}
break;
case 'N':
KEY("Name", bType->name, fread_string_nospace(fp));
break;
case 'R':
if (!strcmp(word, "Rng_Defense"))
{
bType->range_min.defense = fread_number(fp);
bType->range_max.defense = fread_number(fp);
fMatch = TRUE;
break;
}
if (!strcmp(word, "Rng_Health"))
{
bType->range_min.health = fread_number(fp);
bType->range_max.health = fread_number(fp);
fMatch = TRUE;
break;
}
if (!strcmp(word, "Rng_Att_MOB"))
{
bType->range_min.mob_attack = fread_number(fp);
bType->range_max.mob_attack = fread_number(fp);
fMatch = TRUE;
break;
}
if (!strcmp(word, "Rng_Att_NPC"))
{
bType->range_min.npc_attack = fread_number(fp);
bType->range_max.npc_attack = fread_number(fp);
fMatch = TRUE;
break;
}
break;
case 'S':
KEY("Size", bType->size, fread_number(fp));
break;
case 'V':
KEY("Vnum", bType->vnum, fread_number(fp));
if (!strcmp(word, "Vmob"))
{
mob_vnum vnmobnum = fread_number(fp);
if ( vnmob >= BLD_MAX_MOB )
log("SYSERR: fread_bld_template() - too many defending mobs.");
else
bType->vmob[vnmob++] = vnmobnum;
fMatch = TRUE;
break;
}
break;
}
if (!fMatch)
log("fread_bld_template: no match: %s", word);
}
if (bType->name)
free(bType->name);
DISPOSE(bType);
return (NULL);
}
/*
* load all buildings templates
*
* called from boot_world() in db.c
*/
void LoadBldTemplate(void)
{
FILE *fp;
char indname[256];
char letter;
char *word;
sprintf(indname, "%sbuildings.txt", BLD_PREFIX);
if (!(fp = fopen(indname, "r")))
{
log("SYSERR: Cannot open buildings index file %s.", indname);
return;
}
for ( ; ; )
{
letter = fread_letter(fp);
if (letter == '*')
{
fread_to_eol(fp);
continue;
}
if (letter != '#')
{
log("LoadBldTemplate(): # not found.");
break;
}
word = fread_word(fp);
if (!str_cmp(word, "BUILDING"))
{
if (num_of_bld_templ >= NUM_BUILDING_TYPE)
{
log("LoadBldTemplate: more template than NUM_BUILDING_TYPE %d", NUM_BUILDING_TYPE);
fclose(fp);
return;
}
building_template[num_of_bld_templ++] = fread_bld_template(fp);
}
else if (!str_cmp(word, "END"))
break;
else
{
log("LoadBldTemplate: bad section %s.", word);
continue;
}
}
fclose(fp);
}
/* ================================================================= */
/* Code for placing and removing buildings in/from room */
/* ================================================================= */
/* place a building into a wild or zone room */
void building_to_room(BUILDING_DATA *bld, ROOM_DATA *pRoom)
{
ROOM_DATA *room;
if (!bld)
return;
if (!pRoom && !bld->coord && bld->vnum_room == NOWHERE)
return;
// a room exists.. place the building there..
if (pRoom)
{
bld->vnum_room = NOTHING;
bld->coord = NULL;
if (IS_WILD(pRoom))
{
if (!bld->coord)
CREATE(bld->coord, COORD_DATA, 1);
bld->coord->y = GET_RY(pRoom);
bld->coord->x = GET_RX(pRoom);
SET_BIT(ROOM_FLAGS(pRoom), ROOM_WILD_STATIC);
}
else
bld->vnum_room = pRoom->number;
/* add to the room list */
bld->next_in_room = pRoom->buildings;
pRoom->buildings = bld;
bld->in_room = pRoom;
return;
}
// zone room
if (bld->vnum_room != NOWHERE)
{
if (!(room = get_room(bld->vnum_room)))
{
log("SYSERR: Cannot place building to room %d.", bld->vnum_room);
return;
}
bld->coord = NULL;
}
// wild room
else
{
if (!(room = create_wild_room(bld->coord, TRUE)))
{
log("SYSERR: Cannot place building to coord %d %d.",
bld->coord->y, bld->coord->x);
return;
}
bld->vnum_room = NOWHERE;
}
/* add to the room list */
bld->next_in_room = room->buildings;
room->buildings = bld;
bld->in_room = room;
}
/* ================================================================= */
/* Code for creating new buildings */
/* ================================================================= */
/* allocate memory and initialize data for a new building */
BUILDING_DATA *new_building(void)
{
BUILDING_DATA *bld;
int xm;
CREATE(bld, BUILDING_DATA, 1);
bld->vnum = NOWHERE;
bld->type = NULL;
bld->next = NULL;
bld->next_in_room = NULL;
bld->in_room = NULL;
bld->coord = NULL;
bld->people = NULL;
bld->auth = NULL;
bld->keyword = NULL;
bld->description = NULL;
bld->trp = NULL;
bld->cmds_list = NULL;
bld->vnum_room = NOWHERE;
bld->can_enter = NOTHING;
bld->owner_type = NOTHING;
bld->owner_id = NOTHING;
bld->flags = 0;
for (xm = 0; xm < BLD_MAX_MOB; xm++)
bld->vmob[xm] = NOBODY;
return (bld);
}
/* make the building inside */
bool create_building_rooms(BUILDING_DATA *bld)
{
FILE *fp;
EXTRA_DESCR *new_descr;
char fname[128];
char letter, *flags;
int room, door;
sprintf(fname, "%s%d.bld", BLD_PREFIX, bld->type->vnum);
if (!(fp = fopen(fname, "r")))
{
log("SYSERR: Unable to open building template file %s.", fname);
return (FALSE);
}
CREATE(bld->rooms, ROOM_DATA *, bld->type->size);
for (room = 0; room < bld->type->size; room++)
{
CREATE(bld->rooms[room], ROOM_DATA, 1);
bld->rooms[room]->number = room;
bld->rooms[room]->zone = BUILDING_ZONE;
CREATE(bld->rooms[room]->extra_data, ROOM_EXTRA, 1);
bld->rooms[room]->extra_data->vnum = bld->vnum;
}
// in entrance room must always be light
bld->rooms[0]->light = 1;
for ( ;; )
{
letter = fread_letter(fp);
if (feof(fp))
break;
if (letter == '$')
break;
if (letter == '*')
{
fread_to_eol(fp);
continue;
}
if (letter != '#')
{
log("create_building_rooms(): # not found.");
break;
}
room = fread_number(fp);
if (room < 0 || room > bld->type->size)
break;
bld->rooms[room]->number = room;
bld->rooms[room]->name = fread_string_nospace(fp);
bld->rooms[room]->description = fread_string_nospace(fp);
flags = fread_word(fp);
bld->rooms[room]->room_flags = asciiflag_conv(flags);
bld->rooms[room]->sector_type = fread_number(fp);
for ( ;; )
{
letter = fread_letter(fp);
if (letter == '*')
{
fread_to_eol(fp);
continue;
}
if (letter == 'S' || letter == '$')
break;
switch (letter)
{
case 'D':
door = fread_number(fp);
if ( door < 0 || door > NUM_OF_DIRS )
{
log( "create_building_rooms: vnum %d has bad door number %d.", room, door );
break;
}
else
{
EXIT_DATA *pexit;
char flags[128];
char *ln;
int x1, x2;
pexit = make_exit(bld->rooms[room], NULL, door);
pexit->description = fread_string_nospace(fp);
pexit->keyword = fread_string_nospace(fp);
ln = fread_line(fp);
x1=x2=0;
sscanf( ln, "%s %d %d ", &flags, &x1, &x2 );
pexit->key = x1;
pexit->vnum = x2;
pexit->vdir = door;
pexit->exit_info = asciiflag_conv(flags);
pexit->to_room = bld->rooms[pexit->vnum];
/* sanity check */
if (pexit->exit_info && !EXIT_FLAGGED(pexit, EX_ISDOOR))
SET_BIT(pexit->exit_info, EX_ISDOOR);
}
break;
case 'E':
CREATE(new_descr, EXTRA_DESCR, 1);
new_descr->keyword = fread_string(fp, buf2);
new_descr->description = fread_string(fp, buf2);
new_descr->next = bld->rooms[room]->ex_description;
bld->rooms[room]->ex_description = new_descr;
break;
/* Room Trigger */
case 'T':
setup_trigger( bld->rooms[room], fp );
break;
}
}
if (letter == '$')
break;
}
fclose(fp);
return (TRUE);
}
void exec_bld_cmds(BUILDING_DATA *bld)
{
BUILDING_CMD *bCmd;
CHAR_DATA *mob;
OBJ_DATA *obj;
ROOM_DATA *bRoom;
int x;
for (bCmd = bld->type->cmds_list; bCmd; bCmd = bCmd->next)
{
switch (bCmd->cmd)
{
default:
log("SYSERR: exec_bld_cmds() - unknown command in building %d.", bld->vnum);
bCmd->cmd = '*';
continue;
case '*':
continue;
case 'M':
if (!(bRoom = bld->rooms[bCmd->arg[2]]))
{
log("SYSERR: exec_bld_cmds() - invalid room vnum %d in building %d.", bCmd->arg[2], bld->vnum);
bCmd->cmd = '*';
continue;
}
for (x = 0; x < bCmd->arg[1]; x++)
{
if (!(mob = read_mobile(bCmd->arg[0], VIRTUAL)))
{
log("SYSERR: exec_bld_cmds() - invalid mob vnum %d in building %d.", bCmd->arg[0], bld->vnum);
bCmd->cmd = '*';
break;
}
char_to_room(mob, bRoom);
}
break;
case 'O':
if (!(bRoom = bld->rooms[bCmd->arg[2]]))
{
log("SYSERR: exec_bld_cmds() - invalid room vnum %d in building %d.", bCmd->arg[2], bld->vnum);
bCmd->cmd = '*';
continue;
}
for (x = 0; x < bCmd->arg[1]; x++)
{
if (!(obj = read_object(bCmd->arg[0], VIRTUAL)))
{
log("SYSERR: exec_bld_cmds() - invalid obj vnum %d in building %d.", bCmd->arg[0], bld->vnum);
bCmd->cmd = '*';
break;
}
obj_to_room(obj, bRoom);
}
break;
}
}
}
/* setup data for a yet-to-be created building */
BUILDING_DATA *setup_new_building(BUILDING_TYPE *bType, ROOM_DATA *pRoom, long owner_id, char owner_type)
{
BUILDING_DATA *bld;
EXIT_DATA *pexit;
char buf[MAX_STRING_LENGTH];
int iHash;
if (!bType || !pRoom)
{
log("SYSERR: setup_new_building() - invalid pointer.");
return (NULL);
}
bld = new_building();
bld->vnum = ++top_of_buildings;
bld->type = bType;
bld->size = bType->size;
bld->keyword = str_dup(bType->name);
sprintf(buf, "%s %s", AN(bType->name), bType->name);
bld->description = str_dup(buf);
/* setup building rooms */
if (!create_building_rooms(bld))
{
log("SYSERR: Setup_new_building() - cannot create building rooms.");
bld->type = NULL;
DISPOSE(bld);
return (NULL);
}
if (owner_type == BLD_OWN_CHAR)
{
bld->owner_id = owner_id;
bld->owner_type = BLD_OWN_CHAR;
bld->can_enter = BLD_ENT_CHAR;
}
else
{
CLAN_DATA *pClan = get_clan(owner_id);
if (!pClan)
{
log("SYSERR: setup_new_building() - invalid clan number %d.", owner_id);
bld->type = NULL;
DISPOSE(bld);
return (NULL);
}
bld->owner_id = owner_id;
bld->owner_type = BLD_OWN_CLAN;
bld->can_enter = BLD_ENT_CLAN;
if (bType->vnum == BLD_CASTLE)
{
if (pClan->hall == NOWHERE)
{
SET_BIT(bld->flags, BLD_F_CLANHALL);
pClan->hall = bld->vnum;
}
}
}
// everyone should be allowed to enter a trading post or a stable
if (bld->type->vnum == BLD_STORE || bld->type->vnum == BLD_STABLE)
bld->can_enter = BLD_ENT_FREE;
/* set up defense pts */
bld->max_val.defense = number(bType->range_min.defense, bType->range_max.defense);
bld->curr_val.defense = bld->max_val.defense;
/* set up health pts */
bld->max_val.health = number(bType->range_min.health, bType->range_max.health);
bld->curr_val.health = bld->max_val.health;
/* set up mob_attack pts */
if (bType->range_max.mob_attack)
{
int xm;
bld->max_val.mob_attack = number(bType->range_min.mob_attack, bType->range_max.mob_attack);
bld->curr_val.mob_attack = bld->max_val.mob_attack;
for (xm = 0; xm < BLD_MAX_MOB; xm++)
{
if (bType->vmob[xm] == NOBODY)
continue;
bld->vmob[xm] = bType->vmob[xm];
}
}
/* set up npc_attack pts */
if (bType->range_max.npc_attack)
{
bld->max_val.npc_attack = number(bType->range_min.npc_attack, bType->range_max.npc_attack);
bld->curr_val.npc_attack = bld->max_val.npc_attack;
}
// execute building commands (load objs & mobs)
exec_bld_cmds(bld);
/* add to the global hash table */
iHash = bld->vnum % BLD_HASH;
bld->next = building_list[iHash];
building_list[iHash] = bld;
/* place building into room */
building_to_room(bld, pRoom);
/* exit building --> room */
pexit = make_exit(bld->rooms[bld->type->entrance], NULL, SOUTH);
pexit->to_room = bld->in_room;
pexit->keyword = str_dup("door");
SET_BIT(EXIT_FLAGS(pexit), EX_ISDOOR);
// forced save
SaveBuildings();
return (bld);
}
/* ======================================================================= */
/* Code for building Buildings */
/* ======================================================================= */
/* time needed in each phase for each building rooms.. in mud hours */
int bwks_timing[] =
{
0,
4,
2,
3
};
/* setup build works a new building */
int build_works_start(BUILDING_TYPE *bType, ROOM_DATA *pRoom, long owner_id, char owner_type)
{
BLD_WORKS *pWorks;
CREATE(pWorks, BLD_WORKS, 1);
pWorks->next = NULL;
pWorks->prev = NULL;
pWorks->num = ++last_works_num;
pWorks->owner_type = owner_type;
pWorks->owner_id = owner_id;
pWorks->authorized = FALSE;
pWorks->phase = BWKS_BASE;
pWorks->timer = bwks_timing[BWKS_BASE] * bType->size;
pWorks->type = bType->vnum;
pWorks->coord = NULL;
pWorks->in_room = NULL;
if (IS_WILD(pRoom))
{
CREATE(pWorks->coord, COORD_DATA, 1);
pWorks->coord->y = GET_RY(pRoom);
pWorks->coord->x = GET_RX(pRoom);
SET_BIT(ROOM_FLAGS(pRoom), ROOM_BUILDING_WORKS | ROOM_WILD_STATIC);
}
else
{
pWorks->in_room = pRoom;
SET_BIT(ROOM_FLAGS(pRoom), ROOM_BUILDING_WORKS);
}
LINK(pWorks, first_build_work, last_build_work, next, prev);
return (pWorks->num);
}
void build_works_process(void)
{
BLD_WORKS *pWorks, *pWorks_next;
if (!first_build_work)
return;
for (pWorks = first_build_work; pWorks; pWorks = pWorks_next)
{
pWorks_next = pWorks->next;
if (--pWorks->timer <= 0)
{
BUILDING_TYPE *bType = get_bld_template(pWorks->type);
if (++pWorks->phase > BWKS_FINAL)
{
BUILDING_DATA *bld;
if (pWorks->coord)
pWorks->in_room = get_wild_room(pWorks->coord);
bld = setup_new_building(bType, pWorks->in_room, pWorks->owner_id, pWorks->owner_type);
UNLINK(pWorks, first_build_work, last_build_work, next, prev);
REMOVE_BIT(ROOM_FLAGS(pWorks->in_room), ROOM_BUILDING_WORKS);
pWorks->in_room = NULL;
pWorks->next = NULL;
pWorks->prev = NULL;
DISPOSE(pWorks->coord);
DISPOSE(pWorks);
}
else
pWorks->timer = bwks_timing[pWorks->phase] * bType->size;
}
}
}
const char *bwks_phase_descr[] =
{
"none",
"basement",
"walls",
"roof",
"\n"
};
void build_works_list(CHAR_DATA *ch)
{
BLD_WORKS *pWorks;
if (!first_build_work)
{
send_to_char("Currently, there are no building works in progress.\r\n", ch);
return;
}
send_to_char("List of build works currently in progress:\r\n", ch);
for ( pWorks = first_build_work; pWorks; pWorks = pWorks->next )
{
ch_printf(ch, " %30s Phase: [%-10s] Hours left: %d\r\n",
building_template[pWorks->type]->name,
bwks_phase_descr[pWorks->phase], pWorks->timer);
}
}
ACMD(do_listworks)
{
build_works_list(ch);
}
/* ============================================================= */
void SaveWorksList(void)
{
FILE *fp;
BLD_WORKS *pWorks;
char fname[128];
if (!first_build_work)
return;
sprintf(fname, "%sworkslist.txt", LIB_BUILDINGS);
if (!(fp = fopen(fname, "w")))
{
log("SYSERR: SaveWorksList() - cannot create file %s.", fname);
return;
}
for (pWorks = first_build_work; pWorks; pWorks = pWorks->next)
{
fprintf(fp, "Work %d %hd %d %hd %hd %hd %d ",
pWorks->num,
pWorks->owner_type, pWorks->owner_id, (pWorks->authorized ? 1 : 0),
pWorks->phase, pWorks->timer, pWorks->type);
if (pWorks->coord)
fprintf(fp, "C %hd %hd", pWorks->coord->y, pWorks->coord->x);
else
fprintf(fp, "R %d", pWorks->in_room->number);
fprintf(fp, "\n");
}
fprintf(fp, "$\n");
fclose(fp);
}
void ReadWorksList(void)
{
FILE *fp;
BLD_WORKS *pWorks;
char fname[128], *word, letter;
// list already loaded....
if (first_build_work)
return;
// nullify head & tail
first_build_work = NULL;
last_build_work = NULL;
last_works_num = 0;
sprintf(fname, "%sworkslist.txt", LIB_BUILDINGS);
if (!(fp = fopen(fname, "r")))
return;
for ( ; ; )
{
word = feof(fp) ? "$" : fread_word(fp);
switch (UPPER(word[0]))
{
case '*':
fread_to_eol( fp );
break;
case '$':
fclose(fp);
return;
case 'W':
CREATE(pWorks, BLD_WORKS, 1);
pWorks->next = NULL;
pWorks->prev = NULL;
pWorks->num = fread_number(fp);
pWorks->owner_type = fread_number(fp);
pWorks->owner_id = fread_number(fp);
pWorks->authorized = fread_number(fp);
pWorks->phase = fread_number(fp);
pWorks->timer = fread_number(fp);
pWorks->type = fread_number(fp);
letter = fread_letter(fp);
pWorks->coord = NULL;
pWorks->in_room = NULL;
if (letter == 'C')
{
CREATE(pWorks->coord, COORD_DATA, 1);
pWorks->coord->y = fread_number(fp);
pWorks->coord->x = fread_number(fp);
pWorks->in_room = create_wild_room(pWorks->coord, TRUE);
}
else
pWorks->in_room = get_room(fread_number(fp));
LINK(pWorks, first_build_work, last_build_work, next, prev);
if (last_works_num < pWorks->num)
last_works_num = pWorks->num;
}
}
fclose(fp);
}
/* ============================================================= */
/* create a new building of the given type */
void create_building(CHAR_DATA *ch, char *arg, int clan_num)
{
char owner_type;
bool can_build = TRUE;
int vnum, gold, cost;
long owner_id;
if (!num_of_bld_templ)
{
send_to_char("No building can be built right now.\r\n", ch);
return;
}
if (!*arg)
{
send_to_char("Usage: build <building type>\r\n", ch);
show_valid_list(ch);
return;
}
if ((vnum = get_bld_template_by_name(arg)) == NOTHING)
{
ch_printf(ch, "Unknown building type '%s'.\r\n", arg);
show_valid_list(ch);
return;
}
if (!terrain_type[SECT(ch->in_room)])
{
send_to_char("You cannot build in this room.\r\n", ch);
return;
}
/* check invalid room sector */
switch (SECT(ch->in_room))
{
case SECT_INSIDE:
case SECT_WATER_SWIM:
case SECT_WATER_NOSWIM:
case SECT_UNDERWATER:
case SECT_FLYING:
case SECT_MOUNTAIN_PEAK:
case SECT_REEF:
case SECT_SEA:
case SECT_RIVER:
case SECT_ROAD:
case SECT_BRIDGE:
case SECT_WILD_EXIT:
case SECT_ZONE_BORDER:
case SECT_ZONE_INSIDE:
case SECT_RIVER_NAVIGABLE:
case SECT_SHIP_STERN:
case SECT_SHIP_DECK:
case SECT_SHIP_BOW:
case SECT_SHIP_UNDERDK:
case SECT_SHIP_CABIN:
case SECT_SHIP_HOLD:
case SECT_FERRY_DECK:
case SECT_FORD:
case SECT_SHALLOWS:
can_build = FALSE;
break;
}
if (!can_build)
{
ch_printf(ch, "You cannot build in '%s' rooms.\r\n",
terrain_type[SECT(ch->in_room)]->name);
return;
}
cost = building_template[vnum]->cost;
if (clan_num == NOTHING)
{
owner_id = GET_IDNUM(ch);
owner_type = BLD_OWN_CHAR;
gold = get_gold(ch) + GET_BANK_GOLD(ch);
if (gold < cost)
gold = -1;
else
{
if ( get_gold(ch) < cost )
{
int diff = cost - get_gold(ch);
sub_gold(ch, get_gold(ch));
GET_BANK_GOLD(ch) -= diff;
}
else
sub_gold(ch, cost);
}
}
else
{
CLAN_DATA *pClan = get_clan(clan_num);
if ( !pClan )
{
send_to_char("Ooopss.. clan error: contact an immortal.\r\n", ch);
log("SYSERR: create_building() - invalid clan number %d.", clan_num);
return;
}
owner_id = clan_num;
owner_type = BLD_OWN_CLAN;
gold = pClan->treasure;
if ( gold < cost )
gold = -1;
else
pClan->treasure -= cost;
}
if (gold == -1 && IS_MORTAL(ch))
{
ch_printf(ch, "You need %d gold coins to build %s %s.\r\n",
building_template[vnum]->cost, AN(building_template[vnum]->name),
building_template[vnum]->name);
return;
}
ch_printf(ch, "You pay %d gold coins of building expenses.\r\n",
building_template[vnum]->cost);
if (IS_IMMORTAL(ch))
setup_new_building(building_template[vnum], ch->in_room, owner_id, owner_type);
else
build_works_start(building_template[vnum], ch->in_room, owner_id, owner_type);
}
/* the build command */
ACMD(do_build)
{
char arg[MAX_INPUT_LENGTH];
argument = one_argument(argument, arg);
if (!*arg)
{
send_to_char("Usage: build <building type>\r\n", ch);
return;
}
argument = one_argument(argument, arg);
if (!*arg)
{
show_valid_list(ch);
return;
}
create_building(ch, arg, NOTHING);
}
/* show the status of a building - IMMS */
void do_stat_building(CHAR_DATA *ch, BUILDING_DATA *bld)
{
char bflags[128];
ch_printf(ch, "Vnum : %d\r\n", bld->vnum);
ch_printf(ch, "Type : %s\r\n", bld_type_descr[bld->type->vnum]);
ch_printf(ch, "Name : %s\r\n", bld->description);
if (BUILDING_FLAGGED(bld, BLD_F_RUIN))
return;
ch_printf(ch, "Size : %d\r\n", bld->size);
if (bld->coord)
ch_printf(ch, "Location : %d %d\r\n", GET_RY(bld), GET_RX(bld));
else
ch_printf(ch, "Location : room %d\r\n", bld->vnum_room);
sprintbit(bld->flags, bld_flags_descr, bflags);
ch_printf(ch, "Flags : %s\r\n", bflags);
ch_printf(ch, "Defense : %d / %d\r\n", bld->curr_val.defense, bld->max_val.defense);
ch_printf(ch, "Health : %d / %d\r\n", bld->curr_val.health, bld->max_val.health);
ch_printf(ch, "Owner type : %s\r\n", bld_owner_descr[bld->owner_type]);
ch_printf(ch, "Owner Id : %d\r\n", bld->owner_id);
ch_printf(ch, "Enter auth : %s\r\n", bld_enter_descr[bld->can_enter]);
if (bld->max_val.npc_attack > 0)
ch_printf(ch, "NPC damage : %d / %d.\r\n",
bld->curr_val.npc_attack, bld->max_val.npc_attack);
if (bld->max_val.mob_attack > 0)
{
int x;
ch_printf(ch, "Mobs loaded: %d / %d.\r\n",
bld->curr_val.mob_attack, bld->max_val.mob_attack);
for (x = 0; x < BLD_MAX_MOB; x++)
{
if (bld->vmob[x] == NOTHING)
continue;
ch_printf(ch, " Mob vnum : %d\r\n", bld->vmob[x]);
}
}
}
ACMD(do_bldlist)
{
BUILDING_DATA *bld;
char sbaf[MAX_STRING_LENGTH];
int iHash;
if (!building_loaded)
{
send_to_char("No buildings at all.\r\n", ch);
return;
}
send_to_char("List of building in world:\r\n", ch);
for (iHash = 0; iHash < BLD_HASH; iHash++)
{
for (bld = building_list[iHash]; bld; bld = bld->next)
{
if (IS_WILD(bld->in_room))
sprintf(sbaf, "Wild [%d %d]", GET_Y(bld), GET_X(bld));
else
sprintf(sbaf, "Room [%d]", bld->in_room->number);
ch_printf(ch, "[%d] %-30s Location: %s\r\n",
bld->vnum, bld->description, sbaf);
}
}
}
/* ================================================================= */
/* Code for saving buildings */
/* ================================================================= */
/* write on file the building inside */
void fwrite_building_rooms(BUILDING_DATA *bld, FILE *fp)
{
ROOM_DATA *room;
EXIT_DATA *pexit;
char dflags[128];
int num;
for (num = 0; num < bld->size; num++)
{
room = bld->rooms[num];
if (!room) break;
/* Copy the description and strip off trailing newlines */
strcpy(buf, room->description ? room->description : "Empty room.");
strip_cr(buf);
sprintascii(buf2, room->room_flags);
fprintf(fp,
"#%d\n"
"%s~\n"
"%s~\n"
"%s %d %d %d\n",
room->number,
room->name ? room->name : "Untitled",
buf, buf2, room->sector_type,
room->extra_data->curr_hp, room->extra_data->max_hp
);
/* Now you write out the exits for the room */
for (pexit = room->first_exit; pexit; pexit = pexit->next)
{
/* check for non-building exits */
if (!IS_BUILDING(pexit->to_room))
continue;
if (pexit->description)
{
strcpy(buf, pexit->description);
strip_cr(buf);
}
else
*buf = '\0';
if (pexit->keyword)
strcpy(buf1, pexit->keyword);
else
*buf1 = '\0';
/* New door flags handling -- Fab 2000 */
REMOVE_BIT(EXIT_FLAGS(pexit), EX_LOCKED);
REMOVE_BIT(EXIT_FLAGS(pexit), EX_CLOSED);
REMOVE_BIT(EXIT_FLAGS(pexit), EX_HIDDEN);
/* sanity check */
if (EXIT_FLAGS(pexit) && !EXIT_FLAGGED(pexit, EX_ISDOOR))
SET_BIT(EXIT_FLAGS(pexit), EX_ISDOOR);
sprintascii(dflags, pexit->exit_info);
fprintf(fp,
"D%d\n"
"%s~\n"
"%s~\n"
"%s %d %d\n", pexit->vdir, buf, buf1, dflags,
pexit->key, ( pexit->to_room != NULL ? pexit->to_room->number : NOWHERE ) );
}
if (room->ex_description)
{
EXTRA_DESCR *xdesc;
for (xdesc = room->ex_description; xdesc; xdesc = xdesc->next)
{
strcpy(buf, xdesc->description);
strip_cr(buf);
fprintf(fp,
"E\n"
"%s~\n"
"%s~\n", xdesc->keyword, buf);
}
}
fprintf(fp, "S\n");
}
/* Write the final line */
fprintf(fp, "$\n\n");
}
/* write on file one building */
void fwrite_building(BUILDING_DATA *bld)
{
FILE *fp;
char fname[128];
int num, xm;
sprintf(fname, "%s%d.bld", LIB_BUILDINGS, bld->vnum);
if (!(fp = fopen(fname, "w")))
{
log("SYSERR: fwrite_building() - unable to create file %s.", fname);
return;
}
fprintf(fp, "#BUILDING\n");
fprintf(fp, "Vnum %d\n", bld->vnum);
fprintf(fp, "Type %d\n", bld->type->vnum);
if (bld->coord)
fprintf(fp, "Coord %hd %hd\n", GET_RY(bld), GET_RX(bld));
if (bld->vnum_room != NOWHERE)
fprintf(fp, "Vnum_room %d\n", bld->vnum_room);
fprintf(fp, "Size %hd\n", bld->size);
fprintf(fp, "Owner_Id %ld\n", bld->owner_id);
fprintf(fp, "Owner_Type %d\n", bld->owner_type);
fprintf(fp, "Enter_Type %d\n", bld->can_enter);
fprintf(fp, "Defense %hd %hd\n", bld->curr_val.defense, bld->max_val.defense);
fprintf(fp, "Health %hd %hd\n", bld->curr_val.health, bld->max_val.health);
if (bld->max_val.mob_attack > 0)
fprintf(fp, "Attack_MOB %hd %hd\n", bld->curr_val.mob_attack, bld->max_val.mob_attack);
if (bld->max_val.npc_attack > 0)
fprintf(fp, "Attack_NPC %hd %hd\n", bld->curr_val.npc_attack, bld->max_val.npc_attack);
if (bld->flags)
fprintf(fp, "Flags %d\n", bld->flags);
for (xm = 0; xm < BLD_MAX_MOB; xm++)
{
if (bld->vmob[xm] == NOBODY)
continue;
fprintf(fp, "Vmob %d\n", bld->vmob[xm]);
}
if (bld->keyword)
fprintf(fp, "Keywords %s~\n", bld->keyword);
if (bld->description)
fprintf(fp, "Description %s~\n", bld->description);
if (bld->auth)
{
AUTH_DATA *bAuth;
for (bAuth = bld->auth; bAuth; bAuth = bAuth->next)
fprintf(fp, "IdAuth %ld %s\n", bAuth->id_num, bAuth->name);
}
if (bld->trp)
fprintf(fp, "TradingPost %d\n", bld->trp->vnum);
fprintf(fp, "End\n\n");
if (!BUILDING_FLAGGED(bld, BLD_F_RUIN))
{
fprintf(fp, "#ROOMS\n");
fwrite_building_rooms(bld, fp);
for (num = 0; num < bld->size; num++)
{
if (bld->rooms[num] && bld->rooms[num]->first_content)
{
fprintf(fp, "#ROOMCONTENT\n");
fprintf(fp, "Room %d\n", num);
save_objs( bld->rooms[num]->last_content, fp, 0, 0);
fprintf(fp, "End\n\n");
}
}
}
fprintf(fp, "#END\n");
fclose(fp);
}
/*
* save all buildings
*
* called from heartbeat() in comm.c
*/
void SaveBuildings(void)
{
FILE *fp;
BUILDING_DATA *bld;
char fname[128];
int i;
if (!top_of_buildings)
return;
sprintf(fname, "%sindex", LIB_BUILDINGS);
if (!(fp = fopen(fname, "w")))
{
log("SYSERR: SaveBuildings() - unable to create index file %s.", fname);
return;
}
for (i = 0; i < BLD_HASH; i++)
{
for (bld = building_list[i]; bld; bld = bld->next)
{
if (bld->vnum == NOTHING || !bld->type || bld->type->vnum == NOTHING)
continue;
fprintf(fp, "%d.bld\n", bld->vnum);
fwrite_building(bld);
}
}
fprintf(fp, "$\n");
fclose(fp);
SaveWorksList();
}
/* forced save of all buildings - IMMS */
ACMD(do_bldsave)
{
SaveBuildings();
send_to_char(OK, ch);
}
/* ================================================================= */
/* Code for loading saved buildings */
/* ================================================================= */
#define MAX_BAG_ROWS 5
/* load contents of a building room from file */
void fread_building_contents(BUILDING_DATA *bld, FILE *fp)
{
OBJ_DATA *obj, *obj2, *cont_row[MAX_BAG_ROWS];
int location, j, roomnum;
char *word;
bool fMatch;
/* Empty all of the container lists (you never know ...) */
for (j = 0; j < MAX_BAG_ROWS; j++)
cont_row[j] = NULL;
for ( ; ; )
{
word = feof( fp ) ? "End" : fread_word( fp );
fMatch = FALSE;
switch (UPPER(word[0]))
{
case '*':
fMatch = TRUE;
fread_to_eol(fp);
break;
case 'E':
if (!strcmp(word, "End"))
return;
case 'R':
KEY("Room", roomnum, fread_number(fp));
break;
case '#':
// skip #OBJECT line..
fread_to_eol( fp );
if ((obj = fread_one_obj(fp, &location)) == NULL)
continue;
obj_to_room(obj, bld->rooms[roomnum]);
for (j = MAX_BAG_ROWS - 1; j > -location; j--)
{
if (cont_row[j]) /* No container, back to inventory. */
{
for (; cont_row[j]; cont_row[j] = obj2)
{
obj2 = cont_row[j]->next_content;
obj_to_room( cont_row[j], bld->rooms[roomnum] );
}
cont_row[j] = NULL;
}
}
if (j == -location && cont_row[j]) /* Content list exists. */
{
if (GET_OBJ_TYPE(obj) == ITEM_CONTAINER ||
GET_OBJ_TYPE(obj) == ITEM_MISSILE_CONT)
{
/* Take the item, fill it, and give it back. */
obj_from_room(obj);
obj->first_content = NULL;
obj->last_content = NULL;
for (; cont_row[j]; cont_row[j] = obj2)
{
obj2 = cont_row[j]->next_content;
obj_to_obj(cont_row[j], obj);
}
obj_to_room(obj, bld->rooms[roomnum]);
}
else /* Object isn't container, empty content list. */
{
for (; cont_row[j]; cont_row[j] = obj2)
{
obj2 = cont_row[j]->next_content;
obj_to_room(cont_row[j], bld->rooms[roomnum]);
}
cont_row[j] = NULL;
}
}
if (location < 0 && location >= -MAX_BAG_ROWS)
{
obj_from_room(obj);
if ((obj2 = cont_row[-location - 1]) != NULL)
{
while (obj2->next_content)
obj2 = obj2->next_content;
obj2->next_content = obj;
}
else
cont_row[-location - 1] = obj;
}
break;
}
}
}
/* load from file the building inside */
void fread_building_rooms(BUILDING_DATA *bld, FILE *fp)
{
EXTRA_DESCR *new_descr;
char letter, *flags;
int room, door;
CREATE(bld->rooms, ROOM_DATA *, bld->size);
for (room = 0; room < bld->size; room++)
{
CREATE(bld->rooms[room], ROOM_DATA, 1);
bld->rooms[room]->zone = BUILDING_ZONE;
CREATE(bld->rooms[room]->extra_data, ROOM_EXTRA, 1);
bld->rooms[room]->extra_data->vnum = bld->vnum;
}
// in entrance room must always be light
bld->rooms[0]->light = 1;
if (bld->trp)
{
// assign to first building room the special procedure
bld->rooms[0]->func = tradingpost;
// save room in TP data for reference..
bld->trp->in_room = bld->rooms[0];
}
for ( ;; )
{
letter = fread_letter(fp);
if (feof(fp))
break;
if (letter == '$')
break;
if (letter == '*')
{
fread_to_eol(fp);
continue;
}
if (letter != '#')
{
log("create_building_rooms(): # not found.");
break;
}
room = fread_number(fp);
if (room < 0 || room > bld->type->size)
break;
bld->rooms[room]->number = room;
bld->rooms[room]->name = fread_string_nospace(fp);
bld->rooms[room]->description = fread_string_nospace(fp);
flags = fread_word(fp);
bld->rooms[room]->room_flags = asciiflag_conv(flags);
bld->rooms[room]->sector_type = fread_number(fp);
bld->rooms[room]->extra_data->curr_hp = fread_number(fp);
bld->rooms[room]->extra_data->max_hp = fread_number(fp);
for (;;)
{
letter = fread_letter(fp);
if (letter == '*')
{
fread_to_eol(fp);
continue;
}
if (letter == 'S' || letter == '$')
break;
switch (letter)
{
case 'D':
door = fread_number(fp);
if ( door < 0 || door > NUM_OF_DIRS )
{
log("create_building_rooms: vnum %d has bad door number %d.", room, door);
break;
}
else
{
EXIT_DATA *pexit;
char flags[128];
char *ln;
int x1, x2;
pexit = make_exit( bld->rooms[room], NULL, door );
pexit->description = fread_string_nospace(fp);
pexit->keyword = fread_string_nospace(fp);
ln = fread_line(fp);
x1=x2=0;
sscanf( ln, "%s %d %d ", &flags, &x1, &x2 );
pexit->key = x1;
pexit->vnum = x2;
pexit->vdir = door;
pexit->exit_info = asciiflag_conv( flags );
pexit->to_room = bld->rooms[pexit->vnum];
/* sanity check */
if ( pexit->exit_info && !EXIT_FLAGGED( pexit, EX_ISDOOR ) )
SET_BIT( pexit->exit_info, EX_ISDOOR );
}
break;
case 'E':
CREATE(new_descr, EXTRA_DESCR, 1);
new_descr->keyword = fread_string(fp, buf2);
new_descr->description = fread_string(fp, buf2);
new_descr->next = bld->rooms[room]->ex_description;
bld->rooms[room]->ex_description = new_descr;
break;
/* Room Trigger */
case 'T':
setup_trigger( bld->rooms[room], fp );
break;
}
}
if (letter == '$')
break;
}
}
/* load from file the building data */
BUILDING_DATA *fread_building_data( FILE *fp )
{
BUILDING_DATA *bld;
char *word;
bool fMatch;
sh_int vnmob = 0;
bld = new_building();
for ( ; ; )
{
word = feof( fp ) ? "End" : fread_word( fp );
fMatch = FALSE;
switch (UPPER(word[0]))
{
case '*':
fMatch = TRUE;
fread_to_eol( fp );
break;
case 'A':
if (!strcmp(word, "Attack_MOB"))
{
bld->curr_val.mob_attack = fread_number(fp);
bld->max_val.mob_attack = fread_number(fp);
fMatch = TRUE;
break;
}
if (!strcmp(word, "Attack_NPC"))
{
bld->curr_val.npc_attack = fread_number(fp);
bld->max_val.npc_attack = fread_number(fp);
fMatch = TRUE;
break;
}
break;
case 'C':
if (!strcmp(word, "Coord"))
{
CREATE(bld->coord, COORD_DATA, 1);
bld->coord->y = fread_number(fp);
bld->coord->x = fread_number(fp);
fMatch = TRUE;
break;
}
break;
case 'D':
KEY("Description", bld->description, fread_string_nospace(fp));
if (!strcmp(word, "Defense"))
{
bld->curr_val.defense = fread_number(fp);
bld->max_val.defense = fread_number(fp);
fMatch = TRUE;
break;
}
break;
case 'E':
KEY("Enter_Type", bld->can_enter, fread_number(fp));
if (!strcmp(word, "End"))
{
if (!bld->type || (!bld->coord && !bld->vnum_room))
{
bld->type = NULL;
if (bld->coord)
DISPOSE(bld->coord);
DISPOSE(bld);
return (NULL);
}
return (bld);
}
break;
case 'F':
KEY("Flags", bld->flags, fread_number(fp));
break;
case 'H':
if (!strcmp(word, "Health"))
{
bld->curr_val.health = fread_number(fp);
bld->max_val.health = fread_number(fp);
fMatch = TRUE;
break;
}
break;
case 'I':
if (!strcmp(word, "IdAuth"))
{
AUTH_DATA *bAuth;
CREATE(bAuth, AUTH_DATA, 1);
bAuth->id_num = fread_number(fp);
bAuth->name = str_dup(fread_word(fp));
bAuth->next = bld->auth;
bld->auth = bAuth;
fMatch = TRUE;
break;
}
break;
case 'K':
KEY("Keywords", bld->keyword, fread_string_nospace(fp));
break;
case 'O':
KEY("Owner_Id", bld->owner_id, fread_number(fp));
KEY("Owner_Type", bld->owner_type, fread_number(fp));
break;
case 'S':
KEY("Size", bld->size, fread_number(fp));
break;
case 'T':
KEY("Type", bld->type, get_bld_template(fread_number(fp)));
if (!strcmp(word, "TradingPost"))
{
TRADING_POST *pTp;
int tpnum;
fMatch = TRUE;
tpnum = fread_number(fp);
if (!(pTp = find_trading_post(tpnum)))
{
log("SYSERR: fread_building_data() - invalid trading post vnum %d.", tpnum);
break;
}
// give building trading post status
bld->trp = pTp;
break;
}
break;
case 'V':
KEY("Vnum", bld->vnum, fread_number(fp));
KEY("Vnum_room", bld->vnum_room, fread_number(fp));
if (!strcmp(word, "Vmob"))
{
mob_vnum vnmobnum = fread_number(fp);
if (vnmob >= BLD_MAX_MOB)
log("SYSERR: fread_building_data() - too many defending mobs.");
else
bld->vmob[vnmob++] = vnmobnum;
fMatch = TRUE;
break;
}
break;
}
}
return (NULL);
}
/* load from file one building */
BUILDING_DATA *fread_building(char *bname)
{
FILE *fp;
BUILDING_DATA *bld = NULL;
char fname[128];
char letter;
char *word;
sprintf(fname, "%s%s", LIB_BUILDINGS, bname);
if (!(fp = fopen(fname, "r")))
{
log("SYSERR: fread_building() - unable to open file %s.", fname);
return (NULL);
}
for ( ;; )
{
letter = fread_letter(fp);
if (letter == '*')
{
fread_to_eol( fp );
continue;
}
if (letter != '#')
{
log( "fread_building: # not found." );
break;
}
word = fread_word(fp);
if (!strcmp(word, "BUILDING"))
{
if (!(bld = fread_building_data(fp)))
{
log("SYSERR: fread_building() - error in reading data for building file %s.", bname);
break;
}
}
else if (!strcmp(word, "ROOMS"))
fread_building_rooms(bld, fp);
else if (!strcmp(word, "ROOMCONTENT"))
fread_building_contents(bld, fp);
else if (!strcmp(word, "END"))
break;
else
{
log("fread_building: bad section %s.", word);
continue;
}
}
fclose(fp);
return (bld);
}
/*
* load all buildings
*
* called from ???
*/
void LoadBuildings(void)
{
FILE *fp;
BUILDING_DATA *bld;
EXIT_DATA *pexit;
char fname[128];
int iHash;
if (building_loaded)
{
log("SYSERR: LoadBuildings() - already loaded.");
return;
}
sprintf(fname, "%sindex", LIB_BUILDINGS);
if (!(fp = fopen(fname, "r")))
{
log(" No building templates defined.");
return;
}
building_loaded = TRUE;
top_of_buildings = 0;
while (!feof(fp))
{
char *bldfname = fread_word( fp );
if (bldfname[0] == '$')
break;
if (!(bld = fread_building(bldfname)))
continue;
building_to_room(bld, NULL);
if (!BUILDING_FLAGGED(bld, BLD_F_RUIN))
{
/* exit building --> wilderness */
pexit = make_exit(bld->rooms[bld->type->entrance], NULL, SOUTH);
if (bld->vnum_room != NOWHERE)
pexit->to_room = get_room(bld->vnum_room);
else
pexit->to_room = get_wild_room(bld->coord);
pexit->keyword = str_dup("door");
SET_BIT(EXIT_FLAGS(pexit), EX_ISDOOR);
}
// execute building commands (load objs & mobs)
exec_bld_cmds(bld);
/* add to the global hash table */
iHash = bld->vnum % BLD_HASH;
bld->next = building_list[iHash];
building_list[iHash] = bld;
top_of_buildings++;
}
fclose(fp);
ReadWorksList();
}
/* ======================================================================= */
/* Code for repairing buildings */
/* ======================================================================= */
/* make some reparations */
void repair_building(CHAR_DATA *ch, BUILDING_DATA *bld)
{
if (BUILDING_FLAGGED(bld, BLD_F_RUIN))
{
act("$b: you cannot repair ruins.", FALSE, ch, NULL, bld, TO_CHAR);
return;
}
if (bld->max_val.health == bld->curr_val.health)
{
act("$b does not need reparations.", FALSE, ch, NULL, bld, TO_CHAR);
return;
}
if (!roll(GET_DEX(ch)))
{
send_to_char("You fail.\r\n", ch);
return;
}
bld->curr_val.health++;
act("You make sone reparations to $b.", FALSE, ch, NULL, bld, TO_CHAR);
act("$n makes sone reparations to $b.", FALSE, ch, NULL, bld, TO_ROOM);
}
/* ============================================================================ */
/* Code for attacking, damaging and repairing buildings, plus buildings defense */
/* ============================================================================ */
/*
* some buildings, in response of an attack,
* can "generate" some mobs to fight the attacker
*
* this code pick a defender mob at random from
* the list of possible defenders mobs
*/
CHAR_DATA *get_bld_defmob(BUILDING_DATA *bld)
{
CHAR_DATA *mob;
int xn, nlast, num;
for (nlast = -1, xn = 0; xn < BLD_MAX_MOB; xn++)
{
if (bld->vmob[xn] == NOBODY)
break;
nlast = xn;
}
/* no mobs.. hmmmm */
if (nlast == -1)
{
log("SYSERR: get_bld_defmob() - cannot find a valid mob vnum.");
return (NULL);
}
if (nlast == 0) num = nlast; // single mob
else num = number(0, nlast); // two or more mobs
if (!(mob = read_mobile(bld->vmob[num], VIRTUAL)))
{
log("SYSERR: get_bld_defmob() - invalid mob vnum %d.", bld->vmob[num]);
return (NULL);
}
return (mob);
}
/*
* called when a building is destroyed
*/
void damage_people_inside(BUILDING_DATA *bld)
{
CHAR_DATA *tch, *tch_next = NULL;
EXIT_DATA *pexit;
bool saved = FALSE;
pexit = get_exit(bld->rooms[bld->type->entrance], SOUTH);
if (pexit && !valid_exit(pexit))
pexit = NULL;
for (tch = bld->people; tch; tch = tch_next)
{
tch_next = tch->next_in_building;
act("$b collapses and crumbles.", FALSE, tch, NULL, bld, TO_CHAR);
saved = FALSE;
/*
* if tch is in the entrance room, and if the door is open, and if he makes
* a check on dex at -4, arf, he can jump out of the building..
*/
if (tch->in_room == bld->rooms[bld->type->entrance] && pexit &&
roll(GET_DEX(tch) - 4))
{
act("You quickly leap out of $b's door one moment before it crumbles.",
FALSE, tch, NULL, bld, TO_CHAR);
act("$n quickly leaps out of $b's door one moment before it crumbles.",
FALSE, tch, NULL, bld, TO_ROOM);
char_from_building(tch);
char_from_room(tch);
char_to_room(tch, bld->in_room);
act("$n leaps out of $b'door one moment before it crumbles.",
FALSE, tch, NULL, bld, TO_ROOM);
continue;
}
// take him out so, if he die, we place the corpse OUTSIDE the building
char_from_building(tch);
char_from_room(tch);
char_to_room(tch, bld->in_room);
send_to_char("You are hit by falling rubbles.\r\n", tch);
// char suffer massive damage.. :-(((
damage(tch, tch, number(50,100) * (bld->type->vnum + 1), -1);
}
}
/*
* adjust destroyed building descriptions with
* ruins of the correct type
*/
void make_ruins(BUILDING_DATA *bld)
{
char dbuf[MAX_STRING_LENGTH];
SET_BIT(BUILDING_FLAGS(bld), BLD_F_RUIN);
sprintf(dbuf, "ruins %s", bld->type->name);
if (bld->keyword)
DISPOSE(bld->keyword);
bld->keyword = str_dup(dbuf);
sprintf(dbuf, "the ruins of %s %s", AN(bld->type->name), bld->type->name);
if (bld->description)
DISPOSE(bld->description);
bld->description = str_dup(dbuf);
}
/*
* return 0 if building is destroyed, >0 otherwise
*/
int damage_building(BUILDING_DATA *bld, int dam)
{
bld->curr_val.health -= dam;
if (bld->curr_val.health <= 0)
{
bld->curr_val.health = 0;
damage_people_inside(bld);
make_ruins(bld);
fwrite_building(bld);
return (0);
}
return (1);
}
/* one hit to a building */
void hit_building(CHAR_DATA *ch, BUILDING_DATA *bld)
{
OBJ_DATA *weapon;
char dbuf[MAX_STRING_LENGTH];
int dam;
if (!ch || !bld)
return;
if (!(weapon = GET_EQ(ch, WEAR_WIELD)))
{
send_to_char("You cannot damage a building with your bare hands.\r\n", ch);
return;
}
if (GET_OBJ_TYPE(weapon) != ITEM_WEAPON)
{
send_to_char("Using a weapon would surely help.\r\n", ch);
return;
}
// calc damage
dam = GET_REAL_DAMROLL(ch);
dam += dice(GET_OBJ_VAL(weapon, 1), GET_OBJ_VAL(weapon, 2));
// subtract building defense
dam -= bld->curr_val.defense;
// damage goes from 0 to 100
dam = URANGE(0, dam, 100);
// check for damaging the weapon used
check_damage_obj(ch, weapon, 8);
/* no damage done */
if (!dam)
{
// message to attacker
act("You strike $b, but make no damages.", FALSE, ch, NULL, bld, TO_CHAR);
// message to room
act("$n strikes $b but nothing happens.", FALSE, ch, NULL, bld, TO_ROOM);
/*
* some buildings can auto-respond to attacks..
* ie: towers have npc archers which fires upon attacking ppl
*/
if (bld->curr_val.npc_attack)
{
damage(ch, ch, bld->curr_val.npc_attack, -1);
act("You are hit by arrows fired at you from $b.", FALSE, ch, NULL, bld, TO_CHAR);
act("$n is being hit by arrows fired at $m from $b.", FALSE, ch, NULL, bld, TO_ROOM);
}
return;
}
/* damage the building */
// if 0 the building has been destroyed
if (!damage_building(bld, dam))
{
// message to attacker
act("Your attack DESTROY $b.", FALSE, ch, NULL, bld, TO_CHAR);
// message to room
act("$n DESTROYS $b with $s attack.", FALSE, ch, NULL, bld, TO_ROOM);
return;
}
// message to attacker
sprintf(dbuf, "You strike $b, causing %d damages.", dam);
act(dbuf, FALSE, ch, NULL, bld, TO_CHAR);
// message to room
act("$n strike $b, causing some damage.", FALSE, ch, NULL, bld, TO_ROOM);
/*
* some buildings can auto-respond to attacks..
* ie: towers could have npc archers which fires upon attacking ppl
*/
if (bld->curr_val.npc_attack)
{
damage(ch, ch, bld->curr_val.npc_attack, -1);
act("You are hit by arrows fired at you from $b.", FALSE, ch, NULL, bld, TO_CHAR);
act("$n is being hit by arrows fired at $m from $b.", FALSE, ch, NULL, bld, TO_ROOM);
}
/*
* some buildings, in response of an attack,
* can "generate" mobs to fight the attacker
*/
if (bld->curr_val.mob_attack > 0)
{
CHAR_DATA *mob = get_bld_defmob(bld);
if (mob)
{
bld->curr_val.mob_attack--;
// message to vict
sprintf(dbuf, "$N exit from %s and attacks you.", bld->description);
act(dbuf, FALSE, ch, NULL, mob, TO_CHAR);
// message to room
sprintf(dbuf, "$N exit from %s and attacks $n.", bld->description);
act(dbuf, FALSE, ch, NULL, mob, TO_ROOM);
char_to_room(mob, ch->in_room);
hit(mob, ch, -1);
}
}
}
/* one single attack to a building */
bool attack_building(CHAR_DATA *ch, char *arg)
{
BUILDING_DATA *bld;
if (!*arg)
return (FALSE);
if (!(bld = find_building_in_room_by_name(ch->in_room, arg)))
return (FALSE);
if (BUILDING_FLAGGED(bld, BLD_F_RUIN))
{
ch_printf(ch, "%s %s has already been destroyed.\r\n",
AN(bld->type->name), bld->type->name);
return (TRUE);
}
hit_building(ch, bld);
return (TRUE);
}
/* ============================================================================ */
/* AUTHORIZE Code */
/* ============================================================================ */
AUTH_DATA *get_ship_auth( SHIP_DATA *ship, long idnum );
void auth_aboard( SHIP_DATA *ship, CHAR_DATA *ch, CHAR_DATA *vict, int mode );
ACMD(do_authorize)
{
BUILDING_DATA *pBld = NULL;
SHIP_DATA *pShip = NULL;
AUTH_DATA *bAuthList = NULL, *bAuth = NULL;
CHAR_DATA *vict;
char arg[MAX_INPUT_LENGTH], sbuf[MAX_STRING_LENGTH];
if (!ch) return;
if (!(pBld = ch->in_building) && !(pShip = ch->in_ship))
{
send_to_char("You can use this command only when inside a building or aboard a ship.\r\n", ch);
return;
}
argument = one_argument(argument, arg);
if (!*arg)
{
send_to_char(
"Usage:\r\n"
"-------------------------------------------------------------\r\n"
"authorize list show list of authorized people\r\n"
"authorize <name> set or revoke authorization to player 'name'\r\n"
"-------------------------------------------------------------\r\n"
, ch);
return;
}
if (!str_cmp(arg, "list"))
{
if (pBld)
{
if (!can_enter_bld(ch, pBld, TRUE))
{
send_to_char("You have no rights, go away.\r\n", ch);
return;
}
bAuthList = pBld->auth;
}
else if (pShip)
{
if (GET_IDNUM(ch) != pShip->idcaptain && GET_IDNUM(ch) != pShip->idowner)
{
send_to_char("You must be the captain or the owner to authorize people.\r\n", ch );
return;
}
bAuthList = pShip->authorized;
}
else
bAuthList = NULL;
if (!bAuthList)
{
send_to_char("No one is authorized.\r\n", ch);
return;
}
strcpy(sbuf, "List of authorized people:\r\n");
for (bAuth = bAuthList; bAuth; bAuth = bAuth->next)
sprintf(sbuf + strlen(sbuf), "%s\r\n", bAuth->name);
page_string(ch->desc, sbuf, 0);
return;
}
if (pBld)
{
if (!(vict = get_player_vis(ch, arg, NULL, FIND_CHAR_WORLD)))
{
ch_printf(ch, "No one called '%' is in the game at the moment.\r\n", arg);
return;
}
/* new introduction system */
if ( !is_char_known(ch, vict) )
{
send_to_char("You cannot authorize someone you don't know.\r\n", ch );
return;
}
if (!can_enter_bld(ch, pBld, TRUE))
{
send_to_char("You have no rights, go away.\r\n", ch);
return;
}
if (get_bld_auth(pBld, GET_IDNUM(vict)))
auth_enter(pBld, ch, vict, 0);
else
auth_enter(pBld, ch, vict, 1);
}
else if (pShip)
{
ROOM_DATA *pRoom;
if (!SHIP_FLAGGED(pShip, SHIP_IN_PORT) || !(pRoom = get_wild_room(pShip->port)))
{
send_to_char("You can authorize people only when ship is at one port.\r\n", ch);
return;
}
if (!(vict = get_char_elsewhere_vis(ch, pRoom, arg, NULL)))
{
ch_printf( ch, "No one called '%s' is in the port.\r\n", arg );
return;
}
/* new introduction system */
if (!is_char_known(ch, vict))
{
send_to_char("You cannot authorize someone you don't know.\r\n", ch );
return;
}
if (GET_IDNUM(ch) != pShip->idcaptain && GET_IDNUM(ch) != pShip->idowner)
{
send_to_char("You must be the captain or the owner to authorize people.\r\n", ch );
return;
}
/* toggle authorization */
if (get_ship_auth(pShip, GET_IDNUM(vict)))
auth_aboard(pShip, ch, vict, 0);
else
auth_aboard(pShip, ch, vict, 1);
}
}