mirror of
				https://github.com/DarkflameUniverse/DarkflameServer.git
				synced 2025-10-31 04:32:06 +00:00 
			
		
		
		
	Merge branch 'main' into ub-fixes
This commit is contained in:
		| @@ -957,6 +957,7 @@ namespace MessageType { | ||||
| 		MODIFY_PLAYER_ZONE_STATISTIC = 1046, | ||||
| 		APPLY_EXTERNAL_FORCE = 1049, | ||||
| 		GET_APPLIED_EXTERNAL_FORCE = 1050, | ||||
| 		ACTIVITY_NOTIFY = 1051, | ||||
| 		ITEM_EQUIPPED = 1052, | ||||
| 		ACTIVITY_STATE_CHANGE_REQUEST = 1053, | ||||
| 		OVERRIDE_FRICTION = 1054, | ||||
|   | ||||
| @@ -14,7 +14,7 @@ public: | ||||
| 		uint32_t lastPlayedTimestamp{}; | ||||
| 		float primaryScore{}; | ||||
| 		float secondaryScore{}; | ||||
| 		uint32_t tertiaryScore{}; | ||||
| 		float tertiaryScore{}; | ||||
| 		uint32_t numWins{}; | ||||
| 		uint32_t numTimesPlayed{}; | ||||
| 		uint32_t ranking{}; | ||||
|   | ||||
| @@ -1493,6 +1493,14 @@ void Entity::OnChoiceBoxResponse(Entity* sender, int32_t button, const std::u16s | ||||
| 	GetScript()->OnChoiceBoxResponse(this, sender, button, buttonIdentifier, identifier); | ||||
| } | ||||
|  | ||||
| void Entity::OnActivityNotify(GameMessages::ActivityNotify& notify) { | ||||
| 	GetScript()->OnActivityNotify(this, notify); | ||||
| } | ||||
|  | ||||
| void Entity::OnShootingGalleryFire(GameMessages::ShootingGalleryFire& fire) { | ||||
| 	GetScript()->OnShootingGalleryFire(*this, fire); | ||||
| } | ||||
|  | ||||
| void Entity::RequestActivityExit(Entity* sender, LWOOBJID player, bool canceled) { | ||||
| 	GetScript()->OnRequestActivityExit(sender, player, canceled); | ||||
| } | ||||
|   | ||||
| @@ -13,6 +13,11 @@ | ||||
| #include "eKillType.h" | ||||
| #include "Observable.h" | ||||
|  | ||||
| namespace GameMessages { | ||||
| 	struct ActivityNotify; | ||||
| 	struct ShootingGalleryFire; | ||||
| }; | ||||
|  | ||||
| namespace Loot { | ||||
| 	class Info; | ||||
| }; | ||||
| @@ -210,6 +215,8 @@ public: | ||||
| 	void OnZonePropertyModelRemoved(Entity* player); | ||||
| 	void OnZonePropertyModelRemovedWhileEquipped(Entity* player); | ||||
| 	void OnZonePropertyModelRotated(Entity* player); | ||||
| 	void OnActivityNotify(GameMessages::ActivityNotify& notify); | ||||
| 	void OnShootingGalleryFire(GameMessages::ShootingGalleryFire& notify); | ||||
|  | ||||
| 	void OnMessageBoxResponse(Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData); | ||||
| 	void OnChoiceBoxResponse(Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier); | ||||
|   | ||||
| @@ -95,7 +95,7 @@ void QueryToLdf(Leaderboard& leaderboard, const std::vector<ILeaderboard::Entry> | ||||
| 			// Score:1 | ||||
| 			entry.push_back(new LDFData<int32_t>(u"Streak", leaderboardEntry.secondaryScore)); | ||||
| 			// Streak:1 | ||||
| 			entry.push_back(new LDFData<float>(u"HitPercentage", (leaderboardEntry.tertiaryScore / 100.0f))); | ||||
| 			entry.push_back(new LDFData<float>(u"HitPercentage", leaderboardEntry.tertiaryScore)); | ||||
| 			// HitPercentage:3 between 0 and 1 | ||||
| 			break; | ||||
| 		case Racing: | ||||
| @@ -199,9 +199,9 @@ std::vector<ILeaderboard::Entry> FilterFriends(const std::vector<ILeaderboard::E | ||||
| 	std::vector<ILeaderboard::Entry> friendsLeaderboard; | ||||
| 	for (const auto& entry : leaderboard) { | ||||
| 		const auto res = std::ranges::find_if(friendOfPlayer, [&entry, relatedPlayer](const FriendData& data) { | ||||
| 			return entry.charId == data.friendID || entry.charId == relatedPlayer; | ||||
| 			return entry.charId == data.friendID; | ||||
| 			}); | ||||
| 		if (res != friendOfPlayer.cend()) { | ||||
| 		if (res != friendOfPlayer.cend() || entry.charId == relatedPlayer) { | ||||
| 			friendsLeaderboard.push_back(entry); | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
| @@ -69,9 +69,10 @@ InventoryComponent::InventoryComponent(Entity* parent) : Component(parent) { | ||||
| 	auto slot = 0u; | ||||
|  | ||||
| 	for (const auto& item : items) { | ||||
| 		if (!item.equip || !Inventory::IsValidItem(item.itemid)) { | ||||
| 			continue; | ||||
| 		} | ||||
| 		if (!Inventory::IsValidItem(item.itemid)) continue; | ||||
| 		AddItem(item.itemid, item.count); | ||||
|  | ||||
| 		if (!item.equip) continue; | ||||
|  | ||||
| 		const LWOOBJID id = ObjectIDManager::GenerateObjectID(); | ||||
|  | ||||
|   | ||||
| @@ -265,6 +265,7 @@ void MovementAIComponent::PullToPoint(const NiPoint3& point) { | ||||
|  | ||||
| void MovementAIComponent::SetPath(std::vector<PathWaypoint> path) { | ||||
| 	if (path.empty()) return; | ||||
| 	while (!m_CurrentPath.empty()) m_CurrentPath.pop(); | ||||
| 	std::for_each(path.rbegin(), path.rend() - 1, [this](const PathWaypoint& point) { | ||||
| 		this->m_CurrentPath.push(point); | ||||
| 		}); | ||||
|   | ||||
| @@ -524,7 +524,7 @@ void PetComponent::NotifyTamingBuildSuccess(NiPoint3 position) { | ||||
|  | ||||
| 	GameMessages::SendRegisterPetDBID(m_Tamer, petSubKey, tamer->GetSystemAddress()); | ||||
|  | ||||
| 	inventoryComponent->AddItem(m_Parent->GetLOT(), 1, eLootSourceType::ACTIVITY, eInventoryType::MODELS, {}, LWOOBJID_EMPTY, true, false, petSubKey); | ||||
| 	inventoryComponent->AddItem(m_Parent->GetLOT(), 1, eLootSourceType::INVENTORY, eInventoryType::MODELS, {}, LWOOBJID_EMPTY, true, false, petSubKey); | ||||
| 	auto* item = inventoryComponent->FindItemBySubKey(petSubKey, MODELS); | ||||
|  | ||||
| 	if (item == nullptr) { | ||||
|   | ||||
| @@ -123,6 +123,11 @@ void SkillComponent::SyncPlayerProjectile(const LWOOBJID projectileId, RakNet::B | ||||
| 	behavior->Handle(sync_entry.context, bitStream, branch); | ||||
|  | ||||
| 	this->m_managedProjectiles.erase(this->m_managedProjectiles.begin() + index); | ||||
|  | ||||
| 	GameMessages::ActivityNotify notify; | ||||
| 	notify.notification.push_back( std::make_unique<LDFData<int32_t>>(u"shot_done", sync_entry.skillId)); | ||||
|  | ||||
| 	m_Parent->OnActivityNotify(notify); | ||||
| } | ||||
|  | ||||
| void SkillComponent::RegisterPlayerProjectile(const LWOOBJID projectileId, BehaviorContext* context, const BehaviorBranchContext& branch, const LOT lot) { | ||||
| @@ -132,6 +137,7 @@ void SkillComponent::RegisterPlayerProjectile(const LWOOBJID projectileId, Behav | ||||
| 	entry.branchContext = branch; | ||||
| 	entry.lot = lot; | ||||
| 	entry.id = projectileId; | ||||
| 	entry.skillId = context->skillID; | ||||
|  | ||||
| 	this->m_managedProjectiles.push_back(entry); | ||||
| } | ||||
|   | ||||
| @@ -40,6 +40,8 @@ struct ProjectileSyncEntry { | ||||
|  | ||||
| 	BehaviorBranchContext branchContext{ 0, 0 }; | ||||
|  | ||||
| 	int32_t skillId{ 0 }; | ||||
|  | ||||
| 	explicit ProjectileSyncEntry(); | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -703,6 +703,12 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System | ||||
| 	case MessageType::Game::UPDATE_INVENTORY_GROUP_CONTENTS: | ||||
| 		GameMessages::HandleUpdateInventoryGroupContents(inStream, entity, sysAddr); | ||||
| 		break; | ||||
| 	case MessageType::Game::SHOOTING_GALLERY_FIRE: { | ||||
| 		GameMessages::ShootingGalleryFire fire{}; | ||||
| 		fire.Deserialize(inStream); | ||||
| 		fire.Handle(*entity, sysAddr); | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	default: | ||||
| 		LOG_DEBUG("Received Unknown GM with ID: %4i, %s", messageID, StringifiedEnum::ToString(messageID).data()); | ||||
|   | ||||
| @@ -6395,4 +6395,35 @@ namespace GameMessages { | ||||
| 		bitStream.Write(targetPosition.y); | ||||
| 		bitStream.Write(targetPosition.z); | ||||
| 	} | ||||
|  | ||||
| 	void SetModelToBuild::Serialize(RakNet::BitStream& bitStream) const { | ||||
| 		bitStream.Write(modelLot != -1); | ||||
| 		if (modelLot != -1) bitStream.Write(modelLot); | ||||
| 	} | ||||
|  | ||||
| 	void SpawnModelBricks::Serialize(RakNet::BitStream& bitStream) const { | ||||
| 		bitStream.Write(amount != 0.0f); | ||||
| 		if (amount != 0.0f) bitStream.Write(amount); | ||||
| 		bitStream.Write(position != NiPoint3Constant::ZERO); | ||||
| 		if (position != NiPoint3Constant::ZERO) { | ||||
| 			bitStream.Write(position.x); | ||||
| 			bitStream.Write(position.y); | ||||
| 			bitStream.Write(position.z); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	bool ShootingGalleryFire::Deserialize(RakNet::BitStream& bitStream) { | ||||
| 		if (!bitStream.Read(target.x)) return false; | ||||
| 		if (!bitStream.Read(target.y)) return false; | ||||
| 		if (!bitStream.Read(target.z)) return false; | ||||
| 		if (!bitStream.Read(rotation.w)) return false; | ||||
| 		if (!bitStream.Read(rotation.x)) return false; | ||||
| 		if (!bitStream.Read(rotation.y)) return false; | ||||
| 		if (!bitStream.Read(rotation.z)) return false; | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	void ShootingGalleryFire::Handle(Entity& entity, const SystemAddress& sysAddr) { | ||||
| 		entity.OnShootingGalleryFire(*this); | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -54,6 +54,8 @@ namespace GameMessages { | ||||
| 		virtual ~GameMsg() = default; | ||||
| 		void Send(const SystemAddress& sysAddr) const; | ||||
| 		virtual void Serialize(RakNet::BitStream& bitStream) const {} | ||||
| 		virtual bool Deserialize(RakNet::BitStream& bitStream) { return true; } | ||||
| 		virtual void Handle(Entity& entity, const SystemAddress& sysAddr) {}; | ||||
| 		MessageType::Game msgId; | ||||
| 		LWOOBJID target{ LWOOBJID_EMPTY }; | ||||
| 	}; | ||||
| @@ -727,6 +729,35 @@ namespace GameMessages { | ||||
| 		ConfigureRacingControl() : GameMsg(MessageType::Game::CONFIGURE_RACING_CONTROL) {} | ||||
| 		std::vector<std::unique_ptr<LDFBaseData>> racingSettings{}; | ||||
| 	}; | ||||
|  | ||||
| 	struct SetModelToBuild : public GameMsg { | ||||
| 		SetModelToBuild() : GameMsg(MessageType::Game::SET_MODEL_TO_BUILD) {} | ||||
| 		void Serialize(RakNet::BitStream& bitStream) const override; | ||||
| 		LOT modelLot{ -1 }; | ||||
| 	}; | ||||
|  | ||||
| 	struct SpawnModelBricks : public GameMsg { | ||||
| 		SpawnModelBricks() : GameMsg(MessageType::Game::SPAWN_MODEL_BRICKS) {} | ||||
| 		void Serialize(RakNet::BitStream& bitStream) const override; | ||||
|  | ||||
| 		float amount{ 0.0f }; | ||||
| 		NiPoint3 position{ NiPoint3Constant::ZERO }; | ||||
| 	}; | ||||
|  | ||||
| 	struct ActivityNotify : public GameMsg { | ||||
| 		ActivityNotify() : GameMsg(MessageType::Game::ACTIVITY_NOTIFY) {} | ||||
|  | ||||
| 		std::vector<std::unique_ptr<LDFBaseData>> notification{}; | ||||
| 	}; | ||||
|  | ||||
| 	struct ShootingGalleryFire : public GameMsg { | ||||
| 		ShootingGalleryFire() : GameMsg(MessageType::Game::SHOOTING_GALLERY_FIRE) {} | ||||
| 		bool Deserialize(RakNet::BitStream& bitStream) override; | ||||
| 		void Handle(Entity& entity, const SystemAddress& sysAddr) override; | ||||
|  | ||||
| 		NiPoint3 target{}; | ||||
| 		NiQuaternion rotation{}; | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| #endif // GAMEMESSAGES_H | ||||
|   | ||||
| @@ -12,7 +12,7 @@ void VeBricksampleServer::OnUse(Entity* self, Entity* user) { | ||||
| 		auto* inventoryComponent = user->GetComponent<InventoryComponent>(); | ||||
|  | ||||
| 		if (loot && inventoryComponent != nullptr && inventoryComponent->GetLotCount(loot) == 0) { | ||||
| 			inventoryComponent->AddItem(loot, 1, eLootSourceType::ACTIVITY); | ||||
| 			inventoryComponent->AddItem(loot, 1, eLootSourceType::NONE); | ||||
|  | ||||
| 			for (auto* brickEntity : Game::entityManager->GetEntitiesInGroup("Bricks")) { | ||||
| 				GameMessages::SendNotifyClientObject(brickEntity->GetObjectID(), u"Pickedup"); | ||||
|   | ||||
| @@ -10,7 +10,7 @@ void VeMissionConsole::OnUse(Entity* self, Entity* user) { | ||||
|  | ||||
| 	auto* inventoryComponent = user->GetComponent<InventoryComponent>(); | ||||
| 	if (inventoryComponent != nullptr) { | ||||
| 		inventoryComponent->AddItem(12547, 1, eLootSourceType::ACTIVITY);  // Add the panel required for pickup | ||||
| 		inventoryComponent->AddItem(12547, 1, eLootSourceType::NONE);  // Add the panel required for pickup | ||||
| 	} | ||||
|  | ||||
| 	// The flag to set is 101<number> | ||||
|   | ||||
| @@ -163,7 +163,7 @@ int32_t ActivityManager::GetGameID(Entity* self) const { | ||||
|  | ||||
| float_t ActivityManager::ActivityTimerGetRemainingTime(Entity* self, const std::string& timerName) const { | ||||
| 	auto* timer = GetTimer(timerName); | ||||
| 	return timer != nullptr ? std::min(timer->stopTime - timer->runTime, 0.0f) : 0.0f; | ||||
| 	return timer != nullptr ? std::max(timer->stopTime - timer->runTime, 0.0f) : 0.0f; | ||||
| } | ||||
|  | ||||
| void ActivityManager::ActivityTimerReset(Entity* self, const std::string& timerName) { | ||||
|   | ||||
| @@ -357,6 +357,22 @@ namespace CppScripts { | ||||
| 		virtual void OnRequestActivityExit(Entity* sender, LWOOBJID player, bool canceled) {}; | ||||
|  | ||||
| 		virtual void OnZoneLoadedInfo(Entity* self, const GameMessages::ZoneLoadedInfo& info) {}; | ||||
|  | ||||
| 		/** | ||||
| 		 * @brief Handles notifying when activity data is done | ||||
| 		 *  | ||||
| 		 * @param self  | ||||
| 		 * @param notify The parameters of the notification | ||||
| 		 */ | ||||
| 		virtual void OnActivityNotify(Entity* self, GameMessages::ActivityNotify& notify) {}; | ||||
|  | ||||
| 		/** | ||||
| 		 * @brief handles shooting gallery fire | ||||
| 		 *  | ||||
| 		 * @param self  | ||||
| 		 * @param fire The firing data | ||||
| 		 */ | ||||
| 		virtual void OnShootingGalleryFire(Entity& self, GameMessages::ShootingGalleryFire& fire) {}; | ||||
| 	}; | ||||
|  | ||||
| 	Script* const GetScript(Entity* parent, const std::string& scriptName); | ||||
|   | ||||
| @@ -16,6 +16,8 @@ | ||||
| #include "eReplicaComponentType.h" | ||||
| #include "RenderComponent.h" | ||||
| #include "eGameActivity.h" | ||||
| #include "Item.h" | ||||
| #include <ranges> | ||||
|  | ||||
| void SGCannon::OnStartup(Entity* self) { | ||||
| 	LOG("OnStartup"); | ||||
| @@ -81,10 +83,6 @@ void SGCannon::OnActivityStateChangeRequest(Entity* self, LWOOBJID senderID, int | ||||
| 		auto* player = Game::entityManager->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); | ||||
| 		if (player != nullptr) { | ||||
| 			LOG("Player is ready"); | ||||
| 			/*GameMessages::SendSetStunned(player->GetObjectID(), eStateChangeType::PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, | ||||
| 										 true, true, true, true, true, true, true);*/ | ||||
|  | ||||
| 			LOG("Sending ActivityEnter"); | ||||
|  | ||||
| 			GameMessages::SendActivityEnter(self->GetObjectID(), player->GetSystemAddress()); | ||||
|  | ||||
| @@ -103,7 +101,6 @@ void SGCannon::OnActivityStateChangeRequest(Entity* self, LWOOBJID senderID, int | ||||
| 			auto* characterComponent = player->GetComponent<CharacterComponent>(); | ||||
|  | ||||
| 			if (characterComponent != nullptr) { | ||||
| 				characterComponent->SetIsRacing(true); | ||||
| 				characterComponent->SetCurrentActivity(eGameActivity::SHOOTING_GALLERY); | ||||
| 				auto possessor = player->GetComponent<PossessorComponent>(); | ||||
| 				if (possessor) { | ||||
| @@ -114,20 +111,12 @@ void SGCannon::OnActivityStateChangeRequest(Entity* self, LWOOBJID senderID, int | ||||
| 				Game::entityManager->SerializeEntity(player); | ||||
| 			} | ||||
|  | ||||
| 			self->SetNetworkVar<bool>(HideScoreBoardVariable, true); | ||||
| 			self->SetNetworkVar<bool>(ReSetSuperChargeVariable, true); | ||||
| 			self->SetNetworkVar<bool>(ShowLoadingUI, true); | ||||
| 			self->AddCallbackTimer(1.0f, [self, this]() { | ||||
| 				self->SetNetworkVar<bool>(HideScoreBoardVariable, true); | ||||
| 				self->SetNetworkVar<bool>(ReSetSuperChargeVariable, true); | ||||
| 				self->SetNetworkVar<bool>(ShowLoadingUI, true); | ||||
| 				}); | ||||
|  | ||||
| 			/* | ||||
| 			GameMessages::SendTeleport( | ||||
| 				player->GetObjectID(), | ||||
| 				{-292.6415710449219, 230.20237731933594, -3.9090466499328613}, | ||||
| 				{0.7067984342575073, -6.527870573336259e-05, 0.707414984703064, 0.00021762956748716533}, | ||||
| 				player->GetSystemAddress(), true | ||||
| 			); | ||||
| 			*/ | ||||
|  | ||||
| 			//GameMessages::SendRequestActivityEnter(self->GetObjectID(), player->GetSystemAddress(), false, player->GetObjectID()); | ||||
| 		} else { | ||||
| 			LOG("Player not found"); | ||||
| 		} | ||||
| @@ -245,14 +234,6 @@ void SGCannon::GameOverTimerFunc(Entity* self) { | ||||
|  | ||||
| 		GameMessages::SendActivityPause(self->GetObjectID(), true, player->GetSystemAddress()); | ||||
|  | ||||
| 		/*const auto leftoverCannonballs = Game::entityManager->GetEntitiesInGroup("cannonball"); | ||||
| 		if (leftoverCannonballs.empty()) { | ||||
| 			RecordPlayerScore(self); | ||||
|  | ||||
| 		} else { | ||||
| 			ActivityTimerStart(self, EndGameBufferTimer, 1, leftoverCannonballs.size()); | ||||
| 		}*/ | ||||
|  | ||||
| 		ActivityTimerStart(self, EndGameBufferTimer, 1, 1); | ||||
|  | ||||
| 		TimerToggle(self); | ||||
| @@ -261,60 +242,51 @@ void SGCannon::GameOverTimerFunc(Entity* self) { | ||||
|  | ||||
| void SGCannon::DoSpawnTimerFunc(Entity* self, const std::string& name) { | ||||
| 	if (self->GetVar<bool>(GameStartedVariable)) { | ||||
| 		LOG_DEBUG("time name %s %s", name.c_str(), name.substr(7).c_str()); | ||||
| 		const auto spawnNumber = static_cast<uint32_t>(std::stoi(name.substr(7))); | ||||
| 		const auto& activeSpawns = self->GetVar<std::vector<SGEnemy>>(ActiveSpawnsVariable); | ||||
| 		LOG_DEBUG("size %i, %i", activeSpawns.size(), spawnNumber); | ||||
| 		if (activeSpawns.size() <= spawnNumber) { | ||||
| 			LOG_DEBUG("Trying to spawn %i when spawns size is only %i", spawnNumber, activeSpawns.size()); | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		const auto& toSpawn = activeSpawns.at(spawnNumber); | ||||
| 		LOG_DEBUG("toSpawn %i", toSpawn.spawnPaths.size()); | ||||
| 		const auto pathIndex = GeneralUtils::GenerateRandomNumber<float_t>(0, toSpawn.spawnPaths.size() - 1); | ||||
| 		LOG_DEBUG("index %f", pathIndex); | ||||
| 		LOG_DEBUG("%s", toSpawn.spawnPaths.at(pathIndex).c_str()); | ||||
| 		const auto pathIndex = GeneralUtils::GenerateRandomNumber<size_t>(0, toSpawn.spawnPaths.size() - 1); | ||||
| 		const auto* path = Game::zoneManager->GetZone()->GetPath(toSpawn.spawnPaths.at(pathIndex)); | ||||
| 		if (!path) { | ||||
| 			LOG_DEBUG("Path %s at index %i is null", toSpawn.spawnPaths.at(pathIndex).c_str(), pathIndex); | ||||
| 		if (!path || path->pathWaypoints.empty()) { | ||||
| 			LOG_DEBUG("Path %s at index %i or has 0 waypoints", toSpawn.spawnPaths.at(pathIndex).c_str(), pathIndex); | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		LOG_DEBUG("%s", path->pathName.c_str()); | ||||
|  | ||||
| 		auto info = EntityInfo{}; | ||||
| 		info.lot = toSpawn.lot; | ||||
| 		info.spawnerID = self->GetObjectID(); | ||||
| 		info.pos = path->pathWaypoints.at(0).position; | ||||
| 		info.pos = path->pathWaypoints[0].position; | ||||
|  | ||||
| 		info.settings = { | ||||
| 			new LDFData<SGEnemy>(u"SpawnData", toSpawn), | ||||
| 			new LDFData<std::string>(u"custom_script_server", "scripts/ai/ACT/SG_TARGET.lua"), | ||||
| 			new LDFData<std::string>(u"custom_script_server", "scripts/ai/ACT/SG_TARGET.lua"), // this script is never loaded | ||||
| 			new LDFData<std::string>(u"custom_script_client", "scripts/client/ai/SG_TARGET_CLIENT.lua"), | ||||
| 			new LDFData<std::string>(u"attached_path", path->pathName), | ||||
| 			new LDFData<uint32_t>(u"attached_path_start", 0), | ||||
| 			new LDFData<std::u16string>(u"groupID", u"SGEnemy") | ||||
| 			new LDFData<std::u16string>(u"groupID", u"SGEnemy"), | ||||
| 			new LDFData<uint32_t>(u"wave", self->GetVar<uint32_t>(ThisWaveVariable)), | ||||
| 		}; | ||||
|  | ||||
| 		LOG_DEBUG("Spawning enemy %i on path %s", toSpawn.lot, path->pathName.c_str()); | ||||
|  | ||||
| 		auto* enemy = Game::entityManager->CreateEntity(info, nullptr, self); | ||||
| 		Game::entityManager->ConstructEntity(enemy); | ||||
|  | ||||
| 		auto* movementAI = enemy->AddComponent<MovementAIComponent>(MovementAIInfo{}); | ||||
| 		auto* simplePhysicsComponent = enemy->GetComponent<SimplePhysicsComponent>(); | ||||
| 		if (simplePhysicsComponent) { | ||||
| 			simplePhysicsComponent->SetPhysicsMotionState(4); | ||||
| 		} | ||||
|  | ||||
| 		Game::entityManager->ConstructEntity(enemy); | ||||
|  | ||||
| 		movementAI->SetMaxSpeed(toSpawn.initialSpeed); | ||||
| 		movementAI->SetCurrentSpeed(toSpawn.initialSpeed); | ||||
| 		movementAI->SetHaltDistance(0.0f); | ||||
|  | ||||
| 		std::vector<PathWaypoint> pathWaypoints = path->pathWaypoints; | ||||
|  | ||||
| 		if (GeneralUtils::GenerateRandomNumber<float_t>(0, 1) < 0.5f) { | ||||
| 			std::reverse(pathWaypoints.begin(), pathWaypoints.end()); | ||||
| 		} | ||||
|  | ||||
| 		movementAI->SetPath(pathWaypoints); | ||||
| 		movementAI->SetPath(path->pathWaypoints); | ||||
|  | ||||
| 		enemy->AddDieCallback([this, self, enemy, name]() { | ||||
| 			RegisterHit(self, enemy, name); | ||||
| @@ -362,7 +334,10 @@ void SGCannon::StartGame(Entity* self) { | ||||
|  | ||||
| 	auto rewardObjects = Game::entityManager->GetEntitiesInGroup(constants.rewardModelGroup); | ||||
| 	for (auto* reward : rewardObjects) { | ||||
| 		reward->OnFireEventServerSide(self, ModelToBuildEvent); | ||||
| 		GameMessages::SetModelToBuild modelToBuild{}; | ||||
| 		modelToBuild.modelLot = LOT_NULL; | ||||
| 		modelToBuild.target = reward->GetObjectID(); | ||||
| 		modelToBuild.Send(UNASSIGNED_SYSTEM_ADDRESS); | ||||
| 	} | ||||
|  | ||||
| 	auto* player = Game::entityManager->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); | ||||
| @@ -400,6 +375,10 @@ void SGCannon::DoGameStartup(Entity* self) { | ||||
| 		constants.firstWaveStartTime); | ||||
| } | ||||
|  | ||||
| void SGCannon::OnShootingGalleryFire(Entity& self, GameMessages::ShootingGalleryFire& fire) { | ||||
| 	self.SetVar<uint32_t>(ShotsFiredVariable, self.GetVar<uint32_t>(ShotsFiredVariable) + 1); | ||||
| } | ||||
|  | ||||
| void SGCannon::SpawnNewModel(Entity* self) { | ||||
|  | ||||
| 	// Add a new reward to the existing rewards | ||||
| @@ -407,6 +386,7 @@ void SGCannon::SpawnNewModel(Entity* self) { | ||||
| 	if (currentReward != -1) { | ||||
| 		auto rewards = self->GetVar<std::vector<LOT>>(RewardsVariable); | ||||
| 		rewards.push_back(currentReward); | ||||
| 		self->SetVar<std::vector<LOT>>(RewardsVariable, rewards); | ||||
| 		self->SetNetworkVar<int32_t>(RewardAddedVariable, currentReward); | ||||
| 	} | ||||
|  | ||||
| @@ -438,9 +418,13 @@ void SGCannon::SpawnNewModel(Entity* self) { | ||||
| 				std::unordered_map<LOT, int32_t> toDrop = {}; | ||||
| 				toDrop = Loot::RollLootMatrix(player, lootMatrix); | ||||
|  | ||||
| 				for (auto drop : toDrop) { | ||||
| 					rewardModel->OnFireEventServerSide(self, ModelToBuildEvent, drop.first); | ||||
| 					self->SetVar<LOT>(CurrentRewardVariable, drop.first); | ||||
| 				for (const auto [lot, count] : toDrop) { | ||||
| 					GameMessages::SetModelToBuild modelToBuild{}; | ||||
| 					modelToBuild.modelLot = lot; | ||||
| 					modelToBuild.target = rewardModel->GetObjectID(); | ||||
| 					modelToBuild.Send(player->GetSystemAddress()); | ||||
|  | ||||
| 					self->SetVar<LOT>(CurrentRewardVariable, lot); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| @@ -514,11 +498,11 @@ void SGCannon::RecordPlayerScore(Entity* self) { | ||||
| 	const auto currentWave = self->GetVar<uint32_t>(ThisWaveVariable); | ||||
|  | ||||
| 	if (currentWave > 0) { | ||||
| 		auto totalWaveScore = 0; | ||||
| 		auto totalWaveScore = totalScore; | ||||
| 		auto playerScores = self->GetVar<std::vector<int32_t>>(PlayerScoresVariable); | ||||
|  | ||||
| 		for (const auto& waveScore : playerScores) { | ||||
| 			totalWaveScore += waveScore; | ||||
| 			totalWaveScore -= waveScore; | ||||
| 		} | ||||
|  | ||||
| 		if (currentWave >= playerScores.size()) { | ||||
| @@ -526,6 +510,7 @@ void SGCannon::RecordPlayerScore(Entity* self) { | ||||
| 		} else { | ||||
| 			playerScores[currentWave] = totalWaveScore; | ||||
| 		} | ||||
| 		self->SetVar<std::vector<int32_t>>(PlayerScoresVariable, playerScores); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -547,12 +532,11 @@ void SGCannon::PlaySceneAnimation(Entity* self, const std::u16string& animationN | ||||
| } | ||||
|  | ||||
| void SGCannon::PauseChargeCannon(Entity* self) { | ||||
| 	const auto time = std::max(static_cast<uint32_t>(std::ceil(ActivityTimerGetCurrentTime(self, SuperChargeTimer))), static_cast<uint32_t>(1)); | ||||
| 	const auto time = std::max(static_cast<uint32_t>(std::ceil(ActivityTimerGetRemainingTime(self, SuperChargeTimer))), static_cast<uint32_t>(1)); | ||||
|  | ||||
| 	self->SetVar<bool>(SuperChargePausedVariable, true); | ||||
| 	self->SetVar<uint32_t>(CurrentSuperChargedTimeVariable, time); | ||||
| 	self->SetNetworkVar<uint32_t>(ChargeCountingVariable, time); | ||||
|  | ||||
| 	ActivityTimerStop(self, SuperChargeTimer); | ||||
| } | ||||
|  | ||||
| @@ -568,14 +552,17 @@ void SGCannon::StopGame(Entity* self, bool cancel) { | ||||
|  | ||||
| 	// The player won, store all the score and send rewards | ||||
| 	if (!cancel) { | ||||
| 		int32_t percentage = 0.0f; | ||||
| 		auto misses = self->GetVar<uint32_t>(MissesVariable); | ||||
| 		auto fired = self->GetVar<uint32_t>(ShotsFiredVariable); | ||||
| 		float percentage = 0.0f; | ||||
| 		float misses = self->GetVar<uint32_t>(MissesVariable); | ||||
| 		float fired = self->GetVar<uint32_t>(ShotsFiredVariable); | ||||
|  | ||||
| 		if (fired > 0) { | ||||
| 		if (fired > 0.0f) { | ||||
| 			percentage = misses / fired; | ||||
| 		} | ||||
|  | ||||
| 		percentage = 1.0f - percentage; | ||||
| 		percentage = std::max(percentage, 0.0f); | ||||
|  | ||||
| 		auto* missionComponent = player->GetComponent<MissionComponent>(); | ||||
|  | ||||
| 		if (missionComponent != nullptr) { | ||||
| @@ -596,13 +583,27 @@ void SGCannon::StopGame(Entity* self, bool cancel) { | ||||
| 		auto* inventory = player->GetComponent<InventoryComponent>(); | ||||
| 		if (inventory != nullptr) { | ||||
| 			for (const auto rewardLot : self->GetVar<std::vector<LOT>>(RewardsVariable)) { | ||||
| 				inventory->AddItem(rewardLot, 1, eLootSourceType::ACTIVITY, eInventoryType::MODELS); | ||||
| 				inventory->AddItem(rewardLot, 1, eLootSourceType::NONE, eInventoryType::MODELS); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		self->SetNetworkVar<std::u16string>(u"UI_Rewards", | ||||
| 			GeneralUtils::to_u16string(self->GetVar<int32_t>(TotalScoreVariable)) + u"_0_0_0_0_0_0" | ||||
| 		); | ||||
| 		const auto& waveScores = self->GetVar<std::vector<int32_t>>(PlayerScoresVariable); | ||||
| 		std::stringstream stream; | ||||
|  | ||||
| 		stream << self->GetVar<int32_t>(TotalScoreVariable) << "_"; | ||||
|  | ||||
| 		// technically unused in shooting gallery but serialize it regardless. | ||||
| 		for (const auto& score : waveScores) { | ||||
| 			stream << score << "_"; | ||||
| 		} | ||||
| 		auto totalmissed = fired - misses; | ||||
| 		if (totalmissed < 0) { | ||||
| 			totalmissed = 0; | ||||
| 		} | ||||
|  | ||||
| 		stream << fired << "_" << totalmissed << "_" << self->GetVar<uint32_t>(MaxStreakVariable); | ||||
|  | ||||
| 		self->SetNetworkVar<std::u16string>(u"UI_Rewards", GeneralUtils::ASCIIToUTF16(stream.str())); | ||||
| 	} | ||||
|  | ||||
| 	GameMessages::SendActivityStop(self->GetObjectID(), false, cancel, player->GetSystemAddress()); | ||||
| @@ -617,10 +618,42 @@ void SGCannon::StopGame(Entity* self, bool cancel) { | ||||
| 	ResetVars(self); | ||||
| } | ||||
|  | ||||
|  | ||||
| void SGCannon::OnActivityNotify(Entity* self, GameMessages::ActivityNotify& notify) { | ||||
| 	if (!self->GetVar<bool>(GameStartedVariable)) return; | ||||
|  | ||||
| 	const auto& params = notify.notification; | ||||
| 	if (params.empty()) return; | ||||
|  | ||||
| 	const auto& param = params[0]; | ||||
| 	if (param->GetValueType() != LDF_TYPE_S32 || param->GetKey() != u"shot_done") return; | ||||
|  | ||||
| 	const auto superChargeShotDone = static_cast<LDFData<int32_t>*>(param.get())->GetValue() == GetConstants().cannonSuperChargeSkill; | ||||
|  | ||||
| 	const auto& hitTargets = self->GetVar<std::vector<LWOOBJID>>(u"CannonBallKills"); | ||||
|  | ||||
| 	if (hitTargets.empty() && !superChargeShotDone) { | ||||
| 		self->SetVar<uint32_t>(u"m_curStreak", 0); | ||||
| 		self->SetVar<uint32_t>(MissesVariable, self->GetVar<uint32_t>(MissesVariable) + 1); | ||||
| 		self->SetNetworkVar<bool>(u"HideStreak", true); | ||||
| 		self->SetNetworkVar<bool>(u"UnMarkAll", true); | ||||
| 		UpdateStreak(self); | ||||
| 	} else if (hitTargets.size() > 1) { | ||||
| 		self->SetNetworkVar<bool>(u"mHit", true); | ||||
| 	} | ||||
|  | ||||
| 	self->SetVar<std::vector<LWOOBJID>>(u"CannonBallKills", {}); | ||||
| } | ||||
|  | ||||
| void SGCannon::RegisterHit(Entity* self, Entity* target, const std::string& timerName) { | ||||
| 	if (!self->GetVar<bool>(GameStartedVariable)) return; | ||||
|  | ||||
| 	auto cannonBallKills = self->GetVar<std::vector<LWOOBJID>>(u"CannonBallKills"); | ||||
| 	cannonBallKills.push_back(target->GetObjectID()); | ||||
| 	self->SetVar<std::vector<LWOOBJID>>(u"CannonBallKills", cannonBallKills); | ||||
| 	const auto& spawnInfo = target->GetVar<SGEnemy>(u"SpawnData"); | ||||
|  | ||||
| 	if (spawnInfo.respawns) { | ||||
| 	if (spawnInfo.respawns && target->GetVar<uint32_t>(u"wave") == self->GetVar<uint32_t>(ThisWaveVariable)) { | ||||
| 		const auto respawnTime = GeneralUtils::GenerateRandomNumber<float_t>(spawnInfo.minRespawnTime, spawnInfo.maxRespawnTime); | ||||
|  | ||||
| 		ActivityTimerStart(self, timerName, respawnTime, respawnTime); | ||||
| @@ -637,6 +670,7 @@ void SGCannon::RegisterHit(Entity* self, Entity* target, const std::string& time | ||||
| 	} else { | ||||
| 		if (!self->GetVar<bool>(SuperChargeActiveVariable)) { | ||||
| 			self->SetVar<uint32_t>(u"m_curStreak", 0); | ||||
| 			self->SetVar<uint32_t>(MissesVariable, self->GetVar<uint32_t>(MissesVariable) + 1); | ||||
| 		} | ||||
|  | ||||
| 		self->SetNetworkVar<bool>(u"hitFriend", true); | ||||
| @@ -646,10 +680,6 @@ void SGCannon::RegisterHit(Entity* self, Entity* target, const std::string& time | ||||
|  | ||||
| 	auto scScore = self->GetVar<int32_t>(TotalScoreVariable) - lastSuperTotal; | ||||
|  | ||||
| 	LOG("LastSuperTotal: %i, scScore: %i, constants.chargedPoints: %i", | ||||
| 		lastSuperTotal, scScore, constants.chargedPoints | ||||
| 	); | ||||
|  | ||||
| 	if (!self->GetVar<bool>(SuperChargeActiveVariable) && scScore >= constants.chargedPoints && score >= 0) { | ||||
| 		StartChargedCannon(self); | ||||
| 		self->SetNetworkVar<float>(u"SuperChargeBar", 100.0f); | ||||
| @@ -684,6 +714,40 @@ void SGCannon::RegisterHit(Entity* self, Entity* target, const std::string& time | ||||
| 	if (missionComponent == nullptr) return; | ||||
|  | ||||
| 	missionComponent->Progress(eMissionTaskType::SMASH, spawnInfo.lot, self->GetObjectID()); | ||||
|  | ||||
| 	auto matrix = self->GetVar<uint32_t>(MatrixVariable); | ||||
|  | ||||
| 	float rewardS = 0.0f; | ||||
| 	float rewardF = 0.0f; | ||||
| 	if (matrix <= 5) { | ||||
| 		const auto scoreRewardNum = "Score_Reward_" + std::to_string(matrix); | ||||
| 		const auto rewardAmountItr = constants.scoreRewards.find(scoreRewardNum); | ||||
| 		if (rewardAmountItr != constants.scoreRewards.end()) { | ||||
| 			const float rewardAmount = rewardAmountItr->second / 100 * 3; | ||||
| 			rewardS = newScore / rewardAmount; | ||||
| 			rewardF = std::round(rewardS * 3); | ||||
|  | ||||
| 			if (rewardF > 100.0f) rewardF = 100.0f; | ||||
|  | ||||
| 			self->SetNetworkVar(ModelPercentVariable, rewardF); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (rewardF > 0.0f && rewardF < 200.0f && matrix <= 5) { | ||||
| 		const auto rewardModelGroup = Game::entityManager->GetEntitiesInGroup(constants.rewardModelGroup); | ||||
| 		if (!rewardModelGroup.empty()) { | ||||
| 			auto* rewardModel = rewardModelGroup[0]; | ||||
| 			GameMessages::SpawnModelBricks spawnBricks{}; | ||||
| 			spawnBricks.target = rewardModel->GetObjectID(); | ||||
| 			spawnBricks.amount = rewardF / 100.0f; | ||||
| 			spawnBricks.position = target->GetPosition(); | ||||
| 			spawnBricks.Send(player->GetSystemAddress()); | ||||
| 			if (rewardF >= 100.0f) { | ||||
| 				SpawnNewModel(self); | ||||
| 				self->SetVar<uint32_t>(MatrixVariable, matrix + 1); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void SGCannon::UpdateStreak(Entity* self) { | ||||
| @@ -745,41 +809,34 @@ void SGCannon::ToggleSuperCharge(Entity* self, bool enable) { | ||||
|  | ||||
| 	auto* selfInventoryComponent = self->GetComponent<InventoryComponent>(); | ||||
|  | ||||
| 	if (inventoryComponent == nullptr) { | ||||
| 		LOG("Inventory component not found"); | ||||
| 	// This is a gm in the original script | ||||
| 	Item* meItem1{}; | ||||
| 	Item* meItem2{}; | ||||
| 	for (const auto item : selfInventoryComponent->GetInventory(eInventoryType::ITEMS)->GetItems() | std::views::values) { | ||||
| 		if (item->GetSlot() == 0) meItem1 = item; | ||||
| 		else if (item->GetSlot() == 1) meItem2 = item; | ||||
| 	} | ||||
|  | ||||
| 	if (!meItem1 || !meItem2) { | ||||
| 		LOG("Cannon does not have the required items equipped"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (enable) { | ||||
| 		LOG("Player is activating super charge"); | ||||
| 		selfInventoryComponent->UpdateSlot("greeble_r", { ObjectIDManager::GenerateRandomObjectID(), 6505, 1, 0 }); | ||||
| 		selfInventoryComponent->UpdateSlot("greeble_l", { ObjectIDManager::GenerateRandomObjectID(), 6506, 1, 0 }); | ||||
| 		selfInventoryComponent->EquipItem(meItem1); | ||||
| 		selfInventoryComponent->EquipItem(meItem2); | ||||
|  | ||||
| 		// TODO: Equip items | ||||
| 		skillID = constants.cannonSuperChargeSkill; | ||||
| 		cooldown = 400; | ||||
| 	} else { | ||||
| 		selfInventoryComponent->UpdateSlot("greeble_r", { ObjectIDManager::GenerateRandomObjectID(), 0, 0, 0 }); | ||||
| 		selfInventoryComponent->UpdateSlot("greeble_l", { ObjectIDManager::GenerateRandomObjectID(), 0, 0, 0 }); | ||||
| 		selfInventoryComponent->UnEquipItem(meItem1); | ||||
| 		selfInventoryComponent->UnEquipItem(meItem2); | ||||
|  | ||||
| 		self->SetNetworkVar<float>(u"SuperChargeBar", 0); | ||||
|  | ||||
| 		LOG("Player disables super charge"); | ||||
|  | ||||
| 		// TODO: Unequip items | ||||
| 		for (const auto& equipped : equippedItems) { | ||||
| 			if (equipped.first == "special_r" || equipped.first == "special_l") { | ||||
| 				LOG("Trying to unequip a weapon, %i", equipped.second.lot); | ||||
|  | ||||
| 				auto* item = inventoryComponent->FindItemById(equipped.second.id); | ||||
|  | ||||
| 				if (item != nullptr) { | ||||
| 					inventoryComponent->UnEquipItem(item); | ||||
| 				} else { | ||||
| 					LOG("Item not found, %i", equipped.second.lot); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		cooldown = 800; | ||||
| 		self->SetVar<uint32_t>(NumberOfChargesVariable, 0); | ||||
| 	} | ||||
| @@ -794,10 +851,10 @@ void SGCannon::ToggleSuperCharge(Entity* self, bool enable) { | ||||
|  | ||||
| 	DynamicShootingGalleryParams properties = shootingGalleryComponent->GetDynamicParams(); | ||||
|  | ||||
| 	properties.cannonFOV = 58.6f; | ||||
| 	properties.cannonVelocity = 129.0; | ||||
| 	properties.cannonFOV = constants.cannonFOV; | ||||
| 	properties.cannonVelocity = constants.cannonVelocity; | ||||
| 	properties.cannonRefireRate = cooldown; | ||||
| 	properties.cannonMinDistance = 30; | ||||
| 	properties.cannonMinDistance = constants.cannonMinDistance; | ||||
| 	properties.cannonTimeout = -1; | ||||
|  | ||||
| 	shootingGalleryComponent->SetDynamicParams(properties); | ||||
| @@ -829,22 +886,38 @@ std::vector<std::vector<SGEnemy>> SGCannon::GetWaves() { | ||||
| 			1.0, false, true | ||||
| 		}, | ||||
|  | ||||
| 		// Sub 1 | ||||
| 		// Sub 1 but for dlu | ||||
| 		{ | ||||
| 			std::vector<std::string> { "Wave_1_Sub_1", "Wave_1_Sub_2" }, | ||||
| 			6016, 0.0, 2.0, true, 0.0, 2.0, | ||||
| 			10.0, 1000, false, 0.0, 1.0, | ||||
| 			1.0, true, true | ||||
| 		}, | ||||
|  | ||||
| 		// Sub 2 | ||||
| 		{ | ||||
| 			std::vector<std::string> { "Wave_2_Sub_1", "Wave_2_Sub_2" }, | ||||
| 			6016, 0.0, 2.0, true, 0.0, 2.0, | ||||
| 			2.0, 1000, false, 0.0, 1.0, | ||||
| 			1.0, true, true | ||||
| 		}, | ||||
|  | ||||
| 		//// Sub 1 | ||||
| 		//{ | ||||
| 		//	std::vector<std::string> { "Wave_1_Sub_1", "Wave_1_Sub_2" }, | ||||
| 		//	6016, 0.0, 2.0, true, 0.0, 2.0, | ||||
| 		//	10.0, 1000, false, 0.0, 1.0, | ||||
| 		//	1.0, true, true | ||||
| 		//}, | ||||
|  | ||||
| 		// Sub 2 but for dlu | ||||
| 		{ | ||||
| 			std::vector<std::string> { "Wave_2_Sub_1", "Wave_2_Sub_2" }, | ||||
| 			6016, 0.0, 2.0, true, 0.0, 2.0, | ||||
| 			3.0, 1000, false, 0.0, 1.0, | ||||
| 			1.0, true, true | ||||
| 		}, | ||||
|  | ||||
| 		// Sub 2 | ||||
| 		//{ | ||||
| 		//	std::vector<std::string> { "Wave_2_Sub_1", "Wave_2_Sub_2" }, | ||||
| 		//	6016, 0.0, 2.0, true, 0.0, 2.0, | ||||
| 		//	2.0, 1000, false, 0.0, 1.0, | ||||
| 		//	1.0, true, true | ||||
| 		//}, | ||||
|  | ||||
| 		// Friendly | ||||
| 		{ | ||||
| 			std::vector<std::string> { "Wave_3_FShip_1", "Wave_3_FShip_2" }, | ||||
| @@ -897,10 +970,18 @@ std::vector<std::vector<SGEnemy>> SGCannon::GetWaves() { | ||||
| 		}, | ||||
|  | ||||
| 		// Sub 2 | ||||
| 		//{ | ||||
| 		//	std::vector<std::string> { "Wave_2_Sub_1", "Wave_2_Sub_2" }, | ||||
| 		//	6016, 0.0, 2.0, true, 0.0, 2.0, | ||||
| 		//	2.0, 1000, false, 0.0, 1.0, | ||||
| 		//	1.0, true, true | ||||
| 		//}, | ||||
|  | ||||
| 		// Sub 2 but for dlu | ||||
| 		{ | ||||
| 			std::vector<std::string> { "Wave_2_Sub_1", "Wave_2_Sub_2" }, | ||||
| 			6016, 0.0, 2.0, true, 0.0, 2.0, | ||||
| 			2.0, 1000, false, 0.0, 1.0, | ||||
| 			3.0, 1000, false, 0.0, 1.0, | ||||
| 			1.0, true, true | ||||
| 		}, | ||||
|  | ||||
| @@ -963,11 +1044,19 @@ std::vector<std::vector<SGEnemy>> SGCannon::GetWaves() { | ||||
| 			1.0, true, true | ||||
| 		}, | ||||
|  | ||||
| 		// Sub 2 | ||||
| 		//{ | ||||
| 		//	std::vector<std::string> { "Wave_2_Sub_1", "Wave_2_Sub_2" }, | ||||
| 		//	6016, 0.0, 2.0, true, 0.0, 2.0, | ||||
| 		//	2.0, 1000, false, 0.0, 1.0, | ||||
| 		//	1.0, true, true | ||||
| 		//}, | ||||
|  | ||||
| 		// Sub 2 | ||||
| 		{ | ||||
| 			std::vector<std::string> { "Wave_2_Sub_1", "Wave_2_Sub_2" }, | ||||
| 			6016, 0.0, 2.0, true, 0.0, 2.0, | ||||
| 			2.0, 1000, false, 0.0, 1.0, | ||||
| 			3.0, 1000, false, 0.0, 1.0, | ||||
| 			1.0, true, true | ||||
| 		}, | ||||
|  | ||||
| @@ -987,14 +1076,22 @@ std::vector<std::vector<SGEnemy>> SGCannon::GetWaves() { | ||||
| 			1.0, false, true | ||||
| 		}, | ||||
|  | ||||
| 		// Ness | ||||
| 		// Ness temp fix for dlu where speeds are set to 7 to match a speed closer to live while we work on movingplatform components. | ||||
| 		{ | ||||
| 			std::vector<std::string> { "Wave_1_Ness_1", "Wave_1_Ness_2", "Wave_2_Ness_1" }, | ||||
| 			2565, 10.0, 15.0, true, 10.0, 15.0, | ||||
| 			2.0, 10000, false, 0.0, 1.0, | ||||
| 			1.0, true, true | ||||
| 			7.0, 10000, false, 0.0, 7.0, | ||||
| 			7.0, true, true | ||||
| 		}, | ||||
|  | ||||
| 		// // Ness | ||||
| 		// { | ||||
| 		// 	std::vector<std::string> { "Wave_1_Ness_1", "Wave_1_Ness_2", "Wave_2_Ness_1" }, | ||||
| 		// 	2565, 10.0, 15.0, true, 10.0, 15.0, | ||||
| 		// 	2.0, 10000, false, 0.0, 1.0, | ||||
| 		// 	1.0, true, true | ||||
| 		// }, | ||||
|  | ||||
| 		// Friendly 1 | ||||
| 		{ | ||||
| 			std::vector<std::string> { "Wave_3_FShip_1", "Wave_3_FShip_2" }, | ||||
| @@ -1033,11 +1130,8 @@ void SGCannon::ResetVars(Entity* self) { | ||||
| 	self->SetVar<int32_t>(TotalScoreVariable, 0); | ||||
|  | ||||
| 	self->SetVar<uint32_t>(u"m_curStreak", 0); | ||||
| 	self->SetNetworkVar<float>(u"SuperChargeBar", 0); | ||||
| 	self->SetVar<uint32_t>(u"LastSuperTotal", 0); | ||||
| 	self->SetNetworkVar<float>(u"SuperChargeBar", 0.0f); | ||||
| 	self->SetNetworkVar<bool>(u"ShowStreak", 0); | ||||
| 	self->SetNetworkVar<bool>(u"UnMarkAll", true); | ||||
| 	self->SetVar<std::vector<LWOOBJID>>(u"LastHitTarget", {}); | ||||
|  | ||||
| 	const_cast<std::vector<SGEnemy>&>(self->GetVar<std::vector<SGEnemy>>(ActiveSpawnsVariable)).clear(); | ||||
| 	self->SetVar<std::vector<SGEnemy>>(ActiveSpawnsVariable, {}); | ||||
| @@ -1056,40 +1150,42 @@ void SGCannon::ResetVars(Entity* self) { | ||||
|  | ||||
| SGConstants SGCannon::GetConstants() { | ||||
| 	return { | ||||
| 		Vector3 { -908.542480, 229.773178, -908.542480 }, | ||||
| 		Quaternion { 0.91913521289825, 0, 0.39394217729568, 0 }, | ||||
| 		1864, | ||||
| 		34, | ||||
| 		1822, | ||||
| 		Vector3 { 6.652, -2, 1.5 }, | ||||
| 		157, | ||||
| 		129.0, | ||||
| 		30.0, | ||||
| 		800.0, | ||||
| 		Vector3 { 0, 4.3, 9 }, | ||||
| 		6297, | ||||
| 		1822, | ||||
| 		249, | ||||
| 		228, | ||||
| 		-1, | ||||
| 		58.6, | ||||
| 		true, | ||||
| 		2, | ||||
| 		10, | ||||
| 		25000, | ||||
| 		"QBRewardGroup", | ||||
| 		1864, | ||||
| 		50000, | ||||
| 		157, | ||||
| 		100000, | ||||
| 		187, | ||||
| 		200000, | ||||
| 		188, | ||||
| 		400000, | ||||
| 		189, | ||||
| 		800000, | ||||
| 		190, | ||||
| 		4.0, | ||||
| 		7.0 | ||||
| 		.playerStartPosition = Vector3 { -908.542480, 229.773178, -908.542480 }, | ||||
| 		.playerStartRotation = Quaternion { 0.91913521289825, 0, 0.39394217729568, 0 }, | ||||
| 		.cannonLot = 1864, | ||||
| 		.impactSkillID = 34, | ||||
| 		.projectileLot = 1822, | ||||
| 		.playerOffset = Vector3 { 6.652, -2, 1.5 }, | ||||
| 		.rewardModelMatrix = 157, | ||||
| 		.cannonVelocity = 129.0, | ||||
| 		.cannonMinDistance = 30.0, | ||||
| 		.cannonRefireRate = 800.0, | ||||
| 		.cannonBarrelOffset = Vector3 { 0, 4.3, 9 }, | ||||
| 		.cannonSuperchargedProjectileLot = 6297, | ||||
| 		.cannonProjectileLot = 1822, | ||||
| 		.cannonSuperChargeSkill = 249, | ||||
| 		.cannonSkill = 228, | ||||
| 		.cannonTimeout = -1, | ||||
| 		.cannonFOV = 58.6, | ||||
| 		.useLeaderboards = true, | ||||
| 		.streakModifier = 2, | ||||
| 		.chargedTime = 10, | ||||
| 		.chargedPoints = 25000, | ||||
| 		.rewardModelGroup = "QBRewardGroup", | ||||
| 		.activityID = 1864, | ||||
| 		.scoreRewards = { | ||||
| 			{"Score_Reward_1", 50000}, | ||||
| 			{"Score_Reward_2", 100000}, | ||||
| 			{"Score_Reward_3", 200000}, | ||||
| 			{"Score_Reward_4", 400000}, | ||||
| 			{"Score_Reward_5", 800000}, | ||||
| 		}, | ||||
| 		.scoreLootMatrix1 = 157, | ||||
| 		.scoreLootMatrix2 = 187, | ||||
| 		.scoreLootMatrix3 = 188, | ||||
| 		.scoreLootMatrix4 = 189, | ||||
| 		.scoreLootMatrix5 = 190, | ||||
| 		.firstWaveStartTime = 4.0, | ||||
| 		.inBetweenWavePause = 7.0 | ||||
| 	}; | ||||
| } | ||||
|   | ||||
| @@ -44,15 +44,11 @@ struct SGConstants { | ||||
| 	uint32_t chargedPoints; | ||||
| 	std::string rewardModelGroup; | ||||
| 	uint32_t activityID; | ||||
| 	uint32_t scoreReward1; | ||||
| 	std::map<std::string, uint32_t> scoreRewards; | ||||
| 	uint32_t scoreLootMatrix1; | ||||
| 	uint32_t scoreReward2; | ||||
| 	uint32_t scoreLootMatrix2; | ||||
| 	uint32_t scoreReward3; | ||||
| 	uint32_t scoreLootMatrix3; | ||||
| 	uint32_t scoreReward4; | ||||
| 	uint32_t scoreLootMatrix4; | ||||
| 	uint32_t scoreReward5; | ||||
| 	uint32_t scoreLootMatrix5; | ||||
| 	float_t firstWaveStartTime; | ||||
| 	float_t inBetweenWavePause; | ||||
| @@ -68,6 +64,8 @@ public: | ||||
| 	void OnActivityTimerDone(Entity* self, const std::string& name) override; | ||||
| 	void OnActivityTimerUpdate(Entity* self, const std::string& name, float_t timeRemaining, float_t elapsedTime) override; | ||||
| 	void OnRequestActivityExit(Entity* self, LWOOBJID player, bool canceled) override; | ||||
| 	void OnActivityNotify(Entity* self, GameMessages::ActivityNotify& notify) override; | ||||
| 	void OnShootingGalleryFire(Entity& self, GameMessages::ShootingGalleryFire& fire) override; | ||||
| 	void SuperChargeTimerFunc(Entity* self); | ||||
| 	void SpawnWaveTimerFunc(Entity* self); | ||||
| 	void EndWaveTimerFunc(Entity* self); | ||||
| @@ -142,6 +140,7 @@ private: | ||||
| 	std::u16string CannonBallSkillIDVariable = u"cbskill"; | ||||
| 	std::u16string HideSuperChargeVariable = u"HideSuper"; | ||||
| 	std::u16string AudioFinalWaveDoneVariable = u"Audio_Final_Wave_Done"; | ||||
| 	std::u16string ModelPercentVariable = u"modelPercent"; | ||||
|  | ||||
| 	std::string SpawnWaveTimer = "SpawnWave"; | ||||
| 	std::string EndWaveTimer = "EndWave"; | ||||
|   | ||||
| @@ -267,41 +267,31 @@ int main(int argc, char** argv) { | ||||
|  | ||||
| 	// pre calculate the FDB checksum | ||||
| 	if (Game::config->GetValue("check_fdb") == "1") { | ||||
| 		std::ifstream fileStream; | ||||
| 		auto cdclient = Game::assetManager->GetFile("cdclient.fdb"); | ||||
| 		if (cdclient) { | ||||
|  | ||||
| 		static const std::vector<std::string> aliases = { | ||||
| 			"CDServers.fdb", | ||||
| 			"cdserver.fdb", | ||||
| 			"CDClient.fdb", | ||||
| 			"cdclient.fdb", | ||||
| 		}; | ||||
| 			const int32_t bufferSize = 1024; | ||||
| 			MD5 md5; | ||||
|  | ||||
| 		for (const auto& file : aliases) { | ||||
| 			fileStream.open(Game::assetManager->GetResPath() / file, std::ios::binary | std::ios::in); | ||||
| 			if (fileStream.is_open()) { | ||||
| 				break; | ||||
| 			char fileStreamBuffer[bufferSize] = {}; | ||||
|  | ||||
| 			while (!cdclient.eof()) { | ||||
| 				memset(fileStreamBuffer, 0, bufferSize); | ||||
| 				cdclient.read(fileStreamBuffer, bufferSize); | ||||
| 				md5.update(fileStreamBuffer, cdclient.gcount()); | ||||
| 			} | ||||
|  | ||||
| 			const char* nullTerminateBuffer = "\0"; | ||||
| 			md5.update(nullTerminateBuffer, 1); // null terminate the data | ||||
| 			md5.finalize(); | ||||
| 			databaseChecksum = md5.hexdigest(); | ||||
|  | ||||
| 			LOG("FDB Checksum calculated as: %s", databaseChecksum.c_str()); | ||||
| 		} | ||||
|  | ||||
| 		const int32_t bufferSize = 1024; | ||||
| 		MD5 md5; | ||||
|  | ||||
| 		char fileStreamBuffer[1024] = {}; | ||||
|  | ||||
| 		while (!fileStream.eof()) { | ||||
| 			memset(fileStreamBuffer, 0, bufferSize); | ||||
| 			fileStream.read(fileStreamBuffer, bufferSize); | ||||
| 			md5.update(fileStreamBuffer, fileStream.gcount()); | ||||
| 		if (databaseChecksum.empty()) { | ||||
| 			LOG("check_fdb is on but no fdb file found."); | ||||
| 			return EXIT_FAILURE; | ||||
| 		} | ||||
|  | ||||
| 		fileStream.close(); | ||||
|  | ||||
| 		const char* nullTerminateBuffer = "\0"; | ||||
| 		md5.update(nullTerminateBuffer, 1); // null terminate the data | ||||
| 		md5.finalize(); | ||||
| 		databaseChecksum = md5.hexdigest(); | ||||
|  | ||||
| 		LOG("FDB Checksum calculated as: %s", databaseChecksum.c_str()); | ||||
| 	} | ||||
|  | ||||
| 	uint32_t currentFrameDelta = highFrameDelta; | ||||
| @@ -548,115 +538,115 @@ void HandlePacketChat(Packet* packet) { | ||||
| 	if (packet->data[0] == ID_USER_PACKET_ENUM && packet->length >= 4) { | ||||
| 		if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT) { | ||||
| 			switch (static_cast<MessageType::Chat>(packet->data[3])) { | ||||
| 				case MessageType::Chat::WORLD_ROUTE_PACKET: { | ||||
| 					CINSTREAM_SKIP_HEADER; | ||||
| 					LWOOBJID playerID; | ||||
| 					inStream.Read(playerID); | ||||
| 			case MessageType::Chat::WORLD_ROUTE_PACKET: { | ||||
| 				CINSTREAM_SKIP_HEADER; | ||||
| 				LWOOBJID playerID; | ||||
| 				inStream.Read(playerID); | ||||
|  | ||||
| 					auto player = Game::entityManager->GetEntity(playerID); | ||||
| 					if (!player) return; | ||||
| 				auto player = Game::entityManager->GetEntity(playerID); | ||||
| 				if (!player) return; | ||||
|  | ||||
| 					auto sysAddr = player->GetSystemAddress(); | ||||
| 				auto sysAddr = player->GetSystemAddress(); | ||||
|  | ||||
| 					//Write our stream outwards: | ||||
| 					CBITSTREAM; | ||||
| 					unsigned char data; | ||||
| 					while (inStream.Read(data)) { | ||||
| 						bitStream.Write(data); | ||||
| 					} | ||||
|  | ||||
| 					SEND_PACKET; //send routed packet to player | ||||
| 					break; | ||||
| 				//Write our stream outwards: | ||||
| 				CBITSTREAM; | ||||
| 				unsigned char data; | ||||
| 				while (inStream.Read(data)) { | ||||
| 					bitStream.Write(data); | ||||
| 				} | ||||
|  | ||||
| 				case MessageType::Chat::GM_ANNOUNCE: { | ||||
| 					CINSTREAM_SKIP_HEADER; | ||||
| 				SEND_PACKET; //send routed packet to player | ||||
| 				break; | ||||
| 			} | ||||
|  | ||||
| 					std::string title; | ||||
| 					std::string msg; | ||||
| 			case MessageType::Chat::GM_ANNOUNCE: { | ||||
| 				CINSTREAM_SKIP_HEADER; | ||||
|  | ||||
| 					uint32_t len; | ||||
| 					inStream.Read<uint32_t>(len); | ||||
| 					for (uint32_t i = 0; len > i; i++) { | ||||
| 						char character; | ||||
| 						inStream.Read<char>(character); | ||||
| 						title += character; | ||||
| 					} | ||||
| 				std::string title; | ||||
| 				std::string msg; | ||||
|  | ||||
| 					len = 0; | ||||
| 					inStream.Read<uint32_t>(len); | ||||
| 					for (uint32_t i = 0; len > i; i++) { | ||||
| 						char character; | ||||
| 						inStream.Read<char>(character); | ||||
| 						msg += character; | ||||
| 					} | ||||
| 				uint32_t len; | ||||
| 				inStream.Read<uint32_t>(len); | ||||
| 				for (uint32_t i = 0; len > i; i++) { | ||||
| 					char character; | ||||
| 					inStream.Read<char>(character); | ||||
| 					title += character; | ||||
| 				} | ||||
|  | ||||
| 					//Send to our clients: | ||||
| 					AMFArrayValue args; | ||||
| 				len = 0; | ||||
| 				inStream.Read<uint32_t>(len); | ||||
| 				for (uint32_t i = 0; len > i; i++) { | ||||
| 					char character; | ||||
| 					inStream.Read<char>(character); | ||||
| 					msg += character; | ||||
| 				} | ||||
|  | ||||
| 					args.Insert("title", title); | ||||
| 					args.Insert("message", msg); | ||||
| 				//Send to our clients: | ||||
| 				AMFArrayValue args; | ||||
|  | ||||
| 					GameMessages::SendUIMessageServerToAllClients("ToggleAnnounce", args); | ||||
| 				args.Insert("title", title); | ||||
| 				args.Insert("message", msg); | ||||
|  | ||||
| 				GameMessages::SendUIMessageServerToAllClients("ToggleAnnounce", args); | ||||
|  | ||||
| 				break; | ||||
| 			} | ||||
|  | ||||
| 			case MessageType::Chat::GM_MUTE: { | ||||
| 				CINSTREAM_SKIP_HEADER; | ||||
| 				LWOOBJID playerId; | ||||
| 				time_t expire = 0; | ||||
| 				inStream.Read(playerId); | ||||
| 				inStream.Read(expire); | ||||
|  | ||||
| 				auto* entity = Game::entityManager->GetEntity(playerId); | ||||
| 				auto* character = entity != nullptr ? entity->GetCharacter() : nullptr; | ||||
| 				auto* user = character != nullptr ? character->GetParentUser() : nullptr; | ||||
| 				if (user) { | ||||
| 					user->SetMuteExpire(expire); | ||||
|  | ||||
| 					entity->GetCharacter()->SendMuteNotice(); | ||||
| 				} | ||||
|  | ||||
| 				break; | ||||
| 			} | ||||
|  | ||||
| 			case MessageType::Chat::TEAM_GET_STATUS: { | ||||
| 				CINSTREAM_SKIP_HEADER; | ||||
|  | ||||
| 				LWOOBJID teamID = 0; | ||||
| 				char lootOption = 0; | ||||
| 				char memberCount = 0; | ||||
| 				std::vector<LWOOBJID> members; | ||||
|  | ||||
| 				inStream.Read(teamID); | ||||
| 				bool deleteTeam = inStream.ReadBit(); | ||||
|  | ||||
| 				if (deleteTeam) { | ||||
| 					TeamManager::Instance()->DeleteTeam(teamID); | ||||
|  | ||||
| 					LOG("Deleting team (%llu)", teamID); | ||||
|  | ||||
| 					break; | ||||
| 				} | ||||
|  | ||||
| 				case MessageType::Chat::GM_MUTE: { | ||||
| 					CINSTREAM_SKIP_HEADER; | ||||
| 					LWOOBJID playerId; | ||||
| 					time_t expire = 0; | ||||
| 					inStream.Read(playerId); | ||||
| 					inStream.Read(expire); | ||||
| 				inStream.Read(lootOption); | ||||
| 				inStream.Read(memberCount); | ||||
| 				LOG("Updating team (%llu), (%i), (%i)", teamID, lootOption, memberCount); | ||||
| 				for (char i = 0; i < memberCount; i++) { | ||||
| 					LWOOBJID member = LWOOBJID_EMPTY; | ||||
| 					inStream.Read(member); | ||||
| 					members.push_back(member); | ||||
|  | ||||
| 					auto* entity = Game::entityManager->GetEntity(playerId); | ||||
| 					auto* character = entity != nullptr ? entity->GetCharacter() : nullptr; | ||||
| 					auto* user = character != nullptr ? character->GetParentUser() : nullptr; | ||||
| 					if (user) { | ||||
| 						user->SetMuteExpire(expire); | ||||
|  | ||||
| 						entity->GetCharacter()->SendMuteNotice(); | ||||
| 					} | ||||
|  | ||||
| 					break; | ||||
| 					LOG("Updating team member (%llu)", member); | ||||
| 				} | ||||
|  | ||||
| 				case MessageType::Chat::TEAM_GET_STATUS: { | ||||
| 					CINSTREAM_SKIP_HEADER; | ||||
| 				TeamManager::Instance()->UpdateTeam(teamID, lootOption, members); | ||||
|  | ||||
| 					LWOOBJID teamID = 0; | ||||
| 					char lootOption = 0; | ||||
| 					char memberCount = 0; | ||||
| 					std::vector<LWOOBJID> members; | ||||
|  | ||||
| 					inStream.Read(teamID); | ||||
| 					bool deleteTeam = inStream.ReadBit(); | ||||
|  | ||||
| 					if (deleteTeam) { | ||||
| 						TeamManager::Instance()->DeleteTeam(teamID); | ||||
|  | ||||
| 						LOG("Deleting team (%llu)", teamID); | ||||
|  | ||||
| 						break; | ||||
| 					} | ||||
|  | ||||
| 					inStream.Read(lootOption); | ||||
| 					inStream.Read(memberCount); | ||||
| 					LOG("Updating team (%llu), (%i), (%i)", teamID, lootOption, memberCount); | ||||
| 					for (char i = 0; i < memberCount; i++) { | ||||
| 						LWOOBJID member = LWOOBJID_EMPTY; | ||||
| 						inStream.Read(member); | ||||
| 						members.push_back(member); | ||||
|  | ||||
| 						LOG("Updating team member (%llu)", member); | ||||
| 					} | ||||
|  | ||||
| 					TeamManager::Instance()->UpdateTeam(teamID, lootOption, members); | ||||
|  | ||||
| 					break; | ||||
| 				} | ||||
| 				default: | ||||
| 					LOG("Received an unknown chat: %i", int(packet->data[3])); | ||||
| 				break; | ||||
| 			} | ||||
| 			default: | ||||
| 				LOG("Received an unknown chat: %i", int(packet->data[3])); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 jadebenn
					jadebenn