/* ************************************************************************ * 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); } }