/* ************************************************************************
* File: building.c EmpireMUD AD 1.0 *
* Usage: Miscellaneous player-level commands *
* *
* All rights reserved. See license.doc for complete information. *
* *
* Code base by Paul Clarke. EmpireMUD Project, a tbgMUD Production. *
* Based upon CircleMUD 3.0, beta patch level 17, by Jeremy Elson. *
* *
* Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University *
* CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. *
************************************************************************ */
/*
* Paul's Thoughts:
* - sector checks should be standardized so they can be done through one
* function. this also cleans up adding new sect flags
*/
#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 "empire.h"
#include "skills.h"
#include "vnums.h"
/* extern variables */
extern bool can_claim(Creature ch);
extern int last_action_rotation;
extern int rev_dir[];
extern const char *dirs[];
#define CLEAR_FIELD(r) ((SECT(r) == SECT_ROAD && world[r].type == 0 && world[r].type2 == 0) || SECT(r) == SECT_SEEDED || SECT(r) == SECT_FIELD)
#define CLEAR_BRIDGE(r) ((SECT(r) == SECT_ROAD && world[r].type == 1 && world[r].type2 == -1) && IS_COMPLETE(r))
#define CLEAR_DESERT(r) ((SECT(r) == SECT_ROAD && world[r].type == 0 && world[r].type2 == 1) || SECT(r) == SECT_DESERT)
/* Terrain flags */
#define BUILD_NONE -1
#define BUILD_WATER (1 << 0)
#define BUILD_FIELD (1 << 1)
#define BUILD_MOUNTAIN (1 << 2)
#define BUILD_FOREST (1 << 3)
#define BUILD_DESERT (1 << 4)
#define BUILD_RIVER (1 << 5)
#define BUILD_TUNNEL (1 << 6)
#define BUILD_BRIDGE (1 << 7)
/* For find_building_list_entry */
#define FIND_BUILD_NORMAL 0
#define FIND_BUILD_UPGRADE 1
#define MAX_MONUMENT_SIZE 5
/* This prevents structures from trying to face the wrong way */
#define SINGLE_SPARE {{-1}}
#define NORTH_ONLY_SPARE SINGLE_SPARE, SINGLE_SPARE, SINGLE_SPARE
#define SIMPLE_MAP(sect) {{{(sect)}}, NORTH_ONLY_SPARE}
#define HENGE_MAP { \
{ /* North-facing */ \
{ MONUMENT_O_HENGE_UL, MONUMENT_O_HENGE_UR }, \
{ MONUMENT_O_HENGE_LL, MONUMENT_O_HENGE_LR } \
}, \
NORTH_ONLY_SPARE \
}
#define TEMPLE_MAP { \
{ /* North-facing */ \
{ MONUMENT_C_TEMPLE_UL, MONUMENT_C_TEMPLE_UR }, \
{ MONUMENT_C_TEMPLE_LL, MONUMENT_C_TEMPLE_LR } \
}, \
NORTH_ONLY_SPARE \
}
#define HIGHTEMPLE_MAP { \
{ /* North-facing */ \
{ MONUMENT_C_HIGHTEMPLE_UL, MONUMENT_C_HIGHTEMPLE_UC, MONUMENT_C_HIGHTEMPLE_UR }, \
{ MONUMENT_C_HIGHTEMPLE_CL, MONUMENT_C_HIGHTEMPLE_CC, MONUMENT_C_HIGHTEMPLE_CR }, \
{ MONUMENT_C_HIGHTEMPLE_LL, MONUMENT_C_HIGHTEMPLE_LC, MONUMENT_C_HIGHTEMPLE_LR } \
}, \
NORTH_ONLY_SPARE \
}
#define FORT_MAP { \
{ /* North-facing */ \
{ MULTI_UL_DOOR, MULTI_UR }, \
{ MULTI_LL, MULTI_LR } \
}, \
/* East */ SINGLE_SPARE, \
{ /* South-facing */ \
{ MULTI_UL, MULTI_UR }, \
{ MULTI_LL, MULTI_LR_DOOR } \
}, \
/* West */ SINGLE_SPARE \
}
#define CASTLE_MAP { \
{ /* North-facing */ \
{ MULTI_UL, MULTI_HORIZ_DOOR, MULTI_UR }, \
{ MULTI_VERT_L, MULTI_CENTER, MULTI_VERT_R }, \
{ MULTI_LL, MULTI_HORIZ, MULTI_LR } \
}, \
{ /* East-facing */ \
{ MULTI_UL, MULTI_HORIZ, MULTI_UR }, \
{ MULTI_VERT_L, MULTI_CENTER, MULTI_VERT_DOOR_R }, \
{ MULTI_LL, MULTI_HORIZ, MULTI_LR } \
}, \
{ /* South-facing */ \
{ MULTI_UL, MULTI_HORIZ, MULTI_UR }, \
{ MULTI_VERT_L, MULTI_CENTER, MULTI_VERT_R }, \
{ MULTI_LL, MULTI_HORIZ_DOOR, MULTI_LR } \
}, \
{ /* West-facing */ \
{ MULTI_UL, MULTI_HORIZ, MULTI_UR }, \
{ MULTI_VERT_DOOR_L,MULTI_CENTER, MULTI_VERT_R }, \
{ MULTI_LL, MULTI_HORIZ, MULTI_LR } \
} \
}
#define PYRAMID_MAP { \
{ /* North-facing */ \
{ MONUMENT_C_PYRAMID_CORNER_L, MONUMENT_C_PYRAMID_HORIZ_DOOR, MONUMENT_C_PYRAMID_HORIZ, MONUMENT_C_PYRAMID_CORNER_R }, \
{ MONUMENT_C_PYRAMID_VERT_L, MONUMENT_C_PYRAMID_CENTER_UL, MONUMENT_C_PYRAMID_CENTER_UR, MONUMENT_C_PYRAMID_VERT_R }, \
{ MONUMENT_C_PYRAMID_VERT_L, MONUMENT_C_PYRAMID_CENTER_LL, MONUMENT_C_PYRAMID_CENTER_LR, MONUMENT_C_PYRAMID_VERT_R }, \
{ MONUMENT_C_PYRAMID_CORNER_L, MONUMENT_C_PYRAMID_HORIZ, MONUMENT_C_PYRAMID_HORIZ, MONUMENT_C_PYRAMID_CORNER_R } \
}, \
{ /* East-facing */ \
{ MONUMENT_C_PYRAMID_CORNER_L, MONUMENT_C_PYRAMID_HORIZ, MONUMENT_C_PYRAMID_HORIZ, MONUMENT_C_PYRAMID_CORNER_R }, \
{ MONUMENT_C_PYRAMID_VERT_L, MONUMENT_C_PYRAMID_CENTER_UL, MONUMENT_C_PYRAMID_CENTER_UR, MONUMENT_C_PYRAMID_VERT_DOOR_R }, \
{ MONUMENT_C_PYRAMID_VERT_L, MONUMENT_C_PYRAMID_CENTER_LL, MONUMENT_C_PYRAMID_CENTER_LR, MONUMENT_C_PYRAMID_VERT_R }, \
{ MONUMENT_C_PYRAMID_CORNER_L, MONUMENT_C_PYRAMID_HORIZ, MONUMENT_C_PYRAMID_HORIZ, MONUMENT_C_PYRAMID_CORNER_R } \
}, \
{ /* South-facing */ \
{ MONUMENT_C_PYRAMID_CORNER_L, MONUMENT_C_PYRAMID_HORIZ, MONUMENT_C_PYRAMID_HORIZ, MONUMENT_C_PYRAMID_CORNER_R }, \
{ MONUMENT_C_PYRAMID_VERT_L, MONUMENT_C_PYRAMID_CENTER_UL, MONUMENT_C_PYRAMID_CENTER_UR, MONUMENT_C_PYRAMID_VERT_R }, \
{ MONUMENT_C_PYRAMID_VERT_L, MONUMENT_C_PYRAMID_CENTER_LL, MONUMENT_C_PYRAMID_CENTER_LR, MONUMENT_C_PYRAMID_VERT_R }, \
{ MONUMENT_C_PYRAMID_CORNER_L, MONUMENT_C_PYRAMID_HORIZ, MONUMENT_C_PYRAMID_HORIZ_DOOR, MONUMENT_C_PYRAMID_CORNER_R } \
}, \
{ /* West-facing */ \
{ MONUMENT_C_PYRAMID_CORNER_L, MONUMENT_C_PYRAMID_HORIZ, MONUMENT_C_PYRAMID_HORIZ, MONUMENT_C_PYRAMID_CORNER_R }, \
{ MONUMENT_C_PYRAMID_VERT_L, MONUMENT_C_PYRAMID_CENTER_UL, MONUMENT_C_PYRAMID_CENTER_UR, MONUMENT_C_PYRAMID_VERT_R }, \
{ MONUMENT_C_PYRAMID_VERT_DOOR_L,MONUMENT_C_PYRAMID_CENTER_LL, MONUMENT_C_PYRAMID_CENTER_LR, MONUMENT_C_PYRAMID_VERT_R }, \
{ MONUMENT_C_PYRAMID_CORNER_L, MONUMENT_C_PYRAMID_HORIZ, MONUMENT_C_PYRAMID_HORIZ, MONUMENT_C_PYRAMID_CORNER_R } \
} \
}
/* Buildings with name "upgrade" won't trigger dismantle, and can't be built */
#define BUILD_UPGRADE "Upgrade"
/* Buildings with the name "dismantle" can't be built */
#define BUILD_DISMANTLE "Dismantle"
#define BUILD_LINE_BREAK { "\t", 0, 0, 0, 0, 0, 0, SIMPLE_MAP(-1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
#define BUILD_LAST_ENTRY { "\n", 0, 0, 0, 0, 0, 0, SIMPLE_MAP(-1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
struct build_data_structure {
char *name;
int special;
bool closed;
int height, width;
int sect, type2;
int map[NUM_SIMPLE_DIRS][MAX_MONUMENT_SIZE][MAX_MONUMENT_SIZE];
int built_on, facing, reverse;
int science, leadership, intelligence;
int sticks, logs, rocks, iron;
int max_rooms, designate_flags, base_affects;
} build[] = {
/*
* "name", special processing #, closed?, height (tiles), width (tiles),
* map (see below), build sects,
* leadership, intelligence,
* sticks, logs, rocks, iron
*
* Special Processing:
* -1: no special processing
* 0: required person to dedicate to
* 1: face a direction but don't change map
* 2: face a direction and use the direction map
* 3: it's a well
*
* Maps:
* These are used to map out the tiles of any monument from 1x1 to
* MAX_MONUMENT_SIZExMAX_MONUMENT_SIZE.
*/
/* Simple Field buildings */
{ "hut", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_HUT),
BUILD_FIELD, BUILD_FIELD, -1,
1, 0, 1,
30, 0, 0, 0,
0, 0, 0 },
{ "cabin", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_CABIN),
BUILD_FIELD, BUILD_FIELD, -1,
1, 0, 1,
0, 12, 0, 0,
0, 0, 0 },
{ "house", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_HOUSE),
BUILD_FIELD, BUILD_FIELD, -1,
1, 0, 1,
0, 20, 0, 0,
2, 0, 0 },
{ "househaven", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_HAVEN_HOUSE),
BUILD_FIELD, BUILD_FIELD, -1,
6, 0, 5,
0, 20, 20, 0,
3, 0, 0 },
{ "well", 3, 0, 1, 1,
SECT_WELL, -1, SIMPLE_MAP(0),
BUILD_FIELD, -1, -1,
2, 0, 1,
5, 1, 20, 0,
0, 0, 0 },
{ "stonehouse", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_STONE_HOUSE),
BUILD_FIELD, BUILD_FIELD, -1,
2, 0, 1,
0, 20, 20, 0,
3, 0, 0 },
{ "largehouse", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_LARGE_HOUSE),
BUILD_FIELD, BUILD_FIELD, -1,
2, 0, 2,
0, 40, 40, 0,
5, 0, 0 },
{ "baths", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_BATHS),
BUILD_FIELD, BUILD_FIELD, -1,
3, 0, 3,
30, 8, 40, 0,
0, 0, 0 },
{ "fountain", -1, 0, 1, 1,
SECT_FOUNTAIN, -1, SIMPLE_MAP(0),
BUILD_FIELD, -1, -1,
4, 0, 3,
30, 4, 40, 0,
0, 0, 0 },
{ "fort", 2, 1, 2, 2,
SECT_MULTI, 0, FORT_MAP,
BUILD_FIELD, BUILD_FIELD, -1,
4, 1, 4,
0, 100, 100, 60,
20, DES_FORGE | DES_ARMORY, 0 },
{ "castle", 2, 1, 3, 3,
SECT_MULTI, 0, CASTLE_MAP,
BUILD_FIELD, BUILD_FIELD, -1,
5, 2, 4,
0, 150, 200, 135,
40, DES_FORGE | DES_ARMORY | DES_GREATHALL | DES_THRONE | DES_VAULT | DES_BATHS, 0 },
BUILD_LINE_BREAK,
/* Desert Buildings */
{ "mudhut", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_MUD_HUT),
BUILD_DESERT, BUILD_DESERT, -1,
1, 0, 1,
0, 1, 20, 0,
0, 0, 0 },
{ "pueblo", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_PUEBLO),
BUILD_DESERT, BUILD_DESERT, -1,
2, 0, 2,
0, 12, 40, 0,
2, 0, 0 },
{ "pueblohaven", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_HAVEN_PUEBLO),
BUILD_DESERT, BUILD_DESERT, -1,
6, 0, 5,
0, 12, 40, 0,
3, 0, 0 },
{ "undergroundcomplex", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_UNDERGROUND_COMPLEX),
BUILD_DESERT, BUILD_DESERT, -1,
4, 0, 3,
40, 120, 0, 100,
25, DES_NO_HALL | DES_TUNNEL, ROOM_AFF_CHAMELEON_DESERT },
{ "greathouse", 2, 1, 2, 2,
SECT_MULTI, 2, FORT_MAP,
BUILD_DESERT, BUILD_DESERT, -1,
4, 1, 4,
0, 40, 250, 60,
20, DES_FORGE | DES_ARMORY, 0 },
{ "palace", 2, 1, 3, 3,
SECT_MULTI, 2, CASTLE_MAP,
BUILD_DESERT, BUILD_DESERT, -1,
5, 2, 5,
0, 100, 250, 120,
40, DES_FORGE | DES_ARMORY | DES_GREATHALL | DES_THRONE | DES_VAULT | DES_BATHS, 0 },
BUILD_LINE_BREAK,
/* Tree Buildings */
{ "treehouse", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_TREE_COMPLEX),
BUILD_FOREST, BUILD_FOREST, -1,
2, 0, 3,
30, 3, 0, 0,
0, DES_SKYBRIDGE, ROOM_AFF_CHAMELEON_FOREST },
/*{ "treecomplex", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_TREE_COMPLEX),
BUILD_FOREST, BUILD_FOREST, -1,
3, 0, 4,
30, 40, 0, 5,
3, DES_SKYBRIDGE, ROOM_AFF_CHAMELEON_FOREST },*/
{ "treefort", 2, 1, 2, 2,
SECT_MULTI, 1, FORT_MAP,
BUILD_FOREST, BUILD_FOREST, -1,
4, 1, 4,
250, 30, 0, 40,
20, DES_FORGE | DES_ARMORY | DES_SKYBRIDGE, ROOM_AFF_CHAMELEON_FOREST },
{ "burrowhaven", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_HAVEN_BURROW),
BUILD_FOREST, BUILD_FOREST, -1,
6, 0, 5,
0, 20, 20, 0,
3, DES_NO_HALL | DES_TUNNEL, 0 },
BUILD_LINE_BREAK,
/* Mountain buildings */
{ "mine", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_MINE),
BUILD_MOUNTAIN, BUILD_MOUNTAIN | BUILD_FIELD | BUILD_DESERT, -1,
1, 0, 2,
0, 14, 0, 0,
0, 0, 0 },
{ "cliffdwelling", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_CLIFF_DWELLING),
BUILD_MOUNTAIN, BUILD_MOUNTAIN | BUILD_FIELD | BUILD_DESERT, -1,
2, 0, 2,
5, 20, 30, 0,
3, 0, 0 },
{ "cavehaven", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_HAVEN_CAVE),
BUILD_MOUNTAIN, BUILD_MOUNTAIN, -1,
6, 0, 5,
0, 20, 0, 0,
3, DES_TUNNEL | DES_NO_HALL, ROOM_AFF_CHAMELEON_MOUNTAIN },
{ "tunnel", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_TUNNEL),
BUILD_MOUNTAIN, BUILD_FIELD | BUILD_DESERT | BUILD_TUNNEL, BUILD_MOUNTAIN | BUILD_TUNNEL,
2, 0, 3,
0, 20, 0, 0,
0, 0, 0 },
/* tunnel upgrade */
{ BUILD_UPGRADE, 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_TUNNEL2),
SECT_BUILDING, BUILDING_TUNNEL, -1,
4, 0, 3,
0, 20, 0, 0,
0, 0, 0 },
/* tunnel2 dismantle */
{ BUILD_DISMANTLE, 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_TUNNEL2),
BUILD_MOUNTAIN, BUILD_FIELD | BUILD_DESERT | BUILD_TUNNEL, BUILD_MOUNTAIN | BUILD_TUNNEL,
4, 0, 3,
0, 40, 0, 0,
0, 0, 0 },
{ "mountainoutpost", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_MOUNTAIN_OUTPOST),
BUILD_MOUNTAIN, BUILD_MOUNTAIN, -1,
3, 0, 2,
30, 4, 20, 0,
0, 0, 0 },
{ "minecomplex", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_MINE_COMPLEX),
BUILD_MOUNTAIN, BUILD_MOUNTAIN | BUILD_FIELD | BUILD_DESERT, -1,
4, 0, 4,
30, 120, 0, 20,
25, DES_NO_HALL | DES_TUNNEL, 0 },
BUILD_LINE_BREAK,
/* Guard Towers */
{ "guardtower", 1, 1, 1, 1,
SECT_BUILDING, 0, SIMPLE_MAP(BUILDING_GUARD_TOWER),
BUILD_FIELD, BUILD_FIELD, -1,
3, 0, 3,
30, 4, 0, 0,
0, 0, 0 },
/* guard tower upgrade 1 */
{ BUILD_UPGRADE, 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_GUARD_TOWER2),
SECT_BUILDING, BUILDING_GUARD_TOWER, -1,
4, 0, 4,
30, 4, 0, 20,
0, 0, 0 },
/* guard tower 2 dismantle */
{ BUILD_DISMANTLE, 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_GUARD_TOWER2),
BUILD_FIELD | BUILD_DESERT, BUILD_FIELD | BUILD_DESERT, -1,
4, 0, 4,
60, 8, 0, 20,
0, 0, 0 },
/* guard tower upgrade 2 */
{ BUILD_UPGRADE, 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_GUARD_TOWER3),
SECT_BUILDING, BUILDING_GUARD_TOWER2, -1,
5, 0, 5,
30, 4, 0, 40,
0, 0, 0 },
/* guard tower 3 dismantle */
{ BUILD_DISMANTLE, 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_GUARD_TOWER3),
BUILD_FIELD | BUILD_DESERT, BUILD_FIELD | BUILD_DESERT, -1,
5, 0, 5,
90, 12, 0, 60,
0, 0, 0 },
{ "sentry", 1, 1, 1, 1,
SECT_BUILDING, 2, SIMPLE_MAP(BUILDING_GUARD_TOWER),
BUILD_DESERT, BUILD_DESERT, -1,
3, 0, 3,
30, 4, 0, 0,
0, 0, 0 },
{ "watchtower", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_WATCH_TOWER),
BUILD_FOREST, BUILD_FOREST, -1,
3, 0, 4,
30, 4, 0, 20,
0, 0, ROOM_AFF_CHAMELEON_FOREST },
BUILD_LINE_BREAK,
/* Barriers */
{ "fence", -1, 0, 1, 1,
SECT_BARRIER, 0, SIMPLE_MAP(0),
BUILD_FIELD, BUILD_FIELD, -1,
1, 0, 1,
20, 0, 0, 0,
0, 0, 0 },
{ "trellis", -1, 0, 1, 1,
SECT_BARRIER, 1, SIMPLE_MAP(0),
BUILD_FOREST, BUILD_FOREST, -1,
2, 0, 1,
20, 0, 0, 0,
0, 0, ROOM_AFF_CHAMELEON_FOREST },
{ "spikedbarrier", -1, 0, 1, 1,
SECT_BARRIER, 2, SIMPLE_MAP(0),
BUILD_DESERT, BUILD_DESERT, -1,
1, 0, 1,
20, 0, 0, 0,
0, 0, 0 },
{ "wall", -1, 0, 1, 1,
SECT_BARRIER, 0, SIMPLE_MAP(1),
BUILD_FIELD, BUILD_FIELD, -1,
3, 0, 1,
0, 0, 20, 0,
0, 0, 0 },
{ "palisade", -1, 0, 1, 1,
SECT_BARRIER, 1, SIMPLE_MAP(1),
BUILD_FOREST, BUILD_FOREST, -1,
4, 0, 1,
0, 0, 20, 0,
0, 0, ROOM_AFF_CHAMELEON_FOREST },
{ "adobewall", -1, 0, 1, 1,
SECT_BARRIER, 2, SIMPLE_MAP(1),
BUILD_DESERT, BUILD_DESERT, -1,
3, 0, 1,
0, 0, 20, 0,
0, 0, 0 },
{ "gatehouse", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_GATEHOUSE),
BUILD_FIELD | BUILD_DESERT, BUILD_FIELD | BUILD_DESERT, BUILD_FIELD | BUILD_DESERT,
2, 0, 2,
30, 4, 20, 0,
0, 0, 0 },
BUILD_LINE_BREAK,
/* Specialized Buildings */
{ "baker", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_BAKER),
BUILD_FIELD | BUILD_DESERT, BUILD_FIELD | BUILD_DESERT, -1,
2, 0, 3,
0, 25, 30, 8,
0, 0, 0 },
{ "carpenter", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_CARPENTER),
BUILD_FIELD | BUILD_DESERT, BUILD_FIELD | BUILD_DESERT, -1,
3, 0, 3,
20, 40, 10, 10,
0, 0, 0 },
{ "forge", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_FORGE),
BUILD_FIELD | BUILD_DESERT, BUILD_FIELD | BUILD_DESERT, -1,
3, 0, 3,
0, 20, 30, 50,
0, 0, 0 },
{ "glassworker", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_GLASS),
BUILD_FIELD | BUILD_DESERT, BUILD_FIELD | BUILD_DESERT, -1,
3, 0, 3,
0, 20, 30, 8,
0, 0, 0 },
{ "mill", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_MILL),
BUILD_FIELD | BUILD_DESERT, BUILD_FIELD | BUILD_DESERT, -1,
2, 0, 3,
0, 20, 60, 0,
0, 0, 0 },
{ "potter", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_POTTER),
BUILD_FIELD | BUILD_DESERT, BUILD_FIELD | BUILD_DESERT, -1,
3, 0, 3,
0, 20, 20, 10,
0, 0, 0 },
{ "stable", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_STABLE),
BUILD_FIELD | BUILD_DESERT, BUILD_FIELD | BUILD_DESERT, -1,
2, 0, 3,
0, 60, 0, 20,
0, 0, 0 },
BUILD_LINE_BREAK,
/* Water Specialized Buildings */
{ "bridge", -1, 0, 1, 1,
SECT_ROAD, -1, SIMPLE_MAP(1),
BUILD_RIVER, -1, -1,
3, 0, 3,
30, 16, 20, 0,
0, 0, 0 },
{ "docks", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_DOCKS),
BUILD_FIELD | BUILD_DESERT, BUILD_WATER, BUILD_FIELD | BUILD_DESERT,
3, 0, 2,
0, 40, 0, 0,
0, 0, 0 },
{ "shipyard", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_SHIPYARD),
BUILD_FIELD | BUILD_DESERT, BUILD_WATER, BUILD_FIELD | BUILD_DESERT,
3, 0, 3,
0, 50, 30, 0,
0, 0, 0 },
/* shipyard upgrade */
{ BUILD_UPGRADE, 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_SHIPYARD2),
SECT_BUILDING, BUILDING_SHIPYARD, -1,
4, 0, 3,
0, 75, 0, 35,
0, 0, 0 },
/* shipyard2 dismantle */
{ BUILD_DISMANTLE, 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_SHIPYARD2),
BUILD_FIELD | BUILD_DESERT, BUILD_WATER, BUILD_FIELD | BUILD_DESERT,
4, 0, 3,
0, 125, 30, 35,
0, 0, 0 },
BUILD_LINE_BREAK,
/* Storage Buildings */
{ "apiary", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_APIARY),
BUILD_FIELD, BUILD_FIELD, -1,
2, 0, 2,
0, 20, 0, 0,
0, 0, 0 },
{ "arsenal", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_ARSENAL),
BUILD_FIELD | BUILD_DESERT, BUILD_FIELD | BUILD_DESERT, -1,
1, 0, 1,
0, 20, 0, 0,
0, 0, 0 },
{ "cannery", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_CANNERY),
BUILD_FIELD | BUILD_DESERT, BUILD_FIELD | BUILD_DESERT, -1,
1, 0, 1,
0, 20, 0, 0,
0, 0, 0 },
{ "foundry", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_FOUNDRY),
BUILD_FIELD | BUILD_DESERT, BUILD_FIELD | BUILD_DESERT, -1,
1, 0, 1,
0, 20, 0, 0,
0, 0, 0 },
{ "granary", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_GRANARY),
BUILD_FIELD | BUILD_DESERT, BUILD_FIELD | BUILD_DESERT, -1,
1, 0, 1,
0, 20, 0, 0,
0, 0, 0 },
{ "gravelpit", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_GRAVEL_PIT),
BUILD_FIELD | BUILD_DESERT, BUILD_FIELD | BUILD_DESERT, -1,
1, 0, 1,
20, 0, 0, 0,
0, 0, 0 },
{ "lumberyard", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_LUMBER_YARD),
BUILD_FIELD | BUILD_DESERT, BUILD_FIELD | BUILD_DESERT, -1,
1, 0, 1,
20, 0, 0, 0,
0, 0, 0 },
{ "tannery", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_TANNERY),
BUILD_FIELD | BUILD_DESERT, BUILD_FIELD | BUILD_DESERT, -1,
1, 0, 1,
0, 20, 0, 0,
0, 0, 0 },
{ "utilityshed", 1, 1, 1, 1,
SECT_BUILDING, -1, SIMPLE_MAP(BUILDING_TOOLS),
BUILD_FIELD | BUILD_DESERT, BUILD_FIELD | BUILD_DESERT, -1,
2, 0, 2,
0, 20, 0, 0,
0, 0, 0 },
BUILD_LINE_BREAK,
/* Monuments: Open */
{ "statue", 0, 0, 1, 1,
SECT_MONUMENT_OPEN, -1, SIMPLE_MAP(MONUMENT_O_STATUE),
BUILD_FIELD | BUILD_DESERT, -1, -1,
0, 3, 1,
0, 80, 100, 0,
0, 0, 0 },
/* henge dismantles */
{ BUILD_DISMANTLE, -1, 0, 1, 1,
SECT_MONUMENT_OPEN, -1, SIMPLE_MAP(MONUMENT_O_HENGE_UL),
BUILD_FIELD | BUILD_DESERT, -1, -1,
0, 0, 3,
0, 0, 100, 0,
0, 0, 0 },
{ BUILD_DISMANTLE, -1, 0, 1, 1,
SECT_MONUMENT_OPEN, -1, SIMPLE_MAP(MONUMENT_O_HENGE_UR),
BUILD_FIELD | BUILD_DESERT, -1, -1,
0, 0, 3,
0, 0, 100, 0,
0, 0, 0 },
{ BUILD_DISMANTLE, -1, 0, 1, 1,
SECT_MONUMENT_OPEN, -1, SIMPLE_MAP(MONUMENT_O_HENGE_LL),
BUILD_FIELD | BUILD_DESERT, -1, -1,
0, 0, 3,
0, 0, 100, 0,
0, 0, 0 },
{ BUILD_DISMANTLE, -1, 0, 1, 1,
SECT_MONUMENT_OPEN, -1, SIMPLE_MAP(MONUMENT_O_HENGE_LR),
BUILD_FIELD | BUILD_DESERT, -1, -1,
0, 0, 3,
0, 0, 100, 0,
0, 0, 0 },
{ "henge", -1, 0, 2, 2,
SECT_MONUMENT_OPEN, -1, HENGE_MAP,
BUILD_FIELD | BUILD_DESERT, -1, -1,
0, 3, 3,
0, 0, 100, 0,
0, 0, 0 },
{ "megalith", -1, 0, 1, 1,
SECT_MONUMENT_OPEN, -1, SIMPLE_MAP(MONUMENT_O_MEGALITH),
BUILD_FIELD | BUILD_DESERT, -1, -1,
0, 3, 2,
0, 80, 250, 0,
0, 0, 0 },
{ "cemetary", -1, 0, 1, 1,
SECT_MONUMENT_OPEN, -1, SIMPLE_MAP(MONUMENT_O_CEMETARY),
BUILD_FIELD, -1, -1,
0, 3, 1,
0, 0, 100, 0,
0, 0, 0 },
{ "park", -1, 0, 1, 1,
SECT_MONUMENT_OPEN, -1, SIMPLE_MAP(MONUMENT_O_PARK),
BUILD_FIELD, -1, -1,
0, 3, 2,
25, 20, 0, 0,
0, 0, 0 },
BUILD_LINE_BREAK,
/* Monuments: Closed */
{ "tomb", 1, 1, 1, 1,
SECT_MONUMENT_CLOSED, -1, SIMPLE_MAP(MONUMENT_C_TOMB),
BUILD_FIELD | BUILD_DESERT, BUILD_FIELD | BUILD_DESERT, -1,
0, 4, 3,
0, 20, 30, 0,
0, 0, 0 },
{ "shrine", 0, 1, 1, 1,
SECT_MONUMENT_CLOSED, -1, SIMPLE_MAP(MONUMENT_C_SHRINE),
BUILD_FIELD | BUILD_DESERT, BUILD_FIELD | BUILD_DESERT, -1,
0, 3, 2,
60, 4, 20, 0,
0, 0, 0 },
{ "temple", 0, 1, 2, 2,
SECT_MONUMENT_CLOSED, -1, TEMPLE_MAP,
BUILD_FIELD | BUILD_DESERT, BUILD_FIELD | BUILD_DESERT, -1,
0, 4, 3,
40, 40, 80, 0,
0, 0, 0 },
{ "hightemple", 0, 1, 3, 3,
SECT_MONUMENT_CLOSED, -1, HIGHTEMPLE_MAP,
BUILD_FIELD | BUILD_DESERT, BUILD_FIELD | BUILD_DESERT, -1,
0, 5, 4,
80, 80, 200, 0,
0, 0, 0 },
{ "pyramid", 2, 1, 4, 4,
SECT_MONUMENT_CLOSED, -1, PYRAMID_MAP,
BUILD_DESERT, BUILD_DESERT, -1,
0, 5, 5,
250, 250, 250, 250,
0, 0, 0 },
/* This must come last */
BUILD_LAST_ENTRY
};
int find_building_list_entry(room_rnum room, byte type) {
int i, j, x, y;
room_rnum r = HOME_ROOM(room), shift, point;
bool ok, done = FALSE;
/* find y */
for (y = 0; ; y++) {
shift = real_shift(r, y * shift_dir[NORTH][0], y * shift_dir[NORTH][1]);
if (HOME_ROOM(shift) != r) {
y--;
break;
}
}
/* find x */
for (x = 0; ; x++) {
shift = real_shift(r, x * shift_dir[WEST][0], x * shift_dir[WEST][1]);
if (HOME_ROOM(shift) != r) {
x--;
break;
}
}
/* We set up our north-west corner point.. */
point = r;
point = real_shift(point, x * shift_dir[WEST][0], x * shift_dir[WEST][1]);
point = real_shift(point, y * shift_dir[NORTH][0], y * shift_dir[NORTH][1]);
/* Error checking */
if (HOME_ROOM(point) != r) {
syslog(0, TRUE, "SYSERR: Point setup failed in find_building_list_entry!");
return -1;
}
/* Check the building map:
* - we will go through each direction that the map could face
* - we will pan from the northwest corner, comparing each sect
* - any time 'ok' was not cancelled, we will break
*/
/* Each building in the building tree */
for (i = 0; str_cmp("\n", build[i].name); i++) {
if (type == FIND_BUILD_UPGRADE && str_cmp(build[i].name, BUILD_UPGRADE))
continue;
else if (type == FIND_BUILD_NORMAL && !str_cmp(build[i].name, BUILD_UPGRADE))
continue;
/* Each possible direction */
for (j = 0, ok = TRUE; j < NUM_SIMPLE_DIRS; j++, ok = TRUE) {
/* Note: this WILL mess up if the building has no maps.. but why would it? */
if (build[i].map[j][0][0] == -1)
continue;
/* Across the width */
for (x = 0; x < build[i].width && ok; x++) {
/* Down the height */
for (y = 0; y < build[i].height && ok; y++) {
shift = point;
shift = real_shift(shift, x * shift_dir[EAST][0], x * shift_dir[EAST][1]);
shift = real_shift(shift, y * shift_dir[SOUTH][0], y * shift_dir[SOUTH][1]);
if (SECT(shift) != build[i].sect)
ok = FALSE;
if (build[i].type2 != -1 && world[shift].type2 != build[i].type2)
ok = FALSE;
if (world[shift].type != build[i].map[j][y][x])
ok = FALSE;
}
}
/* Was ok never false? */
if (ok) {
done = TRUE;
break;
}
}
/* Are we done? */
if (done)
break;
}
if (!str_cmp("\n", build[i].name))
return -1;
return i;
}
bool is_entrance(int rnum) {
int i, j;
/* A few times I call this function with NOWHERE.. easier here */
if (rnum == NOWHERE)
return FALSE;
for (i = 0; i < NUM_2D_DIRS; i++)
if (SECT((j = real_shift(rnum, shift_dir[i][0], shift_dir[i][1]))) == SECT_BUILDING || SECT((j = real_shift(rnum, shift_dir[i][0], shift_dir[i][1]))) == SECT_MONUMENT_CLOSED || SECT((j = real_shift(rnum, shift_dir[i][0], shift_dir[i][1]))) == SECT_MULTI) {
if (world[j].building_entrance == i)
return TRUE;
else if ((BUILDING_TYPE(j) == BUILDING_DOCKS || BUILDING_TYPE(j) == BUILDING_SHIPYARD || BUILDING_TYPE(j) == BUILDING_SHIPYARD2 || BUILDING_TYPE(j) == BUILDING_GATEHOUSE) && world[j].building_entrance == rev_dir[i])
return TRUE;
}
return FALSE;
}
bool build_monument_map(Creature ch, int type, int dir, room_rnum map[MAX_MONUMENT_SIZE][MAX_MONUMENT_SIZE]) {
int i, j, k;
int focus_column = ((build[type].width + 1) / 2) - 1;
/*
* This shows us how to find the focus_column in row 0
* This is shift east, shift north for a given width/height
*/
int amount_to_shift[NUM_SIMPLE_DIRS][2][MAX_MONUMENT_SIZE + 1] = {
/* North */ { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0 } },
/* East */ { { 0, 0, -1, -1, -2, -2 }, { 0, 0, 1, 1, 1, 2 } },
/* South */ { { 0, 0, -1, 0, -1, 0 }, { 0, 0, 1, 2, 3, 4 } },
/* West */ { { 0, 0, 0, 1, 1, 2 }, { 0, 0, 0, 1, 2, 2 } }
};
for (i = 0; i < MAX_MONUMENT_SIZE; i++)
for (j = 0; j < MAX_MONUMENT_SIZE; j++)
map[i][j] = NOWHERE;
/*
* Set up the primary room
* This is always the top-center or left-of-center, depending upon width
* X XO OXO OXOO OOXOO
* OO OOO OOOO OOOOO
* OOO OOOO OOOOO
* OOOO OOOOO
* OOOOO
*
* If you don't understand what it's doing, have faith
*/
/* Shift east by the appropriate amount for this width */
map[0][focus_column] = real_shift(ch->in_room, amount_to_shift[dir][0][build[type].width] * shift_dir[EAST][0], amount_to_shift[dir][0][build[type].width] * shift_dir[EAST][1]);
/* Shift north by the appropriate amount for this height */
map[0][focus_column] = real_shift(map[0][focus_column], amount_to_shift[dir][1][build[type].height] * shift_dir[NORTH][0], amount_to_shift[dir][1][build[type].height] * shift_dir[NORTH][1]);
/* Now design the top row */
for (k = 0; k < build[type].width; k++)
map[0][k] = real_shift(map[0][focus_column], (k - focus_column) * shift_dir[EAST][0], (k - focus_column) * shift_dir[EAST][1]);
/* Set up the bottom half of the map based upon the top */
for (j = 1; j < build[type].height; j++)
for (i = 0; i < build[type].width; i++)
map[j][i] = real_shift(map[0][i], j * shift_dir[SOUTH][0], j * shift_dir[SOUTH][1]);
/* Check sectors */
for (j = 0; j < build[type].height; j++)
for (i = 0; i < build[type].width; i++)
if (!CAN_USE_ROOM(ch, map[j][i], 1)) {
msg_to_char(ch, "You don't have permission to build at (%d, %d).\r\n", X_COORD(map[j][i]), Y_COORD(map[j][i]));
return FALSE;
}
else if (!((IS_SET(build[type].built_on, BUILD_FIELD) && CLEAR_FIELD(map[j][i])) || (IS_SET(build[type].built_on, BUILD_MOUNTAIN) && SECT(map[j][i]) == SECT_MOUNTAIN) || (IS_SET(build[type].built_on, BUILD_DESERT) && CLEAR_DESERT(map[j][i])) || (IS_SET(build[type].built_on, BUILD_RIVER) && SECT(map[j][i]) == SECT_RIVER) || (IS_SET(build[type].built_on, BUILD_FOREST) && SECT(map[j][i]) == SECT_FOREST_4) || (IS_SET(build[type].built_on, BUILD_WATER) && (SECT(map[j][i]) == SECT_OCEAN || SECT(map[j][i]) == SECT_RIVER)))) {
msg_to_char(ch, "You need to build on: ");
*buf = '\0';
if (IS_SET(build[type].built_on, BUILD_FIELD))
sprintf(buf + strlen(buf), "%sfield", *buf ? ", " : "");
if (IS_SET(build[type].built_on, BUILD_WATER | BUILD_RIVER))
sprintf(buf + strlen(buf), "%swater", *buf ? ", " : "");
if (IS_SET(build[type].built_on, BUILD_MOUNTAIN))
sprintf(buf + strlen(buf), "%smountain", *buf ? ", " : "");
if (IS_SET(build[type].built_on, BUILD_DESERT))
sprintf(buf + strlen(buf), "%sdesert", *buf ? ", " : "");
if (IS_SET(build[type].built_on, BUILD_FOREST))
sprintf(buf + strlen(buf), "%sforest", *buf ? ", " : "");
msg_to_char(ch, "%s (%d, %d)\r\n", buf, X_COORD(map[j][i]), Y_COORD(map[j][i]));
return FALSE;
}
else if (is_entrance(map[j][i])) {
msg_to_char(ch, "You can't build in front of the entrance at (%d, %d).\r\n", X_COORD(map[j][i]), Y_COORD(map[j][i]));
return FALSE;
}
/* The sectors are good, permission is good, it all looks good. */
return TRUE;
}
void setup_monument_resources(room_rnum room, int type) {
world[room].res.logs = build[type].logs;
world[room].res.rocks = build[type].rocks;
world[room].res.iron = build[type].iron;
world[room].res.sticks = build[type].sticks;
}
ACMD(do_build) {
room_rnum to_room = NOWHERE, to_rev = NOWHERE;
room_rnum map[MAX_MONUMENT_SIZE][MAX_MONUMENT_SIZE];
int e = -1, type = 0, map_dir = NORTH, dir = NORTH;
bool found = 0;
int i, j, c = 0;
long id = 0;
two_arguments(argument, arg, buf);
if (*arg)
for (type = 0; str_cmp(build[type].name, "\n") && (!is_abbrev(arg, build[type].name) || !str_cmp(build[type].name, BUILD_UPGRADE) || !str_cmp(build[type].name, BUILD_DISMANTLE)); type++);
if (!*arg || !str_cmp(build[type].name, "\n")) {
/* Cancel building */
if (GET_ACTION(ch) == ACT_BUILDING) {
msg_to_char(ch, "You stop building.\r\n");
act("$n stops building.", FALSE, ch, 0, 0, TO_ROOM);
GET_ACTION(ch) = ACT_NONE;
}
/* Continue building */
else if (!IS_COMPLETE(ch->in_room)) {
if (IS_DISMANTLING(ch->in_room))
msg_to_char(ch, "The building is being dismantled, you can't rebuild it now.\r\n");
else if (GET_ACTION(ch) != ACT_NONE)
msg_to_char(ch, "You're kinda busy right now.\r\n");
else {
GET_ACTION(ch) = ACT_BUILDING;
GET_ACTION_ROTATION(ch) = last_action_rotation;
GET_ACTION_ROOM(ch) = ch->in_room;
msg_to_char(ch, "You start building.\r\n");
act("$n starts building.", FALSE, ch, 0, 0, TO_ROOM);
}
}
/* Send output */
else {
msg_to_char(ch, "What type of structure are you trying to build?\r\n");
for (type = 0; str_cmp(build[type].name, "\n"); type++)
if (GET_SCIENCE(ch) >= build[type].science && GET_INTELLIGENCE(ch) >= build[type].intelligence && GET_LEADERSHIP(ch) >= build[type].leadership) {
if (!str_cmp(build[type].name, "\t")) {
if (c > 0) {
msg_to_char(ch, "\r\n");
c = 0;
}
}
else if (str_cmp(build[type].name, "\r") && str_cmp(build[type].name, BUILD_UPGRADE) && str_cmp(build[type].name, BUILD_DISMANTLE) && (++c))
msg_to_char(ch, " %s", build[type].name);
}
}
}
else if (GET_ACTION(ch) != ACT_NONE)
msg_to_char(ch, "You're already busy.\r\n");
else if (GET_INTELLIGENCE(ch) < build[type].intelligence || GET_SCIENCE(ch) < build[type].science || GET_LEADERSHIP(ch) < build[type].leadership)
msg_to_char(ch, "You don't have the skill to erect that structure.\r\n");
else if ((build[type].sect == SECT_MONUMENT_CLOSED || build[type].sect == SECT_MONUMENT_OPEN) && (e = real_empire(GET_LOYALTY(ch))) == -1)
msg_to_char(ch, "You can't build a monument if you're not a member of an empire.\r\n");
else if ((e = real_empire(get_id_by_empire(ch))) == -1 && 0)
msg_to_char(ch, "You will never see this line, it's only here to set up an empire!\r\n");
else if (e != -1 && GET_RANK(ch) < empire[e].priv[PRIV_BUILD])
msg_to_char(ch, "You don't have permission to build anything.\r\n");
else
found = TRUE;
/* 'found' is used for clean viewing */
if (!found)
return;
/* special handling: parameters */
switch (build[type].special) {
case 0:
if (!*buf || (id = get_id_by_name(buf)) <= 0) {
msg_to_char(ch, "To whom would you like to dedicate this monument?\r\n");
return;
}
break;
case 1:
case 2:
if (!*buf || (dir = parse_direction(buf)) < 0) {
msg_to_char(ch, "Which direction would you like to face this building?\r\n");
return;
}
if (build[type].special == 1)
break;
/* type 2 only */
/* map_dir tells it whether or not to map by dir */
map_dir = dir;
/* type 2's must go n,e,s,w */
if (dir >= NUM_SIMPLE_DIRS || build[type].map[dir][0][0] == -1) {
msg_to_char(ch, "You can't face it that direction.\r\n");
return;
}
break;
}
/* Now that we're sure we can do this otherwise, lets build the map */
if (!build_monument_map(ch, type, map_dir, map))
return;
/* At this point we have the map designated and the type chosen.. */
/* For closed-type monuments only */
if (build[type].closed) {
/* The 'facing' room */
to_room = real_shift(ch->in_room, shift_dir[dir][0], shift_dir[dir][1]);
if (!((IS_SET(build[type].facing, BUILD_FIELD) && CLEAR_FIELD(to_room)) || (IS_SET(build[type].facing, BUILD_TUNNEL) && BUILDING_TYPE(to_room) == BUILDING_TUNNEL && IS_COMPLETE(to_room)) || (IS_SET(build[type].facing, BUILD_MOUNTAIN) && SECT(to_room) == SECT_MOUNTAIN) || (IS_SET(build[type].facing, BUILD_DESERT) && CLEAR_DESERT(to_room)) || (IS_SET(build[type].facing, BUILD_RIVER) && SECT(to_room) == SECT_RIVER) || (IS_SET(build[type].facing, BUILD_FOREST) && SECT(to_room) == SECT_FOREST_4) || (IS_SET(build[type].facing, BUILD_WATER) && (SECT(to_room) == SECT_OCEAN || SECT(to_room) == SECT_RIVER)))) {
msg_to_char(ch, "You need to build facing: ");
*buf = '\0';
if (IS_SET(build[type].facing, BUILD_FIELD))
sprintf(buf + strlen(buf), "%sfield", *buf ? ", " : "");
if (IS_SET(build[type].facing, BUILD_WATER | BUILD_RIVER))
sprintf(buf + strlen(buf), "%swater", *buf ? ", " : "");
if (IS_SET(build[type].facing, BUILD_TUNNEL))
sprintf(buf + strlen(buf), "%stunnel", *buf ? ", " : "");
if (IS_SET(build[type].facing, BUILD_BRIDGE))
sprintf(buf + strlen(buf), "%sbridge", *buf ? ", " : "");
if (IS_SET(build[type].facing, BUILD_MOUNTAIN))
sprintf(buf + strlen(buf), "%smountain", *buf ? ", " : "");
if (IS_SET(build[type].facing, BUILD_DESERT))
sprintf(buf + strlen(buf), "%sdesert", *buf ? ", " : "");
if (IS_SET(build[type].facing, BUILD_FOREST))
sprintf(buf + strlen(buf), "%sforest", *buf ? ", " : "");
msg_to_char(ch, buf);
return;
}
/* The 'reverse' room */
if (build[type].reverse != -1) {
to_rev = real_shift(ch->in_room, shift_dir[rev_dir[dir]][0], shift_dir[rev_dir[dir]][1]);
if (!((IS_SET(build[type].reverse, BUILD_FIELD) && CLEAR_FIELD(to_rev)) || (IS_SET(build[type].reverse, BUILD_TUNNEL) && (BUILDING_TYPE(to_rev) == BUILDING_TUNNEL || BUILDING_TYPE(to_rev) == BUILDING_TUNNEL2) && IS_COMPLETE(to_rev)) || (IS_SET(build[type].reverse, BUILD_MOUNTAIN) && SECT(to_rev) == SECT_MOUNTAIN) || (IS_SET(build[type].reverse, BUILD_DESERT) && CLEAR_DESERT(to_rev)) || (IS_SET(build[type].reverse, BUILD_RIVER) && SECT(to_rev) == SECT_RIVER) || (IS_SET(build[type].reverse, BUILD_FOREST) && SECT(to_rev) == SECT_FOREST_4) || (IS_SET(build[type].reverse, BUILD_WATER) && (SECT(to_rev) == SECT_OCEAN || SECT(to_rev) == SECT_RIVER)))) {
msg_to_char(ch, "You need to build with the reverse side facing ");
if (IS_SET(build[type].reverse, BUILD_TUNNEL))
msg_to_char(ch, "another tunnel.\r\n");
else if (IS_SET(build[type].reverse, BUILD_FIELD))
msg_to_char(ch, "cleared field.\r\n");
else if (IS_SET(build[type].reverse, BUILD_WATER | BUILD_RIVER))
msg_to_char(ch, "the water.\r\n");
else if (IS_SET(build[type].reverse, BUILD_MOUNTAIN))
msg_to_char(ch, "a mountain.\r\n");
else if (IS_SET(build[type].reverse, BUILD_DESERT))
msg_to_char(ch, "the desert.\r\n");
else if (IS_SET(build[type].reverse, BUILD_FOREST))
msg_to_char(ch, "the forest.\r\n");
else if (IS_SET(build[type].reverse, BUILD_BRIDGE))
msg_to_char(ch, "a bridge.\r\n");
return;
}
}
/* If we're going to be closing a room off, we need to kick people out */
for (j = 0; j < build[type].height; j++)
for (i = 0; i < build[type].width; i++) {
while (world[map[j][i]].people && map[j][i] != ch->in_room)
char_to_room(world[map[j][i]].people, to_room);
while (world[map[j][i]].contents && map[j][i] != ch->in_room)
obj_to_room(world[map[j][i]].contents, ch->in_room);
}
}
/* Now set up the rooms, open or closed */
for (j = 0; j < build[type].height; j++)
for (i = 0; i < build[type].width; i++) {
/* type2 for multi-build land recovery */
if (SECT(map[j][i]) == SECT_FIELD) world[map[j][i]].type2 = 0;
else if (SECT(map[j][i]) == SECT_FOREST_4) world[map[j][i]].type2 = 1;
else if (SECT(map[j][i]) == SECT_DESERT) world[map[j][i]].type2 = 2;
/* Or if it's declared explicitly */
if (build[type].type2 != -1)
world[map[j][i]].type2 = build[type].type2;
SECT(map[j][i]) = build[type].sect;
world[map[j][i]].type = build[type].map[map_dir][j][i];
/* Clean up set values */
if (world[map[j][i]].name) {
free(world[map[j][i]].name);
world[map[j][i]].name = NULL;
}
if (world[map[j][i]].description) {
free(world[map[j][i]].description);
world[map[j][i]].description = NULL;
}
if (world[map[j][i]].icon) {
free(world[map[j][i]].icon);
world[map[j][i]].icon = NULL;
}
world[map[j][i]].build_value = 0;
world[map[j][i]].base_affects = build[type].base_affects;
SET_BIT(world[map[j][i]].affects, build[type].base_affects);
/* special handling: each room in the map */
switch (build[type].special) {
case 0:
world[map[j][i]].spare = id;
break;
case 3:
GET_BUILD_VALUE(map[j][i]) = 1000;
break;
}
/* Extra special handling for mines */
if (BUILDING_TYPE(map[j][i]) == BUILDING_MINE && world[map[j][i]].type2 == 0) {
world[map[j][i]].spare = number(40, 60);
switch(number(0, 25)) {
case 24:
case 23: world[map[j][i]].type2 = ITEM_MAT_SILVER; world[map[j][i]].spare /= 2; break;
default: world[map[j][i]].type2 = ITEM_MAT_IRON; break;
}
}
if (build[type].closed) {
if (map[j][i] != ch->in_room)
world[map[j][i]].home_room = world[ch->in_room].number;
world[map[j][i]].building_entrance = -1;
}
if (!build[type].closed || map[j][i] == ch->in_room)
setup_monument_resources(map[j][i], type);
if (can_claim(ch) || world[map[j][i]].home_room != NOWHERE) {
world[map[j][i]].owner = get_id_by_empire(ch);
if (world[map[j][i]].home_room == NOWHERE)
empire[e].territory++;
}
IS_DISMANTLING(map[j][i]) = FALSE;
}
/* type2 if it's declared explicitly (overrides setting above) */
if (build[type].type2 != -1)
world[ch->in_room].type2 = build[type].type2;
/* ch->in_room is already set up, but we need to give it an exit */
if (build[type].closed) {
CREATE(world[ch->in_room].dir_option[dir], struct room_direction_data, 1);
world[ch->in_room].dir_option[dir]->to_room = to_room;
world[ch->in_room].dir_option[dir]->exit_info = 0;
world[ch->in_room].dir_option[dir]->keyword = NULL;
if (build[type].reverse != -1) {
CREATE(world[ch->in_room].dir_option[rev_dir[dir]], struct room_direction_data, 1);
world[ch->in_room].dir_option[rev_dir[dir]]->to_room = to_rev;
world[ch->in_room].dir_option[rev_dir[dir]]->exit_info = 0;
world[ch->in_room].dir_option[rev_dir[dir]]->keyword = NULL;
}
/* All entrances default to south */
world[ch->in_room].building_entrance = rev_dir[dir];
}
GET_ACTION(ch) = ACT_BUILDING;
GET_ACTION_ROOM(ch) = ch->in_room;
GET_ACTION_ROTATION(ch) = last_action_rotation;
msg_to_char(ch, "You start to build %s %s!\r\n", AN(build[type].name), build[type].name);
sprintf(buf, "$n begins to build %s %s!", AN(build[type].name), build[type].name);
act(buf, FALSE, ch, 0, 0, TO_ROOM);
}
ACMD(do_upgrade) {
if (BUILDING_TYPE(ch->in_room) == BUILDING_GUARD_TOWER3 || BUILDING_TYPE(ch->in_room) == BUILDING_SHIPYARD2 || BUILDING_TYPE(ch->in_room) == BUILDING_TUNNEL2)
msg_to_char(ch, "You can't upgrade it any more.\r\n");
else if (BUILDING_TYPE(ch->in_room) == BUILDING_GUARD_TOWER || BUILDING_TYPE(ch->in_room) == BUILDING_GUARD_TOWER2) {
if ((BUILDING_TYPE(ch->in_room) == BUILDING_GUARD_TOWER && GET_SCIENCE(ch) < 4) || (BUILDING_TYPE(ch->in_room) == BUILDING_GUARD_TOWER2 && GET_SCIENCE(ch) < 5))
msg_to_char(ch, "You don't have the skill needed to upgrade this tower.\r\n");
else if (!CAN_USE_ROOM(ch, ch->in_room, 1))
msg_to_char(ch, "You don't have permission to upgrade this tower.\r\n");
else if (!IS_COMPLETE(ch->in_room))
msg_to_char(ch, "You can't upgrade it until the original construction is complete.\r\n");
else if (GET_ACTION(ch) != ACT_NONE)
msg_to_char(ch, "You're already building.\r\n");
else {
GET_ACTION(ch) = ACT_BUILDING;
GET_ACTION_ROOM(ch) = ch->in_room;
GET_ACTION_ROTATION(ch) = last_action_rotation;
if (BUILDING_TYPE(ch->in_room) == BUILDING_GUARD_TOWER)
world[ch->in_room].type = BUILDING_GUARD_TOWER2;
else
world[ch->in_room].type = BUILDING_GUARD_TOWER3;
world[ch->in_room].res.logs = 4;
world[ch->in_room].res.sticks = 30;
world[ch->in_room].res.rocks = 0;
world[ch->in_room].res.iron = 20 * (1+(BUILDING_TYPE(ch->in_room) == BUILDING_GUARD_TOWER3));
msg_to_char(ch, "You begin to upgrade the tower.\r\n");
act("$n starts upgrading the tower.", FALSE, ch, 0, 0, TO_ROOM);
}
return;
}
else if (BUILDING_TYPE(ch->in_room) == BUILDING_SHIPYARD) {
if (GET_SCIENCE(ch) < 4)
msg_to_char(ch, "You don't have the skill needed to upgrade this shipyard.\r\n");
else if (!CAN_USE_ROOM(ch, ch->in_room, 1))
msg_to_char(ch, "You don't have permission to upgrade this shipyard.\r\n");
else if (!IS_COMPLETE(ch->in_room))
msg_to_char(ch, "You can't upgrade it until the original construction is complete.\r\n");
else if (GET_ACTION(ch) != ACT_NONE)
msg_to_char(ch, "You're already building.\r\n");
else {
GET_ACTION(ch) = ACT_BUILDING;
GET_ACTION_ROOM(ch) = ch->in_room;
GET_ACTION_ROTATION(ch) = last_action_rotation;
world[ch->in_room].type = BUILDING_SHIPYARD2;
world[ch->in_room].res.logs = 75;
world[ch->in_room].res.sticks = 0;
world[ch->in_room].res.rocks = 0;
world[ch->in_room].res.iron = 35;
msg_to_char(ch, "You begin to upgrade the shipyard.\r\n");
act("$n starts upgrading the shipyard.", FALSE, ch, 0, 0, TO_ROOM);
}
return;
}
else if (BUILDING_TYPE(ch->in_room) == BUILDING_TUNNEL) {
if (GET_SCIENCE(ch) < 4)
msg_to_char(ch, "You don't have the skill needed to upgrade this tunnel.\r\n");
else if (!CAN_USE_ROOM(ch, ch->in_room, 1))
msg_to_char(ch, "You don't have permission to upgrade this tunnel.\r\n");
else if (!IS_COMPLETE(ch->in_room))
msg_to_char(ch, "You can't upgrade it until the original construction is complete.\r\n");
else if (GET_ACTION(ch) != ACT_NONE)
msg_to_char(ch, "You're already building.\r\n");
else {
GET_ACTION(ch) = ACT_BUILDING;
GET_ACTION_ROOM(ch) = ch->in_room;
GET_ACTION_ROTATION(ch) = last_action_rotation;
world[ch->in_room].type = BUILDING_TUNNEL2;
world[ch->in_room].res.logs = 20;
world[ch->in_room].res.sticks = 0;
world[ch->in_room].res.rocks = 0;
world[ch->in_room].res.iron = 0;
msg_to_char(ch, "You begin to upgrade the tunnel.\r\n");
act("$n starts upgrading the tunnel.", FALSE, ch, 0, 0, TO_ROOM);
}
return;
}
else
msg_to_char(ch, "You can only upgrade guard towers, shipyards, and tunnels.\r\n");
}
ACMD(do_plant) {
extern const char *crops[];
Object obj;
Creature c;
bool found = FALSE;
if (IS_NPC(ch))
return;
for (c = world[ch->in_room].people; c; c = c->next_in_room)
if (!IS_NPC(c) && GET_ACTION(c) == ACT_PLANTING)
found = TRUE;
one_argument(argument, arg);
if (GET_ACTION(ch) == ACT_PLANTING)
msg_to_char(ch, "You're already planting something.\r\n");
else if (GET_ACTION(ch) != ACT_NONE)
msg_to_char(ch, "You're already busy doing something else.\r\n");
else if (SECT(ch->in_room) != SECT_FIELD)
msg_to_char(ch, "You can only plant in open field.\r\n");
else if (found)
msg_to_char(ch, "Someone else is already planting here.\r\n");
else if (!CAN_USE_ROOM(ch, ch->in_room, 1))
msg_to_char(ch, "You don't have permission to plant anything here.\r\n");
else if (real_empire(world[ch->in_room].owner) != -1 && GET_RANK(ch) < empire[real_empire(world[ch->in_room].owner)].priv[PRIV_HARVEST])
msg_to_char(ch, "You don't have permission to plant crops.\r\n");
else if (!*arg)
msg_to_char(ch, "What do you want to plant?\r\n");
else if (!(obj = get_obj_in_list_vis(ch, arg, ch->carrying)))
msg_to_char(ch, "You don't seem to have any %s.\r\n", arg);
else if (!OBJ_FLAGGED(obj, ITEM_PLANTABLE))
msg_to_char(ch, "You can't plant that!\r\n");
else {
SECT(ch->in_room) = SECT_SEEDED;
world[ch->in_room].type = GET_OBJ_VAL(obj, 1);
extract_obj(obj);
GET_BUILD_VALUE(ch->in_room) = 120;
GET_ACTION(ch) = ACT_PLANTING;
GET_ACTION_TIMER(ch) = 4;
GET_ACTION_ROOM(ch) = ch->in_room;
GET_ACTION_ROTATION(ch) = last_action_rotation;
msg_to_char(ch, "You begin planting %s here.\r\n", crops[(int) world[ch->in_room].type]);
sprintf(buf, "$n kneels and begins to plant %s here.", crops[(int) world[ch->in_room].type]);
act(buf, FALSE, ch, 0, 0, TO_ROOM);
}
}
room_rnum create_room(room_vnum vnum) {
Room new_world;
Creature c;
Object o;
int i, j, n = 0;
bool found = FALSE;
if (vnum < MAP_SIZE) {
syslog(0, TRUE, "SYSERR: create_room() attempting to create low vnum %d", vnum);
return NOWHERE;
}
if (real_room(vnum) != NOWHERE) {
syslog(0, TRUE, "SYSERR: create_room() room %d already exists", vnum);
return NOWHERE;
}
CREATE(new_world, struct room_data, top_of_world+2);
for (i = 0; i <= top_of_world; i++)
if (world[i].number < vnum)
new_world[i] = world[i];
else if (world[i].number > vnum) {
if (!found) {
found = TRUE;
new_world[i].number = vnum;
new_world[i].zone = NUM_MAP_ZONES;
new_world[i].sector_type = SECT_INSIDE;
for (j = 0; j < NUM_OF_DIRS; j++)
new_world[i].dir_option[j] = NULL;
new_world[i].type = 0;
new_world[i].type2 = 0;
new_world[i].build_value = 0;
new_world[i].building_entrance = 0;
new_world[i].spare = 0;
new_world[i].owner = 0;
new_world[i].home_room = NOWHERE;
new_world[i].dismantling = 0;
new_world[i].res.iron = 0;
new_world[i].res.rocks = 0;
new_world[i].res.logs = 0;
new_world[i].res.sticks = 0;
new_world[i].light = 0;
new_world[i].contents = NULL;
new_world[i].people = NULL;
n = i;
}
new_world[i+1] = world[i];
for (c = world[i].people; c; c = c->next_in_room)
c->in_room = c->in_room + 1;
for (o = world[i].contents; o; o = o->next_content)
o->in_room = o->in_room + 1;
}
if (!found) {
new_world[i].number = vnum;
new_world[i].zone = NUM_MAP_ZONES;
new_world[i].sector_type = SECT_INSIDE;
for (j = 0; j < NUM_OF_DIRS; j++)
new_world[i].dir_option[j] = NULL;
new_world[i].type = 0;
new_world[i].type2 = 0;
new_world[i].build_value = 0;
new_world[i].building_entrance = 0;
new_world[i].spare = 0;
new_world[i].owner = 0;
new_world[i].home_room = NOWHERE;
new_world[i].dismantling = 0;
new_world[i].res.iron = 0;
new_world[i].res.rocks = 0;
new_world[i].res.logs = 0;
new_world[i].res.sticks = 0;
new_world[i].light = 0;
new_world[i].contents = NULL;
new_world[i].people = NULL;
n = i;
}
top_of_world++;
free(world);
world = new_world;
for (i = 0; i <= top_of_world; i++)
for (j = 0; j < NUM_OF_DIRS; j++)
if (world[i].dir_option[j] && world[i].dir_option[j]->to_room >= n)
world[i].dir_option[j]->to_room++;
return n;
}
void delete_room(room_rnum rnum) {
void Crash_rentsave(Creature ch);
Room new_world;
Creature c;
Object o;
int i, j;
if (rnum > top_of_world || world[rnum].number < MAP_SIZE) {
syslog(0, TRUE, "SYSERR: delete_room() attempting to delete rnum %d", rnum);
return;
}
/* Remove the people */
while (world[rnum].people) {
if (!IS_NPC(world[rnum].people)) {
Crash_rentsave(world[rnum].people);
save_char(world[rnum].people, NOWHERE);
}
extract_char(world[rnum].people);
}
/* Remove the objects */
while (world[rnum].contents)
extract_obj(world[rnum].contents);
CREATE(new_world, struct room_data, top_of_world);
for (i = 0; i < top_of_world; i++)
if (i < rnum)
new_world[i] = world[i];
else if (i >= rnum) {
for (c = world[i+1].people; c; c = c->next_in_room)
if (c->in_room != NOWHERE)
c->in_room = i;
for (o = world[i+1].contents; o; o = o->next_content)
if (o->in_room != NOWHERE)
o->in_room = i;
new_world[i] = world[i+1];
}
top_of_world--;
free(world);
world = new_world;
for (i = 0; i <= top_of_world; i++)
for (j = 0; j < NUM_OF_DIRS; j++) {
if (world[i].dir_option[j] && world[i].dir_option[j]->to_room == rnum) {
if (world[i].dir_option[j]->keyword)
free(world[i].dir_option[j]->keyword);
free(world[i].dir_option[j]);
world[i].dir_option[j] = NULL;
}
if (world[i].dir_option[j] && world[i].dir_option[j]->to_room > rnum)
world[i].dir_option[j]->to_room--;
}
}
room_vnum find_free_vnum(void) {
room_vnum i;
for (i = MAP_SIZE;; i++)
if (real_room(i) == NOWHERE)
return i;
/* We should NEVER get here.. but if we do.. */
log("SYSERR: find_free_vnum() ended the for() loop");
exit(1);
}
/*
* subcmd 0 = designate
* subcmd 1 = redesignate
*/
ACMD(do_designate) {
extern const int room_designate_flags[NUM_RTYPES][2];
int dir = -1, type, b, r = HOME_ROOM(ch->in_room);
Object o;
room_rnum new;
const char *rtypes[] = {
"\r", "armory", "bedroom", "dining room",
"forge", "great hall", "hall", "kitchen", "sitting room",
"study", "throne room", "storage", "vault",
"\r", "\r", "\r", "\r", /* ship room types */
"tunnel", "skybridge", "baths", "shield racks",
"armor storage", "closet", "\n"
};
/*
* arg = direction
* buf = room type
*/
if (!subcmd)
argument = one_argument(argument, arg);
skip_spaces(&argument);
strcpy(buf, argument);
if ((b = find_building_list_entry(ch->in_room, FIND_BUILD_NORMAL)) == -1)
msg_to_char(ch, "You can't designate rooms here!\r\n");
else if (!subcmd && ((dir = parse_direction(arg)) < 0))
msg_to_char(ch, "Which direction would you like to designate a room?\r\n");
else if ((type = search_block(buf, rtypes, FALSE)) < 0) {
msg_to_char(ch, "Invalid room type. Valid choices are: armory");
for (type = 2; str_cmp(rtypes[type], "\n"); type++)
if (strcmp(rtypes[type], "\r"))
msg_to_char(ch, ", %s", rtypes[type]);
}
else if (!CAN_USE_ROOM(ch, ch->in_room, 1))
msg_to_char(ch, "You don't have permission to designate rooms here.\r\n");
else if (GET_LOYALTY(ch) && GET_RANK(ch) < empire[real_empire(GET_LOYALTY(ch))].priv[PRIV_BUILD])
msg_to_char(ch, "You don't have permission to designate rooms.\r\n");
else if (!subcmd && SECT(ch->in_room) != SECT_INSIDE && dir != world[ch->in_room].building_entrance)
msg_to_char(ch, "You may only designate %s from here.\r\n", dirs[(int) world[ch->in_room].building_entrance]);
else if (IS_OUTDOORS(ch))
msg_to_char(ch, "You can't designate outside of a building.\r\n");
else if (SECT(ch->in_room) != SECT_INSIDE && subcmd)
msg_to_char(ch, "You can't redesignate here.\r\n");
else if (build[b].max_rooms <= 0)
msg_to_char(ch, "You can't designate here.\r\n");
else if (!subcmd && world[ch->in_room].dir_option[dir] && world[ch->in_room].dir_option[dir]->to_room != NOWHERE)
msg_to_char(ch, "There is already a room that direction.\r\n");
else if (!subcmd && world[r].inside_rooms >= build[b].max_rooms)
msg_to_char(ch, "There's no more free space.\r\n");
else if (IS_SET(room_designate_flags[type][0], DES_NEVER))
msg_to_char(ch, "You can't designate that type of room!\r\n");
else if (room_designate_flags[type][0] != 0 && !IS_SET(build[b].designate_flags, room_designate_flags[type][0]))
msg_to_char(ch, "You can't designate that here!\r\n");
else if (room_designate_flags[type][1] != 0 && IS_SET(build[b].designate_flags, room_designate_flags[type][0]))
msg_to_char(ch, "You can't designate that here!\r\n");
else {
if (subcmd)
new = ch->in_room;
else {
if (!world[ch->in_room].dir_option[dir])
CREATE(world[ch->in_room].dir_option[dir], struct room_direction_data, 1);
world[ch->in_room].dir_option[dir]->to_room = (new = create_room(find_free_vnum()));
world[ch->in_room].dir_option[dir]->exit_info = 0;
world[ch->in_room].dir_option[dir]->keyword = NULL;
CREATE(world[new].dir_option[rev_dir[dir]], struct room_direction_data, 1);
world[new].dir_option[rev_dir[dir]]->to_room = ch->in_room;
world[new].dir_option[rev_dir[dir]]->exit_info = 0;
world[new].dir_option[rev_dir[dir]]->keyword = NULL;
world[r].inside_rooms++;
}
/* remove old board */
if (world[ch->in_room].type == RTYPE_STUDY)
for (o = world[ch->in_room].contents; o; o = o->next_content)
if (GET_OBJ_VNUM(o) == BOARD_MORT)
extract_obj(o);
/* add new board */
if (type == RTYPE_STUDY)
obj_to_room(read_object(BOARD_MORT, VIRTUAL), new);
/* set applicable values */
world[new].type = type;
world[new].home_room = world[r].number;
world[new].owner = world[r].owner;
/* send messages */
if (subcmd) {
msg_to_char(ch, "You redesignate this room as a %s.\r\n", rtypes[type]);
sprintf(buf, "$n redesignates this room as a %s.\r\n", rtypes[type]);
act(buf, FALSE, ch, 0, 0, TO_ROOM);
}
else {
msg_to_char(ch, "You designate the room %s as a %s.\r\n", dirs[dir], rtypes[type]);
sprintf(buf, "$n designates the room %s as a %s.\r\n", dirs[dir], rtypes[type]);
act(buf, FALSE, ch, 0, 0, TO_ROOM);
}
}
}
void process_build(Creature ch, room_rnum room) {
void read_empire_territory();
struct resource_data *res = &world[room].res;
Object obj = NULL;
Creature c = NULL;
bool found = FALSE;
if (res->logs && !found) {
for (obj = ch->carrying; obj; obj = obj->next_content)
if (!found && GET_OBJ_VNUM(obj) == o_LOG && (found = 1) && (res->logs--))
break;
if (!found)
for (obj = world[room].contents; obj; obj = obj->next_content)
if (!found && GET_OBJ_VNUM(obj) == o_LOG && (found = 1) && (res->logs--))
break;
}
if (res->sticks && !found) {
for (obj = ch->carrying; obj; obj = obj->next_content)
if (!found && GET_OBJ_VNUM(obj) == o_STICK && (found = 1) && (res->sticks--))
break;
if (!found)
for (obj = world[room].contents; obj; obj = obj->next_content)
if (!found && GET_OBJ_VNUM(obj) == o_STICK && (found = 1) && (res->sticks--))
break;
}
if (res->rocks && !found) {
for (obj = ch->carrying; obj; obj = obj->next_content)
if (!found && GET_OBJ_VNUM(obj) == o_ROCK && (found = 1) && (res->rocks--))
break;
if (!found)
for (obj = world[room].contents; obj; obj = obj->next_content)
if (!found && GET_OBJ_VNUM(obj) == o_ROCK && (found = 1) && (res->rocks--))
break;
}
if (res->iron && !found) {
for (obj = ch->carrying; obj; obj = obj->next_content)
if (!found && GET_OBJ_VNUM(obj) == o_IRON && (found = 1) && (res->iron--))
break;
if (!found)
for (obj = world[room].contents; obj; obj = obj->next_content)
if (!found && GET_OBJ_VNUM(obj) == o_IRON && (found = 1) && (res->iron--))
break;
}
/* small chance of error here.. */
if (!IS_COMPLETE(room)) {
if (!found || !obj) {
msg_to_char(ch, "You run out of resources and stop building.\r\n");
act("$n runs out of resources and stops building.", FALSE, ch, 0, 0, TO_ROOM);
GET_ACTION(ch) = ACT_NONE;
return;
}
act("$n places $p carefully in the structure.", FALSE, ch, obj, 0, TO_ROOM);
act("You carefully place $p in the structure.", FALSE, ch, obj, 0, TO_CHAR);
}
if (IS_COMPLETE(room)) {
msg_to_char(ch, "You complete the construction!\r\n");
act("$n has completed the construction!", FALSE, ch, 0, 0, TO_ROOM);
for (c = world[ch->in_room].people; c; c = c->next_in_room)
if (!IS_NPC(c) && GET_ACTION(c) == ACT_BUILDING)
GET_ACTION(c) = ACT_NONE;
if (SECT(room) == SECT_MONUMENT_OPEN || SECT(room) == SECT_MONUMENT_CLOSED)
read_empire_territory();
}
if (obj)
extract_obj(obj);
}
void disassociate_building(room_rnum room) {
int i, j, k, sect = SECT_FIELD;
world[room].inside_rooms = 0;
IS_DISMANTLING(room) = 0;
for (i = 0; i < NUM_OF_DIRS; i++)
if (world[room].dir_option[i]) {
if (world[room].dir_option[i]->keyword)
free(world[room].dir_option[i]->keyword);
free(world[room].dir_option[i]);
world[room].dir_option[i] = NULL;
}
if (world[room].name) {
free(world[room].name);
world[room].name = NULL;
}
if (world[room].description) {
free(world[room].description);
world[room].description = NULL;
}
if (world[room].icon) {
free(world[room].icon);
world[room].icon = NULL;
}
world[room].base_affects = 0;
world[room].affects = 0;
if ((k = find_building_list_entry(room, FIND_BUILD_NORMAL)) != -1) {
if (IS_SET(build[k].built_on, BUILD_WATER | BUILD_RIVER))
sect = SECT_RIVER;
else if (IS_SET(build[k].built_on, BUILD_FOREST) && (count_bits(build[k].built_on) < 2 || world[room].type2 == 1))
sect = SECT_FOREST_4;
else if (IS_SET(build[k].built_on, BUILD_DESERT) && (count_bits(build[k].built_on) < 2 || world[room].type2 == 2))
sect = SECT_DESERT;
else if (IS_SET(build[k].built_on, BUILD_MOUNTAIN | BUILD_TUNNEL))
sect = SECT_MOUNTAIN;
else
sect = SECT_FIELD;
}
SECT(room) = sect;
world[room].type = 0;
if (SECT(room) != SECT_MOUNTAIN)
world[room].type2 = 0;
for (j = 0; j <= top_of_world; j++) {
if (HOME_ROOM(j) != room || j == room)
continue;
while (world[j].people)
char_to_room(world[j].people, room);
while (world[j].contents)
obj_to_room(world[j].contents, room);
world[j].home_room = NOWHERE;
if (j < MAP_SIZE) {
SECT(j) = sect;
world[j].type = 0;
if (SECT(j) != SECT_MOUNTAIN)
world[j].type2 = 0;
}
else {
delete_room(j);
j--;
}
}
}
void process_dismantling(Creature ch, room_rnum room) {
struct resource_data *res = &world[room].res;
Object obj = NULL;
Creature c = NULL;
bool found = FALSE;
if (res->logs && !found) {
obj = read_object(o_LOG, VIRTUAL);
found = TRUE;
res->logs--;
}
if (res->sticks && !found) {
obj = read_object(o_STICK, VIRTUAL);
found = TRUE;
res->sticks--;
}
if (res->rocks && !found) {
obj = read_object(o_ROCK, VIRTUAL);
found = TRUE;
res->rocks--;
}
if (res->iron && !found) {
obj = read_object(o_IRON, VIRTUAL);
found = TRUE;
res->iron--;
}
if (obj) {
if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch) || GET_OBJ_WEIGHT(obj) + IS_CARRYING_W(ch) > CAN_CARRY_W(ch))
obj_to_room(obj, ch->in_room);
else
obj_to_char(obj, ch);
act("$n removes $p from the structure.", FALSE, ch, obj, 0, TO_ROOM);
act("You carefully remove $p from the structure.", FALSE, ch, obj, 0, TO_CHAR);
}
if (IS_COMPLETE(room)) {
msg_to_char(ch, "You finish dismantling the building.\r\n");
act("$n finishes dismantling the building.", FALSE, ch, 0, 0, TO_ROOM);
for (c = world[ch->in_room].people; c; c = c->next_in_room)
if (!IS_NPC(c) && GET_ACTION(c) == ACT_DISMANTLING)
GET_ACTION(c) = ACT_NONE;
disassociate_building(room);
}
}
ACMD(do_dismantle) {
Object obj, next_obj;
Creature targ, next_targ;
int i, j;
if (IS_NPC(ch))
return;
if (GET_ACTION(ch) == ACT_DISMANTLING) {
msg_to_char(ch, "You stop dismantling the building.\r\n");
act("$n stops dismantling the building.", FALSE, ch, 0, 0, TO_ROOM);
GET_ACTION(ch) = ACT_NONE;
return;
}
if (GET_ACTION(ch) != ACT_NONE) {
msg_to_char(ch, "You're kinda busy right now.\r\n");
return;
}
if (IS_DISMANTLING(ch->in_room)) {
msg_to_char(ch, "You begin to dismantle the building.\r\n");
act("$n begins to dismantle the building.", FALSE, ch, 0, 0, TO_ROOM);
GET_ACTION(ch) = ACT_DISMANTLING;
GET_ACTION_ROTATION(ch) = last_action_rotation;
GET_ACTION_ROOM(ch) = ch->in_room;
return;
}
if ((i = find_building_list_entry(ch->in_room, FIND_BUILD_NORMAL)) == -1) {
msg_to_char(ch, "You can't dismantle this building.\r\n");
return;
}
if (!CAN_USE_ROOM(ch, ch->in_room, 1)) {
msg_to_char(ch, "You don't have permission to dismantle this building.\r\n");
return;
}
if (GET_LOYALTY(ch) && GET_RANK(ch) < empire[real_empire(GET_LOYALTY(ch))].priv[PRIV_BUILD]) {
msg_to_char(ch, "You don't have permission to dismantle anything.\r\n");
return;
}
if (GET_INTELLIGENCE(ch) < build[i].intelligence || GET_SCIENCE(ch) < build[i].science) {
msg_to_char(ch, "You don't have the skill needed to dismantle this building properly.\r\n");
return;
}
for (j = MAP_SIZE; j <= top_of_world; j++) {
if (HOME_ROOM(j) != ch->in_room)
continue;
for (obj = world[j].contents; obj; obj = next_obj) {
next_obj = obj->next_content;
obj_to_room(obj, ch->in_room);
if (GET_OBJ_TYPE(obj) == ITEM_BOARD)
extract_obj(obj);
}
for (targ = world[j].people; targ; targ = next_targ) {
next_targ = targ->next_in_room;
char_from_room(targ);
char_to_room(targ, ch->in_room);
}
}
if (!IS_COMPLETE(ch->in_room)) {
world[ch->in_room].res.logs = (build[i].logs - world[ch->in_room].res.logs) / 2;
world[ch->in_room].res.sticks = (build[i].sticks - world[ch->in_room].res.sticks) / 2;
world[ch->in_room].res.rocks = (build[i].rocks - world[ch->in_room].res.rocks) / 2;
world[ch->in_room].res.iron = (build[i].iron - world[ch->in_room].res.iron) / 2;
}
else {
world[ch->in_room].res.logs = build[i].logs / 2;
world[ch->in_room].res.sticks = build[i].sticks / 2;
world[ch->in_room].res.rocks = build[i].rocks / 2;
world[ch->in_room].res.iron = build[i].iron / 2;
}
IS_DISMANTLING(ch->in_room) = TRUE;
GET_ACTION(ch) = ACT_DISMANTLING;
GET_ACTION_ROTATION(ch) = last_action_rotation;
GET_ACTION_ROOM(ch) = ch->in_room;
msg_to_char(ch, "You begin to dismantle the building.\r\n\r\n");
act("$n begins to dismantle the building.\r\n", FALSE, ch, 0, 0, TO_ROOM);
process_dismantling(ch, ch->in_room);
WAIT_STATE(ch, 2 RL_SEC);
}
ACMD(do_lay) {
int i;
Object obj, next_obj;
for (i = 0, obj = ch->carrying; obj; obj = obj->next_content)
if (GET_OBJ_VNUM(obj) == o_ROCK)
i++;
for (obj = world[ch->in_room].contents; obj; obj = obj->next_content)
if (GET_OBJ_VNUM(obj) == o_ROCK)
i++;
if (!CAN_USE_ROOM(ch, ch->in_room, 1))
msg_to_char(ch, "You can't lay road here!\r\n");
else if (real_empire(GET_LOYALTY(ch)) != -1 && GET_RANK(ch) < empire[real_empire(GET_LOYALTY(ch))].priv[PRIV_BUILD])
msg_to_char(ch, "You don't have permission to lay road.\r\n");
else if (GET_INTELLIGENCE(ch) < 2 || GET_SCIENCE(ch) < 1)
msg_to_char(ch, "You don't have the skill to properly do that.\r\n");
else if (SECT(ch->in_room) == SECT_ROAD && !world[ch->in_room].type) {
for (i = 0; i < 20; i++) {
obj = read_object(o_ROCK, VIRTUAL);
if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch) || GET_OBJ_WEIGHT(obj) + IS_CARRYING_W(ch) > CAN_CARRY_W(ch))
obj_to_room(obj, ch->in_room);
else
obj_to_char(obj, ch);
}
msg_to_char(ch, "You pull up the road.\r\n");
act("$n pulls up the road.", FALSE, ch, 0, 0, TO_ROOM);
if (world[ch->in_room].type2 == 1)
SECT(ch->in_room) = SECT_DESERT;
else
SECT(ch->in_room) = SECT_FIELD;
WAIT_STATE(ch, PULSE_VIOLENCE * 2);
}
else if (SECT(ch->in_room) != SECT_FIELD && SECT(ch->in_room) != SECT_DESERT)
msg_to_char(ch, "You can't lay road here!\r\n");
else if (i < 20)
msg_to_char(ch, "You don't have enough rocks to do that.\r\n");
else {
for (i = 20, obj = ch->carrying; obj && i > 0; obj = next_obj) {
next_obj = obj->next_content;
if (GET_OBJ_VNUM(obj) == o_ROCK) {
i--;
extract_obj(obj);
}
}
for (obj = world[ch->in_room].contents; obj && i > 0; obj = next_obj) {
next_obj = obj->next_content;
if (GET_OBJ_VNUM(obj) == o_ROCK) {
i--;
extract_obj(obj);
}
}
msg_to_char(ch, "You lay a road here.\r\n");
act("$n lays a road here.", FALSE, ch, 0, 0, TO_ROOM);
world[ch->in_room].type = 0;
if (SECT(ch->in_room) == SECT_DESERT)
world[ch->in_room].type2 = 1;
else
world[ch->in_room].type2 = 0;
SECT(ch->in_room) = SECT_ROAD;
WAIT_STATE(ch, PULSE_VIOLENCE * 2);
}
}
void disperse_resources(room_rnum room) {
int i, j;
if ((i = find_building_list_entry(room, FIND_BUILD_NORMAL)) == -1)
return;
if (str_cmp(build[i].name, "\n")) {
for (j = build[i].logs; j; j--)
obj_to_room(read_object(o_LOG, VIRTUAL), room);
for (j = build[i].sticks; j; j--)
obj_to_room(read_object(o_STICK, VIRTUAL), room);
for (j = build[i].rocks; j; j--)
obj_to_room(read_object(o_ROCK, VIRTUAL), room);
for (j = build[i].iron; j; j--)
obj_to_room(read_object(o_IRON, VIRTUAL), room);
}
}