yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
minecart_collision_tool.cc
Go to the documentation of this file.
2
6#include "imgui/imgui.h"
7
8namespace yaze::editor {
9namespace {
10bool IsStop(uint8_t value) {
11 return value >= 0xB7 && value <= 0xBA;
12}
13bool IsSwitch(uint8_t value) {
14 return value >= 0xD0 && value <= 0xD3;
15}
16bool IsRail(uint8_t value) {
17 return (value >= 0xB0 && value <= 0xBE) || IsSwitch(value);
18}
19} // namespace
20
21absl::StatusOr<zelda3::CustomCollisionMap> PreviewMinecartCollisionStamp(
22 const zelda3::CustomCollisionMap& before,
23 const MinecartCollisionStamp& stamp) {
24 if ((stamp.size != 1 && stamp.size != 2) || stamp.x < 0 || stamp.y < 0 ||
25 stamp.x > 64 - stamp.size || stamp.y > 64 - stamp.size ||
26 (stamp.value != 0 && !IsRail(stamp.value))) {
27 return absl::InvalidArgumentError("Choose a rail stamp inside the room");
28 }
29 auto after = before;
30 for (int y = stamp.y; y < stamp.y + stamp.size; ++y) {
31 for (int x = stamp.x; x < stamp.x + stamp.size; ++x) {
32 const auto old = before.tiles[y * 64 + x];
33 if (before.HasOverride(y * 64 + x) && !IsRail(old)) {
34 return absl::FailedPreconditionError(
35 "Other collision occupies this cell; use the collision inspector");
36 }
37 if (stamp.value != 0 && ((IsStop(old) && !IsStop(stamp.value)) ||
38 (IsSwitch(old) && !IsSwitch(stamp.value)))) {
39 return absl::FailedPreconditionError(
40 "Stop or switch protected; choose the matching behavior tool");
41 }
42 if (stamp.value == 0) {
43 // The rail tool's erase stamp removes an override, not floor physics.
44 after.ClearOverride(y * 64 + x);
45 } else {
46 after.SetOverride(y * 64 + x, stamp.value);
47 }
48 }
49 }
50 after.has_data = before.has_data || stamp.value != 0;
51 return after;
52}
53
55 const zelda3::CustomCollisionMap& collision,
56 int room_id, uint8_t value, int size,
57 const MinecartCollisionApply& apply) {
58 const DungeonCanvasTransform transform(rt.canvas_p0, rt.scrolling, rt.scale);
59 auto [x, y] = transform.ScreenToRoomTiles(ImGui::GetMousePos(), 8);
60 if (!rt.hovered || x < 0 || y < 0 || x >= 64 || y >= 64) {
61 message_.clear();
62 return;
63 }
64 // Two-cell stamps align with the 16 pixel art / sprite grid.
65 if (size == 2) {
66 x &= ~1;
67 y &= ~1;
68 }
69 const MinecartCollisionStamp stamp{x, y, size, value};
70 const auto preview = PreviewMinecartCollisionStamp(collision, stamp);
71 const auto delta = ImGui::GetIO().MouseDelta;
72 if (message_.empty() || delta.x != 0 || delta.y != 0 || !preview.ok()) {
73 message_ = preview.ok()
74 ? "Click to stamp. Click the room canvas, then Escape "
75 "leaves stamping."
76 : std::string(preview.status().message());
77 }
78 const auto& theme = AgentUI::GetTheme();
79 if (rt.draw_list) {
80 const ImVec2 max(rt.canvas_p0.x + rt.canvas_sz.x * transform.scale(),
81 rt.canvas_p0.y + rt.canvas_sz.y * transform.scale());
82 rt.draw_list->PushClipRect(rt.canvas_p0, max, true);
83 const auto color = ImGui::GetColorU32(preview.ok() ? theme.status_warning
84 : theme.status_error);
85 for (int dy = 0; dy < size; ++dy) {
86 for (int dx = 0; dx < size; ++dx) {
87 const auto p =
88 transform.RoomPixelsToScreen(ImVec2((x + dx) * 8, (y + dy) * 8));
89 const auto q = transform.RoomPixelsToScreen(
90 ImVec2((x + dx + 1) * 8, (y + dy + 1) * 8));
91 rt.draw_list->AddRectFilled(p, q, (color & 0x00FFFFFF) | 0x55000000);
92 rt.draw_list->AddRect(p, q, color);
93 }
94 }
95 rt.draw_list->PopClipRect();
96 }
97 if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && preview.ok() && apply &&
98 !ImGui::IsMouseDown(ImGuiMouseButton_Middle) &&
99 !ImGui::IsMouseDown(ImGuiMouseButton_Right)) {
100 const auto status = apply(room_id, collision, stamp);
101 if (!status.ok())
102 message_ = std::string(status.message());
103 }
104 ImGui::BeginTooltip();
105 ImGui::Text("Upper layer: %d x %d cells at %d, %d", size, size, x, y);
106 ImGui::TextUnformatted(message_.c_str());
107 ImGui::EndTooltip();
108}
109
110} // namespace yaze::editor
std::pair< int, int > ScreenToRoomTiles(ImVec2 screen, int tile_size) const
void Draw(const gui::CanvasRuntime &rt, const zelda3::CustomCollisionMap &collision, int room_id, uint8_t value, int size, const MinecartCollisionApply &apply)
const AgentUITheme & GetTheme()
Editors are the view controllers for the application.
std::function< absl::Status( int, const zelda3::CustomCollisionMap &, const MinecartCollisionStamp &)> MinecartCollisionApply
absl::StatusOr< zelda3::CustomCollisionMap > PreviewMinecartCollisionStamp(const zelda3::CustomCollisionMap &before, const MinecartCollisionStamp &stamp)
std::array< uint8_t, 64 *64 > tiles
bool HasOverride(size_t offset) const