3#include "absl/strings/str_format.h"
13 if (!overworld || !overworld->
is_loaded()) {
14 return absl::FailedPreconditionError(
"Overworld not loaded");
26 auto& holes = overworld->
holes();
27 for (
size_t i = 0; i < holes.size(); ++i) {
28 if (holes[i].deleted) {
30 holes[i].deleted =
false;
31 holes[i].map_id_ = map_id;
32 holes[i].x_ =
static_cast<int>(snapped_pos.x);
33 holes[i].y_ =
static_cast<int>(snapped_pos.y);
34 holes[i].entrance_id_ = 0;
35 holes[i].is_hole_ =
true;
38 holes[i].UpdateMapProperties(map_id);
40 LOG_DEBUG(
"EntityOps",
"Inserted hole at slot %zu: pos=(%d,%d) map=0x%02X",
41 i, holes[i].x_, holes[i].y_, map_id);
46 return absl::ResourceExhaustedError(
47 "No space available for new hole. Delete one first.");
52 for (
size_t i = 0; i < entrances->size(); ++i) {
53 if (entrances->at(i).deleted) {
55 entrances->at(i).deleted =
false;
56 entrances->at(i).map_id_ = map_id;
57 entrances->at(i).x_ =
static_cast<int>(snapped_pos.x);
58 entrances->at(i).y_ =
static_cast<int>(snapped_pos.y);
59 entrances->at(i).entrance_id_ = 0;
60 entrances->at(i).is_hole_ =
false;
63 entrances->at(i).UpdateMapProperties(map_id);
65 LOG_DEBUG(
"EntityOps",
"Inserted entrance at slot %zu: pos=(%d,%d) map=0x%02X",
66 i, entrances->at(i).x_, entrances->at(i).y_, map_id);
68 return &entrances->at(i);
71 return absl::ResourceExhaustedError(
72 "No space available for new entrance. Delete one first.");
79 if (!overworld || !overworld->
is_loaded()) {
80 return absl::FailedPreconditionError(
"Overworld not loaded");
92 for (
size_t i = 0; i < exits.size(); ++i) {
93 if (exits[i].deleted_) {
95 exits[i].deleted_ =
false;
96 exits[i].map_id_ = map_id;
97 exits[i].x_ =
static_cast<int>(snapped_pos.x);
98 exits[i].y_ =
static_cast<int>(snapped_pos.y);
102 exits[i].room_id_ = 0;
103 exits[i].x_scroll_ = 0;
104 exits[i].y_scroll_ = 0;
105 exits[i].x_camera_ = 0;
106 exits[i].y_camera_ = 0;
107 exits[i].x_player_ =
static_cast<uint16_t
>(snapped_pos.x);
108 exits[i].y_player_ =
static_cast<uint16_t
>(snapped_pos.y);
109 exits[i].scroll_mod_x_ = 0;
110 exits[i].scroll_mod_y_ = 0;
111 exits[i].door_type_1_ = 0;
112 exits[i].door_type_2_ = 0;
115 exits[i].UpdateMapProperties(map_id);
117 LOG_DEBUG(
"EntityOps",
"Inserted exit at slot %zu: pos=(%d,%d) map=0x%02X",
118 i, exits[i].x_, exits[i].y_, map_id);
124 return absl::ResourceExhaustedError(
125 "No space available for new exit. Delete one first.");
130 int game_state, uint8_t sprite_id) {
132 if (!overworld || !overworld->
is_loaded()) {
133 return absl::FailedPreconditionError(
"Overworld not loaded");
136 if (game_state < 0 || game_state > 2) {
137 return absl::InvalidArgumentError(
"Invalid game state (must be 0-2)");
144 auto* current_ow_map = overworld->
overworld_map(current_map);
149 int map_local_x =
static_cast<int>(snapped_pos.x) % 512;
150 int map_local_y =
static_cast<int>(snapped_pos.y) % 512;
153 uint8_t game_x =
static_cast<uint8_t
>(map_local_x / 16);
154 uint8_t game_y =
static_cast<uint8_t
>(map_local_y / 16);
161 current_ow_map->current_graphics(),
162 static_cast<uint8_t
>(map_id),
166 static_cast<int>(snapped_pos.x),
167 static_cast<int>(snapped_pos.y)
170 sprites.push_back(new_sprite);
175 LOG_DEBUG(
"EntityOps",
"Inserted sprite at game_state=%d: pos=(%d,%d) map=0x%02X id=0x%02X",
176 game_state, inserted_sprite->
x_, inserted_sprite->
y_, map_id, sprite_id);
178 return inserted_sprite;
185 if (!overworld || !overworld->
is_loaded()) {
186 return absl::FailedPreconditionError(
"Overworld not loaded");
193 auto* current_ow_map = overworld->
overworld_map(current_map);
198 int fake_id = current_map % 0x40;
199 int sy = fake_id / 8;
200 int sx = fake_id - (sy * 8);
203 int map_local_x =
static_cast<int>(snapped_pos.x) % 512;
204 int map_local_y =
static_cast<int>(snapped_pos.y) % 512;
207 uint8_t game_x =
static_cast<uint8_t
>(map_local_x / 16);
208 uint8_t game_y =
static_cast<uint8_t
>(map_local_y / 16);
216 static_cast<uint16_t
>(map_id),
217 static_cast<int>(snapped_pos.x),
218 static_cast<int>(snapped_pos.y),
224 inserted_item->
game_x_ = game_x;
225 inserted_item->
game_y_ = game_y;
227 LOG_DEBUG(
"EntityOps",
"Inserted item: pos=(%d,%d) game=(%d,%d) map=0x%02X id=0x%02X",
228 inserted_item->
x_, inserted_item->
y_, game_x, game_y, map_id, item_id);
230 return inserted_item;
Represents the full Overworld data, light and dark world.
const std::vector< OverworldEntrance > & holes() const
auto overworld_map(int i) const
auto mutable_sprites(int state)
A class for managing sprites in the overworld and underworld.
#define LOG_DEBUG(category, format,...)
absl::StatusOr< zelda3::OverworldItem * > InsertItem(zelda3::Overworld *overworld, ImVec2 mouse_pos, int current_map, uint8_t item_id)
Insert a new item at the specified position.
absl::StatusOr< zelda3::OverworldEntrance * > InsertEntrance(zelda3::Overworld *overworld, ImVec2 mouse_pos, int current_map, bool is_hole)
Flat helper functions for entity insertion/manipulation.
absl::StatusOr< zelda3::OverworldExit * > InsertExit(zelda3::Overworld *overworld, ImVec2 mouse_pos, int current_map)
Insert a new exit at the specified position.
ImVec2 SnapToEntityGrid(ImVec2 pos)
Snap position to 16x16 grid (standard entity positioning)
absl::StatusOr< zelda3::Sprite * > InsertSprite(zelda3::Overworld *overworld, ImVec2 mouse_pos, int current_map, int game_state, uint8_t sprite_id)
Insert a new sprite at the specified position.
ImVec2 ClampToOverworldBounds(ImVec2 pos)
Clamp position to valid overworld bounds.
uint8_t GetParentMapId(const zelda3::OverworldMap *map, int current_map)
Helper to get parent map ID for multi-area maps.
Main namespace for the application.