/** * 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; }
/** * Examine, and perhaps modify a neighbouring path edge or ride connection, to make it connect (or not if not \a add_edges) * to the centre examined tile. * @param voxel_pos Coordinate of the neighbouring voxel. * @param edge Edge to examine, and/or connected to. * @param add_edges If set, add edges (else, remove them). * @param at_bottom Whether a path connection is expected at the bottom (if \c false, it should be at the top). * @param dest_voxel [out] %Voxel containing the neighbouring path, or \c nullptr. * @param dest_inst_data [out] New instance of the voxel. Only valid if \a dest_voxel is not \c nullptr. * @param dest_status [out] Status of the neighbouring path. * @return Neighbouring voxel was (logically) connected to the centre tile. */ static bool ExamineNeighbourPathEdge(const XYZPoint16 &voxel_pos, TileEdge edge, bool add_edges, bool at_bottom, Voxel **dest_voxel, uint16 *dest_inst_data, PathStatus *dest_status) { Voxel *v; *dest_voxel = nullptr; *dest_status = PAS_UNUSED; *dest_inst_data = PATH_INVALID; v = _world.GetCreateVoxel(voxel_pos, false); if (v == nullptr) return false; uint16 fences = v->GetFences(); FenceType fence_type = GetFenceType(fences, edge); if (fence_type != FENCE_TYPE_INVALID) return false; uint16 number = v->GetInstance(); if (number == SRI_PATH) { uint16 instance_data = v->GetInstanceData(); if (!HasValidPath(instance_data)) return false; uint8 slope = GetImplodedPathSlope(instance_data); if (at_bottom) { if (slope >= PATH_FLAT_COUNT && slope != _path_up_from_edge[edge]) return false; } else { if (slope != _path_down_from_edge[edge]) return false; } PathStatus status = _sprite_manager.GetPathStatus(GetPathType(instance_data)); if (add_edges && status == PAS_QUEUE_PATH) { // Only try to connect to queue paths if they are not yet connected to 2 (or more) neighbours. if (GetQuePathEdgeConnectCount(slope) > 1) return false; } slope = SetPathEdge(slope, edge, add_edges); *dest_status = status; *dest_voxel = v; *dest_inst_data = SetImplodedPathSlope(instance_data, slope); return true; } else if (number >= SRI_FULL_RIDES) { // A ride instance. Does it have an entrance here? if ((v->GetInstanceData() & (1 << edge)) != 0) { *dest_status = PAS_QUEUE_PATH; return true; } } return false; }
void RideBuildWindow::SelectorMouseButtonEvent(uint8 state) { if (!IsLeftClick(state)) return; if (this->selector.area.width != 1 || this->selector.area.height != 1) return; ShopInstance *si = static_cast<ShopInstance *>(this->instance); SmallRideInstance inst_number = static_cast<SmallRideInstance>(this->instance->GetIndex()); uint8 entrances = si->GetEntranceDirections(si->vox_pos); Voxel *v = _world.GetCreateVoxel(si->vox_pos, true); assert(v != nullptr && v->GetInstance() == SRI_FREE); v->SetInstance(inst_number); v->SetInstanceData(entrances); _rides_manager.NewInstanceAdded(inst_number); AddRemovePathEdges(si->vox_pos, PATH_EMPTY, entrances, false, PAS_QUEUE_PATH); this->instance = nullptr; // Delete this window, and si = nullptr; // (Also clean the copy of the pointer.) delete this; ShowShopManagementGui(inst_number); // Open gui for the new shop. }