mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-11-22 13:37:22 +00:00
Merge remote-tracking branch 'upstream/main' into bbbfix
This commit is contained in:
commit
caffa94141
37
README.md
37
README.md
@ -27,11 +27,11 @@ Darkflame Universe is a server emulator and does not distribute any LEGO® Unive
|
||||
Development of the latest iteration of Darkflame Universe has been done primarily in a Unix-like environment and is where it has been tested and designed for deployment. It is therefore highly recommended that Darkflame Universe be built and deployed using a Unix-like environment for the most streamlined experience.
|
||||
|
||||
### Prerequisites
|
||||
**Clone the repository**
|
||||
#### Clone the repository
|
||||
```bash
|
||||
git clone --recursive https://github.com/DarkflameUniverse/DarkflameServer
|
||||
```
|
||||
**Python**
|
||||
#### Python
|
||||
|
||||
Some tools utilized to streamline the setup process require Python 3, make sure you have it installed.
|
||||
|
||||
@ -52,7 +52,7 @@ Make sure packages like `gcc`, `cmake`, and `zlib` are installed. Depending on t
|
||||
|
||||
CMake must be version 3.14 or higher!
|
||||
|
||||
**Build the repository**
|
||||
#### Build the repository
|
||||
|
||||
You can either run `build.sh` when in the root folder of the repository:
|
||||
|
||||
@ -70,8 +70,8 @@ cd build
|
||||
# Run CMake to generate make files
|
||||
cmake ..
|
||||
|
||||
# Run make to build the project. To build utilizing multiple cores, append `-j` and the amount of cores to utilize, for example `make -j8`
|
||||
make
|
||||
# To build utilizing multiple cores, append `-j` and the amount of cores to utilize, for example `cmake --build . --config Release -j8'
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
### MacOS builds
|
||||
@ -93,7 +93,7 @@ cmake --build . --config Release
|
||||
### Windows builds (native)
|
||||
Ensure that you have either the [MSVC](https://visualstudio.microsoft.com/vs/) or the [Clang](https://github.com/llvm/llvm-project/releases/) (recommended) compiler installed. You will also need to install [CMake](https://cmake.org/download/). Currently on native Windows the server will only work in Release mode.
|
||||
|
||||
**Build the repository**
|
||||
#### Build the repository
|
||||
```batch
|
||||
:: Create the build directory
|
||||
mkdir build
|
||||
@ -105,7 +105,7 @@ cmake ..
|
||||
:: Run CMake with build flag to build
|
||||
cmake --build . --config Release
|
||||
```
|
||||
**Windows for ARM** has not been tested but should build by doing the following
|
||||
#### Windows for ARM has not been tested but should build by doing the following
|
||||
```batch
|
||||
:: Create the build directory
|
||||
mkdir build
|
||||
@ -121,13 +121,13 @@ cmake --build . --config Release
|
||||
### Windows builds (WSL)
|
||||
This section will go through how to install [WSL](https://docs.microsoft.com/en-us/windows/wsl/install) and building in a Linux environment under Windows. WSL requires Windows 10 version 2004 and higher (Build 19041 and higher) or Windows 11.
|
||||
|
||||
**Open the Command Prompt application with Administrator permissions and run the following:**
|
||||
#### Open the Command Prompt application with Administrator permissions and run the following:
|
||||
```bash
|
||||
# Installing Windows Subsystem for Linux
|
||||
wsl --install
|
||||
```
|
||||
|
||||
**Open the Ubuntu application and run the following:**
|
||||
#### Open the Ubuntu application and run the following:
|
||||
```bash
|
||||
# Make sure the install is up to date
|
||||
apt update && apt upgrade
|
||||
@ -159,7 +159,7 @@ now follow the build section for your system
|
||||
|
||||
### Resources
|
||||
|
||||
**LEGO® Universe 1.10.64**
|
||||
#### LEGO® Universe 1.10.64
|
||||
|
||||
This repository does not distribute any LEGO® Universe files. A full install of LEGO® Universe version 1.10.64 (latest) is required to finish setting up Darkflame Universe.
|
||||
|
||||
@ -182,20 +182,20 @@ shasum -a 256 <file>
|
||||
certutil -hashfile <file> SHA256
|
||||
```
|
||||
|
||||
**Unpacking the client**
|
||||
#### Unpacking the client
|
||||
* Clone lcdr's utilities repository [here](https://github.com/lcdr/utils)
|
||||
* Use `pkextractor.pyw` to unpack the client files if they are not already unpacked
|
||||
|
||||
**Setup resource directory**
|
||||
#### Setup resource directory
|
||||
* In the `build` directory create a `res` directory if it does not already exist.
|
||||
* Copy over or create symlinks from `macros`, `BrickModels`, `chatplus_en_us.txt`, `names`, and `maps` in your client `res` directory to the server `build/res` directory
|
||||
* Unzip the navmeshes [here](./resources/navmeshes.zip) and place them in `build/res/maps/navmeshes`
|
||||
|
||||
**Setup locale**
|
||||
#### Setup locale
|
||||
* In the `build` directory create a `locale` directory if it does not already exist
|
||||
* Copy over or create symlinks from `locale.xml` in your client `locale` directory to the `build/locale` directory
|
||||
|
||||
**Client database**
|
||||
#### Client database
|
||||
* Use `fdb_to_sqlite.py` in lcdr's utilities on `res/cdclient.fdb` in the unpacked client to convert the client database to `cdclient.sqlite`
|
||||
* Move and rename `cdclient.sqlite` into `build/res/CDServer.sqlite`
|
||||
* Run each SQL file in the order at which they appear [here](migrations/cdserver/) on the SQLite database
|
||||
@ -205,13 +205,16 @@ Darkflame Universe utilizes a MySQL/MariaDB database for account and character i
|
||||
|
||||
Initial setup can vary drastically based on which operating system or distribution you are running; there are instructions out there for most setups, follow those and come back here when you have a database up and running.
|
||||
* Create a database for Darkflame Universe to use
|
||||
* Use the command `./MasterServer -m` to automatically run them.
|
||||
|
||||
**Configuration**
|
||||
#### Configuration
|
||||
|
||||
After the server has been built there should be four `ini` files in the build director: `authconfig.ini`, `chatconfig.ini`, `masterconfig.ini`, and `worldconfig.ini`. Go through them and fill in the database credentials and configure other settings if necessary.
|
||||
|
||||
**Verify**
|
||||
#### Setup and Migrations
|
||||
|
||||
Use the command `./MasterServer -m` to setup the tables in the database. The first time this command is run on a database, the tables will be up to date with the most recent version. To update your database tables, run this command again. Multiple invocations will not affect any functionality.
|
||||
|
||||
#### Verify
|
||||
|
||||
Your build directory should now look like this:
|
||||
* AuthServer
|
||||
|
14
dCommon/eUnequippableActiveType.h
Normal file
14
dCommon/eUnequippableActiveType.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef __EUNEQUIPPABLEACTIVETYPE__H__
|
||||
#define __EUNEQUIPPABLEACTIVETYPE__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class eUnequippableActiveType : int32_t {
|
||||
INVALID = -1,
|
||||
PET = 0,
|
||||
MOUNT
|
||||
};
|
||||
|
||||
#endif //!__EUNEQUIPPABLEACTIVETYPE__H__
|
@ -45,7 +45,7 @@ CDItemComponentTable::CDItemComponentTable(void) {
|
||||
entry.offsetGroupID = tableData.getIntField(19, -1);
|
||||
entry.buildTypes = tableData.getIntField(20, -1);
|
||||
entry.reqPrecondition = tableData.getStringField(21, "");
|
||||
entry.animationFlag = tableData.getIntField(22, -1);
|
||||
entry.animationFlag = tableData.getIntField(22, 0);
|
||||
entry.equipEffects = tableData.getIntField(23, -1);
|
||||
entry.readyForQA = tableData.getIntField(24, -1) == 1 ? true : false;
|
||||
entry.itemRating = tableData.getIntField(25, -1);
|
||||
@ -123,7 +123,7 @@ const CDItemComponent& CDItemComponentTable::GetItemComponentByID(unsigned int s
|
||||
entry.offsetGroupID = tableData.getIntField(19, -1);
|
||||
entry.buildTypes = tableData.getIntField(20, -1);
|
||||
entry.reqPrecondition = tableData.getStringField(21, "");
|
||||
entry.animationFlag = tableData.getIntField(22, -1);
|
||||
entry.animationFlag = tableData.getIntField(22, 0);
|
||||
entry.equipEffects = tableData.getIntField(23, -1);
|
||||
entry.readyForQA = tableData.getIntField(24, -1) == 1 ? true : false;
|
||||
entry.itemRating = tableData.getIntField(25, -1);
|
||||
|
@ -1454,6 +1454,13 @@ void Entity::Smash(const LWOOBJID source, const eKillType killType, const std::u
|
||||
Kill(EntityManager::Instance()->GetEntity(source));
|
||||
return;
|
||||
}
|
||||
auto* possessorComponent = GetComponent<PossessorComponent>();
|
||||
if (possessorComponent) {
|
||||
if (possessorComponent->GetPossessable() != LWOOBJID_EMPTY) {
|
||||
auto* mount = EntityManager::Instance()->GetEntity(possessorComponent->GetPossessable());
|
||||
if (mount) possessorComponent->Dismount(mount, true);
|
||||
}
|
||||
}
|
||||
|
||||
destroyableComponent->Smash(source, killType, deathType);
|
||||
}
|
||||
|
@ -167,18 +167,6 @@ public:
|
||||
*/
|
||||
void SetLastRocketItemID(LWOOBJID lastRocketItemID) { m_LastRocketItemID = lastRocketItemID; }
|
||||
|
||||
/**
|
||||
* Gets the object ID of the mount item that is being used
|
||||
* @return the object ID of the mount item that is being used
|
||||
*/
|
||||
LWOOBJID GetMountItemID() const { return m_MountItemID; }
|
||||
|
||||
/**
|
||||
* Sets the object ID of the mount item that is being used
|
||||
* @param m_MountItemID the object ID of the mount item that is being used
|
||||
*/
|
||||
void SetMountItemID(LWOOBJID mountItemID) { m_MountItemID = mountItemID; }
|
||||
|
||||
/**
|
||||
* Gets the name of this character
|
||||
* @return the name of this character
|
||||
@ -569,11 +557,6 @@ private:
|
||||
* ID of the last rocket used
|
||||
*/
|
||||
LWOOBJID m_LastRocketItemID = LWOOBJID_EMPTY;
|
||||
|
||||
/**
|
||||
* Mount Item ID
|
||||
*/
|
||||
LWOOBJID m_MountItemID = LWOOBJID_EMPTY;
|
||||
};
|
||||
|
||||
#endif // CHARACTERCOMPONENT_H
|
||||
|
@ -32,6 +32,7 @@ ControllablePhysicsComponent::ControllablePhysicsComponent(Entity* entity) : Com
|
||||
m_IgnoreMultipliers = false;
|
||||
m_PickupRadius = 0.0f;
|
||||
m_DirtyPickupRadiusScale = true;
|
||||
m_IsTeleporting = false;
|
||||
|
||||
if (entity->GetLOT() != 1) // Other physics entities we care about will be added by BaseCombatAI
|
||||
return;
|
||||
@ -128,7 +129,10 @@ void ControllablePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bo
|
||||
outBitStream->Write0();
|
||||
}
|
||||
|
||||
if (!bIsInitialUpdate) outBitStream->Write0();
|
||||
if (!bIsInitialUpdate) {
|
||||
outBitStream->Write(m_IsTeleporting);
|
||||
m_IsTeleporting = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ControllablePhysicsComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
|
||||
|
@ -220,6 +220,18 @@ public:
|
||||
*/
|
||||
bool GetStatic() const { return m_Static; }
|
||||
|
||||
/**
|
||||
* Sets if the entity is Teleporting,
|
||||
* @param value whether or not the entity is Is Teleporting
|
||||
*/
|
||||
void SetIsTeleporting(const bool value) { m_IsTeleporting = value; }
|
||||
|
||||
/**
|
||||
* Returns whether or not this entity is currently is teleporting
|
||||
* @return whether or not this entity is currently is teleporting
|
||||
*/
|
||||
bool GetIsTeleporting() const { return m_IsTeleporting; }
|
||||
|
||||
/**
|
||||
* Returns the Physics entity for the component
|
||||
* @return Physics entity for the component
|
||||
@ -355,6 +367,11 @@ private:
|
||||
* The active pickup radius for this entity
|
||||
*/
|
||||
float m_PickupRadius;
|
||||
|
||||
/**
|
||||
* If the entity is teleporting
|
||||
*/
|
||||
bool m_IsTeleporting;
|
||||
};
|
||||
|
||||
#endif // CONTROLLABLEPHYSICSCOMPONENT_H
|
||||
|
@ -26,6 +26,8 @@
|
||||
|
||||
#include "MissionComponent.h"
|
||||
#include "CharacterComponent.h"
|
||||
#include "PossessableComponent.h"
|
||||
#include "PossessorComponent.h"
|
||||
#include "dZoneManager.h"
|
||||
|
||||
DestroyableComponent::DestroyableComponent(Entity* parent) : Component(parent) {
|
||||
@ -608,6 +610,24 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32
|
||||
SetHealth(health);
|
||||
SetIsShielded(absorb > 0);
|
||||
|
||||
// Dismount on the possessable hit
|
||||
auto possessable = m_Parent->GetComponent<PossessableComponent>();
|
||||
if (possessable && possessable->GetDepossessOnHit()) {
|
||||
possessable->Dismount();
|
||||
}
|
||||
|
||||
// Dismount on the possessor hit
|
||||
auto possessor = m_Parent->GetComponent<PossessorComponent>();
|
||||
if (possessor) {
|
||||
auto possessableId = possessor->GetPossessable();
|
||||
if (possessableId != LWOOBJID_EMPTY) {
|
||||
auto possessable = EntityManager::Instance()->GetEntity(possessableId);
|
||||
if (possessable) {
|
||||
possessor->Dismount(possessable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_Parent->GetLOT() != 1) {
|
||||
echo = true;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "DestroyableComponent.h"
|
||||
#include "dConfig.h"
|
||||
#include "eItemType.h"
|
||||
#include "eUnequippableActiveType.h"
|
||||
|
||||
InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document) : Component(parent) {
|
||||
this->m_Dirty = true;
|
||||
@ -62,23 +63,23 @@ InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* do
|
||||
const auto& info = Inventory::FindItemComponent(item.itemid);
|
||||
|
||||
UpdateSlot(info.equipLocation, { id, static_cast<LOT>(item.itemid), item.count, slot++ });
|
||||
|
||||
|
||||
// Equip this items proxies.
|
||||
auto subItems = info.subItems;
|
||||
|
||||
|
||||
subItems.erase(std::remove_if(subItems.begin(), subItems.end(), ::isspace), subItems.end());
|
||||
|
||||
|
||||
if (!subItems.empty()) {
|
||||
const auto subItemsSplit = GeneralUtils::SplitString(subItems, ',');
|
||||
|
||||
|
||||
for (auto proxyLotAsString : subItemsSplit) {
|
||||
const auto proxyLOT = static_cast<LOT>(std::stoi(proxyLotAsString));
|
||||
|
||||
|
||||
const auto& proxyInfo = Inventory::FindItemComponent(proxyLOT);
|
||||
const LWOOBJID proxyId = ObjectIDManager::Instance()->GenerateObjectID();
|
||||
|
||||
|
||||
// Use item.count since we equip item.count number of the item this is a requested proxy of
|
||||
UpdateSlot(proxyInfo.equipLocation, { proxyId, proxyLOT, item.count, slot++ } );
|
||||
UpdateSlot(proxyInfo.equipLocation, { proxyId, proxyLOT, item.count, slot++ });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -795,9 +796,7 @@ void InventoryComponent::RemoveSlot(const std::string& location) {
|
||||
}
|
||||
|
||||
void InventoryComponent::EquipItem(Item* item, const bool skipChecks) {
|
||||
if (!Inventory::IsValidItem(item->GetLot())) {
|
||||
return;
|
||||
}
|
||||
if (!Inventory::IsValidItem(item->GetLot())) return;
|
||||
|
||||
// Temp items should be equippable but other transfer items shouldn't be (for example the instruments in RB)
|
||||
if (item->IsEquipped()
|
||||
@ -820,9 +819,7 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) {
|
||||
|
||||
auto* characterComponent = m_Parent->GetComponent<CharacterComponent>();
|
||||
|
||||
if (characterComponent != nullptr) {
|
||||
characterComponent->SetLastRocketItemID(item->GetId());
|
||||
}
|
||||
if (characterComponent != nullptr) characterComponent->SetLastRocketItemID(item->GetId());
|
||||
|
||||
lauchPad->OnUse(m_Parent);
|
||||
|
||||
@ -836,94 +833,8 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) {
|
||||
|
||||
const auto type = static_cast<eItemType>(item->GetInfo().itemType);
|
||||
|
||||
if (item->GetLot() == 8092 && m_Parent->GetGMLevel() >= GAME_MASTER_LEVEL_OPERATOR && hasCarEquipped == false) {
|
||||
auto startPosition = m_Parent->GetPosition();
|
||||
|
||||
auto startRotation = NiQuaternion::LookAt(startPosition, startPosition + NiPoint3::UNIT_X);
|
||||
auto angles = startRotation.GetEulerAngles();
|
||||
angles.y -= PI;
|
||||
startRotation = NiQuaternion::FromEulerAngles(angles);
|
||||
|
||||
GameMessages::SendTeleport(m_Parent->GetObjectID(), startPosition, startRotation, m_Parent->GetSystemAddress(), true, true);
|
||||
|
||||
EntityInfo info{};
|
||||
info.lot = 8092;
|
||||
info.pos = startPosition;
|
||||
info.rot = startRotation;
|
||||
info.spawnerID = m_Parent->GetObjectID();
|
||||
|
||||
auto* carEntity = EntityManager::Instance()->CreateEntity(info, nullptr, m_Parent);
|
||||
m_Parent->AddChild(carEntity);
|
||||
|
||||
auto* destroyableComponent = carEntity->GetComponent<DestroyableComponent>();
|
||||
|
||||
// Setup the vehicle stats.
|
||||
if (destroyableComponent != nullptr) {
|
||||
destroyableComponent->SetIsSmashable(false);
|
||||
destroyableComponent->SetIsImmune(true);
|
||||
}
|
||||
// #108
|
||||
auto* possessableComponent = carEntity->GetComponent<PossessableComponent>();
|
||||
|
||||
if (possessableComponent != nullptr) {
|
||||
previousPossessableID = possessableComponent->GetPossessor();
|
||||
possessableComponent->SetPossessor(m_Parent->GetObjectID());
|
||||
}
|
||||
|
||||
auto* moduleAssemblyComponent = carEntity->GetComponent<ModuleAssemblyComponent>();
|
||||
|
||||
if (moduleAssemblyComponent != nullptr) {
|
||||
moduleAssemblyComponent->SetSubKey(item->GetSubKey());
|
||||
moduleAssemblyComponent->SetUseOptionalParts(false);
|
||||
|
||||
for (auto* config : item->GetConfig()) {
|
||||
if (config->GetKey() == u"assemblyPartLOTs") {
|
||||
moduleAssemblyComponent->SetAssemblyPartsLOTs(GeneralUtils::ASCIIToUTF16(config->GetValueAsString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
// #107
|
||||
auto* possessorComponent = m_Parent->GetComponent<PossessorComponent>();
|
||||
|
||||
if (possessorComponent) possessorComponent->SetPossessable(carEntity->GetObjectID());
|
||||
|
||||
auto* characterComponent = m_Parent->GetComponent<CharacterComponent>();
|
||||
|
||||
if (characterComponent) characterComponent->SetIsRacing(true);
|
||||
|
||||
EntityManager::Instance()->ConstructEntity(carEntity);
|
||||
EntityManager::Instance()->SerializeEntity(m_Parent);
|
||||
GameMessages::SendSetJetPackMode(m_Parent, false);
|
||||
|
||||
GameMessages::SendNotifyVehicleOfRacingObject(carEntity->GetObjectID(), m_Parent->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS);
|
||||
GameMessages::SendRacingPlayerLoaded(LWOOBJID_EMPTY, m_Parent->GetObjectID(), carEntity->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS);
|
||||
GameMessages::SendVehicleUnlockInput(carEntity->GetObjectID(), false, UNASSIGNED_SYSTEM_ADDRESS);
|
||||
GameMessages::SendTeleport(m_Parent->GetObjectID(), startPosition, startRotation, m_Parent->GetSystemAddress(), true, true);
|
||||
GameMessages::SendTeleport(carEntity->GetObjectID(), startPosition, startRotation, m_Parent->GetSystemAddress(), true, true);
|
||||
EntityManager::Instance()->SerializeEntity(m_Parent);
|
||||
|
||||
hasCarEquipped = true;
|
||||
equippedCarEntity = carEntity;
|
||||
return;
|
||||
} else if (item->GetLot() == 8092 && m_Parent->GetGMLevel() >= GAME_MASTER_LEVEL_OPERATOR && hasCarEquipped == true) {
|
||||
GameMessages::SendNotifyRacingClient(LWOOBJID_EMPTY, 3, 0, LWOOBJID_EMPTY, u"", m_Parent->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS);
|
||||
auto player = dynamic_cast<Player*>(m_Parent);
|
||||
player->SendToZone(player->GetCharacter()->GetZoneID());
|
||||
equippedCarEntity->Kill();
|
||||
hasCarEquipped = false;
|
||||
equippedCarEntity = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!building) {
|
||||
if (item->GetLot() == 6086) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == eItemType::ITEM_TYPE_LOOT_MODEL || type == eItemType::ITEM_TYPE_VEHICLE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!building && (item->GetLot() == 6086 || type == eItemType::ITEM_TYPE_LOOT_MODEL || type == eItemType::ITEM_TYPE_VEHICLE)) return;
|
||||
|
||||
if (type != eItemType::ITEM_TYPE_LOOT_MODEL && type != eItemType::ITEM_TYPE_MODEL) {
|
||||
if (!item->GetBound() && !item->GetPreconditionExpression()->Check(m_Parent)) {
|
||||
@ -940,9 +851,7 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) {
|
||||
set->OnEquip(lot);
|
||||
}
|
||||
|
||||
if (item->GetInfo().isBOE) {
|
||||
item->SetBound(true);
|
||||
}
|
||||
if (item->GetInfo().isBOE) item->SetBound(true);
|
||||
|
||||
GenerateProxies(item);
|
||||
|
||||
@ -989,6 +898,85 @@ void InventoryComponent::UnEquipItem(Item* item) {
|
||||
}
|
||||
}
|
||||
|
||||
void InventoryComponent::HandlePossession(Item* item) {
|
||||
auto* characterComponent = m_Parent->GetComponent<CharacterComponent>();
|
||||
if (!characterComponent) return;
|
||||
|
||||
auto* possessorComponent = m_Parent->GetComponent<PossessorComponent>();
|
||||
if (!possessorComponent) return;
|
||||
|
||||
// Don't do anything if we are busy dismounting
|
||||
if (possessorComponent->GetIsDismounting()) return;
|
||||
|
||||
// Check to see if we are already mounting something
|
||||
auto* currentlyPossessedEntity = EntityManager::Instance()->GetEntity(possessorComponent->GetPossessable());
|
||||
auto currentlyPossessedItem = possessorComponent->GetMountItemID();
|
||||
|
||||
if (currentlyPossessedItem) {
|
||||
if (currentlyPossessedEntity) possessorComponent->Dismount(currentlyPossessedEntity);
|
||||
return;
|
||||
}
|
||||
|
||||
GameMessages::SendSetStunned(m_Parent->GetObjectID(), eStunState::PUSH, m_Parent->GetSystemAddress(), LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true);
|
||||
|
||||
// Set the mount Item ID so that we know what were handling
|
||||
possessorComponent->SetMountItemID(item->GetId());
|
||||
GameMessages::SendSetMountInventoryID(m_Parent, item->GetId(), UNASSIGNED_SYSTEM_ADDRESS);
|
||||
|
||||
// Create entity to mount
|
||||
auto startRotation = m_Parent->GetRotation();
|
||||
|
||||
EntityInfo info{};
|
||||
info.lot = item->GetLot();
|
||||
info.pos = m_Parent->GetPosition();
|
||||
info.rot = startRotation;
|
||||
info.spawnerID = m_Parent->GetObjectID();
|
||||
|
||||
auto* mount = EntityManager::Instance()->CreateEntity(info, nullptr, m_Parent);
|
||||
|
||||
// Check to see if the mount is a vehicle, if so, flip it
|
||||
auto* vehicleComponent = mount->GetComponent<VehiclePhysicsComponent>();
|
||||
if (vehicleComponent) {
|
||||
auto angles = startRotation.GetEulerAngles();
|
||||
// Make it right side up
|
||||
angles.x -= PI;
|
||||
// Make it going in the direction of the player
|
||||
angles.y -= PI;
|
||||
startRotation = NiQuaternion::FromEulerAngles(angles);
|
||||
mount->SetRotation(startRotation);
|
||||
// We're pod racing now
|
||||
characterComponent->SetIsRacing(true);
|
||||
}
|
||||
|
||||
// Setup the destroyable stats
|
||||
auto* destroyableComponent = mount->GetComponent<DestroyableComponent>();
|
||||
if (destroyableComponent) {
|
||||
destroyableComponent->SetIsSmashable(false);
|
||||
destroyableComponent->SetIsImmune(true);
|
||||
}
|
||||
|
||||
// Mount it
|
||||
auto* possessableComponent = mount->GetComponent<PossessableComponent>();
|
||||
if (possessableComponent) {
|
||||
possessableComponent->SetIsItemSpawned(true);
|
||||
possessableComponent->SetPossessor(m_Parent->GetObjectID());
|
||||
// Possess it
|
||||
possessorComponent->SetPossessable(mount->GetObjectID());
|
||||
possessorComponent->SetPossessableType(possessableComponent->GetPossessionType());
|
||||
}
|
||||
|
||||
GameMessages::SendSetJetPackMode(m_Parent, false);
|
||||
|
||||
// Make it go to the client
|
||||
EntityManager::Instance()->ConstructEntity(mount);
|
||||
// Update the possessor
|
||||
EntityManager::Instance()->SerializeEntity(m_Parent);
|
||||
|
||||
// have to unlock the input so it vehicle can be driven
|
||||
if (vehicleComponent) GameMessages::SendVehicleUnlockInput(mount->GetObjectID(), false, m_Parent->GetSystemAddress());
|
||||
GameMessages::SendMarkInventoryItemAsActive(m_Parent->GetObjectID(), true, eUnequippableActiveType::MOUNT, item->GetId(), m_Parent->GetSystemAddress());
|
||||
}
|
||||
|
||||
void InventoryComponent::ApplyBuff(Item* item) const {
|
||||
const auto buffs = FindBuffs(item, true);
|
||||
|
||||
|
@ -198,6 +198,13 @@ public:
|
||||
*/
|
||||
void UnEquipItem(Item* item);
|
||||
|
||||
/**
|
||||
* Unequips an Item from the inventory
|
||||
* @param item the Item to unequip
|
||||
* @return if we were successful
|
||||
*/
|
||||
void HandlePossession(Item* item);
|
||||
|
||||
/**
|
||||
* Adds a buff related to equipping a lot to the entity
|
||||
* @param item the item to find buffs for
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "dpWorld.h"
|
||||
#include "PetDigServer.h"
|
||||
#include "../dWorldServer/ObjectIDManager.h"
|
||||
#include "eUnequippableActiveType.h"
|
||||
|
||||
#include "Game.h"
|
||||
#include "dConfig.h"
|
||||
@ -883,7 +884,7 @@ void PetComponent::Activate(Item* item, bool registerPet, bool fromTaming) {
|
||||
GameMessages::SendSetPetNameModerated(m_Owner, m_DatabaseId, m_ModerationStatus, owner->GetSystemAddress());
|
||||
}
|
||||
|
||||
GameMessages::SendMarkInventoryItemAsActive(m_Owner, true, 0, m_ItemId, GetOwner()->GetSystemAddress());
|
||||
GameMessages::SendMarkInventoryItemAsActive(m_Owner, true, eUnequippableActiveType::PET, m_ItemId, GetOwner()->GetSystemAddress());
|
||||
|
||||
activePets[m_Owner] = m_Parent->GetObjectID();
|
||||
|
||||
@ -945,7 +946,7 @@ void PetComponent::AddDrainImaginationTimer(Item* item, bool fromTaming) {
|
||||
void PetComponent::Deactivate() {
|
||||
GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), -1, u"despawn", "", LWOOBJID_EMPTY, 1, 1, true);
|
||||
|
||||
GameMessages::SendMarkInventoryItemAsActive(m_Owner, false, 0, m_ItemId, GetOwner()->GetSystemAddress());
|
||||
GameMessages::SendMarkInventoryItemAsActive(m_Owner, false, eUnequippableActiveType::PET, m_ItemId, GetOwner()->GetSystemAddress());
|
||||
|
||||
activePets.erase(m_Owner);
|
||||
|
||||
|
@ -18,7 +18,7 @@ PossessableComponent::PossessableComponent(Entity* parent, uint32_t componentId)
|
||||
|
||||
// Should a result not exist for this default to attached visible
|
||||
if (!result.eof()) {
|
||||
m_PossessionType = static_cast<ePossessionType>(result.getIntField(0, 0));
|
||||
m_PossessionType = static_cast<ePossessionType>(result.getIntField(0, 1)); // Default to Attached Visible
|
||||
m_DepossessOnHit = static_cast<bool>(result.getIntField(1, 0));
|
||||
} else {
|
||||
m_PossessionType = ePossessionType::ATTACHED_VISIBLE;
|
||||
@ -30,7 +30,7 @@ PossessableComponent::PossessableComponent(Entity* parent, uint32_t componentId)
|
||||
void PossessableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
|
||||
outBitStream->Write(m_DirtyPossessable || bIsInitialUpdate);
|
||||
if (m_DirtyPossessable || bIsInitialUpdate) {
|
||||
m_DirtyPossessable = false;
|
||||
m_DirtyPossessable = false; // reset flag
|
||||
outBitStream->Write(m_Possessor != LWOOBJID_EMPTY);
|
||||
if (m_Possessor != LWOOBJID_EMPTY) outBitStream->Write(m_Possessor);
|
||||
|
||||
@ -38,9 +38,18 @@ void PossessableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsIn
|
||||
if (m_AnimationFlag != eAnimationFlags::IDLE_INVALID) outBitStream->Write(m_AnimationFlag);
|
||||
|
||||
outBitStream->Write(m_ImmediatelyDepossess);
|
||||
m_ImmediatelyDepossess = false; // reset flag
|
||||
}
|
||||
}
|
||||
|
||||
void PossessableComponent::OnUse(Entity* originator) {
|
||||
// TODO: Implement this
|
||||
void PossessableComponent::Dismount() {
|
||||
SetPossessor(LWOOBJID_EMPTY);
|
||||
if (m_ItemSpawned) m_Parent->ScheduleKillAfterUpdate();
|
||||
}
|
||||
|
||||
void PossessableComponent::OnUse(Entity* originator) {
|
||||
auto* possessor = originator->GetComponent<PossessorComponent>();
|
||||
if (possessor) {
|
||||
possessor->Mount(m_Parent);
|
||||
}
|
||||
}
|
||||
|
@ -20,14 +20,24 @@ public:
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags);
|
||||
|
||||
/**
|
||||
* Sets the possessor of this entity
|
||||
* @brief mounts the Entity
|
||||
*/
|
||||
void Mount();
|
||||
|
||||
/**
|
||||
* @brief dismounts the Entity
|
||||
*/
|
||||
void Dismount();
|
||||
|
||||
/**
|
||||
* Sets the possessor of this Entity
|
||||
* @param value the ID of the possessor to set
|
||||
*/
|
||||
void SetPossessor(LWOOBJID value) { m_Possessor = value; m_DirtyPossessable = true; };
|
||||
|
||||
/**
|
||||
* Returns the possessor of this entity
|
||||
* @return the possessor of this entity
|
||||
* Returns the possessor of this Entity
|
||||
* @return the possessor of this Entity
|
||||
*/
|
||||
LWOOBJID GetPossessor() const { return m_Possessor; };
|
||||
|
||||
@ -38,19 +48,19 @@ public:
|
||||
void SetAnimationFlag(eAnimationFlags value) { m_AnimationFlag = value; m_DirtyPossessable = true; };
|
||||
|
||||
/**
|
||||
* Returns the possession type of this entity
|
||||
* @return the possession type of this entity
|
||||
* Returns the possession type of this Entity
|
||||
* @return the possession type of this Entity
|
||||
*/
|
||||
ePossessionType GetPossessionType() const { return m_PossessionType; };
|
||||
|
||||
/**
|
||||
* Returns if the entity should deposses on hit
|
||||
* @return if the entity should deposses on hit
|
||||
* Returns if the Entity should deposses on hit
|
||||
* @return if the Entity should deposses on hit
|
||||
*/
|
||||
bool GetDepossessOnHit() const { return m_DepossessOnHit; };
|
||||
|
||||
/**
|
||||
* Forcibly depossess the entity
|
||||
* Forcibly depossess the Entity
|
||||
*/
|
||||
void ForceDepossess() { m_ImmediatelyDepossess = true; m_DirtyPossessable = true; };
|
||||
|
||||
@ -58,13 +68,13 @@ public:
|
||||
* Set if the parent entity was spawned from an item
|
||||
* @param value if the parent entity was spawned from an item
|
||||
*/
|
||||
void SetItemSpawned(bool value) { m_ItemSpawned = value; };
|
||||
void SetIsItemSpawned(bool value) { m_ItemSpawned = value; };
|
||||
|
||||
/**
|
||||
* Returns if the parent entity was spawned from an item
|
||||
* @return if the parent entity was spawned from an item
|
||||
*/
|
||||
LWOOBJID GetItemSpawned() const { return m_ItemSpawned; };
|
||||
LWOOBJID GetIsItemSpawned() const { return m_ItemSpawned; };
|
||||
|
||||
/**
|
||||
* Handles an OnUsed event by some other entity, if said entity has a Possessor it becomes the possessor
|
||||
|
@ -1,12 +1,28 @@
|
||||
#include "PossessorComponent.h"
|
||||
#include "PossessableComponent.h"
|
||||
#include "CharacterComponent.h"
|
||||
#include "EntityManager.h"
|
||||
#include "GameMessages.h"
|
||||
#include "eUnequippableActiveType.h"
|
||||
|
||||
PossessorComponent::PossessorComponent(Entity* parent) : Component(parent) {
|
||||
m_Possessable = LWOOBJID_EMPTY;
|
||||
}
|
||||
|
||||
PossessorComponent::~PossessorComponent() {}
|
||||
|
||||
|
||||
PossessorComponent::~PossessorComponent() {
|
||||
if (m_Possessable != LWOOBJID_EMPTY) {
|
||||
auto* mount = EntityManager::Instance()->GetEntity(m_Possessable);
|
||||
if (mount) {
|
||||
auto* possessable = mount->GetComponent<PossessableComponent>();
|
||||
if (possessable) {
|
||||
if (possessable->GetIsItemSpawned()) {
|
||||
GameMessages::SendMarkInventoryItemAsActive(m_Parent->GetObjectID(), false, eUnequippableActiveType::MOUNT, GetMountItemID(), m_Parent->GetSystemAddress());
|
||||
}
|
||||
possessable->Dismount();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PossessorComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
|
||||
outBitStream->Write(m_DirtyPossesor || bIsInitialUpdate);
|
||||
@ -19,3 +35,48 @@ void PossessorComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInit
|
||||
outBitStream->Write(m_PossessableType);
|
||||
}
|
||||
}
|
||||
|
||||
void PossessorComponent::Mount(Entity* mount) {
|
||||
// Don't do anything if we are busy dismounting
|
||||
if (GetIsDismounting() || !mount) return;
|
||||
|
||||
GameMessages::SendSetMountInventoryID(m_Parent, mount->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS);
|
||||
auto* possessableComponent = mount->GetComponent<PossessableComponent>();
|
||||
if (possessableComponent) {
|
||||
possessableComponent->SetPossessor(m_Parent->GetObjectID());
|
||||
SetPossessable(mount->GetObjectID());
|
||||
SetPossessableType(possessableComponent->GetPossessionType());
|
||||
}
|
||||
|
||||
auto characterComponent = m_Parent->GetComponent<CharacterComponent>();
|
||||
if (characterComponent) characterComponent->SetIsRacing(true);
|
||||
|
||||
// GM's to send
|
||||
GameMessages::SendSetJetPackMode(m_Parent, false);
|
||||
GameMessages::SendVehicleUnlockInput(mount->GetObjectID(), false, m_Parent->GetSystemAddress());
|
||||
GameMessages::SendSetStunned(m_Parent->GetObjectID(), eStunState::PUSH, m_Parent->GetSystemAddress(), LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true);
|
||||
|
||||
EntityManager::Instance()->SerializeEntity(m_Parent);
|
||||
EntityManager::Instance()->SerializeEntity(mount);
|
||||
}
|
||||
|
||||
void PossessorComponent::Dismount(Entity* mount, bool forceDismount) {
|
||||
// Don't do anything if we are busy dismounting
|
||||
if (GetIsDismounting() || !mount) return;
|
||||
SetIsDismounting(true);
|
||||
|
||||
if (mount) {
|
||||
auto* possessableComponent = mount->GetComponent<PossessableComponent>();
|
||||
if (possessableComponent) {
|
||||
possessableComponent->SetPossessor(LWOOBJID_EMPTY);
|
||||
if (forceDismount) possessableComponent->ForceDepossess();
|
||||
}
|
||||
EntityManager::Instance()->SerializeEntity(m_Parent);
|
||||
EntityManager::Instance()->SerializeEntity(mount);
|
||||
|
||||
auto characterComponent = m_Parent->GetComponent<CharacterComponent>();
|
||||
if (characterComponent) characterComponent->SetIsRacing(false);
|
||||
}
|
||||
// Make sure we don't have wacky controls
|
||||
GameMessages::SendSetPlayerControlScheme(m_Parent, eControlSceme::SCHEME_A);
|
||||
}
|
||||
|
@ -25,35 +25,63 @@ public:
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags);
|
||||
|
||||
/**
|
||||
* Sets the entity that this entity is possessing
|
||||
* @param value the ID of the entity this ID should posess
|
||||
* @brief Mounts the entity
|
||||
*
|
||||
* @param mount Entity to be mounted
|
||||
*/
|
||||
void Mount(Entity* mount);
|
||||
|
||||
/**
|
||||
* @brief Dismounts the entity
|
||||
*
|
||||
* @param mount Entity to be dismounted
|
||||
* @param forceDismount Should we forcibly dismount the entity
|
||||
*/
|
||||
void Dismount(Entity* mount, bool forceDismount = false);
|
||||
|
||||
/**
|
||||
* Sets the ID that this entity is possessing
|
||||
* @param value The ID that this entity is possessing
|
||||
*/
|
||||
void SetPossessable(LWOOBJID value) { m_Possessable = value; m_DirtyPossesor = true; }
|
||||
|
||||
/**
|
||||
* Returns the entity that this entity is currently posessing
|
||||
* @return the entity that this entity is currently posessing
|
||||
* @return The entity that this entity is currently posessing
|
||||
*/
|
||||
LWOOBJID GetPossessable() const { return m_Possessable; }
|
||||
|
||||
/**
|
||||
* Sets if we are busy mounting or dismounting
|
||||
* @param value if we are busy mounting or dismounting
|
||||
* Sets if we are busy dismounting
|
||||
* @param value If we are busy dismounting
|
||||
*/
|
||||
void SetIsBusy(bool value) { m_IsBusy = value; }
|
||||
void SetIsDismounting(bool value) { m_IsDismounting = value; }
|
||||
|
||||
/**
|
||||
* Returns if we are busy mounting or dismounting
|
||||
* @return if we are busy mounting or dismounting
|
||||
* Returns if we are busy dismounting
|
||||
* @return If we are busy dismounting
|
||||
*/
|
||||
bool GetIsBusy() const { return m_IsBusy; }
|
||||
bool GetIsDismounting() const { return m_IsDismounting; }
|
||||
|
||||
/**
|
||||
* Sets the possesible type that's currently used, merely used by the shooting gallery if it's 0
|
||||
* @param value the possesible type to set
|
||||
* @param value The possesible type to set
|
||||
*/
|
||||
void SetPossessableType(ePossessionType value) { m_PossessableType = value; m_DirtyPossesor = true; }
|
||||
|
||||
|
||||
/**
|
||||
* Gets the object ID of the mount item that is being used
|
||||
* @return The object ID of the mount item that is being used
|
||||
*/
|
||||
LWOOBJID GetMountItemID() const { return m_MountItemID; }
|
||||
|
||||
/**
|
||||
* Sets the object ID of the mount item that is being used
|
||||
* @param m_MountItemID The object ID of the mount item that is being used
|
||||
*/
|
||||
void SetMountItemID(LWOOBJID mountItemID) { m_MountItemID = mountItemID; }
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
@ -68,14 +96,19 @@ private:
|
||||
ePossessionType m_PossessableType = ePossessionType::NO_POSSESSION;
|
||||
|
||||
/**
|
||||
* @brief if the possessor is dirty
|
||||
* @brief If the possessor is dirty
|
||||
*
|
||||
*/
|
||||
bool m_DirtyPossesor = false;
|
||||
|
||||
/**
|
||||
* @brief if the possessor is busy mounting or dismounting
|
||||
* @brief If the possessor is busy dismounting
|
||||
*
|
||||
*/
|
||||
bool m_IsBusy = false;
|
||||
bool m_IsDismounting = false;
|
||||
|
||||
/**
|
||||
* Mount Item ID
|
||||
*/
|
||||
LWOOBJID m_MountItemID = LWOOBJID_EMPTY;
|
||||
};
|
||||
|
@ -653,6 +653,10 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System
|
||||
GameMessages::HandleUpdatePlayerStatistic(inStream, entity);
|
||||
break;
|
||||
|
||||
case GAME_MSG_DISMOUNT_COMPLETE:
|
||||
GameMessages::HandleDismountComplete(inStream, entity, sysAddr);
|
||||
break;
|
||||
|
||||
default:
|
||||
//Game::logger->Log("GameMessageHandler", "Unknown game message ID: %X", messageID);
|
||||
break;
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "ChatPackets.h"
|
||||
#include "GameConfig.h"
|
||||
#include "RocketLaunchLupComponent.h"
|
||||
#include "eUnequippableActiveType.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <future>
|
||||
@ -3367,7 +3368,7 @@ void GameMessages::SendRegisterPetDBID(LWOOBJID objectId, LWOOBJID petDBID, cons
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void GameMessages::SendMarkInventoryItemAsActive(LWOOBJID objectId, bool bActive, int32_t iType, LWOOBJID itemID, const SystemAddress& sysAddr) {
|
||||
void GameMessages::SendMarkInventoryItemAsActive(LWOOBJID objectId, bool bActive, eUnequippableActiveType iType, LWOOBJID itemID, const SystemAddress& sysAddr) {
|
||||
CBITSTREAM;
|
||||
CMSGHEADER;
|
||||
|
||||
@ -3376,8 +3377,8 @@ void GameMessages::SendMarkInventoryItemAsActive(LWOOBJID objectId, bool bActive
|
||||
|
||||
bitStream.Write(bActive);
|
||||
|
||||
bitStream.Write(iType != 0);
|
||||
if (iType != 0) bitStream.Write(iType);
|
||||
bitStream.Write(iType != eUnequippableActiveType::INVALID);
|
||||
if (iType != eUnequippableActiveType::INVALID) bitStream.Write(iType);
|
||||
|
||||
bitStream.Write(itemID != LWOOBJID_EMPTY);
|
||||
if (itemID != LWOOBJID_EMPTY) bitStream.Write(itemID);
|
||||
@ -3814,7 +3815,6 @@ void GameMessages::SendDisplayChatBubble(LWOOBJID objectId, const std::u16string
|
||||
void GameMessages::SendSetMountInventoryID(Entity* entity, const LWOOBJID& objectID, const SystemAddress& sysAddr) {
|
||||
CBITSTREAM;
|
||||
CMSGHEADER;
|
||||
|
||||
bitStream.Write(entity->GetObjectID());
|
||||
bitStream.Write(GAME_MSG::GAME_MSG_SET_MOUNT_INVENTORY_ID);
|
||||
bitStream.Write(objectID);
|
||||
@ -3824,30 +3824,53 @@ void GameMessages::SendSetMountInventoryID(Entity* entity, const LWOOBJID& objec
|
||||
|
||||
|
||||
void GameMessages::HandleDismountComplete(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) {
|
||||
// Get the objectID from the bitstream
|
||||
LWOOBJID objectId{};
|
||||
inStream->Read(objectId);
|
||||
auto* mount = EntityManager::Instance()->GetEntity(objectId);
|
||||
|
||||
// If we aren't possessing somethings, the don't do anything
|
||||
if (objectId != LWOOBJID_EMPTY) {
|
||||
PossessorComponent* possessor;
|
||||
if (entity->TryGetComponent(COMPONENT_TYPE_POSSESSOR, possessor)) {
|
||||
if (mount) {
|
||||
possessor->SetIsBusy(false);
|
||||
possessor->SetPossessable(LWOOBJID_EMPTY);
|
||||
possessor->SetPossessableType(ePossessionType::NO_POSSESSION);
|
||||
auto* possessorComponent = entity->GetComponent<PossessorComponent>();
|
||||
auto* mount = EntityManager::Instance()->GetEntity(objectId);
|
||||
// make sure we have the things we need and they aren't null
|
||||
if (possessorComponent && mount) {
|
||||
if (!possessorComponent->GetIsDismounting()) return;
|
||||
possessorComponent->SetIsDismounting(false);
|
||||
possessorComponent->SetPossessable(LWOOBJID_EMPTY);
|
||||
possessorComponent->SetPossessableType(ePossessionType::NO_POSSESSION);
|
||||
|
||||
GameMessages::SendSetStunned(entity->GetObjectID(), eStunState::POP, UNASSIGNED_SYSTEM_ADDRESS, LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true);
|
||||
|
||||
EntityManager::Instance()->SerializeEntity(entity);
|
||||
// character related things
|
||||
auto* character = entity->GetComponent<CharacterComponent>();
|
||||
if (character) {
|
||||
// If we had an active item turn it off
|
||||
if (possessorComponent->GetMountItemID() != LWOOBJID_EMPTY) GameMessages::SendMarkInventoryItemAsActive(entity->GetObjectID(), false, eUnequippableActiveType::MOUNT, possessorComponent->GetMountItemID(), entity->GetSystemAddress());
|
||||
possessorComponent->SetMountItemID(LWOOBJID_EMPTY);
|
||||
}
|
||||
|
||||
// Set that the controllabel phsyics comp is teleporting
|
||||
auto* controllablePhysicsComponent = entity->GetComponent<ControllablePhysicsComponent>();
|
||||
if (controllablePhysicsComponent) controllablePhysicsComponent->SetIsTeleporting(true);
|
||||
|
||||
// Call dismoint on the possessable comp to let it handle killing the possessable
|
||||
auto* possessableComponent = mount->GetComponent<PossessableComponent>();
|
||||
if (possessableComponent) possessableComponent->Dismount();
|
||||
|
||||
// Update the entity that was possessing
|
||||
EntityManager::Instance()->SerializeEntity(entity);
|
||||
|
||||
// We aren't mounted so remove the stun
|
||||
GameMessages::SendSetStunned(entity->GetObjectID(), eStunState::POP, UNASSIGNED_SYSTEM_ADDRESS, LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GameMessages::HandleAcknowledgePossession(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) {
|
||||
Game::logger->Log("HandleAcknowledgePossession", "Got AcknowledgePossession from %i", entity->GetLOT());
|
||||
EntityManager::Instance()->SerializeEntity(entity);
|
||||
LWOOBJID objectId{};
|
||||
inStream->Read(objectId);
|
||||
auto* mount = EntityManager::Instance()->GetEntity(objectId);
|
||||
if (mount) EntityManager::Instance()->SerializeEntity(mount);
|
||||
}
|
||||
|
||||
//Racing
|
||||
@ -4698,12 +4721,6 @@ void GameMessages::HandleFireEventServerSide(RakNet::BitStream* inStream, Entity
|
||||
return;
|
||||
}
|
||||
|
||||
if (args == u"toggleMail") {
|
||||
AMFArrayValue args;
|
||||
args.InsertValue("visible", new AMFFalseValue());
|
||||
GameMessages::SendUIMessageServerToSingleClient(entity, sysAddr, "ToggleMail", &args);
|
||||
}
|
||||
|
||||
// This should probably get it's own "ServerEvents" system or something at some point
|
||||
if (args == u"ZonePlayer") {
|
||||
// Should probably check to make sure they're using a launcher at some point before someone makes a hack that lets you testmap
|
||||
|
@ -19,6 +19,7 @@ class NiQuaternion;
|
||||
class User;
|
||||
class Entity;
|
||||
class NiPoint3;
|
||||
enum class eUnequippableActiveType;
|
||||
|
||||
namespace GameMessages {
|
||||
class PropertyDataMessage;
|
||||
@ -318,7 +319,7 @@ namespace GameMessages {
|
||||
|
||||
void SendRegisterPetDBID(LWOOBJID objectId, LWOOBJID petDBID, const SystemAddress& sysAddr);
|
||||
|
||||
void SendMarkInventoryItemAsActive(LWOOBJID objectId, bool bActive, int32_t iType, LWOOBJID itemID, const SystemAddress& sysAddr);
|
||||
void SendMarkInventoryItemAsActive(LWOOBJID objectId, bool bActive, eUnequippableActiveType iType, LWOOBJID itemID, const SystemAddress& sysAddr);
|
||||
|
||||
void SendClientExitTamingMinigame(LWOOBJID objectId, bool bVoluntaryExit, const SystemAddress& sysAddr);
|
||||
|
||||
|
@ -10,6 +10,9 @@
|
||||
#include "dLogger.h"
|
||||
#include "EntityManager.h"
|
||||
#include "RenderComponent.h"
|
||||
#include "PossessableComponent.h"
|
||||
#include "CharacterComponent.h"
|
||||
#include "eItemType.h"
|
||||
|
||||
class Inventory;
|
||||
|
||||
@ -71,6 +74,12 @@ Item::Item(
|
||||
id = GeneralUtils::SetBit(id, OBJECT_BIT_CHARACTER);
|
||||
id = GeneralUtils::SetBit(id, OBJECT_BIT_PERSISTENT);
|
||||
|
||||
const auto type = static_cast<eItemType>(info->itemType);
|
||||
|
||||
if (type == eItemType::ITEM_TYPE_MOUNT) {
|
||||
id = GeneralUtils::SetBit(id, OBJECT_BIT_CLIENT);
|
||||
}
|
||||
|
||||
this->id = id;
|
||||
|
||||
inventory->AddManagedItem(this);
|
||||
@ -254,49 +263,34 @@ bool Item::Consume() {
|
||||
return success;
|
||||
}
|
||||
|
||||
bool Item::UseNonEquip() {
|
||||
auto* compRegistryTable = CDClientManager::Instance()->GetTable<CDComponentsRegistryTable>("ComponentsRegistry");
|
||||
|
||||
const auto packageComponentId = compRegistryTable->GetByIDAndType(lot, COMPONENT_TYPE_PACKAGE);
|
||||
|
||||
auto* packCompTable = CDClientManager::Instance()->GetTable<CDPackageComponentTable>("PackageComponent");
|
||||
|
||||
auto packages = packCompTable->Query([=](const CDPackageComponent entry) {return entry.id == static_cast<uint32_t>(packageComponentId); });
|
||||
|
||||
const auto success = !packages.empty();
|
||||
|
||||
auto inventoryComponent = inventory->GetComponent();
|
||||
|
||||
auto playerEntity = inventoryComponent->GetParent();
|
||||
|
||||
if (subKey != LWOOBJID_EMPTY) {
|
||||
void Item::UseNonEquip() {
|
||||
const auto type = static_cast<eItemType>(info->itemType);
|
||||
if (type == eItemType::ITEM_TYPE_MOUNT) {
|
||||
GetInventory()->GetComponent()->HandlePossession(this);
|
||||
} else if (type == eItemType::ITEM_TYPE_PET_INVENTORY_ITEM && subKey != LWOOBJID_EMPTY) {
|
||||
const auto& databasePet = GetInventory()->GetComponent()->GetDatabasePet(subKey);
|
||||
|
||||
if (databasePet.lot != LOT_NULL) {
|
||||
GetInventory()->GetComponent()->SpawnPet(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (success && (playerEntity->GetGMLevel() >= eGameMasterLevel::GAME_MASTER_LEVEL_JUNIOR_DEVELOPER || this->GetPreconditionExpression()->Check(playerEntity))) {
|
||||
auto* entityParent = inventory->GetComponent()->GetParent();
|
||||
} else if (type == eItemType::ITEM_TYPE_PACKAGE) {
|
||||
auto* compRegistryTable = CDClientManager::Instance()->GetTable<CDComponentsRegistryTable>("ComponentsRegistry");
|
||||
const auto packageComponentId = compRegistryTable->GetByIDAndType(lot, COMPONENT_TYPE_PACKAGE);
|
||||
auto* packCompTable = CDClientManager::Instance()->GetTable<CDPackageComponentTable>("PackageComponent");
|
||||
auto packages = packCompTable->Query([=](const CDPackageComponent entry) {return entry.id == static_cast<uint32_t>(packageComponentId); });
|
||||
|
||||
for (auto& pack : packages) {
|
||||
std::unordered_map<LOT, int32_t> result{};
|
||||
|
||||
result = LootGenerator::Instance().RollLootMatrix(entityParent, pack.LootMatrixIndex);
|
||||
|
||||
if (!inventory->GetComponent()->HasSpaceForLoot(result)) {
|
||||
return false;
|
||||
const auto success = !packages.empty();
|
||||
if (success) {
|
||||
auto* entityParent = inventory->GetComponent()->GetParent();
|
||||
for (auto& pack : packages) {
|
||||
std::unordered_map<LOT, int32_t> result{};
|
||||
result = LootGenerator::Instance().RollLootMatrix(entityParent, pack.LootMatrixIndex);
|
||||
if (!inventory->GetComponent()->HasSpaceForLoot(result)) {
|
||||
}
|
||||
LootGenerator::Instance().GiveLoot(inventory->GetComponent()->GetParent(), result, eLootSourceType::LOOT_SOURCE_CONSUMPTION);
|
||||
}
|
||||
|
||||
LootGenerator::Instance().GiveLoot(inventory->GetComponent()->GetParent(), result, eLootSourceType::LOOT_SOURCE_CONSUMPTION);
|
||||
inventory->GetComponent()->RemoveItem(lot, 1);
|
||||
}
|
||||
Game::logger->Log("Item", "Used (%i)", lot);
|
||||
inventory->GetComponent()->RemoveItem(lot, 1);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void Item::Disassemble(const eInventoryType inventoryType) {
|
||||
|
@ -193,9 +193,8 @@ public:
|
||||
|
||||
/**
|
||||
* Uses this item if its non equip, essentially an interface for the linked GM
|
||||
* @return whether the use was successful, e.g. the skill was cast
|
||||
*/
|
||||
bool UseNonEquip();
|
||||
void UseNonEquip();
|
||||
|
||||
/**
|
||||
* Disassembles the part LOTs of this item back into the inventory, if it has any
|
||||
|
@ -419,6 +419,11 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
|
||||
if ((chatCommand == "playanimation" || chatCommand == "playanim") && args.size() == 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) {
|
||||
std::u16string anim = GeneralUtils::ASCIIToUTF16(args[0], args[0].size());
|
||||
GameMessages::SendPlayAnimation(entity, anim);
|
||||
auto* possessorComponent = entity->GetComponent<PossessorComponent>();
|
||||
if (possessorComponent) {
|
||||
auto* possessedComponent = EntityManager::Instance()->GetEntity(possessorComponent->GetPossessable());
|
||||
if (possessedComponent) GameMessages::SendPlayAnimation(possessedComponent, anim);
|
||||
}
|
||||
}
|
||||
|
||||
if (chatCommand == "list-spawns" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) {
|
||||
@ -471,12 +476,24 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
|
||||
|
||||
auto* controllablePhysicsComponent = entity->GetComponent<ControllablePhysicsComponent>();
|
||||
|
||||
if (controllablePhysicsComponent == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!controllablePhysicsComponent) return;
|
||||
controllablePhysicsComponent->SetSpeedMultiplier(boost);
|
||||
|
||||
// speedboost possesables
|
||||
auto possessor = entity->GetComponent<PossessorComponent>();
|
||||
if (possessor) {
|
||||
auto possessedID = possessor->GetPossessable();
|
||||
if (possessedID != LWOOBJID_EMPTY) {
|
||||
auto possessable = EntityManager::Instance()->GetEntity(possessedID);
|
||||
if (possessable) {
|
||||
auto* possessControllablePhysicsComponent = possessable->GetComponent<ControllablePhysicsComponent>();
|
||||
if (possessControllablePhysicsComponent) {
|
||||
possessControllablePhysicsComponent->SetSpeedMultiplier(boost);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EntityManager::Instance()->SerializeEntity(entity);
|
||||
}
|
||||
|
||||
@ -894,21 +911,17 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
|
||||
ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /teleport <x> (<y>) <z> - if no Y given, will teleport to the height of the terrain (or any physics object).");
|
||||
}
|
||||
|
||||
auto* possessorComponent = entity->GetComponent<PossessorComponent>();
|
||||
|
||||
if (possessorComponent != nullptr) {
|
||||
auto* possessorComponent = entity->GetComponent<PossessorComponent>();
|
||||
if (possessorComponent) {
|
||||
auto* possassableEntity = EntityManager::Instance()->GetEntity(possessorComponent->GetPossessable());
|
||||
|
||||
if (possassableEntity != nullptr) {
|
||||
auto* vehiclePhysicsComponent = possassableEntity->GetComponent<VehiclePhysicsComponent>();
|
||||
|
||||
if (vehiclePhysicsComponent != nullptr) {
|
||||
if (vehiclePhysicsComponent) {
|
||||
vehiclePhysicsComponent->SetPosition(pos);
|
||||
|
||||
EntityManager::Instance()->SerializeEntity(possassableEntity);
|
||||
|
||||
Game::logger->Log("ClientPackets", "Forced updated vehicle position");
|
||||
}
|
||||
} else GameMessages::SendTeleport(possassableEntity->GetObjectID(), pos, NiQuaternion(), sysAddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -926,18 +939,12 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
|
||||
}
|
||||
|
||||
if (chatCommand == "dismount" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) {
|
||||
PossessorComponent* possessorComponent;
|
||||
if (entity->TryGetComponent(COMPONENT_TYPE_POSSESSOR, possessorComponent)) {
|
||||
Entity* vehicle = EntityManager::Instance()->GetEntity(possessorComponent->GetPossessable());
|
||||
if (!vehicle) return;
|
||||
|
||||
PossessableComponent* possessableComponent;
|
||||
if (vehicle->TryGetComponent(COMPONENT_TYPE_POSSESSABLE, possessableComponent)) {
|
||||
possessableComponent->SetPossessor(LWOOBJID_EMPTY);
|
||||
possessorComponent->SetPossessable(LWOOBJID_EMPTY);
|
||||
|
||||
EntityManager::Instance()->SerializeEntity(vehicle);
|
||||
EntityManager::Instance()->SerializeEntity(entity);
|
||||
auto* possessorComponent = entity->GetComponent<PossessorComponent>();
|
||||
if (possessorComponent) {
|
||||
auto possessableId = possessorComponent->GetPossessable();
|
||||
if (possessableId != LWOOBJID_EMPTY) {
|
||||
auto* possessableEntity = EntityManager::Instance()->GetEntity(possessableId);
|
||||
if (possessableEntity) possessorComponent->Dismount(possessableEntity, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1231,6 +1238,18 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
|
||||
return;
|
||||
}
|
||||
|
||||
auto vehiclePhysicsComponent = newEntity->GetComponent<VehiclePhysicsComponent>();
|
||||
if (vehiclePhysicsComponent) {
|
||||
auto newRot = newEntity->GetRotation();
|
||||
auto angles = newRot.GetEulerAngles();
|
||||
// make it right side up
|
||||
angles.x -= PI;
|
||||
// make it going in the direction of the player
|
||||
angles.y -= PI;
|
||||
newRot = NiQuaternion::FromEulerAngles(angles);
|
||||
newEntity->SetRotation(newRot);
|
||||
}
|
||||
|
||||
EntityManager::Instance()->ConstructEntity(newEntity);
|
||||
}
|
||||
|
||||
@ -1520,7 +1539,33 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
|
||||
return;
|
||||
}
|
||||
|
||||
GameMessages::SendVehicleAddPassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS);
|
||||
if (args.size() >= 1) {
|
||||
float time;
|
||||
|
||||
if (!GeneralUtils::TryParse(args[0], time)) {
|
||||
ChatPackets::SendSystemMessage(sysAddr, u"Invalid boost time.");
|
||||
return;
|
||||
} else {
|
||||
GameMessages::SendVehicleAddPassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS);
|
||||
entity->AddCallbackTimer(time, [vehicle]() {
|
||||
if (!vehicle) return;
|
||||
GameMessages::SendVehicleRemovePassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
GameMessages::SendVehicleAddPassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ((chatCommand == "unboost") && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) {
|
||||
auto* possessorComponent = entity->GetComponent<PossessorComponent>();
|
||||
|
||||
if (possessorComponent == nullptr) return;
|
||||
auto* vehicle = EntityManager::Instance()->GetEntity(possessorComponent->GetPossessable());
|
||||
|
||||
if (vehicle == nullptr) return;
|
||||
GameMessages::SendVehicleRemovePassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS);
|
||||
}
|
||||
|
||||
if (chatCommand == "activatespawner" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) {
|
||||
|
@ -140,14 +140,19 @@ void ClientPackets::HandleClientPositionUpdate(const SystemAddress& sysAddr, Pac
|
||||
inStream.Read(angVelocity.z);
|
||||
}
|
||||
|
||||
bool hasVehicle = false;
|
||||
bool updateChar = true;
|
||||
|
||||
if (possessorComponent != nullptr) {
|
||||
auto* possassableEntity = EntityManager::Instance()->GetEntity(possessorComponent->GetPossessable());
|
||||
|
||||
if (possassableEntity != nullptr) {
|
||||
auto* vehiclePhysicsComponent = possassableEntity->GetComponent<VehiclePhysicsComponent>();
|
||||
auto* possessableComponent = possassableEntity->GetComponent<PossessableComponent>();
|
||||
if (possessableComponent) {
|
||||
// While possessing something, only update char if we are attached to the thing we are possessing
|
||||
if (possessableComponent->GetPossessionType() != ePossessionType::ATTACHED_VISIBLE) updateChar = false;
|
||||
}
|
||||
|
||||
auto* vehiclePhysicsComponent = possassableEntity->GetComponent<VehiclePhysicsComponent>();
|
||||
if (vehiclePhysicsComponent != nullptr) {
|
||||
// This is flipped for whatever reason
|
||||
rotation = NiQuaternion(rotation.z, rotation.y, rotation.x, rotation.w);
|
||||
@ -160,19 +165,30 @@ void ClientPackets::HandleClientPositionUpdate(const SystemAddress& sysAddr, Pac
|
||||
vehiclePhysicsComponent->SetDirtyVelocity(velocityFlag);
|
||||
vehiclePhysicsComponent->SetAngularVelocity(angVelocity);
|
||||
vehiclePhysicsComponent->SetDirtyAngularVelocity(angVelocityFlag);
|
||||
|
||||
EntityManager::Instance()->SerializeEntity(possassableEntity);
|
||||
|
||||
hasVehicle = true;
|
||||
} else {
|
||||
// Need to get the mount's controllable physics
|
||||
auto* controllablePhysicsComponent = possassableEntity->GetComponent<ControllablePhysicsComponent>();
|
||||
if (!controllablePhysicsComponent) return;
|
||||
controllablePhysicsComponent->SetPosition(position);
|
||||
controllablePhysicsComponent->SetRotation(rotation);
|
||||
controllablePhysicsComponent->SetIsOnGround(onGround);
|
||||
controllablePhysicsComponent->SetIsOnRail(onRail);
|
||||
controllablePhysicsComponent->SetVelocity(velocity);
|
||||
controllablePhysicsComponent->SetDirtyVelocity(velocityFlag);
|
||||
controllablePhysicsComponent->SetAngularVelocity(angVelocity);
|
||||
controllablePhysicsComponent->SetDirtyAngularVelocity(angVelocityFlag);
|
||||
}
|
||||
EntityManager::Instance()->SerializeEntity(possassableEntity);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasVehicle) {
|
||||
if (!updateChar) {
|
||||
velocity = NiPoint3::ZERO;
|
||||
angVelocity = NiPoint3::ZERO;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Handle statistics
|
||||
auto* characterComponent = entity->GetComponent<CharacterComponent>();
|
||||
if (characterComponent != nullptr) {
|
||||
@ -192,9 +208,7 @@ void ClientPackets::HandleClientPositionUpdate(const SystemAddress& sysAddr, Pac
|
||||
player->SetGhostReferencePoint(position);
|
||||
EntityManager::Instance()->QueueGhostUpdate(player->GetObjectID());
|
||||
|
||||
if (!hasVehicle) {
|
||||
EntityManager::Instance()->SerializeEntity(entity);
|
||||
}
|
||||
if (updateChar) EntityManager::Instance()->SerializeEntity(entity);
|
||||
|
||||
//TODO: add moving platform stuffs
|
||||
/*bool movingPlatformFlag;
|
||||
|
15
dScripts/AgQbWall.cpp
Normal file
15
dScripts/AgQbWall.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
#include "AgQbWall.h"
|
||||
|
||||
void AgQbWall::OnRebuildComplete(Entity* self, Entity* player) {
|
||||
self->SetVar(u"player", player->GetObjectID());
|
||||
auto targetWallSpawners = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"spawner"));
|
||||
if (targetWallSpawners != "") {
|
||||
auto groupObjs = EntityManager::Instance()->GetEntitiesInGroup(targetWallSpawners);
|
||||
for (auto* obj : groupObjs) {
|
||||
if (obj) {
|
||||
obj->SetVar(u"player", player->GetObjectID());
|
||||
obj->OnFireEventServerSide(self, "spawnMobs");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
7
dScripts/AgQbWall.h
Normal file
7
dScripts/AgQbWall.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include "CppScripts.h"
|
||||
|
||||
class AgQbWall : public CppScripts::Script {
|
||||
public:
|
||||
void OnRebuildComplete(Entity* self, Entity* player) override;
|
||||
};
|
@ -21,6 +21,7 @@ set(DSCRIPT_SOURCES "ActivityManager.cpp"
|
||||
"AgPropGuard.cpp"
|
||||
"AgPropguards.cpp"
|
||||
"AgQbElevator.cpp"
|
||||
"AgQbWall.cpp"
|
||||
"AgSalutingNpcs.cpp"
|
||||
"AgShipPlayerDeathTrigger.cpp"
|
||||
"AgShipPlayerShockServer.cpp"
|
||||
@ -94,11 +95,13 @@ set(DSCRIPT_SOURCES "ActivityManager.cpp"
|
||||
"FvConsoleRightQuickbuild.cpp"
|
||||
"FvDragonSmashingGolemQb.cpp"
|
||||
"FvFacilityBrick.cpp"
|
||||
"FvFacilityPipes.cpp"
|
||||
"FvFlyingCreviceDragon.cpp"
|
||||
"FvFong.cpp"
|
||||
"FvFreeGfNinjas.cpp"
|
||||
"FvHorsemenTrigger.cpp"
|
||||
"FvMaelstromCavalry.cpp"
|
||||
"FvMaelstromGeyser.cpp"
|
||||
"FvMaelstromDragon.cpp"
|
||||
"FvNinjaGuard.cpp"
|
||||
"FvPandaServer.cpp"
|
||||
@ -113,7 +116,9 @@ set(DSCRIPT_SOURCES "ActivityManager.cpp"
|
||||
"GfCaptainsCannon.cpp"
|
||||
"GfJailkeepMission.cpp"
|
||||
"GfJailWalls.cpp"
|
||||
"GfMaelstromGeyser.cpp"
|
||||
"GfOrgan.cpp"
|
||||
"GfParrotCrash.cpp"
|
||||
"GfTikiTorch.cpp"
|
||||
"GrowingFlower.cpp"
|
||||
"HydrantBroken.cpp"
|
||||
@ -193,6 +198,7 @@ set(DSCRIPT_SOURCES "ActivityManager.cpp"
|
||||
"PetDigServer.cpp"
|
||||
"PetFromDigServer.cpp"
|
||||
"PetFromObjectServer.cpp"
|
||||
"PirateRep.cpp"
|
||||
"PropertyBankInteract.cpp"
|
||||
"PropertyDeathPlane.cpp"
|
||||
"PropertyDevice.cpp"
|
||||
@ -201,6 +207,7 @@ set(DSCRIPT_SOURCES "ActivityManager.cpp"
|
||||
"PrSeagullFly.cpp"
|
||||
"PrWhistle.cpp"
|
||||
"QbEnemyStunner.cpp"
|
||||
"QbSpawner.cpp"
|
||||
"RaceImagineCrateServer.cpp"
|
||||
"RaceImaginePowerup.cpp"
|
||||
"RaceMaelstromGeiser.cpp"
|
||||
@ -240,6 +247,7 @@ set(DSCRIPT_SOURCES "ActivityManager.cpp"
|
||||
"WaveBossHammerling.cpp"
|
||||
"WaveBossHorsemen.cpp"
|
||||
"WaveBossSpiderling.cpp"
|
||||
"WblGenericZone.cpp"
|
||||
"WhFans.cpp"
|
||||
"WildAmbients.cpp"
|
||||
"WishingWellServer.cpp"
|
||||
|
@ -61,6 +61,8 @@
|
||||
#include "VeMissionConsole.h"
|
||||
#include "VeEpsilonServer.h"
|
||||
#include "AgSurvivalBuffStation.h"
|
||||
#include "QbSpawner.h"
|
||||
#include "AgQbWall.h"
|
||||
|
||||
// NS Scripts
|
||||
#include "NsModularBuild.h"
|
||||
@ -117,6 +119,9 @@
|
||||
#include "GfApeSmashingQB.h"
|
||||
#include "ZoneGfProperty.h"
|
||||
#include "GfArchway.h"
|
||||
#include "GfMaelstromGeyser.h"
|
||||
#include "PirateRep.h"
|
||||
#include "GfParrotCrash.h"
|
||||
|
||||
// SG Scripts
|
||||
#include "SGCannon.h"
|
||||
@ -141,12 +146,14 @@
|
||||
#include "FvConsoleLeftQuickbuild.h"
|
||||
#include "FvConsoleRightQuickbuild.h"
|
||||
#include "FvFacilityBrick.h"
|
||||
#include "FvFacilityPipes.h"
|
||||
#include "ImgBrickConsoleQB.h"
|
||||
#include "ActParadoxPipeFix.h"
|
||||
#include "FvNinjaGuard.h"
|
||||
#include "FvPassThroughWall.h"
|
||||
#include "FvBounceOverWall.h"
|
||||
#include "FvFong.h"
|
||||
#include "FvMaelstromGeyser.h"
|
||||
|
||||
// FB Scripts
|
||||
#include "AgJetEffectServer.h"
|
||||
@ -281,6 +288,9 @@
|
||||
#include "RockHydrantBroken.h"
|
||||
#include "WhFans.h"
|
||||
|
||||
// WBL scripts
|
||||
#include "WblGenericZone.h"
|
||||
|
||||
//Big bad global bc this is a namespace and not a class:
|
||||
InvalidScript* invalidToReturn = new InvalidScript();
|
||||
std::map<std::string, CppScripts::Script*> m_Scripts;
|
||||
@ -461,6 +471,10 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr
|
||||
script = new WildAmbients();
|
||||
else if (scriptName == "scripts\\ai\\NS\\NS_PP_01\\L_NS_PP_01_TELEPORT.lua")
|
||||
script = new PropertyDeathPlane();
|
||||
else if (scriptName == "scripts\\02_server\\Map\\General\\L_QB_SPAWNER.lua")
|
||||
script = new QbSpawner();
|
||||
else if (scriptName == "scripts\\ai\\AG\\L_AG_QB_Wall.lua")
|
||||
script = new AgQbWall();
|
||||
|
||||
//GF:
|
||||
else if (scriptName == "scripts\\02_server\\Map\\GF\\L_GF_TORCH.lua")
|
||||
@ -495,9 +509,14 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr
|
||||
script = new GfApeSmashingQB();
|
||||
else if (scriptName == "scripts\\zone\\PROPERTY\\GF\\L_ZONE_GF_PROPERTY.lua")
|
||||
script = new ZoneGfProperty();
|
||||
else if (scriptName == "scripts\\ai\\GF\\L_GF_ARCHWAY.lua") {
|
||||
else if (scriptName == "scripts\\ai\\GF\\L_GF_ARCHWAY.lua")
|
||||
script = new GfArchway();
|
||||
}
|
||||
else if (scriptName == "scripts\\ai\\GF\\L_GF_MAELSTROM_GEYSER.lua")
|
||||
script = new GfMaelstromGeyser();
|
||||
else if (scriptName == "scripts\\ai\\GF\\L_PIRATE_REP.lua")
|
||||
script = new PirateRep();
|
||||
else if (scriptName == "scripts\\ai\\GF\\L_GF_PARROT_CRASH.lua")
|
||||
script = new GfParrotCrash();
|
||||
|
||||
// SG
|
||||
else if (scriptName == "scripts\\ai\\MINIGAME\\SG_GF\\SERVER\\SG_CANNON.lua")
|
||||
@ -564,6 +583,8 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr
|
||||
script = new FvConsoleRightQuickbuild();
|
||||
else if (scriptName == "scripts\\ai\\FV\\L_FV_FACILITY_BRICK.lua")
|
||||
script = new FvFacilityBrick();
|
||||
else if (scriptName == "scripts\\ai\\FV\\L_FV_FACILITY_PIPES.lua")
|
||||
script = new FvFacilityPipes();
|
||||
else if (scriptName == "scripts\\02_server\\Map\\FV\\L_IMG_BRICK_CONSOLE_QB.lua")
|
||||
script = new ImgBrickConsoleQB();
|
||||
else if (scriptName == "scripts\\ai\\FV\\L_ACT_PARADOX_PIPE_FIX.lua")
|
||||
@ -576,6 +597,9 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr
|
||||
script = new FvBounceOverWall();
|
||||
else if (scriptName == "scripts\\02_server\\Map\\FV\\L_NPC_FONG.lua")
|
||||
script = new FvFong();
|
||||
else if (scriptName == "scripts\\ai\\FV\\L_FV_MAELSTROM_GEYSER.lua") {
|
||||
script = new FvMaelstromGeyser();
|
||||
}
|
||||
|
||||
//Misc:
|
||||
if (scriptName == "scripts\\02_server\\Map\\General\\L_EXPLODING_ASSET.lua")
|
||||
@ -813,12 +837,17 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr
|
||||
script = new BuccaneerValiantShip();
|
||||
else if (scriptName == "scripts\\EquipmentScripts\\FireFirstSkillonStartup.lua")
|
||||
script = new FireFirstSkillonStartup();
|
||||
|
||||
// FB
|
||||
else if (scriptName == "scripts\\ai\\NS\\WH\\L_ROCKHYDRANT_BROKEN.lua")
|
||||
script = new RockHydrantBroken();
|
||||
else if (scriptName == "scripts\\ai\\NS\\L_NS_WH_FANS.lua")
|
||||
script = new WhFans();
|
||||
|
||||
// WBL
|
||||
else if (scriptName == "scripts\\zone\\LUPs\\WBL_generic_zone.lua")
|
||||
script = new WblGenericZone();
|
||||
|
||||
//Ignore these scripts:
|
||||
else if (scriptName == "scripts\\02_server\\Enemy\\General\\L_SUSPEND_LUA_AI.lua")
|
||||
script = invalidToReturn;
|
||||
|
10
dScripts/FvFacilityPipes.cpp
Normal file
10
dScripts/FvFacilityPipes.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
#include "FvFacilityPipes.h"
|
||||
#include "GameMessages.h"
|
||||
|
||||
void FvFacilityPipes::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) {
|
||||
if (args == "startFX") {
|
||||
GameMessages::SendPlayFXEffect(self->GetObjectID(), m_LeftPipeEffectID, m_EffectType, m_LeftPipeEffectName);
|
||||
GameMessages::SendPlayFXEffect(self->GetObjectID(), m_RightPipeEffectID, m_EffectType, m_RightPipeEffectName);
|
||||
GameMessages::SendPlayFXEffect(self->GetObjectID(), m_ImaginationCanisterEffectID, m_EffectType, m_ImaginationCanisterEffectName);
|
||||
}
|
||||
}
|
15
dScripts/FvFacilityPipes.h
Normal file
15
dScripts/FvFacilityPipes.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include "CppScripts.h"
|
||||
|
||||
class FvFacilityPipes : public CppScripts::Script {
|
||||
public:
|
||||
void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override;
|
||||
private:
|
||||
const std::u16string m_EffectType = u"create";
|
||||
const std::string m_LeftPipeEffectName = "LeftPipeOff";
|
||||
const int32_t m_LeftPipeEffectID = 2774;
|
||||
const std::string m_RightPipeEffectName = "RightPipeOff";
|
||||
const int32_t m_RightPipeEffectID = 2777;
|
||||
const std::string m_ImaginationCanisterEffectName = "imagination_canister";
|
||||
const int32_t m_ImaginationCanisterEffectID = 2750;
|
||||
};
|
18
dScripts/FvMaelstromGeyser.cpp
Normal file
18
dScripts/FvMaelstromGeyser.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
#include "FvMaelstromGeyser.h"
|
||||
#include "SkillComponent.h"
|
||||
|
||||
void FvMaelstromGeyser::OnStartup(Entity* self) {
|
||||
self->AddTimer(m_StartSkillTimerName, m_StartSkillTimerTime);
|
||||
self->AddTimer(m_KillSelfTimerName, m_KillSelfTimerTime);
|
||||
}
|
||||
|
||||
void FvMaelstromGeyser::OnTimerDone(Entity* self, std::string timerName) {
|
||||
if (timerName == m_StartSkillTimerName) {
|
||||
auto* skillComponent = self->GetComponent<SkillComponent>();
|
||||
skillComponent->CalculateBehavior(m_SkillID, m_BehaviorID, LWOOBJID_EMPTY, true);
|
||||
}
|
||||
if (timerName == m_KillSelfTimerName) {
|
||||
self->Smash(LWOOBJID_EMPTY, eKillType::SILENT);
|
||||
}
|
||||
}
|
||||
|
18
dScripts/FvMaelstromGeyser.h
Normal file
18
dScripts/FvMaelstromGeyser.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include "CppScripts.h"
|
||||
|
||||
class FvMaelstromGeyser final : public CppScripts::Script
|
||||
{
|
||||
public:
|
||||
void OnStartup(Entity* self) override;
|
||||
void OnTimerDone(Entity* self, std::string timerName) override;
|
||||
|
||||
|
||||
private:
|
||||
const std::string m_StartSkillTimerName = "startSkill";
|
||||
const float m_StartSkillTimerTime = 2.0;
|
||||
const std::string m_KillSelfTimerName = "killSelf";
|
||||
const float m_KillSelfTimerTime = 5.5;
|
||||
const uint32_t m_SkillID = 831;
|
||||
const uint32_t m_BehaviorID = 15500;
|
||||
};
|
18
dScripts/GfMaelstromGeyser.cpp
Normal file
18
dScripts/GfMaelstromGeyser.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
#include "GfMaelstromGeyser.h"
|
||||
#include "SkillComponent.h"
|
||||
|
||||
void GfMaelstromGeyser::OnStartup(Entity* self) {
|
||||
self->AddTimer(m_StartSkillTimerName, m_StartSkillTimerTime);
|
||||
self->AddTimer(m_KillSelfTimerName, m_KillSelfTimerTime);
|
||||
}
|
||||
|
||||
void GfMaelstromGeyser::OnTimerDone(Entity* self, std::string timerName) {
|
||||
if (timerName == m_StartSkillTimerName) {
|
||||
auto* skillComponent = self->GetComponent<SkillComponent>();
|
||||
skillComponent->CalculateBehavior(m_SkillID, m_BehaviorID, LWOOBJID_EMPTY, true);
|
||||
}
|
||||
if (timerName == m_KillSelfTimerName) {
|
||||
self->Smash(LWOOBJID_EMPTY, eKillType::SILENT);
|
||||
}
|
||||
}
|
||||
|
17
dScripts/GfMaelstromGeyser.h
Normal file
17
dScripts/GfMaelstromGeyser.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include "CppScripts.h"
|
||||
|
||||
class GfMaelstromGeyser final : public CppScripts::Script
|
||||
{
|
||||
public:
|
||||
void OnStartup(Entity* self) override;
|
||||
void OnTimerDone(Entity* self, std::string timerName) override;
|
||||
|
||||
private:
|
||||
const std::string m_StartSkillTimerName = "startSkill";
|
||||
const float m_StartSkillTimerTime = 2.0;
|
||||
const std::string m_KillSelfTimerName = "killSelf";
|
||||
const float m_KillSelfTimerTime = 7.5;
|
||||
const uint32_t m_SkillID = 607;
|
||||
const uint32_t m_BehaviorID = 10500;
|
||||
};
|
13
dScripts/GfParrotCrash.cpp
Normal file
13
dScripts/GfParrotCrash.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include "GfParrotCrash.h"
|
||||
#include "SkillComponent.h"
|
||||
#include "Entity.h"
|
||||
#include "dLogger.h"
|
||||
|
||||
void GfParrotCrash::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) {
|
||||
auto* skillComponent = self->GetComponent<SkillComponent>();
|
||||
if (args == "Slow") {
|
||||
skillComponent->CalculateBehavior(m_SlowSkillID, m_SlowBehaviorID, sender->GetObjectID());
|
||||
} else if (args == "Unslow") {
|
||||
skillComponent->CalculateBehavior(m_UnslowSkillID, m_UnslowBehaviorID, sender->GetObjectID());
|
||||
}
|
||||
}
|
13
dScripts/GfParrotCrash.h
Normal file
13
dScripts/GfParrotCrash.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include "CppScripts.h"
|
||||
|
||||
class GfParrotCrash : public CppScripts::Script {
|
||||
public:
|
||||
void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override;
|
||||
private:
|
||||
const uint32_t m_SlowSkillID = 795;
|
||||
const uint32_t m_SlowBehaviorID = 14214;
|
||||
const uint32_t m_UnslowSkillID = 796;
|
||||
const uint32_t m_UnslowBehaviorID = 14215;
|
||||
};
|
||||
|
@ -9,3 +9,11 @@ void MailBoxServer::OnUse(Entity* self, Entity* user) {
|
||||
args.InsertValue("state", value);
|
||||
GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "pushGameState", &args);
|
||||
}
|
||||
|
||||
void MailBoxServer::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) {
|
||||
if (args == "toggleMail") {
|
||||
AMFArrayValue args;
|
||||
args.InsertValue("visible", new AMFFalseValue());
|
||||
GameMessages::SendUIMessageServerToSingleClient(sender, sender->GetSystemAddress(), "ToggleMail", &args);
|
||||
}
|
||||
}
|
||||
|
@ -12,4 +12,5 @@ public:
|
||||
* @param user The user that interacted with this Entity.
|
||||
*/
|
||||
void OnUse(Entity* self, Entity* user) override;
|
||||
void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override;
|
||||
};
|
||||
|
11
dScripts/PirateRep.cpp
Normal file
11
dScripts/PirateRep.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include "PirateRep.h"
|
||||
#include "Character.h"
|
||||
|
||||
void PirateRep::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) {
|
||||
if (missionID == m_PirateRepMissionID && missionState >= MissionState::MISSION_STATE_READY_TO_COMPLETE) {
|
||||
auto* character = target->GetCharacter();
|
||||
if (character) {
|
||||
character->SetPlayerFlag(ePlayerFlags::GF_PIRATE_REP, true);
|
||||
}
|
||||
}
|
||||
}
|
9
dScripts/PirateRep.h
Normal file
9
dScripts/PirateRep.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include "CppScripts.h"
|
||||
|
||||
class PirateRep : public CppScripts::Script {
|
||||
public:
|
||||
void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override;
|
||||
private:
|
||||
const int m_PirateRepMissionID = 301;
|
||||
};
|
136
dScripts/QbSpawner.cpp
Normal file
136
dScripts/QbSpawner.cpp
Normal file
@ -0,0 +1,136 @@
|
||||
#include "QbSpawner.h"
|
||||
#include "BaseCombatAIComponent.h"
|
||||
#include "MovementAIComponent.h"
|
||||
|
||||
void QbSpawner::OnStartup(Entity* self) {
|
||||
auto mobNum = self->GetVar<int>(u"mobNum");
|
||||
auto spawnDist = self->GetVar<float>(u"spawnDist");
|
||||
auto mobTemplate = self->GetVar<LWOOBJID>(u"mobTemplate");
|
||||
auto spawnTime = self->GetVar<float>(u"spawnTime");
|
||||
|
||||
if (!mobNum) self->SetVar<int>(u"mobNum", m_DefaultMobNum);
|
||||
if (!spawnDist) self->SetVar<float>(u"spawnDist", m_DefaultSpawnDist);
|
||||
if (!mobTemplate) self->SetVar<LWOOBJID>(u"mobTemplate", m_DefaultMobTemplate);
|
||||
if (!spawnTime) self->SetVar<float>(u"spawnTime", m_DefaultSpawnTime);
|
||||
|
||||
// go ahead and setup the mob table here
|
||||
std::vector<LWOOBJID> mobTable;
|
||||
mobTable.assign(self->GetVar<int>(u"mobNum"), LWOOBJID_EMPTY);
|
||||
|
||||
self->SetVar<std::vector<LWOOBJID>>(u"mobTable", mobTable);
|
||||
}
|
||||
|
||||
void QbSpawner::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) {
|
||||
auto gateObjID = sender->GetObjectID();
|
||||
if (!gateObjID) return;
|
||||
if (args == "spawnMobs") {
|
||||
self->SetVar(u"gateObj", gateObjID);
|
||||
auto spawnTime = self->GetVar<float>(u"spawnTime");
|
||||
self->AddTimer("SpawnMobEnemies", spawnTime);
|
||||
}
|
||||
}
|
||||
|
||||
void QbSpawner::OnTimerDone(Entity* self, std::string timerName) {
|
||||
if (timerName == "SpawnMobEnemies") {
|
||||
auto mobTable = self->GetVar<std::vector<LWOOBJID>>(u"mobTable");
|
||||
|
||||
auto spawnDist = self->GetVar<float>(u"spawnDist");
|
||||
auto mobTemplate = self->GetVar<LWOOBJID>(u"mobTemplate");
|
||||
|
||||
auto gateObjID = self->GetVar<LWOOBJID>(u"gateObj");
|
||||
if (!gateObjID) return;
|
||||
|
||||
auto* gate = EntityManager::Instance()->GetEntity(gateObjID);
|
||||
if (!gate) return;
|
||||
|
||||
auto oPos = gate->GetPosition();
|
||||
auto oDir = gate->GetRotation().GetForwardVector();
|
||||
NiPoint3 newPos(
|
||||
oPos.x + (oDir.x * spawnDist),
|
||||
oPos.y,
|
||||
oPos.z + (oDir.z * spawnDist)
|
||||
);
|
||||
auto newRot = NiQuaternion::LookAt(newPos, oPos);
|
||||
|
||||
for (int i = 0; i < mobTable.size(); i++) {
|
||||
int posOffset = -10;
|
||||
if (mobTable[i] == LWOOBJID_EMPTY) {
|
||||
posOffset = posOffset + 5 * i;
|
||||
auto newOffset = newPos;
|
||||
newOffset.z = newOffset.z + posOffset;
|
||||
|
||||
EntityInfo info{};
|
||||
info.lot = mobTemplate;
|
||||
info.pos = newOffset;
|
||||
info.rot = newRot;
|
||||
info.spawnerID = self->GetObjectID();
|
||||
info.spawnerNodeID = 0;
|
||||
info.settings = {
|
||||
new LDFData<bool>(u"no_timed_spawn", true),
|
||||
new LDFData<float>(u"aggroRadius", 70),
|
||||
new LDFData<float>(u"softtetherRadius", 80),
|
||||
new LDFData<float>(u"tetherRadius", 90),
|
||||
new LDFData<float>(u"wanderRadius", 5),
|
||||
new LDFData<int>(u"mobTableLoc", i)
|
||||
};
|
||||
|
||||
auto* child = EntityManager::Instance()->CreateEntity(info, nullptr, self);
|
||||
EntityManager::Instance()->ConstructEntity(child);
|
||||
|
||||
OnChildLoaded(self, child);
|
||||
} else {
|
||||
auto* mob = EntityManager::Instance()->GetEntity(mobTable[i]);
|
||||
AggroTargetObject(self, mob);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void QbSpawner::OnChildLoaded(Entity* self, Entity* child) {
|
||||
auto mobTable = self->GetVar<std::vector<LWOOBJID>>(u"mobTable");
|
||||
auto tableLoc = child->GetVar<int>(u"mobTableLoc");
|
||||
|
||||
mobTable[tableLoc] = child->GetObjectID();
|
||||
self->SetVar<std::vector<LWOOBJID>>(u"mobTable", mobTable);
|
||||
|
||||
AggroTargetObject(self, child);
|
||||
|
||||
const auto selfID = self->GetObjectID();
|
||||
|
||||
child->AddDieCallback([this, selfID, child]() {
|
||||
auto* self = EntityManager::Instance()->GetEntity(selfID);
|
||||
OnChildRemoved(self, child);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void QbSpawner::OnChildRemoved(Entity* self, Entity* child) {
|
||||
auto mobTable = self->GetVar<std::vector<LWOOBJID>>(u"mobTable");
|
||||
auto tableLoc = child->GetVar<int>(u"mobTableLoc");
|
||||
|
||||
mobTable[tableLoc] = LWOOBJID_EMPTY;
|
||||
self->SetVar<std::vector<LWOOBJID>>(u"mobTable", mobTable);
|
||||
}
|
||||
|
||||
void QbSpawner::AggroTargetObject(Entity* self, Entity* enemy) {
|
||||
auto* baseCombatAIComponent = enemy->GetComponent<BaseCombatAIComponent>();
|
||||
if (!baseCombatAIComponent) return;
|
||||
|
||||
auto gateObjID = self->GetVar<LWOOBJID>(u"gateObj");
|
||||
if (gateObjID) {
|
||||
auto* gate = EntityManager::Instance()->GetEntity(gateObjID);
|
||||
if (gate) {
|
||||
auto* movementAIComponent = enemy->GetComponent<MovementAIComponent>();
|
||||
if (movementAIComponent) movementAIComponent->SetDestination(gate->GetPosition());
|
||||
baseCombatAIComponent->Taunt(gateObjID, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
auto playerObjID = self->GetVar<LWOOBJID>(u"player");
|
||||
if (playerObjID) {
|
||||
baseCombatAIComponent->Taunt(playerObjID, 100);
|
||||
}
|
||||
|
||||
}
|
||||
|
17
dScripts/QbSpawner.h
Normal file
17
dScripts/QbSpawner.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include "CppScripts.h"
|
||||
|
||||
class QbSpawner : public CppScripts::Script {
|
||||
public:
|
||||
void OnStartup(Entity* self) override;
|
||||
void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override;
|
||||
void OnTimerDone(Entity* self, std::string timerName) override;
|
||||
void OnChildLoaded(Entity* self, Entity* child);
|
||||
void OnChildRemoved(Entity* self, Entity* child);
|
||||
void AggroTargetObject(Entity* self, Entity* enemy);
|
||||
private:
|
||||
const int m_DefaultMobNum = 3;
|
||||
const float m_DefaultSpawnDist = 25.0;
|
||||
const LWOOBJID m_DefaultMobTemplate = 4712;
|
||||
const float m_DefaultSpawnTime = 2.0;
|
||||
};
|
10
dScripts/WblGenericZone.cpp
Normal file
10
dScripts/WblGenericZone.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
#include "WblGenericZone.h"
|
||||
#include "Player.h"
|
||||
|
||||
void WblGenericZone::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) {
|
||||
if (args == m_WblAbortMsg) {
|
||||
if (!sender) return;
|
||||
auto player = dynamic_cast<Player*>(sender);
|
||||
if (player) player->SendToZone(m_WblMainZone);
|
||||
}
|
||||
}
|
10
dScripts/WblGenericZone.h
Normal file
10
dScripts/WblGenericZone.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include "CppScripts.h"
|
||||
class WblGenericZone : public CppScripts::Script
|
||||
{
|
||||
public:
|
||||
void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override;
|
||||
private:
|
||||
const LWOMAPID m_WblMainZone = 1600;
|
||||
const std::string m_WblAbortMsg = "AbortWBLZone";
|
||||
};
|
@ -63,7 +63,8 @@ These commands are primarily for development and testing. The usage of many of t
|
||||
|teleport|`/teleport <x> (y) <z>`|Teleports you. If no Y is given, you are teleported to the height of the terrain or physics object at (x, z). Alias: `/tele`.|6|
|
||||
|activatespawner|`/activatespawner <spawner name>`|Activates spawner by name.|8|
|
||||
|addmission|`/addmission <mission id>`|Accepts the mission, adding it to your journal.|8|
|
||||
|boost|`/boost`|Adds a passive boost action if you are in a vehicle.|8|
|
||||
|boost|`/boost (time)`|Adds a passive boost action if you are in a vehicle. If time is given it will end after that amount of time|8|
|
||||
|unboost|`/unboost`|Removes a passive vehicle boost|8|
|
||||
|buff|`/buff <id> <duration>`|Applies the buff with the given id for the given number of seconds.|8|
|
||||
|buffme|`/buffme`|Sets health, armor, and imagination to 999.|8|
|
||||
|buffmed|`/buffmed`|Sets health, armor, and imagination to 9.|8|
|
||||
@ -71,7 +72,7 @@ These commands are primarily for development and testing. The usage of many of t
|
||||
|completemission|`/completemission <mission id>`|Completes the mission, removing it from your journal.|8|
|
||||
|createprivate|`/createprivate <zone id> <clone id> <password>`|Creates a private zone with password.|8|
|
||||
|debugui|`/debugui`|Toggle Debug UI.|8|
|
||||
|dismount|`/dismount`|Dismounts you from the vehicle.|8|
|
||||
|dismount|`/dismount`|Dismounts you from the vehicle or mount.|8|
|
||||
|force-save|`/force-save`|While saving to database usually happens on regular intervals and when you disconnect from the server, this command saves your player's data to the database.|8|
|
||||
|freecam|`/freecam`|Toggles freecam mode.|8|
|
||||
|freemoney|`/freemoney <coins>`|Gives coins.|8|
|
||||
|
16
thirdparty/CMakeLists.txt
vendored
16
thirdparty/CMakeLists.txt
vendored
@ -6,13 +6,15 @@ set(tinyxml2_BUILD_TESTING OFF)
|
||||
# Source Code for tinyxml2
|
||||
add_subdirectory(tinyxml2)
|
||||
|
||||
# Source Code for libbcrypt
|
||||
# Disable warning about no project version.
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0048 NEW)
|
||||
# Disable warning about the minimum version of cmake used for bcrypt being deprecated in the future
|
||||
set(CMAKE_WARN_DEPRECATED OFF CACHE BOOL "" FORCE)
|
||||
|
||||
add_subdirectory(libbcrypt)
|
||||
# Source Code for libbcrypt. Uses a file glob instead to get around Windows build issues.
|
||||
file(
|
||||
GLOB SOURCES_LIBBCRYPT
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/libbcrypt/*.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/libbcrypt/src/*.c
|
||||
)
|
||||
add_library(bcrypt ${SOURCES_LIBBCRYPT})
|
||||
|
||||
# Source code for sqlite
|
||||
add_subdirectory(SQLite)
|
||||
|
Loading…
Reference in New Issue
Block a user