New weapon behaviours

This commit is contained in:
2016-03-01 13:26:50 +01:00
parent 6eb0b83d6b
commit e4c6a19c38
12 changed files with 232 additions and 55 deletions
@@ -15,10 +15,10 @@ public:
} }
void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cWeapon, double dt) override; void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cWeapon, double dt) override;
void UpdateWeapon(WeaponInfo& wi, double dt) override; void UpdateWeapon(ComponentWrapper cWeapon, WeaponInfo& wi, double dt) override;
void OnPrimaryFire(WeaponInfo& wi) override; void OnPrimaryFire(ComponentWrapper cWeapon, WeaponInfo& wi) override;
void OnCeasePrimaryFire(WeaponInfo& wi) override; void OnCeasePrimaryFire(ComponentWrapper cWeapon, WeaponInfo& wi) override;
bool OnInputCommand(WeaponInfo& wi, const Events::InputCommand& e) override; bool OnInputCommand(ComponentWrapper cWeapon, WeaponInfo& wi, const Events::InputCommand& e) override;
private: private:
std::random_device m_RandomDevice; std::random_device m_RandomDevice;
@@ -29,8 +29,8 @@ private:
bool OnSetCamera(const Events::SetCamera& e); bool OnSetCamera(const Events::SetCamera& e);
// Weapon functions // Weapon functions
void fireShell(WeaponInfo& wi); void fireShell(ComponentWrapper cWeapon, WeaponInfo& wi);
void dealDamage(WeaponInfo& wi, glm::vec3 direction, double damage); void dealDamage(ComponentWrapper cWeapon, WeaponInfo& wi, glm::vec3 direction, double damage);
// Utility // Utility
float traceRayDistance(glm::vec3 origin, glm::vec3 direction); float traceRayDistance(glm::vec3 origin, glm::vec3 direction);
@@ -0,0 +1,32 @@
#include "WeaponBehaviour.h"
#include "Collision/Collision.h"
#include "Core/EPlayerDamage.h"
class SidearmWeaponBehaviour : public WeaponBehaviour<SidearmWeaponBehaviour>
{
public:
SidearmWeaponBehaviour(SystemParams systemParams, IRenderer* renderer, Octree<EntityAABB>* collisionOctree)
: System(systemParams)
, WeaponBehaviour(systemParams, "SidearmWeapon", renderer, collisionOctree)
, m_RandomEngine(m_RandomDevice())
{ }
void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cWeapon, double dt) override;
void UpdateWeapon(ComponentWrapper cWeapon, WeaponInfo& wi, double dt) override;
void OnPrimaryFire(ComponentWrapper cWeapon, WeaponInfo& wi) override;
void OnCeasePrimaryFire(ComponentWrapper cWeapon, WeaponInfo& wi) override;
void OnHolster(ComponentWrapper cWeapon, WeaponInfo& wi) override;
private:
std::random_device m_RandomDevice;
std::mt19937 m_RandomEngine;
EntityWrapper m_CurrentCamera;
// Weapon functions
void fireBullet(ComponentWrapper cWeapon, WeaponInfo& wi);
//void dealDamage(WeaponInfo& wi, glm::vec3 direction, double damage);
// Utility
bool canFire(ComponentWrapper cWeapon);
//float traceRayDistance(glm::vec3 origin, glm::vec3 direction);
};
+48 -26
View File
@@ -24,36 +24,35 @@ public:
} }
virtual ~WeaponBehaviour() = default; virtual ~WeaponBehaviour() = default;
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) override virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cWeapon, double dt) override
{ {
auto weapon = getActiveWeapon(entity); auto weapon = getActiveWeapon(entity);
if (!weapon) { if (!weapon) {
return; return;
} else { } else {
UpdateWeapon(*weapon, dt); UpdateWeapon(cWeapon, *weapon, dt);
} }
} }
protected: protected:
struct WeaponInfo struct WeaponInfo
{ {
std::string WeaponComponent;
EntityWrapper Player; EntityWrapper Player;
EntityWrapper WeaponEntity; EntityWrapper WeaponEntity;
EntityWrapper FirstPersonEntity; EntityWrapper FirstPersonEntity;
EntityWrapper ThirdPersonEntity; EntityWrapper ThirdPersonEntity;
ComponentWrapper GetComponent() { return WeaponEntity[WeaponComponent]; }
}; };
IRenderer* m_Renderer; IRenderer* m_Renderer;
Octree<EntityAABB>* m_CollisionOctree; Octree<EntityAABB>* m_CollisionOctree;
std::unordered_map<EntityWrapper, WeaponInfo> m_ActiveWeapons; std::unordered_map<EntityWrapper, WeaponInfo> m_ActiveWeapons;
virtual void UpdateWeapon(WeaponInfo& wi, double dt) { } virtual void UpdateWeapon(ComponentWrapper cWeapon, WeaponInfo& wi, double dt) { }
virtual void OnPrimaryFire(WeaponInfo& wi) { } virtual void OnPrimaryFire(ComponentWrapper cWeapon, WeaponInfo& wi) { }
virtual void OnCeasePrimaryFire(WeaponInfo& wi) { } virtual void OnCeasePrimaryFire(ComponentWrapper cWeapon, WeaponInfo& wi) { }
virtual void OnReload(WeaponInfo& wi) { } virtual void OnReload(ComponentWrapper cWeapon, WeaponInfo& wi) { }
virtual bool OnInputCommand(WeaponInfo& wi, const Events::InputCommand& e) { return false; } virtual void OnHolster(ComponentWrapper cWeapon, WeaponInfo& wi) { }
virtual bool OnInputCommand(ComponentWrapper cWeapon, WeaponInfo& wi, const Events::InputCommand& e) { return false; }
private: private:
EventRelay<ETYPE, Events::InputCommand> m_EInputCommand; EventRelay<ETYPE, Events::InputCommand> m_EInputCommand;
@@ -70,15 +69,19 @@ private:
} }
// Make sure the player has this weapon // Make sure the player has this weapon
auto weapon = getWeaponComponent(player); auto cWeapon = getWeaponComponent(player);
if (!weapon) { if (!cWeapon) {
return false; return false;
} }
// Weapon selection // Weapon selection
if (e.Command == "SelectWeapon") { if (e.Command == "SelectWeapon") {
if (static_cast<ComponentInfo::EnumType>(e.Value) == static_cast<ComponentInfo::EnumType>((*weapon)["Slot"])) { if (e.Value > 0) {
selectWeapon(player); if (static_cast<ComponentInfo::EnumType>(e.Value) == static_cast<ComponentInfo::EnumType>((*cWeapon)["Slot"])) {
selectWeapon(player);
} else {
holsterWeapon(*cWeapon, player);
}
} }
} }
@@ -91,18 +94,18 @@ private:
// Fire // Fire
if (e.Command == "PrimaryFire") { if (e.Command == "PrimaryFire") {
if (e.Value > 0) { if (e.Value > 0) {
OnPrimaryFire(*activeWeapon); OnPrimaryFire(*cWeapon, *activeWeapon);
} else { } else {
OnCeasePrimaryFire(*activeWeapon); OnCeasePrimaryFire(*cWeapon, *activeWeapon);
} }
} }
// Reload // Reload
if (e.Command == "Reload" && e.Value != 0) { if (e.Command == "Reload" && e.Value != 0) {
OnReload(*activeWeapon); OnReload(*cWeapon, *activeWeapon);
} }
return OnInputCommand(*activeWeapon, e); return OnInputCommand(*cWeapon, *activeWeapon, e);
} }
boost::optional<ComponentWrapper> getWeaponComponent(EntityWrapper player) boost::optional<ComponentWrapper> getWeaponComponent(EntityWrapper player)
@@ -131,6 +134,11 @@ private:
void selectWeapon(EntityWrapper player) void selectWeapon(EntityWrapper player)
{ {
// Don't reselect weapon if it's already active
if (getActiveWeapon(player)) {
return;
}
// Find the weapon attachments matching the weapon type // Find the weapon attachments matching the weapon type
std::vector<EntityWrapper> weaponAttachments = player.ChildrenWithComponent("WeaponAttachment"); std::vector<EntityWrapper> weaponAttachments = player.ChildrenWithComponent("WeaponAttachment");
EntityWrapper firstPersonAttachment; EntityWrapper firstPersonAttachment;
@@ -152,14 +160,6 @@ private:
return; return;
} }
// Purge other weapon entities
for (auto& attachment : weaponAttachments) {
//if (attachment == firstPersonAttachment || attachment == thirdPersonAttachment) {
// continue;
//}
attachment.DeleteChildren();
}
// Spawn the weapon(s) // Spawn the weapon(s)
EntityWrapper firstPersonWeapon; EntityWrapper firstPersonWeapon;
EntityWrapper thirdPersonWeapon; EntityWrapper thirdPersonWeapon;
@@ -170,12 +170,34 @@ private:
thirdPersonWeapon = SpawnerSystem::Spawn(thirdPersonAttachment, thirdPersonAttachment); thirdPersonWeapon = SpawnerSystem::Spawn(thirdPersonAttachment, thirdPersonAttachment);
} }
m_ActiveWeapons[player].WeaponComponent = m_ComponentType;
m_ActiveWeapons[player].Player = player; m_ActiveWeapons[player].Player = player;
m_ActiveWeapons[player].WeaponEntity = player; m_ActiveWeapons[player].WeaponEntity = player;
m_ActiveWeapons[player].FirstPersonEntity = firstPersonWeapon; m_ActiveWeapons[player].FirstPersonEntity = firstPersonWeapon;
m_ActiveWeapons[player].ThirdPersonEntity = thirdPersonWeapon; m_ActiveWeapons[player].ThirdPersonEntity = thirdPersonWeapon;
} }
void holsterWeapon(ComponentWrapper cWeapon, EntityWrapper player)
{
auto activeWeapon = getActiveWeapon(player);
if (!activeWeapon) {
return;
}
WeaponInfo& wi = *activeWeapon;
// Send holster event
OnHolster(cWeapon, wi);
// Delete weapon entities
if (wi.FirstPersonEntity.Valid()) {
m_World->DeleteEntity(wi.FirstPersonEntity.ID);
}
if (wi.ThirdPersonEntity.Valid()) {
m_World->DeleteEntity(wi.ThirdPersonEntity.ID);
}
// Make weapon inactive
m_ActiveWeapons.erase(player);
}
}; };
#endif #endif
+1
View File
@@ -49,5 +49,6 @@
<xs:include schemaLocation="Components/DoubleJump.xsd"/> <xs:include schemaLocation="Components/DoubleJump.xsd"/>
<xs:include schemaLocation="Components/WeaponAttachment.xsd"/> <xs:include schemaLocation="Components/WeaponAttachment.xsd"/>
<xs:include schemaLocation="Components/DefenderWeapon.xsd"/> <xs:include schemaLocation="Components/DefenderWeapon.xsd"/>
<xs:include schemaLocation="Components/SidearmWeapon.xsd"/>
<xs:include schemaLocation="Components/CapturePointGameMode.xsd"/> <xs:include schemaLocation="Components/CapturePointGameMode.xsd"/>
</xs:schema> </xs:schema>
@@ -4,6 +4,18 @@
<xs:import schemaLocation="../Types.xsd" namespace="types"/> <xs:import schemaLocation="../Types.xsd" namespace="types"/>
<xs:include schemaLocation="../Types/WeaponSlotEnum.xsd"/> <xs:include schemaLocation="../Types/WeaponSlotEnum.xsd"/>
<xs:complexType name="WeaponStateEnum" mixed="true">
<xs:complexContent>
<xs:extension base="t:enum">
<xs:choice>
<xs:element name="Idle" type="t:int" fixed="0" minOccurs="0"/>
<xs:element name="Firing" type="t:int" fixed="1" minOccurs="0"/>
<xs:element name="Reloading" type="t:int" fixed="2" minOccurs="0"/>
</xs:choice>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="DefenderWeapon"> <xs:element name="DefenderWeapon">
<xs:complexType> <xs:complexType>
<xs:all> <xs:all>
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<SidearmWeapon xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="SidearmWeapon.xsd">
<MagazineAmmo>16</MagazineAmmo>
<MagazineSize>16</MagazineSize>
<BaseDamage>20</BaseDamage>
<RPM>120</RPM>
<ViewPunch>0.01</ViewPunch>
<ReloadTime>0.5</ReloadTime>
<Slot><Secondary/></Slot>
<TriggerHeld>false</TriggerHeld>
<FireCooldown>0</FireCooldown>
<IsReloading>false</IsReloading>
<ReloadTimer>0</ReloadTimer>
</SidearmWeapon>
@@ -0,0 +1,48 @@
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:t="types">
<xs:import schemaLocation="../Types.xsd" namespace="types"/>
<xs:include schemaLocation="../Types/WeaponSlotEnum.xsd"/>
<xs:complexType name="WeaponStateEnum" mixed="true">
<xs:complexContent>
<xs:extension base="t:enum">
<xs:choice>
<xs:element name="Idle" type="t:int" fixed="0" minOccurs="0"/>
<xs:element name="Firing" type="t:int" fixed="1" minOccurs="0"/>
<xs:element name="Reloading" type="t:int" fixed="2" minOccurs="0"/>
</xs:choice>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="SidearmWeapon">
<xs:complexType>
<xs:all>
<xs:element name="MagazineAmmo" type="t:int" minOccurs="0">
<xs:annotation><xs:documentation>Ammo currently loaded into the magazine</xs:documentation></xs:annotation>
</xs:element>
<xs:element name="MagazineSize" type="t:int" minOccurs="0">
<xs:annotation><xs:documentation>Max number of rounds in a magazine</xs:documentation></xs:annotation>
</xs:element>
<xs:element name="BaseDamage" type="t:double" minOccurs="0">
<xs:annotation><xs:documentation>Damage dealt if all shotgun pellets hit</xs:documentation></xs:annotation>
</xs:element>
<xs:element name="RPM" type="t:double" minOccurs="0">
<xs:annotation><xs:documentation>Rate of fire in rounds per minute</xs:documentation></xs:annotation>
</xs:element>
<xs:element name="ViewPunch" type="t:float" minOccurs="0">
<xs:annotation><xs:documentation>View punch in radians for each shell fired</xs:documentation></xs:annotation>
</xs:element>
<xs:element name="ReloadTime" type="t:double" minOccurs="0">
<xs:annotation><xs:documentation>Time it takes to load ONE SHELL into the weapon in seconds</xs:documentation></xs:annotation>
</xs:element>
<xs:element name="Slot" type="WeaponSlotEnum" minOccurs="0"/>
<xs:element name="TriggerHeld" type="t:bool" minOccurs="0"/>
<xs:element name="FireCooldown" type="t:double" minOccurs="0"/>
<xs:element name="IsReloading" type="t:bool" minOccurs="0"/>
<xs:element name="ReloadTimer" type="t:double" minOccurs="0"/>
</xs:all>
</xs:complexType>
</xs:element>
</xs:schema>
+2 -7
View File
@@ -6,11 +6,6 @@
<Origin X="0" Y="0.772000015" Z="0"/> <Origin X="0" Y="0.772000015" Z="0"/>
<Size X="1" Y="1.60000002" Z="1"/> <Size X="1" Y="1.60000002" Z="1"/>
</c:AABB> </c:AABB>
<c:AssaultWeapon>
<Slot>
<Secondary/>
</Slot>
</c:AssaultWeapon>
<c:Collidable/> <c:Collidable/>
<c:DefenderWeapon> <c:DefenderWeapon>
<TimeSinceLastFire>1.6944730461160304</TimeSinceLastFire> <TimeSinceLastFire>1.6944730461160304</TimeSinceLastFire>
@@ -399,11 +394,11 @@
<Entity name="SecondaryAttachment"> <Entity name="SecondaryAttachment">
<Components> <Components>
<c:Spawner> <c:Spawner>
<EntityFile>Schema/Entities/AssaultWeaponView.xml</EntityFile> <EntityFile>Schema/Entities/SidearmWeaponView.xml</EntityFile>
</c:Spawner> </c:Spawner>
<c:Transform/> <c:Transform/>
<c:WeaponAttachment> <c:WeaponAttachment>
<Weapon>AssaultWeapon</Weapon> <Weapon>SidearmWeapon</Weapon>
</c:WeaponAttachment> </c:WeaponAttachment>
</Components> </Components>
<Children/> <Children/>
+1
View File
@@ -52,6 +52,7 @@
<xs:element ref="c:Button" minOccurs="0"/> <xs:element ref="c:Button" minOccurs="0"/>
<xs:element ref="c:WeaponAttachment" minOccurs="0"/> <xs:element ref="c:WeaponAttachment" minOccurs="0"/>
<xs:element ref="c:DefenderWeapon" minOccurs="0"/> <xs:element ref="c:DefenderWeapon" minOccurs="0"/>
<xs:element ref="c:SidearmWeapon" minOccurs="0"/>
</xs:all> </xs:all>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
+1 -1
View File
@@ -17,7 +17,7 @@ void Renderer::Initialize()
m_TextPass->Initialize(); m_TextPass->Initialize();
/* m_ScreenQuad = ResourceManager::Load<Model>("Models/Core/ScreenQuad.obj"); /* m_ScreenQuad = ResourceManager::Load<Model>("Models/Core/ScreenQuad.obj");
m_UnitQuad = ResourceManager::Load<Model>("Models/Core/UnitQuad.obj"); m_UnitQuad = ResourceManager::Load<Model>(sModels/Core/UnitQuad.obj");
m_UnitSphere = ResourceManager::Load<Model>("Models/Core/UnitSphere.obj");*/ m_UnitSphere = ResourceManager::Load<Model>("Models/Core/UnitSphere.obj");*/
m_ImGuiRenderPass = new ImGuiRenderPass(this, m_EventBroker); m_ImGuiRenderPass = new ImGuiRenderPass(this, m_EventBroker);
@@ -6,36 +6,32 @@ void DefenderWeaponBehaviour::UpdateComponent(EntityWrapper& entity, ComponentWr
WeaponBehaviour::UpdateComponent(entity, cWeapon, dt); WeaponBehaviour::UpdateComponent(entity, cWeapon, dt);
} }
void DefenderWeaponBehaviour::UpdateWeapon(WeaponInfo& wi, double dt) void DefenderWeaponBehaviour::UpdateWeapon(ComponentWrapper cWeapon, WeaponInfo& wi, double dt)
{ {
ComponentWrapper cWeapon = wi.GetComponent();
bool isFiring = cWeapon["IsFiring"]; bool isFiring = cWeapon["IsFiring"];
bool cooldownPassed = (double)cWeapon["TimeSinceLastFire"] >= (60.0 / (double)cWeapon["RPM"]); bool cooldownPassed = (double)cWeapon["TimeSinceLastFire"] >= (60.0 / (double)cWeapon["RPM"]);
bool isNotShielding = wi.Player.ChildrenWithComponent("Shield").size() == 0; bool isNotShielding = wi.Player.ChildrenWithComponent("Shield").size() == 0;
if (isFiring && cooldownPassed && isNotShielding) { if (isFiring && cooldownPassed && isNotShielding) {
fireShell(wi); fireShell(cWeapon, wi);
} }
} }
void DefenderWeaponBehaviour::OnPrimaryFire(WeaponInfo& wi) void DefenderWeaponBehaviour::OnPrimaryFire(ComponentWrapper cWeapon, WeaponInfo& wi)
{ {
ComponentWrapper cWeapon = wi.GetComponent();
cWeapon["IsFiring"] = true; cWeapon["IsFiring"] = true;
bool cooldownPassed = (double)cWeapon["TimeSinceLastFire"] >= (60.0 / (double)cWeapon["RPM"]); bool cooldownPassed = (double)cWeapon["TimeSinceLastFire"] >= (60.0 / (double)cWeapon["RPM"]);
bool isNotShielding = wi.Player.ChildrenWithComponent("Shield").size() == 0; bool isNotShielding = wi.Player.ChildrenWithComponent("Shield").size() == 0;
if (cooldownPassed && isNotShielding) { if (cooldownPassed && isNotShielding) {
fireShell(wi); fireShell(cWeapon, wi);
} }
} }
void DefenderWeaponBehaviour::OnCeasePrimaryFire(WeaponInfo& wi) void DefenderWeaponBehaviour::OnCeasePrimaryFire(ComponentWrapper cWeapon, WeaponInfo& wi)
{ {
ComponentWrapper cWeapon = wi.GetComponent();
cWeapon["IsFiring"] = false; cWeapon["IsFiring"] = false;
} }
bool DefenderWeaponBehaviour::OnInputCommand(WeaponInfo& wi, const Events::InputCommand& e) bool DefenderWeaponBehaviour::OnInputCommand(ComponentWrapper cWeapon, WeaponInfo& wi, const Events::InputCommand& e)
{ {
if (e.Command == "SpecialAbility" && IsServer) { if (e.Command == "SpecialAbility" && IsServer) {
EntityWrapper attachment = wi.Player.FirstChildByName("ShieldAttachment"); EntityWrapper attachment = wi.Player.FirstChildByName("ShieldAttachment");
@@ -57,10 +53,8 @@ bool DefenderWeaponBehaviour::OnSetCamera(const Events::SetCamera& e)
return true; return true;
} }
void DefenderWeaponBehaviour::fireShell(WeaponInfo& wi) void DefenderWeaponBehaviour::fireShell(ComponentWrapper cWeapon, WeaponInfo& wi)
{ {
ComponentWrapper cWeapon = wi.GetComponent();
cWeapon["TimeSinceLastFire"] = 0.0; cWeapon["TimeSinceLastFire"] = 0.0;
int numPellets = cWeapon["NumPellets"]; int numPellets = cWeapon["NumPellets"];
float spreadAngle = cWeapon["SpreadAngle"]; float spreadAngle = cWeapon["SpreadAngle"];
@@ -95,13 +89,13 @@ void DefenderWeaponBehaviour::fireShell(WeaponInfo& wi)
orientation.x += angles.x; orientation.x += angles.x;
orientation.y += angles.y; orientation.y += angles.y;
glm::vec3 trajectory = direction * distance; glm::vec3 trajectory = direction * distance;
dealDamage(wi, direction, pelletDamage); dealDamage(cWeapon, wi, direction, pelletDamage);
} }
} }
} }
void DefenderWeaponBehaviour::dealDamage(WeaponInfo& wi, glm::vec3 direction, double damage) void DefenderWeaponBehaviour::dealDamage(ComponentWrapper cWeapon, WeaponInfo& wi, glm::vec3 direction, double damage)
{ {
// Only deal damage client side // Only deal damage client side
if (!IsClient) { if (!IsClient) {
@@ -0,0 +1,58 @@
#include "Systems/Weapon/SidearmWeaponBehaviour.h"
void SidearmWeaponBehaviour::UpdateComponent(EntityWrapper& entity, ComponentWrapper& cWeapon, double dt)
{
double& cooldown = cWeapon["FireCooldown"];
if (cooldown > 0) {
cooldown -= dt;
if (cooldown < 0) {
cooldown = 0;
}
}
WeaponBehaviour::UpdateComponent(entity, cWeapon, dt);
}
void SidearmWeaponBehaviour::UpdateWeapon(ComponentWrapper cWeapon, WeaponInfo& wi, double dt)
{
if (canFire(cWeapon)) {
fireBullet(cWeapon, wi);
}
}
void SidearmWeaponBehaviour::OnPrimaryFire(ComponentWrapper cWeapon, WeaponInfo& wi)
{
cWeapon["TriggerHeld"] = true;
if (canFire(cWeapon)) {
fireBullet(cWeapon, wi);
}
}
void SidearmWeaponBehaviour::OnCeasePrimaryFire(ComponentWrapper cWeapon, WeaponInfo& wi)
{
cWeapon["TriggerHeld"] = false;
}
void SidearmWeaponBehaviour::OnHolster(ComponentWrapper cWeapon, WeaponInfo& wi)
{
// Make sure the trigger is released if weapon is holstered while firing
cWeapon["TriggerHeld"] = false;
// Cancel any reload
cWeapon["IsReloading"] = false;
cWeapon["ReloadTimer"] = 0.0;
LOG_DEBUG("HOLSTER");
}
void SidearmWeaponBehaviour::fireBullet(ComponentWrapper cWeapon, WeaponInfo& wi)
{
}
bool SidearmWeaponBehaviour::canFire(ComponentWrapper cWeapon)
{
bool triggerHeld = cWeapon["TriggerHeld"];
double& cooldown = cWeapon["FireCooldown"];
// TODO: Ammo checks
return triggerHeld && cooldown <= 0.0;
}