Merge remote-tracking branch 'origin/master' into PerfectSoundForRelease
This commit is contained in:
@@ -27,7 +27,7 @@ void EntityWrapper::AttachComponent(const char* componentName)
|
||||
|
||||
EntityWrapper EntityWrapper::Parent()
|
||||
{
|
||||
if (this->World == nullptr || this->ID == EntityID_Invalid) {
|
||||
if (!Valid()) {
|
||||
return EntityWrapper::Invalid;
|
||||
} else {
|
||||
return EntityWrapper(this->World, this->World->GetParent(this->ID));
|
||||
@@ -36,6 +36,10 @@ EntityWrapper EntityWrapper::Parent()
|
||||
|
||||
EntityWrapper EntityWrapper::FirstParentByName(const std::string& parentEntityName)
|
||||
{
|
||||
if (!Valid()) {
|
||||
return EntityWrapper::Invalid;
|
||||
}
|
||||
|
||||
EntityWrapper entity = *this;
|
||||
while (entity.Parent().Valid()) {
|
||||
entity = entity.Parent();
|
||||
@@ -48,6 +52,10 @@ EntityWrapper EntityWrapper::FirstParentByName(const std::string& parentEntityNa
|
||||
|
||||
EntityWrapper EntityWrapper::FirstChildByName(const std::string& name)
|
||||
{
|
||||
if (!Valid()) {
|
||||
return EntityWrapper::Invalid;
|
||||
}
|
||||
|
||||
return firstChildByNameRecursive(name, this->ID);
|
||||
}
|
||||
|
||||
@@ -78,6 +86,10 @@ EntityWrapper EntityWrapper::FirstLevelChildByName(const std::string& name)
|
||||
|
||||
EntityWrapper EntityWrapper::FirstParentWithComponent(const std::string& componentType)
|
||||
{
|
||||
if (!Valid()) {
|
||||
return EntityWrapper::Invalid;
|
||||
}
|
||||
|
||||
EntityWrapper entity = *this;
|
||||
while (entity.Parent().Valid()) {
|
||||
entity = entity.Parent();
|
||||
|
||||
@@ -173,6 +173,9 @@ void Client::parseMessageType(Packet& packet)
|
||||
case MessageType::RemoveWorld:
|
||||
parseRemoveWorld(packet);
|
||||
break;
|
||||
case MessageType::KD:
|
||||
parseKDEvent(packet);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -357,6 +360,22 @@ void Client::parseRemoveWorld(Packet & packet)
|
||||
m_EventBroker->Publish(e);
|
||||
}
|
||||
|
||||
void Client::parseKDEvent(Packet & packet)
|
||||
{
|
||||
Events::KillDeath e;
|
||||
e.Casualty = packet.ReadPrimitive<int>();
|
||||
e.CasualtyClass = packet.ReadPrimitive<int>();
|
||||
e.CasualtyName = packet.ReadString();
|
||||
e.CasualtyTeam = packet.ReadPrimitive<int>();
|
||||
|
||||
e.Killer = packet.ReadPrimitive<int>();
|
||||
e.KillerClass = packet.ReadPrimitive<int>();
|
||||
e.KillerName = packet.ReadString();
|
||||
e.KillerTeam = packet.ReadPrimitive<int>();
|
||||
|
||||
m_EventBroker->Publish(e);
|
||||
}
|
||||
|
||||
void Client::updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID)
|
||||
{
|
||||
for (auto field : componentInfo.FieldsInOrder) {
|
||||
|
||||
@@ -560,9 +560,48 @@ bool Server::OnAmmoPickup(const Events::AmmoPickup & e)
|
||||
bool Server::OnPlayerDeath(const Events::PlayerDeath& e)
|
||||
{
|
||||
Events::KillDeath eKD;
|
||||
auto entity = e;
|
||||
eKD.Casualty = getPlayerIDFromEntityID(e.Player.ID);
|
||||
eKD.Killer = getPlayerIDFromEntityID(e.Killer.ID);
|
||||
|
||||
eKD.CasualtyName = m_ConnectedPlayers.at(getPlayerIDFromEntityID(e.Player.ID)).Name;
|
||||
eKD.KillerName = m_ConnectedPlayers.at(getPlayerIDFromEntityID(e.Killer.ID)).Name;
|
||||
|
||||
if(entity.Player.HasComponent("Team")) {
|
||||
eKD.CasualtyTeam = (const int&)entity.Player["Team"]["Team"];
|
||||
}
|
||||
if (entity.Killer.HasComponent("Team")) {
|
||||
eKD.KillerTeam = (const int&)entity.Killer["Team"]["Team"];
|
||||
}
|
||||
|
||||
if(entity.Player.HasComponent("DashAbility")) {
|
||||
eKD.CasualtyClass = 1;
|
||||
} else if (entity.Player.HasComponent("ShieldAbility")) {
|
||||
eKD.CasualtyClass = 2;
|
||||
} else if (entity.Player.HasComponent("SprintAbility")) {
|
||||
eKD.CasualtyClass = 3;
|
||||
}
|
||||
if (entity.Killer.HasComponent("DashAbility")) {
|
||||
eKD.KillerClass = 1;
|
||||
} else if (entity.Killer.HasComponent("ShieldAbility")) {
|
||||
eKD.KillerClass = 2;
|
||||
} else if (entity.Killer.HasComponent("SprintAbility")) {
|
||||
eKD.KillerClass = 3;
|
||||
}
|
||||
|
||||
m_EventBroker->Publish(eKD);
|
||||
|
||||
Packet kdPacket(MessageType::KD);
|
||||
kdPacket.WritePrimitive(eKD.Casualty);
|
||||
kdPacket.WritePrimitive(eKD.CasualtyClass);
|
||||
kdPacket.WriteString(eKD.CasualtyName);
|
||||
kdPacket.WritePrimitive(eKD.CasualtyTeam);
|
||||
|
||||
kdPacket.WritePrimitive(eKD.Killer);
|
||||
kdPacket.WritePrimitive(eKD.KillerClass);
|
||||
kdPacket.WriteString(eKD.KillerName);
|
||||
kdPacket.WritePrimitive(eKD.KillerTeam);
|
||||
reliableBroadcast(kdPacket);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,18 +76,18 @@ void AnimationSystem::UpdateAnimations(double dt)
|
||||
Field<std::string> res = modelEntity["Model"]["Resource"];
|
||||
model = ResourceManager::Load<::Model, true>(res);
|
||||
} catch (const std::exception&) {
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
Skeleton* skeleton = model->m_RawModel->m_Skeleton;
|
||||
if (skeleton == nullptr) {
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
const Skeleton::Animation* animation = skeleton->GetAnimation(animationC["AnimationName"]);
|
||||
|
||||
if (animation == nullptr) {
|
||||
continue;;
|
||||
continue;
|
||||
}
|
||||
|
||||
double animationSpeed = (const double&)animationC["Speed"];
|
||||
@@ -128,8 +128,8 @@ void AnimationSystem::UpdateAnimations(double dt)
|
||||
void AnimationSystem::UpdateWeights(double dt)
|
||||
{
|
||||
for (auto it = m_AutoBlendQueues.begin(); it != m_AutoBlendQueues.end(); ) {
|
||||
/* LOG_INFO("%s", it->first.Name().c_str());
|
||||
it->second.PrintQueue();*/
|
||||
//LOG_INFO("%s", it->first.Name().c_str());
|
||||
//it->second.PrintQueue();
|
||||
|
||||
if(it->second.HasActiveBlendJob()) {
|
||||
AutoBlendQueue::AutoBlendJob& blendJob = it->second.GetActiveBlendJob();
|
||||
@@ -159,12 +159,13 @@ void AnimationSystem::UpdateWeights(double dt)
|
||||
|
||||
bool AnimationSystem::OnAutoAnimationBlend(Events::AutoAnimationBlend& e)
|
||||
{
|
||||
|
||||
if (!e.RootNode.Valid()) {
|
||||
LOG_ERROR("%s, RootNode invalid %s", e.NodeName, e.RootNode.Name().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!e.RootNode.HasComponent("Model")) {
|
||||
LOG_ERROR("%s, RootNode has no model %s", e.NodeName, e.RootNode.Name().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -172,11 +173,13 @@ bool AnimationSystem::OnAutoAnimationBlend(Events::AutoAnimationBlend& e)
|
||||
try {
|
||||
model = ResourceManager::Load<::Model, true>((std::string)e.RootNode["Model"]["Resource"]);
|
||||
} catch (const std::exception&) {
|
||||
LOG_ERROR("%s, RootNode model not finished loading %s", e.NodeName, e.RootNode.Name().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
Skeleton* skeleton = model->m_RawModel->m_Skeleton;
|
||||
if (skeleton == nullptr) {
|
||||
LOG_ERROR("%s, RootNode skeleton invalid %s", e.NodeName, e.RootNode.Name().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -184,6 +187,7 @@ bool AnimationSystem::OnAutoAnimationBlend(Events::AutoAnimationBlend& e)
|
||||
if (skeleton->BlendTrees.find(e.RootNode) != skeleton->BlendTrees.end()) {
|
||||
blendTree = skeleton->BlendTrees.at(e.RootNode);
|
||||
} else {
|
||||
LOG_ERROR("%s, No blendtree was found invalid %s", e.NodeName, e.RootNode.Name().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -194,6 +198,7 @@ bool AnimationSystem::OnAutoAnimationBlend(Events::AutoAnimationBlend& e)
|
||||
subTreeRoot = blendTree->GetSubTreeRoot(e.NodeName);
|
||||
|
||||
if (!subTreeRoot.Valid()) {
|
||||
LOG_ERROR("%s, subTreeRoot invalid", e.NodeName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -238,6 +243,7 @@ bool AnimationSystem::OnAutoAnimationBlend(Events::AutoAnimationBlend& e)
|
||||
subTreeRoot = entity;
|
||||
|
||||
if (!subTreeRoot.Valid()) {
|
||||
LOG_ERROR("%s, subTreeRoot invalid", e.NodeName);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1336,7 +1336,7 @@ void DrawFinalPass::DrawToDepthStencilBuffer(std::list<std::shared_ptr<RenderJob
|
||||
} else {
|
||||
frameBones = modelJob->Skeleton->GetTPose();
|
||||
}
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
|
||||
|
||||
} else {
|
||||
if (lastShader != m_FillDepthStencilBufferProgram->GetHandle()) {
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
#include "Game/Systems/MainMenuSystem.h"
|
||||
#include "Game/Systems/ServerListSystem.h"
|
||||
#include "Game/Systems/StartSystem.h"
|
||||
#include "Game/Systems/EndScreenSystem.h"
|
||||
#include "Game/Systems/FadeSystem.h"
|
||||
#include "Rendering/TextureSprite.h"
|
||||
|
||||
|
||||
@@ -158,6 +160,8 @@ Game::Game(int argc, char* argv[])
|
||||
m_SystemPipeline->AddSystem<SpectatorCameraSystem>(updateOrderLevel);
|
||||
m_SystemPipeline->AddSystem<ServerListSystem>(updateOrderLevel, m_Renderer);
|
||||
m_SystemPipeline->AddSystem<StartSystem>(updateOrderLevel);
|
||||
m_SystemPipeline->AddSystem<EndScreenSystem>(updateOrderLevel);
|
||||
m_SystemPipeline->AddSystem<FadeSystem>(updateOrderLevel);
|
||||
// Populate Octree with collidables
|
||||
++updateOrderLevel;
|
||||
m_SystemPipeline->AddSystem<FillOctreeSystem>(updateOrderLevel, m_OctreeCollision, "Collidable");
|
||||
|
||||
@@ -14,6 +14,7 @@ bool MultiplayerSnapshotFilter::FilterComponent(EntityWrapper entity, SharedComp
|
||||
|| component.Info.Name == "Physics"
|
||||
|| component.Info.Name == "AssaultWeapon"
|
||||
|| component.Info.Name == "DefenderWeapon"
|
||||
|| component.Info.Name == "SidearmWeapon"
|
||||
|| component.Info.Name == "Animation"
|
||||
|| component.Info.Name == "Blend"
|
||||
|| component.Info.Name == "BlendAdditive"
|
||||
|
||||
@@ -23,26 +23,29 @@ void AbilityCooldownHUDSystem::Update(double dt)
|
||||
|
||||
if (!abilityEntity.Valid()) {
|
||||
//If we dont have a shield ability, we return, since we cannot do anything.
|
||||
if (entity.HasComponent("Sprite")) {
|
||||
(Field<std::string>)entity["Sprite"]["DiffuseTexture"] = "Textures/Test/aM4ME4GR.png";
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
//If we have a shield ability, we set the right icon
|
||||
abilityName = "ShieldAbility";
|
||||
if (entity.HasComponent("Sprite")) {
|
||||
entity["Sprite"]["DiffuseTexture"] = "Textures\\Icons\\Abilities\\SheildDots-01.png";
|
||||
(Field<std::string>)entity["Sprite"]["DiffuseTexture"] = "Textures/Icons/Abilities/Long/SheildDots-01.png";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//If we do have a sprint ability, we change the icon
|
||||
abilityName = "SprintAbility";
|
||||
if (entity.HasComponent("Sprite")) {
|
||||
entity["Sprite"]["DiffuseTexture"] = "Textures\\Icons\\Abilities\\Dash-01.png";
|
||||
(Field<std::string>)entity["Sprite"]["DiffuseTexture"] = "Textures/Icons/Abilities/Long/Dash-01.png";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//If we have a dash ability, we set the icon to the correct one.
|
||||
abilityName = "DashAbility";
|
||||
if (entity.HasComponent("Sprite")) {
|
||||
entity["Sprite"]["DiffuseTexture"] = "Textures\\Icons\\Abilities\\Superman-01.png";
|
||||
(Field<std::string>)entity["Sprite"]["DiffuseTexture"] = "Textures/Icons/Abilities/Long/Superman-01.png";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,23 +60,23 @@ void AbilityCooldownHUDSystem::Update(double dt)
|
||||
|
||||
if (cooldownTextEntity.Valid()) {
|
||||
if (cooldownTextEntity.HasComponent("Text")) {
|
||||
cooldownTextEntity["Text"]["Content"] = std::to_string(currentAbilityCD).substr(0, 3);
|
||||
(Field<std::string>)cooldownTextEntity["Text"]["Content"] = std::to_string(currentAbilityCD).substr(0, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (abilityName == "ShieldAbility") {
|
||||
maxAbilityCD = 0.0;
|
||||
maxAbilityCD = 1.0;
|
||||
currentAbilityCD = 1 - (bool)abilityEntity[abilityName]["Active"];
|
||||
}
|
||||
|
||||
if (abilityName == "SprintAbility") {
|
||||
maxAbilityCD = 0.0;
|
||||
maxAbilityCD = 1.0;
|
||||
currentAbilityCD = 1 - (bool)abilityEntity[abilityName]["Active"];
|
||||
}
|
||||
|
||||
if (entity.HasComponent("Fill")) {
|
||||
entity["Fill"]["Percentage"] = currentAbilityCD/maxAbilityCD;
|
||||
(Field<double>)entity["Fill"]["Percentage"] = currentAbilityCD/maxAbilityCD;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -5,36 +5,38 @@ void BoostIconsHUDSystem::UpdateComponent(EntityWrapper& entity, ComponentWrappe
|
||||
EntityWrapper assaultEntity = entity.FirstChildByName("Assault");
|
||||
EntityWrapper defenderEntity = entity.FirstChildByName("Defender");
|
||||
EntityWrapper sniperEntity = entity.FirstChildByName("Sniper");
|
||||
EntityWrapper player = entity.FirstParentWithComponent("Player");
|
||||
|
||||
|
||||
if(assaultEntity.Valid()) {
|
||||
if (assaultEntity.HasComponent("Fill")) {
|
||||
EntityWrapper parentWithAssaultBoost = assaultEntity.FirstParentWithComponent("BoostAssault");
|
||||
if (parentWithAssaultBoost.Valid()) {
|
||||
assaultEntity["Fill"]["Percentage"] = 1.0;
|
||||
EntityWrapper assaultBoost = player.FirstChildByName("BoostAssault");
|
||||
if (assaultBoost.Valid()) {
|
||||
(Field<double>)assaultEntity["Fill"]["Percentage"] = 1.0;
|
||||
} else {
|
||||
assaultEntity["Fill"]["Percentage"] = 0.0;
|
||||
(Field<double>)assaultEntity["Fill"]["Percentage"] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (defenderEntity.Valid()) {
|
||||
if (defenderEntity.HasComponent("Fill")) {
|
||||
EntityWrapper parentWithAssaultBoost = defenderEntity.FirstParentWithComponent("BoostDefender");
|
||||
if (parentWithAssaultBoost.Valid()) {
|
||||
defenderEntity["Fill"]["Percentage"] = 1.0;
|
||||
EntityWrapper defenderBoost = player.FirstChildByName("BoostDefender");
|
||||
if (defenderBoost.Valid()) {
|
||||
(Field<double>)defenderEntity["Fill"]["Percentage"] = 1.0;
|
||||
} else {
|
||||
defenderEntity["Fill"]["Percentage"] = 0.0;
|
||||
(Field<double>)defenderEntity["Fill"]["Percentage"] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sniperEntity.Valid()) {
|
||||
if (sniperEntity.HasComponent("Fill")) {
|
||||
EntityWrapper parentWithAssaultBoost = sniperEntity.FirstParentWithComponent("BoostSniper");
|
||||
if (parentWithAssaultBoost.Valid()) {
|
||||
sniperEntity["Fill"]["Percentage"] = 1.0;
|
||||
EntityWrapper sniperBoost = player.FirstChildByName("BoostSniper");
|
||||
if (sniperBoost.Valid()) {
|
||||
(Field<double>)sniperEntity["Fill"]["Percentage"] = 1.0;
|
||||
} else {
|
||||
sniperEntity["Fill"]["Percentage"] = 0.0;
|
||||
(Field<double>)sniperEntity["Fill"]["Percentage"] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,21 +8,16 @@ BoostSystem::BoostSystem(SystemParams params)
|
||||
|
||||
bool BoostSystem::OnPlayerDamage(Events::PlayerDamage& e)
|
||||
{
|
||||
if (e.Victim.ID == e.Inflictor.ID) {
|
||||
|
||||
|
||||
if (e.Victim == e.Inflictor) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!e.Victim.Valid() || !LocalPlayer.Valid()) {
|
||||
if (!e.Victim.Valid() || !e.Inflictor.Valid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (e.Victim != LocalPlayer && !e.Victim.IsChildOf(LocalPlayer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!e.Inflictor.Valid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//if its not friendly fire, return
|
||||
if ((int)m_World->GetComponent(e.Inflictor.ID, "Team")["Team"] != (int)m_World->GetComponent(e.Victim.ID, "Team")["Team"]) {
|
||||
@@ -35,19 +30,27 @@ bool BoostSystem::OnPlayerDamage(Events::PlayerDamage& e)
|
||||
return false;
|
||||
}
|
||||
|
||||
//get the XML file, example: "Schema/Entities/BoostclassName.xml"
|
||||
std::string classXML = "Schema/Entities/" + className + ".xml";
|
||||
if (className == "SidearmWeapon") { // give ammo
|
||||
giveAmmo(e.Inflictor, e.Victim);
|
||||
} else { //give boost
|
||||
if (!IsServer) {
|
||||
return false;
|
||||
}
|
||||
//get the XML file, example: "Schema/Entities/BoostclassName.xml"
|
||||
std::string classXML = "Schema/Entities/" + className + ".xml";
|
||||
|
||||
//check if player already has a child with the component, if so delete that child
|
||||
auto playerBoostAssaultEntity = e.Victim.FirstChildByName(className);
|
||||
if (playerBoostAssaultEntity.Valid()) {
|
||||
m_World->DeleteEntity(playerBoostAssaultEntity.ID);
|
||||
//check if player already has a child with the component, if so delete that child
|
||||
auto playerBoostAssaultEntity = e.Victim.FirstChildByName(className);
|
||||
if (playerBoostAssaultEntity.Valid()) {
|
||||
m_World->DeleteEntity(playerBoostAssaultEntity.ID);
|
||||
}
|
||||
//load boost XML file, set it entity parented with the victim player
|
||||
auto entityFile = ResourceManager::Load<EntityFile>(classXML);
|
||||
EntityWrapper boostAssaultEntity = entityFile->MergeInto(m_World);
|
||||
m_World->SetName(boostAssaultEntity.ID, className);
|
||||
m_World->SetParent(boostAssaultEntity.ID, e.Victim.ID);
|
||||
}
|
||||
//load boost XML file, set it entity parented with the victim player
|
||||
auto entityFile = ResourceManager::Load<EntityFile>(classXML);
|
||||
EntityWrapper boostAssaultEntity = entityFile->MergeInto(m_World);
|
||||
m_World->SetName(boostAssaultEntity.ID, className);
|
||||
m_World->SetParent(boostAssaultEntity.ID, e.Victim.ID);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -55,14 +58,56 @@ bool BoostSystem::OnPlayerDamage(Events::PlayerDamage& e)
|
||||
std::string BoostSystem::DetermineClass(EntityWrapper inflictorPlayer)
|
||||
{
|
||||
//determine the class based on what component the inflictor-player has
|
||||
if (m_World->HasComponent(inflictorPlayer.ID, "DashAbility")) {
|
||||
return "BoostAssault";
|
||||
}
|
||||
if (m_World->HasComponent(inflictorPlayer.ID, "ShieldAbility")) {
|
||||
return "BoostDefender";
|
||||
}
|
||||
if (m_World->HasComponent(inflictorPlayer.ID, "SprintAbility")) {
|
||||
return "BoostSniper";
|
||||
if (inflictorPlayer.HasComponent("Player")) {
|
||||
if ((std::string)inflictorPlayer["Player"]["CurrentWeapon"] == "AssaultWeapon") {
|
||||
return "BoostAssault";
|
||||
}
|
||||
if ((std::string)inflictorPlayer["Player"]["CurrentWeapon"] == "DefenderWeapon") {
|
||||
return "BoostDefender";
|
||||
}
|
||||
if ((std::string)inflictorPlayer["Player"]["CurrentWeapon"] == "SniperWeapon") {
|
||||
return "BoostSniper";
|
||||
}
|
||||
if ((std::string)inflictorPlayer["Player"]["CurrentWeapon"] == "SidearmWeapon") {
|
||||
return "SidearmWeapon";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void BoostSystem::giveAmmo(EntityWrapper giver, EntityWrapper receiver)
|
||||
{
|
||||
if (receiver.HasComponent("AssaultWeapon")) {
|
||||
int magazineSize = receiver["AssaultWeapon"]["MagazineSize"];
|
||||
Field<int> magazineAmmo = receiver["AssaultWeapon"]["MagazineAmmo"];
|
||||
int prevMagazineAmmo = receiver["AssaultWeapon"]["MagazineAmmo"];
|
||||
int maxAmmo = receiver["AssaultWeapon"]["MaxAmmo"];
|
||||
Field<int> ammo = receiver["AssaultWeapon"]["Ammo"];
|
||||
|
||||
int givenAmmo = 20;
|
||||
|
||||
magazineAmmo = glm::clamp(magazineAmmo + givenAmmo, 0, magazineSize);
|
||||
if (magazineAmmo > prevMagazineAmmo) {
|
||||
givenAmmo = prevMagazineAmmo + givenAmmo - magazineSize;
|
||||
}
|
||||
if (givenAmmo > 0) {
|
||||
ammo = glm::clamp(ammo + givenAmmo, 0, maxAmmo);
|
||||
}
|
||||
} else if (receiver.HasComponent("DefenderWeapon")) {
|
||||
int magazineSize = receiver["DefenderWeapon"]["MagazineSize"];
|
||||
Field<int> magazineAmmo = receiver["DefenderWeapon"]["MagazineAmmo"];
|
||||
int prevMagazineAmmo = receiver["DefenderWeapon"]["MagazineAmmo"];
|
||||
int maxAmmo = receiver["DefenderWeapon"]["MaxAmmo"];
|
||||
Field<int> ammo = receiver["DefenderWeapon"]["Ammo"];
|
||||
|
||||
int givenAmmo = 3;
|
||||
|
||||
magazineAmmo = glm::clamp(magazineAmmo + givenAmmo, 0, magazineSize);
|
||||
if (magazineAmmo > prevMagazineAmmo) {
|
||||
givenAmmo = prevMagazineAmmo + givenAmmo - magazineSize;
|
||||
}
|
||||
if (givenAmmo > 0) {
|
||||
ammo = glm::clamp(ammo + givenAmmo, 0, maxAmmo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
#include "Systems/EndScreenSystem.h"
|
||||
|
||||
|
||||
EndScreenSystem::EndScreenSystem(SystemParams params)
|
||||
: System(params)
|
||||
, ImpureSystem()
|
||||
{
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EWin, &EndScreenSystem::OnWin);
|
||||
}
|
||||
|
||||
void EndScreenSystem::Update(double dt)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool EndScreenSystem::OnWin(const Events::Win& e)
|
||||
{
|
||||
auto endScreenCameras = m_World->GetComponents("EndScreen");
|
||||
if(endScreenCameras == nullptr) {
|
||||
LOG_ERROR("Win event recieved but no Endscreen camera is present.");
|
||||
return 1;
|
||||
}
|
||||
for(auto& camera : *endScreenCameras) {
|
||||
EntityWrapper entity = EntityWrapper(m_World, camera.EntityID);
|
||||
|
||||
Events::SetCamera event;
|
||||
event.CameraEntity = entity;
|
||||
m_EventBroker->Publish(event);
|
||||
|
||||
EntityWrapper redSprite = entity.FirstChildByName("SpriteRed");
|
||||
EntityWrapper blueSprite = entity.FirstChildByName("SpriteBlue");
|
||||
EntityWrapper redText = entity.FirstChildByName("TextRed");
|
||||
EntityWrapper blueText = entity.FirstChildByName("TextBlue");
|
||||
|
||||
if (e.TeamThatWon == 2) {
|
||||
//Red team won
|
||||
if(redSprite.HasComponent("Sprite"))
|
||||
(Field<bool>)redSprite["Sprite"]["Visible"] = true;
|
||||
if (redText.HasComponent("Text"))
|
||||
(Field<bool>)redText["Text"]["Visible"] = true;
|
||||
|
||||
if (blueSprite.HasComponent("Sprite"))
|
||||
(Field<bool>)blueSprite["Sprite"]["Visible"] = false;
|
||||
if (blueText.HasComponent("Text"))
|
||||
(Field<bool>)blueText["Text"]["Visible"] = false;
|
||||
|
||||
}else if (e.TeamThatWon == 3) {
|
||||
//Blue team won
|
||||
if (redSprite.HasComponent("Sprite"))
|
||||
(Field<bool>)redSprite["Sprite"]["Visible"] = false;
|
||||
if (redText.HasComponent("Text"))
|
||||
(Field<bool>)redText["Text"]["Visible"] = false;
|
||||
|
||||
if (blueSprite.HasComponent("Sprite"))
|
||||
(Field<bool>)blueSprite["Sprite"]["Visible"] = true;
|
||||
if (blueText.HasComponent("Text"))
|
||||
(Field<bool>)blueText["Text"]["Visible"] = true;
|
||||
} else {
|
||||
//No team won?
|
||||
if (redSprite.HasComponent("Sprite"))
|
||||
(Field<bool>)redSprite["Sprite"]["Visible"] = false;
|
||||
if (blueSprite.HasComponent("Sprite"))
|
||||
(Field<bool>)blueSprite["Sprite"]["Visible"] = false;
|
||||
|
||||
if (redText.HasComponent("Text"))
|
||||
(Field<bool>)redText["Text"]["Visible"] = false;
|
||||
if (blueText.HasComponent("Text"))
|
||||
(Field<bool>)blueText["Text"]["Visible"] = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#include "Systems/FadeSystem.h"
|
||||
|
||||
void FadeSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& cFade, double dt)
|
||||
{
|
||||
double dTime = dt;
|
||||
if (dTime == 0.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!entity.Valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((bool)cFade["Out"]) {
|
||||
dTime *= -1;
|
||||
}
|
||||
|
||||
if((bool)cFade["Reverse"]) {
|
||||
dTime *= 2;
|
||||
}
|
||||
|
||||
double fadeTime = cFade["FadeTime"];
|
||||
Field<double> currentTime = cFade["Time"];
|
||||
currentTime += dTime;
|
||||
|
||||
if(currentTime > fadeTime) {
|
||||
currentTime = 0.0;
|
||||
if ((bool)cFade["Reverse"]) {
|
||||
(Field<bool>)cFade["Out"] = !(bool)cFade["Out"];
|
||||
currentTime = fadeTime;
|
||||
}
|
||||
}
|
||||
if(currentTime < 0.0) {
|
||||
currentTime = fadeTime;
|
||||
if ((bool)cFade["Reverse"]) {
|
||||
(Field<bool>)cFade["Out"] = !(bool)cFade["Out"];
|
||||
currentTime = 0.0;
|
||||
}
|
||||
}
|
||||
double ratio = currentTime/fadeTime;
|
||||
|
||||
if(entity.HasComponent("Model")){
|
||||
((Field<glm::vec4>)entity["Model"]["Color"]).w(ratio);
|
||||
}
|
||||
if (entity.HasComponent("Sprite")) {
|
||||
((Field<glm::vec4>)entity["Sprite"]["Color"]).w(ratio);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -22,8 +22,8 @@ void HealthHUDSystem::Update(double dt)
|
||||
if (entityIDParent.HasComponent("Health")) {
|
||||
|
||||
if (entity.HasComponent("Text")) {
|
||||
Field<double> health = entityIDParent["Health"]["Health"];
|
||||
Field<double> maxHealth = entityIDParent["Health"]["Health"];
|
||||
double health = (const double&)entityIDParent["Health"]["Health"];
|
||||
double maxHealth = (const double&)entityIDParent["Health"]["MaxHealth"];
|
||||
std::string s = "";
|
||||
s = s + std::to_string((int)health);
|
||||
s = s + "/";
|
||||
@@ -34,8 +34,8 @@ void HealthHUDSystem::Update(double dt)
|
||||
}
|
||||
|
||||
if(entity.HasComponent("Fill")) {
|
||||
Field<double> health = entityIDParent["Health"]["Health"];
|
||||
Field<double> maxHealth = entityIDParent["Health"]["Health"];
|
||||
double health = (const double&)entityIDParent["Health"]["Health"];
|
||||
double maxHealth = (const double&)entityIDParent["Health"]["MaxHealth"];
|
||||
float healthPercentage = health/maxHealth;
|
||||
entity["Fill"]["Color"] = glm::vec4(1.0 - healthPercentage, 0.f, healthPercentage, glm::vec4(entity["Fill"]["Color"]).a);
|
||||
entity["Fill"]["Percentage"] = (double)healthPercentage;
|
||||
|
||||
@@ -58,7 +58,7 @@ bool HealthSystem::OnPlayerHealthPickup(Events::PlayerHealthPickup& e)
|
||||
ComponentWrapper cHealth = e.Player["Health"];
|
||||
Field<double> health = cHealth["Health"];
|
||||
health += e.HealthAmount;
|
||||
health = std::min((double)health, (double)cHealth["MaxHealth"]);
|
||||
health = std::min(*health, (const double&)cHealth["MaxHealth"]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,10 @@ void KillFeedSystem::Update(double dt)
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto it = m_DeathQueue.begin(); it != m_DeathQueue.end(); it++) {
|
||||
(*it).TimeToLive -= dt;
|
||||
}
|
||||
|
||||
for (auto& killFeedComponent : *killFeeds) {
|
||||
EntityWrapper entity = EntityWrapper(m_World, killFeedComponent.EntityID);
|
||||
|
||||
@@ -16,10 +20,7 @@ void KillFeedSystem::Update(double dt)
|
||||
(Field<std::string>)child["Text"]["Content"] = "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int feedIndex = 1;
|
||||
for (auto it = m_DeathQueue.begin(); it != m_DeathQueue.end(); ) {
|
||||
bool remove = false;
|
||||
@@ -27,14 +28,19 @@ void KillFeedSystem::Update(double dt)
|
||||
EntityWrapper child = entity.FirstChildByName("KillFeed" + std::to_string(feedIndex));
|
||||
|
||||
if (child.HasComponent("Text")) {
|
||||
(Field<std::string>)child["Text"]["Content"] = (*it).Content;
|
||||
(Field<glm::vec4>)child["Text"]["Color"] = (*it).Color;
|
||||
|
||||
(*it).TimeToLive -= dt;
|
||||
std::string str = "";
|
||||
//Add killer to the start of string.
|
||||
str = (*it).KillerColor + "\\" + std::to_string((*it).KillerClass) + "\\CFFFFFF" + " " + (*it).KillerName + " ";
|
||||
//Add Weapon to middle of string.
|
||||
str += "\\" + std::to_string((*it).KillerClass+3) + " ";
|
||||
//Add victim to the end of string
|
||||
str += (*it).VictimColor + "\\" + std::to_string((*it).VictimClass) + "\\CFFFFFF" + " " + (*it).VictimName;
|
||||
|
||||
(Field<std::string>)child["Text"]["Content"] = str;
|
||||
|
||||
if ((*it).TimeToLive <= 0.f) {
|
||||
(Field<std::string>)child["Text"]["Content"] = "";
|
||||
(Field<glm::vec4>)child["Text"]["Color"] = (*it).Color;
|
||||
remove = true;
|
||||
}
|
||||
}
|
||||
@@ -52,29 +58,30 @@ void KillFeedSystem::Update(double dt)
|
||||
}
|
||||
}
|
||||
|
||||
bool KillFeedSystem::OnPlayerDeath(Events::PlayerDeath& e)
|
||||
bool KillFeedSystem::OnPlayerKillDeath(Events::KillDeath& e)
|
||||
{
|
||||
KillFeedInfo kfInfo;
|
||||
KillFeedInfo info;
|
||||
|
||||
if (e.Player.HasComponent("Team")) {
|
||||
int red = e.Player["Team"].Enum("Team", "Red");
|
||||
int blue = e.Player["Team"].Enum("Team", "Blue");
|
||||
|
||||
if ((int)e.Player["Team"]["Team"] == red) {
|
||||
kfInfo.Content = "Blue Player killed Red Player";
|
||||
kfInfo.Color = glm::vec4(0.f, 0.2f, 1.f, 0.8f);
|
||||
m_DeathQueue.push_back(kfInfo);
|
||||
} else if ((int)e.Player["Team"]["Team"] == blue) {
|
||||
kfInfo.Content = "Red Player killed blue Player";
|
||||
kfInfo.Color = glm::vec4(1.f, 0.f, 0.f, 0.8f);
|
||||
m_DeathQueue.push_back(kfInfo);
|
||||
}
|
||||
info.KillerName = e.KillerName;
|
||||
info.KillerID = e.Killer;
|
||||
info.KillerClass = e.KillerClass;
|
||||
info.KillerTeam = e.KillerTeam;
|
||||
if(info.KillerTeam == 2){
|
||||
info.KillerColor = m_BlueColor;
|
||||
} else if (info.KillerTeam == 3) {
|
||||
info.KillerColor = m_RedColor;
|
||||
}
|
||||
|
||||
|
||||
if(m_DeathQueue.size() > 3) {
|
||||
m_DeathQueue.pop_front();
|
||||
info.VictimName = e.CasualtyName;
|
||||
info.VictimID = e.Casualty;
|
||||
info.VictimClass = e.CasualtyClass;
|
||||
info.VictimTeam = e.CasualtyTeam;
|
||||
if (info.VictimTeam == 2) {
|
||||
info.VictimColor = m_BlueColor;
|
||||
} else if (info.VictimTeam == 3) {
|
||||
info.VictimColor = m_RedColor;
|
||||
}
|
||||
|
||||
return true;
|
||||
m_DeathQueue.push_back(info);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ void PickupSpawnSystem::Update(double dt)
|
||||
m_PickupAtMaximum.erase(it);
|
||||
break;
|
||||
}
|
||||
if ((double)it->player["Health"]["Health"] < (double)it->player["Health"]["MaxHealth"]) {
|
||||
if ((const double&)it->player["Health"]["Health"] < (const double&)it->player["Health"]["MaxHealth"]) {
|
||||
DoPickup(it->player, it->trigger);
|
||||
m_PickupAtMaximum.erase(it);
|
||||
break;
|
||||
@@ -59,7 +59,7 @@ bool PickupSpawnSystem::OnTriggerTouch(Events::TriggerTouch& e)
|
||||
return false;
|
||||
}
|
||||
//if at maxhealth, save the trigger-touch to a vector since standing inside it will not re-trigger the trigger
|
||||
if ((double)e.Entity["Health"]["Health"] >= (double)e.Entity["Health"]["MaxHealth"]) {
|
||||
if ((const double&)e.Entity["Health"]["Health"] >= (const double&)e.Entity["Health"]["MaxHealth"]) {
|
||||
m_PickupAtMaximum.push_back({ e.Entity, e.Trigger });
|
||||
return false;
|
||||
}
|
||||
@@ -87,7 +87,7 @@ void PickupSpawnSystem::DoPickup(EntityWrapper &player, EntityWrapper &trigger)
|
||||
if (!trigger.Valid()) {
|
||||
return;
|
||||
}
|
||||
double healthGiven = 0.01*(double)trigger["HealthPickup"]["HealthGain"] * (double)player["Health"]["MaxHealth"];
|
||||
double healthGiven = 0.01*(const double&)trigger["HealthPickup"]["HealthGain"] * (const double&)player["Health"]["MaxHealth"];
|
||||
|
||||
//only the server will increase the players hp and set it in the next delta
|
||||
Events::PlayerHealthPickup ePlayerHealthPickup;
|
||||
|
||||
@@ -24,6 +24,8 @@ void PlayerMovementSystem::Update(double dt)
|
||||
if (LocalPlayer.Valid()){
|
||||
updateVelocity(LocalPlayer, dt);
|
||||
}
|
||||
|
||||
|
||||
m_SprintEffectTimer += dt;
|
||||
if (m_SprintEffectTimer < 0.016f) {
|
||||
return;
|
||||
@@ -82,17 +84,15 @@ void PlayerMovementSystem::updateMovementControllers(double dt)
|
||||
// Limit camera pitch so we don't break our necks
|
||||
cameraOrientation.x(glm::clamp(cameraOrientation.x(), -glm::half_pi<float>(), glm::half_pi<float>()));
|
||||
|
||||
float pitch = cameraOrientation.x();
|
||||
double time = ((pitch + glm::half_pi<float>()) / glm::pi<float>());
|
||||
|
||||
// Set third person model aim pitch
|
||||
EntityWrapper playerModel = player.FirstChildByName("PlayerModel");
|
||||
if (playerModel.Valid()) {
|
||||
EntityWrapper aimPrimaryEntity = playerModel.FirstChildByName("Aim");
|
||||
if(aimPrimaryEntity.Valid()){
|
||||
if(aimPrimaryEntity.HasComponent("Animation")) {
|
||||
float pitch = cameraOrientation.x();
|
||||
double time = ((pitch + glm::half_pi<float>()) / glm::pi<float>());
|
||||
(Field<double>)aimPrimaryEntity["Animation"]["Time"] = time;
|
||||
}
|
||||
}
|
||||
setAim(playerModel, "SidearmWeapon", time);
|
||||
setAim(playerModel, "AssaultWeapon", time);
|
||||
setAim(playerModel, "DefenderWeapon", time);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,6 +314,25 @@ void PlayerMovementSystem::updateVelocity(EntityWrapper player, double dt)
|
||||
position += velocity * (float)dt;
|
||||
}
|
||||
|
||||
|
||||
void PlayerMovementSystem::setAim(EntityWrapper root, std::string weaponNodeName, double time)
|
||||
{
|
||||
if (root.Valid()) {
|
||||
EntityWrapper blendTreeUpper = root.FirstChildByName("BlendTreeUpper");
|
||||
if (blendTreeUpper.Valid()) {
|
||||
EntityWrapper weapon = blendTreeUpper.FirstChildByName(weaponNodeName);
|
||||
if(weapon.Valid()) {
|
||||
EntityWrapper aim = weapon.FirstChildByName("Aim");
|
||||
if (aim.Valid()) {
|
||||
if (aim.HasComponent("Animation")) {
|
||||
(Field<double>)aim["Animation"]["Time"] = time;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerMovementSystem::playerStep(double dt, EntityWrapper player)
|
||||
{
|
||||
// Position of the local player, used see how far a player has moved.
|
||||
@@ -373,17 +392,22 @@ void PlayerMovementSystem::spawnHexagon(EntityWrapper target)
|
||||
|
||||
bool PlayerMovementSystem::OnDashAbility(Events::DashAbility & e)
|
||||
{
|
||||
EntityWrapper player(m_World, e.Player);
|
||||
if (!player.Valid()){// || !IsClient || player.ID == LocalPlayer.ID) {
|
||||
EntityWrapper eventPlayer(m_World, e.Player);
|
||||
if (!eventPlayer.Valid()){// || IsServer || eventPlayer.ID == LocalPlayer.ID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// auto entityFile = ResourceManager::Load<EntityFile>("Schema/Entities/DashEffect.xml");
|
||||
// EntityWrapper dashEffect = entityFile->MergeInto(m_World);
|
||||
EntityWrapper playerModel = player.FirstChildByName("PlayerModel");
|
||||
EntityWrapper playerModel = eventPlayer.FirstChildByName("PlayerModel");
|
||||
|
||||
for (auto& kv : m_PlayerInputControllers) {
|
||||
EntityWrapper player = kv.first;
|
||||
if(player != eventPlayer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
auto& controller = kv.second;
|
||||
|
||||
if (!player.Valid()) {
|
||||
|
||||
@@ -10,6 +10,7 @@ void AssaultWeaponBehaviour::UpdateComponent(EntityWrapper& entity, ComponentWra
|
||||
|
||||
void AssaultWeaponBehaviour::UpdateWeapon(ComponentWrapper cWeapon, WeaponInfo& wi, double dt)
|
||||
{
|
||||
CheckBoost(cWeapon, wi);
|
||||
// Start reloading automatically if at 0 mag ammo
|
||||
Field<int> magAmmo = cWeapon["MagazineAmmo"];
|
||||
if (m_ConfigAutoReload && magAmmo <= 0) {
|
||||
@@ -36,8 +37,11 @@ void AssaultWeaponBehaviour::UpdateWeapon(ComponentWrapper cWeapon, WeaponInfo&
|
||||
Field<int> magSize = cWeapon["MagazineSize"];
|
||||
Field<int> ammo = cWeapon["Ammo"];
|
||||
|
||||
ammo = glm::max(0, ammo - (magSize - magAmmo));
|
||||
magAmmo = glm::min(*magSize, *ammo);
|
||||
int usedAmmo = glm::max(0, *magSize - *magAmmo);
|
||||
magAmmo = glm::clamp(*ammo + *magAmmo, 0, *magSize);
|
||||
ammo = glm::max(0, *ammo - usedAmmo);
|
||||
|
||||
|
||||
isReloading = false;
|
||||
if (wi.FirstPersonEntity.Valid()) {
|
||||
wi.FirstPersonEntity.FirstChildByName("ViewModel")["Model"]["Visible"] = true;
|
||||
@@ -74,7 +78,7 @@ void AssaultWeaponBehaviour::UpdateWeapon(ComponentWrapper cWeapon, WeaponInfo&
|
||||
float animationWeight = glm::min(speed, movementSpeed) / movementSpeed;
|
||||
EntityWrapper rootNode = wi.FirstPersonEntity;
|
||||
if (rootNode.Valid()) {
|
||||
EntityWrapper blend = rootNode.FirstChildByName("MovementBlend");
|
||||
EntityWrapper blend = rootNode.FirstChildByName("MovementBlendAssault");
|
||||
if (blend.Valid()) {
|
||||
(Field<double>)blend["Blend"]["Weight"] = animationWeight;
|
||||
}
|
||||
@@ -166,6 +170,14 @@ void AssaultWeaponBehaviour::OnReload(ComponentWrapper cWeapon, WeaponInfo& wi)
|
||||
void AssaultWeaponBehaviour::OnEquip(ComponentWrapper cWeapon, WeaponInfo& wi)
|
||||
{
|
||||
cWeapon["FireCooldown"] = (double)cWeapon["EquipTime"];
|
||||
|
||||
if (wi.ThirdPersonPlayerModel.Valid()) {
|
||||
Events::AutoAnimationBlend b1;
|
||||
b1.RootNode = wi.ThirdPersonPlayerModel;
|
||||
b1.NodeName = "AssaultWeapon";
|
||||
b1.SingleLevelBlend = true;
|
||||
m_EventBroker->Publish(b1);
|
||||
}
|
||||
}
|
||||
|
||||
void AssaultWeaponBehaviour::OnHolster(ComponentWrapper cWeapon, WeaponInfo& wi)
|
||||
@@ -216,16 +228,25 @@ void AssaultWeaponBehaviour::fireBullet(ComponentWrapper cWeapon, WeaponInfo& wi
|
||||
}
|
||||
|
||||
// Tracer
|
||||
EntityWrapper tracerSpawner = weaponModelEntity.FirstChildByName("WeaponMuzzle");
|
||||
EntityWrapper tracerSpawner = weaponModelEntity.FirstChildByName("WeaponMuzzleRay");
|
||||
if (tracerSpawner.Valid()) {
|
||||
glm::vec3 origin = TransformSystem::AbsolutePosition(tracerSpawner);
|
||||
glm::vec3 direction = glm::quat(TransformSystem::AbsoluteOrientationEuler(tracerSpawner)) * glm::vec3(0, 0, -1);
|
||||
float distance = traceRayDistance(origin, direction);
|
||||
EntityWrapper ray = SpawnerSystem::Spawn(tracerSpawner);
|
||||
EntityWrapper ray = SpawnerSystem::Spawn(tracerSpawner, tracerSpawner);
|
||||
if (ray.Valid()) {
|
||||
((Field<glm::vec3>)ray["Transform"]["Scale"]).z(distance);
|
||||
}
|
||||
}
|
||||
//MuzzleFlash
|
||||
EntityWrapper muzzleFlashSpawner = weaponModelEntity.FirstChildByName("WeaponMuzzleFlash");
|
||||
if (muzzleFlashSpawner.Valid()) {
|
||||
std::uniform_real_distribution<float> randomSpreadAngle(0.f, 3.1415f*2);
|
||||
EntityWrapper flash = SpawnerSystem::Spawn(muzzleFlashSpawner, muzzleFlashSpawner);
|
||||
if (flash.Valid()) {
|
||||
((Field<glm::vec3>)flash["Transform"]["Orientation"]).z(randomSpreadAngle(m_RandomEngine));
|
||||
}
|
||||
}
|
||||
|
||||
// Deal damage
|
||||
if (dealDamage(cWeapon, wi)) {
|
||||
@@ -239,6 +260,25 @@ void AssaultWeaponBehaviour::fireBullet(ComponentWrapper cWeapon, WeaponInfo& wi
|
||||
m_EventBroker->Publish(e);
|
||||
}
|
||||
}
|
||||
|
||||
// View punch
|
||||
if (IsClient) {
|
||||
EntityWrapper camera = wi.Player.FirstChildByName("Camera");
|
||||
if (camera.Valid()) {
|
||||
Field<glm::vec3> cameraOrientation = camera["Transform"]["Orientation"];
|
||||
float viewPunch = cWeapon["ViewPunch"];
|
||||
float maxTravelAngle = cWeapon["MaxTravelAngle"];
|
||||
Field<float> currentTravel = cWeapon["CurrentTravel"];
|
||||
if (currentTravel < maxTravelAngle) {
|
||||
float change = viewPunch;
|
||||
if (currentTravel + change > maxTravelAngle) {
|
||||
change = maxTravelAngle - currentTravel;
|
||||
}
|
||||
cameraOrientation.x(cameraOrientation.x() + change);
|
||||
currentTravel += change;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Play animation
|
||||
playAnimationAndReturn(wi.FirstPersonEntity, "ActionBlend", "Fire");
|
||||
@@ -321,3 +361,149 @@ bool AssaultWeaponBehaviour::dealDamage(ComponentWrapper cWeapon, WeaponInfo& wi
|
||||
|
||||
return damage > 0;
|
||||
}
|
||||
|
||||
void AssaultWeaponBehaviour::CheckBoost(ComponentWrapper cWeapon, WeaponInfo& wi)
|
||||
{
|
||||
// Only check ammo client side
|
||||
if (!IsClient) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only handle ammo check for the local player
|
||||
if (wi.Player != LocalPlayer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure the player isn't checking from the grave
|
||||
if (!wi.Player.Valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 3D-pick middle of screen
|
||||
Rectangle viewport = m_Renderer->GetViewportSize();
|
||||
glm::vec2 centerScreen(viewport.Width / 2, viewport.Height / 2);
|
||||
// TODO: Some horizontal spread
|
||||
PickData pickData = m_Renderer->Pick(centerScreen);
|
||||
EntityWrapper victim(m_World, pickData.Entity);
|
||||
if (!victim.Valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't let us somehow shoot ourselves in the foot
|
||||
if (victim == LocalPlayer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only care about players being hit
|
||||
if (!victim.HasComponent("Player")) {
|
||||
victim = victim.FirstParentWithComponent("Player");
|
||||
}
|
||||
if (!victim.Valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// If friendly fire, reduce damage to 0 (needed to make Boosts, Ammosharing work)
|
||||
if ((ComponentInfo::EnumType)victim["Team"]["Team"] == (ComponentInfo::EnumType)wi.Player["Team"]["Team"]) {
|
||||
|
||||
EntityWrapper friendlyBoostHudSpawner = wi.FirstPersonPlayerModel.FirstChildByName("FriendlyBoostAttachment");
|
||||
if (friendlyBoostHudSpawner.Valid()) {
|
||||
|
||||
EntityWrapper assaultBoost = victim.FirstChildByName("BoostAssault");
|
||||
EntityWrapper defenderBoost = victim.FirstChildByName("BoostDefender");
|
||||
EntityWrapper sniperBoost = victim.FirstChildByName("BoostSniper");
|
||||
|
||||
auto children = m_World->GetDirectChildren(friendlyBoostHudSpawner.ID);
|
||||
|
||||
if (children.first == children.second) {
|
||||
if (friendlyBoostHudSpawner.HasComponent("Spawner")) {
|
||||
|
||||
EntityWrapper friendlyBoostHud = SpawnerSystem::Spawn(friendlyBoostHudSpawner, friendlyBoostHudSpawner);
|
||||
if (friendlyBoostHud.Valid()) {
|
||||
EntityWrapper assaultBoostEntity = friendlyBoostHud.FirstChildByName("AssaultBoost");
|
||||
if (assaultBoostEntity.Valid()) {
|
||||
EntityWrapper active = assaultBoostEntity.FirstChildByName("Active");
|
||||
if (active.HasComponent("Text")) {
|
||||
if (assaultBoost.Valid()) {
|
||||
(Field<bool>)active["Text"]["Visible"] = true;
|
||||
} else {
|
||||
(Field<bool>)active["Text"]["Visible"] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EntityWrapper defenderBoostEntity = friendlyBoostHud.FirstChildByName("DefenderBoost");
|
||||
if (defenderBoostEntity.Valid()) {
|
||||
EntityWrapper active = defenderBoostEntity.FirstChildByName("Active");
|
||||
if (active.HasComponent("Text")) {
|
||||
if (defenderBoost.Valid()) {
|
||||
(Field<bool>)active["Text"]["Visible"] = true;
|
||||
} else {
|
||||
(Field<bool>)active["Text"]["Visible"] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EntityWrapper sniperBoostEntity = friendlyBoostHud.FirstChildByName("SniperBoost");
|
||||
if (sniperBoostEntity.Valid()) {
|
||||
EntityWrapper active = sniperBoostEntity.FirstChildByName("Active");
|
||||
if (active.HasComponent("Text")) {
|
||||
if (sniperBoost.Valid()) {
|
||||
(Field<bool>)active["Text"]["Visible"] = true;
|
||||
} else {
|
||||
(Field<bool>)active["Text"]["Visible"] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
EntityWrapper friendlyBoostHud = friendlyBoostHudSpawner.FirstChildByName("FriendlyBoostHUD");
|
||||
if (friendlyBoostHud.Valid()) {
|
||||
if(friendlyBoostHud.HasComponent("Lifetime")) {
|
||||
(Field<double>)friendlyBoostHud["Lifetime"]["Lifetime"] = 0.5;
|
||||
}
|
||||
|
||||
|
||||
|
||||
EntityWrapper assaultBoostEntity = friendlyBoostHud.FirstChildByName("AssaultBoost");
|
||||
if (assaultBoostEntity.Valid()) {
|
||||
EntityWrapper active = assaultBoostEntity.FirstChildByName("Active");
|
||||
if (active.HasComponent("Text")) {
|
||||
if (assaultBoost.Valid()) {
|
||||
(Field<bool>)active["Text"]["Visible"] = true;
|
||||
} else {
|
||||
(Field<bool>)active["Text"]["Visible"] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EntityWrapper defenderBoostEntity = friendlyBoostHud.FirstChildByName("DefenderBoost");
|
||||
if (defenderBoostEntity.Valid()) {
|
||||
EntityWrapper active = defenderBoostEntity.FirstChildByName("Active");
|
||||
if (active.HasComponent("Text")) {
|
||||
if (defenderBoost.Valid()) {
|
||||
(Field<bool>)active["Text"]["Visible"] = true;
|
||||
} else {
|
||||
(Field<bool>)active["Text"]["Visible"] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EntityWrapper sniperBoostEntity = friendlyBoostHud.FirstChildByName("SniperBoost");
|
||||
if (sniperBoostEntity.Valid()) {
|
||||
EntityWrapper active = sniperBoostEntity.FirstChildByName("Active");
|
||||
if (active.HasComponent("Text")) {
|
||||
if (sniperBoost.Valid()) {
|
||||
(Field<bool>)active["Text"]["Visible"] = true;
|
||||
} else {
|
||||
(Field<bool>)active["Text"]["Visible"] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ void DefenderWeaponBehaviour::UpdateComponent(EntityWrapper& entity, ComponentWr
|
||||
|
||||
void DefenderWeaponBehaviour::UpdateWeapon(ComponentWrapper cWeapon, WeaponInfo& wi, double dt)
|
||||
{
|
||||
CheckBoost(cWeapon, wi);
|
||||
// Decrement reload timer
|
||||
Field<double> reloadTimer = cWeapon["ReloadTimer"];
|
||||
reloadTimer = glm::max(0.0, reloadTimer - dt);
|
||||
@@ -37,6 +38,16 @@ void DefenderWeaponBehaviour::UpdateWeapon(ComponentWrapper cWeapon, WeaponInfo&
|
||||
} else {
|
||||
isReloading = false;
|
||||
playAnimationAndReturn(wi.FirstPersonEntity, "FinalBlend", "ReloadEnd");
|
||||
|
||||
if (wi.ThirdPersonPlayerModel.Valid()) {
|
||||
Events::AutoAnimationBlend eFireIdle;
|
||||
eFireIdle.Duration = 0.2;
|
||||
eFireIdle.RootNode = wi.ThirdPersonPlayerModel;
|
||||
eFireIdle.NodeName = "Fire";
|
||||
eFireIdle.Start = false;
|
||||
m_EventBroker->Publish(eFireIdle);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +103,7 @@ void DefenderWeaponBehaviour::OnReload(ComponentWrapper cWeapon, WeaponInfo& wi)
|
||||
}
|
||||
|
||||
double reloadTime = cWeapon["ReloadTime"];
|
||||
Field<double> reloadTimer = cWeapon["ReloadTimer"];
|
||||
Field<double> reloadTimer = cWeapon["ReloadTimer"];
|
||||
|
||||
// Start reload
|
||||
isReloading = true;
|
||||
@@ -114,6 +125,16 @@ void DefenderWeaponBehaviour::OnReload(ComponentWrapper cWeapon, WeaponInfo& wi)
|
||||
eBlendLoop.AnimationEntity = wi.FirstPersonEntity.FirstChildByName("ReloadStart");
|
||||
m_EventBroker->Publish(eBlendLoop);
|
||||
}
|
||||
|
||||
if(wi.ThirdPersonPlayerModel.Valid()) {
|
||||
Events::AutoAnimationBlend eReload;
|
||||
eReload.Duration = 0.2;
|
||||
eReload.RootNode = wi.ThirdPersonPlayerModel;
|
||||
eReload.NodeName = "Reload";
|
||||
eReload.Restart = true;
|
||||
eReload.Start = true;
|
||||
m_EventBroker->Publish(eReload);
|
||||
}
|
||||
}
|
||||
|
||||
void DefenderWeaponBehaviour::OnHolster(ComponentWrapper cWeapon, WeaponInfo& wi)
|
||||
@@ -132,27 +153,81 @@ bool DefenderWeaponBehaviour::OnInputCommand(ComponentWrapper cWeapon, WeaponInf
|
||||
EntityWrapper attachment = wi.Player.FirstChildByName("ShieldAttachment");
|
||||
if (attachment.Valid()) {
|
||||
if (e.Value > 0) {
|
||||
|
||||
if(wi.Player.Valid()) {
|
||||
if(wi.Player.HasComponent("ShieldAbility")) {
|
||||
(Field<bool>)wi.Player["ShieldAbility"]["Active"] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsServer) {
|
||||
SpawnerSystem::Spawn(attachment, attachment);
|
||||
}
|
||||
|
||||
EntityWrapper backAttachment = attachment.FirstChildByName("Back");
|
||||
if (backAttachment.Valid()) {
|
||||
Events::AutoAnimationBlend eDeployShieldAttachement;
|
||||
eDeployShieldAttachement.RootNode = backAttachment;
|
||||
eDeployShieldAttachement.NodeName = "Deploy";
|
||||
eDeployShieldAttachement.Restart = true;
|
||||
eDeployShieldAttachement.Start = true;
|
||||
m_EventBroker->Publish(eDeployShieldAttachement);
|
||||
}
|
||||
EntityWrapper frontAttachment = attachment.FirstChildByName("Front");
|
||||
if (frontAttachment.Valid()) {
|
||||
Events::AutoAnimationBlend eDeployShieldAttachement;
|
||||
eDeployShieldAttachement.RootNode = frontAttachment;
|
||||
eDeployShieldAttachement.NodeName = "Deploy";
|
||||
eDeployShieldAttachement.Restart = true;
|
||||
eDeployShieldAttachement.Start = true;
|
||||
m_EventBroker->Publish(eDeployShieldAttachement);
|
||||
|
||||
}
|
||||
|
||||
if (IsClient) {
|
||||
EntityWrapper root = wi.FirstPersonEntity;
|
||||
if (root.Valid()) {
|
||||
EntityWrapper animationNode = root.FirstChildByName("Shield");
|
||||
if (animationNode.Valid()) {
|
||||
Events::AutoAnimationBlend eFireBlend;
|
||||
eFireBlend.RootNode = root;
|
||||
eFireBlend.NodeName = "Shield";
|
||||
eFireBlend.Restart = true;
|
||||
eFireBlend.Start = true;
|
||||
m_EventBroker->Publish(eFireBlend);
|
||||
Events::AutoAnimationBlend eShieldBlend;
|
||||
eShieldBlend.RootNode = root;
|
||||
eShieldBlend.NodeName = "Shield";
|
||||
eShieldBlend.Restart = true;
|
||||
eShieldBlend.Start = true;
|
||||
m_EventBroker->Publish(eShieldBlend);
|
||||
}
|
||||
}
|
||||
} else { // server only
|
||||
EntityWrapper root = wi.ThirdPersonPlayerModel;
|
||||
if (root.Valid()) {
|
||||
Events::AutoAnimationBlend eShieldActivateBlend;
|
||||
eShieldActivateBlend.RootNode = root;
|
||||
eShieldActivateBlend.NodeName = "ActivateShield";
|
||||
eShieldActivateBlend.Restart = true;
|
||||
eShieldActivateBlend.Start = true;
|
||||
m_EventBroker->Publish(eShieldActivateBlend);
|
||||
|
||||
EntityWrapper animationNode = root.FirstChildByName("ActivateShield");
|
||||
if (animationNode.Valid()) {
|
||||
Events::AutoAnimationBlend eShieldIdleBlend;
|
||||
eShieldIdleBlend.RootNode = root;
|
||||
eShieldIdleBlend.NodeName = "ShieldFront";
|
||||
eShieldIdleBlend.Restart = true;
|
||||
eShieldIdleBlend.Start = true;
|
||||
eShieldIdleBlend.AnimationEntity = animationNode;
|
||||
m_EventBroker->Publish(eShieldIdleBlend);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
attachment.DeleteChildren();
|
||||
|
||||
if (wi.Player.Valid()) {
|
||||
if (wi.Player.HasComponent("ShieldAbility")) {
|
||||
(Field<bool>)wi.Player["ShieldAbility"]["Active"] = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsClient) {
|
||||
EntityWrapper root = wi.FirstPersonEntity;
|
||||
if (root.Valid()) {
|
||||
@@ -166,6 +241,26 @@ bool DefenderWeaponBehaviour::OnInputCommand(ComponentWrapper cWeapon, WeaponInf
|
||||
m_EventBroker->Publish(eFireBlend);
|
||||
}
|
||||
}
|
||||
} else { // server only
|
||||
EntityWrapper root = wi.ThirdPersonPlayerModel;
|
||||
if (root.Valid()) {
|
||||
Events::AutoAnimationBlend eShieldDeactivateBlend;
|
||||
eShieldDeactivateBlend.RootNode = root;
|
||||
eShieldDeactivateBlend.NodeName = "ActivateShield";
|
||||
eShieldDeactivateBlend.Restart = true;
|
||||
eShieldDeactivateBlend.Start = true;
|
||||
eShieldDeactivateBlend.Reverse = true;
|
||||
m_EventBroker->Publish(eShieldDeactivateBlend);
|
||||
|
||||
EntityWrapper animationNode = root.FirstChildByName("ActivateShield");
|
||||
if (animationNode.Valid()) {
|
||||
Events::AutoAnimationBlend eActionBlend;
|
||||
eActionBlend.RootNode = root;
|
||||
eActionBlend.NodeName = "ActionBlend";
|
||||
eActionBlend.AnimationEntity = animationNode;
|
||||
m_EventBroker->Publish(eActionBlend);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,6 +269,18 @@ bool DefenderWeaponBehaviour::OnInputCommand(ComponentWrapper cWeapon, WeaponInf
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void DefenderWeaponBehaviour::OnEquip(ComponentWrapper cWeapon, WeaponInfo& wi)
|
||||
{
|
||||
if (wi.ThirdPersonPlayerModel.Valid()) {
|
||||
Events::AutoAnimationBlend b1;
|
||||
b1.RootNode = wi.ThirdPersonPlayerModel;
|
||||
b1.NodeName = "DefenderWeapon";
|
||||
b1.SingleLevelBlend = true;
|
||||
m_EventBroker->Publish(b1);
|
||||
}
|
||||
}
|
||||
|
||||
void DefenderWeaponBehaviour::fireShell(ComponentWrapper cWeapon, WeaponInfo& wi)
|
||||
{
|
||||
cWeapon["FireCooldown"] = 60.0 / (double)cWeapon["RPM"];
|
||||
@@ -190,70 +297,54 @@ void DefenderWeaponBehaviour::fireShell(ComponentWrapper cWeapon, WeaponInfo& wi
|
||||
magAmmo -= 1;
|
||||
}
|
||||
|
||||
int numPellets = cWeapon["NumPellets"];
|
||||
float spreadAngle = cWeapon["SpreadAngle"];
|
||||
std::uniform_real_distribution<float> randomSpreadAngle(-spreadAngle, spreadAngle);
|
||||
|
||||
// Calculate pellet angles
|
||||
// HACK: Random for now?
|
||||
// TODO: Make distribution even for each quadrant
|
||||
std::vector<glm::vec2> pelletAngles;
|
||||
for (int i = 0; i < numPellets; i++) {
|
||||
pelletAngles.push_back(glm::vec2(randomSpreadAngle(m_RandomEngine), randomSpreadAngle(m_RandomEngine)));
|
||||
// We can't really do any valuable calculations without a valid camera
|
||||
if (!m_CurrentCamera.Valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
double pelletDamage = (double)cWeapon["BaseDamage"] / numPellets;
|
||||
int numPellets = cWeapon["NumPellets"];
|
||||
|
||||
// Create a spread pattern
|
||||
std::vector<glm::vec2> pattern;
|
||||
// The first pellet is always centered
|
||||
pattern.push_back(glm::vec2(0, 0));
|
||||
// Any additional pellets form circles around the middle
|
||||
int numOuterPellets = numPellets - 1;
|
||||
float angleIncrement = glm::two_pi<float>() / numOuterPellets;
|
||||
for (int i = 0; i < numOuterPellets; ++i) {
|
||||
float angle = angleIncrement * i;
|
||||
glm::vec2 pellet = glm::vec2(glm::cos(angle), glm::sin(angle));
|
||||
pattern.push_back(pellet);
|
||||
}
|
||||
|
||||
// Deal damage (clientside)
|
||||
dealDamage(cWeapon, wi, pattern);
|
||||
|
||||
// Spawn tracers
|
||||
spawnTracers(cWeapon, wi, pattern);
|
||||
|
||||
// View punch
|
||||
if (IsClient) {
|
||||
EntityWrapper camera = wi.Player.FirstChildByName("Camera");
|
||||
if (camera.Valid()) {
|
||||
Field<glm::vec3> cameraOrientation = camera["Transform"]["Orientation"];
|
||||
float viewPunch = cWeapon["ViewPunch"];
|
||||
float maxTravelAngle = cWeapon["MaxTravelAngle"];
|
||||
Field<float> currentTravel = cWeapon["CurrentTravel"];
|
||||
if (currentTravel < maxTravelAngle) {
|
||||
float change = viewPunch;
|
||||
if (currentTravel + change > maxTravelAngle) {
|
||||
change = maxTravelAngle - currentTravel;
|
||||
}
|
||||
cameraOrientation.x(cameraOrientation.x() + change);
|
||||
currentTravel += change;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tracers
|
||||
EntityWrapper weaponModelEntity;
|
||||
if (wi.Player == LocalPlayer) {
|
||||
weaponModelEntity = wi.FirstPersonEntity;
|
||||
} else {
|
||||
weaponModelEntity = wi.ThirdPersonEntity;
|
||||
}
|
||||
if (weaponModelEntity.Valid()) {
|
||||
EntityWrapper spawner = weaponModelEntity.FirstChildByName("WeaponMuzzle");
|
||||
Events::PlaySoundOnEntity e;
|
||||
e.Emitter = weaponModelEntity;
|
||||
e.FilePath = "Audio/weapon/Shotgun/ShotgunFire.wav";
|
||||
e.Gain = 1.f;
|
||||
if (IsClient) {
|
||||
m_EventBroker->Publish(e);
|
||||
}
|
||||
for (auto& angles : pelletAngles) {
|
||||
glm::vec3 direction = TransformSystem::AbsoluteOrientation(spawner) * glm::quat(glm::vec3(angles, 0.f)) * glm::vec3(0, 0, -1);
|
||||
float distance = traceRayDistance(TransformSystem::AbsolutePosition(spawner), direction);
|
||||
EntityWrapper ray = SpawnerSystem::Spawn(spawner);
|
||||
((Field<glm::vec3>)ray["Transform"]["Scale"]).z(distance / 100.f);
|
||||
Field<glm::vec3> orientation = ray["Transform"]["Orientation"];
|
||||
orientation.x(orientation.x() + angles.x);
|
||||
orientation.y(orientation.y() + angles.y);
|
||||
glm::vec3 trajectory = direction * distance;
|
||||
dealDamage(cWeapon, wi, direction, pelletDamage);
|
||||
}
|
||||
}
|
||||
//if (IsClient) {
|
||||
// EntityWrapper camera = wi.Player.FirstChildByName("Camera");
|
||||
// if (camera.Valid()) {
|
||||
// glm::vec3& cameraOrientation = camera["Transform"]["Orientation"];
|
||||
// float viewPunch = cWeapon["ViewPunch"];
|
||||
// float maxTravelAngle = cWeapon["MaxTravelAngle"];
|
||||
// float& currentTravel = cWeapon["CurrentTravel"];
|
||||
// if (currentTravel < maxTravelAngle) {
|
||||
// float change = viewPunch;
|
||||
// if (currentTravel + change > maxTravelAngle) {
|
||||
// change = maxTravelAngle - currentTravel;
|
||||
// }
|
||||
// cameraOrientation.x += change;
|
||||
// currentTravel += change;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
// Play animation
|
||||
playAnimationAndReturn(wi.FirstPersonEntity, "FinalBlend", "Fire");
|
||||
playAnimationAndReturn(wi.ThirdPersonPlayerModel, "FinalBlend", "Fire");
|
||||
|
||||
// Sound
|
||||
Events::PlaySoundOnEntity e;
|
||||
@@ -262,7 +353,63 @@ void DefenderWeaponBehaviour::fireShell(ComponentWrapper cWeapon, WeaponInfo& wi
|
||||
m_EventBroker->Publish(e);
|
||||
}
|
||||
|
||||
void DefenderWeaponBehaviour::dealDamage(ComponentWrapper cWeapon, WeaponInfo& wi, glm::vec3 direction, double damage)
|
||||
void DefenderWeaponBehaviour::spawnTracers(ComponentWrapper cWeapon, WeaponInfo& wi, std::vector<glm::vec2> pattern)
|
||||
{
|
||||
EntityWrapper flashSpawner = getRelevantWeaponEntity(wi).FirstChildByName("WeaponMuzzleFlash");
|
||||
if (flashSpawner.Valid()) {
|
||||
std::uniform_real_distribution<float> randomSpreadAngle(0.f, 3.1415f*2);
|
||||
EntityWrapper flash = SpawnerSystem::Spawn(flashSpawner, flashSpawner);
|
||||
if (flash.Valid()) {
|
||||
((Field<glm::vec3>)flash["Transform"]["Orientation"]).z(randomSpreadAngle(m_RandomEngine));
|
||||
}
|
||||
}
|
||||
|
||||
EntityWrapper muzzle = getRelevantWeaponEntity(wi).FirstChildByName("WeaponMuzzleRay");
|
||||
if (!muzzle.Valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
EntityWrapper camera = wi.Player.FirstChildByName("Camera");
|
||||
if (!camera.Valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
float spreadAngle = glm::radians((float)cWeapon["SpreadAngle"]);
|
||||
|
||||
for (auto& pellet : pattern) {
|
||||
glm::quat pelletRotation = glm::quat(TransformSystem::AbsoluteOrientationEuler(camera)) * glm::quat(glm::vec3(pellet.y, pellet.x, 0) * spreadAngle);
|
||||
glm::vec3 cameraPosition = TransformSystem::AbsolutePosition(camera);
|
||||
glm::vec3 direction = pelletRotation * glm::vec3(0, 0, -1);
|
||||
|
||||
float distance;
|
||||
glm::vec3 hitPosition;
|
||||
if (Collision::EntityFirstHitByRay(Ray(cameraPosition, direction), m_CollisionOctree, distance, hitPosition) != boost::none) { // don't spawn ray if you "miss the world"
|
||||
|
||||
EntityWrapper ray = SpawnerSystem::Spawn(muzzle);
|
||||
if (ray.Valid()) {
|
||||
ComponentWrapper cTransform = ray["Transform"];
|
||||
Field<glm::vec3> rayOrigin = cTransform["Position"];
|
||||
Field<glm::vec3> rayOrientation = cTransform["Orientation"];
|
||||
Field<glm::vec3> rayScale = cTransform["Scale"];
|
||||
|
||||
glm::vec3 muzzlePosition = TransformSystem::AbsolutePosition(muzzle);
|
||||
glm::quat muzzleOrientation = TransformSystem::AbsoluteOrientation(muzzle);
|
||||
|
||||
rayOrigin = muzzlePosition;
|
||||
|
||||
glm::vec3 muzzleToHit = hitPosition - muzzlePosition;
|
||||
glm::vec3 lookVector = glm::normalize(-muzzleToHit);
|
||||
float pitch = std::asin(-lookVector.y);
|
||||
float yaw = std::atan2(lookVector.x, lookVector.z);
|
||||
glm::quat orientation = glm::quat(glm::vec3(pitch, yaw, 0));
|
||||
rayOrientation = glm::eulerAngles(orientation);
|
||||
rayScale.x(glm::length(muzzleToHit));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DefenderWeaponBehaviour::dealDamage(ComponentWrapper cWeapon, WeaponInfo& wi, const std::vector<glm::vec2>& pattern)
|
||||
{
|
||||
// Only deal damage client side
|
||||
if (!IsClient) {
|
||||
@@ -278,47 +425,76 @@ void DefenderWeaponBehaviour::dealDamage(ComponentWrapper cWeapon, WeaponInfo& w
|
||||
if (!wi.Player.Valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
glm::vec3 maxRange = direction * 2.f;
|
||||
EntityWrapper camera = wi.Player.FirstChildByName("Camera");
|
||||
glm::vec3 cameraPosition = TransformSystem::AbsolutePosition(camera);
|
||||
if (!camera.Valid()) {
|
||||
return;
|
||||
}
|
||||
Rectangle screenResolution = m_Renderer->GetViewportSize();
|
||||
glm::vec2 centerScreen = glm::vec2(screenResolution.Width / 2, screenResolution.Height / 2);
|
||||
glm::vec2 screenCoords = cameraFromEntity(m_CurrentCamera).WorldToScreen(cameraPosition + maxRange, m_Renderer->GetViewportSize());
|
||||
PickData pickData = m_Renderer->Pick(centerScreen + screenCoords);
|
||||
EntityWrapper victim(m_World, pickData.Entity);
|
||||
if (!victim.Valid()) {
|
||||
return;
|
||||
|
||||
// Convert the spread angle to screen coordinates, taking FOV into account
|
||||
Rectangle res = m_Renderer->GetViewportSize();
|
||||
float spreadAngle = glm::radians((float)cWeapon["SpreadAngle"]);
|
||||
float nearClip = (double)m_CurrentCamera["Camera"]["NearClip"];
|
||||
float farClip = (double)m_CurrentCamera["Camera"]["FarClip"];
|
||||
float yFOV = glm::radians((double)m_CurrentCamera["Camera"]["FOV"]);
|
||||
//float yRefFOV = glm::radians(59.f);
|
||||
//float yRef = glm::tan(yRefFOV) * nearClip;
|
||||
//float yRatio = yRef / (glm::tan(yFOV) * nearClip);
|
||||
//float yMax = (yRatio / 2.f) * spreadAngle * (res.Height / 2.f);
|
||||
float yRefFOV = glm::radians(59.f);
|
||||
float yRef = glm::tan(yRefFOV) * nearClip;
|
||||
float yRatio = yRef / (glm::tan(yFOV) * nearClip);
|
||||
float yMax = yRatio * (glm::tan(spreadAngle) * (farClip - nearClip)) * glm::pi<float>(); // ????? Good enough????
|
||||
|
||||
LOG_DEBUG("Ratio: %f", yRatio);
|
||||
LOG_DEBUG("fatClip: %f", farClip);
|
||||
LOG_DEBUG("yMax: %f", yMax);
|
||||
double pelletDamage = (double)cWeapon["BaseDamage"] / pattern.size();
|
||||
|
||||
// Pick!
|
||||
std::unordered_map<EntityWrapper, double> damageSum;
|
||||
glm::vec2 screenCenter(res.Width / 2.f, res.Height / 2.f);
|
||||
for (auto& pellet : pattern) {
|
||||
glm::vec2 pickCoord = screenCenter + (pellet * glm::vec2(yMax, yMax));
|
||||
PickData pick = m_Renderer->Pick(pickCoord);
|
||||
|
||||
EntityWrapper victim(m_World, pick.Entity);
|
||||
if (!victim.Valid()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Temp hit decal
|
||||
EntityWrapper hit = ResourceManager::Load<EntityFile>("Schema/Entities/HitTest.xml")->MergeInto(m_World);
|
||||
(Field<glm::vec3>)hit["Transform"]["Position"] = pick.Position;
|
||||
|
||||
// Don't let us shoot ourselves in the foot somehow
|
||||
if (victim == LocalPlayer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only care about players being hit
|
||||
if (!victim.HasComponent("Player")) {
|
||||
victim = victim.FirstParentWithComponent("Player");
|
||||
if (!victim.Valid()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for friendly fire
|
||||
if ((ComponentInfo::EnumType)victim["Team"]["Team"] == (ComponentInfo::EnumType)wi.Player["Team"]["Team"]) {
|
||||
// TODO: Ammo sharing
|
||||
continue;
|
||||
}
|
||||
|
||||
damageSum[victim] += pelletDamage;
|
||||
((Field<glm::vec4>)hit["Model"]["Color"]).z(1.f);
|
||||
}
|
||||
|
||||
// Don't let us shoot ourselves in the foot somehow
|
||||
if (victim == LocalPlayer) {
|
||||
return;
|
||||
// Deal damage!
|
||||
for (auto& kv : damageSum) {
|
||||
// Deal damage!
|
||||
Events::PlayerDamage ePlayerDamage;
|
||||
ePlayerDamage.Inflictor = wi.Player;
|
||||
ePlayerDamage.Victim = kv.first;
|
||||
ePlayerDamage.Damage = kv.second;
|
||||
m_EventBroker->Publish(ePlayerDamage);
|
||||
LOG_DEBUG("Dealt %f damage to #%i", kv.second, kv.first.ID);
|
||||
}
|
||||
|
||||
// Only care about players being hit
|
||||
if (!victim.HasComponent("Player")) {
|
||||
victim = victim.FirstParentWithComponent("Player");
|
||||
}
|
||||
if (!victim.Valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for friendly fire
|
||||
if ((ComponentInfo::EnumType)victim["Team"]["Team"] == (ComponentInfo::EnumType)wi.Player["Team"]["Team"]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Deal damage!
|
||||
Events::PlayerDamage ePlayerDamage;
|
||||
ePlayerDamage.Inflictor = wi.Player;
|
||||
ePlayerDamage.Victim = victim;
|
||||
ePlayerDamage.Damage = damage;
|
||||
m_EventBroker->Publish(ePlayerDamage);
|
||||
LOG_DEBUG("Damage: %f", damage);
|
||||
}
|
||||
|
||||
bool DefenderWeaponBehaviour::canFire(ComponentWrapper cWeapon, WeaponInfo& wi)
|
||||
@@ -343,3 +519,148 @@ Camera DefenderWeaponBehaviour::cameraFromEntity(EntityWrapper camera)
|
||||
cam.SetOrientation(glm::quat((const glm::vec3&)cTransform["Orientation"]));
|
||||
return cam;
|
||||
}
|
||||
|
||||
void DefenderWeaponBehaviour::CheckBoost(ComponentWrapper cWeapon, WeaponInfo& wi)
|
||||
{
|
||||
// Only check ammo client side
|
||||
if (!IsClient) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only handle ammo check for the local player
|
||||
if (wi.Player != LocalPlayer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure the player isn't checking from the grave
|
||||
if (!wi.Player.Valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 3D-pick middle of screen
|
||||
Rectangle viewport = m_Renderer->GetViewportSize();
|
||||
glm::vec2 centerScreen(viewport.Width / 2, viewport.Height / 2);
|
||||
// TODO: Some horizontal spread
|
||||
PickData pickData = m_Renderer->Pick(centerScreen);
|
||||
EntityWrapper victim(m_World, pickData.Entity);
|
||||
if (!victim.Valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't let us somehow shoot ourselves in the foot
|
||||
if (victim == LocalPlayer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only care about players being hit
|
||||
if (!victim.HasComponent("Player")) {
|
||||
victim = victim.FirstParentWithComponent("Player");
|
||||
}
|
||||
if (!victim.Valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// If friendly fire, reduce damage to 0 (needed to make Boosts, Ammosharing work)
|
||||
if ((ComponentInfo::EnumType)victim["Team"]["Team"] == (ComponentInfo::EnumType)wi.Player["Team"]["Team"]) {
|
||||
|
||||
EntityWrapper friendlyBoostHudSpawner = wi.FirstPersonPlayerModel.FirstChildByName("FriendlyBoostAttachment");
|
||||
if (friendlyBoostHudSpawner.Valid()) {
|
||||
|
||||
EntityWrapper assaultBoost = victim.FirstChildByName("BoostAssault");
|
||||
EntityWrapper defenderBoost = victim.FirstChildByName("BoostDefender");
|
||||
EntityWrapper sniperBoost = victim.FirstChildByName("BoostSniper");
|
||||
|
||||
auto children = m_World->GetDirectChildren(friendlyBoostHudSpawner.ID);
|
||||
|
||||
if (children.first == children.second) {
|
||||
if (friendlyBoostHudSpawner.HasComponent("Spawner")) {
|
||||
|
||||
EntityWrapper friendlyBoostHud = SpawnerSystem::Spawn(friendlyBoostHudSpawner, friendlyBoostHudSpawner);
|
||||
if (friendlyBoostHud.Valid()) {
|
||||
EntityWrapper assaultBoostEntity = friendlyBoostHud.FirstChildByName("AssaultBoost");
|
||||
if (assaultBoostEntity.Valid()) {
|
||||
EntityWrapper active = assaultBoostEntity.FirstChildByName("Active");
|
||||
if (active.HasComponent("Text")) {
|
||||
if (assaultBoost.Valid()) {
|
||||
(Field<bool>)active["Text"]["Visible"] = true;
|
||||
} else {
|
||||
(Field<bool>)active["Text"]["Visible"] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EntityWrapper defenderBoostEntity = friendlyBoostHud.FirstChildByName("DefenderBoost");
|
||||
if (defenderBoostEntity.Valid()) {
|
||||
EntityWrapper active = defenderBoostEntity.FirstChildByName("Active");
|
||||
if (active.HasComponent("Text")) {
|
||||
if (defenderBoost.Valid()) {
|
||||
(Field<bool>)active["Text"]["Visible"] = true;
|
||||
} else {
|
||||
(Field<bool>)active["Text"]["Visible"] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EntityWrapper sniperBoostEntity = friendlyBoostHud.FirstChildByName("SniperBoost");
|
||||
if (sniperBoostEntity.Valid()) {
|
||||
EntityWrapper active = sniperBoostEntity.FirstChildByName("Active");
|
||||
if (active.HasComponent("Text")) {
|
||||
if (sniperBoost.Valid()) {
|
||||
(Field<bool>)active["Text"]["Visible"] = true;
|
||||
} else {
|
||||
(Field<bool>)active["Text"]["Visible"] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
EntityWrapper friendlyBoostHud = friendlyBoostHudSpawner.FirstChildByName("FriendlyBoostHUD");
|
||||
if (friendlyBoostHud.Valid()) {
|
||||
if (friendlyBoostHud.HasComponent("Lifetime")) {
|
||||
(Field<double>)friendlyBoostHud["Lifetime"]["Lifetime"] = 0.5;
|
||||
}
|
||||
|
||||
|
||||
|
||||
EntityWrapper assaultBoostEntity = friendlyBoostHud.FirstChildByName("AssaultBoost");
|
||||
if (assaultBoostEntity.Valid()) {
|
||||
EntityWrapper active = assaultBoostEntity.FirstChildByName("Active");
|
||||
if (active.HasComponent("Text")) {
|
||||
if (assaultBoost.Valid()) {
|
||||
(Field<bool>)active["Text"]["Visible"] = true;
|
||||
} else {
|
||||
(Field<bool>)active["Text"]["Visible"] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EntityWrapper defenderBoostEntity = friendlyBoostHud.FirstChildByName("DefenderBoost");
|
||||
if (defenderBoostEntity.Valid()) {
|
||||
EntityWrapper active = defenderBoostEntity.FirstChildByName("Active");
|
||||
if (active.HasComponent("Text")) {
|
||||
if (defenderBoost.Valid()) {
|
||||
(Field<bool>)active["Text"]["Visible"] = true;
|
||||
} else {
|
||||
(Field<bool>)active["Text"]["Visible"] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EntityWrapper sniperBoostEntity = friendlyBoostHud.FirstChildByName("SniperBoost");
|
||||
if (sniperBoostEntity.Valid()) {
|
||||
EntityWrapper active = sniperBoostEntity.FirstChildByName("Active");
|
||||
if (active.HasComponent("Text")) {
|
||||
if (sniperBoost.Valid()) {
|
||||
(Field<bool>)active["Text"]["Visible"] = true;
|
||||
} else {
|
||||
(Field<bool>)active["Text"]["Visible"] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,61 @@ void SidearmWeaponBehaviour::UpdateComponent(EntityWrapper& entity, ComponentWra
|
||||
|
||||
void SidearmWeaponBehaviour::UpdateWeapon(ComponentWrapper cWeapon, WeaponInfo& wi, double dt)
|
||||
{
|
||||
CheckAmmo(cWeapon, wi);
|
||||
|
||||
// Start reloading automatically if at 0 mag ammo
|
||||
Field<int> magAmmo = cWeapon["MagazineAmmo"];
|
||||
if (m_ConfigAutoReload && magAmmo <= 0) {
|
||||
OnReload(cWeapon, wi);
|
||||
}
|
||||
|
||||
// Only start reloading once we're done firing
|
||||
Field<bool> reloadQueued = cWeapon["ReloadQueued"];
|
||||
Field<double> fireCooldown = cWeapon["FireCooldown"];
|
||||
Field<bool> isReloading = cWeapon["IsReloading"];
|
||||
if (reloadQueued && fireCooldown <= 0) {
|
||||
reloadQueued = fireCooldown;
|
||||
isReloading = true;
|
||||
}
|
||||
|
||||
// Decrement reload timer
|
||||
Field<double> reloadTimer = cWeapon["ReloadTimer"];
|
||||
if (isReloading) {
|
||||
reloadTimer = glm::max(0.0, reloadTimer - dt);
|
||||
}
|
||||
|
||||
// Handle reloading
|
||||
if (isReloading && reloadTimer <= 0.0) {
|
||||
Field<int> magSize = cWeapon["MagazineSize"];
|
||||
|
||||
magAmmo = magSize;
|
||||
isReloading = false;
|
||||
if (wi.FirstPersonEntity.Valid()) {
|
||||
wi.FirstPersonEntity.FirstChildByName("ViewModel")["Model"]["Visible"] = true;
|
||||
}
|
||||
if (wi.ThirdPersonEntity.Valid()) {
|
||||
wi.ThirdPersonEntity["Model"]["Visible"] = true;
|
||||
}
|
||||
}
|
||||
double reloadTime = cWeapon["ReloadTime"];
|
||||
if (isReloading && reloadTimer <= reloadTime / 2) {
|
||||
|
||||
}
|
||||
|
||||
// Update first person run animation
|
||||
ComponentWrapper cPlayer = wi.Player["Player"];
|
||||
ComponentWrapper cPhysics = wi.Player["Physics"];
|
||||
const float& movementSpeed = cPlayer["MovementSpeed"];
|
||||
float speed = glm::length((const glm::vec3&)cPhysics["Velocity"]);
|
||||
float animationWeight = glm::min(speed, movementSpeed) / movementSpeed;
|
||||
EntityWrapper rootNode = wi.FirstPersonEntity;
|
||||
if (rootNode.Valid()) {
|
||||
EntityWrapper blend = rootNode.FirstChildByName("MovementBlendSidearm");
|
||||
if (blend.Valid()) {
|
||||
(Field<double>)blend["Blend"]["Weight"] = animationWeight;
|
||||
}
|
||||
}
|
||||
|
||||
if ((bool)cWeapon["Automatic"] && canFire(cWeapon)) {
|
||||
fireBullet(cWeapon, wi);
|
||||
}
|
||||
@@ -32,9 +87,78 @@ void SidearmWeaponBehaviour::OnCeasePrimaryFire(ComponentWrapper cWeapon, Weapon
|
||||
cWeapon["TriggerHeld"] = false;
|
||||
}
|
||||
|
||||
|
||||
void SidearmWeaponBehaviour::OnReload(ComponentWrapper cWeapon, WeaponInfo& wi)
|
||||
{
|
||||
Field<bool> reloadQueued = cWeapon["ReloadQueued"];
|
||||
Field<bool> isReloading = cWeapon["IsReloading"];
|
||||
if (reloadQueued || isReloading) {
|
||||
return;
|
||||
}
|
||||
|
||||
Field<int> magAmmo = cWeapon["MagazineAmmo"];
|
||||
Field<int> magSize = cWeapon["MagazineSize"];
|
||||
if (magAmmo >= magSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
double reloadTime = cWeapon["ReloadTime"];
|
||||
Field<double> reloadTimer = cWeapon["ReloadTimer"];
|
||||
|
||||
// Start reload
|
||||
reloadQueued = true;
|
||||
reloadTimer = reloadTime;
|
||||
|
||||
// Play animation
|
||||
playAnimationAndReturn(wi.FirstPersonEntity, "ActionBlend", "Reload");
|
||||
// Third person anim
|
||||
Events::AutoAnimationBlend eReloadBlend;
|
||||
eReloadBlend.RootNode = wi.ThirdPersonPlayerModel;
|
||||
eReloadBlend.NodeName = "Reload";
|
||||
eReloadBlend.Restart = true;
|
||||
eReloadBlend.Start = true;
|
||||
m_EventBroker->Publish(eReloadBlend);
|
||||
|
||||
// Spawn explosion effect
|
||||
if (wi.FirstPersonEntity.Valid()) {
|
||||
if (IsClient) {
|
||||
EntityWrapper reloadEffectSpawner = wi.FirstPersonEntity.FirstChildByName("ReloadSpawner");
|
||||
if (reloadEffectSpawner.Valid()) {
|
||||
reloadEffectSpawner.DeleteChildren();
|
||||
SpawnerSystem::Spawn(reloadEffectSpawner, reloadEffectSpawner);
|
||||
}
|
||||
}
|
||||
wi.FirstPersonEntity.FirstChildByName("ViewModel")["Model"]["Visible"] = false;
|
||||
}
|
||||
if (wi.ThirdPersonEntity.Valid()) {
|
||||
if (IsServer) {
|
||||
EntityWrapper reloadEffectSpawner = wi.ThirdPersonEntity.FirstChildByName("ReloadSpawner");
|
||||
if (reloadEffectSpawner.Valid()) {
|
||||
reloadEffectSpawner.DeleteChildren();
|
||||
SpawnerSystem::Spawn(reloadEffectSpawner, reloadEffectSpawner);
|
||||
}
|
||||
}
|
||||
wi.ThirdPersonEntity["Model"]["Visible"] = false;
|
||||
}
|
||||
|
||||
// Sound
|
||||
Events::PlaySoundOnEntity e;
|
||||
e.Emitter = wi.Player;
|
||||
e.FilePath = "Audio/weapon/Assault/AssaultWeaponReload.wav";
|
||||
m_EventBroker->Publish(e);
|
||||
}
|
||||
|
||||
void SidearmWeaponBehaviour::OnEquip(ComponentWrapper cWeapon, WeaponInfo& wi)
|
||||
{
|
||||
cWeapon["FireCooldown"] = (double)cWeapon["EquipTime"];
|
||||
|
||||
if(wi.ThirdPersonPlayerModel.Valid()) {
|
||||
Events::AutoAnimationBlend b1;
|
||||
b1.RootNode = wi.ThirdPersonPlayerModel;
|
||||
b1.NodeName = "SidearmWeapon";
|
||||
b1.SingleLevelBlend = true;
|
||||
m_EventBroker->Publish(b1);
|
||||
}
|
||||
}
|
||||
|
||||
void SidearmWeaponBehaviour::OnHolster(ComponentWrapper cWeapon, WeaponInfo& wi)
|
||||
@@ -51,27 +175,369 @@ void SidearmWeaponBehaviour::fireBullet(ComponentWrapper cWeapon, WeaponInfo& wi
|
||||
{
|
||||
cWeapon["FireCooldown"] = 60.0 / (double)cWeapon["RPM"];
|
||||
|
||||
// Ammo
|
||||
Field<int> magAmmo = cWeapon["MagazineAmmo"];
|
||||
if (magAmmo <= 0) {
|
||||
return;
|
||||
} else {
|
||||
magAmmo -= 1;
|
||||
}
|
||||
|
||||
// Get weapon model based on current person
|
||||
EntityWrapper weaponModelEntity = getRelevantWeaponEntity(wi);
|
||||
if (!weaponModelEntity.Valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Tracer
|
||||
EntityWrapper tracerSpawner = weaponModelEntity.FirstChildByName("WeaponMuzzle");
|
||||
//Tracer
|
||||
EntityWrapper tracerSpawner = weaponModelEntity.FirstChildByName("WeaponMuzzleRay");
|
||||
if (tracerSpawner.Valid()) {
|
||||
glm::vec3 origin = TransformSystem::AbsolutePosition(tracerSpawner);
|
||||
glm::vec3 direction = TransformSystem::AbsoluteOrientation(tracerSpawner) * glm::vec3(0, 0, -1);
|
||||
float distance = traceRayDistance(origin, direction);
|
||||
EntityWrapper ray = SpawnerSystem::Spawn(tracerSpawner);
|
||||
((Field<glm::vec3>)ray["Transform"]["Scale"]).z(distance / 100.f);
|
||||
EntityWrapper ray = SpawnerSystem::Spawn(tracerSpawner, tracerSpawner);
|
||||
if (ray.Valid()) {
|
||||
((Field<glm::vec3>)ray["Transform"]["Scale"]).z(distance);
|
||||
}
|
||||
}
|
||||
|
||||
//Flash
|
||||
EntityWrapper flashSpawner = weaponModelEntity.FirstChildByName("WeaponMuzzleFlash");
|
||||
if (flashSpawner.Valid()) {
|
||||
std::uniform_real_distribution<float> randomSpreadAngle(0.f, 3.1415f*2);
|
||||
EntityWrapper flash = SpawnerSystem::Spawn(flashSpawner, flashSpawner);
|
||||
if(flash.Valid()){
|
||||
((Field<glm::vec3>)flash["Transform"]["Orientation"]).z(randomSpreadAngle(m_RandomEngine));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Deal damage
|
||||
if (dealDamage(cWeapon, wi)) {
|
||||
// Show hit marker
|
||||
EntityWrapper hitMarkerSpawner = wi.Player.FirstChildByName("HitMarkerSpawner");
|
||||
if (hitMarkerSpawner.Valid()) {
|
||||
SpawnerSystem::Spawn(hitMarkerSpawner, hitMarkerSpawner);
|
||||
Events::PlaySoundOnEntity e;
|
||||
e.Emitter = wi.Player;
|
||||
e.FilePath = "Audio/weapon/hitclick.wav";
|
||||
m_EventBroker->Publish(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Play animation
|
||||
playAnimationAndReturn(wi.FirstPersonEntity, "ActionBlend", "Fire");
|
||||
|
||||
// Third person anim
|
||||
if (wi.ThirdPersonPlayerModel.Valid()) {
|
||||
Events::AutoAnimationBlend b1;
|
||||
b1.RootNode = wi.ThirdPersonPlayerModel;
|
||||
b1.NodeName = "Fire";
|
||||
b1.Restart = true;
|
||||
b1.Start = true;
|
||||
m_EventBroker->Publish(b1);
|
||||
}
|
||||
}
|
||||
|
||||
bool SidearmWeaponBehaviour::canFire(ComponentWrapper cWeapon)
|
||||
{
|
||||
bool triggerHeld = cWeapon["TriggerHeld"];
|
||||
Field<double> cooldown = cWeapon["FireCooldown"];
|
||||
// TODO: Ammo checks
|
||||
return triggerHeld && cooldown <= 0.0;
|
||||
}
|
||||
bool cooldownPassed = (double)cWeapon["FireCooldown"] <= 0.0;
|
||||
bool isNotReloading = !(bool)cWeapon["IsReloading"];
|
||||
return triggerHeld && cooldownPassed && isNotReloading;
|
||||
}
|
||||
|
||||
bool SidearmWeaponBehaviour::dealDamage(ComponentWrapper cWeapon, WeaponInfo& wi)
|
||||
{
|
||||
// Only deal damage client side
|
||||
if (!IsClient) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only handle damage for the local player
|
||||
if (wi.Player != LocalPlayer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure the player isn't shooting from the grave
|
||||
if (!wi.Player.Valid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3D-pick middle of screen
|
||||
Rectangle viewport = m_Renderer->GetViewportSize();
|
||||
glm::vec2 centerScreen(viewport.Width / 2, viewport.Height / 2);
|
||||
// TODO: Some horizontal spread
|
||||
PickData pickData = m_Renderer->Pick(centerScreen);
|
||||
EntityWrapper victim(m_World, pickData.Entity);
|
||||
if (!victim.Valid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't let us somehow shoot ourselves in the foot
|
||||
if (victim == LocalPlayer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only care about players being hit
|
||||
if (!victim.HasComponent("Player")) {
|
||||
victim = victim.FirstParentWithComponent("Player");
|
||||
}
|
||||
if (!victim.Valid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
double damage = cWeapon["BaseDamage"];
|
||||
// If friendly fire, reduce damage to 0 (needed to make Boosts, Ammosharing work)
|
||||
if ((ComponentInfo::EnumType)victim["Team"]["Team"] == (ComponentInfo::EnumType)wi.Player["Team"]["Team"]) {
|
||||
damage = 0;
|
||||
|
||||
bool gaveAmmo = false;
|
||||
|
||||
if (victim.HasComponent("AssaultWeapon")) {
|
||||
int magazineSize = victim["AssaultWeapon"]["MagazineSize"];
|
||||
int magazineAmmo = victim["AssaultWeapon"]["MagazineAmmo"];
|
||||
|
||||
int maxAmmo = victim["AssaultWeapon"]["MaxAmmo"];
|
||||
int ammo = victim["AssaultWeapon"]["Ammo"];
|
||||
|
||||
if (magazineAmmo < magazineSize) {
|
||||
gaveAmmo = true;
|
||||
} else if (ammo < maxAmmo) {
|
||||
gaveAmmo = true;
|
||||
}
|
||||
} else if (victim.HasComponent("DefenderWeapon")) {
|
||||
int magazineSize = victim["DefenderWeapon"]["MagazineSize"];
|
||||
int magazineAmmo = victim["DefenderWeapon"]["MagazineAmmo"];
|
||||
|
||||
int maxAmmo = victim["DefenderWeapon"]["MaxAmmo"];
|
||||
int ammo = victim["DefenderWeapon"]["Ammo"];
|
||||
|
||||
if (magazineAmmo < magazineSize) {
|
||||
gaveAmmo = true;
|
||||
} else if (ammo < maxAmmo) {
|
||||
gaveAmmo = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (gaveAmmo) {
|
||||
EntityWrapper effectSpawner = wi.FirstPersonEntity.FirstChildByName("AmmoShareEffectSpawner");
|
||||
if (effectSpawner.Valid()) {
|
||||
if (effectSpawner.HasComponent("Spawner")) {
|
||||
SpawnerSystem::Spawn(effectSpawner, effectSpawner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spawnTracer(cWeapon, wi);
|
||||
|
||||
// Deal damage!
|
||||
Events::PlayerDamage ePlayerDamage;
|
||||
ePlayerDamage.Inflictor = wi.Player;
|
||||
ePlayerDamage.Victim = victim;
|
||||
ePlayerDamage.Damage = damage;
|
||||
m_EventBroker->Publish(ePlayerDamage);
|
||||
|
||||
return damage > 0;
|
||||
}
|
||||
|
||||
void SidearmWeaponBehaviour::spawnTracer(ComponentWrapper cWeapon, WeaponInfo& wi)
|
||||
{
|
||||
EntityWrapper muzzle = getRelevantWeaponEntity(wi).FirstChildByName("WeaponMuzzle");
|
||||
if (!muzzle.Valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
EntityWrapper camera = wi.Player.FirstChildByName("Camera");
|
||||
if (!camera.Valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
glm::vec3 cameraPosition = TransformSystem::AbsolutePosition(camera);
|
||||
glm::vec3 direction = glm::vec3(0, 0, -1);
|
||||
|
||||
float distance;
|
||||
glm::vec3 hitPosition;
|
||||
Collision::EntityFirstHitByRay(Ray(cameraPosition, direction), m_CollisionOctree, distance, hitPosition);
|
||||
|
||||
EntityWrapper ray = SpawnerSystem::Spawn(muzzle);
|
||||
if (ray.Valid()) {
|
||||
ComponentWrapper cTransform = ray["Transform"];
|
||||
Field<glm::vec3> rayOrigin = cTransform["Position"];
|
||||
Field<glm::vec3> rayOrientation = cTransform["Orientation"];
|
||||
Field<glm::vec3> rayScale = cTransform["Scale"];
|
||||
|
||||
glm::vec3 muzzlePosition = TransformSystem::AbsolutePosition(muzzle);
|
||||
glm::quat muzzleOrientation = TransformSystem::AbsoluteOrientation(muzzle);
|
||||
|
||||
rayOrigin = muzzlePosition;
|
||||
|
||||
glm::vec3 muzzleToHit = hitPosition - muzzlePosition;
|
||||
glm::vec3 lookVector = glm::normalize(-muzzleToHit);
|
||||
float pitch = std::asin(-lookVector.y);
|
||||
float yaw = std::atan2(lookVector.x, lookVector.z);
|
||||
glm::quat orientation = glm::quat(glm::vec3(pitch, yaw, 0));
|
||||
rayOrientation = glm::eulerAngles(orientation);
|
||||
rayScale.z(glm::length(muzzleToHit));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
void SidearmWeaponBehaviour::giveAmmo(ComponentWrapper cWeapon, WeaponInfo& wi, EntityWrapper receiver)
|
||||
{
|
||||
bool gaveAmmo = false;
|
||||
|
||||
if (receiver.HasComponent("AssaultWeapon")) {
|
||||
int magazineSize = receiver["AssaultWeapon"]["MagazineSize"];
|
||||
int& magazineAmmo = receiver["AssaultWeapon"]["MagazineAmmo"];
|
||||
|
||||
int maxAmmo = receiver["AssaultWeapon"]["MaxAmmo"];
|
||||
int& ammo = receiver["AssaultWeapon"]["Ammo"];
|
||||
|
||||
if(magazineAmmo < magazineSize) {
|
||||
magazineAmmo += 1;
|
||||
gaveAmmo = true;
|
||||
} else if (ammo < maxAmmo) {
|
||||
ammo += 1;
|
||||
gaveAmmo = true;
|
||||
}
|
||||
} else if (receiver.HasComponent("DefenderWeapon")) {
|
||||
int magazineSize = receiver["DefenderWeapon"]["MagazineSize"];
|
||||
int& magazineAmmo = receiver["DefenderWeapon"]["MagazineAmmo"];
|
||||
|
||||
int maxAmmo = receiver["DefenderWeapon"]["MaxAmmo"];
|
||||
int& ammo = receiver["DefenderWeapon"]["Ammo"];
|
||||
|
||||
if (magazineAmmo < magazineSize) {
|
||||
magazineAmmo += 1;
|
||||
gaveAmmo = true;
|
||||
} else if (ammo < maxAmmo) {
|
||||
ammo += 1;
|
||||
gaveAmmo = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(gaveAmmo) {
|
||||
EntityWrapper effectSpawner = wi.FirstPersonEntity.FirstChildByName("AmmoShareEffectSpawner");
|
||||
if(effectSpawner.Valid()) {
|
||||
if (effectSpawner.HasComponent("Spawner")) {
|
||||
SpawnerSystem::Spawn(effectSpawner, effectSpawner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
void SidearmWeaponBehaviour::CheckAmmo(ComponentWrapper cWeapon, WeaponInfo& wi)
|
||||
{
|
||||
// Only check ammo client side
|
||||
if (!IsClient) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only handle ammo check for the local player
|
||||
if (wi.Player != LocalPlayer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure the player isn't checking from the grave
|
||||
if (!wi.Player.Valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 3D-pick middle of screen
|
||||
Rectangle viewport = m_Renderer->GetViewportSize();
|
||||
glm::vec2 centerScreen(viewport.Width / 2, viewport.Height / 2);
|
||||
// TODO: Some horizontal spread
|
||||
PickData pickData = m_Renderer->Pick(centerScreen);
|
||||
EntityWrapper victim(m_World, pickData.Entity);
|
||||
if (!victim.Valid()) {
|
||||
RemoveFrindlyAmmoHUD(wi);
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't let us somehow shoot ourselves in the foot
|
||||
if (victim == LocalPlayer) {
|
||||
RemoveFrindlyAmmoHUD(wi);
|
||||
return;
|
||||
}
|
||||
|
||||
// Only care about players being hit
|
||||
if (!victim.HasComponent("Player")) {
|
||||
victim = victim.FirstParentWithComponent("Player");
|
||||
}
|
||||
if (!victim.Valid()) {
|
||||
RemoveFrindlyAmmoHUD(wi);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// If friendly fire, reduce damage to 0 (needed to make Boosts, Ammosharing work)
|
||||
if ((ComponentInfo::EnumType)victim["Team"]["Team"] == (ComponentInfo::EnumType)wi.Player["Team"]["Team"]) {
|
||||
int magazineAmmo = 0;
|
||||
int ammo = 0;
|
||||
if (victim.HasComponent("AssaultWeapon")) {
|
||||
magazineAmmo = (int)victim["AssaultWeapon"]["MagazineAmmo"];
|
||||
ammo = (int)victim["AssaultWeapon"]["Ammo"];
|
||||
|
||||
} else if (victim.HasComponent("DefenderWeapon")) {
|
||||
magazineAmmo = (int)victim["DefenderWeapon"]["MagazineAmmo"];
|
||||
ammo = (int)victim["DefenderWeapon"]["Ammo"];
|
||||
}
|
||||
|
||||
|
||||
EntityWrapper friendlyAmmoHudSpawner = wi.FirstPersonPlayerModel.FirstChildByName("FriendlyAmmoAttachment");
|
||||
if (friendlyAmmoHudSpawner.Valid()) {
|
||||
|
||||
auto children = m_World->GetDirectChildren(friendlyAmmoHudSpawner.ID);
|
||||
|
||||
if (children.first == children.second) {
|
||||
if (friendlyAmmoHudSpawner.HasComponent("Spawner")) {
|
||||
EntityWrapper friendlyAmmoHud = SpawnerSystem::Spawn(friendlyAmmoHudSpawner, friendlyAmmoHudSpawner);
|
||||
if (friendlyAmmoHud.Valid()) {
|
||||
EntityWrapper textEntity = friendlyAmmoHud.FirstChildByName("MagazineAmmo");
|
||||
if (textEntity.Valid()) {
|
||||
if (textEntity.HasComponent("Text")) {
|
||||
(Field<std::string>)textEntity["Text"]["Content"] = std::to_string(magazineAmmo);
|
||||
}
|
||||
}
|
||||
|
||||
EntityWrapper ammoTextEntity = friendlyAmmoHud.FirstChildByName("Ammo");
|
||||
if (ammoTextEntity.Valid()) {
|
||||
if (ammoTextEntity.HasComponent("Text")) {
|
||||
(Field<std::string>)ammoTextEntity["Text"]["Content"] = std::to_string(ammo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
EntityWrapper textEntity = friendlyAmmoHudSpawner.FirstChildByName("MagazineAmmo");
|
||||
if (textEntity.Valid()) {
|
||||
if (textEntity.HasComponent("Text")) {
|
||||
(Field<std::string>)textEntity["Text"]["Content"] = std::to_string(magazineAmmo);
|
||||
}
|
||||
}
|
||||
|
||||
EntityWrapper ammoTextEntity = friendlyAmmoHudSpawner.FirstChildByName("Ammo");
|
||||
if (ammoTextEntity.Valid()) {
|
||||
if (ammoTextEntity.HasComponent("Text")) {
|
||||
(Field<std::string>)ammoTextEntity["Text"]["Content"] = std::to_string(ammo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SidearmWeaponBehaviour::RemoveFrindlyAmmoHUD(WeaponInfo& wi)
|
||||
{
|
||||
EntityWrapper friendlyAmmoHudSpawner = wi.FirstPersonPlayerModel.FirstChildByName("FriendlyAmmoAttachment");
|
||||
if (friendlyAmmoHudSpawner.Valid()) {
|
||||
friendlyAmmoHudSpawner.DeleteChildren();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user