/
Mr.Stalin
/
FOnline-Engine
Обзор
Документация
Войти
/
Mr.Stalin
/
FOnline-Engine
Код
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
Source/Scripting/ClientMapScriptMethods.cpp
913 строк
28 KB
cvet
feat(map): enhance roof handling by adding GetHiddenRoofNum method and updating roof number retrieval logic
10 авг 2026, 18:20
10 авг 2026, 18:20
46d2044
Код
Авторство
О чём код?
// __________ ___ ______ _ // / ____/ __ \____ / (_)___ ___ / ____/___ ____ _(_)___ ___ // / /_ / / / / __ \/ / / __ \/ _ \ / __/ / __ \/ __ `/ / __ \/ _ ` // / __/ / /_/ / / / / / / / / / __/ / /___/ / / / /_/ / / / / / __/ // /_/ \____/_/ /_/_/_/_/ /_/\___/ /_____/_/ /_/\__, /_/_/ /_/\___/ // /____/ // FOnline Engine // https://fonline.ru // https://github.com/cvet/fonline // // MIT License // // Copyright (c) 2006 - 2026, Anton Tsvetinskiy aka cvet <cvet@tut.by> // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // #include "Common.h" #include "Client.h" #include "Geometry.h" #include "MapSprite.h" #include "ScriptSystem.h" FO_BEGIN_NAMESPACE ///@ ExportMethod FO_SCRIPT_API void Client_Map_DrawMap(ptr<MapView> self) { if (!self->GetEngine()->CanDrawInScripts) { throw ScriptException("You can use this function only in RenderIface event"); } self->DrawMap(); } ///@ ExportMethod FO_SCRIPT_API void Client_Map_DrawMapSprite(ptr<MapView> self, ptr<MapSpriteHolder> mapSpr) { auto engine = self->GetEngine(); if (!self->GetSize().is_valid_pos(mapSpr->Hex)) { return; } if (!self->IsHexToDraw(mapSpr->Hex)) { return; } auto anim = engine->AnimGetSpr(mapSpr->SprId); if (!anim) { return; } ucolor color = mapSpr->Color; bool is_flat = mapSpr->IsFlat; bool no_light = mapSpr->NoLight; DrawOrderType draw_order = mapSpr->DrawOrder; int32_t draw_order_hy_offset = mapSpr->DrawOrderHyOffset; CornerType corner = mapSpr->Corner; bool disable_egg = mapSpr->DisableEgg; if (mapSpr->ProtoId) { auto proto = engine->GetProtoItem(mapSpr->ProtoId); FO_VERIFY_AND_THROW(proto, "Map sprite references unknown item proto"); color = proto->GetColorize() ? proto->GetColorizeColor() : ucolor::clear; is_flat = proto->GetDrawFlatten(); no_light = is_flat && !(proto->GetIsScenery() || proto->GetIsWall()); draw_order = is_flat ? (proto->GetStatic() ? DrawOrderType::FlatItemPreLight : DrawOrderType::FlatItemAfterLight) : DrawOrderType::Item; draw_order_hy_offset = numeric_cast<int32_t>(proto->GetDrawOrderOffsetHexY()); corner = proto->GetCorner(); disable_egg = proto->GetDisableEgg(); } auto mspr = self->AddMapSprite(anim, mapSpr->Hex, draw_order, draw_order_hy_offset, // mapSpr->Offset, mapSpr->IsTweakOffs ? &mapSpr->TweakOffset : nullptr, // mapSpr->IsTweakAlpha ? &mapSpr->TweakAlpha : nullptr, &mapSpr->Valid); mapSpr->MSpr = mspr; if (mapSpr->Angle != 0) { mspr->SetAngle(mapSpr->Angle); } if (mapSpr->MapProjected) { mspr->SetMapProjected(true); } if (!no_light) { mspr->SetLight(corner, self->GetLightData(), self->GetSize()); } if (!is_flat && !disable_egg) { EggAppearenceType egg_appearence; switch (corner) { case CornerType::South: egg_appearence = EggAppearenceType::ByXOrY; break; case CornerType::North: egg_appearence = EggAppearenceType::ByXAndY; break; case CornerType::EastWest: case CornerType::West: egg_appearence = EggAppearenceType::ByY; break; default: egg_appearence = EggAppearenceType::ByX; break; } mspr->SetEggAppearence(egg_appearence); } if (color != ucolor::clear) { mspr->SetColor(ucolor {color, 0}); mspr->SetFixedAlpha(color.comp.a); } } ///@ ExportMethod FO_SCRIPT_API bool Client_Map_DrawEntitySprite(ptr<MapView> self, ptr<ClientEntity> entity, int32_t effectSubtype, ucolor color, int32_t padding) { auto engine = self->GetEngine(); if (!engine->CanDrawInScripts) { throw ScriptException("You can use this function only in render events"); } if (padding < 0) { throw ScriptException("Negative padding"); } auto effect = engine->GetOffscreenEffect(effectSubtype); return self->DrawEntitySprite(entity, effect, color, padding); } ///@ ExportMethod FO_SCRIPT_API void Client_Map_RebuildFog(ptr<MapView> self) { self->RebuildFog(); } ///@ ExportMethod FO_SCRIPT_API void Client_Map_SetDayColors(ptr<MapView> self, ucolor mapDayColor, int32_t mapLightCapacity, ucolor globalDayColor, int32_t globalLightCapacity) { self->SetDayColors(mapDayColor, mapLightCapacity, globalDayColor, globalLightCapacity); } ///@ ExportMethod FO_SCRIPT_API isize32 Client_Map_GetScreenSize(ptr<MapView> self) { return self->GetScreenSize(); } ///@ ExportMethod FO_SCRIPT_API void Client_Map_SetScreenSize(ptr<MapView> self, isize32 size) { self->SetScreenSize(size); } ///@ ExportMethod FO_SCRIPT_API bool Client_Map_IsScrollCheck(ptr<MapView> self) { return self->IsScrollCheck(); } ///@ ExportMethod FO_SCRIPT_API void Client_Map_SetScrollCheck(ptr<MapView> self, bool enabled) { self->SetScrollCheck(enabled); } ///@ ExportMethod FO_SCRIPT_API void Client_Map_SetExtraScrollOffset(ptr<MapView> self, fpos32 offset) { self->SetExtraScrollOffset(offset); } ///@ ExportMethod FO_SCRIPT_API nptr<ItemView> Client_Map_GetItem(ptr<MapView> self, ident_t itemId) { if (!itemId) { throw ScriptException("Item id arg is zero"); } auto item = self->GetItem(itemId); return item; } ///@ ExportMethod FO_SCRIPT_API nptr<ItemView> Client_Map_GetItemOnHex(ptr<MapView> self, mpos hex) { if (!self->GetSize().is_valid_pos(hex)) { throw ScriptException("Invalid hex arg"); } auto item = self->GetItemOnHex(hex); return item; } ///@ ExportMethod FO_SCRIPT_API vector<ptr<ItemView>> Client_Map_GetItems(ptr<MapView> self) { span<refcount_ptr<ItemHexView>> map_items = self->GetItems(); return MakeScriptRefHandleVectorAs<ItemView, ItemHexView>(map_items); } ///@ ExportMethod FO_SCRIPT_API vector<ptr<ItemView>> Client_Map_GetItemsOnHex(ptr<MapView> self, mpos hex) { if (!self->GetSize().is_valid_pos(hex)) { throw ScriptException("Invalid hex arg"); } span<ptr<ItemHexView>> hex_items = self->GetItemsOnHex(hex); return vector<ptr<ItemView>>(hex_items.begin(), hex_items.end()); } ///@ ExportMethod FO_SCRIPT_API nptr<CritterView> Client_Map_GetCritter(ptr<MapView> self, ident_t critterId) { if (!critterId) { return nullptr; } auto cr = self->GetCritter(critterId); return cr; } ///@ ExportMethod FO_SCRIPT_API nptr<CritterView> Client_Map_GetCritterOnHex(ptr<MapView> self, mpos hex, CritterFindType findType) { if (!self->GetSize().is_valid_pos(hex)) { throw ScriptException("Invalid hex arg"); } vector<ptr<CritterHexView>> critters = self->GetCrittersOnHex(hex, findType); std::ranges::stable_sort(critters, [&hex](ptr<const CritterHexView> cr1, ptr<const CritterHexView> cr2) { int32_t dist1 = GeometryHelper::GetDistance(hex, cr1->GetHex()) - cr1->GetMultihex(); int32_t dist2 = GeometryHelper::GetDistance(hex, cr2->GetHex()) - cr2->GetMultihex(); return dist1 < dist2; }); if (critters.empty()) { return nullptr; } auto cr = critters.front(); return cr; } ///@ ExportMethod FO_SCRIPT_API nptr<CritterView> Client_Map_GetCritterInRadius(ptr<MapView> self, mpos hex, int32_t radius, CritterFindType findType) { if (!self->GetSize().is_valid_pos(hex)) { throw ScriptException("Invalid hex arg"); } vector<ptr<CritterHexView>> critters = self->GetCrittersInRadius(hex, radius, findType); std::ranges::stable_sort(critters, [&hex](ptr<const CritterHexView> cr1, ptr<const CritterHexView> cr2) { int32_t dist1 = GeometryHelper::GetDistance(hex, cr1->GetHex()) - cr1->GetMultihex(); int32_t dist2 = GeometryHelper::GetDistance(hex, cr2->GetHex()) - cr2->GetMultihex(); return dist1 < dist2; }); if (critters.empty()) { return nullptr; } auto cr = critters.front(); return cr; } ///@ ExportMethod FO_SCRIPT_API vector<ptr<CritterView>> Client_Map_GetCritters(ptr<MapView> self, CritterFindType findType = CritterFindType::Any) { span<refcount_ptr<CritterHexView>> map_critters = self->GetCritters(); vector<ptr<CritterView>> critters; critters.reserve(map_critters.size()); for (size_t i = 0; i < map_critters.size(); i++) { auto cr = map_critters[i].as_ptr(); if (cr->CheckFind(findType)) { critters.emplace_back(cr); } } return critters; } ///@ ExportMethod FO_SCRIPT_API vector<ptr<CritterView>> Client_Map_GetCritters(ptr<MapView> self, hstring pid, CritterFindType findType) { span<refcount_ptr<CritterHexView>> map_critters = self->GetCritters(); vector<ptr<CritterView>> critters; for (size_t i = 0; i < map_critters.size(); i++) { auto cr = map_critters[i].as_ptr(); if (cr->GetProtoId() == pid && cr->CheckFind(findType)) { critters.emplace_back(cr); } } return critters; } ///@ ExportMethod FO_SCRIPT_API vector<ptr<CritterView>> Client_Map_GetCritters(ptr<MapView> self, ptr<ProtoCritter> proto, CritterFindType findType) { span<refcount_ptr<CritterHexView>> map_critters = self->GetCritters(); vector<ptr<CritterView>> critters; for (size_t i = 0; i < map_critters.size(); i++) { auto cr = map_critters[i].as_ptr(); if (cr->GetProtoId() == proto->GetProtoId() && cr->CheckFind(findType)) { critters.emplace_back(cr); } } return critters; } ///@ ExportMethod FO_SCRIPT_API vector<ptr<CritterView>> Client_Map_GetCrittersOnHex(ptr<MapView> self, mpos hex, CritterFindType findType) { if (!self->GetSize().is_valid_pos(hex)) { throw ScriptException("Invalid hex arg"); } vector<ptr<CritterHexView>> critters = self->GetCrittersOnHex(hex, findType); std::ranges::stable_sort(critters, [&hex](ptr<const CritterHexView> cr1, ptr<const CritterHexView> cr2) { int32_t dist1 = GeometryHelper::GetDistance(hex, cr1->GetHex()) - cr1->GetMultihex(); int32_t dist2 = GeometryHelper::GetDistance(hex, cr2->GetHex()) - cr2->GetMultihex(); return dist1 < dist2; }); return vector<ptr<CritterView>>(critters.begin(), critters.end()); } ///@ ExportMethod FO_SCRIPT_API vector<ptr<CritterView>> Client_Map_GetCrittersInRadius(ptr<MapView> self, mpos hex, int32_t radius, CritterFindType findType) { if (!self->GetSize().is_valid_pos(hex)) { throw ScriptException("Invalid hex arg"); } vector<ptr<CritterHexView>> critters = self->GetCrittersInRadius(hex, radius, findType); std::ranges::stable_sort(critters, [&hex](ptr<const CritterHexView> cr1, ptr<const CritterHexView> cr2) { int32_t dist1 = GeometryHelper::GetDistance(hex, cr1->GetHex()) - cr1->GetMultihex(); int32_t dist2 = GeometryHelper::GetDistance(hex, cr2->GetHex()) - cr2->GetMultihex(); return dist1 < dist2; }); return vector<ptr<CritterView>>(critters.begin(), critters.end()); } ///@ ExportMethod FO_SCRIPT_API vector<ptr<CritterView>> Client_Map_GetCrittersInPath(ptr<MapView> self, mpos fromHex, mpos toHex, float32_t angle, int32_t dist, CritterFindType findType) { if (!self->GetSize().is_valid_pos(fromHex)) { throw ScriptException("Invalid fromHex arg"); } if (!self->GetSize().is_valid_pos(toHex)) { throw ScriptException("Invalid toHex arg"); } vector<ptr<CritterHexView>> critters; self->TraceBullet(fromHex, toHex, dist, angle, &critters, findType, nullptr, nullptr, nullptr, true); return vector<ptr<CritterView>>(critters.begin(), critters.end()); } ///@ ExportMethod FO_SCRIPT_API vector<ptr<CritterView>> Client_Map_GetCrittersWithBlockInPath(ptr<MapView> self, mpos fromHex, mpos toHex, float32_t angle, int32_t dist, CritterFindType findType, mpos& preBlockHex, mpos& blockHex) { if (!self->GetSize().is_valid_pos(fromHex)) { throw ScriptException("Invalid fromHex arg"); } if (!self->GetSize().is_valid_pos(toHex)) { throw ScriptException("Invalid toHex arg"); } vector<ptr<CritterHexView>> critters; self->TraceBullet(fromHex, toHex, dist, angle, &critters, findType, &preBlockHex, &blockHex, nullptr, true); return vector<ptr<CritterView>>(critters.begin(), critters.end()); } ///@ ExportMethod FO_SCRIPT_API void Client_Map_GetHexInPath(ptr<MapView> self, mpos fromHex, mpos& toHex, float32_t angle, int32_t dist) { if (!self->GetSize().is_valid_pos(fromHex)) { throw ScriptException("Invalid fromHex arg"); } if (!self->GetSize().is_valid_pos(toHex)) { throw ScriptException("Invalid toHex arg"); } mpos pre_block; self->TraceBullet(fromHex, toHex, dist, angle, nullptr, CritterFindType::Any, &pre_block, nullptr, nullptr, true); toHex = pre_block; } ///@ ExportMethod FO_SCRIPT_API vector<mdir> Client_Map_GetPath(ptr<MapView> self, mpos fromHex, mpos toHex, int32_t cut) { if (!self->GetSize().is_valid_pos(fromHex)) { throw ScriptException("Invalid fromHex arg"); } if (!self->GetSize().is_valid_pos(toHex)) { throw ScriptException("Invalid toHex arg"); } if (GeometryHelper::GetDistance(fromHex, toHex) <= 1) { if (GeometryHelper::GetDistance(fromHex, toHex) > 0 && cut == 0) { return {GeometryHelper::GetHexDir(fromHex, toHex)}; } return {}; } mpos to_hex = toHex; mpos init_to_hex = toHex; if (cut > 0 && !self->CutPath(nullptr, fromHex, to_hex, numeric_cast<int32_t>(cut))) { return {}; } if (cut > 0 && GeometryHelper::GetDistance(fromHex, init_to_hex) <= cut && GeometryHelper::GetDistance(fromHex, to_hex) <= 1) { return {}; } auto result = self->FindPath(nullptr, fromHex, to_hex, -1); if (!result) { return {}; } return result->DirSteps; } ///@ ExportMethod FO_SCRIPT_API vector<mdir> Client_Map_GetPath(ptr<MapView> self, ptr<CritterView> cr, mpos toHex, int32_t cut) { if (!self->GetSize().is_valid_pos(toHex)) { throw ScriptException("Invalid toHex arg"); } auto hex_cr = cr.dyn_cast<CritterHexView>(); if (!hex_cr) { throw ScriptException("Critter is not on map"); } if (GeometryHelper::GetDistance(hex_cr->GetHex(), toHex) <= 1 + hex_cr->GetMultihex()) { if (GeometryHelper::GetDistance(hex_cr->GetHex(), toHex) > hex_cr->GetMultihex() && cut == 0) { return {GeometryHelper::GetHexDir(hex_cr->GetHex(), toHex)}; } return {}; } mpos to_hex = toHex; mpos init_to_hex = toHex; if (cut > 0 && !self->CutPath(hex_cr, hex_cr->GetHex(), to_hex, numeric_cast<int32_t>(cut))) { return {}; } if (cut > 0 && GeometryHelper::GetDistance(hex_cr->GetHex(), init_to_hex) <= cut + hex_cr->GetMultihex() && GeometryHelper::GetDistance(hex_cr->GetHex(), to_hex) <= 1 + hex_cr->GetMultihex()) { return {}; } auto result = self->FindPath(hex_cr, hex_cr->GetHex(), to_hex, -1); if (!result) { return {}; } return result->DirSteps; } ///@ ExportMethod FO_SCRIPT_API int32_t Client_Map_GetPathLength(ptr<MapView> self, mpos fromHex, mpos toHex, int32_t cut) { if (!self->GetSize().is_valid_pos(fromHex)) { throw ScriptException("Invalid fromHex arg"); } if (!self->GetSize().is_valid_pos(toHex)) { throw ScriptException("Invalid toHex arg"); } if (GeometryHelper::GetDistance(fromHex, toHex) <= 1) { return cut > 0 ? 0 : 1; } mpos to_hex = toHex; mpos init_to_hex = toHex; if (cut > 0 && !self->CutPath(nullptr, fromHex, to_hex, numeric_cast<int32_t>(cut))) { return 0; } if (cut > 0 && GeometryHelper::GetDistance(fromHex, init_to_hex) <= cut && GeometryHelper::GetDistance(fromHex, to_hex) <= 1) { return 0; } auto result = self->FindPath(nullptr, fromHex, to_hex, -1); if (!result) { return 0; } return numeric_cast<int32_t>(result->DirSteps.size()); } ///@ ExportMethod FO_SCRIPT_API int32_t Client_Map_GetPathLength(ptr<MapView> self, ptr<CritterView> cr, mpos toHex, int32_t cut) { if (!self->GetSize().is_valid_pos(toHex)) { throw ScriptException("Invalid toHex arg"); } auto hex_cr = cr.dyn_cast<CritterHexView>(); if (!hex_cr) { throw ScriptException("Critter is not on map"); } if (GeometryHelper::GetDistance(hex_cr->GetHex(), toHex) <= 1 + hex_cr->GetMultihex()) { return cut > 0 ? 0 : 1; } mpos to_hex = toHex; mpos init_to_hex = toHex; if (cut > 0 && !self->CutPath(hex_cr, hex_cr->GetHex(), to_hex, numeric_cast<int32_t>(cut))) { return 0; } if (cut > 0 && GeometryHelper::GetDistance(hex_cr->GetHex(), init_to_hex) <= cut + hex_cr->GetMultihex() && GeometryHelper::GetDistance(hex_cr->GetHex(), to_hex) <= 1 + hex_cr->GetMultihex()) { return 0; } auto result = self->FindPath(hex_cr, hex_cr->GetHex(), to_hex, -1); if (!result) { return 0; } return numeric_cast<int32_t>(result->DirSteps.size()); } ///@ ExportMethod FO_SCRIPT_API void Client_Map_MoveScreenToHex(ptr<MapView> self, mpos hex, ipos16 hex_offset, int32_t speed, bool canStop) { if (!self->GetSize().is_valid_pos(hex)) { throw ScriptException("Invalid hex arg"); } if (speed < 0) { throw ScriptException("Negative speed"); } if (speed == 0) { self->InstantScrollTo(hex); } else { self->ScrollToHex(hex, hex_offset, speed, canStop); } } ///@ ExportMethod FO_SCRIPT_API void Client_Map_ApplyScreenScroll(ptr<MapView> self, ipos32 offset, int32_t speed, bool canStop) { self->ApplyScrollOffset(offset, speed, canStop); } ///@ ExportMethod FO_SCRIPT_API bool Client_Map_IsAutoScrolling(ptr<MapView> self) { return self->IsAutoScrolling(); } ///@ ExportMethod FO_SCRIPT_API bool Client_Map_MoveHexByDir(ptr<MapView> self, mpos& hex, mdir dir) { if (GeometryHelper::MoveHexByDir(hex, dir, self->GetSize())) { return true; } else { return false; } } ///@ ExportMethod FO_SCRIPT_API int32_t Client_Map_MoveHexByDir(ptr<MapView> self, mpos& hex, mdir dir, int32_t steps) { int32_t result = 0; for (int32_t i = 0; i < steps; i++) { if (GeometryHelper::MoveHexByDir(hex, dir, self->GetSize())) { result++; } else { break; } } return result; } ///@ ExportMethod FO_SCRIPT_API void Client_Map_RedrawMap(ptr<MapView> self) { self->RebuildMap(); } ///@ ExportMethod FO_SCRIPT_API void Client_Map_ChangeZoom(ptr<MapView> self, float32_t targetZoom) { if (is_float_equal(targetZoom, self->GetSpritesZoomTarget())) { return; } fsize32 screen_size = fsize32(self->GetScreenSize()); auto input = self->GetEngine()->SprMngr.GetInput(); fpos32 mouse_pos = input->IsMouseAvailable() ? fpos32(input->GetMousePosition()) : fpos32 {screen_size.width / 2.0f, screen_size.height / 2.0f}; float32_t mouse_x_factor = std::clamp(mouse_pos.x / screen_size.width, 0.0f, 1.0f); float32_t mouse_y_factor = std::clamp(mouse_pos.y / screen_size.height, 0.0f, 1.0f); self->ChangeZoom(targetZoom, {mouse_x_factor, mouse_y_factor}); } ///@ ExportMethod FO_SCRIPT_API ipos32 Client_Map_GetHexScreenPos(ptr<MapView> self, mpos hex) { if (!self->GetSize().is_valid_pos(hex)) { throw ScriptException("Invalid hex provided"); } ipos32 hex_pos = self->GetHexMapPos(hex); ipos32 hex_center = {GameSettings::MAP_HEX_WIDTH / 2, GameSettings::MAP_HEX_HEIGHT / 2}; return self->MapToScreenPos(hex_pos + hex_center); } ///@ ExportMethod FO_SCRIPT_API ipos32 Client_Map_GetHexMapPos(ptr<MapView> self, mpos hex) { if (!self->GetSize().is_valid_pos(hex)) { throw ScriptException("Invalid hex provided"); } return self->GetHexMapPos(hex); } ///@ ExportMethod FO_SCRIPT_API fpos32 Client_Map_GetHexScreenPosF(ptr<MapView> self, mpos hex) { if (!self->GetSize().is_valid_pos(hex)) { throw ScriptException("Invalid hex provided"); } ipos32 hex_pos = self->GetHexMapPos(hex); ipos32 hex_center = {GameSettings::MAP_HEX_WIDTH / 2, GameSettings::MAP_HEX_HEIGHT / 2}; ipos32 map_pos = hex_pos + hex_center; return (fpos32(map_pos) - self->GetScrollOffset()) * self->GetSpritesZoom(); } ///@ ExportMethod FO_SCRIPT_API bool Client_Map_GetHexAtScreenPos(ptr<MapView> self, ipos32 pos, mpos& hex) { return self->GetHexAtScreen(pos, hex, nullptr); } ///@ ExportMethod FO_SCRIPT_API bool Client_Map_GetHexAtScreenPos(ptr<MapView> self, ipos32 pos, mpos& hex, ipos32& hexOffset) { return self->GetHexAtScreen(pos, hex, &hexOffset); } ///@ ExportMethod FO_SCRIPT_API void Client_Map_SetTransparentEgg(ptr<MapView> self, TransparentEggSlot slot, mpos hex, ipos32 hexOffset, isize32 eggSize) { self->SetTransparentEgg(slot, hex, hexOffset, eggSize, false); } ///@ ExportMethod FO_SCRIPT_API void Client_Map_SetTransparentEgg(ptr<MapView> self, TransparentEggSlot slot, nptr<CritterView> cr) { auto cr_hex = cr.dyn_cast<CritterHexView>(); if (!cr_hex) { self->ClearTransparentEgg(slot); return; } if (cr_hex->GetMap() != self || !cr_hex->IsMapSpriteValid()) { self->ClearTransparentEgg(slot); return; } // SetTransparentEgg expects a hex-center-relative offset; GetHexMapPos is the cell top-left, // so reference the hex visual center (top-left + half a hex) when measuring the sprite center. irect32 rect = cr_hex->GetViewRect(); ipos32 hex_pos = self->GetHexMapPos(cr_hex->GetHex()); ipos32 hex_center = {hex_pos.x + GameSettings::MAP_HEX_WIDTH / 2, hex_pos.y + GameSettings::MAP_HEX_HEIGHT / 2}; ipos32 center_offset = {rect.x + rect.width / 2 - hex_center.x, rect.y + rect.height / 2 - hex_center.y}; self->SetTransparentEgg(slot, cr_hex->GetHex(), center_offset, rect.size(), true); } ///@ ExportMethod FO_SCRIPT_API void Client_Map_ClearTransparentEgg(ptr<MapView> self, TransparentEggSlot slot) { self->ClearTransparentEgg(slot); } ///@ ExportMethod FO_SCRIPT_API nptr<ItemView> Client_Map_GetItemAtScreenPos(ptr<MapView> self, ipos32 pos) { bool item_egg; auto item = self->GetItemAtScreen(pos, item_egg, 0, true).first; return item; } ///@ ExportMethod FO_SCRIPT_API nptr<CritterView> Client_Map_GetCritterAtScreenPos(ptr<MapView> self, ipos32 pos, int32_t extraRange = 0) { auto cr = self->GetCritterAtScreen(pos, false, 0, true).first; if (!cr && extraRange != 0) { cr = self->GetCritterAtScreen(pos, true, extraRange, false).first; } return cr; } ///@ ExportMethod FO_SCRIPT_API nptr<ClientEntity> Client_Map_GetEntityAtScreenPos(ptr<MapView> self, ipos32 pos) { auto entity = self->GetEntityAtScreen(pos, 0, true).first; return entity; } ///@ ExportMethod FO_SCRIPT_API bool Client_Map_IsHexValid(ptr<MapView> self, mpos hex) { return self->GetSize().is_valid_pos(hex); } ///@ ExportMethod FO_SCRIPT_API vector<mpos> Client_Map_GetVisibleHexes(ptr<MapView> self) { msize map_size = self->GetSize(); vector<mpos> hexes; hexes.reserve(numeric_cast<size_t>(map_size.width) * numeric_cast<size_t>(map_size.height)); for (int32_t hy = 0; hy < map_size.height; hy++) { for (int32_t hx = 0; hx < map_size.width; hx++) { mpos hex = map_size.from_raw_pos(hx, hy); if (self->IsHexToDraw(hex)) { hexes.emplace_back(hex); } } } return hexes; } ///@ ExportMethod FO_SCRIPT_API bool Client_Map_IsHexVisible(ptr<MapView> self, mpos hex) { if (!self->GetSize().is_valid_pos(hex)) { throw ScriptException("Invalid hex arg"); } return self->GetField(hex).IsView; } ///@ ExportMethod FO_SCRIPT_API bool Client_Map_IsHexMovable(ptr<MapView> self, mpos hex) { if (!self->GetSize().is_valid_pos(hex)) { throw ScriptException("Invalid hex arg"); } return !self->GetField(hex).MoveBlocked; } ///@ ExportMethod FO_SCRIPT_API bool Client_Map_IsHexShootable(ptr<MapView> self, mpos hex) { if (!self->GetSize().is_valid_pos(hex)) { throw ScriptException("Invalid hex arg"); } return !self->GetField(hex).ShootBlocked; } ///@ ExportMethod FO_SCRIPT_API bool Client_Map_IsOutsideArea(ptr<MapView> self, mpos hex) { if (!self->GetSize().is_valid_pos(hex)) { throw ScriptException("Invalid hex arg"); } return self->IsOutsideArea(hex); } ///@ ExportMethod FO_SCRIPT_API ptr<FogLayer> Client_Map_AddFog(ptr<MapView> self, nptr<CritterView> cr, DrawOrderType drawOrder, int32_t flushEffectSubtype = -1) { nptr<RenderEffect> customFlushEffect = nullptr; if (flushEffectSubtype >= 0) { customFlushEffect = self->GetEngine()->GetOffscreenEffect(flushEffectSubtype); } auto fog = self->AddFog(cr, drawOrder, customFlushEffect); return fog; } ///@ ExportMethod FO_SCRIPT_API ptr<FogLayer> Client_Map_AddFog(ptr<MapView> self, mpos hex, DrawOrderType drawOrder, int32_t flushEffectSubtype = -1) { if (!self->GetSize().is_valid_pos(hex)) { throw ScriptException("Invalid hex arg"); } nptr<RenderEffect> customFlushEffect = nullptr; if (flushEffectSubtype >= 0) { customFlushEffect = self->GetEngine()->GetOffscreenEffect(flushEffectSubtype); } auto fog = self->AddFog(hex, drawOrder, customFlushEffect); return fog; } ///@ ExportMethod FO_SCRIPT_API nptr<SpritePattern> Client_Map_RunSpritePattern(ptr<MapView> self, string_view spriteName, int32_t spriteCount) { if (spriteCount < 1) { throw ScriptException("Invalid sprite count"); } auto sprite_pattern = self->RunSpritePattern(spriteName, spriteCount); return sprite_pattern; } ///@ ExportMethod FO_SCRIPT_API isize32 Client_Map_GetHexContentSize(ptr<MapView> self, mpos hex) { return self->GetHexContentSize(hex); } ///@ ExportMethod FO_SCRIPT_API ptr<ItemView> Client_Map_CreateLocalItem(ptr<MapView> self, hstring pid, mpos hex) { auto proto = self->GetEngine()->GetProtoItem(pid); if (!proto) { throw ScriptException("Invalid item pid arg"); } if (!self->GetSize().is_valid_pos(hex)) { throw ScriptException("Invalid hex arg"); } auto item = self->AddLocalItem(pid, hex); return item; } ///@ ExportMethod FO_SCRIPT_API void Client_Map_SetHiddenRoof(ptr<MapView> self, mpos hex) { self->SetHiddenRoof(hex); } ///@ ExportMethod FO_SCRIPT_API int32_t Client_Map_GetRoofNum(ptr<MapView> self, mpos hex) { if (!self->GetSize().is_valid_pos(hex)) { throw ScriptException("Invalid hex arg"); } return self->GetField(hex).RoofNum; } ///@ ExportMethod FO_SCRIPT_API int32_t Client_Map_GetHiddenRoofNum(ptr<MapView> self) { return self->GetHiddenRoofNum(); } FO_END_NAMESPACE