feat(editor): add Trainer/Banker/Auctioneer/Repair NPC flags + SQL export

CreatureSpawn struct gains four AzerothCore-standard NPC flag bits:
  trainer    -> npcflag 0x10
  repair     -> npcflag 0x1000
  banker     -> npcflag 0x20000
  auctioneer -> npcflag 0x200000
Saved/loaded via the JSON spawn file, exported to creature_template.npcflag,
exposed as checkboxes in the NPC template panel. Lets users build full
city NPCs (city auctioneer, weapon trainer, etc.) without dropping to SQL.
This commit is contained in:
Kelsi 2026-05-06 04:03:23 -07:00
parent bc6e60c6e9
commit 99aaab3aa8
4 changed files with 23 additions and 1 deletions

View file

@ -1919,6 +1919,11 @@ void EditorUI::renderNpcPanel(EditorApp& app) {
ImGui::SameLine(); ImGui::Checkbox("Questgiver", &tmpl.questgiver);
ImGui::Checkbox("Vendor", &tmpl.vendor);
ImGui::SameLine(); ImGui::Checkbox("Innkeeper", &tmpl.innkeeper);
ImGui::Checkbox("Trainer", &tmpl.trainer);
ImGui::SameLine(); ImGui::Checkbox("Banker", &tmpl.banker);
ImGui::Checkbox("Auctioneer", &tmpl.auctioneer);
ImGui::SameLine(); ImGui::Checkbox("Repair", &tmpl.repair);
ImGui::SameLine(); ImGui::Checkbox("Flightmaster", &tmpl.flightmaster);
// Update nameBuf when preset selection changes it
if (tmpl.name.c_str() != std::string(nameBuf))

View file

@ -85,6 +85,10 @@ bool NpcSpawner::saveToFile(const std::string& path) const {
js["vendor"] = s.vendor;
js["flightmaster"] = s.flightmaster;
js["innkeeper"] = s.innkeeper;
js["trainer"] = s.trainer;
js["auctioneer"] = s.auctioneer;
js["banker"] = s.banker;
js["repair"] = s.repair;
nlohmann::json patrol = nlohmann::json::array();
for (const auto& p : s.patrolPath) {
@ -156,6 +160,10 @@ bool NpcSpawner::loadFromFile(const std::string& path) {
s.vendor = js.value("vendor", false);
s.flightmaster = js.value("flightmaster", false);
s.innkeeper = js.value("innkeeper", false);
s.trainer = js.value("trainer", false);
s.auctioneer = js.value("auctioneer", false);
s.banker = js.value("banker", false);
s.repair = js.value("repair", false);
if (js.contains("position") && js["position"].is_array() && js["position"].size() >= 3) {
s.position = glm::vec3(js["position"][0].get<float>(),

View file

@ -56,6 +56,10 @@ struct CreatureSpawn {
bool vendor = false;
bool flightmaster = false;
bool innkeeper = false;
bool trainer = false; // class/profession trainer (SQL npcflag 0x10)
bool auctioneer = false; // (SQL npcflag 0x200000)
bool banker = false; // (SQL npcflag 0x20000)
bool repair = false; // (SQL npcflag 0x1000)
bool selected = false;
};

View file

@ -50,11 +50,16 @@ bool SQLExporter::exportCreatures(const std::vector<CreatureSpawn>& spawns,
const auto& s = spawns[i];
uint32_t entry = startEntry + static_cast<uint32_t>(i);
// AzerothCore creature_template.npcflag bits.
uint32_t npcFlags = 0;
if (s.questgiver) npcFlags |= 0x02;
if (s.trainer) npcFlags |= 0x10;
if (s.vendor) npcFlags |= 0x80;
if (s.flightmaster) npcFlags |= 0x02000000;
if (s.repair) npcFlags |= 0x1000;
if (s.innkeeper) npcFlags |= 0x10000;
if (s.banker) npcFlags |= 0x20000;
if (s.auctioneer) npcFlags |= 0x200000;
if (s.flightmaster) npcFlags |= 0x02000000;
uint32_t unitFlags = 0;
if (!s.hostile) unitFlags |= 0x02; // NON_ATTACKABLE