-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRaceBase.cpp
More file actions
98 lines (86 loc) · 3.32 KB
/
RaceBase.cpp
File metadata and controls
98 lines (86 loc) · 3.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// This file is part of ClassicAPI.
//
// ClassicAPI is free software: you can redistribute it and/or modify it under the terms
// of the GNU Lesser 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 Lesser General Public License for more details.
#include "Game.h"
#include "Offsets.h"
#include "dbc/Lookup.h"
#include <cstdint>
namespace Unit::RaceBase {
namespace {
using ResolveUnitToken_t = void *(__fastcall *)(const char *token);
// `UnitRaceBase(unit) → (raceFile, raceID)` — returns the locale-
// independent race token (`"Human"`, `"Orc"`, `"Dwarf"`, `"NightElf"`,
// `"Scourge"`, `"Tauren"`, `"Gnome"`, `"Troll"`) plus the numeric
// raceID (1..8 in vanilla), or `(nil, nil)` if the unit can't be
// resolved.
//
// Sibling to `UnitClassBase` — same descriptor-byte + DBC.Filename
// chain, just reading `UNIT_FIELD_BYTES_0` byte 0 (race) instead of
// byte 1 (class) and looking up `ChrRaces.dbc::Filename` at `+0x3C`
// (locale-independent string, distinct from the localized `Name[9]`
// at `+0x44` that `UnitRace` already returns).
//
// Race byte is broadcast in UpdateField data, so this works for any
// synced unit token (player, target, party / raid, mouseover,
// inspect targets — anything FUN_RESOLVE_UNIT_TOKEN handles).
//
// Returns `(nil, nil)` for unresolvable units (empty target /
// party slot, unloaded descriptor), unit-byte 0 (uninitialized /
// NPC), or out-of-range race bytes (no matching ChrRaces.dbc row).
int __fastcall Script_UnitRaceBase(void *L) {
if (!Game::Lua::IsString(L, 1)) {
Game::Lua::Error(L, "Usage: UnitRaceBase(\"unit\")");
return 0;
}
const char *token = Game::Lua::ToString(L, 1);
if (token == nullptr) {
Game::Lua::PushNil(L);
Game::Lua::PushNil(L);
return 2;
}
auto resolve = reinterpret_cast<ResolveUnitToken_t>(Offsets::FUN_RESOLVE_UNIT_TOKEN);
auto *unit = static_cast<const uint8_t *>(resolve(token));
if (unit == nullptr) {
Game::Lua::PushNil(L);
Game::Lua::PushNil(L);
return 2;
}
auto *desc = *reinterpret_cast<const uint8_t *const *>(
unit + Offsets::OFF_UNIT_DESCRIPTOR);
if (desc == nullptr) {
Game::Lua::PushNil(L);
Game::Lua::PushNil(L);
return 2;
}
const uint8_t raceByte = *(desc + Offsets::OFF_UNIT_DESCRIPTOR_RACE_BYTE);
if (raceByte == 0) {
Game::Lua::PushNil(L);
Game::Lua::PushNil(L);
return 2;
}
const char *raceFile = DBC::StringField(
Offsets::VAR_CHRRACES_RECORDS,
Offsets::VAR_CHRRACES_COUNT,
raceByte,
Offsets::OFF_CHRRACES_FILENAME);
if (raceFile == nullptr) {
Game::Lua::PushNil(L);
Game::Lua::PushNil(L);
return 2;
}
Game::Lua::PushString(L, raceFile);
Game::Lua::PushNumber(L, static_cast<double>(raceByte));
return 2;
}
void RegisterLuaFunctions() {
Game::Lua::RegisterGlobalFunction("UnitRaceBase", &Script_UnitRaceBase);
}
const Game::ModuleAutoRegister _autoreg{&RegisterLuaFunctions};
} // namespace
} // namespace Unit::RaceBase