mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-11-08 17:28:20 +00:00
feat: refactor vanity (#1477)
* feat: refactor vanity cleanup code to be generalized for objects remove unused party feature add fallback to data to text Allow for better organizing data in multiple files remove special case flag values in favor of config data general cleanup and fixes * newline at eof's
This commit is contained in:
parent
cf706d4974
commit
192c8cf974
@ -179,7 +179,7 @@ file(ARCHIVE_EXTRACT INPUT ${PROJECT_BINARY_DIR}/navmeshes.zip DESTINATION ${PRO
|
||||
file(REMOVE ${PROJECT_BINARY_DIR}/navmeshes.zip)
|
||||
|
||||
# Copy vanity files on first build
|
||||
set(VANITY_FILES "CREDITS.md" "INFO.md" "TESTAMENT.md" "NPC.xml")
|
||||
set(VANITY_FILES "CREDITS.md" "INFO.md" "TESTAMENT.md" "root.xml" "dev-tribute.xml" "atm.xml")
|
||||
|
||||
foreach(file ${VANITY_FILES})
|
||||
configure_file("${CMAKE_SOURCE_DIR}/vanity/${file}" "${CMAKE_BINARY_DIR}/vanity/${file}" COPYONLY)
|
||||
|
@ -2197,3 +2197,9 @@ void Entity::SetRespawnRot(const NiQuaternion& rotation) {
|
||||
auto* characterComponent = GetComponent<CharacterComponent>();
|
||||
if (characterComponent) characterComponent->SetRespawnRot(rotation);
|
||||
}
|
||||
|
||||
void Entity::SetScale(const float scale) {
|
||||
if (scale == m_Scale) return;
|
||||
m_Scale = scale;
|
||||
Game::entityManager->SerializeEntity(this);
|
||||
}
|
@ -295,6 +295,8 @@ public:
|
||||
|
||||
void ProcessPositionUpdate(PositionUpdate& update);
|
||||
|
||||
void SetScale(const float scale);
|
||||
|
||||
protected:
|
||||
LWOOBJID m_ObjectID;
|
||||
|
||||
|
@ -22,143 +22,13 @@
|
||||
|
||||
#include <fstream>
|
||||
|
||||
std::vector<VanityNPC> VanityUtilities::m_NPCs = {};
|
||||
std::vector<VanityParty> VanityUtilities::m_Parties = {};
|
||||
std::vector<std::string> VanityUtilities::m_PartyPhrases = {};
|
||||
std::vector<VanityObject> VanityUtilities::m_Objects = {};
|
||||
std::set<std::string> VanityUtilities::m_LoadedFiles = {};
|
||||
|
||||
|
||||
void VanityUtilities::SpawnVanity() {
|
||||
if (Game::config->GetValue("disable_vanity") == "1") {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32_t zoneID = Game::server->GetZoneID();
|
||||
|
||||
for (const auto& npc : m_NPCs) {
|
||||
if (npc.m_ID == LWOOBJID_EMPTY) continue;
|
||||
if (npc.m_LOT == 176){
|
||||
Game::zoneManager->RemoveSpawner(npc.m_ID);
|
||||
} else{
|
||||
auto* entity = Game::entityManager->GetEntity(npc.m_ID);
|
||||
if (!entity) continue;
|
||||
entity->Smash(LWOOBJID_EMPTY, eKillType::VIOLENT);
|
||||
}
|
||||
}
|
||||
|
||||
m_NPCs.clear();
|
||||
m_Parties.clear();
|
||||
m_PartyPhrases.clear();
|
||||
|
||||
ParseXML((BinaryPathFinder::GetBinaryDir() / "vanity/NPC.xml").string());
|
||||
|
||||
// Loop through all parties
|
||||
for (const auto& party : m_Parties) {
|
||||
const auto chance = party.m_Chance;
|
||||
const auto zone = party.m_Zone;
|
||||
|
||||
if (zone != Game::server->GetZoneID()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float rate = GeneralUtils::GenerateRandomNumber<float>(0, 1);
|
||||
if (chance < rate) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Copy m_NPCs into a new vector
|
||||
std::vector<VanityNPC> npcList = m_NPCs;
|
||||
std::vector<uint32_t> taken = {};
|
||||
|
||||
LOG("Spawning party with %i locations", party.m_Locations.size());
|
||||
|
||||
// Loop through all locations
|
||||
for (const auto& location : party.m_Locations) {
|
||||
rate = GeneralUtils::GenerateRandomNumber<float>(0, 1);
|
||||
if (0.75f < rate) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get a random NPC
|
||||
auto npcIndex = GeneralUtils::GenerateRandomNumber<uint32_t>(0, npcList.size() - 1);
|
||||
|
||||
while (std::find(taken.begin(), taken.end(), npcIndex) != taken.end()) {
|
||||
npcIndex = GeneralUtils::GenerateRandomNumber<uint32_t>(0, npcList.size() - 1);
|
||||
}
|
||||
|
||||
auto& npc = npcList[npcIndex];
|
||||
// Skip spawners
|
||||
if (npc.m_LOT == 176) continue;
|
||||
|
||||
taken.push_back(npcIndex);
|
||||
|
||||
LOG("ldf size is %i", npc.ldf.size());
|
||||
if (npc.ldf.empty()) {
|
||||
npc.ldf = {
|
||||
new LDFData<std::vector<std::u16string>>(u"syncLDF", { u"custom_script_client" }),
|
||||
new LDFData<std::u16string>(u"custom_script_client", u"scripts\\ai\\SPEC\\MISSION_MINIGAME_CLIENT.lua")
|
||||
};
|
||||
}
|
||||
|
||||
// Spawn the NPC
|
||||
if (npc.m_LOT == 176){
|
||||
npc.m_ID = SpawnSpawner(npc.m_LOT, location.m_Position, location.m_Rotation, npc.ldf);
|
||||
} else {
|
||||
auto* npcEntity = SpawnNPC(npc.m_LOT, npc.m_Name, location.m_Position, location.m_Rotation, npc.m_Equipment, npc.ldf);
|
||||
if (!npc.m_Phrases.empty()) {
|
||||
npcEntity->SetVar<std::vector<std::string>>(u"chats", m_PartyPhrases);
|
||||
SetupNPCTalk(npcEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop through all NPCs
|
||||
for (auto& npc : m_NPCs) {
|
||||
if (npc.m_Locations.find(Game::server->GetZoneID()) == npc.m_Locations.end())
|
||||
continue;
|
||||
|
||||
const std::vector<VanityNPCLocation>& locations = npc.m_Locations.at(Game::server->GetZoneID());
|
||||
|
||||
// Pick a random location
|
||||
const auto& location = locations[GeneralUtils::GenerateRandomNumber<int>(
|
||||
static_cast<size_t>(0), static_cast<size_t>(locations.size() - 1))];
|
||||
|
||||
float rate = GeneralUtils::GenerateRandomNumber<float>(0, 1);
|
||||
if (location.m_Chance < rate) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (npc.ldf.empty()) {
|
||||
npc.ldf = {
|
||||
new LDFData<std::vector<std::u16string>>(u"syncLDF", { u"custom_script_client" }),
|
||||
new LDFData<std::u16string>(u"custom_script_client", u"scripts\\ai\\SPEC\\MISSION_MINIGAME_CLIENT.lua")
|
||||
};
|
||||
}
|
||||
if (npc.m_LOT == 176){
|
||||
npc.m_ID = SpawnSpawner(npc.m_LOT, location.m_Position, location.m_Rotation, npc.ldf);
|
||||
} else {
|
||||
// Spawn the NPC
|
||||
auto* npcEntity = SpawnNPC(npc.m_LOT, npc.m_Name, location.m_Position, location.m_Rotation, npc.m_Equipment, npc.ldf);
|
||||
if (!npcEntity) continue;
|
||||
npc.m_ID = npcEntity->GetObjectID();
|
||||
if (!npc.m_Phrases.empty()){
|
||||
npcEntity->SetVar<std::vector<std::string>>(u"chats", npc.m_Phrases);
|
||||
|
||||
auto* scriptComponent = npcEntity->GetComponent<ScriptComponent>();
|
||||
|
||||
if (scriptComponent && !npc.m_Script.empty()) {
|
||||
scriptComponent->SetScript(npc.m_Script);
|
||||
scriptComponent->SetSerialized(false);
|
||||
|
||||
for (const auto& npc : npc.m_Flags) {
|
||||
npcEntity->SetVar<bool>(GeneralUtils::ASCIIToUTF16(npc.first), npc.second);
|
||||
}
|
||||
}
|
||||
SetupNPCTalk(npcEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (zoneID == 1200) {
|
||||
{
|
||||
EntityInfo info;
|
||||
@ -175,38 +45,99 @@ void VanityUtilities::SpawnVanity() {
|
||||
Game::entityManager->ConstructEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
if (Game::config->GetValue("disable_vanity") == "1") {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& npc : m_Objects) {
|
||||
if (npc.m_ID == LWOOBJID_EMPTY) continue;
|
||||
if (npc.m_LOT == 176){
|
||||
Game::zoneManager->RemoveSpawner(npc.m_ID);
|
||||
} else{
|
||||
auto* entity = Game::entityManager->GetEntity(npc.m_ID);
|
||||
if (!entity) continue;
|
||||
entity->Smash(LWOOBJID_EMPTY, eKillType::VIOLENT);
|
||||
}
|
||||
}
|
||||
|
||||
m_Objects.clear();
|
||||
m_LoadedFiles.clear();
|
||||
|
||||
ParseXML((BinaryPathFinder::GetBinaryDir() / "vanity/root.xml").string());
|
||||
|
||||
// Loop through all objects
|
||||
for (auto& object : m_Objects) {
|
||||
if (object.m_Locations.find(Game::server->GetZoneID()) == object.m_Locations.end()) continue;
|
||||
|
||||
const std::vector<VanityObjectLocation>& locations = object.m_Locations.at(Game::server->GetZoneID());
|
||||
|
||||
// Pick a random location
|
||||
const auto& location = locations[GeneralUtils::GenerateRandomNumber<int>(
|
||||
static_cast<size_t>(0), static_cast<size_t>(locations.size() - 1))];
|
||||
|
||||
float rate = GeneralUtils::GenerateRandomNumber<float>(0, 1);
|
||||
if (location.m_Chance < rate) continue;
|
||||
|
||||
if (object.m_Config.empty()) {
|
||||
object.m_Config = {
|
||||
new LDFData<std::vector<std::u16string>>(u"syncLDF", { u"custom_script_client" }),
|
||||
new LDFData<std::u16string>(u"custom_script_client", u"scripts\\ai\\SPEC\\MISSION_MINIGAME_CLIENT.lua")
|
||||
};
|
||||
}
|
||||
if (object.m_LOT == 176){
|
||||
object.m_ID = SpawnSpawner(object, location);
|
||||
} else {
|
||||
// Spawn the NPC
|
||||
auto* objectEntity = SpawnObject(object, location);
|
||||
if (!objectEntity) continue;
|
||||
object.m_ID = objectEntity->GetObjectID();
|
||||
if (!object.m_Phrases.empty()){
|
||||
objectEntity->SetVar<std::vector<std::string>>(u"chats", object.m_Phrases);
|
||||
|
||||
auto* scriptComponent = objectEntity->GetComponent<ScriptComponent>();
|
||||
|
||||
if (scriptComponent && !object.m_Script.empty()) {
|
||||
scriptComponent->SetScript(object.m_Script);
|
||||
scriptComponent->SetSerialized(false);
|
||||
}
|
||||
SetupNPCTalk(objectEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LWOOBJID VanityUtilities::SpawnSpawner(LOT lot, const NiPoint3& position, const NiQuaternion& rotation, const std::vector<LDFBaseData*>& ldf){
|
||||
LWOOBJID VanityUtilities::SpawnSpawner(const VanityObject& object, const VanityObjectLocation& location) {
|
||||
SceneObject obj;
|
||||
obj.lot = lot;
|
||||
obj.lot = object.m_LOT;
|
||||
// guratantee we have no collisions
|
||||
do {
|
||||
obj.id = ObjectIDManager::GenerateObjectID();
|
||||
} while(Game::zoneManager->GetSpawner(obj.id));
|
||||
obj.position = position;
|
||||
obj.rotation = rotation;
|
||||
obj.settings = ldf;
|
||||
obj.position = location.m_Position;
|
||||
obj.rotation = location.m_Rotation;
|
||||
obj.settings = object.m_Config;
|
||||
Level::MakeSpawner(obj);
|
||||
return obj.id;
|
||||
}
|
||||
|
||||
Entity* VanityUtilities::SpawnNPC(LOT lot, const std::string& name, const NiPoint3& position, const NiQuaternion& rotation, const std::vector<LOT>& inventory, const std::vector<LDFBaseData*>& ldf) {
|
||||
Entity* VanityUtilities::SpawnObject(const VanityObject& object, const VanityObjectLocation& location) {
|
||||
EntityInfo info;
|
||||
info.lot = lot;
|
||||
info.pos = position;
|
||||
info.rot = rotation;
|
||||
info.lot = object.m_LOT;
|
||||
info.pos = location.m_Position;
|
||||
info.rot = location.m_Rotation;
|
||||
info.scale = location.m_Scale;
|
||||
info.spawnerID = Game::entityManager->GetZoneControlEntity()->GetObjectID();
|
||||
info.settings = ldf;
|
||||
info.settings = object.m_Config;
|
||||
|
||||
auto* entity = Game::entityManager->CreateEntity(info);
|
||||
entity->SetVar(u"npcName", name);
|
||||
entity->SetVar(u"npcName", object.m_Name);
|
||||
if (entity->GetVar<bool>(u"noGhosting")) entity->SetIsGhostingCandidate(false);
|
||||
|
||||
auto* inventoryComponent = entity->GetComponent<InventoryComponent>();
|
||||
|
||||
if (inventoryComponent && !inventory.empty()) {
|
||||
inventoryComponent->SetNPCItems(inventory);
|
||||
if (inventoryComponent && !object.m_Equipment.empty()) {
|
||||
inventoryComponent->SetNPCItems(object.m_Equipment);
|
||||
}
|
||||
|
||||
auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
|
||||
@ -223,6 +154,11 @@ Entity* VanityUtilities::SpawnNPC(LOT lot, const std::string& name, const NiPoin
|
||||
}
|
||||
|
||||
void VanityUtilities::ParseXML(const std::string& file) {
|
||||
if (m_LoadedFiles.contains(file)){
|
||||
LOG("Trying to load vanity file %s twice!!!", file.c_str());
|
||||
return;
|
||||
}
|
||||
m_LoadedFiles.insert(file);
|
||||
// Read the entire file
|
||||
std::ifstream xmlFile(file);
|
||||
std::string xml((std::istreambuf_iterator<char>(xmlFile)), std::istreambuf_iterator<char>());
|
||||
@ -231,210 +167,112 @@ void VanityUtilities::ParseXML(const std::string& file) {
|
||||
tinyxml2::XMLDocument doc;
|
||||
doc.Parse(xml.c_str(), xml.size());
|
||||
|
||||
// Read the NPCs
|
||||
auto* npcs = doc.FirstChildElement("npcs");
|
||||
|
||||
if (npcs == nullptr) {
|
||||
LOG("Failed to parse NPCs");
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto* party = npcs->FirstChildElement("party"); party != nullptr; party = party->NextSiblingElement("party")) {
|
||||
// Get 'zone' as uint32_t and 'chance' as float
|
||||
uint32_t zone = 0;
|
||||
float chance = 0.0f;
|
||||
|
||||
if (party->Attribute("zone") != nullptr) {
|
||||
zone = std::stoul(party->Attribute("zone"));
|
||||
}
|
||||
|
||||
if (party->Attribute("chance") != nullptr) {
|
||||
chance = std::stof(party->Attribute("chance"));
|
||||
}
|
||||
|
||||
VanityParty partyInfo;
|
||||
partyInfo.m_Zone = zone;
|
||||
partyInfo.m_Chance = chance;
|
||||
|
||||
auto* locations = party->FirstChildElement("locations");
|
||||
|
||||
if (locations == nullptr) {
|
||||
LOG("Failed to parse party locations");
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto* location = locations->FirstChildElement("location"); location != nullptr;
|
||||
location = location->NextSiblingElement("location")) {
|
||||
// Get the location data
|
||||
auto* x = location->Attribute("x");
|
||||
auto* y = location->Attribute("y");
|
||||
auto* z = location->Attribute("z");
|
||||
auto* rw = location->Attribute("rw");
|
||||
auto* rx = location->Attribute("rx");
|
||||
auto* ry = location->Attribute("ry");
|
||||
auto* rz = location->Attribute("rz");
|
||||
|
||||
if (x == nullptr || y == nullptr || z == nullptr || rw == nullptr || rx == nullptr || ry == nullptr
|
||||
|| rz == nullptr) {
|
||||
LOG("Failed to parse party location data");
|
||||
// Read the objects
|
||||
auto* files = doc.FirstChildElement("files");
|
||||
if (files) {
|
||||
for (auto* file = files->FirstChildElement("file"); file != nullptr; file = file->NextSiblingElement("file")) {
|
||||
std::string enabled = file->Attribute("enabled");
|
||||
std::string filename = file->Attribute("name");
|
||||
if (enabled != "1") {
|
||||
continue;
|
||||
}
|
||||
|
||||
VanityNPCLocation locationData;
|
||||
locationData.m_Position = { std::stof(x), std::stof(y), std::stof(z) };
|
||||
locationData.m_Rotation = { std::stof(rw), std::stof(rx), std::stof(ry), std::stof(rz) };
|
||||
locationData.m_Chance = 1.0f;
|
||||
|
||||
partyInfo.m_Locations.push_back(locationData);
|
||||
}
|
||||
|
||||
m_Parties.push_back(partyInfo);
|
||||
}
|
||||
|
||||
auto* partyPhrases = npcs->FirstChildElement("partyphrases");
|
||||
|
||||
if (partyPhrases == nullptr) {
|
||||
LOG("No party phrases found");
|
||||
} else {
|
||||
for (auto* phrase = partyPhrases->FirstChildElement("phrase"); phrase != nullptr;
|
||||
phrase = phrase->NextSiblingElement("phrase")) {
|
||||
// Get the phrase
|
||||
auto* text = phrase->GetText();
|
||||
|
||||
if (text == nullptr) {
|
||||
LOG("Failed to parse party phrase");
|
||||
continue;
|
||||
}
|
||||
|
||||
m_PartyPhrases.push_back(text);
|
||||
ParseXML((BinaryPathFinder::GetBinaryDir() / "vanity" / filename).string());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto* npc = npcs->FirstChildElement("npc"); npc != nullptr; npc = npc->NextSiblingElement("npc")) {
|
||||
// Get the NPC name
|
||||
auto* name = npc->Attribute("name");
|
||||
// Read the objects
|
||||
auto* objects = doc.FirstChildElement("objects");
|
||||
|
||||
if (!name) name = "";
|
||||
if (objects) {
|
||||
for (auto* object = objects->FirstChildElement("object"); object != nullptr; object = object->NextSiblingElement("object")) {
|
||||
// Get the NPC name
|
||||
auto* name = object->Attribute("name");
|
||||
|
||||
// Get the NPC lot
|
||||
auto* lot = npc->Attribute("lot");
|
||||
if (!name) name = "";
|
||||
|
||||
if (lot == nullptr) {
|
||||
LOG("Failed to parse NPC lot");
|
||||
continue;
|
||||
}
|
||||
// Get the NPC lot
|
||||
auto* lot = object->Attribute("lot");
|
||||
|
||||
// Get the equipment
|
||||
auto* equipment = npc->FirstChildElement("equipment");
|
||||
std::vector<LOT> inventory;
|
||||
|
||||
if (equipment) {
|
||||
auto* text = equipment->GetText();
|
||||
|
||||
if (text != nullptr) {
|
||||
std::string equipmentString(text);
|
||||
|
||||
std::vector<std::string> splitEquipment = GeneralUtils::SplitString(equipmentString, ',');
|
||||
|
||||
for (auto& item : splitEquipment) {
|
||||
inventory.push_back(std::stoi(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get the phrases
|
||||
auto* phrases = npc->FirstChildElement("phrases");
|
||||
|
||||
std::vector<std::string> phraseList = {};
|
||||
|
||||
if (phrases) {
|
||||
for (auto* phrase = phrases->FirstChildElement("phrase"); phrase != nullptr;
|
||||
phrase = phrase->NextSiblingElement("phrase")) {
|
||||
// Get the phrase
|
||||
auto* text = phrase->GetText();
|
||||
if (text == nullptr) {
|
||||
LOG("Failed to parse NPC phrase");
|
||||
continue;
|
||||
}
|
||||
phraseList.push_back(text);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the script
|
||||
auto* scriptElement = npc->FirstChildElement("script");
|
||||
|
||||
std::string scriptName = "";
|
||||
|
||||
if (scriptElement != nullptr) {
|
||||
auto* scriptNameAttribute = scriptElement->Attribute("name");
|
||||
if (scriptNameAttribute) scriptName = scriptNameAttribute;
|
||||
}
|
||||
|
||||
auto* ldfElement = npc->FirstChildElement("ldf");
|
||||
std::vector<std::u16string> keys = {};
|
||||
|
||||
std::vector<LDFBaseData*> ldf = {};
|
||||
if(ldfElement) {
|
||||
for (auto* entry = ldfElement->FirstChildElement("entry"); entry != nullptr;
|
||||
entry = entry->NextSiblingElement("entry")) {
|
||||
// Get the ldf data
|
||||
auto* data = entry->Attribute("data");
|
||||
if (!data) continue;
|
||||
|
||||
LDFBaseData* ldfData = LDFBaseData::DataFromString(data);
|
||||
keys.push_back(ldfData->GetKey());
|
||||
ldf.push_back(ldfData);
|
||||
}
|
||||
}
|
||||
if (!keys.empty()) ldf.push_back(new LDFData<std::vector<std::u16string>>(u"syncLDF", keys));
|
||||
|
||||
VanityNPC npcData;
|
||||
npcData.m_Name = name;
|
||||
npcData.m_LOT = std::stoi(lot);
|
||||
npcData.m_Equipment = inventory;
|
||||
npcData.m_Phrases = phraseList;
|
||||
npcData.m_Script = scriptName;
|
||||
npcData.ldf = ldf;
|
||||
|
||||
// Get flags
|
||||
auto* flags = npc->FirstChildElement("flags");
|
||||
|
||||
if (flags != nullptr) {
|
||||
for (auto* flag = flags->FirstChildElement("flag"); flag != nullptr;
|
||||
flag = flag->NextSiblingElement("flag")) {
|
||||
// Get the flag name
|
||||
auto* name = flag->Attribute("name");
|
||||
|
||||
if (name == nullptr) {
|
||||
LOG("Failed to parse NPC flag name");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the flag value
|
||||
auto* value = flag->Attribute("value");
|
||||
|
||||
if (value == nullptr) {
|
||||
LOG("Failed to parse NPC flag value");
|
||||
continue;
|
||||
}
|
||||
|
||||
npcData.m_Flags[name] = std::stoi(value);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the zones
|
||||
for (auto* zone = npc->FirstChildElement("zone"); zone != nullptr; zone = zone->NextSiblingElement("zone")) {
|
||||
// Get the zone ID
|
||||
auto* zoneID = zone->Attribute("id");
|
||||
|
||||
if (zoneID == nullptr) {
|
||||
LOG("Failed to parse NPC zone ID");
|
||||
if (lot == nullptr) {
|
||||
LOG("Failed to parse object lot");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the equipment
|
||||
auto* equipment = object->FirstChildElement("equipment");
|
||||
std::vector<LOT> inventory;
|
||||
|
||||
if (equipment) {
|
||||
auto* text = equipment->GetText();
|
||||
|
||||
if (text != nullptr) {
|
||||
std::string equipmentString(text);
|
||||
|
||||
std::vector<std::string> splitEquipment = GeneralUtils::SplitString(equipmentString, ',');
|
||||
|
||||
for (auto& item : splitEquipment) {
|
||||
inventory.push_back(std::stoi(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get the phrases
|
||||
auto* phrases = object->FirstChildElement("phrases");
|
||||
|
||||
std::vector<std::string> phraseList = {};
|
||||
|
||||
if (phrases) {
|
||||
for (auto* phrase = phrases->FirstChildElement("phrase"); phrase != nullptr;
|
||||
phrase = phrase->NextSiblingElement("phrase")) {
|
||||
// Get the phrase
|
||||
auto* text = phrase->GetText();
|
||||
if (text == nullptr) {
|
||||
LOG("Failed to parse NPC phrase");
|
||||
continue;
|
||||
}
|
||||
phraseList.push_back(text);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the script
|
||||
auto* scriptElement = object->FirstChildElement("script");
|
||||
|
||||
std::string scriptName = "";
|
||||
|
||||
if (scriptElement != nullptr) {
|
||||
auto* scriptNameAttribute = scriptElement->Attribute("name");
|
||||
if (scriptNameAttribute) scriptName = scriptNameAttribute;
|
||||
}
|
||||
|
||||
auto* configElement = object->FirstChildElement("config");
|
||||
std::vector<std::u16string> keys = {};
|
||||
|
||||
std::vector<LDFBaseData*> config = {};
|
||||
if(configElement) {
|
||||
for (auto* key = configElement->FirstChildElement("key"); key != nullptr;
|
||||
key = key->NextSiblingElement("key")) {
|
||||
// Get the config data
|
||||
auto* data = key->Attribute("data");
|
||||
if (!data) continue;
|
||||
|
||||
LDFBaseData* configData = LDFBaseData::DataFromString(data);
|
||||
keys.push_back(configData->GetKey());
|
||||
config.push_back(configData);
|
||||
}
|
||||
}
|
||||
if (!keys.empty()) config.push_back(new LDFData<std::vector<std::u16string>>(u"syncLDF", keys));
|
||||
|
||||
VanityObject objectData;
|
||||
objectData.m_Name = name;
|
||||
objectData.m_LOT = std::stoi(lot);
|
||||
objectData.m_Equipment = inventory;
|
||||
objectData.m_Phrases = phraseList;
|
||||
objectData.m_Script = scriptName;
|
||||
objectData.m_Config = config;
|
||||
|
||||
// Get the locations
|
||||
auto* locations = zone->FirstChildElement("locations");
|
||||
auto* locations = object->FirstChildElement("locations");
|
||||
|
||||
if (locations == nullptr) {
|
||||
LOG("Failed to parse NPC locations");
|
||||
@ -443,7 +281,9 @@ void VanityUtilities::ParseXML(const std::string& file) {
|
||||
|
||||
for (auto* location = locations->FirstChildElement("location"); location != nullptr;
|
||||
location = location->NextSiblingElement("location")) {
|
||||
|
||||
// Get the location data
|
||||
auto* zoneID = location->Attribute("zone");
|
||||
auto* x = location->Attribute("x");
|
||||
auto* y = location->Attribute("y");
|
||||
auto* z = location->Attribute("z");
|
||||
@ -452,41 +292,52 @@ void VanityUtilities::ParseXML(const std::string& file) {
|
||||
auto* ry = location->Attribute("ry");
|
||||
auto* rz = location->Attribute("rz");
|
||||
|
||||
if (x == nullptr || y == nullptr || z == nullptr || rw == nullptr || rx == nullptr || ry == nullptr
|
||||
if (zoneID == nullptr || x == nullptr || y == nullptr || z == nullptr || rw == nullptr || rx == nullptr || ry == nullptr
|
||||
|| rz == nullptr) {
|
||||
LOG("Failed to parse NPC location data");
|
||||
continue;
|
||||
}
|
||||
|
||||
VanityNPCLocation locationData;
|
||||
VanityObjectLocation locationData;
|
||||
locationData.m_Position = { std::stof(x), std::stof(y), std::stof(z) };
|
||||
locationData.m_Rotation = { std::stof(rw), std::stof(rx), std::stof(ry), std::stof(rz) };
|
||||
locationData.m_Chance = 1.0f;
|
||||
|
||||
if (location->Attribute("chance") != nullptr) {
|
||||
if (location->Attribute("chance")) {
|
||||
locationData.m_Chance = std::stof(location->Attribute("chance"));
|
||||
}
|
||||
|
||||
const auto& it = npcData.m_Locations.find(std::stoi(zoneID));
|
||||
if (location->Attribute("scale")) {
|
||||
locationData.m_Scale = std::stof(location->Attribute("scale"));
|
||||
}
|
||||
|
||||
if (it != npcData.m_Locations.end()) {
|
||||
|
||||
const auto& it = objectData.m_Locations.find(std::stoi(zoneID));
|
||||
|
||||
if (it != objectData.m_Locations.end()) {
|
||||
it->second.push_back(locationData);
|
||||
} else {
|
||||
std::vector<VanityNPCLocation> locations;
|
||||
std::vector<VanityObjectLocation> locations;
|
||||
locations.push_back(locationData);
|
||||
npcData.m_Locations.insert(std::make_pair(std::stoi(zoneID), locations));
|
||||
objectData.m_Locations.insert(std::make_pair(std::stoi(zoneID), locations));
|
||||
}
|
||||
|
||||
if (!(std::find(keys.begin(), keys.end(), u"teleport") != keys.end())) {
|
||||
m_Objects.push_back(objectData);
|
||||
objectData.m_Locations.clear();
|
||||
}
|
||||
}
|
||||
if (std::find(keys.begin(), keys.end(), u"teleport") != keys.end()) {
|
||||
m_Objects.push_back(objectData);
|
||||
}
|
||||
}
|
||||
|
||||
m_NPCs.push_back(npcData);
|
||||
}
|
||||
}
|
||||
|
||||
VanityNPC* VanityUtilities::GetNPC(const std::string& name) {
|
||||
for (size_t i = 0; i < m_NPCs.size(); i++) {
|
||||
if (m_NPCs[i].m_Name == name) {
|
||||
return &m_NPCs[i];
|
||||
VanityObject* VanityUtilities::GetObject(const std::string& name) {
|
||||
for (size_t i = 0; i < m_Objects.size(); i++) {
|
||||
if (m_Objects[i].m_Name == name) {
|
||||
return &m_Objects[i];
|
||||
}
|
||||
}
|
||||
|
||||
@ -498,10 +349,13 @@ std::string VanityUtilities::ParseMarkdown(const std::string& file) {
|
||||
|
||||
// Read the file into a string
|
||||
std::ifstream t(file);
|
||||
|
||||
std::stringstream output;
|
||||
// If the file does not exist, return an empty string.
|
||||
if (!t.good()) {
|
||||
return "";
|
||||
output << "File ";
|
||||
output << file.substr(file.rfind("/") + 1);
|
||||
output << " not found!\nContact your DarkflameServer admin\nor find the server source at https://github.com/DarkflameUniverse/DarkflameServer";
|
||||
return output.str();
|
||||
}
|
||||
|
||||
std::stringstream buffer;
|
||||
@ -511,7 +365,6 @@ std::string VanityUtilities::ParseMarkdown(const std::string& file) {
|
||||
// Loop through all lines in the file.
|
||||
// Replace all instances of the markdown syntax with the corresponding HTML.
|
||||
// Only care about headers
|
||||
std::stringstream output;
|
||||
std::string line;
|
||||
std::stringstream ss;
|
||||
ss << fileContents;
|
||||
|
@ -3,15 +3,17 @@
|
||||
#include "dCommonVars.h"
|
||||
#include "Entity.h"
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
struct VanityNPCLocation
|
||||
struct VanityObjectLocation
|
||||
{
|
||||
float m_Chance = 1.0f;
|
||||
NiPoint3 m_Position;
|
||||
NiQuaternion m_Rotation;
|
||||
float m_Scale = 1.0f;
|
||||
};
|
||||
|
||||
struct VanityNPC
|
||||
struct VanityObject
|
||||
{
|
||||
LWOOBJID m_ID = LWOOBJID_EMPTY;
|
||||
std::string m_Name;
|
||||
@ -19,37 +21,24 @@ struct VanityNPC
|
||||
std::vector<LOT> m_Equipment;
|
||||
std::vector<std::string> m_Phrases;
|
||||
std::string m_Script;
|
||||
std::map<std::string, bool> m_Flags;
|
||||
std::map<uint32_t, std::vector<VanityNPCLocation>> m_Locations;
|
||||
std::vector<LDFBaseData*> ldf;
|
||||
std::map<uint32_t, std::vector<VanityObjectLocation>> m_Locations;
|
||||
std::vector<LDFBaseData*> m_Config;
|
||||
};
|
||||
|
||||
struct VanityParty
|
||||
{
|
||||
uint32_t m_Zone;
|
||||
float m_Chance = 1.0f;
|
||||
std::vector<VanityNPCLocation> m_Locations;
|
||||
};
|
||||
|
||||
class VanityUtilities
|
||||
{
|
||||
public:
|
||||
static void SpawnVanity();
|
||||
|
||||
static Entity* SpawnNPC(
|
||||
LOT lot,
|
||||
const std::string& name,
|
||||
const NiPoint3& position,
|
||||
const NiQuaternion& rotation,
|
||||
const std::vector<LOT>& inventory,
|
||||
const std::vector<LDFBaseData*>& ldf
|
||||
static Entity* SpawnObject(
|
||||
const VanityObject& object,
|
||||
const VanityObjectLocation& location
|
||||
);
|
||||
|
||||
static LWOOBJID SpawnSpawner(
|
||||
LOT lot,
|
||||
const NiPoint3& position,
|
||||
const NiQuaternion& rotation,
|
||||
const std::vector<LDFBaseData*>& ldf
|
||||
const VanityObject& object,
|
||||
const VanityObjectLocation& location
|
||||
);
|
||||
|
||||
static std::string ParseMarkdown(
|
||||
@ -60,16 +49,14 @@ public:
|
||||
const std::string& file
|
||||
);
|
||||
|
||||
static VanityNPC* GetNPC(const std::string& name);
|
||||
static VanityObject* GetObject(const std::string& name);
|
||||
|
||||
private:
|
||||
static void SetupNPCTalk(Entity* npc);
|
||||
|
||||
static void NPCTalk(Entity* npc);
|
||||
|
||||
static std::vector<VanityNPC> m_NPCs;
|
||||
|
||||
static std::vector<VanityParty> m_Parties;
|
||||
|
||||
static std::vector<std::string> m_PartyPhrases;
|
||||
static std::vector<VanityObject> m_Objects;
|
||||
|
||||
static std::set<std::string> m_LoadedFiles;
|
||||
};
|
||||
|
@ -1,3 +1,3 @@
|
||||
set(DSCRIPTS_SOURCES_02_SERVER_DLU
|
||||
"DLUVanityNPC.cpp"
|
||||
"DLUVanityTeleportingObject.cpp"
|
||||
PARENT_SCOPE)
|
||||
|
@ -1,22 +1,22 @@
|
||||
#include "DLUVanityNPC.h"
|
||||
#include "DLUVanityTeleportingObject.h"
|
||||
#include "GameMessages.h"
|
||||
#include "dServer.h"
|
||||
#include "VanityUtilities.h"
|
||||
#include "RenderComponent.h"
|
||||
|
||||
void DLUVanityNPC::OnStartup(Entity* self) {
|
||||
m_NPC = VanityUtilities::GetNPC("averysumner - Destroyer of Worlds");
|
||||
void DLUVanityTeleportingObject::OnStartup(Entity* self) {
|
||||
if (!self->HasVar(u"npcName") || !self->HasVar(u"teleport")) return;
|
||||
m_Object = VanityUtilities::GetObject(self->GetVarAsString(u"npcName"));
|
||||
|
||||
if (m_NPC == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (!m_Object) return;
|
||||
if (self->HasVar(u"teleportInterval")) m_TeleportInterval = self->GetVar<float>(u"teleportInterval");
|
||||
|
||||
if (self->GetVar<bool>(u"teleport")) {
|
||||
self->AddTimer("setupTeleport", 15.0f);
|
||||
self->AddTimer("setupTeleport", m_TeleportInterval);
|
||||
}
|
||||
}
|
||||
|
||||
void DLUVanityNPC::OnTimerDone(Entity* self, std::string timerName) {
|
||||
void DLUVanityTeleportingObject::OnTimerDone(Entity* self, std::string timerName) {
|
||||
if (timerName == "setupTeleport") {
|
||||
RenderComponent::PlayAnimation(self, u"interact");
|
||||
GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportBeam", "teleportBeam");
|
||||
@ -28,20 +28,22 @@ void DLUVanityNPC::OnTimerDone(Entity* self, std::string timerName) {
|
||||
GameMessages::SendStopFXEffect(self, true, "teleportBeam");
|
||||
GameMessages::SendStopFXEffect(self, true, "teleportRings");
|
||||
} else if (timerName == "teleport") {
|
||||
std::vector<VanityNPCLocation>& locations = m_NPC->m_Locations[Game::server->GetZoneID()];
|
||||
std::vector<VanityObjectLocation>& locations = m_Object->m_Locations[Game::server->GetZoneID()];
|
||||
|
||||
selectLocation:
|
||||
VanityNPCLocation& newLocation = locations[GeneralUtils::GenerateRandomNumber<size_t>(0, locations.size() - 1)];
|
||||
VanityObjectLocation& newLocation = locations[GeneralUtils::GenerateRandomNumber<size_t>(0, locations.size() - 1)];
|
||||
|
||||
// try to get not the same position, but if we get the same one twice, it's fine
|
||||
if (self->GetPosition() == newLocation.m_Position) {
|
||||
goto selectLocation; // cry about it
|
||||
VanityObjectLocation& newLocation = locations[GeneralUtils::GenerateRandomNumber<size_t>(0, locations.size() - 1)];
|
||||
}
|
||||
|
||||
self->SetPosition(newLocation.m_Position);
|
||||
self->SetRotation(newLocation.m_Rotation);
|
||||
self->SetScale(newLocation.m_Scale);
|
||||
GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportBeam", "teleportBeam");
|
||||
GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportRings", "teleportRings");
|
||||
self->AddTimer("stopFX", 2.0f);
|
||||
self->AddTimer("setupTeleport", 15.0f);
|
||||
self->AddTimer("setupTeleport", m_TeleportInterval);
|
||||
}
|
||||
}
|
@ -1,13 +1,14 @@
|
||||
#pragma once
|
||||
#include "CppScripts.h"
|
||||
|
||||
class VanityNPC;
|
||||
class DLUVanityNPC : public CppScripts::Script
|
||||
class VanityObject;
|
||||
class DLUVanityTeleportingObject : public CppScripts::Script
|
||||
{
|
||||
public:
|
||||
void OnStartup(Entity* self) override;
|
||||
void OnTimerDone(Entity* self, std::string timerName) override;
|
||||
|
||||
private:
|
||||
VanityNPC* m_NPC;
|
||||
VanityObject* m_Object;
|
||||
float m_TeleportInterval = 15.0f;
|
||||
};
|
@ -216,7 +216,7 @@
|
||||
#include "NtNaomiBreadcrumbServer.h"
|
||||
|
||||
// DLU Scripts
|
||||
#include "DLUVanityNPC.h"
|
||||
#include "DLUVanityTeleportingObject.h"
|
||||
|
||||
// AM Scripts
|
||||
#include "AmConsoleTeleportServer.h"
|
||||
@ -834,8 +834,8 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr
|
||||
script = new NjNyaMissionitems();
|
||||
|
||||
//DLU:
|
||||
else if (scriptName == "scripts\\02_server\\DLU\\DLUVanityNPC.lua")
|
||||
script = new DLUVanityNPC();
|
||||
else if (scriptName == "scripts\\02_server\\DLU\\DLUVanityTeleportingObject.lua")
|
||||
script = new DLUVanityTeleportingObject();
|
||||
|
||||
// Survival minigame
|
||||
else if (scriptName == "scripts\\02_server\\Enemy\\Survival\\L_AG_SURVIVAL_STROMBIE.lua")
|
||||
|
23
vanity/atm.xml
Normal file
23
vanity/atm.xml
Normal file
@ -0,0 +1,23 @@
|
||||
<objects>
|
||||
<object lot="13538">
|
||||
<config>
|
||||
<key data="CheckPrecondition=0:168"/>
|
||||
</config>
|
||||
<locations>
|
||||
<location zone="1100" x="248.792" y="381.869" z="-181.114" rw="0.782761" rx="0.00" ry="-0.622322" rz="0.00" />
|
||||
<location zone="1100" x="471.545" y="413.979" z="27.176" rw="0.874378" rx="0.00" ry="-0.485246" rz="0.00" />
|
||||
<location zone="1200" x="51.663" y="291.371" z="-74.650" rw="-0.446235" rx="0.00" ry="0.894916" rz="0.00" />
|
||||
<location zone="1200" x="203.348" y="259.136" z="-543.400" rw="0.481554" rx="0.00" ry="0.876416" rz="0.00" />
|
||||
<location zone="1201" x="46.537" y="233.137" z="-311.395" rw="0.780747" rx="0.00" ry="-0.624847" rz="0.00" />
|
||||
<location zone="1260" x="-255.991" y="535.731" z="322.299" rw="0.683777" rx="0.00" ry="-0.729691" rz="0.00" />
|
||||
<location zone="1600" x="85.210" y="1526.810" z="314.816" rw="-0.159486" rx="0.00" ry="0.987200" rz="0.00" />
|
||||
<location zone="1700" x="-256.293" y="1035.092" z="109.761" rw="0.00" rx="0.00" ry="1" rz="0.00" />
|
||||
<location zone="1300" x="-199.258" y="246.874" z="-101.174" rw="-0.219711" rx="0.00" ry="0.975565" rz="0.00" />
|
||||
<location zone="1300" x="51.848" y="329.0" z="561.114" rw="-0.277656" rx="0.00" ry="0.960681" rz="0.00" />
|
||||
<location zone="1300" x="363.259" y="259.367" z="-210.834" rw="0.961918" rx="0.00" ry="-0.273340" rz="0.00" />
|
||||
<location zone="1400" x="-194.288" y="381.275" z="-93.292" rw="0.935135" rx="0.00" ry="0.354292" rz="0.00" />
|
||||
<location zone="1400" x="-696.957" y="-3.206" z="-452.441" rw="0.884105" rx="0.00" ry="0.467288" rz="0.00" />
|
||||
<location zone="1800" x="-222.634" y="92.693" z="568.392" rw="-0.435024" rx="0.00" ry="0.900419" rz="0.00" />
|
||||
</locations>
|
||||
</object>
|
||||
</objects>
|
@ -1,5 +1,5 @@
|
||||
<npcs>
|
||||
<npc name="Wincent - Developer" lot="2279">
|
||||
<objects>
|
||||
<object name="Wincent - Developer" lot="2279">
|
||||
<equipment>6802, 2519, 2623, 14806</equipment>
|
||||
<phrases>
|
||||
<phrase>Sorry for the mess.</phrase>
|
||||
@ -11,39 +11,33 @@
|
||||
<phrase>Everything is awesome!</phrase>
|
||||
<phrase>I hope my behaviors are behaving themselves.</phrase>
|
||||
</phrases>
|
||||
<zone id="1200">
|
||||
<locations>
|
||||
<location x="-352.5" y="287.6" z="217.7" rw="-0.095" rx="0.0" ry="0.995" rz="0.0" />
|
||||
</locations>
|
||||
</zone>
|
||||
</npc>
|
||||
<npc name="EmosewaMC - Quickbuilder" lot="6738">
|
||||
<locations>
|
||||
<location zone="1200" x="-352.5" y="287.6" z="217.7" rw="-0.095" rx="0.0" ry="0.995" rz="0.0" />
|
||||
</locations>
|
||||
</object>
|
||||
<object name="EmosewaMC - Quickbuilder" lot="6738">
|
||||
<equipment>12947, 12949, 12962, 12963</equipment>
|
||||
<phrases>
|
||||
<phrase>I hope quickbulds are still working!</phrase>
|
||||
<phrase>Be careful crossing the gap!</phrase>
|
||||
<phrase>Have The Maelstrom stopped going invisible?</phrase>
|
||||
</phrases>
|
||||
<zone id="1800">
|
||||
<locations>
|
||||
<location x="745.756" y="75.262" z="-207.989" rw="0.838565" rx="0.0" ry="0.544801" rz="0.0" />
|
||||
</locations>
|
||||
</zone>
|
||||
</npc>
|
||||
<npc name="Neal - Paradox Scout" lot="6738">
|
||||
<locations>
|
||||
<location zone="1800" x="745.756" y="75.262" z="-207.989" rw="0.838565" rx="0.0" ry="0.544801" rz="0.0" />
|
||||
</locations>
|
||||
</object>
|
||||
<object name="Neal - Paradox Scout" lot="6738">
|
||||
<equipment>9950, 9944, 14102, 14092</equipment>
|
||||
<phrases>
|
||||
<phrase>Hello Explorer! It's great to see you made it!</phrase>
|
||||
<phrase>Have you heard about Darkflame?</phrase>
|
||||
<phrase>I've traveled across this entire system, but nothing beats the view here.</phrase>
|
||||
</phrases>
|
||||
<zone id="1200">
|
||||
<locations>
|
||||
<location x="163.835" y="330.756" z="-141.933" rw="0.774887" rx="0.0" ry="-0.6321" rz="0.0" />
|
||||
</locations>
|
||||
</zone>
|
||||
</npc>
|
||||
<npc name="averysumner - Destroyer of Worlds" lot="11235">
|
||||
<locations>
|
||||
<location zone="1200" x="163.835" y="330.756" z="-141.933" rw="0.774887" rx="0.0" ry="-0.6321" rz="0.0" />
|
||||
</locations>
|
||||
</object>
|
||||
<object name="averysumner - Destroyer of Worlds" lot="11235">
|
||||
<equipment></equipment>
|
||||
<phrases>
|
||||
<phrase>cmerw[acowipaejio;fawjioefasdl;kfjm;</phrase>
|
||||
@ -51,20 +45,18 @@
|
||||
<phrase>zxnpoasdfiopwemsadf'kawpfo[ekasdf;'s</phrase>
|
||||
<phrase>*teleports behind you*</phrase>
|
||||
</phrases>
|
||||
<script name="scripts\02_server\DLU\DLUVanityNPC.lua" />
|
||||
<flags>
|
||||
<flag name="teleport" value="1" />
|
||||
</flags>
|
||||
<zone id="1200">
|
||||
<locations>
|
||||
<location x="-361.583" y="285.541" z="64.4695" rw="0.785518" rx="0.0" ry="0.618838" rz="0.0" />
|
||||
<location x="178.188" y="354.528" z="-173.932" rw="0.734375" rx="0.0" ry="-0.678744" rz="0.0" />
|
||||
<location x="-318.569" y="287.637695" z="226.728" rw="-0.289502" rx="0.0" ry="0.957178" rz="0.0" />
|
||||
<location x="389.093" y="295.119" z="-647.583" rw="0.851229" rx="0.0" ry="-0.524795" rz="0.0" />
|
||||
</locations>
|
||||
</zone>
|
||||
</npc>
|
||||
<npc name="NinjaOfLU - Resident Physicist" lot="12260">
|
||||
<script name="scripts\02_server\DLU\DLUVanityTeleportingObject.lua" />
|
||||
<config>
|
||||
<key data="teleport=7:1" />
|
||||
<key data="teleportInterval=3:3.0" />
|
||||
</config>
|
||||
<locations>
|
||||
<location zone="1200" x="-361.583" y="285.541" z="64.4695" rw="0.785518" rx="0.0" ry="0.618838" rz="0.0" />
|
||||
<location zone="1200" x="178.188" y="354.528" z="-173.932" rw="0.734375" rx="0.0" ry="-0.678744" rz="0.0" />
|
||||
<location zone="1200" x="389.093" y="295.119" z="-647.583" rw="0.851229" rx="0.0" ry="-0.524795" rz="0.0" />
|
||||
</locations>
|
||||
</object>
|
||||
<object name="NinjaOfLU - Resident Physicist" lot="12260">
|
||||
<equipment>4360, 2523, 5659, 10067</equipment>
|
||||
<phrases>
|
||||
<phrase>Congratulations! I don't see too many people around here!</phrase>
|
||||
@ -77,18 +69,14 @@
|
||||
<phrase>I have been idle for 10 minutes, and will be returned to the login screen in 5 minutes.</phrase>
|
||||
<phrase>Of what has one to be proud, if dnot one's friends?</phrase>
|
||||
</phrases>
|
||||
<zone id="1100">
|
||||
<locations>
|
||||
<location x="287" y="451" z="-98" rw="-0.320221" rx="0" ry="0.947343" rz="0" />
|
||||
</locations>
|
||||
</zone>
|
||||
<zone id="1800">
|
||||
<locations>
|
||||
<location x="798" y="93" z="325" rw="-0.095" rx="0.0" ry="0.995" rz="0.0" />
|
||||
</locations>
|
||||
</zone>
|
||||
</npc>
|
||||
<npc name="BlasterBuilder - Race Ace" lot="8205">
|
||||
<locations>
|
||||
<location zone="1100" x="287" y="451" z="-98" rw="-0.320221" rx="0" ry="0.947343" rz="0" />
|
||||
</locations>
|
||||
<locations>
|
||||
<location zone="1800" x="798" y="93" z="325" rw="-0.095" rx="0.0" ry="0.995" rz="0.0" />
|
||||
</locations>
|
||||
</object>
|
||||
<object name="BlasterBuilder - Race Ace" lot="8205">
|
||||
<equipment>14098, 8539, 14096, 14092</equipment>
|
||||
<phrases>
|
||||
<phrase>LEGO Universe... LEGO Universe... LEGO Universe... LEGO Universe...</phrase>
|
||||
@ -112,14 +100,12 @@
|
||||
<phrase>Gather uh banana</phrase>
|
||||
<phrase>I've done nothing all day. Why am I here?</phrase>
|
||||
</phrases>
|
||||
<zone id="1100">
|
||||
<locations>
|
||||
<location x="444.318" y="421.154" z="54.4241" rw="0.877539" rx="0.0" ry="0.479506" rz="0.0" />
|
||||
</locations>
|
||||
</zone>
|
||||
</npc>
|
||||
<locations>
|
||||
<location zone="1100" x="444.318" y="421.154" z="54.4241" rw="0.877539" rx="0.0" ry="0.479506" rz="0.0" />
|
||||
</locations>
|
||||
</object>
|
||||
<!-- Mick - Brick Market Broker -->
|
||||
<npc name="Mick - Brick Market Broker" lot="6876">
|
||||
<object name="Mick - Brick Market Broker" lot="6876">
|
||||
<equipment>2519, 4091, 5128, 7990</equipment>
|
||||
<phrases>
|
||||
<phrase>Still can't believe we made it through that 2012 recession.</phrase>
|
||||
@ -133,14 +119,12 @@
|
||||
<phrase>I know a guy that sells jetpacks, it ain't cheap but everything has a price.</phrase>
|
||||
<phrase>You know Dr. Overbuild? He keeps ignoring my calls.</phrase>
|
||||
</phrases>
|
||||
<zone id="1100">
|
||||
<locations>
|
||||
<location x="449.725" y="414.926" z="180.539" rw="0.180645" rx="0.0" ry="0.983548" rz="0.0" />
|
||||
</locations>
|
||||
</zone>
|
||||
</npc>
|
||||
<locations>
|
||||
<location zone="1100" x="449.725" y="414.926" z="180.539" rw="0.180645" rx="0.0" ry="0.983548" rz="0.0" />
|
||||
</locations>
|
||||
</object>
|
||||
<!-- Knightoffaith - Sage of Wanderlust -->
|
||||
<npc name="Knightoffaith - Sage of Wanderlust" lot="12260">
|
||||
<object name="Knightoffaith - Sage of Wanderlust" lot="12260">
|
||||
<equipment>7359, 7368, 7380, 7392, 7403, 8456</equipment>
|
||||
<phrases>
|
||||
<phrase>Come and join me - take a look at the beauty that still remains even amidst the chaos</phrase>
|
||||
@ -155,13 +139,11 @@
|
||||
<phrase>Don't look at me, it was Sam's turn to look after Burno!</phrase>
|
||||
<phrase>The Universe is beautiful - take some time to enjoy it</phrase>
|
||||
</phrases>
|
||||
<zone id="1100">
|
||||
<locations>
|
||||
<location x="-381.053" y="367.787" z="-60.1185" rw="-0.14307" rx="0" ry="0.989713" rz="0" />
|
||||
</locations>
|
||||
</zone>
|
||||
</npc>
|
||||
<npc name="Snifflegully - DLU Alpha Tester" lot="2281">
|
||||
<locations>
|
||||
<location zone="1100" x="-381.053" y="367.787" z="-60.1185" rw="-0.14307" rx="0" ry="0.989713" rz="0" />
|
||||
</locations>
|
||||
</object>
|
||||
<object name="Snifflegully - DLU Alpha Tester" lot="2281">
|
||||
<equipment>15975, 7492, 12690, 12472</equipment>
|
||||
<phrases>
|
||||
<phrase>Praise the cube!</phrase>
|
||||
@ -173,13 +155,11 @@
|
||||
<phrase>Hope you enjoy DLU as much as I have, explorer!</phrase>
|
||||
<phrase>There are many more memories still to be made.</phrase>
|
||||
</phrases>
|
||||
<zone id="1200">
|
||||
<locations>
|
||||
<location x="-429.296" y="291.058" z="212.918" rw="0.339487" rx="0" ry="0.940611" rz="0" />
|
||||
</locations>
|
||||
</zone>
|
||||
</npc>
|
||||
<npc name="Hollis - Master Builder" lot="9893">
|
||||
<locations>
|
||||
<location zone="1200" x="-429.296" y="291.058" z="212.918" rw="0.339487" rx="0" ry="0.940611" rz="0" />
|
||||
</locations>
|
||||
</object>
|
||||
<object name="Hollis - Master Builder" lot="9893">
|
||||
<equipment>4465, 2517, 6855, 8532, 9615</equipment>
|
||||
<phrases>
|
||||
<phrase>Visit Starbase 3001 and blast off to the awesome worlds built by the World Builder League!</phrase>
|
||||
@ -189,13 +169,11 @@
|
||||
<phrase>There are many amazing properties to explore across the universe. You can visit some of them from the launchpads right here in Brick Annex.</phrase>
|
||||
<phrase>Don't stop believing! Uhh, I mean building. Don't stop building!</phrase>
|
||||
</phrases>
|
||||
<zone id="1200">
|
||||
<locations>
|
||||
<location x="-317.509" y="287.652" z="191.86" rw="0.57124" rx="0" ry="-0.820783" rz="0" />
|
||||
</locations>
|
||||
</zone>
|
||||
</npc>
|
||||
<npc name="Xiphoseer - Database Scout" lot="12260">
|
||||
<locations>
|
||||
<location zone="1200" x="-317.509" y="287.652" z="191.86" rw="0.57124" rx="0" ry="-0.820783" rz="0" />
|
||||
</locations>
|
||||
</object>
|
||||
<object name="Xiphoseer - Database Scout" lot="12260">
|
||||
<equipment>2632, 12754, 8645, 8468</equipment>
|
||||
<phrases>
|
||||
<phrase>Oh no, not that old list again</phrase>
|
||||
@ -207,13 +185,11 @@
|
||||
<phrase>Look at that view!</phrase>
|
||||
<phrase>Oxidize!</phrase>
|
||||
</phrases>
|
||||
<zone id="1300">
|
||||
<locations>
|
||||
<location x="283.986" y="261.208" z="-128.466" rw="0.70207" rx="0" ry="0.712108" rz="0" />
|
||||
</locations>
|
||||
</zone>
|
||||
</npc>
|
||||
<npc name="Simon - External Archeologist" lot="7128">
|
||||
<locations>
|
||||
<location zone="1300" x="283.986" y="261.208" z="-128.466" rw="0.70207" rx="0" ry="0.712108" rz="0" />
|
||||
</locations>
|
||||
</object>
|
||||
<object name="Simon - External Archeologist" lot="7128">
|
||||
<equipment>7363, 7371, 7383, 7395, 7405, 8462</equipment>
|
||||
<phrases>
|
||||
<phrase>I want to build a castle, but first I need to build the bricks.</phrase>
|
||||
@ -221,13 +197,11 @@
|
||||
<phrase>When you do extra steps, you can always customize the steps without redoing the whole staircase</phrase>
|
||||
<phrase>Who needs lamps, when you have Tiki Torches</phrase>
|
||||
</phrases>
|
||||
<zone id="1300">
|
||||
<locations>
|
||||
<location x="204.93" y="294.784" z="471.537" rw="0.85015" rx="0" ry="-0.52654" rz="0" />
|
||||
</locations>
|
||||
</zone>
|
||||
</npc>
|
||||
<npc name="Bricknave - Treasure Hunter" lot="2279">
|
||||
<locations>
|
||||
<location zone="1300" x="204.93" y="294.784" z="471.537" rw="0.85015" rx="0" ry="-0.52654" rz="0" />
|
||||
</locations>
|
||||
</object>
|
||||
<object name="Bricknave - Treasure Hunter" lot="2279">
|
||||
<equipment>7486, 7510, 7462, 8539</equipment>
|
||||
<phrases>
|
||||
<phrase>During my very first expedition, Stromlings were called Darklings, and they dropped entire treasure chests!</phrase>
|
||||
@ -239,13 +213,11 @@
|
||||
<phrase>There's treasure inside of all of us. It's called Imagination.</phrase>
|
||||
<phrase>Stromlings! Why did it have to be Stromlings?</phrase>
|
||||
</phrases>
|
||||
<zone id="1300">
|
||||
<locations>
|
||||
<location x="-47.6296" y="322.527" z="533.5" rw="0.145135" rx="0" ry="0.989412" rz="0" />
|
||||
</locations>
|
||||
</zone>
|
||||
</npc>
|
||||
<npc name="Jamie - Shenanigans Enthusiast" lot="9893">
|
||||
<locations>
|
||||
<location zone="1300" x="-47.6296" y="322.527" z="533.5" rw="0.145135" rx="0" ry="0.989412" rz="0" />
|
||||
</locations>
|
||||
</object>
|
||||
<object name="Jamie - Shenanigans Enthusiast" lot="9893">
|
||||
<equipment>12915, 9683, 10476, 13342, 14166</equipment>
|
||||
<phrases>
|
||||
<phrase>sup lol</phrase>
|
||||
@ -253,22 +225,18 @@
|
||||
<phrase>Wait, did the game close yet?</phrase>
|
||||
<phrase>... What year is it?</phrase>
|
||||
</phrases>
|
||||
<zone id="1400">
|
||||
<locations>
|
||||
<location x="-490.608" y="51.9449" z="-347.747" rw="0.594978" rx="0" ry="-0.803742" rz="0" />
|
||||
</locations>
|
||||
</zone>
|
||||
</npc>
|
||||
<npc name="Wicked" lot="7412">
|
||||
<locations>
|
||||
<location zone="1400" x="-490.608" y="51.9449" z="-347.747" rw="0.594978" rx="0" ry="-0.803742" rz="0" />
|
||||
</locations>
|
||||
</object>
|
||||
<object name="Wicked" lot="7412">
|
||||
<equipment>8287, 2957, 7523, 16613</equipment>
|
||||
<phrases></phrases>
|
||||
<zone id="1400">
|
||||
<locations>
|
||||
<location x="264.506" y="339.931" z="54.1201" rw="0.715223" rx="0" ry="0.698896" rz="0" />
|
||||
</locations>
|
||||
</zone>
|
||||
</npc>
|
||||
<npc name="Krysto - Sentinal Veteran" lot="12260">
|
||||
<locations>
|
||||
<location zone="1400" x="264.506" y="339.931" z="54.1201" rw="0.715223" rx="0" ry="0.698896" rz="0" />
|
||||
</locations>
|
||||
</object>
|
||||
<object name="Krysto - Sentinal Veteran" lot="12260">
|
||||
<equipment>12651, 12648, 10158, 5694, 16619, 9681, 8286</equipment>
|
||||
<phrases>
|
||||
<phrase>Need a pick me up? Interact with the consoles here to restore your health and armor!</phrase>
|
||||
@ -280,37 +248,31 @@
|
||||
<phrase>What do you mean my title is misspelled?</phrase>
|
||||
<phrase>When I was your age, numbers were illegal.</phrase>
|
||||
</phrases>
|
||||
<zone id="1900">
|
||||
<locations>
|
||||
<location x="-493.724" y="1124.05" z="-76.6355" rw="0.1719" rx="0" ry="0.985114" rz="0" />
|
||||
</locations>
|
||||
</zone>
|
||||
</npc>
|
||||
<locations>
|
||||
<location zone="1900" x="-493.724" y="1124.05" z="-76.6355" rw="0.1719" rx="0" ry="0.985114" rz="0" />
|
||||
</locations>
|
||||
</object>
|
||||
12651
|
||||
<npc name="Matthew - ?????" lot="2279">
|
||||
<object name="Matthew - ?????" lot="2279">
|
||||
<equipment>9856, 7793, 6928, 6927</equipment>
|
||||
<phrases>
|
||||
<phrase>I think I have a migraine from staring at this for so long</phrase>
|
||||
<phrase>Anything but Portabello</phrase>
|
||||
</phrases>
|
||||
<zone id="1900">
|
||||
<locations>
|
||||
<location x="-227.621" y="1188.28" z="145.734" rw="-0.254353" rx="0" ry="0.967111" rz="0" />
|
||||
</locations>
|
||||
</zone>
|
||||
</npc>
|
||||
<npc name="Raine" lot="9893">
|
||||
<locations>
|
||||
<location zone="1900" x="-227.621" y="1188.28" z="145.734" rw="-0.254353" rx="0" ry="0.967111" rz="0" />
|
||||
</locations>
|
||||
</object>
|
||||
<object name="Raine" lot="9893">
|
||||
<equipment>13342, 7370, 7382</equipment>
|
||||
<phrases>
|
||||
<phrase>Per Aspera ad Astra</phrase>
|
||||
</phrases>
|
||||
<zone id="1900">
|
||||
<locations>
|
||||
<location x="-190.673" y="1218.34" z="221.6" rw="0.972371" rx="0" ry="-0.233441" rz="0" />
|
||||
</locations>
|
||||
</zone>
|
||||
</npc>
|
||||
<npc name="Brickgirl - Explorer" lot="12260">
|
||||
<locations>
|
||||
<location zone="1900" x="-190.673" y="1218.34" z="221.6" rw="0.972371" rx="0" ry="-0.233441" rz="0" />
|
||||
</locations>
|
||||
</object>
|
||||
<object name="Brickgirl - Explorer" lot="12260">
|
||||
<equipment>12781, 12686, 13000, 12802, 12678, 12095</equipment>
|
||||
<phrases>
|
||||
<phrase>Imagination will often carry us to worlds that never were, but without it we go nowhere.</phrase>
|
||||
@ -318,26 +280,22 @@
|
||||
<phrase>Have you tried those buttery croissants from “Farnham Spoon” they are delicious! I might just go and have another</phrase>
|
||||
<phrase>Have fun!</phrase>
|
||||
</phrases>
|
||||
<zone id="1800">
|
||||
<locations>
|
||||
<location x="-39.2259" y="96.8605" z="-550.077" rw="0.815145" rx="0" ry="-0.579257" rz="0" />
|
||||
</locations>
|
||||
</zone>
|
||||
</npc>
|
||||
<npc name="Sam - The Avianite" lot="2281">
|
||||
<locations>
|
||||
<location zone="1800" x="-39.2259" y="96.8605" z="-550.077" rw="0.815145" rx="0" ry="-0.579257" rz="0" />
|
||||
</locations>
|
||||
</object>
|
||||
<object name="Sam - The Avianite" lot="2281">
|
||||
<equipment>12563, 12565, 12567, 12949, 12947, 7570</equipment>
|
||||
<phrases>
|
||||
<phrase>Nice finding me! Now take a moment to take a deep breath, in... And out... NOW GET BACK TO YOUR QUEST!</phrase>
|
||||
<phrase>Wu once told me, "The path we seek is never a straight line"."</phrase>
|
||||
<phrase>Stop! I'm from the future to warn you that there will be snakes, ninja robots! More snakes, ghosts, sky pirates, snakes that make snakes! Bikers, dragon hunters... Wait what do you mean it hasn't happened yet?</phrase>
|
||||
</phrases>
|
||||
<zone id="2000">
|
||||
<locations>
|
||||
<location x="-119.269" y="230.372" z="226.63" rw="0.381416" rx="0" ry="0.924404" rz="0" />
|
||||
</locations>
|
||||
</zone>
|
||||
</npc>
|
||||
<npc name="lcdr - Dab Specialist" lot="8657">
|
||||
<locations>
|
||||
<location zone="2000" x="-119.269" y="230.372" z="226.63" rw="0.381416" rx="0" ry="0.924404" rz="0" />
|
||||
</locations>
|
||||
</object>
|
||||
<object name="lcdr - Dab Specialist" lot="8657">
|
||||
<equipment>15931, 4298, 2526</equipment>
|
||||
<phrases>
|
||||
<phrase>Hello there.</phrase>
|
||||
@ -354,13 +312,11 @@
|
||||
<phrase>Gonk.</phrase>
|
||||
<phrase>There is a theory which states that if ever anyone discovers exactly what the Universe is for and why it is here, it will instantly disappear and be replaced by something even more bizarre and inexplicable. There is another theory, which states that this has already happened.</phrase>
|
||||
</phrases>
|
||||
<zone id="1200">
|
||||
<locations>
|
||||
<location x="197.549" y="259.137" z="-587.759" rw="0.873694" rx="0" ry="0.486475" rz="0" />
|
||||
</locations>
|
||||
</zone>
|
||||
</npc>
|
||||
<npc name="zaop - Assembly Scientist" lot="2279">
|
||||
<locations>
|
||||
<location zone="1200" x="197.549" y="259.137" z="-587.759" rw="0.873694" rx="0" ry="0.486475" rz="0" />
|
||||
</locations>
|
||||
</object>
|
||||
<object name="zaop - Assembly Scientist" lot="2279">
|
||||
<equipment>12099, 3010, 10067, 7503</equipment>
|
||||
<phrases>
|
||||
<phrase>Hi!</phrase>
|
||||
@ -379,22 +335,18 @@
|
||||
<phrase>Excuse me, do you know the way to Frostburgh?</phrase>
|
||||
<phrase>What are those Paradox scientists up to these days?</phrase>
|
||||
</phrases>
|
||||
<zone id="1100">
|
||||
<locations>
|
||||
<location x="436.949" y="415.264" z="151.381" rw="0.528425" rx="0" ry="0.84898" rz="0" />
|
||||
</locations>
|
||||
</zone>
|
||||
</npc>
|
||||
<npc name="Ben" lot="2279">
|
||||
<locations>
|
||||
<location zone="1100" x="436.949" y="415.264" z="151.381" rw="0.528425" rx="0" ry="0.84898" rz="0" />
|
||||
</locations>
|
||||
</object>
|
||||
<object name="Ben" lot="2279">
|
||||
<equipment>8664, 4065, 2587</equipment>
|
||||
<phrases></phrases>
|
||||
<zone id="1200">
|
||||
<locations>
|
||||
<location x="284.538" y="260.627" z="-506.692" rw="0.819721" rx="0" ry="0.572763" rz="0" />
|
||||
</locations>
|
||||
</zone>
|
||||
</npc>
|
||||
<npc name="HappyAngryCatfish - Explorer" lot="2279">
|
||||
<locations>
|
||||
<location zone="1200" x="284.538" y="260.627" z="-506.692" rw="0.819721" rx="0" ry="0.572763" rz="0" />
|
||||
</locations>
|
||||
</object>
|
||||
<object name="HappyAngryCatfish - Explorer" lot="2279">
|
||||
<equipment>8613, 13000, 7570</equipment>
|
||||
<phrases>
|
||||
<phrase>The red parrot can be very difficult to find!</phrase>
|
||||
@ -402,13 +354,11 @@
|
||||
<phrase>I think I may be lost...</phrase>
|
||||
<phrase>I'm feeling a bit emotionally conflicted right now</phrase>
|
||||
</phrases>
|
||||
<zone id="1300">
|
||||
<locations>
|
||||
<location x="-171.217" y="246.482" z="-147.05" rw="-0.203118" rx="0" ry="0.979154" rz="0" />
|
||||
</locations>
|
||||
</zone>
|
||||
</npc>
|
||||
<npc name="Max - Developer" lot="9749">
|
||||
<locations>
|
||||
<location zone="1300" x="-171.217" y="246.482" z="-147.05" rw="-0.203118" rx="0" ry="0.979154" rz="0" />
|
||||
</locations>
|
||||
</object>
|
||||
<object name="Max - Developer" lot="9749">
|
||||
<equipment>4523, 2517, 11909</equipment>
|
||||
<phrases>
|
||||
<phrase>Some people know me as "Darwin"; but that's been a while!</phrase>
|
||||
@ -421,33 +371,8 @@
|
||||
<phrase>I love cats, little meow meows</phrase>
|
||||
<phrase>It's not perfect, but it works!</phrase>
|
||||
</phrases>
|
||||
<zone id="1201">
|
||||
<locations>
|
||||
<location x="197.709" y="179.335" z="-8.05284" rw="0.544424" rx="0" ry="-0.83881" rz="0" />
|
||||
</locations>
|
||||
</zone>
|
||||
</npc>
|
||||
<party zone="1200" chance="0.0">
|
||||
<locations>
|
||||
<location x="-24.3963" y="291.542" z="-117.871" rw="0.480946" rx="0" ry="0.87675" rz="0" />
|
||||
<location x="-16.9897" y="291.584" z="-112.438" rw="0.0677884" rx="0" ry="0.9977" rz="0" />
|
||||
<location x="-3.52143" y="291.66" z="-118.186" rw="0.519658" rx="0" ry="-0.854375" rz="0" />
|
||||
<location x="-4.54551" y="291.661" z="-131.914" rw="0.916747" rx="0" ry="-0.399469" rz="0" />
|
||||
<location x="-18.8573" y="291.566" z="-136.347" rw="0.983708" rx="0" ry="0.179772" rz="0" />
|
||||
<location x="-17.0958" y="291.824" z="-127.153" rw="0.999554" rx="0" ry="0.0298604" rz="0" />
|
||||
<location x="-10.9727" y="291.868" z="-125.387" rw="0.861138" rx="0" ry="0.508372" rz="0" />
|
||||
<location x="-21.9406" y="291.284" z="-139.761" rw="0.990094" rx="0" ry="0.140407" rz="0" />
|
||||
<location x="4.54396" y="291.19" z="-131.908" rw="0.929764" rx="0" ry="-0.368157" rz="0" />
|
||||
<location x="-0.189393" y="291.105" z="-109.617" rw="-0.124242" rx="0" ry="0.992252" rz="0" />
|
||||
<location zone="1201" x="197.709" y="179.335" z="-8.05284" rw="0.544424" rx="0" ry="-0.83881" rz="0" />
|
||||
</locations>
|
||||
</party>
|
||||
<partyphrases>
|
||||
<phrase>Hi there!</phrase>
|
||||
<phrase>Hi!</phrase>
|
||||
<phrase>Hahaha!</phrase>
|
||||
<phrase>Hello there!</phrase>
|
||||
|
||||
<phrase>:D</phrase>
|
||||
<phrase>:P</phrase>
|
||||
</partyphrases>
|
||||
</npcs>
|
||||
</object>
|
||||
</objects>
|
4
vanity/root.xml
Normal file
4
vanity/root.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<files>
|
||||
<file name="dev-tribute.xml" enabled="1"/>
|
||||
<file name="atm.xml" enabled="0"/>
|
||||
</files>
|
Loading…
Reference in New Issue
Block a user