Skip to content
10 changes: 0 additions & 10 deletions src/Effects/Player/PlayerCrippleBoxEffects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,6 @@
#include "Registry.h"
#include "Helpers/Utils.h"

void ZUnlimitedAmmoEffect::Start()
{
auto s_rCripple = GetCrippleBox();
s_rCripple.m_pInterfaceRef->m_bLimitedAmmo = false;

ActivateCrippleBox();
}

REGISTER_CHAOS_EFFECT(ZUnlimitedAmmoEffect);

void ZPlayerPacifistEffect::Start()
{
auto s_rCripple = GetCrippleBox();
Expand Down
11 changes: 0 additions & 11 deletions src/Effects/Player/PlayerCrippleBoxEffects.h
Original file line number Diff line number Diff line change
@@ -1,17 +1,6 @@
#pragma once
#include "Effects/Base/ZPlayerCrippleBoxEffectBase.h"

class ZUnlimitedAmmoEffect : public ZPlayerCrippleBoxEffectBase
{
public:
void Start() override;

std::string GetDisplayName(const bool p_bVoting) const override
{
return "Unlimited Ammo";
}
};

class ZPlayerPacifistEffect : public ZPlayerCrippleBoxEffectBase
{
public:
Expand Down
141 changes: 141 additions & 0 deletions src/Effects/Player/ZMagazineUpdateModifierEffect.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#include "ZMagazineUpdateModifierEffect.h"

#include "Registry.h"
#include "Helpers/Utils.h"
#include "Helpers/PlayerUtils.h"
Comment thread
shadow578 marked this conversation as resolved.

void ZMagazineUpdateModifierEffect::OnModInitialized()
{
if (Hooks::ZHM5ItemWeapon_SetBulletsInMagazine)
{
Hooks::ZHM5ItemWeapon_SetBulletsInMagazine->AddDetour(this, &ZMagazineUpdateModifierEffect::ZHM5ItemWeapon_SetBulletsInMagazine);
}
}

void ZMagazineUpdateModifierEffect::OnModUnload()
{
if (Hooks::ZHM5ItemWeapon_SetBulletsInMagazine)
{
Hooks::ZHM5ItemWeapon_SetBulletsInMagazine->RemoveDetour(&ZMagazineUpdateModifierEffect::ZHM5ItemWeapon_SetBulletsInMagazine);
}
}

bool ZMagazineUpdateModifierEffect::Available() const
{
return IChaosEffect::Available() && Hooks::ZHM5ItemWeapon_SetBulletsInMagazine != nullptr;
}

bool ZMagazineUpdateModifierEffect::IsCompatibleWith(const IChaosEffect* p_pOtherEffect) const
{
return IChaosEffect::IsCompatibleWith(p_pOtherEffect)
&& !Utils::IsInstanceOf<ZMagazineUpdateModifierEffect>(p_pOtherEffect);
}

void ZMagazineUpdateModifierEffect::Start()
{
m_bActive = true;
}

void ZMagazineUpdateModifierEffect::Stop()
{
m_bActive = false;
}

DEFINE_BASE_CLASS_DETOUR(
ZMagazineUpdateModifierEffect,
void,
ZHM5ItemWeapon_SetBulletsInMagazine,
MAKE_FORWARD_PARAMS(th, p_nBullets),
IFirearm* th,
int32_t p_nBullets
)
{
if (!m_bActive)
{
return {HookAction::Continue()};
}

ZHM5ItemWeapon* s_pWeapon = static_cast<ZHM5ItemWeapon*>(th);
if (!s_pWeapon || !s_pWeapon->m_pOwner)
{
return {HookAction::Continue()};
}

// check if we should apply this effect based on weapon owner
// only needed if not applied to all
if (m_eApplyTo != EApplyTo::All)
{
// Note: GetLocalPlayer *may* technically return an empty ref, but in practice this should not happen
// all following code is written such that even an empty ref does not cause crashes though
const auto s_rPlayer = Utils::GetLocalPlayer();
const auto s_bOwnedByPlayer = s_pWeapon->m_pOwner == s_rPlayer.m_entityRef;

// player owns and effect targets actor only?
if (s_bOwnedByPlayer && m_eApplyTo == EApplyTo::Actor)
{
return {HookAction::Continue()};
}

// actor owns and effect targets player only?
if (!s_bOwnedByPlayer && m_eApplyTo == EApplyTo::Player)
{
return {HookAction::Continue()};
}
}

// effect should apply to weapon holder, do the thing
switch (m_eKind)
{
case EKind::UnlimitedMags:
p_nBullets = s_pWeapon->GetMagazineCapacity();
s_pWeapon->m_nBulletsFired = 0;
break;
case EKind::EmptyMags:
p_nBullets = 0;
s_pWeapon->m_nBulletsFired = s_pWeapon->GetMagazineCapacity();
break;
case EKind::SingleBulletMags:
if (p_nBullets > 1)
{
p_nBullets = 1;
s_pWeapon->m_nBulletsFired = std::max(0, s_pWeapon->GetMagazineCapacity() - 1);
}
break;
}

p_Hook->CallOriginal(th, p_nBullets);
return {HookAction::Return()};
}

REGISTER_CHAOS_EFFECT_PARAM(
UnlimitedMags,
ZMagazineUpdateModifierEffect,
"UnlimitedMags",
"Unlimited Ammo",
ZMagazineUpdateModifierEffect::EApplyTo::Player,
ZMagazineUpdateModifierEffect::EKind::UnlimitedMags
);
REGISTER_CHAOS_EFFECT_PARAM(
EmptyMagsPlayer,
ZMagazineUpdateModifierEffect,
"EmptyMagsPlayer",
"Oops, No Bullets!",
ZMagazineUpdateModifierEffect::EApplyTo::Player,
ZMagazineUpdateModifierEffect::EKind::EmptyMags
);
REGISTER_CHAOS_EFFECT_PARAM(
EmptyMagsActors,
ZMagazineUpdateModifierEffect,
"EmptyMagsActors",
"Security Budget Cuts",
ZMagazineUpdateModifierEffect::EApplyTo::Actor,
ZMagazineUpdateModifierEffect::EKind::EmptyMags
);
REGISTER_CHAOS_EFFECT_PARAM(
SingleUseMags,
ZMagazineUpdateModifierEffect,
"SingleUseMags",
"Single Shot",
ZMagazineUpdateModifierEffect::EApplyTo::All,
ZMagazineUpdateModifierEffect::EKind::SingleBulletMags
);
82 changes: 82 additions & 0 deletions src/Effects/Player/ZMagazineUpdateModifierEffect.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#pragma once
#include "IChaosEffect.h"

#include <Glacier/ZItem.h>
#include <Glacier/ZEntity.h>
#include <Glacier/ZMath.h>

#include "Helpers/HookingHelpers.h"

class ZMagazineUpdateModifierEffect : public virtual IChaosEffect // virtual inheritance to allow for ZPlayerJuggernautEffect
{
public:
enum class EApplyTo
{
Player,
Actor,
All // Actors + Player
};

enum class EKind
{
UnlimitedMags,
EmptyMags,
SingleBulletMags
};

ZMagazineUpdateModifierEffect(
const std::string p_sNameSuffix,
const std::string s_sDisplayName,
const EApplyTo p_eApplyTo,
const EKind p_eKind
)
: m_sNameSuffix(p_sNameSuffix),
m_sDisplayName(s_sDisplayName),
m_eApplyTo(p_eApplyTo),
m_eKind(p_eKind)
{
ADD_BASE_CLASS_DETOUR_INSTANCE();
}

~ZMagazineUpdateModifierEffect()
{
REMOVE_BASE_CLASS_DETOUR_INSTANCE();
}

void OnModInitialized() override;
void OnModUnload() override;
bool Available() const override;
bool IsCompatibleWith(const IChaosEffect* p_pOtherEffect) const override;

void Start() override;
void Stop() override;

std::string GetName() const override
{
return IChaosEffect::GetName() + "_" + m_sNameSuffix;
}

std::string GetDisplayName(const bool p_bVoting) const override
{
return m_sDisplayName;
}

private:
std::string m_sNameSuffix;
std::string m_sDisplayName;
EApplyTo m_eApplyTo;
EKind m_eKind;

private:
bool m_bActive = false;

DECLARE_BASE_CLASS_INSTANCES_HELPER(ZMagazineUpdateModifierEffect);

DECLARE_BASE_CLASS_DETOUR(
ZMagazineUpdateModifierEffect,
void,
ZHM5ItemWeapon_SetBulletsInMagazine,
IFirearm* th,
int32_t p_nBullets
);
};
5 changes: 5 additions & 0 deletions src/Effects/Player/ZPlayerOverpoweredEffect.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#include "ZPlayerOverpoweredEffect.h"

#include "Registry.h"

REGISTER_CHAOS_EFFECT(ZPlayerOverpoweredEffect);
93 changes: 93 additions & 0 deletions src/Effects/Player/ZPlayerOverpoweredEffect.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#pragma once
#include "Effects/Player/ZRecoilModifierEffect.h"
#include "Effects/Player/ZMagazineUpdateModifierEffect.h"
#include "Effects/Player/ZWeaponPrecisionOverrideEffect.h"
#include "Effects/Player/ZWeaponRapidFireEffect.h"

// this is such a stupid effect lol
// this effect combines four other effects to create a "juggernaut" mode for the player.
// you can probably see how stupidly overpowered this is :P
// Note: some of the sub-effects define name & display name via constructor parameters (for use with REGISTER_CHAOS_EFFECT_PARAM).
// here, we simply pass dummy values, as we override the methods anyway.
class ZPlayerOverpoweredEffect : public ZRecoilModifierEffect, public ZMagazineUpdateModifierEffect, public ZWeaponPrecisionOverrideEffect, public ZWeaponRapidFireEffect
{
public:
ZPlayerOverpoweredEffect()
: ZRecoilModifierEffect("op", "", SVector2(0.f, 0.f)),
ZMagazineUpdateModifierEffect("op", "", EApplyTo::Player, EKind::UnlimitedMags),
ZWeaponPrecisionOverrideEffect("op", "", 1.f),
ZWeaponRapidFireEffect()
{
}

void OnModInitialized() override
{
ZRecoilModifierEffect::OnModInitialized();
ZMagazineUpdateModifierEffect::OnModInitialized();
ZWeaponPrecisionOverrideEffect::OnModInitialized();
ZWeaponRapidFireEffect::OnModInitialized();
}

void OnModUnload() override
{
ZRecoilModifierEffect::OnModUnload();
ZMagazineUpdateModifierEffect::OnModUnload();
ZWeaponPrecisionOverrideEffect::OnModUnload();
ZWeaponRapidFireEffect::OnModUnload();
}

bool Available() const override
{
return ZRecoilModifierEffect::Available()
&& ZMagazineUpdateModifierEffect::Available()
&& ZWeaponPrecisionOverrideEffect::Available()
&& ZWeaponRapidFireEffect::Available();
}

bool IsCompatibleWith(const IChaosEffect* p_pOtherEffect) const override
{
return ZRecoilModifierEffect::IsCompatibleWith(p_pOtherEffect)
&& ZMagazineUpdateModifierEffect::IsCompatibleWith(p_pOtherEffect)
&& ZWeaponPrecisionOverrideEffect::IsCompatibleWith(p_pOtherEffect)
&& ZWeaponRapidFireEffect::IsCompatibleWith(p_pOtherEffect);
}

void OnDrawDebugUI() override
{
ZRecoilModifierEffect::OnDrawDebugUI();
ZMagazineUpdateModifierEffect::OnDrawDebugUI();
ZWeaponPrecisionOverrideEffect::OnDrawDebugUI();
ZWeaponRapidFireEffect::OnDrawDebugUI();
}

void Start() override
{
ZRecoilModifierEffect::Start();
ZMagazineUpdateModifierEffect::Start();
ZWeaponPrecisionOverrideEffect::Start();
ZWeaponRapidFireEffect::Start();
}

void Stop() override
{
ZRecoilModifierEffect::Stop();
ZMagazineUpdateModifierEffect::Stop();
ZWeaponPrecisionOverrideEffect::Stop();
ZWeaponRapidFireEffect::Stop();
}

std::string GetName() const override
{
return IChaosEffect::GetName();
}

std::string GetDisplayName(const bool p_bVoting) const override
{
return "Unfair Advantage"; // TODO name kinda sucks thb
Comment thread
shadow578 marked this conversation as resolved.
}

EDuration GetDuration() const override
{
return EDuration::Short;
}
};
Loading
Loading