
主要对worldmapinfo.cpp做了相关修改
cpp
#include <algorithm>
#include <climits>
#include <cstdio>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include "getmapbyid.h"
#include "getmobinfobyid.h"
#include "getnpcbyid.h"
#include "hookt.h"
#include "wvs/msghandler.h"
#include "wvs/tooltip.h"
#include "wvs/util.h"
#include "ztl/ztl.h"
ZALLOC_GLOBAL
ZALLOCEX(ZAllocAnonSelector, 0x00BF0B00)
ZALLOCEX(ZAllocStrSelector<char>, 0x00BF0A90)
ZALLOCEX(ZAllocStrSelector<wchar_t>, 0x00BF0BA8)
namespace {
constexpr DWORD kAddrWorldMapOnMouseMove = 0x009EE2B3;
constexpr DWORD kAddrWorldMapOnDestroy = 0x009EB94A;
constexpr DWORD kAddrGetField = 0x00437A0C;
constexpr DWORD kAddrToolTipCtor = 0x008E49B5;
constexpr int kWorldMapSpotsPtrDw = 366;
constexpr int kWorldMapSpotStrideDwords = 17;
constexpr int kWorldMapSpotXDw = 0;
constexpr int kWorldMapSpotYDw = 1;
constexpr int kWorldMapCanvasOriginX = 13;
constexpr int kWorldMapCanvasOriginY = 35;
constexpr int kWorldMapSpotFieldArrayDw = 11;
constexpr int kWorldMapHitRadiusPx = 6;
constexpr int kToolTipMinWidth = 220;
constexpr int kToolTipMaxWidth = 320;
constexpr int kToolTipWidthPadding = 28;
constexpr int kToolTipScreenMargin = 8;
constexpr int kToolTipAnchorYOffset = 18;
constexpr int kToolTipTitleBarHeight = 18;
constexpr int kToolTipTitleTop = 8;
constexpr int kToolTipContentLeft = 12;
constexpr int kToolTipContentTop = 32;
constexpr int kToolTipLineHeight = 24; //+10
constexpr int kToolTipSectionGap = 6;
constexpr int kToolTipItemIndent = 6;
constexpr int kMobIconWidth = 20;
constexpr int kMobIconHeight = 20;
constexpr int kMobIconGap = 6;
constexpr unsigned long kToolTipFillColor = 0xFF141A24;
constexpr unsigned long kToolTipTitleFillColor = 0xFF423010;
constexpr unsigned long kToolTipSeparatorColor = 0x70E0C070;
constexpr unsigned long kToolTipTitleColor = 0xFFFFD45A;
constexpr unsigned long kToolTipMapColor = 0xFF6EDB7E;
constexpr unsigned long kToolTipMonsterHeaderColor = 0xFFFF6A6A;
constexpr unsigned long kToolTipNpcHeaderColor = 0xFF6FAFFF;
constexpr unsigned long kToolTipBodyColor = 0xFFFFFFFF;
constexpr unsigned long kToolTipShadowColor = 0xFF000000;
constexpr unsigned long kToolTipFontSize = 12;
constexpr int kMaxTooltipEntriesPerSection = 10;
const std::string kUnknownText = "未知";
const std::string kTitleText = "地图信息";
using WorldMapOnMouseMove = int(__thiscall*)(void*, int, int);
using WorldMapOnDestroy = void(__thiscall*)(void*);
using GetField = void* (__cdecl*)();
auto CWorldMapDlg__OnMouseMove_Orig =
reinterpret_cast<WorldMapOnMouseMove>(kAddrWorldMapOnMouseMove);
auto CWorldMapDlg__OnDestroy_Orig =
reinterpret_cast<WorldMapOnDestroy>(kAddrWorldMapOnDestroy);
GetField g_GetField = nullptr;
alignas(8) unsigned char g_toolTipBuffer[0x600];
bool g_toolTipInitialized = false;
enum class ToolTipLineKind {
MapName,
MonstersHeader,
MonsterItem,
NpcsHeader,
NpcItem,
Spacer,
};
struct SpotInfo {
int index = -1;
int mapId = 0;
int anchorX = 0;
int anchorY = 0;
};
struct MapToolTipData {
int mapId = 0;
std::string mapName;
std::vector<std::string> monsterLines;
std::vector<std::string> npcLines;
};
struct StyledToolTipLine {
std::string text;
ToolTipLineKind kind = ToolTipLineKind::MapName;
};
struct ToolTipFonts {
IWzFontPtr title;
IWzFontPtr mapName;
IWzFontPtr monstersHeader;
IWzFontPtr npcsHeader;
IWzFontPtr body;
IWzFontPtr shadow;
bool attempted = false;
};
std::unordered_map<int, MapToolTipData> g_mapCache;
ToolTipFonts g_toolTipFonts;
int* ReadIntPtrDw(const void* base, int dwordIndex) {
return *reinterpret_cast<int* const*>(
reinterpret_cast<const char*>(base) + dwordIndex * 4);
}
bool CreateBoldFont(IWzFontPtr& outFont, unsigned long color, unsigned long size = kToolTipFontSize) {
if (outFont) {
return true;
}
PcCreateObject<IWzFontPtr>(L"Canvas#Font", outFont, nullptr);
if (!outFont) {
return false;
}
Ztl_variant_t style = L"B";
auto createFont =
reinterpret_cast<HRESULT(__thiscall*)(IWzFont*, Ztl_bstr_t, unsigned long, unsigned long, const Ztl_variant_t&)>(
0x0046341A);
return SUCCEEDED(createFont(outFont, Ztl_bstr_t(L"Dotum"), size, color, style));
}
bool EnsureToolTipFonts() {
if (g_toolTipFonts.attempted) {
return g_toolTipFonts.title && g_toolTipFonts.mapName && g_toolTipFonts.monstersHeader &&
g_toolTipFonts.npcsHeader && g_toolTipFonts.body && g_toolTipFonts.shadow;
}
g_toolTipFonts.attempted = true;
try {
CreateBoldFont(g_toolTipFonts.title, kToolTipTitleColor);
CreateBoldFont(g_toolTipFonts.mapName, kToolTipMapColor);
CreateBoldFont(g_toolTipFonts.monstersHeader, kToolTipMonsterHeaderColor);
CreateBoldFont(g_toolTipFonts.npcsHeader, kToolTipNpcHeaderColor);
CreateBoldFont(g_toolTipFonts.body, kToolTipBodyColor);
CreateBoldFont(g_toolTipFonts.shadow, kToolTipShadowColor);
}
catch (...) {
}
return g_toolTipFonts.title && g_toolTipFonts.mapName && g_toolTipFonts.monstersHeader &&
g_toolTipFonts.npcsHeader && g_toolTipFonts.body && g_toolTipFonts.shadow;
}
IWzFont* GetFontForLine(const StyledToolTipLine& line) {
switch (line.kind) {
case ToolTipLineKind::MapName:
return g_toolTipFonts.mapName;
case ToolTipLineKind::MonstersHeader:
return g_toolTipFonts.monstersHeader;
case ToolTipLineKind::NpcsHeader:
return g_toolTipFonts.npcsHeader;
case ToolTipLineKind::MonsterItem:
case ToolTipLineKind::NpcItem:
return g_toolTipFonts.body;
case ToolTipLineKind::Spacer:
return nullptr;
}
return g_toolTipFonts.body;
}
int CalcTextWidth(IWzFont* font, const std::string& text) {
if (!font || text.empty()) {
return 0;
}
try {
return static_cast<int>(font->CalcTextWidth(text.c_str()));
}
catch (...) {
return static_cast<int>(text.size()) * 7;
}
}
std::string FitTextToWidth(IWzFont* font, const std::string& text, int maxWidth) {
if (!font || text.empty() || maxWidth <= 0) {
return text;
}
if (CalcTextWidth(font, text) <= maxWidth) {
return text;
}
static const std::string ellipsis = "...";
if (CalcTextWidth(font, ellipsis) > maxWidth) {
return std::string();
}
for (int length = static_cast<int>(text.size()) - 1; length > 0; --length) {
const std::string candidate = text.substr(0, static_cast<size_t>(length)) + ellipsis;
if (CalcTextWidth(font, candidate) <= maxWidth) {
return candidate;
}
}
return ellipsis;
}
std::vector<std::string> BuildMapDisplayLines(const std::string& mapName) {
std::string displayName = mapName.empty() || mapName == "Unknown" ? kUnknownText : mapName;
const std::string separator = " - ";
const size_t separatorPos = displayName.find(separator);
if (separatorPos != std::string::npos) {
const std::string streetName = displayName.substr(0, separatorPos);
const std::string mapOnlyName = displayName.substr(separatorPos + separator.size());
if (!mapOnlyName.empty() && !streetName.empty()) {
return { streetName, mapOnlyName };
}
}
return { displayName };
}
void DrawShadowText(IWzCanvas* canvas, int x, int y, const std::string& text, IWzFont* font) {
if (!canvas || !font || text.empty() || !EnsureToolTipFonts()) {
return;
}
canvas->DrawTextA(x + 1, y + 1, text.c_str(), g_toolTipFonts.shadow);
canvas->DrawTextA(x, y, text.c_str(), font);
}
bool TryGetWorldMapAbsPosition(void* ecx, int& left, int& top) {
try {
auto* ui = reinterpret_cast<IUIMsgHandler*>(ecx);
left = ui->GetAbsLeft();
top = ui->GetAbsTop();
return true;
}
catch (...) {
left = 0;
top = 0;
return false;
}
}
SpotInfo GetSpotAt(void* base, int rx, int ry) {
SpotInfo out;
int* spots = ReadIntPtrDw(base, kWorldMapSpotsPtrDw);
if (!spots) {
return out;
}
const int count = *(spots - 1);
if (count <= 0) {
return out;
}
const int canvasX = rx - kWorldMapCanvasOriginX;
const int canvasY = ry - kWorldMapCanvasOriginY;
const int hitRadiusSquared = kWorldMapHitRadiusPx * kWorldMapHitRadiusPx;
int bestIndex = -1;
int bestRadiusSquared = INT_MAX;
for (int i = 0; i < count; ++i) {
int* spot = spots + i * kWorldMapSpotStrideDwords;
auto fieldArray = *reinterpret_cast<unsigned* const*>(spot + kWorldMapSpotFieldArrayDw);
if (!fieldArray) {
continue;
}
const unsigned fieldCount = *(fieldArray - 1);
if (!fieldCount) {
continue;
}
const int dx = spot[kWorldMapSpotXDw] - canvasX;
const int dy = spot[kWorldMapSpotYDw] - canvasY;
const int radiusSquared = dx * dx + dy * dy;
if (radiusSquared <= hitRadiusSquared && radiusSquared < bestRadiusSquared) {
bestRadiusSquared = radiusSquared;
bestIndex = i;
}
}
if (bestIndex < 0) {
return out;
}
int* spot = spots + bestIndex * kWorldMapSpotStrideDwords;
auto fieldArray = *reinterpret_cast<unsigned* const*>(spot + kWorldMapSpotFieldArrayDw);
out.index = bestIndex;
out.mapId = (fieldArray && *(fieldArray - 1) > 0) ? static_cast<int>(fieldArray[0]) : 0;
out.anchorX = spot[kWorldMapSpotXDw] + kWorldMapCanvasOriginX;
out.anchorY = spot[kWorldMapSpotYDw] + kWorldMapCanvasOriginY;
return out;
}
void* GetFieldContext() {
if (!g_GetField) {
g_GetField = reinterpret_cast<GetField>(kAddrGetField);
}
return g_GetField ? g_GetField() : nullptr;
}
void EnsureToolTip() {
if (g_toolTipInitialized) {
return;
}
reinterpret_cast<void(__thiscall*)(void*)>(kAddrToolTipCtor)(g_toolTipBuffer);
g_toolTipInitialized = true;
}
void ToolTipClear() {
if (g_toolTipInitialized) {
reinterpret_cast<CUIToolTip*>(g_toolTipBuffer)->ClearToolTip();
}
}
std::string BuildCountHeader(size_t count, const char* singular, const char* plural) {
return std::string(count == 1 ? singular : plural) + " (" + std::to_string(count) + "):";
}
std::vector<StyledToolTipLine> BuildStyledLines(const MapToolTipData& data, int toolTipWidth) {
std::vector<StyledToolTipLine> lines;
const int headerWidth = (std::max)(40, toolTipWidth - (kToolTipContentLeft * 2));
const int bodyWidth = headerWidth;
for (const auto& mapLine : BuildMapDisplayLines(data.mapName)) {
lines.push_back({ FitTextToWidth(g_toolTipFonts.mapName, mapLine, headerWidth), ToolTipLineKind::MapName });
}
if (!data.monsterLines.empty()) {
lines.push_back({ "", ToolTipLineKind::Spacer });
const std::string monstersHeader = BuildCountHeader(data.monsterLines.size(), "Monstro", "Monstros");
lines.push_back({ FitTextToWidth(g_toolTipFonts.monstersHeader, monstersHeader, headerWidth), ToolTipLineKind::MonstersHeader });
for (const auto& entry : data.monsterLines) {
lines.push_back({ FitTextToWidth(g_toolTipFonts.body, entry, bodyWidth), ToolTipLineKind::MonsterItem });
}
}
if (!data.npcLines.empty()) {
lines.push_back({ "", ToolTipLineKind::Spacer });
const std::string npcsHeader = BuildCountHeader(data.npcLines.size(), "NPC", "NPCs");
lines.push_back({ FitTextToWidth(g_toolTipFonts.npcsHeader, npcsHeader, headerWidth), ToolTipLineKind::NpcsHeader });
for (const auto& entry : data.npcLines) {
lines.push_back({ FitTextToWidth(g_toolTipFonts.body, entry, bodyWidth), ToolTipLineKind::NpcItem });
}
}
return lines;
}
std::string BuildPlainDescription(const std::vector<StyledToolTipLine>& lines) {
std::string desc;
for (size_t i = 0; i < lines.size(); ++i) {
if (i > 0) {
desc += '\n';
}
desc += lines[i].text;
}
return desc;
}
int ComputeToolTipWidth(const MapToolTipData& data) {
if (!EnsureToolTipFonts()) {
return 260;
}
int width = CalcTextWidth(g_toolTipFonts.title, kTitleText);
for (const auto& mapLine : BuildMapDisplayLines(data.mapName)) {
width = (std::max)(width, CalcTextWidth(g_toolTipFonts.mapName, mapLine));
}
if (!data.monsterLines.empty()) {
width = (std::max)(width, CalcTextWidth(g_toolTipFonts.monstersHeader, BuildCountHeader(data.monsterLines.size(), "Monstro", "Monstros")));
}
if (!data.npcLines.empty()) {
width = (std::max)(width, CalcTextWidth(g_toolTipFonts.npcsHeader, BuildCountHeader(data.npcLines.size(), "NPC", "NPCs")));
}
for (const auto& monster : data.monsterLines) {
width = (std::max)(width, CalcTextWidth(g_toolTipFonts.body, monster));
}
for (const auto& npc : data.npcLines) {
width = (std::max)(width, CalcTextWidth(g_toolTipFonts.body, npc));
}
width += kToolTipWidthPadding;
return (std::clamp)(width, kToolTipMinWidth, kToolTipMaxWidth);
}
/* void DrawStyledToolTip(CUIToolTip* toolTip, const std::vector<StyledToolTipLine>& lines) {
if (!toolTip || !toolTip->m_pLayer || !EnsureToolTipFonts()) {
return;
}
IWzCanvasPtr canvas = toolTip->m_pLayer->canvas[0];
if (!canvas) {
return;
}
const int width = toolTip->m_nWidth;
const int height = toolTip->m_nHeight;
if (width <= 0 || height <= 0) {
return;
}
canvas->DrawRectangle(3, 3, (std::max)(0, width - 6), (std::max)(0, height - 6), kToolTipFillColor);
canvas->DrawRectangle(5, 5, (std::max)(0, width - 10), kToolTipTitleBarHeight, kToolTipTitleFillColor);
canvas->DrawRectangle(9, 27, (std::max)(0, width - 18), 1, kToolTipSeparatorColor);
std::string title = FitTextToWidth(g_toolTipFonts.title, kTitleText, (std::max)(40, width - 20));
const int titleWidth = CalcTextWidth(g_toolTipFonts.title, title);
const int titleX = (std::max)(6, (width - titleWidth) / 2);
DrawShadowText(canvas, titleX, kToolTipTitleTop, title, g_toolTipFonts.title);
int y = kToolTipContentTop;
for (const auto& line : lines) {
if (line.kind == ToolTipLineKind::Spacer) {
y += kToolTipSectionGap;
continue;
}
IWzFont* font = GetFontForLine(line);
if (!font) {
continue;
}
int x = kToolTipContentLeft;
if (line.kind == ToolTipLineKind::MapName) {
const int lineWidth = CalcTextWidth(font, line.text);
x = (std::max)(kToolTipContentLeft, (width - lineWidth) / 2);
}
DrawShadowText(canvas, x, y, line.text, font);
y += kToolTipLineHeight;
}
}*/
void DrawStyledToolTip(CUIToolTip* toolTip, const std::vector<StyledToolTipLine>& lines)
{
if (!toolTip || !toolTip->m_pLayer || !EnsureToolTipFonts()) {
return;
}
IWzCanvasPtr canvas = toolTip->m_pLayer->canvas[0];
if (!canvas) {
return;
}
const int width = toolTip->m_nWidth;
const int height = toolTip->m_nHeight;
if (width <= 0 || height <= 0) {
return;
}
canvas->DrawRectangle(3, 3, (std::max)(0, width - 6), (std::max)(0, height - 6), kToolTipFillColor);
canvas->DrawRectangle(5, 5, (std::max)(0, width - 10), kToolTipTitleBarHeight, kToolTipTitleFillColor);
canvas->DrawRectangle(9, 27, (std::max)(0, width - 18), 1, kToolTipSeparatorColor);
std::string title = FitTextToWidth(g_toolTipFonts.title, kTitleText, (std::max)(40, width - 20));
const int titleWidth = CalcTextWidth(g_toolTipFonts.title, title);
const int titleX = (std::max)(6, (width - titleWidth) / 2);
DrawShadowText(canvas, titleX, kToolTipTitleTop, title, g_toolTipFonts.title);
int y = kToolTipContentTop;
for (const auto& line : lines) {
if (line.kind == ToolTipLineKind::Spacer) {
y += kToolTipSectionGap;
continue;
}
IWzFont* font = GetFontForLine(line);
if (!font) {
continue;
}
int x = kToolTipContentLeft;
std::string drawText = line.text;
int mobId = 0;
const std::string prefix = "[MOBICON:";
if (drawText.rfind(prefix, 0) == 0) {
size_t endPos = drawText.find("]");
if (endPos != std::string::npos) {
mobId = std::atoi(
drawText.substr(prefix.size(), endPos - prefix.size()).c_str()
);
if (endPos + 2 <= drawText.size()) {
drawText = drawText.substr(endPos + 2);
}
else {
drawText.clear();
}
}
}
if (line.kind == ToolTipLineKind::MapName) {
const int lineWidth = CalcTextWidth(font, drawText);
x = (std::max)(kToolTipContentLeft, (width - lineWidth) / 2);
}
if (mobId > 0) {
IWzCanvasPtr icon = GetMobIconById(mobId);
if (icon) {
try {
canvas->CopyEx(
x,
y -4,
icon.GetInterfacePtr(),
CA_OVERWRITE,
kMobIconWidth,
kMobIconHeight,
0,
0,
static_cast<int>(icon->Getwidth()),
static_cast<int>(icon->Getheight()),
vtEmpty
);
}
catch (...) {
}
x += kMobIconWidth + kMobIconGap;
}
}
// 画文字
DrawShadowText(canvas, x, y, drawText, font);
// 行高统一控制(关键)
y += kToolTipLineHeight;
}
}
void ToolTipShow(int screenLeft, int screenTop, const MapToolTipData& data)
{
EnsureToolTip();
auto* toolTip = reinterpret_cast<CUIToolTip*>(g_toolTipBuffer);
toolTip->ClearToolTip();
const int width = ComputeToolTipWidth(data);
const auto lines = BuildStyledLines(data, width);
std::string descText = BuildPlainDescription(lines);
// 关键:因为我们自定义绘制的行高比原 tooltip 默认行高大,
// 所以这里补充空行,让 SetToolTip_String2 创建更高的背景。
int extraHeight = 0;
for (const auto& line : lines) {
if (line.kind == ToolTipLineKind::Spacer)
continue;
// 怪物行现在带 icon,行高更高
if (line.text.rfind("[MOBICON:", 0) == 0) {
extraHeight += 10;
}
}
// 底部额外留白
extraHeight += 16;
const int defaultLineHeight = 14;
int extraLines = (extraHeight + defaultLineHeight - 1) / defaultLineHeight;
for (int i = 0; i < extraLines; ++i) {
descText += "\n ";
}
ZXString<char> title(kTitleText.c_str());
ZXString<char> desc(descText.c_str());
toolTip->SetToolTip_String2(
screenLeft,
screenTop,
title,
desc,
0,
0,
0,
width,
1,
0
);
DrawStyledToolTip(toolTip, lines);
}
MapToolTipData GetMapToolTipData(int mapId) {
const auto cached = g_mapCache.find(mapId);
if (cached != g_mapCache.end()) {
return cached->second;
}
MapToolTipData result;
result.mapId = mapId;
result.mapName = GetMapById(mapId);
try {
wchar_t path[128];
swprintf(path, _countof(path), L"Map/Map/Map%d/%08d.img", mapId / 100000000, mapId);
IWzPropertyPtr pMap = get_rm()->GetObjectA(path).GetUnknown();
if (!pMap) {
g_mapCache[mapId] = result;
return result;
}
IWzPropertyPtr pLife = pMap->item[L"life"].GetUnknown();
if (!pLife) {
g_mapCache[mapId] = result;
return result;
}
std::unordered_set<int> seenMobs;
std::unordered_set<int> seenNpcs;
const int total = pLife->Getcount();
for (int i = 0; i < total; ++i) {
wchar_t indexText[16];
_itow_s(i, indexText, 10);
IWzPropertyPtr pEntry = get_unknown(pLife->item[indexText]);
if (!pEntry) {
continue;
}
const int id = get_int32(pEntry->item[L"id"], 0);
Ztl_variant_t vType = pEntry->item[L"type"];
if (vType.vt != VT_BSTR) {
continue;
}
const std::wstring type = static_cast<const wchar_t*>(_bstr_t(vType));
/* if (type == L"m") {
if (id > 0 && seenMobs.insert(id).second) {
const int level = GetMobLevelById(id);
std::string line = "[等级 " + std::to_string(level) + "] " + GetMobNameById(id);
result.monsterLines.push_back(std::move(line));
}
}*/
if (type == L"m") {
if (id > 0 && seenMobs.insert(id).second) {
const int level = GetMobLevelById(id);
std::string line =
"[MOBICON:" + std::to_string(id) + "] " +
"[等级 " + std::to_string(level) + "] " +
GetMobNameById(id);
result.monsterLines.push_back(std::move(line));
}
}
else if (type == L"n") {
if (id > 0 && seenNpcs.insert(id).second) {
result.npcLines.push_back(GetNpcById(id));
}
}
}
if (result.monsterLines.size() > kMaxTooltipEntriesPerSection) {
result.monsterLines.resize(kMaxTooltipEntriesPerSection);
}
if (result.npcLines.size() > kMaxTooltipEntriesPerSection) {
result.npcLines.resize(kMaxTooltipEntriesPerSection);
}
g_mapCache[mapId] = result;
return result;
}
catch (...) {
g_mapCache[mapId] = result;
return result;
}
}
int __fastcall CWorldMapDlg__OnMouseMove_hook(void* ecx, void*, int x, int y) {
if (!ecx) {
ToolTipClear();
return 0;
}
if (!GetFieldContext()) {
ToolTipClear();
return CWorldMapDlg__OnMouseMove_Orig(ecx, x, y);
}
void* base = reinterpret_cast<char*>(ecx) - 4;
const SpotInfo spot = GetSpotAt(base, x, y);
if (spot.index >= 0 && spot.mapId > 0) {
int absLeft = 0;
int absTop = 0;
TryGetWorldMapAbsPosition(ecx, absLeft, absTop);
try {
reinterpret_cast<IUIMsgHandler*>(ecx)->ClearToolTip();
}
catch (...) {
}
const MapToolTipData data = GetMapToolTipData(spot.mapId);
const int toolTipWidth = ComputeToolTipWidth(data);
const int desiredLeft = absLeft + spot.anchorX - (toolTipWidth / 2);
const int screenLeft = (std::clamp)(
desiredLeft,
kToolTipScreenMargin,
(std::max)(kToolTipScreenMargin, get_screen_width() - toolTipWidth - kToolTipScreenMargin));
const int screenTop = (std::max)(kToolTipScreenMargin, absTop + spot.anchorY + kToolTipAnchorYOffset);
ToolTipShow(screenLeft, screenTop, data);
return 0;
}
ToolTipClear();
const int result = CWorldMapDlg__OnMouseMove_Orig(ecx, x, y);
try {
reinterpret_cast<IUIMsgHandler*>(ecx)->ClearToolTip();
}
catch (...) {
}
return result;
}
void __fastcall CWorldMapDlg__OnDestroy_hook(void* ecx, void*) {
ToolTipClear();
CWorldMapDlg__OnDestroy_Orig(ecx);
}
} // namespace
void AttachMapInfoToolTip() {
ATTACH_HOOK(CWorldMapDlg__OnMouseMove_Orig, CWorldMapDlg__OnMouseMove_hook);
ATTACH_HOOK(CWorldMapDlg__OnDestroy_Orig, CWorldMapDlg__OnDestroy_hook);
}