30 ImGui::TextDisabled(
ICON_MD_INFO " No dungeon rooms loaded.");
35 const int ptr_table_end =
37 const bool collision_table_present =
39 const bool collision_data_region_present =
41 const bool collision_save_supported =
43 if (!collision_table_present) {
45 " Custom collision table missing (use an "
46 "expanded-collision Oracle ROM)");
48 tr(
"Expected ROM >= 0x%X bytes (custom collision pointer table end). "
49 "Current ROM is %zu bytes."),
50 ptr_table_end, rom_size);
52 }
else if (!collision_data_region_present) {
54 " Custom collision data region missing/truncated");
56 tr(
"Expected ROM >= 0x%X bytes (custom collision data soft end). "
57 "Current ROM is %zu bytes."),
64 if (room_id < 0 || room_id >= 296) {
69 auto& room = (*rooms)[room_id];
70 bool has_collision = room.has_custom_collision();
72 ImGui::BeginDisabled(!collision_save_supported);
73 if (ImGui::Button(has_collision ?
"Disable Custom Collision"
74 :
"Enable Custom Collision")) {
78 room.set_has_custom_collision(!has_collision);
88 has_collision = room.has_custom_collision();
95 ImGui::TextUnformatted(tr(
"Authoring"));
98 json_options.
filters.push_back({
"Custom Collision",
"json"});
99 json_options.
filters.push_back({
"All Files",
"*"});
101 ImGui::BeginDisabled(!collision_save_supported);
109 }
catch (
const std::exception& e) {
118 if (!exported_or.ok()) {
123 "custom_collision.json",
"json");
129 ImGui::EndDisabled();
142 if (!collision_save_supported) {
144 " This ROM cannot save custom collision edits "
145 "(expanded collision region missing).");
148 const auto& map = room.custom_collision();
149 size_t override_count = 0;
150 size_t floor_override_count = 0;
151 for (
size_t off = 0; off < map.tiles.size(); ++off) {
152 if (!map.HasOverride(off)) {
156 if (map.tiles[off] == 0x00) {
157 ++floor_override_count;
160 ImGui::Text(tr(
"Override tiles: %zu (%zu floor 00)"), override_count,
161 floor_override_count);
164 if (ImGui::Checkbox(tr(
"Show Collision Overlay"), &show_overlay)) {
171 tr(
"Painting requires an active interaction context."));
177 ImGui::BeginDisabled(!collision_save_supported);
178 if (ImGui::Checkbox(tr(
"Paint Mode"), &is_painting)) {
187 ImGui::EndDisabled();
191 theme.text_warning_yellow,
192 tr(
"Left-drag paints; Alt-drag or Erase mode clears override"));
197 int brush_radius = std::clamp(state.paint_brush_radius, 0, 8);
198 if (ImGui::SliderInt(tr(
"Brush Radius"), &brush_radius, 0, 8)) {
199 state.paint_brush_radius = brush_radius;
203 ImGui::TextDisabled(tr(
"%dx%d"), (brush_radius * 2) + 1,
204 (brush_radius * 2) + 1);
206 bool erase_override = state.paint_collision_erase;
207 if (ImGui::Checkbox(tr(
"Erase Override (Unset)"), &erase_override)) {
208 state.paint_collision_erase = erase_override;
211 if (ImGui::IsItemHovered()) {
213 tr(
"Removes custom collision overrides so tiles fall back to "
214 "underlying object collision. Hold Alt while painting to erase "
220 ImGui::BeginDisabled(state.paint_collision_erase);
221 if (ImGui::BeginCombo(tr(
"Collision Type"),
222 absl::StrFormat(
"%02X: %s", current_val,
223 (current_val < tile_types.size()
224 ? tile_types[current_val]
227 for (
int i = 0; i < static_cast<int>(tile_types.size()); ++i) {
228 bool selected = (current_val == i);
229 if (ImGui::Selectable(
230 absl::StrFormat(
"%02X: %s", i, tile_types[i]).c_str(),
232 state.paint_collision_value =
static_cast<uint8_t
>(i);
233 state.paint_collision_erase =
false;
239 ImGui::EndDisabled();
242 ImGui::Text(tr(
"Quick Select:"));
243 auto quick_button = [&](
const char* label,
const char* id, uint8_t val,
244 const char* tooltip =
nullptr) {
245 if (ImGui::Button(label)) {
246 state.paint_collision_value = val;
247 state.paint_collision_erase =
false;
250 if (tooltip && ImGui::IsItemHovered()) {
251 ImGui::SetTooltip(
"%s", tooltip);
255 "Floor Override (00)",
"quick_collision_floor_00", 0x00,
256 "Forces walkable floor (0x00) over solid object tiles. Use Erase "
257 "Override (or Alt-drag) to remove an override instead.");
259 quick_button(
"Solid (02)",
"quick_collision_solid_02", 0x02);
261 quick_button(
"D.Water (08)",
"quick_collision_dwater_08", 0x08);
262 quick_button(
"S.Water (09)",
"quick_collision_swater_09", 0x09);
264 quick_button(
"Pit (1B)",
"quick_collision_pit_1b", 0x1B);
266 quick_button(
"Spikes (0E)",
"quick_collision_spikes_0e", 0x0E);
270 ImGui::BeginDisabled(!collision_save_supported);
271 if (ImGui::Button(tr(
"Clear All Custom Collision"))) {
276 room.custom_collision() = {};
277 room.MarkCustomCollisionDirty();
288 ImGui::EndDisabled();
291 tr(
"Custom collision allows you to override the physics of individual "
292 "8x8 tiles in the room. This is useful for creating water, pits, or "
293 "walkable floor passages over solid objects."));
std::vector< CustomCollisionTileEntry > tiles