mirror of
https://github.com/brues-code/ClassicAPI.git
synced 2026-11-14 15:10:39 +00:00
Twenty modules each declared their own typedef or wrapper for FUN_LUA_TO_BOOLEAN_LOOSE (4.3.4's StringToBOOL(L, index, default)) or FUN_XML_ATTR_TO_BOOL (StringToBOOL(const char *)). Route them all through one helper each. frame/Cooldown.cpp had a C++ copy of both that read unknown attribute text as true; the engine's reader, which 4.3.4's XML loader uses, reads it as false. SetReverse/SetDrawEdge now also truncate numbers like every other 1.12 flag method.
138 lines
5.8 KiB
C++
138 lines
5.8 KiB
C++
// This file is part of ClassicAPI.
|
|
//
|
|
// ClassicAPI is free software: you can redistribute it and/or modify it under the terms
|
|
// of the GNU General Public License as published by the Free Software Foundation, either
|
|
// version 3 of the License, or (at your option) any later version.
|
|
//
|
|
// ClassicAPI is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
// PURPOSE. See the GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License along with
|
|
// ClassicAPI. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
// `InteractUnit(unitToken [, exactMatch])` — 4.3.4's Script_InteractUnit
|
|
// (GameUI_Scripts.cpp), the C global behind the INTERACTTARGET and
|
|
// INTERACTMOUSEOVER bindings (src/bindings/Bindings.xml).
|
|
//
|
|
// 4.3.4 resolves the argument, then hands the GUID to
|
|
// CGGameUI::OnSpriteRightClick — the same function a mouse right-click in
|
|
// the world runs. 1.12 has that function whole (FUN_ON_SPRITE_RIGHT_CLICK),
|
|
// so this is a call, not a reconstruction: targeting, the object's own
|
|
// right-click (vendor, loot, gossip, mailbox, …) and the autoloot modifier
|
|
// all come from the engine.
|
|
//
|
|
// Resolution, as 4.3.4 does it:
|
|
// - "mouseover" reads the hovered-object GUID directly
|
|
// (VAR_MOUSEOVER_GUID_*, 4.3.4's m_currentObjectTrack), which is any
|
|
// object type — so the mouseover binding works on game objects and
|
|
// corpses, not only units.
|
|
// - anything else goes through 4.3.4's ClosestObjectMatch(token,
|
|
// TYPEMASK_OBJECT, 0, exact, FLT_MAX): a unit token resolves to its
|
|
// GUID (an empty token is no match, never a name search); otherwise the
|
|
// engine's by-name search runs. 1.12's by-name search
|
|
// (FUN_UNIT_FIND_BY_NAME) lacks 4.3.4's leading token step, so the
|
|
// token step is IsUnitToken + FUN_TOKEN_TO_GUID here.
|
|
//
|
|
// `C_PlayerInteractionManager.InteractUnit(unit [, exactMatch [,
|
|
// looseTargeting]])` is the modern name the INTERACTTARGET /
|
|
// INTERACTMOUSEOVER bindings call (with "anyinteract", see
|
|
// target/SoftInteract.cpp): the same resolve and right-click, returning a
|
|
// boolean. looseTargeting has no 1.12 counterpart and is read by nothing.
|
|
//
|
|
// 4.3.4's taint gate is dropped: 1.12 has no secure environment, and every
|
|
// vanilla action function (TargetUnit, CastSpellByName, …) is callable.
|
|
|
|
#include "Game.h"
|
|
#include "Offsets.h"
|
|
#include "unit/Identity.h"
|
|
#include "unit/TokenResolve.h"
|
|
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
|
|
namespace Unit::Interact {
|
|
|
|
namespace {
|
|
|
|
using OnSpriteRightClick_t = int(__stdcall *)(uint32_t guidLo, uint32_t guidHi);
|
|
using TokenToGuid_t = uint64_t(__fastcall *)(const char *token);
|
|
|
|
uint64_t ResolveGuid(void *L, const char *token) {
|
|
if (_stricmp(token, "mouseover") == 0)
|
|
return Game::Read<uint64_t>(Offsets::VAR_MOUSEOVER_GUID_LO);
|
|
if (Unit::TokenResolve::IsUnitToken(token))
|
|
return reinterpret_cast<TokenToGuid_t>(Offsets::FUN_TOKEN_TO_GUID)(token);
|
|
return Unit::Identity::FindGuidByName(token, Offsets::TYPEMASK_OBJECT,
|
|
Game::Lua::ToFlag(L, 2));
|
|
}
|
|
|
|
bool Interact(void *L) {
|
|
const uint64_t guid = ResolveGuid(L, Game::Lua::ToString(L, 1));
|
|
return reinterpret_cast<OnSpriteRightClick_t>(Offsets::FUN_ON_SPRITE_RIGHT_CLICK)(
|
|
static_cast<uint32_t>(guid), static_cast<uint32_t>(guid >> 32)) != 0;
|
|
}
|
|
|
|
int __fastcall Script_InteractUnit(void *L) {
|
|
if (!Game::Lua::IsString(L, 1)) {
|
|
Game::Lua::Error(L, "Usage: InteractUnit(unitToken[, exactMatch])");
|
|
return 0;
|
|
}
|
|
if (Interact(L))
|
|
Game::Lua::PushNumber(L, 1.0);
|
|
else
|
|
Game::Lua::PushNil(L);
|
|
return 1;
|
|
}
|
|
|
|
int __fastcall Script_C_InteractUnit(void *L) {
|
|
if (!Game::Lua::IsString(L, 1)) {
|
|
Game::Lua::Error(L, "Usage: C_PlayerInteractionManager.InteractUnit(unit[, exactMatch[, "
|
|
"looseTargeting]])");
|
|
return 0;
|
|
}
|
|
Game::Lua::PushBool(L, Interact(L));
|
|
return 1;
|
|
}
|
|
|
|
const Game::Doc::Field kArgs[] = {
|
|
Game::Doc::Req("unit", "UnitToken",
|
|
"A unit token, \"mouseover\" for whatever the cursor is over, or a name."),
|
|
Game::Doc::Opt("exactMatch", "bool", "false",
|
|
"When a name is given, require the whole name instead of a prefix."),
|
|
};
|
|
const Game::Doc::Field kRets[] = {
|
|
Game::Doc::Opt("interacted", "number", nullptr,
|
|
"1 when the right-click ran, nil when nothing matched."),
|
|
};
|
|
const Game::Doc::Function kInteractUnit{
|
|
"Targets the unit or object and interacts with it, as a right-click in the world does.",
|
|
kArgs, kRets, "UnitGlobals"};
|
|
|
|
const Game::Doc::Field kManagerArgs[] = {
|
|
Game::Doc::Req("unit", "UnitToken",
|
|
"A unit token, \"mouseover\" for whatever the cursor is over, or a name. "
|
|
"\"anyinteract\" is what the Interact Key uses."),
|
|
Game::Doc::Opt("exactMatch", "bool", "false",
|
|
"When a name is given, require the whole name instead of a prefix."),
|
|
Game::Doc::Opt("looseTargeting", "bool", "true", "Has no effect."),
|
|
};
|
|
const Game::Doc::Field kManagerRets[] = {
|
|
Game::Doc::Req("success", "bool", "True when the interaction ran."),
|
|
};
|
|
const Game::Doc::Function kManagerInteractUnit{
|
|
"Targets the unit or object and interacts with it, as a right-click in the world does.",
|
|
kManagerArgs, kManagerRets, "PlayerInteractionManager"};
|
|
|
|
void RegisterLuaFunctions() {
|
|
Game::Lua::RegisterGlobalFunction("InteractUnit", &Script_InteractUnit, &kInteractUnit);
|
|
Game::Lua::RegisterTableFunction("C_PlayerInteractionManager", "InteractUnit",
|
|
&Script_C_InteractUnit, &kManagerInteractUnit);
|
|
}
|
|
|
|
const Game::ModuleAutoRegister _autoreg{&RegisterLuaFunctions};
|
|
|
|
} // namespace
|
|
|
|
} // namespace Unit::Interact
|