mirror of
https://github.com/DarkflameUniverse/DarkflameServer
synced 2024-08-30 18:43:58 +00:00
Merge branch 'main' into property_behavior_saving
This commit is contained in:
commit
b984cd6a0b
@ -31,7 +31,7 @@ COPY --from=build /app/build/*Server /app/
|
|||||||
|
|
||||||
# Necessary suplimentary files
|
# Necessary suplimentary files
|
||||||
COPY --from=build /app/build/*.ini /app/configs/
|
COPY --from=build /app/build/*.ini /app/configs/
|
||||||
COPY --from=build /app/build/vanity/*.* /app/vanity/*
|
COPY --from=build /app/build/vanity/*.* /app/vanity/
|
||||||
COPY --from=build /app/build/navmeshes /app/navmeshes
|
COPY --from=build /app/build/navmeshes /app/navmeshes
|
||||||
COPY --from=build /app/build/migrations /app/migrations
|
COPY --from=build /app/build/migrations /app/migrations
|
||||||
COPY --from=build /app/build/*.dcf /app/
|
COPY --from=build /app/build/*.dcf /app/
|
||||||
@ -39,7 +39,7 @@ COPY --from=build /app/build/*.dcf /app/
|
|||||||
# backup of config and vanity files to copy to the host incase
|
# backup of config and vanity files to copy to the host incase
|
||||||
# of a mount clobbering the copy from above
|
# of a mount clobbering the copy from above
|
||||||
COPY --from=build /app/build/*.ini /app/default-configs/
|
COPY --from=build /app/build/*.ini /app/default-configs/
|
||||||
COPY --from=build /app/build/vanity/*.* /app/default-vanity/*
|
COPY --from=build /app/build/vanity/*.* /app/default-vanity/
|
||||||
|
|
||||||
# needed as the container runs with the root user
|
# needed as the container runs with the root user
|
||||||
# and therefore sudo doesn't exist
|
# and therefore sudo doesn't exist
|
||||||
|
@ -179,6 +179,7 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HandlePacket(Packet* packet) {
|
void HandlePacket(Packet* packet) {
|
||||||
|
if (packet->length < 1) return;
|
||||||
if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) {
|
if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) {
|
||||||
LOG("A server has disconnected, erasing their connected players from the list.");
|
LOG("A server has disconnected, erasing their connected players from the list.");
|
||||||
} else if (packet->data[0] == ID_NEW_INCOMING_CONNECTION) {
|
} else if (packet->data[0] == ID_NEW_INCOMING_CONNECTION) {
|
||||||
|
@ -201,7 +201,7 @@ void OnTerminate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MakeBacktrace() {
|
void MakeBacktrace() {
|
||||||
struct sigaction sigact;
|
struct sigaction sigact{};
|
||||||
|
|
||||||
sigact.sa_sigaction = CritErrHdlr;
|
sigact.sa_sigaction = CritErrHdlr;
|
||||||
sigact.sa_flags = SA_RESTART | SA_SIGINFO;
|
sigact.sa_flags = SA_RESTART | SA_SIGINFO;
|
||||||
|
@ -31,22 +31,22 @@ public:
|
|||||||
|
|
||||||
virtual ~LDFBaseData() {}
|
virtual ~LDFBaseData() {}
|
||||||
|
|
||||||
virtual void WriteToPacket(RakNet::BitStream& packet) = 0;
|
virtual void WriteToPacket(RakNet::BitStream& packet) const = 0;
|
||||||
|
|
||||||
virtual const std::u16string& GetKey() = 0;
|
virtual const std::u16string& GetKey() const = 0;
|
||||||
|
|
||||||
virtual eLDFType GetValueType() = 0;
|
virtual eLDFType GetValueType() const = 0;
|
||||||
|
|
||||||
/** Gets a string from the key/value pair
|
/** Gets a string from the key/value pair
|
||||||
* @param includeKey Whether or not to include the key in the data
|
* @param includeKey Whether or not to include the key in the data
|
||||||
* @param includeTypeId Whether or not to include the type id in the data
|
* @param includeTypeId Whether or not to include the type id in the data
|
||||||
* @return The string representation of the data
|
* @return The string representation of the data
|
||||||
*/
|
*/
|
||||||
virtual std::string GetString(bool includeKey = true, bool includeTypeId = true) = 0;
|
virtual std::string GetString(bool includeKey = true, bool includeTypeId = true) const = 0;
|
||||||
|
|
||||||
virtual std::string GetValueAsString() = 0;
|
virtual std::string GetValueAsString() const = 0;
|
||||||
|
|
||||||
virtual LDFBaseData* Copy() = 0;
|
virtual LDFBaseData* Copy() const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given an input string, return the data as a LDF key.
|
* Given an input string, return the data as a LDF key.
|
||||||
@ -62,7 +62,7 @@ private:
|
|||||||
T value;
|
T value;
|
||||||
|
|
||||||
//! Writes the key to the packet
|
//! Writes the key to the packet
|
||||||
void WriteKey(RakNet::BitStream& packet) {
|
void WriteKey(RakNet::BitStream& packet) const {
|
||||||
packet.Write<uint8_t>(this->key.length() * sizeof(uint16_t));
|
packet.Write<uint8_t>(this->key.length() * sizeof(uint16_t));
|
||||||
for (uint32_t i = 0; i < this->key.length(); ++i) {
|
for (uint32_t i = 0; i < this->key.length(); ++i) {
|
||||||
packet.Write<uint16_t>(this->key[i]);
|
packet.Write<uint16_t>(this->key[i]);
|
||||||
@ -70,7 +70,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Writes the value to the packet
|
//! Writes the value to the packet
|
||||||
void WriteValue(RakNet::BitStream& packet) {
|
void WriteValue(RakNet::BitStream& packet) const {
|
||||||
packet.Write<uint8_t>(this->GetValueType());
|
packet.Write<uint8_t>(this->GetValueType());
|
||||||
packet.Write(this->value);
|
packet.Write(this->value);
|
||||||
}
|
}
|
||||||
@ -90,7 +90,7 @@ public:
|
|||||||
/*!
|
/*!
|
||||||
\return The value
|
\return The value
|
||||||
*/
|
*/
|
||||||
const T& GetValue(void) { return this->value; }
|
const T& GetValue(void) const { return this->value; }
|
||||||
|
|
||||||
//! Sets the value
|
//! Sets the value
|
||||||
/*!
|
/*!
|
||||||
@ -102,13 +102,13 @@ public:
|
|||||||
/*!
|
/*!
|
||||||
\return The value string
|
\return The value string
|
||||||
*/
|
*/
|
||||||
std::string GetValueString(void) { return ""; }
|
std::string GetValueString(void) const { return ""; }
|
||||||
|
|
||||||
//! Writes the data to a packet
|
//! Writes the data to a packet
|
||||||
/*!
|
/*!
|
||||||
\param packet The packet
|
\param packet The packet
|
||||||
*/
|
*/
|
||||||
void WriteToPacket(RakNet::BitStream& packet) override {
|
void WriteToPacket(RakNet::BitStream& packet) const override {
|
||||||
this->WriteKey(packet);
|
this->WriteKey(packet);
|
||||||
this->WriteValue(packet);
|
this->WriteValue(packet);
|
||||||
}
|
}
|
||||||
@ -117,13 +117,13 @@ public:
|
|||||||
/*!
|
/*!
|
||||||
\return The key
|
\return The key
|
||||||
*/
|
*/
|
||||||
const std::u16string& GetKey(void) override { return this->key; }
|
const std::u16string& GetKey(void) const override { return this->key; }
|
||||||
|
|
||||||
//! Gets the LDF Type
|
//! Gets the LDF Type
|
||||||
/*!
|
/*!
|
||||||
\return The LDF value type
|
\return The LDF value type
|
||||||
*/
|
*/
|
||||||
eLDFType GetValueType(void) override { return LDF_TYPE_UNKNOWN; }
|
eLDFType GetValueType(void) const override { return LDF_TYPE_UNKNOWN; }
|
||||||
|
|
||||||
//! Gets the string data
|
//! Gets the string data
|
||||||
/*!
|
/*!
|
||||||
@ -131,7 +131,7 @@ public:
|
|||||||
\param includeTypeId Whether or not to include the type id in the data
|
\param includeTypeId Whether or not to include the type id in the data
|
||||||
\return The string representation of the data
|
\return The string representation of the data
|
||||||
*/
|
*/
|
||||||
std::string GetString(const bool includeKey = true, const bool includeTypeId = true) override {
|
std::string GetString(const bool includeKey = true, const bool includeTypeId = true) const override {
|
||||||
if (GetValueType() == -1) {
|
if (GetValueType() == -1) {
|
||||||
return GeneralUtils::UTF16ToWTF8(this->key) + "=-1:<server variable>";
|
return GeneralUtils::UTF16ToWTF8(this->key) + "=-1:<server variable>";
|
||||||
}
|
}
|
||||||
@ -154,11 +154,11 @@ public:
|
|||||||
return stream.str();
|
return stream.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetValueAsString() override {
|
std::string GetValueAsString() const override {
|
||||||
return this->GetValueString();
|
return this->GetValueString();
|
||||||
}
|
}
|
||||||
|
|
||||||
LDFBaseData* Copy() override {
|
LDFBaseData* Copy() const override {
|
||||||
return new LDFData<T>(key, value);
|
return new LDFData<T>(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,19 +166,19 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
// LDF Types
|
// LDF Types
|
||||||
template<> inline eLDFType LDFData<std::u16string>::GetValueType(void) { return LDF_TYPE_UTF_16; };
|
template<> inline eLDFType LDFData<std::u16string>::GetValueType(void) const { return LDF_TYPE_UTF_16; };
|
||||||
template<> inline eLDFType LDFData<int32_t>::GetValueType(void) { return LDF_TYPE_S32; };
|
template<> inline eLDFType LDFData<int32_t>::GetValueType(void) const { return LDF_TYPE_S32; };
|
||||||
template<> inline eLDFType LDFData<float>::GetValueType(void) { return LDF_TYPE_FLOAT; };
|
template<> inline eLDFType LDFData<float>::GetValueType(void) const { return LDF_TYPE_FLOAT; };
|
||||||
template<> inline eLDFType LDFData<double>::GetValueType(void) { return LDF_TYPE_DOUBLE; };
|
template<> inline eLDFType LDFData<double>::GetValueType(void) const { return LDF_TYPE_DOUBLE; };
|
||||||
template<> inline eLDFType LDFData<uint32_t>::GetValueType(void) { return LDF_TYPE_U32; };
|
template<> inline eLDFType LDFData<uint32_t>::GetValueType(void) const { return LDF_TYPE_U32; };
|
||||||
template<> inline eLDFType LDFData<bool>::GetValueType(void) { return LDF_TYPE_BOOLEAN; };
|
template<> inline eLDFType LDFData<bool>::GetValueType(void) const { return LDF_TYPE_BOOLEAN; };
|
||||||
template<> inline eLDFType LDFData<uint64_t>::GetValueType(void) { return LDF_TYPE_U64; };
|
template<> inline eLDFType LDFData<uint64_t>::GetValueType(void) const { return LDF_TYPE_U64; };
|
||||||
template<> inline eLDFType LDFData<LWOOBJID>::GetValueType(void) { return LDF_TYPE_OBJID; };
|
template<> inline eLDFType LDFData<LWOOBJID>::GetValueType(void) const { return LDF_TYPE_OBJID; };
|
||||||
template<> inline eLDFType LDFData<std::string>::GetValueType(void) { return LDF_TYPE_UTF_8; };
|
template<> inline eLDFType LDFData<std::string>::GetValueType(void) const { return LDF_TYPE_UTF_8; };
|
||||||
|
|
||||||
// The specialized version for std::u16string (UTF-16)
|
// The specialized version for std::u16string (UTF-16)
|
||||||
template<>
|
template<>
|
||||||
inline void LDFData<std::u16string>::WriteValue(RakNet::BitStream& packet) {
|
inline void LDFData<std::u16string>::WriteValue(RakNet::BitStream& packet) const {
|
||||||
packet.Write<uint8_t>(this->GetValueType());
|
packet.Write<uint8_t>(this->GetValueType());
|
||||||
|
|
||||||
packet.Write<uint32_t>(this->value.length());
|
packet.Write<uint32_t>(this->value.length());
|
||||||
@ -189,7 +189,7 @@ inline void LDFData<std::u16string>::WriteValue(RakNet::BitStream& packet) {
|
|||||||
|
|
||||||
// The specialized version for bool
|
// The specialized version for bool
|
||||||
template<>
|
template<>
|
||||||
inline void LDFData<bool>::WriteValue(RakNet::BitStream& packet) {
|
inline void LDFData<bool>::WriteValue(RakNet::BitStream& packet) const {
|
||||||
packet.Write<uint8_t>(this->GetValueType());
|
packet.Write<uint8_t>(this->GetValueType());
|
||||||
|
|
||||||
packet.Write<uint8_t>(this->value);
|
packet.Write<uint8_t>(this->value);
|
||||||
@ -197,7 +197,7 @@ inline void LDFData<bool>::WriteValue(RakNet::BitStream& packet) {
|
|||||||
|
|
||||||
// The specialized version for std::string (UTF-8)
|
// The specialized version for std::string (UTF-8)
|
||||||
template<>
|
template<>
|
||||||
inline void LDFData<std::string>::WriteValue(RakNet::BitStream& packet) {
|
inline void LDFData<std::string>::WriteValue(RakNet::BitStream& packet) const {
|
||||||
packet.Write<uint8_t>(this->GetValueType());
|
packet.Write<uint8_t>(this->GetValueType());
|
||||||
|
|
||||||
packet.Write<uint32_t>(this->value.length());
|
packet.Write<uint32_t>(this->value.length());
|
||||||
@ -206,18 +206,18 @@ inline void LDFData<std::string>::WriteValue(RakNet::BitStream& packet) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> inline std::string LDFData<std::u16string>::GetValueString() {
|
template<> inline std::string LDFData<std::u16string>::GetValueString() const {
|
||||||
return GeneralUtils::UTF16ToWTF8(this->value, this->value.size());
|
return GeneralUtils::UTF16ToWTF8(this->value, this->value.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> inline std::string LDFData<int32_t>::GetValueString() { return std::to_string(this->value); }
|
template<> inline std::string LDFData<int32_t>::GetValueString() const { return std::to_string(this->value); }
|
||||||
template<> inline std::string LDFData<float>::GetValueString() { return std::to_string(this->value); }
|
template<> inline std::string LDFData<float>::GetValueString() const { return std::to_string(this->value); }
|
||||||
template<> inline std::string LDFData<double>::GetValueString() { return std::to_string(this->value); }
|
template<> inline std::string LDFData<double>::GetValueString() const { return std::to_string(this->value); }
|
||||||
template<> inline std::string LDFData<uint32_t>::GetValueString() { return std::to_string(this->value); }
|
template<> inline std::string LDFData<uint32_t>::GetValueString() const { return std::to_string(this->value); }
|
||||||
template<> inline std::string LDFData<bool>::GetValueString() { return std::to_string(this->value); }
|
template<> inline std::string LDFData<bool>::GetValueString() const { return std::to_string(this->value); }
|
||||||
template<> inline std::string LDFData<uint64_t>::GetValueString() { return std::to_string(this->value); }
|
template<> inline std::string LDFData<uint64_t>::GetValueString() const { return std::to_string(this->value); }
|
||||||
template<> inline std::string LDFData<LWOOBJID>::GetValueString() { return std::to_string(this->value); }
|
template<> inline std::string LDFData<LWOOBJID>::GetValueString() const { return std::to_string(this->value); }
|
||||||
|
|
||||||
template<> inline std::string LDFData<std::string>::GetValueString() { return this->value; }
|
template<> inline std::string LDFData<std::string>::GetValueString() const { return this->value; }
|
||||||
|
|
||||||
#endif //!__LDFFORMAT__H__
|
#endif //!__LDFFORMAT__H__
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "dConfig.h"
|
#include "dConfig.h"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "BinaryPathFinder.h"
|
#include "BinaryPathFinder.h"
|
||||||
#include "GeneralUtils.h"
|
#include "GeneralUtils.h"
|
||||||
|
21
dCommon/dEnums/eReponseMoveItemBetweenInventoryTypeCode.h
Normal file
21
dCommon/dEnums/eReponseMoveItemBetweenInventoryTypeCode.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef __EREPONSEMOVEITEMBETWEENINVENTORYTYPECODE__H__
|
||||||
|
#define __EREPONSEMOVEITEMBETWEENINVENTORYTYPECODE__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum class eReponseMoveItemBetweenInventoryTypeCode : int32_t {
|
||||||
|
SUCCESS,
|
||||||
|
FAIL_GENERIC,
|
||||||
|
FAIL_INV_FULL,
|
||||||
|
FAIL_ITEM_NOT_FOUND,
|
||||||
|
FAIL_CANT_MOVE_TO_THAT_INV_TYPE,
|
||||||
|
FAIL_NOT_NEAR_BANK,
|
||||||
|
FAIL_CANT_SWAP_ITEMS,
|
||||||
|
FAIL_SOURCE_TYPE,
|
||||||
|
FAIL_WRONG_DEST_TYPE,
|
||||||
|
FAIL_SWAP_DEST_TYPE,
|
||||||
|
FAIL_CANT_MOVE_THINKING_HAT,
|
||||||
|
FAIL_DISMOUNT_BEFORE_MOVING
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__EREPONSEMOVEITEMBETWEENINVENTORYTYPECODE__H__
|
@ -27,6 +27,8 @@ Character::Character(uint32_t id, User* parentUser) {
|
|||||||
m_ID = id;
|
m_ID = id;
|
||||||
m_ParentUser = parentUser;
|
m_ParentUser = parentUser;
|
||||||
m_OurEntity = nullptr;
|
m_OurEntity = nullptr;
|
||||||
|
m_GMLevel = eGameMasterLevel::CIVILIAN;
|
||||||
|
m_PermissionMap = static_cast<ePermissionMap>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Character::~Character() {
|
Character::~Character() {
|
||||||
|
@ -464,22 +464,22 @@ private:
|
|||||||
/**
|
/**
|
||||||
* The ID of this character. First 32 bits of the ObjectID.
|
* The ID of this character. First 32 bits of the ObjectID.
|
||||||
*/
|
*/
|
||||||
uint32_t m_ID;
|
uint32_t m_ID{};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The 64-bit unique ID used in the game.
|
* The 64-bit unique ID used in the game.
|
||||||
*/
|
*/
|
||||||
LWOOBJID m_ObjectID;
|
LWOOBJID m_ObjectID{ LWOOBJID_EMPTY };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The user that owns this character.
|
* The user that owns this character.
|
||||||
*/
|
*/
|
||||||
User* m_ParentUser;
|
User* m_ParentUser{};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the character is in game, this is the entity that it represents, else nullptr.
|
* If the character is in game, this is the entity that it represents, else nullptr.
|
||||||
*/
|
*/
|
||||||
Entity* m_OurEntity;
|
Entity* m_OurEntity{};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 0-9, the Game Master level of this character.
|
* 0-9, the Game Master level of this character.
|
||||||
@ -506,17 +506,17 @@ private:
|
|||||||
/**
|
/**
|
||||||
* Whether the custom name of this character is rejected
|
* Whether the custom name of this character is rejected
|
||||||
*/
|
*/
|
||||||
bool m_NameRejected;
|
bool m_NameRejected{};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current amount of coins of this character
|
* The current amount of coins of this character
|
||||||
*/
|
*/
|
||||||
int64_t m_Coins;
|
int64_t m_Coins{};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the character is building
|
* Whether the character is building
|
||||||
*/
|
*/
|
||||||
bool m_BuildMode;
|
bool m_BuildMode{};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The items equipped by the character on world load
|
* The items equipped by the character on world load
|
||||||
@ -583,7 +583,7 @@ private:
|
|||||||
/**
|
/**
|
||||||
* The ID of the properties of this character
|
* The ID of the properties of this character
|
||||||
*/
|
*/
|
||||||
uint32_t m_PropertyCloneID;
|
uint32_t m_PropertyCloneID{};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The XML data for this character, stored as string
|
* The XML data for this character, stored as string
|
||||||
@ -613,7 +613,7 @@ private:
|
|||||||
/**
|
/**
|
||||||
* The last time this character logged in
|
* The last time this character logged in
|
||||||
*/
|
*/
|
||||||
uint64_t m_LastLogin;
|
uint64_t m_LastLogin{};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The gameplay flags this character has (not just true values)
|
* The gameplay flags this character has (not just true values)
|
||||||
|
@ -12,6 +12,7 @@ User::User(const SystemAddress& sysAddr, const std::string& username, const std:
|
|||||||
m_AccountID = 0;
|
m_AccountID = 0;
|
||||||
m_Username = "";
|
m_Username = "";
|
||||||
m_SessionKey = "";
|
m_SessionKey = "";
|
||||||
|
m_MuteExpire = 0;
|
||||||
|
|
||||||
m_MaxGMLevel = eGameMasterLevel::CIVILIAN; //The max GM level this account can assign to it's characters
|
m_MaxGMLevel = eGameMasterLevel::CIVILIAN; //The max GM level this account can assign to it's characters
|
||||||
m_LastCharID = 0;
|
m_LastCharID = 0;
|
||||||
|
@ -105,7 +105,7 @@ void BehaviorContext::ExecuteUpdates() {
|
|||||||
this->scheduledUpdates.clear();
|
this->scheduledUpdates.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BehaviorContext::SyncBehavior(const uint32_t syncId, RakNet::BitStream& bitStream) {
|
bool BehaviorContext::SyncBehavior(const uint32_t syncId, RakNet::BitStream& bitStream) {
|
||||||
BehaviorSyncEntry entry;
|
BehaviorSyncEntry entry;
|
||||||
auto found = false;
|
auto found = false;
|
||||||
|
|
||||||
@ -128,7 +128,7 @@ void BehaviorContext::SyncBehavior(const uint32_t syncId, RakNet::BitStream& bit
|
|||||||
if (!found) {
|
if (!found) {
|
||||||
LOG("Failed to find behavior sync entry with sync id (%i)!", syncId);
|
LOG("Failed to find behavior sync entry with sync id (%i)!", syncId);
|
||||||
|
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* behavior = entry.behavior;
|
auto* behavior = entry.behavior;
|
||||||
@ -137,10 +137,11 @@ void BehaviorContext::SyncBehavior(const uint32_t syncId, RakNet::BitStream& bit
|
|||||||
if (behavior == nullptr) {
|
if (behavior == nullptr) {
|
||||||
LOG("Invalid behavior for sync id (%i)!", syncId);
|
LOG("Invalid behavior for sync id (%i)!", syncId);
|
||||||
|
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
behavior->Sync(this, bitStream, branch);
|
behavior->Sync(this, bitStream, branch);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ struct BehaviorContext
|
|||||||
|
|
||||||
void ExecuteUpdates();
|
void ExecuteUpdates();
|
||||||
|
|
||||||
void SyncBehavior(uint32_t syncId, RakNet::BitStream& bitStream);
|
bool SyncBehavior(uint32_t syncId, RakNet::BitStream& bitStream);
|
||||||
|
|
||||||
void Update(float deltaTime);
|
void Update(float deltaTime);
|
||||||
|
|
||||||
|
@ -29,7 +29,8 @@
|
|||||||
|
|
||||||
BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id): Component(parent) {
|
BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id): Component(parent) {
|
||||||
m_Target = LWOOBJID_EMPTY;
|
m_Target = LWOOBJID_EMPTY;
|
||||||
SetAiState(AiState::spawn);
|
m_DirtyStateOrTarget = true;
|
||||||
|
m_State = AiState::spawn;
|
||||||
m_Timer = 1.0f;
|
m_Timer = 1.0f;
|
||||||
m_StartPosition = parent->GetPosition();
|
m_StartPosition = parent->GetPosition();
|
||||||
m_MovementAI = nullptr;
|
m_MovementAI = nullptr;
|
||||||
|
@ -558,19 +558,9 @@ void InventoryComponent::LoadXml(const tinyxml2::XMLDocument& document) {
|
|||||||
itemElement->QueryAttribute("parent", &parent);
|
itemElement->QueryAttribute("parent", &parent);
|
||||||
// End custom xml
|
// End custom xml
|
||||||
|
|
||||||
std::vector<LDFBaseData*> config;
|
auto* item = new Item(id, lot, inventory, slot, count, bound, {}, parent, subKey);
|
||||||
|
|
||||||
auto* extraInfo = itemElement->FirstChildElement("x");
|
item->LoadConfigXml(*itemElement);
|
||||||
|
|
||||||
if (extraInfo) {
|
|
||||||
std::string modInfo = extraInfo->Attribute("ma");
|
|
||||||
|
|
||||||
LDFBaseData* moduleAssembly = new LDFData<std::u16string>(u"assemblyPartLOTs", GeneralUtils::ASCIIToUTF16(modInfo.substr(2, modInfo.size() - 1)));
|
|
||||||
|
|
||||||
config.push_back(moduleAssembly);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto* item = new Item(id, lot, inventory, slot, count, bound, config, parent, subKey);
|
|
||||||
|
|
||||||
if (equipped) {
|
if (equipped) {
|
||||||
const auto info = Inventory::FindItemComponent(lot);
|
const auto info = Inventory::FindItemComponent(lot);
|
||||||
@ -676,17 +666,7 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument& document) {
|
|||||||
itemElement->SetAttribute("parent", item->GetParent());
|
itemElement->SetAttribute("parent", item->GetParent());
|
||||||
// End custom xml
|
// End custom xml
|
||||||
|
|
||||||
for (auto* data : item->GetConfig()) {
|
item->SaveConfigXml(*itemElement);
|
||||||
if (data->GetKey() != u"assemblyPartLOTs") {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* extraInfo = document.NewElement("x");
|
|
||||||
|
|
||||||
extraInfo->SetAttribute("ma", data->GetString(false).c_str());
|
|
||||||
|
|
||||||
itemElement->LinkEndChild(extraInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
bagElement->LinkEndChild(itemElement);
|
bagElement->LinkEndChild(itemElement);
|
||||||
}
|
}
|
||||||
@ -895,8 +875,6 @@ void InventoryComponent::UnEquipItem(Item* item) {
|
|||||||
|
|
||||||
RemoveSlot(item->GetInfo().equipLocation);
|
RemoveSlot(item->GetInfo().equipLocation);
|
||||||
|
|
||||||
PurgeProxies(item);
|
|
||||||
|
|
||||||
UnequipScripts(item);
|
UnequipScripts(item);
|
||||||
|
|
||||||
Game::entityManager->SerializeEntity(m_Parent);
|
Game::entityManager->SerializeEntity(m_Parent);
|
||||||
@ -906,6 +884,8 @@ void InventoryComponent::UnEquipItem(Item* item) {
|
|||||||
PropertyManagementComponent::Instance()->GetParent()->OnZonePropertyModelRemovedWhileEquipped(m_Parent);
|
PropertyManagementComponent::Instance()->GetParent()->OnZonePropertyModelRemovedWhileEquipped(m_Parent);
|
||||||
Game::zoneManager->GetZoneControlObject()->OnZonePropertyModelRemovedWhileEquipped(m_Parent);
|
Game::zoneManager->GetZoneControlObject()->OnZonePropertyModelRemovedWhileEquipped(m_Parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PurgeProxies(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1525,10 +1505,10 @@ void InventoryComponent::PurgeProxies(Item* item) {
|
|||||||
const auto root = item->GetParent();
|
const auto root = item->GetParent();
|
||||||
|
|
||||||
if (root != LWOOBJID_EMPTY) {
|
if (root != LWOOBJID_EMPTY) {
|
||||||
item = FindItemById(root);
|
Item* itemRoot = FindItemById(root);
|
||||||
|
|
||||||
if (item != nullptr) {
|
if (itemRoot != nullptr) {
|
||||||
UnEquipItem(item);
|
UnEquipItem(itemRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -1600,18 +1580,18 @@ void InventoryComponent::UpdatePetXml(tinyxml2::XMLDocument& document) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool InventoryComponent::SetSkill(int32_t slot, uint32_t skillId){
|
bool InventoryComponent::SetSkill(int32_t slot, uint32_t skillId) {
|
||||||
BehaviorSlot behaviorSlot = BehaviorSlot::Invalid;
|
BehaviorSlot behaviorSlot = BehaviorSlot::Invalid;
|
||||||
if (slot == 1 ) behaviorSlot = BehaviorSlot::Primary;
|
if (slot == 1) behaviorSlot = BehaviorSlot::Primary;
|
||||||
else if (slot == 2 ) behaviorSlot = BehaviorSlot::Offhand;
|
else if (slot == 2) behaviorSlot = BehaviorSlot::Offhand;
|
||||||
else if (slot == 3 ) behaviorSlot = BehaviorSlot::Neck;
|
else if (slot == 3) behaviorSlot = BehaviorSlot::Neck;
|
||||||
else if (slot == 4 ) behaviorSlot = BehaviorSlot::Head;
|
else if (slot == 4) behaviorSlot = BehaviorSlot::Head;
|
||||||
else if (slot == 5 ) behaviorSlot = BehaviorSlot::Consumable;
|
else if (slot == 5) behaviorSlot = BehaviorSlot::Consumable;
|
||||||
else return false;
|
else return false;
|
||||||
return SetSkill(behaviorSlot, skillId);
|
return SetSkill(behaviorSlot, skillId);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InventoryComponent::SetSkill(BehaviorSlot slot, uint32_t skillId){
|
bool InventoryComponent::SetSkill(BehaviorSlot slot, uint32_t skillId) {
|
||||||
if (skillId == 0) return false;
|
if (skillId == 0) return false;
|
||||||
const auto index = m_Skills.find(slot);
|
const auto index = m_Skills.find(slot);
|
||||||
if (index != m_Skills.end()) {
|
if (index != m_Skills.end()) {
|
||||||
@ -1623,4 +1603,3 @@ bool InventoryComponent::SetSkill(BehaviorSlot slot, uint32_t skillId){
|
|||||||
m_Skills.insert_or_assign(slot, skillId);
|
m_Skills.insert_or_assign(slot, skillId);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,8 @@
|
|||||||
#include "eGameMasterLevel.h"
|
#include "eGameMasterLevel.h"
|
||||||
#include "eMissionState.h"
|
#include "eMissionState.h"
|
||||||
#include "dNavMesh.h"
|
#include "dNavMesh.h"
|
||||||
|
#include "eGameActivity.h"
|
||||||
|
#include "eStateChangeType.h"
|
||||||
|
|
||||||
std::unordered_map<LWOOBJID, LWOOBJID> PetComponent::currentActivities{};
|
std::unordered_map<LWOOBJID, LWOOBJID> PetComponent::currentActivities{};
|
||||||
std::unordered_map<LWOOBJID, LWOOBJID> PetComponent::activePets{};
|
std::unordered_map<LWOOBJID, LWOOBJID> PetComponent::activePets{};
|
||||||
@ -210,24 +212,23 @@ void PetComponent::OnUse(Entity* originator) {
|
|||||||
if (dpWorld::IsLoaded()) {
|
if (dpWorld::IsLoaded()) {
|
||||||
NiPoint3 attempt = petPosition + forward * interactionDistance;
|
NiPoint3 attempt = petPosition + forward * interactionDistance;
|
||||||
|
|
||||||
float y = dpWorld::GetNavMesh()->GetHeightAtPoint(attempt);
|
NiPoint3 nearestPoint = dpWorld::GetNavMesh()->NearestPoint(attempt);
|
||||||
|
|
||||||
while (std::abs(y - petPosition.y) > 4 && interactionDistance > 10) {
|
while (std::abs(nearestPoint.y - petPosition.y) > 4 && interactionDistance > 10) {
|
||||||
const NiPoint3 forward = m_Parent->GetRotation().GetForwardVector();
|
const NiPoint3 forward = m_Parent->GetRotation().GetForwardVector();
|
||||||
|
|
||||||
attempt = originatorPosition + forward * interactionDistance;
|
attempt = originatorPosition + forward * interactionDistance;
|
||||||
|
|
||||||
y = dpWorld::GetNavMesh()->GetHeightAtPoint(attempt);
|
nearestPoint = dpWorld::GetNavMesh()->NearestPoint(attempt);
|
||||||
|
|
||||||
interactionDistance -= 0.5f;
|
interactionDistance -= 0.5f;
|
||||||
}
|
}
|
||||||
|
|
||||||
position = attempt;
|
position = nearestPoint;
|
||||||
} else {
|
} else {
|
||||||
position = petPosition + forward * interactionDistance;
|
position = petPosition + forward * interactionDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
auto rotation = NiQuaternion::LookAt(position, petPosition);
|
auto rotation = NiQuaternion::LookAt(position, petPosition);
|
||||||
|
|
||||||
GameMessages::SendNotifyPetTamingMinigame(
|
GameMessages::SendNotifyPetTamingMinigame(
|
||||||
@ -246,11 +247,11 @@ void PetComponent::OnUse(Entity* originator) {
|
|||||||
m_Parent->GetObjectID(),
|
m_Parent->GetObjectID(),
|
||||||
LWOOBJID_EMPTY,
|
LWOOBJID_EMPTY,
|
||||||
originator->GetObjectID(),
|
originator->GetObjectID(),
|
||||||
true,
|
false,
|
||||||
ePetTamingNotifyType::BEGIN,
|
ePetTamingNotifyType::BEGIN,
|
||||||
petPosition,
|
NiPoint3Constant::ZERO,
|
||||||
position,
|
NiPoint3Constant::ZERO,
|
||||||
rotation,
|
NiQuaternion(0.0f, 0.0f, 0.0f, 0.0f),
|
||||||
UNASSIGNED_SYSTEM_ADDRESS
|
UNASSIGNED_SYSTEM_ADDRESS
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -258,11 +259,18 @@ void PetComponent::OnUse(Entity* originator) {
|
|||||||
|
|
||||||
m_Tamer = originator->GetObjectID();
|
m_Tamer = originator->GetObjectID();
|
||||||
SetStatus(5);
|
SetStatus(5);
|
||||||
|
Game::entityManager->SerializeEntity(m_Parent);
|
||||||
|
|
||||||
currentActivities.insert_or_assign(m_Tamer, m_Parent->GetObjectID());
|
currentActivities.insert_or_assign(m_Tamer, m_Parent->GetObjectID());
|
||||||
|
|
||||||
// Notify the start of a pet taming minigame
|
// Notify the start of a pet taming minigame
|
||||||
m_Parent->GetScript()->OnNotifyPetTamingMinigame(m_Parent, originator, ePetTamingNotifyType::BEGIN);
|
m_Parent->GetScript()->OnNotifyPetTamingMinigame(m_Parent, originator, ePetTamingNotifyType::BEGIN);
|
||||||
|
|
||||||
|
auto* characterComponent = originator->GetComponent<CharacterComponent>();
|
||||||
|
if (characterComponent != nullptr) {
|
||||||
|
characterComponent->SetCurrentActivity(eGameActivity::PET_TAMING);
|
||||||
|
Game::entityManager->SerializeEntity(originator);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PetComponent::Update(float deltaTime) {
|
void PetComponent::Update(float deltaTime) {
|
||||||
@ -627,6 +635,11 @@ void PetComponent::RequestSetPetName(std::u16string name) {
|
|||||||
UNASSIGNED_SYSTEM_ADDRESS
|
UNASSIGNED_SYSTEM_ADDRESS
|
||||||
);
|
);
|
||||||
|
|
||||||
|
auto* characterComponent = tamer->GetComponent<CharacterComponent>();
|
||||||
|
if (characterComponent != nullptr) {
|
||||||
|
characterComponent->SetCurrentActivity(eGameActivity::NONE);
|
||||||
|
Game::entityManager->SerializeEntity(tamer);
|
||||||
|
}
|
||||||
GameMessages::SendTerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID());
|
GameMessages::SendTerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID());
|
||||||
|
|
||||||
auto* modelEntity = Game::entityManager->GetEntity(m_ModelId);
|
auto* modelEntity = Game::entityManager->GetEntity(m_ModelId);
|
||||||
@ -666,6 +679,11 @@ void PetComponent::ClientExitTamingMinigame(bool voluntaryExit) {
|
|||||||
UNASSIGNED_SYSTEM_ADDRESS
|
UNASSIGNED_SYSTEM_ADDRESS
|
||||||
);
|
);
|
||||||
|
|
||||||
|
auto* characterComponent = tamer->GetComponent<CharacterComponent>();
|
||||||
|
if (characterComponent != nullptr) {
|
||||||
|
characterComponent->SetCurrentActivity(eGameActivity::NONE);
|
||||||
|
Game::entityManager->SerializeEntity(tamer);
|
||||||
|
}
|
||||||
GameMessages::SendNotifyTamingModelLoadedOnServer(m_Tamer, tamer->GetSystemAddress());
|
GameMessages::SendNotifyTamingModelLoadedOnServer(m_Tamer, tamer->GetSystemAddress());
|
||||||
|
|
||||||
GameMessages::SendTerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID());
|
GameMessages::SendTerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID());
|
||||||
@ -712,6 +730,11 @@ void PetComponent::ClientFailTamingMinigame() {
|
|||||||
UNASSIGNED_SYSTEM_ADDRESS
|
UNASSIGNED_SYSTEM_ADDRESS
|
||||||
);
|
);
|
||||||
|
|
||||||
|
auto* characterComponent = tamer->GetComponent<CharacterComponent>();
|
||||||
|
if (characterComponent != nullptr) {
|
||||||
|
characterComponent->SetCurrentActivity(eGameActivity::NONE);
|
||||||
|
Game::entityManager->SerializeEntity(tamer);
|
||||||
|
}
|
||||||
GameMessages::SendNotifyTamingModelLoadedOnServer(m_Tamer, tamer->GetSystemAddress());
|
GameMessages::SendNotifyTamingModelLoadedOnServer(m_Tamer, tamer->GetSystemAddress());
|
||||||
|
|
||||||
GameMessages::SendTerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID());
|
GameMessages::SendTerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID());
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include "LeaderboardManager.h"
|
#include "LeaderboardManager.h"
|
||||||
#include "dZoneManager.h"
|
#include "dZoneManager.h"
|
||||||
#include "CDActivitiesTable.h"
|
#include "CDActivitiesTable.h"
|
||||||
|
#include "eStateChangeType.h"
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
|
||||||
#ifndef M_PI
|
#ifndef M_PI
|
||||||
@ -77,6 +78,9 @@ void RacingControlComponent::OnPlayerLoaded(Entity* player) {
|
|||||||
|
|
||||||
m_LoadedPlayers++;
|
m_LoadedPlayers++;
|
||||||
|
|
||||||
|
// not live accurate to stun the player but prevents them from using skills during the race that are not meant to be used.
|
||||||
|
GameMessages::SendSetStunned(player->GetObjectID(), eStateChangeType::PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true, true, true);
|
||||||
|
|
||||||
LOG("Loading player %i",
|
LOG("Loading player %i",
|
||||||
m_LoadedPlayers);
|
m_LoadedPlayers);
|
||||||
m_LobbyPlayers.push_back(player->GetObjectID());
|
m_LobbyPlayers.push_back(player->GetObjectID());
|
||||||
|
@ -38,7 +38,7 @@ bool SkillComponent::CastPlayerSkill(const uint32_t behaviorId, const uint32_t s
|
|||||||
|
|
||||||
context->skillID = skillID;
|
context->skillID = skillID;
|
||||||
|
|
||||||
this->m_managedBehaviors.insert_or_assign(skillUid, context);
|
this->m_managedBehaviors.insert({ skillUid, context });
|
||||||
|
|
||||||
auto* behavior = Behavior::CreateBehavior(behaviorId);
|
auto* behavior = Behavior::CreateBehavior(behaviorId);
|
||||||
|
|
||||||
@ -52,17 +52,24 @@ bool SkillComponent::CastPlayerSkill(const uint32_t behaviorId, const uint32_t s
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SkillComponent::SyncPlayerSkill(const uint32_t skillUid, const uint32_t syncId, RakNet::BitStream& bitStream) {
|
void SkillComponent::SyncPlayerSkill(const uint32_t skillUid, const uint32_t syncId, RakNet::BitStream& bitStream) {
|
||||||
const auto index = this->m_managedBehaviors.find(skillUid);
|
const auto index = this->m_managedBehaviors.equal_range(skillUid);
|
||||||
|
|
||||||
if (index == this->m_managedBehaviors.end()) {
|
if (index.first == this->m_managedBehaviors.end()) {
|
||||||
LOG("Failed to find skill with uid (%i)!", skillUid, syncId);
|
LOG("Failed to find skill with uid (%i)!", skillUid, syncId);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* context = index->second;
|
bool foundSyncId = false;
|
||||||
|
for (auto it = index.first; it != index.second && !foundSyncId; ++it) {
|
||||||
|
const auto& context = it->second;
|
||||||
|
|
||||||
context->SyncBehavior(syncId, bitStream);
|
foundSyncId = context->SyncBehavior(syncId, bitStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundSyncId) {
|
||||||
|
LOG("Failed to find sync id (%i) for skill with uid (%i)!", syncId, skillUid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -138,7 +145,7 @@ void SkillComponent::Update(const float deltaTime) {
|
|||||||
for (const auto& pair : this->m_managedBehaviors) pair.second->UpdatePlayerSyncs(deltaTime);
|
for (const auto& pair : this->m_managedBehaviors) pair.second->UpdatePlayerSyncs(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<uint32_t, BehaviorContext*> keep{};
|
std::multimap<uint32_t, BehaviorContext*> keep{};
|
||||||
|
|
||||||
for (const auto& pair : this->m_managedBehaviors) {
|
for (const auto& pair : this->m_managedBehaviors) {
|
||||||
auto* context = pair.second;
|
auto* context = pair.second;
|
||||||
@ -176,7 +183,7 @@ void SkillComponent::Update(const float deltaTime) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
keep.insert_or_assign(pair.first, context);
|
keep.insert({ pair.first, context });
|
||||||
}
|
}
|
||||||
|
|
||||||
this->m_managedBehaviors = keep;
|
this->m_managedBehaviors = keep;
|
||||||
@ -285,7 +292,7 @@ SkillExecutionResult SkillComponent::CalculateBehavior(
|
|||||||
return { false, 0 };
|
return { false, 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
this->m_managedBehaviors.insert_or_assign(context->skillUId, context);
|
this->m_managedBehaviors.insert({ context->skillUId, context });
|
||||||
|
|
||||||
if (!clientInitalized) {
|
if (!clientInitalized) {
|
||||||
// Echo start skill
|
// Echo start skill
|
||||||
|
@ -188,7 +188,7 @@ private:
|
|||||||
/**
|
/**
|
||||||
* All of the active skills mapped by their unique ID.
|
* All of the active skills mapped by their unique ID.
|
||||||
*/
|
*/
|
||||||
std::map<uint32_t, BehaviorContext*> m_managedBehaviors;
|
std::multimap<uint32_t, BehaviorContext*> m_managedBehaviors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All active projectiles.
|
* All active projectiles.
|
||||||
|
@ -76,8 +76,8 @@ void VendorComponent::RefreshInventory(bool isCreation) {
|
|||||||
if (vendorItems.empty()) break;
|
if (vendorItems.empty()) break;
|
||||||
auto randomItemIndex = GeneralUtils::GenerateRandomNumber<int32_t>(0, vendorItems.size() - 1);
|
auto randomItemIndex = GeneralUtils::GenerateRandomNumber<int32_t>(0, vendorItems.size() - 1);
|
||||||
const auto& randomItem = vendorItems.at(randomItemIndex);
|
const auto& randomItem = vendorItems.at(randomItemIndex);
|
||||||
vendorItems.erase(vendorItems.begin() + randomItemIndex);
|
|
||||||
if (SetupItem(randomItem.itemid)) m_Inventory.push_back(SoldItem(randomItem.itemid, randomItem.sortPriority));
|
if (SetupItem(randomItem.itemid)) m_Inventory.push_back(SoldItem(randomItem.itemid, randomItem.sortPriority));
|
||||||
|
vendorItems.erase(vendorItems.begin() + randomItemIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,9 +99,11 @@
|
|||||||
#include "ActivityManager.h"
|
#include "ActivityManager.h"
|
||||||
#include "PlayerManager.h"
|
#include "PlayerManager.h"
|
||||||
#include "eVendorTransactionResult.h"
|
#include "eVendorTransactionResult.h"
|
||||||
|
#include "eReponseMoveItemBetweenInventoryTypeCode.h"
|
||||||
|
|
||||||
#include "CDComponentsRegistryTable.h"
|
#include "CDComponentsRegistryTable.h"
|
||||||
#include "CDObjectsTable.h"
|
#include "CDObjectsTable.h"
|
||||||
|
#include "eItemType.h"
|
||||||
|
|
||||||
void GameMessages::SendFireEventClientSide(const LWOOBJID& objectID, const SystemAddress& sysAddr, std::u16string args, const LWOOBJID& object, int64_t param1, int param2, const LWOOBJID& sender) {
|
void GameMessages::SendFireEventClientSide(const LWOOBJID& objectID, const SystemAddress& sysAddr, std::u16string args, const LWOOBJID& object, int64_t param1, int param2, const LWOOBJID& sender) {
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
@ -412,7 +414,8 @@ void GameMessages::SendPlatformResync(Entity* entity, const SystemAddress& sysAd
|
|||||||
bitStream.Write(qUnexpectedRotation.w);
|
bitStream.Write(qUnexpectedRotation.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
SEND_PACKET_BROADCAST;
|
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST;
|
||||||
|
SEND_PACKET;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameMessages::SendRestoreToPostLoadStats(Entity* entity, const SystemAddress& sysAddr) {
|
void GameMessages::SendRestoreToPostLoadStats(Entity* entity, const SystemAddress& sysAddr) {
|
||||||
@ -4563,16 +4566,31 @@ void GameMessages::HandleRequestMoveItemBetweenInventoryTypes(RakNet::BitStream&
|
|||||||
if (inStream.ReadBit()) inStream.Read(itemLOT);
|
if (inStream.ReadBit()) inStream.Read(itemLOT);
|
||||||
|
|
||||||
if (invTypeDst == invTypeSrc) {
|
if (invTypeDst == invTypeSrc) {
|
||||||
|
SendResponseMoveItemBetweenInventoryTypes(entity->GetObjectID(), sysAddr, invTypeDst, invTypeSrc, eReponseMoveItemBetweenInventoryTypeCode::FAIL_GENERIC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* inventoryComponent = entity->GetComponent<InventoryComponent>();
|
auto* inventoryComponent = entity->GetComponent<InventoryComponent>();
|
||||||
|
|
||||||
if (inventoryComponent != nullptr) {
|
if (inventoryComponent) {
|
||||||
if (itemID != LWOOBJID_EMPTY) {
|
if (itemID != LWOOBJID_EMPTY) {
|
||||||
auto* item = inventoryComponent->FindItemById(itemID);
|
auto* item = inventoryComponent->FindItemById(itemID);
|
||||||
|
|
||||||
if (!item) return;
|
if (!item) {
|
||||||
|
SendResponseMoveItemBetweenInventoryTypes(entity->GetObjectID(), sysAddr, invTypeDst, invTypeSrc, eReponseMoveItemBetweenInventoryTypeCode::FAIL_ITEM_NOT_FOUND);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item->GetLot() == 6086) { // Thinking hat
|
||||||
|
SendResponseMoveItemBetweenInventoryTypes(entity->GetObjectID(), sysAddr, invTypeDst, invTypeSrc, eReponseMoveItemBetweenInventoryTypeCode::FAIL_CANT_MOVE_THINKING_HAT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* destInv = inventoryComponent->GetInventory(invTypeDst);
|
||||||
|
if (destInv && destInv->GetEmptySlots() == 0) {
|
||||||
|
SendResponseMoveItemBetweenInventoryTypes(entity->GetObjectID(), sysAddr, invTypeDst, invTypeSrc, eReponseMoveItemBetweenInventoryTypeCode::FAIL_INV_FULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Despawn the pet if we are moving that pet to the vault.
|
// Despawn the pet if we are moving that pet to the vault.
|
||||||
auto* petComponent = PetComponent::GetActivePet(entity->GetObjectID());
|
auto* petComponent = PetComponent::GetActivePet(entity->GetObjectID());
|
||||||
@ -4581,10 +4599,32 @@ void GameMessages::HandleRequestMoveItemBetweenInventoryTypes(RakNet::BitStream&
|
|||||||
}
|
}
|
||||||
|
|
||||||
inventoryComponent->MoveItemToInventory(item, invTypeDst, iStackCount, showFlyingLoot, false, false, destSlot);
|
inventoryComponent->MoveItemToInventory(item, invTypeDst, iStackCount, showFlyingLoot, false, false, destSlot);
|
||||||
|
SendResponseMoveItemBetweenInventoryTypes(entity->GetObjectID(), sysAddr, invTypeDst, invTypeSrc, eReponseMoveItemBetweenInventoryTypeCode::SUCCESS);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
SendResponseMoveItemBetweenInventoryTypes(entity->GetObjectID(), sysAddr, invTypeDst, invTypeSrc, eReponseMoveItemBetweenInventoryTypeCode::FAIL_GENERIC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameMessages::SendResponseMoveItemBetweenInventoryTypes(LWOOBJID objectId, const SystemAddress& sysAddr, eInventoryType inventoryTypeDestination, eInventoryType inventoryTypeSource, eReponseMoveItemBetweenInventoryTypeCode response) {
|
||||||
|
CBITSTREAM;
|
||||||
|
CMSGHEADER;
|
||||||
|
|
||||||
|
bitStream.Write(objectId);
|
||||||
|
bitStream.Write(eGameMessageType::RESPONSE_MOVE_ITEM_BETWEEN_INVENTORY_TYPES);
|
||||||
|
|
||||||
|
bitStream.Write(inventoryTypeDestination != eInventoryType::ITEMS);
|
||||||
|
if (inventoryTypeDestination != eInventoryType::ITEMS) bitStream.Write(inventoryTypeDestination);
|
||||||
|
|
||||||
|
bitStream.Write(inventoryTypeSource != eInventoryType::ITEMS);
|
||||||
|
if (inventoryTypeSource != eInventoryType::ITEMS) bitStream.Write(inventoryTypeSource);
|
||||||
|
|
||||||
|
bitStream.Write(response != eReponseMoveItemBetweenInventoryTypeCode::FAIL_GENERIC);
|
||||||
|
if (response != eReponseMoveItemBetweenInventoryTypeCode::FAIL_GENERIC) bitStream.Write(response);
|
||||||
|
|
||||||
|
SEND_PACKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void GameMessages::SendShowActivityCountdown(LWOOBJID objectId, bool bPlayAdditionalSound, bool bPlayCountdownSound, std::u16string sndName, int32_t stateToPlaySoundOn, const SystemAddress& sysAddr) {
|
void GameMessages::SendShowActivityCountdown(LWOOBJID objectId, bool bPlayAdditionalSound, bool bPlayCountdownSound, std::u16string sndName, int32_t stateToPlaySoundOn, const SystemAddress& sysAddr) {
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
@ -5351,7 +5391,8 @@ void GameMessages::HandleRemoveItemFromInventory(RakNet::BitStream& inStream, En
|
|||||||
iStackCount = std::min<uint32_t>(item->GetCount(), iStackCount);
|
iStackCount = std::min<uint32_t>(item->GetCount(), iStackCount);
|
||||||
|
|
||||||
if (bConfirmed) {
|
if (bConfirmed) {
|
||||||
if (eInvType == eInventoryType::MODELS) {
|
const auto itemType = static_cast<eItemType>(item->GetInfo().itemType);
|
||||||
|
if (itemType == eItemType::MODEL || itemType == eItemType::LOOT_MODEL) {
|
||||||
item->DisassembleModel(iStackCount);
|
item->DisassembleModel(iStackCount);
|
||||||
}
|
}
|
||||||
auto lot = item->GetLot();
|
auto lot = item->GetLot();
|
||||||
@ -6209,3 +6250,18 @@ void GameMessages::SendSlashCommandFeedbackText(Entity* entity, std::u16string t
|
|||||||
auto sysAddr = entity->GetSystemAddress();
|
auto sysAddr = entity->GetSystemAddress();
|
||||||
SEND_PACKET;
|
SEND_PACKET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameMessages::SendForceCameraTargetCycle(Entity* entity, bool bForceCycling, eCameraTargetCyclingMode cyclingMode, LWOOBJID optionalTargetID) {
|
||||||
|
CBITSTREAM;
|
||||||
|
CMSGHEADER;
|
||||||
|
|
||||||
|
bitStream.Write(entity->GetObjectID());
|
||||||
|
bitStream.Write(eGameMessageType::FORCE_CAMERA_TARGET_CYCLE);
|
||||||
|
bitStream.Write(bForceCycling);
|
||||||
|
bitStream.Write(cyclingMode != eCameraTargetCyclingMode::ALLOW_CYCLE_TEAMMATES);
|
||||||
|
if (cyclingMode != eCameraTargetCyclingMode::ALLOW_CYCLE_TEAMMATES) bitStream.Write(cyclingMode);
|
||||||
|
bitStream.Write(optionalTargetID);
|
||||||
|
|
||||||
|
auto sysAddr = entity->GetSystemAddress();
|
||||||
|
SEND_PACKET;
|
||||||
|
}
|
||||||
|
@ -39,6 +39,12 @@ 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;
|
enum class eVendorTransactionResult : uint32_t;
|
||||||
|
enum class eReponseMoveItemBetweenInventoryTypeCode : int32_t;
|
||||||
|
|
||||||
|
enum class eCameraTargetCyclingMode : int32_t {
|
||||||
|
ALLOW_CYCLE_TEAMMATES,
|
||||||
|
DISALLOW_CYCLING
|
||||||
|
};
|
||||||
|
|
||||||
namespace GameMessages {
|
namespace GameMessages {
|
||||||
class PropertyDataMessage;
|
class PropertyDataMessage;
|
||||||
@ -589,6 +595,7 @@ namespace GameMessages {
|
|||||||
//NT:
|
//NT:
|
||||||
|
|
||||||
void HandleRequestMoveItemBetweenInventoryTypes(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr);
|
void HandleRequestMoveItemBetweenInventoryTypes(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr);
|
||||||
|
void SendResponseMoveItemBetweenInventoryTypes(LWOOBJID objectId, const SystemAddress& sysAddr, eInventoryType inventoryTypeDestination, eInventoryType inventoryTypeSource, eReponseMoveItemBetweenInventoryTypeCode response);
|
||||||
|
|
||||||
void SendShowActivityCountdown(LWOOBJID objectId, bool bPlayAdditionalSound, bool bPlayCountdownSound, std::u16string sndName, int32_t stateToPlaySoundOn, const SystemAddress& sysAddr);
|
void SendShowActivityCountdown(LWOOBJID objectId, bool bPlayAdditionalSound, bool bPlayCountdownSound, std::u16string sndName, int32_t stateToPlaySoundOn, const SystemAddress& sysAddr);
|
||||||
|
|
||||||
@ -666,6 +673,7 @@ namespace GameMessages {
|
|||||||
void HandleCancelDonationOnPlayer(RakNet::BitStream& inStream, Entity* entity);
|
void HandleCancelDonationOnPlayer(RakNet::BitStream& inStream, Entity* entity);
|
||||||
|
|
||||||
void SendSlashCommandFeedbackText(Entity* entity, std::u16string text);
|
void SendSlashCommandFeedbackText(Entity* entity, std::u16string text);
|
||||||
|
void SendForceCameraTargetCycle(Entity* entity, bool bForceCycling, eCameraTargetCyclingMode cyclingMode, LWOOBJID optionalTargetID);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // GAMEMESSAGES_H
|
#endif // GAMEMESSAGES_H
|
||||||
|
@ -27,6 +27,23 @@
|
|||||||
#include "CDComponentsRegistryTable.h"
|
#include "CDComponentsRegistryTable.h"
|
||||||
#include "CDPackageComponentTable.h"
|
#include "CDPackageComponentTable.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const std::map<std::string, std::string> ExtraSettingAbbreviations = {
|
||||||
|
{ "assemblyPartLOTs", "ma" },
|
||||||
|
{ "blueprintID", "b" },
|
||||||
|
{ "userModelID", "ui" },
|
||||||
|
{ "userModelName", "un" },
|
||||||
|
{ "userModelDesc", "ud" },
|
||||||
|
{ "userModelHasBhvr", "ub" },
|
||||||
|
{ "userModelBehaviors", "ubh" },
|
||||||
|
{ "userModelBehaviorSourceID", "ubs" },
|
||||||
|
{ "userModelPhysicsType", "up" },
|
||||||
|
{ "userModelMod", "um" },
|
||||||
|
{ "userModelOpt", "uo" },
|
||||||
|
{ "reforgedLOT", "rl" },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
Item::Item(const LWOOBJID id, const LOT lot, Inventory* inventory, const uint32_t slot, const uint32_t count, const bool bound, const std::vector<LDFBaseData*>& config, const LWOOBJID parent, LWOOBJID subKey, eLootSourceType lootSourceType) {
|
Item::Item(const LWOOBJID id, const LOT lot, Inventory* inventory, const uint32_t slot, const uint32_t count, const bool bound, const std::vector<LDFBaseData*>& config, const LWOOBJID parent, LWOOBJID subKey, eLootSourceType lootSourceType) {
|
||||||
if (!Inventory::IsValidItem(lot)) {
|
if (!Inventory::IsValidItem(lot)) {
|
||||||
return;
|
return;
|
||||||
@ -122,6 +139,10 @@ uint32_t Item::GetSlot() const {
|
|||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<LDFBaseData*> Item::GetConfig() const {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<LDFBaseData*>& Item::GetConfig() {
|
std::vector<LDFBaseData*>& Item::GetConfig() {
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
@ -515,3 +536,35 @@ Item::~Item() {
|
|||||||
|
|
||||||
config.clear();
|
config.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Item::SaveConfigXml(tinyxml2::XMLElement& i) const {
|
||||||
|
tinyxml2::XMLElement* x = nullptr;
|
||||||
|
|
||||||
|
for (const auto* config : this->config) {
|
||||||
|
const auto& key = GeneralUtils::UTF16ToWTF8(config->GetKey());
|
||||||
|
const auto saveKey = ExtraSettingAbbreviations.find(key);
|
||||||
|
if (saveKey == ExtraSettingAbbreviations.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!x) {
|
||||||
|
x = i.InsertNewChildElement("x");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto dataToSave = config->GetString(false);
|
||||||
|
x->SetAttribute(saveKey->second.c_str(), dataToSave.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Item::LoadConfigXml(const tinyxml2::XMLElement& i) {
|
||||||
|
const auto* x = i.FirstChildElement("x");
|
||||||
|
if (!x) return;
|
||||||
|
|
||||||
|
for (const auto& pair : ExtraSettingAbbreviations) {
|
||||||
|
const auto* data = x->Attribute(pair.second.c_str());
|
||||||
|
if (!data) continue;
|
||||||
|
|
||||||
|
const auto value = pair.first + "=" + data;
|
||||||
|
config.push_back(LDFBaseData::DataFromString(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -9,6 +9,10 @@
|
|||||||
#include "eInventoryType.h"
|
#include "eInventoryType.h"
|
||||||
#include "eLootSourceType.h"
|
#include "eLootSourceType.h"
|
||||||
|
|
||||||
|
namespace tinyxml2 {
|
||||||
|
class XMLElement;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An item that can be stored in an inventory and optionally consumed or equipped
|
* An item that can be stored in an inventory and optionally consumed or equipped
|
||||||
* TODO: ideally this should be a component
|
* TODO: ideally this should be a component
|
||||||
@ -116,6 +120,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
std::vector<LDFBaseData*>& GetConfig();
|
std::vector<LDFBaseData*>& GetConfig();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns current config info for this item, e.g. for rockets
|
||||||
|
* @return current config info for this item
|
||||||
|
*/
|
||||||
|
std::vector<LDFBaseData*> GetConfig() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the database info for this item
|
* Returns the database info for this item
|
||||||
* @return the database info for this item
|
* @return the database info for this item
|
||||||
@ -214,6 +224,10 @@ public:
|
|||||||
*/
|
*/
|
||||||
void RemoveFromInventory();
|
void RemoveFromInventory();
|
||||||
|
|
||||||
|
void SaveConfigXml(tinyxml2::XMLElement& i) const;
|
||||||
|
|
||||||
|
void LoadConfigXml(const tinyxml2::XMLElement& i);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* The object ID of this item
|
* The object ID of this item
|
||||||
|
@ -454,6 +454,16 @@ void Mission::YieldRewards() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Even with no repeatable column, reputation is repeatable
|
||||||
|
if (info.reward_reputation > 0) {
|
||||||
|
missionComponent->Progress(eMissionTaskType::EARN_REPUTATION, 0, LWOOBJID_EMPTY, "", info.reward_reputation);
|
||||||
|
auto* const character = entity->GetComponent<CharacterComponent>();
|
||||||
|
if (character) {
|
||||||
|
character->SetReputation(character->GetReputation() + info.reward_reputation);
|
||||||
|
GameMessages::SendUpdateReputation(entity->GetObjectID(), character->GetReputation(), entity->GetSystemAddress());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (m_Completions > 0) {
|
if (m_Completions > 0) {
|
||||||
std::vector<std::pair<LOT, uint32_t>> items;
|
std::vector<std::pair<LOT, uint32_t>> items;
|
||||||
|
|
||||||
@ -532,15 +542,6 @@ void Mission::YieldRewards() {
|
|||||||
modelInventory->SetSize(modelInventory->GetSize() + info.reward_bankinventory);
|
modelInventory->SetSize(modelInventory->GetSize() + info.reward_bankinventory);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.reward_reputation > 0) {
|
|
||||||
missionComponent->Progress(eMissionTaskType::EARN_REPUTATION, 0, 0L, "", info.reward_reputation);
|
|
||||||
auto character = entity->GetComponent<CharacterComponent>();
|
|
||||||
if (character) {
|
|
||||||
character->SetReputation(character->GetReputation() + info.reward_reputation);
|
|
||||||
GameMessages::SendUpdateReputation(entity->GetObjectID(), character->GetReputation(), entity->GetSystemAddress());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info.reward_maxhealth > 0) {
|
if (info.reward_maxhealth > 0) {
|
||||||
destroyableComponent->SetMaxHealth(destroyableComponent->GetMaxHealth() + static_cast<float>(info.reward_maxhealth), true);
|
destroyableComponent->SetMaxHealth(destroyableComponent->GetMaxHealth() + static_cast<float>(info.reward_maxhealth), true);
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "SlashCommandHandler.h"
|
#include "SlashCommandHandler.h"
|
||||||
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
#include <ranges>
|
||||||
|
|
||||||
#include "DEVGMCommands.h"
|
#include "DEVGMCommands.h"
|
||||||
#include "GMGreaterThanZeroCommands.h"
|
#include "GMGreaterThanZeroCommands.h"
|
||||||
@ -30,7 +31,6 @@ void SlashCommandHandler::RegisterCommand(Command command) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& alias : command.aliases) {
|
for (const auto& alias : command.aliases) {
|
||||||
LOG_DEBUG("Registering command %s", alias.c_str());
|
|
||||||
auto [_, success] = RegisteredCommands.try_emplace(alias, command);
|
auto [_, success] = RegisteredCommands.try_emplace(alias, command);
|
||||||
// Don't allow duplicate commands
|
// Don't allow duplicate commands
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@ -60,11 +60,9 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& chat, Entity*
|
|||||||
if (commandHandle.requiredLevel > eGameMasterLevel::CIVILIAN) Database::Get()->InsertSlashCommandUsage(entity->GetObjectID(), input);
|
if (commandHandle.requiredLevel > eGameMasterLevel::CIVILIAN) Database::Get()->InsertSlashCommandUsage(entity->GetObjectID(), input);
|
||||||
commandHandle.handle(entity, sysAddr, args);
|
commandHandle.handle(entity, sysAddr, args);
|
||||||
} else if (entity->GetGMLevel() != eGameMasterLevel::CIVILIAN) {
|
} else if (entity->GetGMLevel() != eGameMasterLevel::CIVILIAN) {
|
||||||
// We don't need to tell civilians they aren't high enough level
|
|
||||||
error = "You are not high enough GM level to use \"" + command + "\"";
|
error = "You are not high enough GM level to use \"" + command + "\"";
|
||||||
}
|
}
|
||||||
} else if (entity->GetGMLevel() == eGameMasterLevel::CIVILIAN) {
|
} else if (entity->GetGMLevel() == eGameMasterLevel::CIVILIAN) {
|
||||||
// We don't need to tell civilians commands don't exist
|
|
||||||
error = "Command " + command + " does not exist!";
|
error = "Command " + command + " does not exist!";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,32 +73,74 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& chat, Entity*
|
|||||||
|
|
||||||
void GMZeroCommands::Help(Entity* entity, const SystemAddress& sysAddr, const std::string args) {
|
void GMZeroCommands::Help(Entity* entity, const SystemAddress& sysAddr, const std::string args) {
|
||||||
std::ostringstream feedback;
|
std::ostringstream feedback;
|
||||||
if (args.empty()) {
|
constexpr size_t pageSize = 10;
|
||||||
feedback << "----- Commands -----";
|
|
||||||
for (const auto& [alias, command] : CommandInfos) {
|
std::string trimmedArgs = args;
|
||||||
// TODO: Limit displaying commands based on GM level they require
|
trimmedArgs.erase(trimmedArgs.begin(), std::find_if_not(trimmedArgs.begin(), trimmedArgs.end(), [](unsigned char ch) {
|
||||||
if (command.requiredLevel > entity->GetGMLevel()) continue;
|
return std::isspace(ch);
|
||||||
LOG("Help command: %s", alias.c_str());
|
}));
|
||||||
feedback << "\n/" << alias << ": " << command.help;
|
trimmedArgs.erase(std::find_if_not(trimmedArgs.rbegin(), trimmedArgs.rend(), [](unsigned char ch) {
|
||||||
|
return std::isspace(ch);
|
||||||
|
}).base(), trimmedArgs.end());
|
||||||
|
|
||||||
|
std::optional<uint32_t> parsedPage = GeneralUtils::TryParse<uint32_t>(trimmedArgs);
|
||||||
|
if (trimmedArgs.empty() || parsedPage.has_value()) {
|
||||||
|
size_t page = parsedPage.value_or(1);
|
||||||
|
|
||||||
|
std::map<std::string, Command> accessibleCommands;
|
||||||
|
for (const auto& [commandName, command] : CommandInfos) {
|
||||||
|
if (command.requiredLevel <= entity->GetGMLevel()) {
|
||||||
|
accessibleCommands.emplace(commandName, command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t totalPages = (accessibleCommands.size() + pageSize - 1) / pageSize;
|
||||||
|
|
||||||
|
if (page < 1 || page > totalPages) {
|
||||||
|
feedback << "Invalid page number. Total pages: " << totalPages;
|
||||||
|
GameMessages::SendSlashCommandFeedbackText(entity, GeneralUtils::ASCIIToUTF16(feedback.str()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = accessibleCommands.begin();
|
||||||
|
std::advance(it, (page - 1) * pageSize);
|
||||||
|
size_t endIdx = std::min(page * pageSize, accessibleCommands.size());
|
||||||
|
|
||||||
|
feedback << "----- Commands (Page " << page << " of " << totalPages << ") -----";
|
||||||
|
for (size_t i = (page - 1) * pageSize; i < endIdx; ++i, ++it) {
|
||||||
|
feedback << "\n/" << it->first << ": " << it->second.help;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto feedbackStr = feedback.str();
|
||||||
|
if (!feedbackStr.empty()) {
|
||||||
|
GameMessages::SendSlashCommandFeedbackText(entity, GeneralUtils::ASCIIToUTF16(feedbackStr));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = std::ranges::find_if(CommandInfos, [&trimmedArgs](const auto& pair) {
|
||||||
|
return std::ranges::find(pair.second.aliases, trimmedArgs) != pair.second.aliases.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (it != CommandInfos.end() && entity->GetGMLevel() >= it->second.requiredLevel) {
|
||||||
|
const auto& command = it->second;
|
||||||
|
feedback << "----- " << it->first << " Info -----\n";
|
||||||
|
feedback << command.info << "\n";
|
||||||
|
if (command.aliases.size() > 1) {
|
||||||
|
feedback << "Aliases: ";
|
||||||
|
for (size_t i = 0; i < command.aliases.size(); ++i) {
|
||||||
|
if (i > 0) feedback << ", ";
|
||||||
|
feedback << command.aliases[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto it = CommandInfos.find(args);
|
feedback << "Command not found.";
|
||||||
if (it != CommandInfos.end() && entity->GetGMLevel() >= it->second.requiredLevel) {
|
|
||||||
feedback << "----- " << args << " -----\n";
|
|
||||||
feedback << it->second.info;
|
|
||||||
if (it->second.aliases.size() > 1) {
|
|
||||||
feedback << "\nAliases: ";
|
|
||||||
for (size_t i = 0; i < it->second.aliases.size(); i++) {
|
|
||||||
if (i > 0) feedback << ", ";
|
|
||||||
feedback << it->second.aliases[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (entity->GetGMLevel() > eGameMasterLevel::CIVILIAN) {
|
|
||||||
feedback << "Command " << std::quoted(args) << " does not exist!";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto feedbackStr = feedback.str();
|
const auto feedbackStr = feedback.str();
|
||||||
if (!feedbackStr.empty()) GameMessages::SendSlashCommandFeedbackText(entity, GeneralUtils::ASCIIToUTF16(feedbackStr));
|
if (!feedbackStr.empty()) {
|
||||||
|
GameMessages::SendSlashCommandFeedbackText(entity, GeneralUtils::ASCIIToUTF16(feedbackStr));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SlashCommandHandler::SendAnnouncement(const std::string& title, const std::string& message) {
|
void SlashCommandHandler::SendAnnouncement(const std::string& title, const std::string& message) {
|
||||||
@ -888,6 +928,15 @@ void SlashCommandHandler::Startup() {
|
|||||||
};
|
};
|
||||||
RegisterCommand(FindPlayerCommand);
|
RegisterCommand(FindPlayerCommand);
|
||||||
|
|
||||||
|
Command SpectateCommand{
|
||||||
|
.help = "Spectate a player",
|
||||||
|
.info = "Specify a player name to spectate. They must be in the same world as you. Leave blank to stop spectating",
|
||||||
|
.aliases = { "spectate", "follow" },
|
||||||
|
.handle = GMGreaterThanZeroCommands::Spectate,
|
||||||
|
.requiredLevel = eGameMasterLevel::JUNIOR_MODERATOR
|
||||||
|
};
|
||||||
|
RegisterCommand(SpectateCommand);
|
||||||
|
|
||||||
// Register GM Zero Commands
|
// Register GM Zero Commands
|
||||||
|
|
||||||
Command HelpCommand{
|
Command HelpCommand{
|
||||||
@ -1007,4 +1056,383 @@ void SlashCommandHandler::Startup() {
|
|||||||
};
|
};
|
||||||
RegisterCommand(InstanceInfoCommand);
|
RegisterCommand(InstanceInfoCommand);
|
||||||
|
|
||||||
|
//Commands that are handled by the client
|
||||||
|
|
||||||
|
Command faqCommand{
|
||||||
|
.help = "Show the LU FAQ Page",
|
||||||
|
.info = "Show the LU FAQ Page",
|
||||||
|
.aliases = {"faq","faqs"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(faqCommand);
|
||||||
|
|
||||||
|
Command teamChatCommand{
|
||||||
|
.help = "Send a message to your teammates.",
|
||||||
|
.info = "Send a message to your teammates.",
|
||||||
|
.aliases = {"team","t"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(teamChatCommand);
|
||||||
|
|
||||||
|
Command showStoreCommand{
|
||||||
|
.help = "Show the LEGO shop page.",
|
||||||
|
.info = "Show the LEGO shop page.",
|
||||||
|
.aliases = {"shop","store"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(showStoreCommand);
|
||||||
|
|
||||||
|
Command minigamesCommand{
|
||||||
|
.help = "Show the LEGO minigames page!",
|
||||||
|
.info = "Show the LEGO minigames page!",
|
||||||
|
.aliases = {"minigames"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(minigamesCommand);
|
||||||
|
|
||||||
|
Command forumsCommand{
|
||||||
|
.help = "Show the LU Forums!",
|
||||||
|
.info = "Show the LU Forums!",
|
||||||
|
.aliases = {"forums"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(forumsCommand);
|
||||||
|
|
||||||
|
Command exitGameCommand{
|
||||||
|
.help = "Exit to desktop",
|
||||||
|
.info = "Exit to desktop",
|
||||||
|
.aliases = {"exit","quit"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(exitGameCommand);
|
||||||
|
|
||||||
|
Command thumbsUpCommand{
|
||||||
|
.help = "Oh, yeah!",
|
||||||
|
.info = "Oh, yeah!",
|
||||||
|
.aliases = {"thumb","thumbs","thumbsup"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(thumbsUpCommand);
|
||||||
|
|
||||||
|
Command victoryCommand{
|
||||||
|
.help = "Victory!",
|
||||||
|
.info = "Victory!",
|
||||||
|
.aliases = {"victory!"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(victoryCommand);
|
||||||
|
|
||||||
|
Command backflipCommand{
|
||||||
|
.help = "Do a flip!",
|
||||||
|
.info = "Do a flip!",
|
||||||
|
.aliases = {"backflip"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(backflipCommand);
|
||||||
|
|
||||||
|
Command clapCommand{
|
||||||
|
.help = "A round of applause!",
|
||||||
|
.info = "A round of applause!",
|
||||||
|
.aliases = {"clap"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(clapCommand);
|
||||||
|
|
||||||
|
Command logoutCharacterCommand{
|
||||||
|
.help = "Returns you to the character select screen.",
|
||||||
|
.info = "Returns you to the character select screen.",
|
||||||
|
.aliases = {"camp","logoutcharacter"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(logoutCharacterCommand);
|
||||||
|
|
||||||
|
Command sayCommand{
|
||||||
|
.help = "Say something outloud so that everyone can hear you",
|
||||||
|
.info = "Say something outloud so that everyone can hear you",
|
||||||
|
.aliases = {"s","say"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(sayCommand);
|
||||||
|
|
||||||
|
Command whisperCommand{
|
||||||
|
.help = "Send a private message to another player.",
|
||||||
|
.info = "Send a private message to another player.",
|
||||||
|
.aliases = {"tell","w","whisper"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(whisperCommand);
|
||||||
|
|
||||||
|
Command locationCommand{
|
||||||
|
.help = "Output your current location on the map to the chat box.",
|
||||||
|
.info = "Output your current location on the map to the chat box.",
|
||||||
|
.aliases = {"loc","locate","location"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(locationCommand);
|
||||||
|
|
||||||
|
Command logoutCommand{
|
||||||
|
.help = "Returns you to the login screen.",
|
||||||
|
.info = "Returns you to the login screen.",
|
||||||
|
.aliases = {"logout","logoutaccount"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(logoutCommand);
|
||||||
|
|
||||||
|
Command shrugCommand{
|
||||||
|
.help = "I dunno...",
|
||||||
|
.info = "I dunno...",
|
||||||
|
.aliases = {"shrug"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(shrugCommand);
|
||||||
|
|
||||||
|
Command leaveTeamCommand{
|
||||||
|
.help = "Leave your current team.",
|
||||||
|
.info = "Leave your current team.",
|
||||||
|
.aliases = {"leave","leaveteam","teamleave","tleave"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(leaveTeamCommand);
|
||||||
|
|
||||||
|
Command teamLootTypeCommand{
|
||||||
|
.help = "[rr|ffa] Set the loot for your current team (round-robin/free for all).",
|
||||||
|
.info = "[rr|ffa] Set the loot for your current team (round-robin/free for all).",
|
||||||
|
.aliases = {"setloot","teamsetloot","tloot","tsetloot"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(teamLootTypeCommand);
|
||||||
|
|
||||||
|
Command removeFriendCommand{
|
||||||
|
.help = "[name] Removes a player from your friends list.",
|
||||||
|
.info = "[name] Removes a player from your friends list.",
|
||||||
|
.aliases = {"removefriend"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(removeFriendCommand);
|
||||||
|
|
||||||
|
Command yesCommand{
|
||||||
|
.help = "Aye aye, captain!",
|
||||||
|
.info = "Aye aye, captain!",
|
||||||
|
.aliases = {"yes"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(yesCommand);
|
||||||
|
|
||||||
|
Command teamInviteCommand{
|
||||||
|
.help = "[name] Invite a player to your team.",
|
||||||
|
.info = "[name] Invite a player to your team.",
|
||||||
|
.aliases = {"invite","inviteteam","teaminvite","tinvite"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(teamInviteCommand);
|
||||||
|
|
||||||
|
Command danceCommand{
|
||||||
|
.help = "Dance 'til you can't dance no more.",
|
||||||
|
.info = "Dance 'til you can't dance no more.",
|
||||||
|
.aliases = {"dance"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(danceCommand);
|
||||||
|
|
||||||
|
Command sighCommand{
|
||||||
|
.help = "Another day, another brick.",
|
||||||
|
.info = "Another day, another brick.",
|
||||||
|
.aliases = {"sigh"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(sighCommand);
|
||||||
|
|
||||||
|
Command recommendedOptionsCommand{
|
||||||
|
.help = "Sets the recommended performance options in the cfg file",
|
||||||
|
.info = "Sets the recommended performance options in the cfg file",
|
||||||
|
.aliases = {"recommendedperfoptions"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(recommendedOptionsCommand);
|
||||||
|
|
||||||
|
Command setTeamLeaderCommand{
|
||||||
|
.help = "[name] Set the leader for your current team.",
|
||||||
|
.info = "[name] Set the leader for your current team.",
|
||||||
|
.aliases = {"leader","setleader","teamsetleader","tleader","tsetleader"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(setTeamLeaderCommand);
|
||||||
|
|
||||||
|
Command cringeCommand{
|
||||||
|
.help = "I don't even want to talk about it...",
|
||||||
|
.info = "I don't even want to talk about it...",
|
||||||
|
.aliases = {"cringe"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(cringeCommand);
|
||||||
|
|
||||||
|
Command talkCommand{
|
||||||
|
.help = "Jibber Jabber",
|
||||||
|
.info = "Jibber Jabber",
|
||||||
|
.aliases = {"talk"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(talkCommand);
|
||||||
|
|
||||||
|
Command cancelQueueCommand{
|
||||||
|
.help = "Cancel Your position in the queue if you are in one.",
|
||||||
|
.info = "Cancel Your position in the queue if you are in one.",
|
||||||
|
.aliases = {"cancelqueue"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(cancelQueueCommand);
|
||||||
|
|
||||||
|
Command lowPerformanceCommand{
|
||||||
|
.help = "Sets the default low-spec performance options in the cfg file",
|
||||||
|
.info = "Sets the default low-spec performance options in the cfg file",
|
||||||
|
.aliases = {"perfoptionslow"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(lowPerformanceCommand);
|
||||||
|
|
||||||
|
Command kickFromTeamCommand{
|
||||||
|
.help = "[name] Kick a player from your current team.",
|
||||||
|
.info = "[name] Kick a player from your current team.",
|
||||||
|
.aliases = {"kick","kickplayer","teamkickplayer","tkick","tkickplayer"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(kickFromTeamCommand);
|
||||||
|
|
||||||
|
Command thanksCommand{
|
||||||
|
.help = "Express your gratitude for another.",
|
||||||
|
.info = "Express your gratitude for another.",
|
||||||
|
.aliases = {"thanks"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(thanksCommand);
|
||||||
|
|
||||||
|
Command waveCommand{
|
||||||
|
.help = "Wave to other players.",
|
||||||
|
.info = "Wave to other players.",
|
||||||
|
.aliases = {"wave"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(waveCommand);
|
||||||
|
|
||||||
|
Command whyCommand{
|
||||||
|
.help = "Why|!?!!",
|
||||||
|
.info = "Why|!?!!",
|
||||||
|
.aliases = {"why"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(whyCommand);
|
||||||
|
|
||||||
|
Command midPerformanceCommand{
|
||||||
|
.help = "Sets the default medium-spec performance options in the cfg file",
|
||||||
|
.info = "Sets the default medium-spec performance options in the cfg file",
|
||||||
|
.aliases = {"perfoptionsmid"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(midPerformanceCommand);
|
||||||
|
|
||||||
|
Command highPerformanceCommand{
|
||||||
|
.help = "Sets the default high-spec performance options in the cfg file",
|
||||||
|
.info = "Sets the default high-spec performance options in the cfg file",
|
||||||
|
.aliases = {"perfoptionshigh"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(highPerformanceCommand);
|
||||||
|
|
||||||
|
Command gaspCommand{
|
||||||
|
.help = "Oh my goodness!",
|
||||||
|
.info = "Oh my goodness!",
|
||||||
|
.aliases = {"gasp"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(gaspCommand);
|
||||||
|
|
||||||
|
Command ignoreCommand{
|
||||||
|
.help = "[name] Add a player to your ignore list.",
|
||||||
|
.info = "[name] Add a player to your ignore list.",
|
||||||
|
.aliases = {"addignore"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(ignoreCommand);
|
||||||
|
|
||||||
|
Command addFriendCommand{
|
||||||
|
.help = "[name] Add a player to your friends list.",
|
||||||
|
.info = "[name] Add a player to your friends list.",
|
||||||
|
.aliases = {"addfriend"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(addFriendCommand);
|
||||||
|
|
||||||
|
Command cryCommand{
|
||||||
|
.help = "Show everyone your 'Aw' face.",
|
||||||
|
.info = "Show everyone your 'Aw' face.",
|
||||||
|
.aliases = {"cry"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(cryCommand);
|
||||||
|
|
||||||
|
Command giggleCommand{
|
||||||
|
.help = "A good little chuckle",
|
||||||
|
.info = "A good little chuckle",
|
||||||
|
.aliases = {"giggle"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(giggleCommand);
|
||||||
|
|
||||||
|
Command saluteCommand{
|
||||||
|
.help = "For those about to build...",
|
||||||
|
.info = "For those about to build...",
|
||||||
|
.aliases = {"salute"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(saluteCommand);
|
||||||
|
|
||||||
|
Command removeIgnoreCommand{
|
||||||
|
.help = "[name] Removes a player from your ignore list.",
|
||||||
|
.info = "[name] Removes a player from your ignore list.",
|
||||||
|
.aliases = {"removeIgnore"},
|
||||||
|
.handle = GMZeroCommands::ClientHandled,
|
||||||
|
.requiredLevel = eGameMasterLevel::CIVILIAN
|
||||||
|
};
|
||||||
|
RegisterCommand(removeIgnoreCommand);
|
||||||
}
|
}
|
||||||
|
@ -322,4 +322,19 @@ namespace GMGreaterThanZeroCommands {
|
|||||||
request.Serialize(bitStream);
|
request.Serialize(bitStream);
|
||||||
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
|
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Spectate(Entity* entity, const SystemAddress& sysAddr, const std::string args) {
|
||||||
|
if (args.empty()) {
|
||||||
|
GameMessages::SendForceCameraTargetCycle(entity, false, eCameraTargetCyclingMode::DISALLOW_CYCLING, entity->GetObjectID());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto player = PlayerManager::GetPlayer(args);
|
||||||
|
if (!player) {
|
||||||
|
GameMessages::SendSlashCommandFeedbackText(entity, u"Player not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GameMessages::SendSlashCommandFeedbackText(entity, u"Spectating Player");
|
||||||
|
GameMessages::SendForceCameraTargetCycle(entity, false, eCameraTargetCyclingMode::DISALLOW_CYCLING, player->GetObjectID());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ namespace GMGreaterThanZeroCommands {
|
|||||||
void Title(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
void Title(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||||
void ShowAll(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
void ShowAll(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||||
void FindPlayer(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
void FindPlayer(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||||
|
void Spectate(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //!GMGREATERTHANZEROCOMMANDS_H
|
#endif //!GMGREATERTHANZEROCOMMANDS_H
|
||||||
|
@ -224,5 +224,9 @@ namespace GMZeroCommands {
|
|||||||
|
|
||||||
ChatPackets::SendSystemMessage(sysAddr, u"Map: " + (GeneralUtils::to_u16string(zoneId.GetMapID())) + u"\nClone: " + (GeneralUtils::to_u16string(zoneId.GetCloneID())) + u"\nInstance: " + (GeneralUtils::to_u16string(zoneId.GetInstanceID())));
|
ChatPackets::SendSystemMessage(sysAddr, u"Map: " + (GeneralUtils::to_u16string(zoneId.GetMapID())) + u"\nClone: " + (GeneralUtils::to_u16string(zoneId.GetCloneID())) + u"\nInstance: " + (GeneralUtils::to_u16string(zoneId.GetInstanceID())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//For client side commands
|
||||||
|
void ClientHandled(Entity* entity, const SystemAddress& sysAddr, const std::string args) {}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ namespace GMZeroCommands {
|
|||||||
void LeaveZone(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
void LeaveZone(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||||
void Resurrect(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
void Resurrect(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||||
void InstanceInfo(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
void InstanceInfo(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||||
|
void ClientHandled(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //!GMZEROCOMMANDS_H
|
#endif //!GMZEROCOMMANDS_H
|
||||||
|
@ -285,7 +285,6 @@ void ParseXml(const std::string& file) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (zoneID.value() != currentZoneID) {
|
if (zoneID.value() != currentZoneID) {
|
||||||
LOG_DEBUG("Skipping (%s) %i location because it is in %i and not the current zone (%i)", name, lot, zoneID.value(), currentZoneID);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
#include "BitStreamUtils.h"
|
#include "BitStreamUtils.h"
|
||||||
#include "Start.h"
|
#include "Start.h"
|
||||||
#include "Server.h"
|
#include "Server.h"
|
||||||
|
#include "CDZoneTableTable.h"
|
||||||
|
|
||||||
namespace Game {
|
namespace Game {
|
||||||
Logger* logger = nullptr;
|
Logger* logger = nullptr;
|
||||||
@ -277,6 +278,17 @@ int main(int argc, char** argv) {
|
|||||||
PersistentIDManager::Initialize();
|
PersistentIDManager::Initialize();
|
||||||
Game::im = new InstanceManager(Game::logger, Game::server->GetIP());
|
Game::im = new InstanceManager(Game::logger, Game::server->GetIP());
|
||||||
|
|
||||||
|
//Get CDClient initial information
|
||||||
|
try {
|
||||||
|
CDClientManager::LoadValuesFromDatabase();
|
||||||
|
} catch (CppSQLite3Exception& e) {
|
||||||
|
LOG("Failed to initialize CDServer SQLite Database");
|
||||||
|
LOG("May be caused by corrupted file: %s", (Game::assetManager->GetResPath() / "CDServer.sqlite").string().c_str());
|
||||||
|
LOG("Error: %s", e.errorMessage());
|
||||||
|
LOG("Error Code: %i", e.errorCode());
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
//Depending on the config, start up servers:
|
//Depending on the config, start up servers:
|
||||||
if (Game::config->GetValue("prestart_servers") != "0") {
|
if (Game::config->GetValue("prestart_servers") != "0") {
|
||||||
StartChatServer();
|
StartChatServer();
|
||||||
@ -382,6 +394,7 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HandlePacket(Packet* packet) {
|
void HandlePacket(Packet* packet) {
|
||||||
|
if (packet->length < 1) return;
|
||||||
if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION) {
|
if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION) {
|
||||||
LOG("A server has disconnected");
|
LOG("A server has disconnected");
|
||||||
|
|
||||||
|
@ -112,6 +112,31 @@ void dNavMesh::LoadNavmesh() {
|
|||||||
m_NavMesh = mesh;
|
m_NavMesh = mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NiPoint3 dNavMesh::NearestPoint(const NiPoint3& location, const float halfExtent) const {
|
||||||
|
NiPoint3 toReturn = location;
|
||||||
|
if (m_NavMesh != nullptr) {
|
||||||
|
float pos[3];
|
||||||
|
pos[0] = location.x;
|
||||||
|
pos[1] = location.y;
|
||||||
|
pos[2] = location.z;
|
||||||
|
|
||||||
|
dtPolyRef nearestRef = 0;
|
||||||
|
float polyPickExt[3] = { halfExtent, halfExtent, halfExtent };
|
||||||
|
float nearestPoint[3] = { 0.0f, 0.0f, 0.0f };
|
||||||
|
dtQueryFilter filter{};
|
||||||
|
|
||||||
|
auto hasPoly = m_NavQuery->findNearestPoly(pos, polyPickExt, &filter, &nearestRef, nearestPoint);
|
||||||
|
if (hasPoly != DT_SUCCESS) {
|
||||||
|
toReturn = location;
|
||||||
|
} else {
|
||||||
|
toReturn.x = nearestPoint[0];
|
||||||
|
toReturn.y = nearestPoint[1];
|
||||||
|
toReturn.z = nearestPoint[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
|
||||||
float dNavMesh::GetHeightAtPoint(const NiPoint3& location, const float halfExtentsHeight) const {
|
float dNavMesh::GetHeightAtPoint(const NiPoint3& location, const float halfExtentsHeight) const {
|
||||||
if (m_NavMesh == nullptr) {
|
if (m_NavMesh == nullptr) {
|
||||||
return location.y;
|
return location.y;
|
||||||
|
@ -29,7 +29,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
float GetHeightAtPoint(const NiPoint3& location, const float halfExtentsHeight = 32.0f) const;
|
float GetHeightAtPoint(const NiPoint3& location, const float halfExtentsHeight = 32.0f) const;
|
||||||
std::vector<NiPoint3> GetPath(const NiPoint3& startPos, const NiPoint3& endPos, float speed = 10.0f);
|
std::vector<NiPoint3> GetPath(const NiPoint3& startPos, const NiPoint3& endPos, float speed = 10.0f);
|
||||||
|
NiPoint3 NearestPoint(const NiPoint3& location, const float halfExtent = 32.0f) const;
|
||||||
bool IsNavmeshLoaded() { return m_NavMesh != nullptr; }
|
bool IsNavmeshLoaded() { return m_NavMesh != nullptr; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "MessageIdentifiers.h"
|
#include "MessageIdentifiers.h"
|
||||||
#include "BitStream.h"
|
#include "BitStream.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
enum class eConnectionType : uint16_t;
|
enum class eConnectionType : uint16_t;
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "SkillComponent.h"
|
#include "SkillComponent.h"
|
||||||
#include "eReplicaComponentType.h"
|
#include "eReplicaComponentType.h"
|
||||||
#include "RenderComponent.h"
|
#include "RenderComponent.h"
|
||||||
|
#include "PlayerManager.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -53,12 +54,14 @@ void BossSpiderQueenEnemyServer::OnStartup(Entity* self) {
|
|||||||
|
|
||||||
void BossSpiderQueenEnemyServer::OnDie(Entity* self, Entity* killer) {
|
void BossSpiderQueenEnemyServer::OnDie(Entity* self, Entity* killer) {
|
||||||
if (Game::zoneManager->GetZoneID().GetMapID() == instanceZoneID && killer) {
|
if (Game::zoneManager->GetZoneID().GetMapID() == instanceZoneID && killer) {
|
||||||
auto* missionComponent = killer->GetComponent<MissionComponent>();
|
for (const auto& player : PlayerManager::GetAllPlayers()) {
|
||||||
|
auto* missionComponent = player->GetComponent<MissionComponent>();
|
||||||
if (missionComponent == nullptr)
|
if (missionComponent == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
missionComponent->CompleteMission(instanceMissionID);
|
missionComponent->CompleteMission(instanceMissionID);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// There is suppose to be a 0.1 second delay here but that may be admitted?
|
// There is suppose to be a 0.1 second delay here but that may be admitted?
|
||||||
auto* controller = Game::entityManager->GetZoneControlEntity();
|
auto* controller = Game::entityManager->GetZoneControlEntity();
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "AgShipPlayerDeathTrigger.h"
|
#include "AgShipPlayerDeathTrigger.h"
|
||||||
#include "AgShipPlayerShockServer.h"
|
#include "AgShipPlayerShockServer.h"
|
||||||
#include "AgSpaceStuff.h"
|
#include "AgSpaceStuff.h"
|
||||||
|
#include "AgShipShake.h"
|
||||||
#include "AgImagSmashable.h"
|
#include "AgImagSmashable.h"
|
||||||
#include "NpcNpSpacemanBob.h"
|
#include "NpcNpSpacemanBob.h"
|
||||||
#include "StoryBoxInteractServer.h"
|
#include "StoryBoxInteractServer.h"
|
||||||
@ -341,6 +342,7 @@ namespace {
|
|||||||
{ "scripts\\ai\\AG\\L_AG_SHIP_PLAYER_DEATH_TRIGGER.lua", []() { return new AgShipPlayerDeathTrigger(); } },
|
{ "scripts\\ai\\AG\\L_AG_SHIP_PLAYER_DEATH_TRIGGER.lua", []() { return new AgShipPlayerDeathTrigger(); } },
|
||||||
{"scripts\\ai\\NP\\L_NPC_NP_SPACEMAN_BOB.lua", []() { return new NpcNpSpacemanBob(); } },
|
{"scripts\\ai\\NP\\L_NPC_NP_SPACEMAN_BOB.lua", []() { return new NpcNpSpacemanBob(); } },
|
||||||
{"scripts\\ai\\AG\\L_AG_SPACE_STUFF.lua", []() { return new AgSpaceStuff();} },
|
{"scripts\\ai\\AG\\L_AG_SPACE_STUFF.lua", []() { return new AgSpaceStuff();} },
|
||||||
|
{"scripts\\ai\\AG\\L_AG_SHIP_SHAKE.lua", []() { return new AgShipShake();}},
|
||||||
{"scripts\\ai\\AG\\L_AG_SHIP_PLAYER_SHOCK_SERVER.lua", []() { return new AgShipPlayerShockServer();} },
|
{"scripts\\ai\\AG\\L_AG_SHIP_PLAYER_SHOCK_SERVER.lua", []() { return new AgShipPlayerShockServer();} },
|
||||||
{"scripts\\ai\\AG\\L_AG_IMAG_SMASHABLE.lua", []() { return new AgImagSmashable();} },
|
{"scripts\\ai\\AG\\L_AG_IMAG_SMASHABLE.lua", []() { return new AgImagSmashable();} },
|
||||||
{"scripts\\02_server\\Map\\General\\L_STORY_BOX_INTERACT_SERVER.lua", []() { return new StoryBoxInteractServer();} },
|
{"scripts\\02_server\\Map\\General\\L_STORY_BOX_INTERACT_SERVER.lua", []() { return new StoryBoxInteractServer();} },
|
||||||
@ -580,6 +582,7 @@ namespace {
|
|||||||
{"scripts\\02_server\\Map\\AM\\L_SKULLKIN_DRILL_STAND.lua", []() {return new AmSkullkinDrillStand();}},
|
{"scripts\\02_server\\Map\\AM\\L_SKULLKIN_DRILL_STAND.lua", []() {return new AmSkullkinDrillStand();}},
|
||||||
{"scripts\\02_server\\Map\\AM\\L_SKULLKIN_TOWER.lua", []() {return new AmSkullkinTower();}},
|
{"scripts\\02_server\\Map\\AM\\L_SKULLKIN_TOWER.lua", []() {return new AmSkullkinTower();}},
|
||||||
{"scripts\\02_server\\Enemy\\AM\\L_AM_NAMED_DARKLING_DRAGON.lua", []() {return new AmDarklingDragon();}},
|
{"scripts\\02_server\\Enemy\\AM\\L_AM_NAMED_DARKLING_DRAGON.lua", []() {return new AmDarklingDragon();}},
|
||||||
|
{"scripts\\02_server\\Enemy\\AM\\L_AM_DARKLING_DRAGON.lua", []() {return new AmDarklingDragon();}},
|
||||||
{"scripts\\02_server\\Enemy\\AM\\L_AM_DARKLING_APE.lua", []() {return new BaseEnemyApe();}},
|
{"scripts\\02_server\\Enemy\\AM\\L_AM_DARKLING_APE.lua", []() {return new BaseEnemyApe();}},
|
||||||
{"scripts\\02_server\\Map\\AM\\L_BLUE_X.lua", []() {return new AmBlueX();}},
|
{"scripts\\02_server\\Map\\AM\\L_BLUE_X.lua", []() {return new AmBlueX();}},
|
||||||
{"scripts\\02_server\\Map\\AM\\L_TEAPOT_SERVER.lua", []() {return new AmTeapotServer();}},
|
{"scripts\\02_server\\Map\\AM\\L_TEAPOT_SERVER.lua", []() {return new AmTeapotServer();}},
|
||||||
@ -654,6 +657,7 @@ namespace {
|
|||||||
|
|
||||||
//Pickups
|
//Pickups
|
||||||
{"scripts\\ai\\SPEC\\L_SPECIAL_1_BRONZE-COIN-SPAWNER.lua", []() {return new SpecialCoinSpawner(1);}},
|
{"scripts\\ai\\SPEC\\L_SPECIAL_1_BRONZE-COIN-SPAWNER.lua", []() {return new SpecialCoinSpawner(1);}},
|
||||||
|
{"scripts\\ai\\SPEC\\L_SPECIAL_1_GOLD-COIN-SPAWNER.lua", []() {return new SpecialCoinSpawner(10000);}},
|
||||||
{"scripts\\ai\\SPEC\\L_SPECIAL_1_SILVER-COIN-SPAWNER.lua", []() {return new SpecialCoinSpawner(100);}},
|
{"scripts\\ai\\SPEC\\L_SPECIAL_1_SILVER-COIN-SPAWNER.lua", []() {return new SpecialCoinSpawner(100);}},
|
||||||
{"scripts\\ai\\SPEC\\L_SPECIAL_10_BRONZE-COIN-SPAWNER.lua", []() {return new SpecialCoinSpawner(10);}},
|
{"scripts\\ai\\SPEC\\L_SPECIAL_10_BRONZE-COIN-SPAWNER.lua", []() {return new SpecialCoinSpawner(10);}},
|
||||||
{"scripts\\ai\\SPEC\\L_SPECIAL_10_GOLD-COIN-SPAWNER.lua", []() {return new SpecialCoinSpawner(100000);}},
|
{"scripts\\ai\\SPEC\\L_SPECIAL_10_GOLD-COIN-SPAWNER.lua", []() {return new SpecialCoinSpawner(100000);}},
|
||||||
@ -700,7 +704,8 @@ CppScripts::Script* const CppScripts::GetScript(Entity* parent, const std::strin
|
|||||||
(scriptName == "scripts\\02_server\\Enemy\\General\\L_BASE_ENEMY_SPIDERLING.lua") ||
|
(scriptName == "scripts\\02_server\\Enemy\\General\\L_BASE_ENEMY_SPIDERLING.lua") ||
|
||||||
(scriptName == "scripts\\ai\\FV\\L_ACT_NINJA_STUDENT.lua") ||
|
(scriptName == "scripts\\ai\\FV\\L_ACT_NINJA_STUDENT.lua") ||
|
||||||
(scriptName == "scripts\\ai\\WILD\\L_WILD_GF_FROG.lua") ||
|
(scriptName == "scripts\\ai\\WILD\\L_WILD_GF_FROG.lua") ||
|
||||||
(scriptName == "scripts\\empty.lua")
|
(scriptName == "scripts\\empty.lua") ||
|
||||||
|
(scriptName == "scripts\\ai\\AG\\L_AG_SENTINEL_GUARD.lua")
|
||||||
)) LOG_DEBUG("LOT %i attempted to load CppScript for '%s', but returned InvalidScript.", parent->GetLOT(), scriptName.c_str());
|
)) LOG_DEBUG("LOT %i attempted to load CppScript for '%s', but returned InvalidScript.", parent->GetLOT(), scriptName.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
81
dScripts/ai/AG/AgShipShake.cpp
Normal file
81
dScripts/ai/AG/AgShipShake.cpp
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#include "AgShipShake.h"
|
||||||
|
#include "EntityInfo.h"
|
||||||
|
#include "GeneralUtils.h"
|
||||||
|
#include "GameMessages.h"
|
||||||
|
#include "EntityManager.h"
|
||||||
|
#include "RenderComponent.h"
|
||||||
|
#include "Entity.h"
|
||||||
|
|
||||||
|
void AgShipShake::OnStartup(Entity* self) {
|
||||||
|
EntityInfo info{};
|
||||||
|
|
||||||
|
info.pos = { -418, 585, -30 };
|
||||||
|
info.lot = 33;
|
||||||
|
info.spawnerID = self->GetObjectID();
|
||||||
|
|
||||||
|
auto* ref = Game::entityManager->CreateEntity(info);
|
||||||
|
|
||||||
|
Game::entityManager->ConstructEntity(ref);
|
||||||
|
|
||||||
|
self->SetVar(u"ShakeObject", ref->GetObjectID());
|
||||||
|
|
||||||
|
self->AddTimer("ShipShakeIdle", 2.0f);
|
||||||
|
self->SetVar(u"RandomTime", 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AgShipShake::OnTimerDone(Entity* self, std::string timerName) {
|
||||||
|
auto* shipFxObject = GetEntityInGroup(ShipFX);
|
||||||
|
auto* shipFxObject2 = GetEntityInGroup(ShipFX2);
|
||||||
|
auto* debrisObject = GetEntityInGroup(DebrisFX);
|
||||||
|
if (timerName == "ShipShakeIdle") {
|
||||||
|
auto* ref = Game::entityManager->GetEntity(self->GetVar<LWOOBJID>(u"ShakeObject"));
|
||||||
|
|
||||||
|
const auto randomTime = self->GetVar<int>(u"RandomTime");
|
||||||
|
auto time = GeneralUtils::GenerateRandomNumber<int>(0, randomTime + 1);
|
||||||
|
|
||||||
|
if (time < randomTime / 2) {
|
||||||
|
time += randomTime / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->AddTimer("ShipShakeIdle", static_cast<float>(time));
|
||||||
|
|
||||||
|
if (ref)
|
||||||
|
GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(ref, FXName, ref->GetObjectID(), 500.0f);
|
||||||
|
|
||||||
|
|
||||||
|
if (debrisObject)
|
||||||
|
GameMessages::SendPlayFXEffect(debrisObject, -1, u"DebrisFall", "Debris", LWOOBJID_EMPTY, 1.0f, 1.0f, true);
|
||||||
|
|
||||||
|
const auto randomFx = GeneralUtils::GenerateRandomNumber<int>(0, 3);
|
||||||
|
|
||||||
|
if (shipFxObject) {
|
||||||
|
std::string effectType = "shipboom" + std::to_string(randomFx);
|
||||||
|
GameMessages::SendPlayFXEffect(shipFxObject, 559, GeneralUtils::ASCIIToUTF16(effectType), "FX", LWOOBJID_EMPTY, 1.0f, 1.0f, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
self->AddTimer("ShipShakeExplode", 5.0f);
|
||||||
|
|
||||||
|
if (shipFxObject2)
|
||||||
|
RenderComponent::PlayAnimation(shipFxObject2, u"explosion");
|
||||||
|
} else if (timerName == "ShipShakeExplode") {
|
||||||
|
if (shipFxObject)
|
||||||
|
RenderComponent::PlayAnimation(shipFxObject, u"idle");
|
||||||
|
if (shipFxObject2)
|
||||||
|
RenderComponent::PlayAnimation(shipFxObject2, u"idle");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Entity* AgShipShake::GetEntityInGroup(const std::string& group) {
|
||||||
|
auto entities = Game::entityManager->GetEntitiesInGroup(group);
|
||||||
|
Entity* en = nullptr;
|
||||||
|
|
||||||
|
for (auto entity : entities) {
|
||||||
|
if (entity) {
|
||||||
|
en = entity;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return en;
|
||||||
|
}
|
||||||
|
|
16
dScripts/ai/AG/AgShipShake.h
Normal file
16
dScripts/ai/AG/AgShipShake.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "CppScripts.h"
|
||||||
|
|
||||||
|
class AgShipShake : public CppScripts::Script {
|
||||||
|
public:
|
||||||
|
void OnStartup(Entity* self) override;
|
||||||
|
void OnTimerDone(Entity* self, std::string timerName) override;
|
||||||
|
|
||||||
|
std::string DebrisFX = "DebrisFX";
|
||||||
|
std::string ShipFX = "ShipFX";
|
||||||
|
std::string ShipFX2 = "ShipFX2";
|
||||||
|
std::u16string FXName = u"camshake-bridge";
|
||||||
|
|
||||||
|
private:
|
||||||
|
Entity* GetEntityInGroup(const std::string& group);
|
||||||
|
};
|
@ -8,21 +8,6 @@
|
|||||||
|
|
||||||
void AgSpaceStuff::OnStartup(Entity* self) {
|
void AgSpaceStuff::OnStartup(Entity* self) {
|
||||||
self->AddTimer("FloaterScale", 5.0f);
|
self->AddTimer("FloaterScale", 5.0f);
|
||||||
|
|
||||||
EntityInfo info{};
|
|
||||||
|
|
||||||
info.pos = { -418, 585, -30 };
|
|
||||||
info.lot = 33;
|
|
||||||
info.spawnerID = self->GetObjectID();
|
|
||||||
|
|
||||||
auto* ref = Game::entityManager->CreateEntity(info);
|
|
||||||
|
|
||||||
Game::entityManager->ConstructEntity(ref);
|
|
||||||
|
|
||||||
self->SetVar(u"ShakeObject", ref->GetObjectID());
|
|
||||||
|
|
||||||
self->AddTimer("ShipShakeIdle", 2.0f);
|
|
||||||
self->SetVar(u"RandomTime", 10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AgSpaceStuff::OnTimerDone(Entity* self, std::string timerName) {
|
void AgSpaceStuff::OnTimerDone(Entity* self, std::string timerName) {
|
||||||
@ -37,70 +22,5 @@ void AgSpaceStuff::OnTimerDone(Entity* self, std::string timerName) {
|
|||||||
|
|
||||||
RenderComponent::PlayAnimation(self, u"path_0" + (GeneralUtils::to_u16string(pathType)));
|
RenderComponent::PlayAnimation(self, u"path_0" + (GeneralUtils::to_u16string(pathType)));
|
||||||
self->AddTimer("FloaterScale", randTime);
|
self->AddTimer("FloaterScale", randTime);
|
||||||
} else if (timerName == "ShipShakeExplode") {
|
|
||||||
DoShake(self, true);
|
|
||||||
} else if (timerName == "ShipShakeIdle") {
|
|
||||||
DoShake(self, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AgSpaceStuff::DoShake(Entity* self, bool explodeIdle) {
|
|
||||||
|
|
||||||
if (!explodeIdle) {
|
|
||||||
auto* ref = Game::entityManager->GetEntity(self->GetVar<LWOOBJID>(u"ShakeObject"));
|
|
||||||
|
|
||||||
const auto randomTime = self->GetVar<int>(u"RandomTime");
|
|
||||||
auto time = GeneralUtils::GenerateRandomNumber<int>(0, randomTime + 1);
|
|
||||||
|
|
||||||
if (time < randomTime / 2) {
|
|
||||||
time += randomTime / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
self->AddTimer("ShipShakeIdle", static_cast<float>(time));
|
|
||||||
|
|
||||||
if (ref)
|
|
||||||
GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(ref, FXName, ref->GetObjectID(), 500.0f);
|
|
||||||
|
|
||||||
auto* debrisObject = GetEntityInGroup(DebrisFX);
|
|
||||||
|
|
||||||
if (debrisObject)
|
|
||||||
GameMessages::SendPlayFXEffect(debrisObject, -1, u"DebrisFall", "Debris", LWOOBJID_EMPTY, 1.0f, 1.0f, true);
|
|
||||||
|
|
||||||
const auto randomFx = GeneralUtils::GenerateRandomNumber<int>(0, 3);
|
|
||||||
|
|
||||||
auto* shipFxObject = GetEntityInGroup(ShipFX);
|
|
||||||
if (shipFxObject) {
|
|
||||||
std::string effectType = "shipboom" + std::to_string(randomFx);
|
|
||||||
GameMessages::SendPlayFXEffect(shipFxObject, 559, GeneralUtils::ASCIIToUTF16(effectType), "FX", LWOOBJID_EMPTY, 1.0f, 1.0f, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
self->AddTimer("ShipShakeExplode", 5.0f);
|
|
||||||
|
|
||||||
auto* shipFxObject2 = GetEntityInGroup(ShipFX2);
|
|
||||||
if (shipFxObject2)
|
|
||||||
RenderComponent::PlayAnimation(shipFxObject2, u"explosion");
|
|
||||||
} else {
|
|
||||||
auto* shipFxObject = GetEntityInGroup(ShipFX);
|
|
||||||
auto* shipFxObject2 = GetEntityInGroup(ShipFX2);
|
|
||||||
|
|
||||||
if (shipFxObject)
|
|
||||||
RenderComponent::PlayAnimation(shipFxObject, u"idle");
|
|
||||||
|
|
||||||
if (shipFxObject2)
|
|
||||||
RenderComponent::PlayAnimation(shipFxObject2, u"idle");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Entity* AgSpaceStuff::GetEntityInGroup(const std::string& group) {
|
|
||||||
auto entities = Game::entityManager->GetEntitiesInGroup(group);
|
|
||||||
Entity* en = nullptr;
|
|
||||||
|
|
||||||
for (auto entity : entities) {
|
|
||||||
if (entity) {
|
|
||||||
en = entity;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return en;
|
|
||||||
}
|
|
||||||
|
@ -5,14 +5,5 @@ class AgSpaceStuff : public CppScripts::Script {
|
|||||||
public:
|
public:
|
||||||
void OnStartup(Entity* self);
|
void OnStartup(Entity* self);
|
||||||
void OnTimerDone(Entity* self, std::string timerName);
|
void OnTimerDone(Entity* self, std::string timerName);
|
||||||
void DoShake(Entity* self, bool explodeIdle);
|
|
||||||
|
|
||||||
std::string DebrisFX = "DebrisFX";
|
|
||||||
std::string ShipFX = "ShipFX";
|
|
||||||
std::string ShipFX2 = "ShipFX2";
|
|
||||||
std::u16string FXName = u"camshake-bridge";
|
|
||||||
|
|
||||||
private:
|
|
||||||
Entity* GetEntityInGroup(const std::string& group);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
set(DSCRIPTS_SOURCES_AI_AG
|
set(DSCRIPTS_SOURCES_AI_AG
|
||||||
"AgShipPlayerDeathTrigger.cpp"
|
"AgShipPlayerDeathTrigger.cpp"
|
||||||
"AgSpaceStuff.cpp"
|
"AgSpaceStuff.cpp"
|
||||||
|
"AgShipShake.cpp"
|
||||||
"AgShipPlayerShockServer.cpp"
|
"AgShipPlayerShockServer.cpp"
|
||||||
"AgImagSmashable.cpp"
|
"AgImagSmashable.cpp"
|
||||||
"ActSharkPlayerDeathTrigger.cpp"
|
"ActSharkPlayerDeathTrigger.cpp"
|
||||||
|
@ -529,6 +529,7 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HandlePacketChat(Packet* packet) {
|
void HandlePacketChat(Packet* packet) {
|
||||||
|
if (packet->length < 1) return;
|
||||||
if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) {
|
if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) {
|
||||||
LOG("Lost our connection to chat, zone(%i), instance(%i)", Game::server->GetZoneID(), Game::server->GetInstanceID());
|
LOG("Lost our connection to chat, zone(%i), instance(%i)", Game::server->GetZoneID(), Game::server->GetInstanceID());
|
||||||
|
|
||||||
@ -542,7 +543,7 @@ void HandlePacketChat(Packet* packet) {
|
|||||||
chatConnected = true;
|
chatConnected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packet->data[0] == ID_USER_PACKET_ENUM) {
|
if (packet->data[0] == ID_USER_PACKET_ENUM && packet->length >= 4) {
|
||||||
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT) {
|
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT) {
|
||||||
switch (static_cast<eChatMessageType>(packet->data[3])) {
|
switch (static_cast<eChatMessageType>(packet->data[3])) {
|
||||||
case eChatMessageType::WORLD_ROUTE_PACKET: {
|
case eChatMessageType::WORLD_ROUTE_PACKET: {
|
||||||
@ -557,8 +558,9 @@ void HandlePacketChat(Packet* packet) {
|
|||||||
|
|
||||||
//Write our stream outwards:
|
//Write our stream outwards:
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
for (BitSize_t i = 0; i < inStream.GetNumberOfBytesUsed(); i++) {
|
unsigned char data;
|
||||||
bitStream.Write(packet->data[i + 16]); //16 bytes == header + playerID to skip
|
while (inStream.Read(data)) {
|
||||||
|
bitStream.Write(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
SEND_PACKET; //send routed packet to player
|
SEND_PACKET; //send routed packet to player
|
||||||
@ -659,7 +661,7 @@ void HandlePacketChat(Packet* packet) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HandleMasterPacket(Packet* packet) {
|
void HandleMasterPacket(Packet* packet) {
|
||||||
|
if (packet->length < 2) return;
|
||||||
if (static_cast<eConnectionType>(packet->data[1]) != eConnectionType::MASTER || packet->length < 4) return;
|
if (static_cast<eConnectionType>(packet->data[1]) != eConnectionType::MASTER || packet->length < 4) return;
|
||||||
switch (static_cast<eMasterMessageType>(packet->data[3])) {
|
switch (static_cast<eMasterMessageType>(packet->data[3])) {
|
||||||
case eMasterMessageType::REQUEST_PERSISTENT_ID_RESPONSE: {
|
case eMasterMessageType::REQUEST_PERSISTENT_ID_RESPONSE: {
|
||||||
@ -785,6 +787,7 @@ void HandleMasterPacket(Packet* packet) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HandlePacket(Packet* packet) {
|
void HandlePacket(Packet* packet) {
|
||||||
|
if (packet->length < 1) return;
|
||||||
if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) {
|
if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) {
|
||||||
auto user = UserManager::Instance()->GetUser(packet->systemAddress);
|
auto user = UserManager::Instance()->GetUser(packet->systemAddress);
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
@ -1207,8 +1210,8 @@ void HandlePacket(Packet* packet) {
|
|||||||
|
|
||||||
//Now write the rest of the data:
|
//Now write the rest of the data:
|
||||||
auto data = inStream.GetData();
|
auto data = inStream.GetData();
|
||||||
for (uint32_t i = 0; i < size; ++i) {
|
for (uint32_t i = 23; i - 23 < size && i < packet->length; ++i) {
|
||||||
bitStream.Write(data[i + 23]);
|
bitStream.Write(data[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE_ORDERED, 0, Game::chatSysAddr, false);
|
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE_ORDERED, 0, Game::chatSysAddr, false);
|
||||||
|
5
thirdparty/CMakeLists.txt
vendored
5
thirdparty/CMakeLists.txt
vendored
@ -23,6 +23,11 @@ if(NOT WIN32)
|
|||||||
target_include_directories(bcrypt PRIVATE "libbcrypt/include/bcrypt")
|
target_include_directories(bcrypt PRIVATE "libbcrypt/include/bcrypt")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Need to define this on Clang and GNU for 'strdup' support
|
||||||
|
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
|
||||||
|
target_compile_definitions(bcrypt PRIVATE "_POSIX_C_SOURCE=200809L")
|
||||||
|
endif()
|
||||||
|
|
||||||
target_include_directories(bcrypt INTERFACE "libbcrypt/include")
|
target_include_directories(bcrypt INTERFACE "libbcrypt/include")
|
||||||
target_include_directories(bcrypt PRIVATE "libbcrypt/src")
|
target_include_directories(bcrypt PRIVATE "libbcrypt/src")
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user