Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
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;
	}
}
Пример #4
0
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);
	}
}