bool hasMatchingWallBrushAtTile(BaseMap* map, WallBrush* wall_brush, uint x, uint y, uint z) { Tile* t = map->getTile(x, y, z); if(!t) return false; ItemVector::const_iterator it = t->items.begin(); for(; it != t->items.end(); ++it) { Item* item = *it; if(item->isWall()) { WallBrush* wb = item->getWallBrush(); if(wb == wall_brush) { return !item_db[item->getID()].wall_hate_me; } else if(wall_brush->friendOf(wb) || wb->friendOf(wall_brush)) { return !item_db[item->getID()].wall_hate_me; } } } return false; }
DoorBrush* Item::getDoorBrush() const { ItemType& it = item_db[id]; if(!it.isWall || !it.isBrushDoor) { return nullptr; } WallBrush* wb = dynamic_cast<WallBrush*>(it.brush); DoorBrush* db = nullptr; // Quite a horrible dependency on a global here, meh. switch(wb->getDoorTypeFromID(id)) { case WALL_DOOR_NORMAL: { db = gui.normal_door_brush; break; } case WALL_DOOR_LOCKED: { db = gui.locked_door_brush; break; } case WALL_DOOR_QUEST: { db = gui.quest_door_brush; break; } case WALL_DOOR_MAGIC: { db = gui.magic_door_brush; break; } case WALL_WINDOW: { db = gui.window_door_brush; break; } case WALL_HATCH_WINDOW: { db = gui.hatch_door_brush; break; } default: { break; } } return db; }
void WallDecorationBrush::draw(BaseMap* map, Tile* tile, void* parameter) { ASSERT(tile); ItemVector::iterator iter = tile->items.begin(); tile->cleanWalls(this); while(iter != tile->items.end()) { Item* item = *iter; if(item->isBorder()) { ++iter; continue; } if(item->isWall()) { // Now we found something interesting. // Is it just a decoration, like what we're trying to add? WallBrush* wb = item->getWallBrush(); if(dynamic_cast<WallDecorationBrush*>(wb)) { // It is, discard and advance! ++iter; continue; } // We first need to figure out the alignment of this item (wall) BorderType wall_alignment = item->getWallAlignment(); // Now we need to figure out if we got an item that mights suffice to place on this tile.. int id = 0; if(item->isBrushDoor()) { // If it's a door ::DoorType doortype = wb->getDoorTypeFromID(item->getID()); uint16_t discarded_id = 0; bool close_match = false; bool open = item->isOpen(); for(std::vector<WallBrush::DoorType>::iterator door_iter = door_items[wall_alignment].begin(); door_iter!= door_items[wall_alignment].end(); ++door_iter) { WallBrush::DoorType& dt = *door_iter; if(dt.type == doortype) { ASSERT(dt.id); ItemType& it = item_db[dt.id]; ASSERT(it.id != 0); if(it.isOpen == open) { id = dt.id; break; } else { discarded_id = dt.id; close_match = true; } if(!close_match && discarded_id == 0) { discarded_id = dt.id; } } } if(id == 0) { id = discarded_id; if(id == 0) { ++iter; continue; } } } else { // If it's a normal wall... if(wall_items[wall_alignment].total_chance <= 0) { // No fitting item, exit ++iter; continue; } int chance = random(1, wall_items[wall_alignment].total_chance); for(std::vector<WallBrush::WallType>::const_iterator witer = wall_items[wall_alignment].items.begin(); witer != wall_items[wall_alignment].items.end(); ++witer) { if(chance <= witer->chance) { id = witer->id; break; } } } // If we found an invalid id we should've already exited the loop ASSERT(id); // Add a matching item above this item. Item* item = Item::Create(id); ++iter; iter = tile->items.insert(iter, item); } ++iter; } }
void WallBrush::doWalls(BaseMap* map, Tile* tile) { ASSERT(tile); // For quicker reference unsigned int x = tile->getPosition().x; unsigned int y = tile->getPosition().y; unsigned int z = tile->getPosition().z; // Advance the vector to the beginning of the walls ItemVector::iterator it = tile->items.begin(); for(; it != tile->items.end() && (*it)->isBorder(); ++it); ItemVector items_to_add; while(it != tile->items.end()) { Item* wall = *it; if(!wall->isWall()) { ++it; continue; } WallBrush* wall_brush = wall->getWallBrush(); // Skip if either the wall has no brush if(!wall_brush) { ++it; continue; } // or if it's a decoration brush. if(wall_brush->isWallDecoration()) { items_to_add.push_back(wall); it = tile->items.erase(it); continue; } bool neighbours[4]; if(x == 0) { if(y == 0) { neighbours[0] = false; neighbours[1] = false; neighbours[2] = hasMatchingWallBrushAtTile(map, wall_brush, x + 1, y, z); neighbours[3] = hasMatchingWallBrushAtTile(map, wall_brush, x, y + 1, z); } else { neighbours[0] = hasMatchingWallBrushAtTile(map, wall_brush, x, y - 1, z); neighbours[1] = false; neighbours[2] = hasMatchingWallBrushAtTile(map, wall_brush, x + 1, y, z); neighbours[3] = hasMatchingWallBrushAtTile(map, wall_brush, x, y + 1, z); } } else if(y == 0) { neighbours[0] = false; neighbours[1] = hasMatchingWallBrushAtTile(map, wall_brush, x - 1, y, z); neighbours[2] = hasMatchingWallBrushAtTile(map, wall_brush, x + 1, y, z); neighbours[3] = hasMatchingWallBrushAtTile(map, wall_brush, x, y + 1, z); } else { neighbours[0] = hasMatchingWallBrushAtTile(map, wall_brush, x, y - 1, z); neighbours[1] = hasMatchingWallBrushAtTile(map, wall_brush, x - 1, y, z); neighbours[2] = hasMatchingWallBrushAtTile(map, wall_brush, x + 1, y, z); neighbours[3] = hasMatchingWallBrushAtTile(map, wall_brush, x, y + 1, z); } uint32_t tiledata = 0; for(int i = 0; i < 4; i++) { if(neighbours[i]) { // Same wall as this one, calculate what border tiledata |= 1 << i; } } bool exit = false; for(int i = 0; i < 2; ++i) { // Repeat twice if(exit) { break; } ::BorderType bt; if(i == 0) { bt = ::BorderType(full_border_types[tiledata]); } else { bt = ::BorderType(half_border_types[tiledata]); } if(wall->getWallAlignment() == WALL_UNTOUCHABLE) { items_to_add.push_back(wall); it = tile->items.erase(it); exit = true; } else if(wall->getWallAlignment() == bt) { // Do nothing, the tile already has a wall like this // However, wall decorations associated with this wall might need to change... items_to_add.push_back(wall); it = tile->items.erase(it); exit = true; while(it != tile->items.end()) { // If we have a decoration ontop of us, we need to change it's alignment aswell! Item* wall_decoration = *it; ASSERT(wall_decoration); WallBrush* brush = wall_decoration->getWallBrush(); if (brush && brush->isWallDecoration()) { // We don't know if we have changed alignment if(wall_decoration->getWallAlignment() == bt) { // Same, no need to change... items_to_add.push_back(wall_decoration); it = tile->items.erase(it); continue; } // Not the same alignment, create newd item with correct alignment uint16_t id = 0; WallNode& wn = brush->wall_items[int(bt)]; if(wn.total_chance <= 0) { if(wn.items.size() == 0) { ++it; continue; } else { id = wn.items.front().id; } } else { int chance = random(1, wn.total_chance); for(std::vector<WallType>::const_iterator witer = wn.items.begin(); witer != wn.items.end(); ++witer) { if(chance <= witer->chance) { id = witer->id; break; } } } if(id != 0) { Item* new_wall = Item::Create(id); if(wall_decoration->isSelected()) { new_wall->select(); } items_to_add.push_back(new_wall); } ++it; } else { break; } } } else { // Randomize a newd wall of the proper alignment uint16_t id = 0; WallBrush* try_brush = wall_brush; while(true) { if(try_brush == nullptr) break; if(id != 0) break; WallNode& wn = try_brush->wall_items[int(bt)]; if(wn.total_chance <= 0) { if(wn.items.size() == 0) { try_brush = try_brush->redirect_to; if(try_brush == wall_brush) break; // To prevent infinite loop continue; } else { id = wn.items.front().id; } } else { int chance = random(1, wn.total_chance); for(std::vector<WallType>::const_iterator node_iter = wn.items.begin(); node_iter != wn.items.end(); ++node_iter) { if(chance <= node_iter->chance) { id = node_iter->id; break; } } } // Propagate down the chain try_brush = try_brush->redirect_to; if(try_brush == wall_brush) break; // To prevent infinite loop } if(try_brush == nullptr && id == 0) { if(i == 1) { ++it; } continue; } else { // If there is such an item, add it to the tile Item* new_wall = Item::Create(id); if(wall->isSelected()) { new_wall->select(); } items_to_add.push_back(new_wall); exit = true; ++it; } // Increment and check for end while(it != tile->items.end()) { // If we have a decoration ontop of us, we need to change it's alignment aswell! Item* wall_decoration = *it; WallBrush* brush = wall_decoration->getWallBrush(); if(brush && brush->isWallDecoration()) { // We know we have changed alignment, so no need to check for it again. uint16_t id = 0; WallNode& wn = brush->wall_items[int(bt)]; if(wn.total_chance <= 0) { if(wn.items.size() == 0) { ++it; continue; } else { id = wn.items.front().id; } } else { int chance = random(1, wn.total_chance); for(std::vector<WallType>::const_iterator node_iter = wn.items.begin(); node_iter != wn.items.end(); ++node_iter) { if(chance <= node_iter->chance) { id = node_iter->id; break; } } } if(id != 0) { Item* new_wall = Item::Create(id); if(wall_decoration->isSelected()) { new_wall->select(); } items_to_add.push_back(new_wall); } ++it; } else { ++it; break; } } } } } tile->cleanWalls(); for(ItemVector::const_iterator it = items_to_add.begin(); it != items_to_add.end(); ++it) { tile->addWallItem(*it); } }