Exemplo n.º 1
0
/**
 * Add edges of the neighbouring path tiles.
 * @param xpos X coordinate of the central voxel with a path tile.
 * @param ypos Y coordinate of the central voxel with a path tile.
 * @param zpos Z coordinate of the central voxel with a path tile.
 * @param slope Imploded path slope of the central voxel.
 * @param dirs Edge directions to change (bitset of #TileEdge), usually #EDGE_ALL.
 * @param use_additions Use #_additions rather than #_world.
 * @param add_edges If set, add edges (else, remove them).
 * @return Updated (imploded) slope at the central voxel.
 */
uint8 AddRemovePathEdges(uint16 xpos, uint16 ypos, uint8 zpos, uint8 slope, uint8 dirs, bool use_additions, bool add_edges)
{
	for (TileEdge edge = EDGE_BEGIN; edge < EDGE_COUNT; edge++) {
		if ((dirs & (1 << edge)) == 0) continue; // Skip directions that should not be updated.
		int delta_z = 0;
		if (slope >= PATH_FLAT_COUNT) {
			if (_path_down_from_edge[edge] == slope) {
				delta_z = 1;
			} else if (_path_up_from_edge[edge] != slope) {
				continue;
			}
		}
		Point16 dxy = _tile_dxy[edge];
		if ((dxy.x < 0 && xpos == 0) || (dxy.x > 0 && xpos == _world.GetXSize() - 1)) continue;
		if ((dxy.y < 0 && ypos == 0) || (dxy.y > 0 && ypos == _world.GetYSize() - 1)) continue;

		TileEdge edge2 = (TileEdge)((edge + 2) % 4);
		bool modified = false;
		if (delta_z <= 0 || zpos < WORLD_Z_SIZE - 1) {
			Voxel *v;
			if (use_additions) {
				v = _additions.GetCreateVoxel(xpos + dxy.x, ypos + dxy.y, zpos + delta_z, false);
			} else {
				v = _world.GetCreateVoxel(xpos + dxy.x, ypos + dxy.y, zpos + delta_z, false);
			}
			if (v != nullptr) {
				uint16 number = v->GetInstance();
				if (number == SRI_PATH) { // Valid path.
					v->SetInstanceData(SetPathEdge(v->GetInstanceData(), edge2, add_edges));
					MarkVoxelDirty(xpos + dxy.x, ypos + dxy.y, zpos + delta_z);
					modified = true;
				} else if (number >= SRI_FULL_RIDES) { // A ride instance. Does it have an entrance here?
					if ((v->GetInstanceData() & (1 << edge2)) != 0) modified = true;
				}
			}
		}
		delta_z--;
		if (delta_z >= 0 || zpos > 0) {
			Voxel *v;
			if (use_additions) {
				v = _additions.GetCreateVoxel(xpos + dxy.x, ypos + dxy.y, zpos + delta_z, false);
			} else {
				v = _world.GetCreateVoxel(xpos + dxy.x, ypos + dxy.y, zpos + delta_z, false);
			}
			if (v != nullptr) {
				uint16 number = v->GetInstance();
				if (number == SRI_PATH) { // Valid path.
					v->SetInstanceData(SetPathEdge(v->GetInstanceData(), edge2, add_edges));
					MarkVoxelDirty(xpos + dxy.x, ypos + dxy.y, zpos + delta_z);
					modified = true;
				} else if (number >= SRI_FULL_RIDES) { // A ride instance. Does it have an entrance here?
					if ((v->GetInstanceData() & (1 << edge2)) != 0) modified = true;
				}
			}
		}
		if (modified && slope < PATH_FLAT_COUNT) slope = SetPathEdge(slope, edge, add_edges);
	}
	return slope;
}
Exemplo n.º 2
0
void FenceGui::SelectorMouseButtonEvent(uint8 state)
{
	if (!IsLeftClick(state)) return;
	if (this->fence_sel.area.width != 1 || this->fence_sel.area.height != 1) return;
	if (this->fence_edge == INVALID_EDGE) return;
	if (_game_mode_mgr.InPlayMode() && _world.GetTileOwner(this->fence_base.x, this->fence_base.y) != OWN_PARK) return;

	VoxelStack *vs = _world.GetModifyStack(this->fence_base.x, this->fence_base.y);
	uint16 fences = GetGroundFencesFromMap(vs, this->fence_base.z);
	fences = SetFenceType(fences, this->fence_edge, this->fence_type);
	AddGroundFencesToMap(fences, vs, this->fence_base.z);
	MarkVoxelDirty(this->fence_base);
}
Exemplo n.º 3
0
/**
 * Change the path type of a currently existing path.
 * @param voxel_pos Coordinate of the voxel.
 * @param path_type The type of path to change to.
 * @param path_spr Imploded sprite number.
 */
static void ChangePathAtTile(const XYZPoint16 &voxel_pos, PathType path_type, uint8 path_spr)
{
	VoxelStack *avs = _additions.GetModifyStack(voxel_pos.x, voxel_pos.y);

	Voxel *av = avs->GetCreate(voxel_pos.z, false);
	AddRemovePathEdges(voxel_pos, path_spr, EDGE_ALL, true, PAS_UNUSED);

	/* Reset flat path to one without edges or corners. */
	if (path_spr < PATH_FLAT_COUNT)
		path_spr = PATH_EMPTY;

	uint8 slope = AddRemovePathEdges(voxel_pos, path_spr, EDGE_ALL, true, _sprite_manager.GetPathStatus(path_type));
	av->SetInstanceData(MakePathInstanceData(slope, path_type));

	MarkVoxelDirty(voxel_pos);
}
Exemplo n.º 4
0
/**
 * Remove a path from a tile, and free the voxels above it as well.
 * @param voxel_pos Coordinate of the voxel.
 * @param path_spr Imploded sprite number.
 * @see BuildPathAtTile
 */
static void RemovePathAtTile(const XYZPoint16 &voxel_pos, uint8 path_spr)
{
	VoxelStack *avs = _additions.GetModifyStack(voxel_pos.x, voxel_pos.y);

	Voxel *av = avs->GetCreate(voxel_pos.z, false);
	av->SetInstance(SRI_FREE);
	av->SetInstanceData(0);
	AddRemovePathEdges(voxel_pos, path_spr, EDGE_ALL, true, PAS_UNUSED);
	MarkVoxelDirty(voxel_pos);

	av = avs->GetCreate(voxel_pos.z + 1, false);
	av->SetInstance(SRI_FREE);
	av->SetInstanceData(0);

	if (path_spr >= PATH_FLAT_COUNT) {
		av = avs->GetCreate(voxel_pos.z + 2, false);
		av->SetInstance(SRI_FREE);
		av->SetInstanceData(0);
	}
}
Exemplo n.º 5
0
/**
 * Build a path at a tile, and claim the voxels above it as well.
 * @param voxel_pos Coordinate of the voxel.
 * @param path_type The type of path to build.
 * @param path_spr Imploded sprite number.
 * @see RemovePathAtTile
 */
static void BuildPathAtTile(const XYZPoint16 &voxel_pos, PathType path_type, uint8 path_spr)
{
	VoxelStack *avs = _additions.GetModifyStack(voxel_pos.x, voxel_pos.y);

	Voxel *av = avs->GetCreate(voxel_pos.z, true);
	av->SetInstance(SRI_PATH);
	uint8 slope = AddRemovePathEdges(voxel_pos, path_spr, EDGE_ALL, true, _sprite_manager.GetPathStatus(path_type));
	av->SetInstanceData(MakePathInstanceData(slope, path_type));

	av = avs->GetCreate(voxel_pos.z + 1, true);
	av->ClearVoxel();
	av->SetInstance(SRI_PATH);
	av->SetInstanceData(PATH_INVALID);

	if (path_spr >= PATH_FLAT_COUNT) { // For non-flat sprites, add another voxel.
		av = avs->GetCreate(voxel_pos.z + 2, true);
		av->ClearVoxel();
		av->SetInstance(SRI_PATH);
		av->SetInstanceData(PATH_INVALID);
	}

	MarkVoxelDirty(voxel_pos);
}
Exemplo n.º 6
0
/** Mark the voxel containing the voxel object as dirty, so it is repainted. */
void VoxelObject::MarkDirty()
{
	MarkVoxelDirty(this->vox_pos);
}
Exemplo n.º 7
0
/**
 * Add edges of the neighbouring path tiles.
 * @param voxel_pos Coordinate of the central voxel with a path tile.
 * @param slope Imploded path slope of the central voxel.
 * @param dirs Edge directions to change (bitset of #TileEdge), usually #EDGE_ALL.
 * @param status Status of the path. #PAS_UNUSED means to remove the edges.
 * @return Updated (imploded) slope at the central voxel.
 */
uint8 AddRemovePathEdges(const XYZPoint16 &voxel_pos, uint8 slope, uint8 dirs, PathStatus status)
{
	PathStatus ngb_status[4];    // Neighbour path status, #PAS_UNUSED means do not connect.
	Voxel *ngb_voxel[4];         // Neighbour voxels with path, may be null if it doesn't need changing.
	uint16 ngb_instance_data[4]; // New instance data, if the voxel exists.
	XYZPoint16 ngb_pos[4];       // Coordinate of the neighbouring voxel.

	Voxel *v = _world.GetCreateVoxel(voxel_pos, false);
	uint16 fences = v->GetFences();

	std::fill_n(ngb_status, lengthof(ngb_status), PAS_UNUSED); // Clear path all statuses to prevent connecting to it if an edge is skipped.
	for (TileEdge edge = EDGE_BEGIN; edge < EDGE_COUNT; edge++) {
		if ((dirs & (1 << edge)) == 0) continue; // Skip directions that should not be updated.
		int delta_z = 0;
		if (slope >= PATH_FLAT_COUNT) {
			if (_path_down_from_edge[edge] == slope) {
				delta_z = 1;
			} else if (_path_up_from_edge[edge] != slope) {
				continue;
			}
		}
		Point16 dxy = _tile_dxy[edge];
		ngb_pos[edge].x = voxel_pos.x + dxy.x;
		ngb_pos[edge].y = voxel_pos.y + dxy.y;
		if (!IsVoxelstackInsideWorld(ngb_pos[edge].x, ngb_pos[edge].y)) continue;

		FenceType fence_type = GetFenceType(fences, edge);
		if (fence_type != FENCE_TYPE_INVALID) continue;

		TileEdge edge2 = (TileEdge)((edge + 2) % 4);
		bool modified = false;
		if (delta_z <= 0 || voxel_pos.z < WORLD_Z_SIZE - 1) {
			ngb_pos[edge].z = voxel_pos.z + delta_z;
			modified = ExamineNeighbourPathEdge(ngb_pos[edge], edge2, status != PAS_UNUSED, true,
					&ngb_voxel[edge], &ngb_instance_data[edge], &ngb_status[edge]);
		}
		delta_z--;
		if (!modified && (delta_z >= 0 || voxel_pos.z > 0)) {
			ngb_pos[edge].z = voxel_pos.z + delta_z;
			ExamineNeighbourPathEdge(ngb_pos[edge], edge2, status != PAS_UNUSED, false,
					&ngb_voxel[edge], &ngb_instance_data[edge], &ngb_status[edge]);
		}
	}

	switch (status) {
		case PAS_UNUSED: // All edges get removed.
		case PAS_NORMAL_PATH: // All edges get added.
			for (TileEdge edge = EDGE_BEGIN; edge < EDGE_COUNT; edge++) {
				if (ngb_status[edge] != PAS_UNUSED) {
					if (slope < PATH_FLAT_COUNT) slope = SetPathEdge(slope, edge, status != PAS_UNUSED);
					if (ngb_voxel[edge] != nullptr) {
						ngb_voxel[edge]->SetInstanceData(ngb_instance_data[edge]);
						MarkVoxelDirty(ngb_pos[edge]);
					}
				}
			}
			return slope;

		case PAS_QUEUE_PATH:
			/* Pass 1: Try to add other queue paths. */
			for (TileEdge edge = EDGE_BEGIN; edge < EDGE_COUNT; edge++) {
				if (ngb_status[edge] == PAS_QUEUE_PATH) {
					if (GetQuePathEdgeConnectCount(slope) > 1) break;

					if (slope < PATH_FLAT_COUNT) slope = SetPathEdge(slope, edge, true);
					if (ngb_voxel[edge] != nullptr) {
						ngb_voxel[edge]->SetInstanceData(ngb_instance_data[edge]);
						MarkVoxelDirty(ngb_pos[edge]);
					}
				}
			}
			/* Pass 2: Add normal paths. */
			for (TileEdge edge = EDGE_BEGIN; edge < EDGE_COUNT; edge++) {
				if (ngb_status[edge] == PAS_NORMAL_PATH) {
					if (GetQuePathEdgeConnectCount(slope) > 1) break;

					if (slope < PATH_FLAT_COUNT) slope = SetPathEdge(slope, edge, true);
					if (ngb_voxel[edge] != nullptr) {
						ngb_voxel[edge]->SetInstanceData(ngb_instance_data[edge]);
						MarkVoxelDirty(ngb_pos[edge]);
					}
				}
			}
			return slope;

		default: NOT_REACHED();
	}
}