65 ImGui::TextColored(ImVec4(1, 0, 0, 1),
"Project root not set.");
73 ImGui::Text(
"Minecart Track Editor");
85 ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.2f, 1.0f),
92 ImGui::TextColored(
show_success_ ? ImVec4(0, 1, 0, 1) : ImVec4(1, 0, 0, 1),
100 "Camera coordinates use $1XXX format (base $1000 + room offset + local "
103 "Hover over dungeon canvas to see coordinates, or click 'Pick' button.");
106 if (ImGui::BeginTable(
"TracksTable", 6,
107 ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg |
108 ImGuiTableFlags_Resizable)) {
109 ImGui::TableSetupColumn(
"ID", ImGuiTableColumnFlags_WidthFixed, 30.0f);
110 ImGui::TableSetupColumn(
"Room ID", ImGuiTableColumnFlags_WidthFixed, 80.0f);
111 ImGui::TableSetupColumn(
"Camera X", ImGuiTableColumnFlags_WidthFixed,
113 ImGui::TableSetupColumn(
"Camera Y", ImGuiTableColumnFlags_WidthFixed,
115 ImGui::TableSetupColumn(
"Pick", ImGuiTableColumnFlags_WidthFixed, 50.0f);
116 ImGui::TableSetupColumn(
"Go", ImGuiTableColumnFlags_WidthFixed, 40.0f);
117 ImGui::TableHeadersRow();
120 ImGui::TableNextRow();
124 ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,
125 IM_COL32(80, 80, 0, 100));
128 ImGui::TableNextColumn();
129 ImGui::Text(
"%d", track.id);
131 ImGui::TableNextColumn();
132 uint16_t room_id =
static_cast<uint16_t
>(track.room_id);
134 absl::StrFormat(
"##Room%d", track.id).c_str(), &room_id, 60.0f)) {
135 track.room_id = room_id;
138 ImGui::TableNextColumn();
139 uint16_t start_x =
static_cast<uint16_t
>(track.start_x);
141 absl::StrFormat(
"##StartX%d", track.id).c_str(), &start_x,
143 track.start_x = start_x;
146 ImGui::TableNextColumn();
147 uint16_t start_y =
static_cast<uint16_t
>(track.start_y);
149 absl::StrFormat(
"##StartY%d", track.id).c_str(), &start_y,
151 track.start_y = start_y;
155 ImGui::TableNextColumn();
156 ImGui::PushID(track.id);
158 if (is_picking_this) {
159 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.8f, 0.6f, 0.0f, 1.0f));
162 if (is_picking_this) {
168 if (is_picking_this) {
169 ImGui::PopStyleColor();
171 if (ImGui::IsItemHovered()) {
172 ImGui::SetTooltip(is_picking_this ?
"Cancel picking"
173 :
"Pick coordinates from canvas");
178 ImGui::TableNextColumn();
179 ImGui::PushID(track.id + 1000);
185 if (ImGui::IsItemHovered()) {
186 ImGui::SetTooltip(
"Navigate to room $%04X", track.room_id);
196 std::filesystem::path path = std::filesystem::path(
project_root_) /
197 "Sprites/Objects/data/minecart_tracks.asm";
199 if (!std::filesystem::exists(path)) {
207 std::ifstream file(path);
208 std::stringstream buffer;
209 buffer << file.rdbuf();
210 std::string content = buffer.str();
212 std::vector<int> rooms;
216 if (!
ParseSection(content,
".TrackStartingRooms", rooms) ||
223 size_t count = std::min({rooms.size(), xs.size(), ys.size()});
224 for (
size_t i = 0; i < count; ++i) {
225 tracks_.push_back({(int)i, rooms[i], xs[i], ys[i]});
234 const std::string& label,
235 std::vector<int>& out_values) {
236 size_t pos = content.find(label);
237 if (pos == std::string::npos)
241 size_t start = pos + label.length();
244 std::regex dw_regex(R
"(dw\s+((?:\$[0-9A-Fa-f]{4}(?:,\s*)?)+))");
248 std::stringstream ss(content.substr(start));
250 while (std::getline(ss, line)) {
252 size_t trimmed_start = line.find_first_not_of(
" \t");
253 if (trimmed_start != std::string::npos && line[trimmed_start] ==
'.')
257 if (std::regex_search(line, match, dw_regex)) {
258 std::string values_str = match[1];
259 std::stringstream val_ss(values_str);
261 while (std::getline(val_ss, segment,
',')) {
263 segment.erase(0, segment.find_first_not_of(
" \t$"));
266 out_values.push_back(std::stoi(segment,
nullptr, 16));