mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-11-14 20:28:21 +00:00
Merge branch 'main' into moreMovementAi
This commit is contained in:
commit
152a33f937
@ -179,7 +179,7 @@ file(ARCHIVE_EXTRACT INPUT ${PROJECT_BINARY_DIR}/navmeshes.zip DESTINATION ${PRO
|
|||||||
file(REMOVE ${PROJECT_BINARY_DIR}/navmeshes.zip)
|
file(REMOVE ${PROJECT_BINARY_DIR}/navmeshes.zip)
|
||||||
|
|
||||||
# Copy vanity files on first build
|
# 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})
|
foreach(file ${VANITY_FILES})
|
||||||
configure_file("${CMAKE_SOURCE_DIR}/vanity/${file}" "${CMAKE_BINARY_DIR}/vanity/${file}" COPYONLY)
|
configure_file("${CMAKE_SOURCE_DIR}/vanity/${file}" "${CMAKE_BINARY_DIR}/vanity/${file}" COPYONLY)
|
||||||
|
@ -106,7 +106,7 @@ enum class eReplicaComponentType : uint32_t {
|
|||||||
INTERACTION_MANAGER,
|
INTERACTION_MANAGER,
|
||||||
DONATION_VENDOR,
|
DONATION_VENDOR,
|
||||||
COMBAT_MEDIATOR,
|
COMBAT_MEDIATOR,
|
||||||
COMMENDATION_VENDOR,
|
ACHIEVEMENT_VENDOR,
|
||||||
GATE_RUSH_CONTROL,
|
GATE_RUSH_CONTROL,
|
||||||
RAIL_ACTIVATOR,
|
RAIL_ACTIVATOR,
|
||||||
ROLLER,
|
ROLLER,
|
||||||
|
15
dCommon/dEnums/eVendorTransactionResult.h
Normal file
15
dCommon/dEnums/eVendorTransactionResult.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef __EVENDORTRANSACTIONRESULT__
|
||||||
|
#define __EVENDORTRANSACTIONRESULT__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum class eVendorTransactionResult : uint32_t {
|
||||||
|
SELL_SUCCESS = 0,
|
||||||
|
SELL_FAIL,
|
||||||
|
PURCHASE_SUCCESS,
|
||||||
|
PURCHASE_FAIL,
|
||||||
|
DONATION_FAIL,
|
||||||
|
DONATION_FULL
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // !__EVENDORTRANSACTIONRESULT__
|
@ -79,7 +79,6 @@ void CDMissionsTable::LoadValuesFromDatabase() {
|
|||||||
entries.push_back(entry);
|
entries.push_back(entry);
|
||||||
tableData.nextRow();
|
tableData.nextRow();
|
||||||
}
|
}
|
||||||
|
|
||||||
tableData.finalize();
|
tableData.finalize();
|
||||||
|
|
||||||
Default.id = -1;
|
Default.id = -1;
|
||||||
@ -118,3 +117,12 @@ const CDMissions& CDMissionsTable::GetByMissionID(uint32_t missionID, bool& foun
|
|||||||
return Default;
|
return Default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::set<int32_t> CDMissionsTable::GetMissionsForReward(LOT lot) {
|
||||||
|
std::set<int32_t> toReturn {};
|
||||||
|
for (const auto& entry : GetEntries()) {
|
||||||
|
if (lot == entry.reward_item1 || lot == entry.reward_item2 || lot == entry.reward_item3 || lot == entry.reward_item4) {
|
||||||
|
toReturn.insert(entry.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
@ -70,6 +70,9 @@ public:
|
|||||||
|
|
||||||
const CDMissions& GetByMissionID(uint32_t missionID, bool& found) const;
|
const CDMissions& GetByMissionID(uint32_t missionID, bool& found) const;
|
||||||
|
|
||||||
|
const std::set<int32_t> GetMissionsForReward(LOT lot);
|
||||||
|
|
||||||
|
|
||||||
static CDMissions Default;
|
static CDMissions Default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -82,6 +82,7 @@
|
|||||||
#include "CollectibleComponent.h"
|
#include "CollectibleComponent.h"
|
||||||
#include "ItemComponent.h"
|
#include "ItemComponent.h"
|
||||||
#include "GhostComponent.h"
|
#include "GhostComponent.h"
|
||||||
|
#include "AchievementVendorComponent.h"
|
||||||
|
|
||||||
// Table includes
|
// Table includes
|
||||||
#include "CDComponentsRegistryTable.h"
|
#include "CDComponentsRegistryTable.h"
|
||||||
@ -615,6 +616,8 @@ void Entity::Initialize() {
|
|||||||
AddComponent<VendorComponent>();
|
AddComponent<VendorComponent>();
|
||||||
} else if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::DONATION_VENDOR, -1) != -1)) {
|
} else if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::DONATION_VENDOR, -1) != -1)) {
|
||||||
AddComponent<DonationVendorComponent>();
|
AddComponent<DonationVendorComponent>();
|
||||||
|
} else if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ACHIEVEMENT_VENDOR, -1) != -1)) {
|
||||||
|
AddComponent<AchievementVendorComponent>();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY_VENDOR, -1) != -1) {
|
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY_VENDOR, -1) != -1) {
|
||||||
@ -1185,6 +1188,11 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
|
|||||||
donationVendorComponent->Serialize(outBitStream, bIsInitialUpdate);
|
donationVendorComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AchievementVendorComponent* achievementVendorComponent;
|
||||||
|
if (TryGetComponent(eReplicaComponentType::ACHIEVEMENT_VENDOR, achievementVendorComponent)) {
|
||||||
|
achievementVendorComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
BouncerComponent* bouncerComponent;
|
BouncerComponent* bouncerComponent;
|
||||||
if (TryGetComponent(eReplicaComponentType::BOUNCER, bouncerComponent)) {
|
if (TryGetComponent(eReplicaComponentType::BOUNCER, bouncerComponent)) {
|
||||||
bouncerComponent->Serialize(outBitStream, bIsInitialUpdate);
|
bouncerComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||||
@ -2179,3 +2187,9 @@ void Entity::SetRespawnRot(const NiQuaternion& rotation) {
|
|||||||
auto* characterComponent = GetComponent<CharacterComponent>();
|
auto* characterComponent = GetComponent<CharacterComponent>();
|
||||||
if (characterComponent) characterComponent->SetRespawnRot(rotation);
|
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 ProcessPositionUpdate(PositionUpdate& update);
|
||||||
|
|
||||||
|
void SetScale(const float scale);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
LWOOBJID m_ObjectID;
|
LWOOBJID m_ObjectID;
|
||||||
|
|
||||||
|
@ -243,13 +243,13 @@ bool BehaviorContext::CalculateUpdate(const float deltaTime) {
|
|||||||
echo.uiBehaviorHandle = entry.handle;
|
echo.uiBehaviorHandle = entry.handle;
|
||||||
echo.uiSkillHandle = this->skillUId;
|
echo.uiSkillHandle = this->skillUId;
|
||||||
|
|
||||||
auto* bitStream = new RakNet::BitStream();
|
RakNet::BitStream bitStream{};
|
||||||
|
|
||||||
// Calculate sync
|
// Calculate sync
|
||||||
entry.behavior->SyncCalculation(this, bitStream, entry.branchContext);
|
entry.behavior->SyncCalculation(this, &bitStream, entry.branchContext);
|
||||||
|
|
||||||
if (!clientInitalized) {
|
if (!clientInitalized) {
|
||||||
echo.sBitStream.assign(reinterpret_cast<char*>(bitStream->GetData()), bitStream->GetNumberOfBytesUsed());
|
echo.sBitStream.assign(reinterpret_cast<char*>(bitStream.GetData()), bitStream.GetNumberOfBytesUsed());
|
||||||
|
|
||||||
// Write message
|
// Write message
|
||||||
RakNet::BitStream message;
|
RakNet::BitStream message;
|
||||||
@ -262,8 +262,6 @@ bool BehaviorContext::CalculateUpdate(const float deltaTime) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ExecuteUpdates();
|
ExecuteUpdates();
|
||||||
|
|
||||||
delete bitStream;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<BehaviorSyncEntry> valid;
|
std::vector<BehaviorSyncEntry> valid;
|
||||||
|
72
dGame/dComponents/AchievementVendorComponent.cpp
Normal file
72
dGame/dComponents/AchievementVendorComponent.cpp
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#include "AchievementVendorComponent.h"
|
||||||
|
#include "MissionComponent.h"
|
||||||
|
#include "InventoryComponent.h"
|
||||||
|
#include "eMissionState.h"
|
||||||
|
#include "CDComponentsRegistryTable.h"
|
||||||
|
#include "CDItemComponentTable.h"
|
||||||
|
#include "eVendorTransactionResult.h"
|
||||||
|
#include "CheatDetection.h"
|
||||||
|
#include "UserManager.h"
|
||||||
|
#include "CDMissionsTable.h"
|
||||||
|
|
||||||
|
bool AchievementVendorComponent::SellsItem(Entity* buyer, const LOT lot) {
|
||||||
|
auto* missionComponent = buyer->GetComponent<MissionComponent>();
|
||||||
|
if (!missionComponent) return false;
|
||||||
|
|
||||||
|
if (m_PlayerPurchasableItems[buyer->GetObjectID()].contains(lot)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CDMissionsTable* missionsTable = CDClientManager::GetTable<CDMissionsTable>();
|
||||||
|
const auto missions = missionsTable->GetMissionsForReward(lot);
|
||||||
|
for (const auto mission : missions) {
|
||||||
|
if (missionComponent->GetMissionState(mission) == eMissionState::COMPLETE) {
|
||||||
|
m_PlayerPurchasableItems[buyer->GetObjectID()].insert(lot);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AchievementVendorComponent::Buy(Entity* buyer, LOT lot, uint32_t count) {
|
||||||
|
// get the item Comp from the item LOT
|
||||||
|
CDComponentsRegistryTable* compRegistryTable = CDClientManager::GetTable<CDComponentsRegistryTable>();
|
||||||
|
CDItemComponentTable* itemComponentTable = CDClientManager::GetTable<CDItemComponentTable>();
|
||||||
|
int itemCompID = compRegistryTable->GetByIDAndType(lot, eReplicaComponentType::ITEM);
|
||||||
|
CDItemComponent itemComp = itemComponentTable->GetItemComponentByID(itemCompID);
|
||||||
|
uint32_t costLOT = itemComp.commendationLOT;
|
||||||
|
|
||||||
|
if (costLOT == -1 || !SellsItem(buyer, lot)) {
|
||||||
|
auto* user = UserManager::Instance()->GetUser(buyer->GetSystemAddress());
|
||||||
|
CheatDetection::ReportCheat(user, buyer->GetSystemAddress(), "Attempted to buy item %i from achievement vendor %i that is not purchasable", lot, m_Parent->GetLOT());
|
||||||
|
GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_FAIL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* inventoryComponent = buyer->GetComponent<InventoryComponent>();
|
||||||
|
if (!inventoryComponent) {
|
||||||
|
GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_FAIL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (costLOT == 13763) { // Faction Token Proxy
|
||||||
|
auto* missionComponent = buyer->GetComponent<MissionComponent>();
|
||||||
|
if (!missionComponent) return;
|
||||||
|
|
||||||
|
if (missionComponent->GetMissionState(545) == eMissionState::COMPLETE) costLOT = 8318; // "Assembly Token"
|
||||||
|
if (missionComponent->GetMissionState(556) == eMissionState::COMPLETE) costLOT = 8321; // "Venture League Token"
|
||||||
|
if (missionComponent->GetMissionState(567) == eMissionState::COMPLETE) costLOT = 8319; // "Sentinels Token"
|
||||||
|
if (missionComponent->GetMissionState(578) == eMissionState::COMPLETE) costLOT = 8320; // "Paradox Token"
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t altCurrencyCost = itemComp.commendationCost * count;
|
||||||
|
if (inventoryComponent->GetLotCount(costLOT) < altCurrencyCost) {
|
||||||
|
GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_FAIL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
inventoryComponent->RemoveItem(costLOT, altCurrencyCost);
|
||||||
|
inventoryComponent->AddItem(lot, count, eLootSourceType::VENDOR);
|
||||||
|
GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_SUCCESS);
|
||||||
|
|
||||||
|
}
|
23
dGame/dComponents/AchievementVendorComponent.h
Normal file
23
dGame/dComponents/AchievementVendorComponent.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef __ACHIEVEMENTVENDORCOMPONENT__H__
|
||||||
|
#define __ACHIEVEMENTVENDORCOMPONENT__H__
|
||||||
|
|
||||||
|
#include "VendorComponent.h"
|
||||||
|
#include "eReplicaComponentType.h"
|
||||||
|
#include <set>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
class Entity;
|
||||||
|
|
||||||
|
class AchievementVendorComponent final : public VendorComponent {
|
||||||
|
public:
|
||||||
|
static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::ACHIEVEMENT_VENDOR;
|
||||||
|
AchievementVendorComponent(Entity* parent) : VendorComponent(parent) {};
|
||||||
|
bool SellsItem(Entity* buyer, const LOT lot);
|
||||||
|
void Buy(Entity* buyer, LOT lot, uint32_t count);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<LWOOBJID,std::set<LOT>> m_PlayerPurchasableItems;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //!__ACHIEVEMENTVENDORCOMPONENT__H__
|
@ -208,9 +208,8 @@ void BuffComponent::ApplyBuff(const int32_t id, const float duration, const LWOO
|
|||||||
void BuffComponent::RemoveBuff(int32_t id, bool fromUnEquip, bool removeImmunity, bool ignoreRefCount) {
|
void BuffComponent::RemoveBuff(int32_t id, bool fromUnEquip, bool removeImmunity, bool ignoreRefCount) {
|
||||||
const auto& iter = m_Buffs.find(id);
|
const auto& iter = m_Buffs.find(id);
|
||||||
|
|
||||||
if (iter == m_Buffs.end()) {
|
// If the buff is already scheduled to be removed, don't do it again
|
||||||
return;
|
if (iter == m_Buffs.end() || m_BuffsToRemove.contains(id)) return;
|
||||||
}
|
|
||||||
|
|
||||||
if (!ignoreRefCount && !iter->second.cancelOnRemoveBuff) {
|
if (!ignoreRefCount && !iter->second.cancelOnRemoveBuff) {
|
||||||
iter->second.refCount--;
|
iter->second.refCount--;
|
||||||
@ -222,7 +221,7 @@ void BuffComponent::RemoveBuff(int32_t id, bool fromUnEquip, bool removeImmunity
|
|||||||
|
|
||||||
GameMessages::SendRemoveBuff(m_Parent, fromUnEquip, removeImmunity, id);
|
GameMessages::SendRemoveBuff(m_Parent, fromUnEquip, removeImmunity, id);
|
||||||
|
|
||||||
m_BuffsToRemove.push_back(id);
|
m_BuffsToRemove.insert(id);
|
||||||
|
|
||||||
RemoveBuffEffect(id);
|
RemoveBuffEffect(id);
|
||||||
}
|
}
|
||||||
|
@ -141,7 +141,7 @@ private:
|
|||||||
std::map<int32_t, Buff> m_Buffs;
|
std::map<int32_t, Buff> m_Buffs;
|
||||||
|
|
||||||
// Buffs to remove at the end of the update frame.
|
// Buffs to remove at the end of the update frame.
|
||||||
std::vector<int32_t> m_BuffsToRemove;
|
std::set<int32_t> m_BuffsToRemove;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parameters (=effects) for each buff
|
* Parameters (=effects) for each buff
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
set(DGAME_DCOMPONENTS_SOURCES
|
set(DGAME_DCOMPONENTS_SOURCES
|
||||||
|
"AchievementVendorComponent.cpp"
|
||||||
"ActivityComponent.cpp"
|
"ActivityComponent.cpp"
|
||||||
"BaseCombatAIComponent.cpp"
|
"BaseCombatAIComponent.cpp"
|
||||||
"BouncerComponent.cpp"
|
"BouncerComponent.cpp"
|
||||||
|
@ -252,7 +252,7 @@ bool SkillComponent::CastSkill(const uint32_t skillId, LWOOBJID target, const LW
|
|||||||
|
|
||||||
|
|
||||||
SkillExecutionResult SkillComponent::CalculateBehavior(const uint32_t skillId, const uint32_t behaviorId, const LWOOBJID target, const bool ignoreTarget, const bool clientInitalized, const LWOOBJID originatorOverride) {
|
SkillExecutionResult SkillComponent::CalculateBehavior(const uint32_t skillId, const uint32_t behaviorId, const LWOOBJID target, const bool ignoreTarget, const bool clientInitalized, const LWOOBJID originatorOverride) {
|
||||||
auto* bitStream = new RakNet::BitStream();
|
RakNet::BitStream bitStream{};
|
||||||
|
|
||||||
auto* behavior = Behavior::CreateBehavior(behaviorId);
|
auto* behavior = Behavior::CreateBehavior(behaviorId);
|
||||||
|
|
||||||
@ -266,14 +266,13 @@ SkillExecutionResult SkillComponent::CalculateBehavior(const uint32_t skillId, c
|
|||||||
|
|
||||||
context->foundTarget = target != LWOOBJID_EMPTY || ignoreTarget || clientInitalized;
|
context->foundTarget = target != LWOOBJID_EMPTY || ignoreTarget || clientInitalized;
|
||||||
|
|
||||||
behavior->Calculate(context, bitStream, { target, 0 });
|
behavior->Calculate(context, &bitStream, { target, 0 });
|
||||||
|
|
||||||
for (auto* script : CppScripts::GetEntityScripts(m_Parent)) {
|
for (auto* script : CppScripts::GetEntityScripts(m_Parent)) {
|
||||||
script->OnSkillCast(m_Parent, skillId);
|
script->OnSkillCast(m_Parent, skillId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!context->foundTarget) {
|
if (!context->foundTarget) {
|
||||||
delete bitStream;
|
|
||||||
delete context;
|
delete context;
|
||||||
|
|
||||||
// Invalid attack
|
// Invalid attack
|
||||||
@ -299,7 +298,7 @@ SkillExecutionResult SkillComponent::CalculateBehavior(const uint32_t skillId, c
|
|||||||
}
|
}
|
||||||
//start.optionalTargetID = target;
|
//start.optionalTargetID = target;
|
||||||
|
|
||||||
start.sBitStream.assign(reinterpret_cast<char*>(bitStream->GetData()), bitStream->GetNumberOfBytesUsed());
|
start.sBitStream.assign(reinterpret_cast<char*>(bitStream.GetData()), bitStream.GetNumberOfBytesUsed());
|
||||||
|
|
||||||
// Write message
|
// Write message
|
||||||
RakNet::BitStream message;
|
RakNet::BitStream message;
|
||||||
@ -313,8 +312,6 @@ SkillExecutionResult SkillComponent::CalculateBehavior(const uint32_t skillId, c
|
|||||||
|
|
||||||
context->ExecuteUpdates();
|
context->ExecuteUpdates();
|
||||||
|
|
||||||
delete bitStream;
|
|
||||||
|
|
||||||
// Valid attack
|
// Valid attack
|
||||||
return { true, context->skillTime };
|
return { true, context->skillTime };
|
||||||
}
|
}
|
||||||
@ -424,13 +421,13 @@ void SkillComponent::SyncProjectileCalculation(const ProjectileSyncEntry& entry)
|
|||||||
|
|
||||||
auto* behavior = Behavior::CreateBehavior(behaviorId);
|
auto* behavior = Behavior::CreateBehavior(behaviorId);
|
||||||
|
|
||||||
auto* bitStream = new RakNet::BitStream();
|
RakNet::BitStream bitStream{};
|
||||||
|
|
||||||
behavior->Calculate(entry.context, bitStream, entry.branchContext);
|
behavior->Calculate(entry.context, &bitStream, entry.branchContext);
|
||||||
|
|
||||||
DoClientProjectileImpact projectileImpact;
|
DoClientProjectileImpact projectileImpact;
|
||||||
|
|
||||||
projectileImpact.sBitStream.assign(reinterpret_cast<char*>(bitStream->GetData()), bitStream->GetNumberOfBytesUsed());
|
projectileImpact.sBitStream.assign(reinterpret_cast<char*>(bitStream.GetData()), bitStream.GetNumberOfBytesUsed());
|
||||||
projectileImpact.i64OwnerID = this->m_Parent->GetObjectID();
|
projectileImpact.i64OwnerID = this->m_Parent->GetObjectID();
|
||||||
projectileImpact.i64OrgID = entry.id;
|
projectileImpact.i64OrgID = entry.id;
|
||||||
projectileImpact.i64TargetID = entry.branchContext.target;
|
projectileImpact.i64TargetID = entry.branchContext.target;
|
||||||
@ -444,37 +441,29 @@ void SkillComponent::SyncProjectileCalculation(const ProjectileSyncEntry& entry)
|
|||||||
Game::server->Send(&message, UNASSIGNED_SYSTEM_ADDRESS, true);
|
Game::server->Send(&message, UNASSIGNED_SYSTEM_ADDRESS, true);
|
||||||
|
|
||||||
entry.context->ExecuteUpdates();
|
entry.context->ExecuteUpdates();
|
||||||
|
|
||||||
delete bitStream;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkillComponent::HandleUnmanaged(const uint32_t behaviorId, const LWOOBJID target, LWOOBJID source) {
|
void SkillComponent::HandleUnmanaged(const uint32_t behaviorId, const LWOOBJID target, LWOOBJID source) {
|
||||||
auto* context = new BehaviorContext(source);
|
BehaviorContext context{ source };
|
||||||
|
|
||||||
context->unmanaged = true;
|
context.unmanaged = true;
|
||||||
context->caster = target;
|
context.caster = target;
|
||||||
|
|
||||||
auto* behavior = Behavior::CreateBehavior(behaviorId);
|
auto* behavior = Behavior::CreateBehavior(behaviorId);
|
||||||
|
|
||||||
auto* bitStream = new RakNet::BitStream();
|
RakNet::BitStream bitStream{};
|
||||||
|
|
||||||
behavior->Handle(context, bitStream, { target });
|
behavior->Handle(&context, &bitStream, { target });
|
||||||
|
|
||||||
delete bitStream;
|
|
||||||
|
|
||||||
delete context;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkillComponent::HandleUnCast(const uint32_t behaviorId, const LWOOBJID target) {
|
void SkillComponent::HandleUnCast(const uint32_t behaviorId, const LWOOBJID target) {
|
||||||
auto* context = new BehaviorContext(target);
|
BehaviorContext context{ target };
|
||||||
|
|
||||||
context->caster = target;
|
context.caster = target;
|
||||||
|
|
||||||
auto* behavior = Behavior::CreateBehavior(behaviorId);
|
auto* behavior = Behavior::CreateBehavior(behaviorId);
|
||||||
|
|
||||||
behavior->UnCast(context, { target });
|
behavior->UnCast(&context, { target });
|
||||||
|
|
||||||
delete context;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SkillComponent::SkillComponent(Entity* parent): Component(parent) {
|
SkillComponent::SkillComponent(Entity* parent): Component(parent) {
|
||||||
|
@ -8,6 +8,11 @@
|
|||||||
#include "CDLootMatrixTable.h"
|
#include "CDLootMatrixTable.h"
|
||||||
#include "CDLootTableTable.h"
|
#include "CDLootTableTable.h"
|
||||||
#include "CDItemComponentTable.h"
|
#include "CDItemComponentTable.h"
|
||||||
|
#include "InventoryComponent.h"
|
||||||
|
#include "Character.h"
|
||||||
|
#include "eVendorTransactionResult.h"
|
||||||
|
#include "UserManager.h"
|
||||||
|
#include "CheatDetection.h"
|
||||||
|
|
||||||
VendorComponent::VendorComponent(Entity* parent) : Component(parent) {
|
VendorComponent::VendorComponent(Entity* parent) : Component(parent) {
|
||||||
m_HasStandardCostItems = false;
|
m_HasStandardCostItems = false;
|
||||||
@ -151,3 +156,60 @@ void VendorComponent::HandleMrReeCameras(){
|
|||||||
m_Inventory.push_back(SoldItem(camera, 0));
|
m_Inventory.push_back(SoldItem(camera, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void VendorComponent::Buy(Entity* buyer, LOT lot, uint32_t count) {
|
||||||
|
|
||||||
|
if (!SellsItem(lot)) {
|
||||||
|
auto* user = UserManager::Instance()->GetUser(buyer->GetSystemAddress());
|
||||||
|
CheatDetection::ReportCheat(user, buyer->GetSystemAddress(), "Attempted to buy item %i from achievement vendor %i that is not purchasable", lot, m_Parent->GetLOT());
|
||||||
|
GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_FAIL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* inventoryComponent = buyer->GetComponent<InventoryComponent>();
|
||||||
|
if (!inventoryComponent) {
|
||||||
|
GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_FAIL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CDComponentsRegistryTable* compRegistryTable = CDClientManager::GetTable<CDComponentsRegistryTable>();
|
||||||
|
CDItemComponentTable* itemComponentTable = CDClientManager::GetTable<CDItemComponentTable>();
|
||||||
|
int itemCompID = compRegistryTable->GetByIDAndType(lot, eReplicaComponentType::ITEM);
|
||||||
|
CDItemComponent itemComp = itemComponentTable->GetItemComponentByID(itemCompID);
|
||||||
|
|
||||||
|
// Extra currency that needs to be deducted in case of crafting
|
||||||
|
auto craftingCurrencies = CDItemComponentTable::ParseCraftingCurrencies(itemComp);
|
||||||
|
for (const auto& [crafintCurrencyLOT, crafintCurrencyCount]: craftingCurrencies) {
|
||||||
|
if (inventoryComponent->GetLotCount(crafintCurrencyLOT) < (crafintCurrencyCount * count)) {
|
||||||
|
GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_FAIL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto& [crafintCurrencyLOT, crafintCurrencyCount]: craftingCurrencies) {
|
||||||
|
inventoryComponent->RemoveItem(crafintCurrencyLOT, crafintCurrencyCount * count);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float buyScalar = GetBuyScalar();
|
||||||
|
const auto coinCost = static_cast<uint32_t>(std::floor((itemComp.baseValue * buyScalar) * count));
|
||||||
|
|
||||||
|
Character* character = buyer->GetCharacter();
|
||||||
|
if (!character || character->GetCoins() < coinCost) {
|
||||||
|
GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_FAIL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Inventory::IsValidItem(itemComp.currencyLOT)) {
|
||||||
|
const uint32_t altCurrencyCost = std::floor(itemComp.altCurrencyCost * buyScalar) * count;
|
||||||
|
if (inventoryComponent->GetLotCount(itemComp.currencyLOT) < altCurrencyCost) {
|
||||||
|
GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_FAIL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
inventoryComponent->RemoveItem(itemComp.currencyLOT, altCurrencyCost);
|
||||||
|
}
|
||||||
|
|
||||||
|
character->SetCoins(character->GetCoins() - (coinCost), eLootSourceType::VENDOR);
|
||||||
|
inventoryComponent->AddItem(lot, count, eLootSourceType::VENDOR);
|
||||||
|
GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_SUCCESS);
|
||||||
|
|
||||||
|
}
|
@ -47,6 +47,7 @@ public:
|
|||||||
m_DirtyVendor = true;
|
m_DirtyVendor = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Buy(Entity* buyer, LOT lot, uint32_t count);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetupMaxCustomVendor();
|
void SetupMaxCustomVendor();
|
||||||
|
@ -269,11 +269,9 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System
|
|||||||
auto* skill_component = entity->GetComponent<SkillComponent>();
|
auto* skill_component = entity->GetComponent<SkillComponent>();
|
||||||
|
|
||||||
if (skill_component != nullptr) {
|
if (skill_component != nullptr) {
|
||||||
auto* bs = new RakNet::BitStream(reinterpret_cast<unsigned char*>(const_cast<char*>(message.sBitStream.c_str())), message.sBitStream.size(), false);
|
auto bs = RakNet::BitStream(reinterpret_cast<unsigned char*>(&message.sBitStream[0]), message.sBitStream.size(), false);
|
||||||
|
|
||||||
skill_component->SyncPlayerProjectile(message.i64LocalID, bs, message.i64TargetID);
|
skill_component->SyncPlayerProjectile(message.i64LocalID, &bs, message.i64TargetID);
|
||||||
|
|
||||||
delete bs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -296,18 +294,16 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System
|
|||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
||||||
if (behaviorId > 0) {
|
if (behaviorId > 0) {
|
||||||
RakNet::BitStream* bs = new RakNet::BitStream(reinterpret_cast<unsigned char*>(const_cast<char*>(startSkill.sBitStream.c_str())), startSkill.sBitStream.size(), false);
|
auto bs = RakNet::BitStream(reinterpret_cast<unsigned char*>(&startSkill.sBitStream[0]), startSkill.sBitStream.size(), false);
|
||||||
|
|
||||||
auto* skillComponent = entity->GetComponent<SkillComponent>();
|
auto* skillComponent = entity->GetComponent<SkillComponent>();
|
||||||
|
|
||||||
success = skillComponent->CastPlayerSkill(behaviorId, startSkill.uiSkillHandle, bs, startSkill.optionalTargetID, startSkill.skillID);
|
success = skillComponent->CastPlayerSkill(behaviorId, startSkill.uiSkillHandle, &bs, startSkill.optionalTargetID, startSkill.skillID);
|
||||||
|
|
||||||
if (success && entity->GetCharacter()) {
|
if (success && entity->GetCharacter()) {
|
||||||
DestroyableComponent* destComp = entity->GetComponent<DestroyableComponent>();
|
DestroyableComponent* destComp = entity->GetComponent<DestroyableComponent>();
|
||||||
destComp->SetImagination(destComp->GetImagination() - skillTable->GetSkillByID(startSkill.skillID).imaginationcost);
|
destComp->SetImagination(destComp->GetImagination() - skillTable->GetSkillByID(startSkill.skillID).imaginationcost);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete bs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Game::server->GetZoneID() == 1302) {
|
if (Game::server->GetZoneID() == 1302) {
|
||||||
@ -353,13 +349,11 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (usr != nullptr) {
|
if (usr != nullptr) {
|
||||||
RakNet::BitStream* bs = new RakNet::BitStream(reinterpret_cast<unsigned char*>(const_cast<char*>(sync.sBitStream.c_str())), sync.sBitStream.size(), false);
|
auto bs = RakNet::BitStream(reinterpret_cast<unsigned char*>(&sync.sBitStream[0]), sync.sBitStream.size(), false);
|
||||||
|
|
||||||
auto* skillComponent = entity->GetComponent<SkillComponent>();
|
auto* skillComponent = entity->GetComponent<SkillComponent>();
|
||||||
|
|
||||||
skillComponent->SyncPlayerSkill(sync.uiSkillHandle, sync.uiBehaviorHandle, bs);
|
skillComponent->SyncPlayerSkill(sync.uiSkillHandle, sync.uiBehaviorHandle, &bs);
|
||||||
|
|
||||||
delete bs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EchoSyncSkill echo = EchoSyncSkill();
|
EchoSyncSkill echo = EchoSyncSkill();
|
||||||
|
@ -78,6 +78,7 @@
|
|||||||
#include "LevelProgressionComponent.h"
|
#include "LevelProgressionComponent.h"
|
||||||
#include "DonationVendorComponent.h"
|
#include "DonationVendorComponent.h"
|
||||||
#include "GhostComponent.h"
|
#include "GhostComponent.h"
|
||||||
|
#include "AchievementVendorComponent.h"
|
||||||
|
|
||||||
// Message includes:
|
// Message includes:
|
||||||
#include "dZoneManager.h"
|
#include "dZoneManager.h"
|
||||||
@ -97,6 +98,7 @@
|
|||||||
#include "ePetAbilityType.h"
|
#include "ePetAbilityType.h"
|
||||||
#include "ActivityManager.h"
|
#include "ActivityManager.h"
|
||||||
#include "PlayerManager.h"
|
#include "PlayerManager.h"
|
||||||
|
#include "eVendorTransactionResult.h"
|
||||||
|
|
||||||
#include "CDComponentsRegistryTable.h"
|
#include "CDComponentsRegistryTable.h"
|
||||||
#include "CDObjectsTable.h"
|
#include "CDObjectsTable.h"
|
||||||
@ -1323,15 +1325,14 @@ void GameMessages::SendVendorStatusUpdate(Entity* entity, const SystemAddress& s
|
|||||||
SEND_PACKET;
|
SEND_PACKET;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameMessages::SendVendorTransactionResult(Entity* entity, const SystemAddress& sysAddr) {
|
void GameMessages::SendVendorTransactionResult(Entity* entity, const SystemAddress& sysAddr, eVendorTransactionResult result) {
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
CMSGHEADER;
|
CMSGHEADER;
|
||||||
|
|
||||||
int iResult = 0x02; // success, seems to be the only relevant one
|
|
||||||
|
|
||||||
bitStream.Write(entity->GetObjectID());
|
bitStream.Write(entity->GetObjectID());
|
||||||
bitStream.Write(eGameMessageType::VENDOR_TRANSACTION_RESULT);
|
bitStream.Write(eGameMessageType::VENDOR_TRANSACTION_RESULT);
|
||||||
bitStream.Write(iResult);
|
bitStream.Write(result);
|
||||||
|
|
||||||
SEND_PACKET;
|
SEND_PACKET;
|
||||||
}
|
}
|
||||||
@ -4664,94 +4665,27 @@ void GameMessages::HandleBuyFromVendor(RakNet::BitStream* inStream, Entity* enti
|
|||||||
if (!user) return;
|
if (!user) return;
|
||||||
Entity* player = Game::entityManager->GetEntity(user->GetLoggedInChar());
|
Entity* player = Game::entityManager->GetEntity(user->GetLoggedInChar());
|
||||||
if (!player) return;
|
if (!player) return;
|
||||||
|
|
||||||
|
// handle buying normal items
|
||||||
|
auto* vendorComponent = entity->GetComponent<VendorComponent>();
|
||||||
|
if (vendorComponent) {
|
||||||
|
vendorComponent->Buy(player, item, count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto* propertyVendorComponent = static_cast<PropertyVendorComponent*>(entity->GetComponent(eReplicaComponentType::PROPERTY_VENDOR));
|
// handle buying achievement items
|
||||||
|
auto* achievementVendorComponent = entity->GetComponent<AchievementVendorComponent>();
|
||||||
|
if (achievementVendorComponent) {
|
||||||
|
achievementVendorComponent->Buy(player, item, count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (propertyVendorComponent != nullptr) {
|
// Handle buying properties
|
||||||
|
auto* propertyVendorComponent = entity->GetComponent<PropertyVendorComponent>();
|
||||||
|
if (propertyVendorComponent) {
|
||||||
propertyVendorComponent->OnBuyFromVendor(player, bConfirmed, item, count);
|
propertyVendorComponent->OnBuyFromVendor(player, bConfirmed, item, count);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto isCommendationVendor = entity->GetLOT() == 13806;
|
|
||||||
|
|
||||||
auto* vend = entity->GetComponent<VendorComponent>();
|
|
||||||
if (!vend && !isCommendationVendor) return;
|
|
||||||
|
|
||||||
auto* inv = player->GetComponent<InventoryComponent>();
|
|
||||||
if (!inv) return;
|
|
||||||
|
|
||||||
if (!isCommendationVendor && !vend->SellsItem(item)) {
|
|
||||||
LOG("User %llu %s tried to buy an item %i from a vendor when they do not sell said item", player->GetObjectID(), user->GetUsername().c_str(), item);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CDComponentsRegistryTable* compRegistryTable = CDClientManager::GetTable<CDComponentsRegistryTable>();
|
|
||||||
CDItemComponentTable* itemComponentTable = CDClientManager::GetTable<CDItemComponentTable>();
|
|
||||||
|
|
||||||
int itemCompID = compRegistryTable->GetByIDAndType(item, eReplicaComponentType::ITEM);
|
|
||||||
CDItemComponent itemComp = itemComponentTable->GetItemComponentByID(itemCompID);
|
|
||||||
|
|
||||||
Character* character = player->GetCharacter();
|
|
||||||
if (!character) return;
|
|
||||||
|
|
||||||
// Extra currency that needs to be deducted in case of crafting
|
|
||||||
auto craftingCurrencies = CDItemComponentTable::ParseCraftingCurrencies(itemComp);
|
|
||||||
for (const auto& craftingCurrency : craftingCurrencies) {
|
|
||||||
inv->RemoveItem(craftingCurrency.first, craftingCurrency.second * count);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isCommendationVendor) {
|
|
||||||
if (itemComp.commendationLOT != 13763) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* missionComponent = player->GetComponent<MissionComponent>();
|
|
||||||
|
|
||||||
if (missionComponent == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOT tokenId = -1;
|
|
||||||
|
|
||||||
if (missionComponent->GetMissionState(545) == eMissionState::COMPLETE) tokenId = 8318; // "Assembly Token"
|
|
||||||
if (missionComponent->GetMissionState(556) == eMissionState::COMPLETE) tokenId = 8321; // "Venture League Token"
|
|
||||||
if (missionComponent->GetMissionState(567) == eMissionState::COMPLETE) tokenId = 8319; // "Sentinels Token"
|
|
||||||
if (missionComponent->GetMissionState(578) == eMissionState::COMPLETE) tokenId = 8320; // "Paradox Token"
|
|
||||||
|
|
||||||
const uint32_t altCurrencyCost = itemComp.commendationCost * count;
|
|
||||||
|
|
||||||
if (inv->GetLotCount(tokenId) < altCurrencyCost) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
inv->RemoveItem(tokenId, altCurrencyCost);
|
|
||||||
|
|
||||||
inv->AddItem(item, count, eLootSourceType::VENDOR);
|
|
||||||
} else {
|
|
||||||
float buyScalar = vend->GetBuyScalar();
|
|
||||||
|
|
||||||
const auto coinCost = static_cast<uint32_t>(std::floor((itemComp.baseValue * buyScalar) * count));
|
|
||||||
|
|
||||||
if (character->GetCoins() < coinCost) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Inventory::IsValidItem(itemComp.currencyLOT)) {
|
|
||||||
const uint32_t altCurrencyCost = std::floor(itemComp.altCurrencyCost * buyScalar) * count;
|
|
||||||
|
|
||||||
if (inv->GetLotCount(itemComp.currencyLOT) < altCurrencyCost) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
inv->RemoveItem(itemComp.currencyLOT, altCurrencyCost);
|
|
||||||
}
|
|
||||||
|
|
||||||
character->SetCoins(character->GetCoins() - (coinCost), eLootSourceType::VENDOR);
|
|
||||||
inv->AddItem(item, count, eLootSourceType::VENDOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
GameMessages::SendVendorTransactionResult(entity, sysAddr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameMessages::HandleSellToVendor(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) {
|
void GameMessages::HandleSellToVendor(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) {
|
||||||
@ -4785,7 +4719,10 @@ void GameMessages::HandleSellToVendor(RakNet::BitStream* inStream, Entity* entit
|
|||||||
CDItemComponent itemComp = itemComponentTable->GetItemComponentByID(itemCompID);
|
CDItemComponent itemComp = itemComponentTable->GetItemComponentByID(itemCompID);
|
||||||
|
|
||||||
// Items with a base value of 0 or max int are special items that should not be sold if they're not sub items
|
// Items with a base value of 0 or max int are special items that should not be sold if they're not sub items
|
||||||
if (itemComp.baseValue == 0 || itemComp.baseValue == UINT_MAX) return;
|
if (itemComp.baseValue == 0 || itemComp.baseValue == UINT_MAX) {
|
||||||
|
GameMessages::SendVendorTransactionResult(entity, sysAddr, eVendorTransactionResult::SELL_FAIL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
float sellScalar = vend->GetSellScalar();
|
float sellScalar = vend->GetSellScalar();
|
||||||
if (Inventory::IsValidItem(itemComp.currencyLOT)) {
|
if (Inventory::IsValidItem(itemComp.currencyLOT)) {
|
||||||
@ -4793,11 +4730,9 @@ void GameMessages::HandleSellToVendor(RakNet::BitStream* inStream, Entity* entit
|
|||||||
inv->AddItem(itemComp.currencyLOT, std::floor(altCurrency), eLootSourceType::VENDOR); // Return alt currencies like faction tokens.
|
inv->AddItem(itemComp.currencyLOT, std::floor(altCurrency), eLootSourceType::VENDOR); // Return alt currencies like faction tokens.
|
||||||
}
|
}
|
||||||
|
|
||||||
//inv->RemoveItem(count, -1, iObjID);
|
|
||||||
inv->MoveItemToInventory(item, eInventoryType::VENDOR_BUYBACK, count, true, false, true);
|
inv->MoveItemToInventory(item, eInventoryType::VENDOR_BUYBACK, count, true, false, true);
|
||||||
character->SetCoins(std::floor(character->GetCoins() + (static_cast<uint32_t>(itemComp.baseValue * sellScalar) * count)), eLootSourceType::VENDOR);
|
character->SetCoins(std::floor(character->GetCoins() + (static_cast<uint32_t>(itemComp.baseValue * sellScalar) * count)), eLootSourceType::VENDOR);
|
||||||
//Game::entityManager->SerializeEntity(player); // so inventory updates
|
GameMessages::SendVendorTransactionResult(entity, sysAddr, eVendorTransactionResult::SELL_SUCCESS);
|
||||||
GameMessages::SendVendorTransactionResult(entity, sysAddr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameMessages::HandleBuybackFromVendor(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) {
|
void GameMessages::HandleBuybackFromVendor(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) {
|
||||||
@ -4839,16 +4774,16 @@ void GameMessages::HandleBuybackFromVendor(RakNet::BitStream* inStream, Entity*
|
|||||||
const auto cost = static_cast<uint32_t>(std::floor(((itemComp.baseValue * sellScalar) * count)));
|
const auto cost = static_cast<uint32_t>(std::floor(((itemComp.baseValue * sellScalar) * count)));
|
||||||
|
|
||||||
if (character->GetCoins() < cost) {
|
if (character->GetCoins() < cost) {
|
||||||
|
GameMessages::SendVendorTransactionResult(entity, sysAddr, eVendorTransactionResult::PURCHASE_FAIL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Inventory::IsValidItem(itemComp.currencyLOT)) {
|
if (Inventory::IsValidItem(itemComp.currencyLOT)) {
|
||||||
const uint32_t altCurrencyCost = std::floor(itemComp.altCurrencyCost * sellScalar) * count;
|
const uint32_t altCurrencyCost = std::floor(itemComp.altCurrencyCost * sellScalar) * count;
|
||||||
|
|
||||||
if (inv->GetLotCount(itemComp.currencyLOT) < altCurrencyCost) {
|
if (inv->GetLotCount(itemComp.currencyLOT) < altCurrencyCost) {
|
||||||
|
GameMessages::SendVendorTransactionResult(entity, sysAddr, eVendorTransactionResult::PURCHASE_FAIL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
inv->RemoveItem(itemComp.currencyLOT, altCurrencyCost);
|
inv->RemoveItem(itemComp.currencyLOT, altCurrencyCost);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4856,7 +4791,7 @@ void GameMessages::HandleBuybackFromVendor(RakNet::BitStream* inStream, Entity*
|
|||||||
inv->MoveItemToInventory(item, Inventory::FindInventoryTypeForLot(item->GetLot()), count, true, false);
|
inv->MoveItemToInventory(item, Inventory::FindInventoryTypeForLot(item->GetLot()), count, true, false);
|
||||||
character->SetCoins(character->GetCoins() - cost, eLootSourceType::VENDOR);
|
character->SetCoins(character->GetCoins() - cost, eLootSourceType::VENDOR);
|
||||||
//Game::entityManager->SerializeEntity(player); // so inventory updates
|
//Game::entityManager->SerializeEntity(player); // so inventory updates
|
||||||
GameMessages::SendVendorTransactionResult(entity, sysAddr);
|
GameMessages::SendVendorTransactionResult(entity, sysAddr, eVendorTransactionResult::PURCHASE_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameMessages::HandleParseChatMessage(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) {
|
void GameMessages::HandleParseChatMessage(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) {
|
||||||
|
@ -38,6 +38,7 @@ enum class eUseItemResponse : uint32_t;
|
|||||||
enum class eQuickBuildFailReason : uint32_t;
|
enum class eQuickBuildFailReason : uint32_t;
|
||||||
enum class eQuickBuildState : uint32_t;
|
enum class eQuickBuildState : uint32_t;
|
||||||
enum class BehaviorSlot : int32_t;
|
enum class BehaviorSlot : int32_t;
|
||||||
|
enum class eVendorTransactionResult : uint32_t;
|
||||||
|
|
||||||
namespace GameMessages {
|
namespace GameMessages {
|
||||||
class PropertyDataMessage;
|
class PropertyDataMessage;
|
||||||
@ -135,7 +136,7 @@ namespace GameMessages {
|
|||||||
|
|
||||||
void SendVendorOpenWindow(Entity* entity, const SystemAddress& sysAddr);
|
void SendVendorOpenWindow(Entity* entity, const SystemAddress& sysAddr);
|
||||||
void SendVendorStatusUpdate(Entity* entity, const SystemAddress& sysAddr, bool bUpdateOnly = false);
|
void SendVendorStatusUpdate(Entity* entity, const SystemAddress& sysAddr, bool bUpdateOnly = false);
|
||||||
void SendVendorTransactionResult(Entity* entity, const SystemAddress& sysAddr);
|
void SendVendorTransactionResult(Entity* entity, const SystemAddress& sysAddr, eVendorTransactionResult result);
|
||||||
|
|
||||||
void SendRemoveItemFromInventory(Entity* entity, const SystemAddress& sysAddr, LWOOBJID iObjID, LOT templateID, int inventoryType, uint32_t stackCount, uint32_t stackRemaining);
|
void SendRemoveItemFromInventory(Entity* entity, const SystemAddress& sysAddr, LWOOBJID iObjID, LOT templateID, int inventoryType, uint32_t stackCount, uint32_t stackRemaining);
|
||||||
void SendConsumeClientItem(Entity* entity, bool bSuccess, LWOOBJID item);
|
void SendConsumeClientItem(Entity* entity, bool bSuccess, LWOOBJID item);
|
||||||
|
@ -22,143 +22,13 @@
|
|||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
std::vector<VanityNPC> VanityUtilities::m_NPCs = {};
|
std::vector<VanityObject> VanityUtilities::m_Objects = {};
|
||||||
std::vector<VanityParty> VanityUtilities::m_Parties = {};
|
std::set<std::string> VanityUtilities::m_LoadedFiles = {};
|
||||||
std::vector<std::string> VanityUtilities::m_PartyPhrases = {};
|
|
||||||
|
|
||||||
void VanityUtilities::SpawnVanity() {
|
void VanityUtilities::SpawnVanity() {
|
||||||
if (Game::config->GetValue("disable_vanity") == "1") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint32_t zoneID = Game::server->GetZoneID();
|
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) {
|
if (zoneID == 1200) {
|
||||||
{
|
{
|
||||||
EntityInfo info;
|
EntityInfo info;
|
||||||
@ -175,38 +45,99 @@ void VanityUtilities::SpawnVanity() {
|
|||||||
Game::entityManager->ConstructEntity(entity);
|
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;
|
SceneObject obj;
|
||||||
obj.lot = lot;
|
obj.lot = object.m_LOT;
|
||||||
// guratantee we have no collisions
|
// guratantee we have no collisions
|
||||||
do {
|
do {
|
||||||
obj.id = ObjectIDManager::GenerateObjectID();
|
obj.id = ObjectIDManager::GenerateObjectID();
|
||||||
} while(Game::zoneManager->GetSpawner(obj.id));
|
} while(Game::zoneManager->GetSpawner(obj.id));
|
||||||
obj.position = position;
|
obj.position = location.m_Position;
|
||||||
obj.rotation = rotation;
|
obj.rotation = location.m_Rotation;
|
||||||
obj.settings = ldf;
|
obj.settings = object.m_Config;
|
||||||
Level::MakeSpawner(obj);
|
Level::MakeSpawner(obj);
|
||||||
return obj.id;
|
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;
|
EntityInfo info;
|
||||||
info.lot = lot;
|
info.lot = object.m_LOT;
|
||||||
info.pos = position;
|
info.pos = location.m_Position;
|
||||||
info.rot = rotation;
|
info.rot = location.m_Rotation;
|
||||||
|
info.scale = location.m_Scale;
|
||||||
info.spawnerID = Game::entityManager->GetZoneControlEntity()->GetObjectID();
|
info.spawnerID = Game::entityManager->GetZoneControlEntity()->GetObjectID();
|
||||||
info.settings = ldf;
|
info.settings = object.m_Config;
|
||||||
|
|
||||||
auto* entity = Game::entityManager->CreateEntity(info);
|
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);
|
if (entity->GetVar<bool>(u"noGhosting")) entity->SetIsGhostingCandidate(false);
|
||||||
|
|
||||||
auto* inventoryComponent = entity->GetComponent<InventoryComponent>();
|
auto* inventoryComponent = entity->GetComponent<InventoryComponent>();
|
||||||
|
|
||||||
if (inventoryComponent && !inventory.empty()) {
|
if (inventoryComponent && !object.m_Equipment.empty()) {
|
||||||
inventoryComponent->SetNPCItems(inventory);
|
inventoryComponent->SetNPCItems(object.m_Equipment);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
|
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) {
|
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
|
// Read the entire file
|
||||||
std::ifstream xmlFile(file);
|
std::ifstream xmlFile(file);
|
||||||
std::string xml((std::istreambuf_iterator<char>(xmlFile)), std::istreambuf_iterator<char>());
|
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;
|
tinyxml2::XMLDocument doc;
|
||||||
doc.Parse(xml.c_str(), xml.size());
|
doc.Parse(xml.c_str(), xml.size());
|
||||||
|
|
||||||
// Read the NPCs
|
// Read the objects
|
||||||
auto* npcs = doc.FirstChildElement("npcs");
|
auto* files = doc.FirstChildElement("files");
|
||||||
|
if (files) {
|
||||||
if (npcs == nullptr) {
|
for (auto* file = files->FirstChildElement("file"); file != nullptr; file = file->NextSiblingElement("file")) {
|
||||||
LOG("Failed to parse NPCs");
|
std::string enabled = file->Attribute("enabled");
|
||||||
return;
|
std::string filename = file->Attribute("name");
|
||||||
}
|
if (enabled != "1") {
|
||||||
|
|
||||||
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");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
ParseXML((BinaryPathFinder::GetBinaryDir() / "vanity" / filename).string());
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto* npc = npcs->FirstChildElement("npc"); npc != nullptr; npc = npc->NextSiblingElement("npc")) {
|
// Read the objects
|
||||||
// Get the NPC name
|
auto* objects = doc.FirstChildElement("objects");
|
||||||
auto* name = npc->Attribute("name");
|
|
||||||
|
|
||||||
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
|
if (!name) name = "";
|
||||||
auto* lot = npc->Attribute("lot");
|
|
||||||
|
|
||||||
if (lot == nullptr) {
|
// Get the NPC lot
|
||||||
LOG("Failed to parse NPC lot");
|
auto* lot = object->Attribute("lot");
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the equipment
|
if (lot == nullptr) {
|
||||||
auto* equipment = npc->FirstChildElement("equipment");
|
LOG("Failed to parse object lot");
|
||||||
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");
|
|
||||||
continue;
|
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
|
// Get the locations
|
||||||
auto* locations = zone->FirstChildElement("locations");
|
auto* locations = object->FirstChildElement("locations");
|
||||||
|
|
||||||
if (locations == nullptr) {
|
if (locations == nullptr) {
|
||||||
LOG("Failed to parse NPC locations");
|
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;
|
for (auto* location = locations->FirstChildElement("location"); location != nullptr;
|
||||||
location = location->NextSiblingElement("location")) {
|
location = location->NextSiblingElement("location")) {
|
||||||
|
|
||||||
// Get the location data
|
// Get the location data
|
||||||
|
auto* zoneID = location->Attribute("zone");
|
||||||
auto* x = location->Attribute("x");
|
auto* x = location->Attribute("x");
|
||||||
auto* y = location->Attribute("y");
|
auto* y = location->Attribute("y");
|
||||||
auto* z = location->Attribute("z");
|
auto* z = location->Attribute("z");
|
||||||
@ -452,41 +292,52 @@ void VanityUtilities::ParseXML(const std::string& file) {
|
|||||||
auto* ry = location->Attribute("ry");
|
auto* ry = location->Attribute("ry");
|
||||||
auto* rz = location->Attribute("rz");
|
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) {
|
|| rz == nullptr) {
|
||||||
LOG("Failed to parse NPC location data");
|
LOG("Failed to parse NPC location data");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
VanityNPCLocation locationData;
|
VanityObjectLocation locationData;
|
||||||
locationData.m_Position = { std::stof(x), std::stof(y), std::stof(z) };
|
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_Rotation = { std::stof(rw), std::stof(rx), std::stof(ry), std::stof(rz) };
|
||||||
locationData.m_Chance = 1.0f;
|
locationData.m_Chance = 1.0f;
|
||||||
|
|
||||||
if (location->Attribute("chance") != nullptr) {
|
if (location->Attribute("chance")) {
|
||||||
locationData.m_Chance = std::stof(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);
|
it->second.push_back(locationData);
|
||||||
} else {
|
} else {
|
||||||
std::vector<VanityNPCLocation> locations;
|
std::vector<VanityObjectLocation> locations;
|
||||||
locations.push_back(locationData);
|
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) {
|
VanityObject* VanityUtilities::GetObject(const std::string& name) {
|
||||||
for (size_t i = 0; i < m_NPCs.size(); i++) {
|
for (size_t i = 0; i < m_Objects.size(); i++) {
|
||||||
if (m_NPCs[i].m_Name == name) {
|
if (m_Objects[i].m_Name == name) {
|
||||||
return &m_NPCs[i];
|
return &m_Objects[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -498,10 +349,13 @@ std::string VanityUtilities::ParseMarkdown(const std::string& file) {
|
|||||||
|
|
||||||
// Read the file into a string
|
// Read the file into a string
|
||||||
std::ifstream t(file);
|
std::ifstream t(file);
|
||||||
|
std::stringstream output;
|
||||||
// If the file does not exist, return an empty string.
|
// If the file does not exist, return an empty string.
|
||||||
if (!t.good()) {
|
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;
|
std::stringstream buffer;
|
||||||
@ -511,7 +365,6 @@ std::string VanityUtilities::ParseMarkdown(const std::string& file) {
|
|||||||
// Loop through all lines in the file.
|
// Loop through all lines in the file.
|
||||||
// Replace all instances of the markdown syntax with the corresponding HTML.
|
// Replace all instances of the markdown syntax with the corresponding HTML.
|
||||||
// Only care about headers
|
// Only care about headers
|
||||||
std::stringstream output;
|
|
||||||
std::string line;
|
std::string line;
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << fileContents;
|
ss << fileContents;
|
||||||
|
@ -3,15 +3,17 @@
|
|||||||
#include "dCommonVars.h"
|
#include "dCommonVars.h"
|
||||||
#include "Entity.h"
|
#include "Entity.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
struct VanityNPCLocation
|
struct VanityObjectLocation
|
||||||
{
|
{
|
||||||
float m_Chance = 1.0f;
|
float m_Chance = 1.0f;
|
||||||
NiPoint3 m_Position;
|
NiPoint3 m_Position;
|
||||||
NiQuaternion m_Rotation;
|
NiQuaternion m_Rotation;
|
||||||
|
float m_Scale = 1.0f;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VanityNPC
|
struct VanityObject
|
||||||
{
|
{
|
||||||
LWOOBJID m_ID = LWOOBJID_EMPTY;
|
LWOOBJID m_ID = LWOOBJID_EMPTY;
|
||||||
std::string m_Name;
|
std::string m_Name;
|
||||||
@ -19,37 +21,24 @@ struct VanityNPC
|
|||||||
std::vector<LOT> m_Equipment;
|
std::vector<LOT> m_Equipment;
|
||||||
std::vector<std::string> m_Phrases;
|
std::vector<std::string> m_Phrases;
|
||||||
std::string m_Script;
|
std::string m_Script;
|
||||||
std::map<std::string, bool> m_Flags;
|
std::map<uint32_t, std::vector<VanityObjectLocation>> m_Locations;
|
||||||
std::map<uint32_t, std::vector<VanityNPCLocation>> m_Locations;
|
std::vector<LDFBaseData*> m_Config;
|
||||||
std::vector<LDFBaseData*> ldf;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VanityParty
|
|
||||||
{
|
|
||||||
uint32_t m_Zone;
|
|
||||||
float m_Chance = 1.0f;
|
|
||||||
std::vector<VanityNPCLocation> m_Locations;
|
|
||||||
};
|
|
||||||
|
|
||||||
class VanityUtilities
|
class VanityUtilities
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void SpawnVanity();
|
static void SpawnVanity();
|
||||||
|
|
||||||
static Entity* SpawnNPC(
|
static Entity* SpawnObject(
|
||||||
LOT lot,
|
const VanityObject& object,
|
||||||
const std::string& name,
|
const VanityObjectLocation& location
|
||||||
const NiPoint3& position,
|
|
||||||
const NiQuaternion& rotation,
|
|
||||||
const std::vector<LOT>& inventory,
|
|
||||||
const std::vector<LDFBaseData*>& ldf
|
|
||||||
);
|
);
|
||||||
|
|
||||||
static LWOOBJID SpawnSpawner(
|
static LWOOBJID SpawnSpawner(
|
||||||
LOT lot,
|
const VanityObject& object,
|
||||||
const NiPoint3& position,
|
const VanityObjectLocation& location
|
||||||
const NiQuaternion& rotation,
|
|
||||||
const std::vector<LDFBaseData*>& ldf
|
|
||||||
);
|
);
|
||||||
|
|
||||||
static std::string ParseMarkdown(
|
static std::string ParseMarkdown(
|
||||||
@ -60,16 +49,14 @@ public:
|
|||||||
const std::string& file
|
const std::string& file
|
||||||
);
|
);
|
||||||
|
|
||||||
static VanityNPC* GetNPC(const std::string& name);
|
static VanityObject* GetObject(const std::string& name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void SetupNPCTalk(Entity* npc);
|
static void SetupNPCTalk(Entity* npc);
|
||||||
|
|
||||||
static void NPCTalk(Entity* npc);
|
static void NPCTalk(Entity* npc);
|
||||||
|
|
||||||
static std::vector<VanityNPC> m_NPCs;
|
static std::vector<VanityObject> m_Objects;
|
||||||
|
|
||||||
static std::vector<VanityParty> m_Parties;
|
static std::set<std::string> m_LoadedFiles;
|
||||||
|
|
||||||
static std::vector<std::string> m_PartyPhrases;
|
|
||||||
};
|
};
|
||||||
|
@ -82,7 +82,7 @@ void AuthPackets::SendHandshake(dServer* server, const SystemAddress& sysAddr, c
|
|||||||
if (serverType == ServerType::Auth) bitStream.Write(ServiceId::Auth);
|
if (serverType == ServerType::Auth) bitStream.Write(ServiceId::Auth);
|
||||||
else if (serverType == ServerType::World) bitStream.Write(ServiceId::World);
|
else if (serverType == ServerType::World) bitStream.Write(ServiceId::World);
|
||||||
else bitStream.Write(ServiceId::General);
|
else bitStream.Write(ServiceId::General);
|
||||||
bitStream.Write<uint32_t>(774909490);
|
bitStream.Write<uint64_t>(215523405360);
|
||||||
|
|
||||||
server->Send(&bitStream, sysAddr, false);
|
server->Send(&bitStream, sysAddr, false);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
set(DSCRIPTS_SOURCES_02_SERVER_DLU
|
set(DSCRIPTS_SOURCES_02_SERVER_DLU
|
||||||
"DLUVanityNPC.cpp"
|
"DLUVanityTeleportingObject.cpp"
|
||||||
PARENT_SCOPE)
|
PARENT_SCOPE)
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
#include "DLUVanityNPC.h"
|
#include "DLUVanityTeleportingObject.h"
|
||||||
#include "GameMessages.h"
|
#include "GameMessages.h"
|
||||||
#include "dServer.h"
|
#include "dServer.h"
|
||||||
#include "VanityUtilities.h"
|
#include "VanityUtilities.h"
|
||||||
#include "RenderComponent.h"
|
#include "RenderComponent.h"
|
||||||
|
|
||||||
void DLUVanityNPC::OnStartup(Entity* self) {
|
void DLUVanityTeleportingObject::OnStartup(Entity* self) {
|
||||||
m_NPC = VanityUtilities::GetNPC("averysumner - Destroyer of Worlds");
|
if (!self->HasVar(u"npcName") || !self->HasVar(u"teleport")) return;
|
||||||
|
m_Object = VanityUtilities::GetObject(self->GetVarAsString(u"npcName"));
|
||||||
|
|
||||||
if (m_NPC == nullptr) {
|
if (!m_Object) return;
|
||||||
return;
|
if (self->HasVar(u"teleportInterval")) m_TeleportInterval = self->GetVar<float>(u"teleportInterval");
|
||||||
}
|
|
||||||
|
|
||||||
if (self->GetVar<bool>(u"teleport")) {
|
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") {
|
if (timerName == "setupTeleport") {
|
||||||
RenderComponent::PlayAnimation(self, u"interact");
|
RenderComponent::PlayAnimation(self, u"interact");
|
||||||
GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportBeam", "teleportBeam");
|
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, "teleportBeam");
|
||||||
GameMessages::SendStopFXEffect(self, true, "teleportRings");
|
GameMessages::SendStopFXEffect(self, true, "teleportRings");
|
||||||
} else if (timerName == "teleport") {
|
} 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:
|
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) {
|
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->SetPosition(newLocation.m_Position);
|
||||||
self->SetRotation(newLocation.m_Rotation);
|
self->SetRotation(newLocation.m_Rotation);
|
||||||
|
self->SetScale(newLocation.m_Scale);
|
||||||
GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportBeam", "teleportBeam");
|
GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportBeam", "teleportBeam");
|
||||||
GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportRings", "teleportRings");
|
GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportRings", "teleportRings");
|
||||||
self->AddTimer("stopFX", 2.0f);
|
self->AddTimer("stopFX", 2.0f);
|
||||||
self->AddTimer("setupTeleport", 15.0f);
|
self->AddTimer("setupTeleport", m_TeleportInterval);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,13 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "CppScripts.h"
|
#include "CppScripts.h"
|
||||||
|
|
||||||
class VanityNPC;
|
class VanityObject;
|
||||||
class DLUVanityNPC : public CppScripts::Script
|
class DLUVanityTeleportingObject : public CppScripts::Script
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void OnStartup(Entity* self) override;
|
void OnStartup(Entity* self) override;
|
||||||
void OnTimerDone(Entity* self, std::string timerName) override;
|
void OnTimerDone(Entity* self, std::string timerName) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VanityNPC* m_NPC;
|
VanityObject* m_Object;
|
||||||
|
float m_TeleportInterval = 15.0f;
|
||||||
};
|
};
|
@ -216,7 +216,7 @@
|
|||||||
#include "NtNaomiBreadcrumbServer.h"
|
#include "NtNaomiBreadcrumbServer.h"
|
||||||
|
|
||||||
// DLU Scripts
|
// DLU Scripts
|
||||||
#include "DLUVanityNPC.h"
|
#include "DLUVanityTeleportingObject.h"
|
||||||
|
|
||||||
// AM Scripts
|
// AM Scripts
|
||||||
#include "AmConsoleTeleportServer.h"
|
#include "AmConsoleTeleportServer.h"
|
||||||
@ -839,8 +839,8 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr
|
|||||||
script = new NjNyaMissionitems();
|
script = new NjNyaMissionitems();
|
||||||
|
|
||||||
//DLU:
|
//DLU:
|
||||||
else if (scriptName == "scripts\\02_server\\DLU\\DLUVanityNPC.lua")
|
else if (scriptName == "scripts\\02_server\\DLU\\DLUVanityTeleportingObject.lua")
|
||||||
script = new DLUVanityNPC();
|
script = new DLUVanityTeleportingObject();
|
||||||
|
|
||||||
// Survival minigame
|
// Survival minigame
|
||||||
else if (scriptName == "scripts\\02_server\\Enemy\\Survival\\L_AG_SURVIVAL_STROMBIE.lua")
|
else if (scriptName == "scripts\\02_server\\Enemy\\Survival\\L_AG_SURVIVAL_STROMBIE.lua")
|
||||||
|
@ -200,9 +200,6 @@ void Level::ReadFileInfoChunk(std::istream& file, Header& header) {
|
|||||||
BinaryIO::BinaryRead(file, header.fileInfo.enviromentChunkStart);
|
BinaryIO::BinaryRead(file, header.fileInfo.enviromentChunkStart);
|
||||||
BinaryIO::BinaryRead(file, header.fileInfo.objectChunkStart);
|
BinaryIO::BinaryRead(file, header.fileInfo.objectChunkStart);
|
||||||
BinaryIO::BinaryRead(file, header.fileInfo.particleChunkStart);
|
BinaryIO::BinaryRead(file, header.fileInfo.particleChunkStart);
|
||||||
|
|
||||||
//PATCH FOR AG: (messed up file?)
|
|
||||||
if (header.fileInfo.revision == 0xCDCDCDCD && m_ParentZone->GetZoneID().GetMapID() == 1100) header.fileInfo.revision = 26;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Level::ReadSceneObjectDataChunk(std::istream& file, Header& header) {
|
void Level::ReadSceneObjectDataChunk(std::istream& file, Header& header) {
|
||||||
|
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>
|
<objects>
|
||||||
<npc name="Wincent - Developer" lot="2279">
|
<object name="Wincent - Developer" lot="2279">
|
||||||
<equipment>6802, 2519, 2623, 14806</equipment>
|
<equipment>6802, 2519, 2623, 14806</equipment>
|
||||||
<phrases>
|
<phrases>
|
||||||
<phrase>Sorry for the mess.</phrase>
|
<phrase>Sorry for the mess.</phrase>
|
||||||
@ -11,39 +11,33 @@
|
|||||||
<phrase>Everything is awesome!</phrase>
|
<phrase>Everything is awesome!</phrase>
|
||||||
<phrase>I hope my behaviors are behaving themselves.</phrase>
|
<phrase>I hope my behaviors are behaving themselves.</phrase>
|
||||||
</phrases>
|
</phrases>
|
||||||
<zone id="1200">
|
<locations>
|
||||||
<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" />
|
||||||
<location x="-352.5" y="287.6" z="217.7" rw="-0.095" rx="0.0" ry="0.995" rz="0.0" />
|
</locations>
|
||||||
</locations>
|
</object>
|
||||||
</zone>
|
<object name="EmosewaMC - Quickbuilder" lot="6738">
|
||||||
</npc>
|
|
||||||
<npc name="EmosewaMC - Quickbuilder" lot="6738">
|
|
||||||
<equipment>12947, 12949, 12962, 12963</equipment>
|
<equipment>12947, 12949, 12962, 12963</equipment>
|
||||||
<phrases>
|
<phrases>
|
||||||
<phrase>I hope quickbulds are still working!</phrase>
|
<phrase>I hope quickbulds are still working!</phrase>
|
||||||
<phrase>Be careful crossing the gap!</phrase>
|
<phrase>Be careful crossing the gap!</phrase>
|
||||||
<phrase>Have The Maelstrom stopped going invisible?</phrase>
|
<phrase>Have The Maelstrom stopped going invisible?</phrase>
|
||||||
</phrases>
|
</phrases>
|
||||||
<zone id="1800">
|
<locations>
|
||||||
<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" />
|
||||||
<location x="745.756" y="75.262" z="-207.989" rw="0.838565" rx="0.0" ry="0.544801" rz="0.0" />
|
</locations>
|
||||||
</locations>
|
</object>
|
||||||
</zone>
|
<object name="Neal - Paradox Scout" lot="6738">
|
||||||
</npc>
|
|
||||||
<npc name="Neal - Paradox Scout" lot="6738">
|
|
||||||
<equipment>9950, 9944, 14102, 14092</equipment>
|
<equipment>9950, 9944, 14102, 14092</equipment>
|
||||||
<phrases>
|
<phrases>
|
||||||
<phrase>Hello Explorer! It's great to see you made it!</phrase>
|
<phrase>Hello Explorer! It's great to see you made it!</phrase>
|
||||||
<phrase>Have you heard about Darkflame?</phrase>
|
<phrase>Have you heard about Darkflame?</phrase>
|
||||||
<phrase>I've traveled across this entire system, but nothing beats the view here.</phrase>
|
<phrase>I've traveled across this entire system, but nothing beats the view here.</phrase>
|
||||||
</phrases>
|
</phrases>
|
||||||
<zone id="1200">
|
<locations>
|
||||||
<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" />
|
||||||
<location x="163.835" y="330.756" z="-141.933" rw="0.774887" rx="0.0" ry="-0.6321" rz="0.0" />
|
</locations>
|
||||||
</locations>
|
</object>
|
||||||
</zone>
|
<object name="averysumner - Destroyer of Worlds" lot="11235">
|
||||||
</npc>
|
|
||||||
<npc name="averysumner - Destroyer of Worlds" lot="11235">
|
|
||||||
<equipment></equipment>
|
<equipment></equipment>
|
||||||
<phrases>
|
<phrases>
|
||||||
<phrase>cmerw[acowipaejio;fawjioefasdl;kfjm;</phrase>
|
<phrase>cmerw[acowipaejio;fawjioefasdl;kfjm;</phrase>
|
||||||
@ -51,20 +45,18 @@
|
|||||||
<phrase>zxnpoasdfiopwemsadf'kawpfo[ekasdf;'s</phrase>
|
<phrase>zxnpoasdfiopwemsadf'kawpfo[ekasdf;'s</phrase>
|
||||||
<phrase>*teleports behind you*</phrase>
|
<phrase>*teleports behind you*</phrase>
|
||||||
</phrases>
|
</phrases>
|
||||||
<script name="scripts\02_server\DLU\DLUVanityNPC.lua" />
|
<script name="scripts\02_server\DLU\DLUVanityTeleportingObject.lua" />
|
||||||
<flags>
|
<config>
|
||||||
<flag name="teleport" value="1" />
|
<key data="teleport=7:1" />
|
||||||
</flags>
|
<key data="teleportInterval=3:3.0" />
|
||||||
<zone id="1200">
|
</config>
|
||||||
<locations>
|
<locations>
|
||||||
<location 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="-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 zone="1200" 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 zone="1200" x="389.093" y="295.119" z="-647.583" rw="0.851229" rx="0.0" ry="-0.524795" 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>
|
||||||
</locations>
|
</object>
|
||||||
</zone>
|
<object name="NinjaOfLU - Resident Physicist" lot="12260">
|
||||||
</npc>
|
|
||||||
<npc name="NinjaOfLU - Resident Physicist" lot="12260">
|
|
||||||
<equipment>4360, 2523, 5659, 10067</equipment>
|
<equipment>4360, 2523, 5659, 10067</equipment>
|
||||||
<phrases>
|
<phrases>
|
||||||
<phrase>Congratulations! I don't see too many people around here!</phrase>
|
<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>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>
|
<phrase>Of what has one to be proud, if dnot one's friends?</phrase>
|
||||||
</phrases>
|
</phrases>
|
||||||
<zone id="1100">
|
<locations>
|
||||||
<locations>
|
<location zone="1100" x="287" y="451" z="-98" rw="-0.320221" rx="0" ry="0.947343" rz="0" />
|
||||||
<location x="287" y="451" z="-98" rw="-0.320221" rx="0" ry="0.947343" rz="0" />
|
</locations>
|
||||||
</locations>
|
<locations>
|
||||||
</zone>
|
<location zone="1800" x="798" y="93" z="325" rw="-0.095" rx="0.0" ry="0.995" rz="0.0" />
|
||||||
<zone id="1800">
|
</locations>
|
||||||
<locations>
|
</object>
|
||||||
<location x="798" y="93" z="325" rw="-0.095" rx="0.0" ry="0.995" rz="0.0" />
|
<object name="BlasterBuilder - Race Ace" lot="8205">
|
||||||
</locations>
|
|
||||||
</zone>
|
|
||||||
</npc>
|
|
||||||
<npc name="BlasterBuilder - Race Ace" lot="8205">
|
|
||||||
<equipment>14098, 8539, 14096, 14092</equipment>
|
<equipment>14098, 8539, 14096, 14092</equipment>
|
||||||
<phrases>
|
<phrases>
|
||||||
<phrase>LEGO Universe... LEGO Universe... LEGO Universe... LEGO Universe...</phrase>
|
<phrase>LEGO Universe... LEGO Universe... LEGO Universe... LEGO Universe...</phrase>
|
||||||
@ -112,14 +100,12 @@
|
|||||||
<phrase>Gather uh banana</phrase>
|
<phrase>Gather uh banana</phrase>
|
||||||
<phrase>I've done nothing all day. Why am I here?</phrase>
|
<phrase>I've done nothing all day. Why am I here?</phrase>
|
||||||
</phrases>
|
</phrases>
|
||||||
<zone id="1100">
|
<locations>
|
||||||
<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" />
|
||||||
<location x="444.318" y="421.154" z="54.4241" rw="0.877539" rx="0.0" ry="0.479506" rz="0.0" />
|
</locations>
|
||||||
</locations>
|
</object>
|
||||||
</zone>
|
|
||||||
</npc>
|
|
||||||
<!-- Mick - Brick Market Broker -->
|
<!-- 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>
|
<equipment>2519, 4091, 5128, 7990</equipment>
|
||||||
<phrases>
|
<phrases>
|
||||||
<phrase>Still can't believe we made it through that 2012 recession.</phrase>
|
<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>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>
|
<phrase>You know Dr. Overbuild? He keeps ignoring my calls.</phrase>
|
||||||
</phrases>
|
</phrases>
|
||||||
<zone id="1100">
|
<locations>
|
||||||
<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" />
|
||||||
<location x="449.725" y="414.926" z="180.539" rw="0.180645" rx="0.0" ry="0.983548" rz="0.0" />
|
</locations>
|
||||||
</locations>
|
</object>
|
||||||
</zone>
|
|
||||||
</npc>
|
|
||||||
<!-- Knightoffaith - Sage of Wanderlust -->
|
<!-- 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>
|
<equipment>7359, 7368, 7380, 7392, 7403, 8456</equipment>
|
||||||
<phrases>
|
<phrases>
|
||||||
<phrase>Come and join me - take a look at the beauty that still remains even amidst the chaos</phrase>
|
<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>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>
|
<phrase>The Universe is beautiful - take some time to enjoy it</phrase>
|
||||||
</phrases>
|
</phrases>
|
||||||
<zone id="1100">
|
<locations>
|
||||||
<locations>
|
<location zone="1100" x="-381.053" y="367.787" z="-60.1185" rw="-0.14307" rx="0" ry="0.989713" rz="0" />
|
||||||
<location x="-381.053" y="367.787" z="-60.1185" rw="-0.14307" rx="0" ry="0.989713" rz="0" />
|
</locations>
|
||||||
</locations>
|
</object>
|
||||||
</zone>
|
<object name="Snifflegully - DLU Alpha Tester" lot="2281">
|
||||||
</npc>
|
|
||||||
<npc name="Snifflegully - DLU Alpha Tester" lot="2281">
|
|
||||||
<equipment>15975, 7492, 12690, 12472</equipment>
|
<equipment>15975, 7492, 12690, 12472</equipment>
|
||||||
<phrases>
|
<phrases>
|
||||||
<phrase>Praise the cube!</phrase>
|
<phrase>Praise the cube!</phrase>
|
||||||
@ -173,13 +155,11 @@
|
|||||||
<phrase>Hope you enjoy DLU as much as I have, explorer!</phrase>
|
<phrase>Hope you enjoy DLU as much as I have, explorer!</phrase>
|
||||||
<phrase>There are many more memories still to be made.</phrase>
|
<phrase>There are many more memories still to be made.</phrase>
|
||||||
</phrases>
|
</phrases>
|
||||||
<zone id="1200">
|
<locations>
|
||||||
<locations>
|
<location zone="1200" x="-429.296" y="291.058" z="212.918" rw="0.339487" rx="0" ry="0.940611" rz="0" />
|
||||||
<location x="-429.296" y="291.058" z="212.918" rw="0.339487" rx="0" ry="0.940611" rz="0" />
|
</locations>
|
||||||
</locations>
|
</object>
|
||||||
</zone>
|
<object name="Hollis - Master Builder" lot="9893">
|
||||||
</npc>
|
|
||||||
<npc name="Hollis - Master Builder" lot="9893">
|
|
||||||
<equipment>4465, 2517, 6855, 8532, 9615</equipment>
|
<equipment>4465, 2517, 6855, 8532, 9615</equipment>
|
||||||
<phrases>
|
<phrases>
|
||||||
<phrase>Visit Starbase 3001 and blast off to the awesome worlds built by the World Builder League!</phrase>
|
<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>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>
|
<phrase>Don't stop believing! Uhh, I mean building. Don't stop building!</phrase>
|
||||||
</phrases>
|
</phrases>
|
||||||
<zone id="1200">
|
<locations>
|
||||||
<locations>
|
<location zone="1200" x="-317.509" y="287.652" z="191.86" rw="0.57124" rx="0" ry="-0.820783" rz="0" />
|
||||||
<location x="-317.509" y="287.652" z="191.86" rw="0.57124" rx="0" ry="-0.820783" rz="0" />
|
</locations>
|
||||||
</locations>
|
</object>
|
||||||
</zone>
|
<object name="Xiphoseer - Database Scout" lot="12260">
|
||||||
</npc>
|
|
||||||
<npc name="Xiphoseer - Database Scout" lot="12260">
|
|
||||||
<equipment>2632, 12754, 8645, 8468</equipment>
|
<equipment>2632, 12754, 8645, 8468</equipment>
|
||||||
<phrases>
|
<phrases>
|
||||||
<phrase>Oh no, not that old list again</phrase>
|
<phrase>Oh no, not that old list again</phrase>
|
||||||
@ -207,13 +185,11 @@
|
|||||||
<phrase>Look at that view!</phrase>
|
<phrase>Look at that view!</phrase>
|
||||||
<phrase>Oxidize!</phrase>
|
<phrase>Oxidize!</phrase>
|
||||||
</phrases>
|
</phrases>
|
||||||
<zone id="1300">
|
<locations>
|
||||||
<locations>
|
<location zone="1300" x="283.986" y="261.208" z="-128.466" rw="0.70207" rx="0" ry="0.712108" rz="0" />
|
||||||
<location x="283.986" y="261.208" z="-128.466" rw="0.70207" rx="0" ry="0.712108" rz="0" />
|
</locations>
|
||||||
</locations>
|
</object>
|
||||||
</zone>
|
<object name="Simon - External Archeologist" lot="7128">
|
||||||
</npc>
|
|
||||||
<npc name="Simon - External Archeologist" lot="7128">
|
|
||||||
<equipment>7363, 7371, 7383, 7395, 7405, 8462</equipment>
|
<equipment>7363, 7371, 7383, 7395, 7405, 8462</equipment>
|
||||||
<phrases>
|
<phrases>
|
||||||
<phrase>I want to build a castle, but first I need to build the bricks.</phrase>
|
<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>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>
|
<phrase>Who needs lamps, when you have Tiki Torches</phrase>
|
||||||
</phrases>
|
</phrases>
|
||||||
<zone id="1300">
|
<locations>
|
||||||
<locations>
|
<location zone="1300" x="204.93" y="294.784" z="471.537" rw="0.85015" rx="0" ry="-0.52654" rz="0" />
|
||||||
<location x="204.93" y="294.784" z="471.537" rw="0.85015" rx="0" ry="-0.52654" rz="0" />
|
</locations>
|
||||||
</locations>
|
</object>
|
||||||
</zone>
|
<object name="Bricknave - Treasure Hunter" lot="2279">
|
||||||
</npc>
|
|
||||||
<npc name="Bricknave - Treasure Hunter" lot="2279">
|
|
||||||
<equipment>7486, 7510, 7462, 8539</equipment>
|
<equipment>7486, 7510, 7462, 8539</equipment>
|
||||||
<phrases>
|
<phrases>
|
||||||
<phrase>During my very first expedition, Stromlings were called Darklings, and they dropped entire treasure chests!</phrase>
|
<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>There's treasure inside of all of us. It's called Imagination.</phrase>
|
||||||
<phrase>Stromlings! Why did it have to be Stromlings?</phrase>
|
<phrase>Stromlings! Why did it have to be Stromlings?</phrase>
|
||||||
</phrases>
|
</phrases>
|
||||||
<zone id="1300">
|
<locations>
|
||||||
<locations>
|
<location zone="1300" x="-47.6296" y="322.527" z="533.5" rw="0.145135" rx="0" ry="0.989412" rz="0" />
|
||||||
<location x="-47.6296" y="322.527" z="533.5" rw="0.145135" rx="0" ry="0.989412" rz="0" />
|
</locations>
|
||||||
</locations>
|
</object>
|
||||||
</zone>
|
<object name="Jamie - Shenanigans Enthusiast" lot="9893">
|
||||||
</npc>
|
|
||||||
<npc name="Jamie - Shenanigans Enthusiast" lot="9893">
|
|
||||||
<equipment>12915, 9683, 10476, 13342, 14166</equipment>
|
<equipment>12915, 9683, 10476, 13342, 14166</equipment>
|
||||||
<phrases>
|
<phrases>
|
||||||
<phrase>sup lol</phrase>
|
<phrase>sup lol</phrase>
|
||||||
@ -253,22 +225,18 @@
|
|||||||
<phrase>Wait, did the game close yet?</phrase>
|
<phrase>Wait, did the game close yet?</phrase>
|
||||||
<phrase>... What year is it?</phrase>
|
<phrase>... What year is it?</phrase>
|
||||||
</phrases>
|
</phrases>
|
||||||
<zone id="1400">
|
<locations>
|
||||||
<locations>
|
<location zone="1400" x="-490.608" y="51.9449" z="-347.747" rw="0.594978" rx="0" ry="-0.803742" rz="0" />
|
||||||
<location x="-490.608" y="51.9449" z="-347.747" rw="0.594978" rx="0" ry="-0.803742" rz="0" />
|
</locations>
|
||||||
</locations>
|
</object>
|
||||||
</zone>
|
<object name="Wicked" lot="7412">
|
||||||
</npc>
|
|
||||||
<npc name="Wicked" lot="7412">
|
|
||||||
<equipment>8287, 2957, 7523, 16613</equipment>
|
<equipment>8287, 2957, 7523, 16613</equipment>
|
||||||
<phrases></phrases>
|
<phrases></phrases>
|
||||||
<zone id="1400">
|
<locations>
|
||||||
<locations>
|
<location zone="1400" x="264.506" y="339.931" z="54.1201" rw="0.715223" rx="0" ry="0.698896" rz="0" />
|
||||||
<location x="264.506" y="339.931" z="54.1201" rw="0.715223" rx="0" ry="0.698896" rz="0" />
|
</locations>
|
||||||
</locations>
|
</object>
|
||||||
</zone>
|
<object name="Krysto - Sentinal Veteran" lot="12260">
|
||||||
</npc>
|
|
||||||
<npc name="Krysto - Sentinal Veteran" lot="12260">
|
|
||||||
<equipment>12651, 12648, 10158, 5694, 16619, 9681, 8286</equipment>
|
<equipment>12651, 12648, 10158, 5694, 16619, 9681, 8286</equipment>
|
||||||
<phrases>
|
<phrases>
|
||||||
<phrase>Need a pick me up? Interact with the consoles here to restore your health and armor!</phrase>
|
<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>What do you mean my title is misspelled?</phrase>
|
||||||
<phrase>When I was your age, numbers were illegal.</phrase>
|
<phrase>When I was your age, numbers were illegal.</phrase>
|
||||||
</phrases>
|
</phrases>
|
||||||
<zone id="1900">
|
<locations>
|
||||||
<locations>
|
<location zone="1900" x="-493.724" y="1124.05" z="-76.6355" rw="0.1719" rx="0" ry="0.985114" rz="0" />
|
||||||
<location x="-493.724" y="1124.05" z="-76.6355" rw="0.1719" rx="0" ry="0.985114" rz="0" />
|
</locations>
|
||||||
</locations>
|
</object>
|
||||||
</zone>
|
|
||||||
</npc>
|
|
||||||
12651
|
12651
|
||||||
<npc name="Matthew - ?????" lot="2279">
|
<object name="Matthew - ?????" lot="2279">
|
||||||
<equipment>9856, 7793, 6928, 6927</equipment>
|
<equipment>9856, 7793, 6928, 6927</equipment>
|
||||||
<phrases>
|
<phrases>
|
||||||
<phrase>I think I have a migraine from staring at this for so long</phrase>
|
<phrase>I think I have a migraine from staring at this for so long</phrase>
|
||||||
<phrase>Anything but Portabello</phrase>
|
<phrase>Anything but Portabello</phrase>
|
||||||
</phrases>
|
</phrases>
|
||||||
<zone id="1900">
|
<locations>
|
||||||
<locations>
|
<location zone="1900" x="-227.621" y="1188.28" z="145.734" rw="-0.254353" rx="0" ry="0.967111" rz="0" />
|
||||||
<location x="-227.621" y="1188.28" z="145.734" rw="-0.254353" rx="0" ry="0.967111" rz="0" />
|
</locations>
|
||||||
</locations>
|
</object>
|
||||||
</zone>
|
<object name="Raine" lot="9893">
|
||||||
</npc>
|
|
||||||
<npc name="Raine" lot="9893">
|
|
||||||
<equipment>13342, 7370, 7382</equipment>
|
<equipment>13342, 7370, 7382</equipment>
|
||||||
<phrases>
|
<phrases>
|
||||||
<phrase>Per Aspera ad Astra</phrase>
|
<phrase>Per Aspera ad Astra</phrase>
|
||||||
</phrases>
|
</phrases>
|
||||||
<zone id="1900">
|
<locations>
|
||||||
<locations>
|
<location zone="1900" x="-190.673" y="1218.34" z="221.6" rw="0.972371" rx="0" ry="-0.233441" rz="0" />
|
||||||
<location x="-190.673" y="1218.34" z="221.6" rw="0.972371" rx="0" ry="-0.233441" rz="0" />
|
</locations>
|
||||||
</locations>
|
</object>
|
||||||
</zone>
|
<object name="Brickgirl - Explorer" lot="12260">
|
||||||
</npc>
|
|
||||||
<npc name="Brickgirl - Explorer" lot="12260">
|
|
||||||
<equipment>12781, 12686, 13000, 12802, 12678, 12095</equipment>
|
<equipment>12781, 12686, 13000, 12802, 12678, 12095</equipment>
|
||||||
<phrases>
|
<phrases>
|
||||||
<phrase>Imagination will often carry us to worlds that never were, but without it we go nowhere.</phrase>
|
<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 you tried those buttery croissants from “Farnham Spoon” they are delicious! I might just go and have another</phrase>
|
||||||
<phrase>Have fun!</phrase>
|
<phrase>Have fun!</phrase>
|
||||||
</phrases>
|
</phrases>
|
||||||
<zone id="1800">
|
<locations>
|
||||||
<locations>
|
<location zone="1800" x="-39.2259" y="96.8605" z="-550.077" rw="0.815145" rx="0" ry="-0.579257" rz="0" />
|
||||||
<location x="-39.2259" y="96.8605" z="-550.077" rw="0.815145" rx="0" ry="-0.579257" rz="0" />
|
</locations>
|
||||||
</locations>
|
</object>
|
||||||
</zone>
|
<object name="Sam - The Avianite" lot="2281">
|
||||||
</npc>
|
|
||||||
<npc name="Sam - The Avianite" lot="2281">
|
|
||||||
<equipment>12563, 12565, 12567, 12949, 12947, 7570</equipment>
|
<equipment>12563, 12565, 12567, 12949, 12947, 7570</equipment>
|
||||||
<phrases>
|
<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>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>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>
|
<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>
|
</phrases>
|
||||||
<zone id="2000">
|
<locations>
|
||||||
<locations>
|
<location zone="2000" x="-119.269" y="230.372" z="226.63" rw="0.381416" rx="0" ry="0.924404" rz="0" />
|
||||||
<location x="-119.269" y="230.372" z="226.63" rw="0.381416" rx="0" ry="0.924404" rz="0" />
|
</locations>
|
||||||
</locations>
|
</object>
|
||||||
</zone>
|
<object name="lcdr - Dab Specialist" lot="8657">
|
||||||
</npc>
|
|
||||||
<npc name="lcdr - Dab Specialist" lot="8657">
|
|
||||||
<equipment>15931, 4298, 2526</equipment>
|
<equipment>15931, 4298, 2526</equipment>
|
||||||
<phrases>
|
<phrases>
|
||||||
<phrase>Hello there.</phrase>
|
<phrase>Hello there.</phrase>
|
||||||
@ -354,13 +312,11 @@
|
|||||||
<phrase>Gonk.</phrase>
|
<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>
|
<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>
|
</phrases>
|
||||||
<zone id="1200">
|
<locations>
|
||||||
<locations>
|
<location zone="1200" x="197.549" y="259.137" z="-587.759" rw="0.873694" rx="0" ry="0.486475" rz="0" />
|
||||||
<location x="197.549" y="259.137" z="-587.759" rw="0.873694" rx="0" ry="0.486475" rz="0" />
|
</locations>
|
||||||
</locations>
|
</object>
|
||||||
</zone>
|
<object name="zaop - Assembly Scientist" lot="2279">
|
||||||
</npc>
|
|
||||||
<npc name="zaop - Assembly Scientist" lot="2279">
|
|
||||||
<equipment>12099, 3010, 10067, 7503</equipment>
|
<equipment>12099, 3010, 10067, 7503</equipment>
|
||||||
<phrases>
|
<phrases>
|
||||||
<phrase>Hi!</phrase>
|
<phrase>Hi!</phrase>
|
||||||
@ -379,22 +335,18 @@
|
|||||||
<phrase>Excuse me, do you know the way to Frostburgh?</phrase>
|
<phrase>Excuse me, do you know the way to Frostburgh?</phrase>
|
||||||
<phrase>What are those Paradox scientists up to these days?</phrase>
|
<phrase>What are those Paradox scientists up to these days?</phrase>
|
||||||
</phrases>
|
</phrases>
|
||||||
<zone id="1100">
|
<locations>
|
||||||
<locations>
|
<location zone="1100" x="436.949" y="415.264" z="151.381" rw="0.528425" rx="0" ry="0.84898" rz="0" />
|
||||||
<location x="436.949" y="415.264" z="151.381" rw="0.528425" rx="0" ry="0.84898" rz="0" />
|
</locations>
|
||||||
</locations>
|
</object>
|
||||||
</zone>
|
<object name="Ben" lot="2279">
|
||||||
</npc>
|
|
||||||
<npc name="Ben" lot="2279">
|
|
||||||
<equipment>8664, 4065, 2587</equipment>
|
<equipment>8664, 4065, 2587</equipment>
|
||||||
<phrases></phrases>
|
<phrases></phrases>
|
||||||
<zone id="1200">
|
<locations>
|
||||||
<locations>
|
<location zone="1200" x="284.538" y="260.627" z="-506.692" rw="0.819721" rx="0" ry="0.572763" rz="0" />
|
||||||
<location x="284.538" y="260.627" z="-506.692" rw="0.819721" rx="0" ry="0.572763" rz="0" />
|
</locations>
|
||||||
</locations>
|
</object>
|
||||||
</zone>
|
<object name="HappyAngryCatfish - Explorer" lot="2279">
|
||||||
</npc>
|
|
||||||
<npc name="HappyAngryCatfish - Explorer" lot="2279">
|
|
||||||
<equipment>8613, 13000, 7570</equipment>
|
<equipment>8613, 13000, 7570</equipment>
|
||||||
<phrases>
|
<phrases>
|
||||||
<phrase>The red parrot can be very difficult to find!</phrase>
|
<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 think I may be lost...</phrase>
|
||||||
<phrase>I'm feeling a bit emotionally conflicted right now</phrase>
|
<phrase>I'm feeling a bit emotionally conflicted right now</phrase>
|
||||||
</phrases>
|
</phrases>
|
||||||
<zone id="1300">
|
<locations>
|
||||||
<locations>
|
<location zone="1300" x="-171.217" y="246.482" z="-147.05" rw="-0.203118" rx="0" ry="0.979154" rz="0" />
|
||||||
<location x="-171.217" y="246.482" z="-147.05" rw="-0.203118" rx="0" ry="0.979154" rz="0" />
|
</locations>
|
||||||
</locations>
|
</object>
|
||||||
</zone>
|
<object name="Max - Developer" lot="9749">
|
||||||
</npc>
|
|
||||||
<npc name="Max - Developer" lot="9749">
|
|
||||||
<equipment>4523, 2517, 11909</equipment>
|
<equipment>4523, 2517, 11909</equipment>
|
||||||
<phrases>
|
<phrases>
|
||||||
<phrase>Some people know me as "Darwin"; but that's been a while!</phrase>
|
<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>I love cats, little meow meows</phrase>
|
||||||
<phrase>It's not perfect, but it works!</phrase>
|
<phrase>It's not perfect, but it works!</phrase>
|
||||||
</phrases>
|
</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>
|
<locations>
|
||||||
<location x="-24.3963" y="291.542" z="-117.871" rw="0.480946" rx="0" ry="0.87675" rz="0" />
|
<location zone="1201" x="197.709" y="179.335" z="-8.05284" rw="0.544424" rx="0" ry="-0.83881" 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" />
|
|
||||||
</locations>
|
</locations>
|
||||||
</party>
|
</object>
|
||||||
<partyphrases>
|
</objects>
|
||||||
<phrase>Hi there!</phrase>
|
|
||||||
<phrase>Hi!</phrase>
|
|
||||||
<phrase>Hahaha!</phrase>
|
|
||||||
<phrase>Hello there!</phrase>
|
|
||||||
|
|
||||||
<phrase>:D</phrase>
|
|
||||||
<phrase>:P</phrase>
|
|
||||||
</partyphrases>
|
|
||||||
</npcs>
|
|
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