/* FinalSun/FinalAlert 2 Mission Editor Copyright (C) 1999-2024 Electronic Arts, Inc. Authored by Matthias Wagner This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "StdAfx.h" #include "TubeTool.h" #include "MapData.h" #include "IsoView.h" #include "Structs.h" #include "inlines.h" #include #include std::unique_ptr findTubeEndAt(const MapCoords& mapCoords3d, const ProjectedCoords& projCoords, const CMapData& map) { const auto& tubes = map.GetTubes(); auto it = std::find_if(tubes.begin(), tubes.end(), [mapCoords3d](const auto& tube) { return tube->getEndCoords() == mapCoords3d; }); if (it != tubes.end()) return std::make_unique(**it); // if not found, also try with z - 4 (e.g. behind cliffs) auto backMapCoords = map.ToMapCoords3d(projCoords, map.GetHeightAt(mapCoords3d) - 4); it = std::find_if(tubes.begin(), tubes.end(), [backMapCoords](const auto& tube) { return tube->getEndCoords() == backMapCoords; }); if (it != tubes.end()) return std::make_unique(**it); return nullptr; } std::vector findTubesAt(const ProjectedCoords& projCoords, const CMapData& map) { std::vector foundTubes; for (auto& t : map.GetTubes()) { auto coords = map.ToMapCoords3d(projCoords, map.GetHeightAt(t->getStartCoords())); if (t->touches(coords)) foundTubes.push_back(t->getId()); } return foundTubes; } AddTubeTool::AddTubeTool(CMapData& map, CIsoView& view, bool bidirectional): MapTool(map, view), m_bidirectional(bidirectional) { } void AddTubeTool::finish() { if (m_tube) { if (m_tube->isValid()) { getMap().SetTube(m_tube.get()); if (m_bidirectional) { auto t2 = m_tube->reverse(); getMap().SetTube(&t2); } } getView().RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); } m_mm_tube.reset(); m_tube.reset(); m_modified_tubes.clear(); } bool AddTubeTool::onRButtonUp(const ProjectedCoords& projCoords, const MapCoords& mapCoords3d, MapToolMouseFlags flags) { if (!m_modified_tubes.empty()) { // reset modified tubes to original state for (auto& tube : m_modified_tubes) { getMap().SetTube(tube.get()); } } bool ret = m_tube != nullptr; m_mm_tube.reset(); m_tube.reset(); m_modified_tubes.clear(); getView().RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); return ret; // if we were adding or modifying a tube, a right click should just cancel this current tube, not the whole tool } void AddTubeTool::onLButtonDblClick(const ProjectedCoords& projCoords, const MapCoords& mapCoords3d, MapToolMouseFlags flags) { } void AddTubeTool::onLButtonUp(const ProjectedCoords& projCoords, const MapCoords& mapCoords3d, MapToolMouseFlags flags) { if (!m_tube) { // first check if there is already a tube at the given location and take ownership if existing auto tube = getTubeToModify(mapCoords3d, projCoords, flags); if (tube) { m_tube = std::move(tube); // also find reverse direction if (m_bidirectional) { const auto& tubes = getMap().GetTubes(); auto reversed = m_tube->reverse(); auto reverseIt = std::find_if(tubes.begin(), tubes.end(), [&reversed](const auto& tube) { return tube->isEqual(reversed, true); }); if (reverseIt != tubes.end()) { m_modified_tubes.push_back(std::make_unique(**reverseIt)); getMap().DeleteTube((*reverseIt)->getId()); } } m_modified_tubes.push_back(std::make_unique(*m_tube)); getMap().DeleteTube(m_tube->getId()); } if (!m_tube) { // create a new tube, first click m_tube = std::move(createNewTube(mapCoords3d)); } } else { int z = getMap().GetHeightAt(m_tube->getStartCoords()); auto mc = getMap().ToMapCoords3d(projCoords, z); if (m_tube->getEndCoords() == MapCoords(mc.x, mc.y)) { finish(); } else { m_tube->append(mc.x, mc.y, m_tube->GetTubeParts().empty() ? 2 : 0); } } getView().RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); } std::unique_ptr AddTubeTool::createNewTube(const MapCoords& mapCoords3d) const { return std::make_unique(mapCoords3d.x, mapCoords3d.y, ETubeDirection::Undefined, mapCoords3d.x, mapCoords3d.y, std::vector()); } std::unique_ptr AddTubeTool::getTubeToModify(const MapCoords& mapCoords3d, const ProjectedCoords& projCoords, MapToolMouseFlags flags) const { if ((flags & MapToolMouseFlags::SHIFT) == MapToolMouseFlags::SHIFT) return findTubeEndAt(mapCoords3d, projCoords, getMap()); return nullptr; } void AddTubeTool::onMouseMove(const ProjectedCoords& projCoords, const MapCoords& mapCoords3d, MapToolMouseFlags flags) { if (m_tube) { m_mm_tube.reset(new CTube(*m_tube)); int z = getMap().GetHeightAt(m_tube->getStartCoords()); auto mc = getMap().ToMapCoords3d(projCoords, z); m_mm_tube->append(mc.x, mc.y, m_tube->GetTubeParts().empty() ? 2 : 0); getView().RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); } else { auto tube = getTubeToModify(mapCoords3d, projCoords, flags); if (tube) { m_hover_tube = std::move(tube); getView().RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); } else if (m_hover_tube) { m_hover_tube.reset(); getView().RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); } } } void AddTubeTool::render() { if (m_mm_tube) { // mouse-move tube getView().DrawTube(*m_mm_tube); } else if (m_tube) { getView().DrawTube(*m_tube); } else if (m_hover_tube) { COLORREF col = RGB(0, 255, 0); getView().DrawTube(*m_hover_tube, nullptr, &col); } } RemoveTubeTool::RemoveTubeTool(CMapData& map, CIsoView& view) : MapTool(map, view) { } void RemoveTubeTool::onMouseMove(const ProjectedCoords& projCoords, const MapCoords& mapCoords3d, MapToolMouseFlags flags) { auto& m = getMap(); std::vector tubes = findTubesAt(projCoords, getMap()); if ((flags & MapToolMouseFlags::LBUTTON) == MapToolMouseFlags::LBUTTON) { for (auto& id : tubes) { m.DeleteTube(id); } } else { m_hover_tubes.reserve(tubes.size()); std::transform(tubes.begin(), tubes.end(), std::back_inserter(m_hover_tubes), [this](std::uint16_t tubeId) { return std::make_unique(*getMap().GetTube(tubeId)); }); } getView().RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); m_hover_tubes.clear(); } void RemoveTubeTool::render() { for(auto& tube: m_hover_tubes) { COLORREF col = RGB(0, 255, 0); getView().DrawTube(*tube, nullptr, &col); } } ModifyTubeTool::ModifyTubeTool(CMapData& map, CIsoView& view, bool bidirectional): AddTubeTool(map, view, bidirectional) { } std::unique_ptr ModifyTubeTool::getTubeToModify(const MapCoords& mapCoords3d, const ProjectedCoords& projCoords, MapToolMouseFlags flags) const { return findTubeEndAt(mapCoords3d, projCoords, getMap()); } std::unique_ptr ModifyTubeTool::createNewTube(const MapCoords& mapCoords3d) const { return nullptr; }