<commit_before>#include "Runtime/Weapon/CGunWeapon.hpp"

#include <algorithm>
#include <array>

#include "Runtime/CDependencyGroup.hpp"
#include "Runtime/CGameState.hpp"
#include "Runtime/CSimplePool.hpp"
#include "Runtime/GameGlobalObjects.hpp"
#include "Runtime/Graphics/CSkinnedModel.hpp"
#include "Runtime/Graphics/CVertexMorphEffect.hpp"
#include "Runtime/Weapon/CEnergyProjectile.hpp"
#include "Runtime/Weapon/CWeapon.hpp"

namespace urde {
namespace {
constexpr std::array skBeamXferNames{
    "PowerXfer", "IceXfer", "WaveXfer", "PlasmaXfer", "PhazonXfer",
};

constexpr std::array skSuitArmNames{
    "PowerArm", "GravityArm", "VariaArm", "PhazonArm", "FusionArm", "FusionArmG", "FusionArmV", "FusionArmP",
};

constexpr std::array skMuzzleNames{
    "PowerMuzzle", "PowerCharge",  "IceMuzzle",    "IceCharge",    "PowerMuzzle",
    "WaveCharge",  "PlasmaMuzzle", "PlasmaCharge", "PhazonMuzzle", "EmptyMuzzle",
};

constexpr std::array skFrozenNames{
    "powerFrozen", "Ice2nd_2",     "iceFrozen", "Ice2nd_2",  "waveFrozen",
    "Ice2nd_2",    "plasmaFrozen", "Ice2nd_2",  "iceFrozen", "Ice2nd_2",
};

constexpr std::array skDependencyNames{
    "Power_DGRP", "Ice_DGRP", "Wave_DGRP", "Plasma_DGRP", "Phazon_DGRP",
};

constexpr std::array skAnimDependencyNames{
    "Power_Anim_DGRP", "Ice_Anim_DGRP", "Wave_Anim_DGRP", "Plasma_Anim_DGRP", "Phazon_Anim_DGRP",
};

constexpr std::array skAnimTypeList{
    0, 4, 1, 2, 3, 5, 6, 7, 8, 9, 10,
};

CPlayerState::EBeamId GetWeaponIndex(EWeaponType type) {
  if (type == EWeaponType::Power)
    return CPlayerState::EBeamId::Power;
  else if (type == EWeaponType::Ice)
    return CPlayerState::EBeamId::Ice;
  else if (type == EWeaponType::Wave)
    return CPlayerState::EBeamId::Wave;
  else if (type == EWeaponType::Plasma)
    return CPlayerState::EBeamId::Plasma;
  else if (type == EWeaponType::Phazon)
    return CPlayerState::EBeamId::Phazon;
  return CPlayerState::EBeamId::Power;
}
} // Anonymous namespace

CGunWeapon::CGunWeapon(CAssetId ancsId, EWeaponType type, TUniqueId playerId, EMaterialTypes playerMaterial,
                       const zeus::CVector3f& scale)
: x4_scale(scale)
, x104_gunCharacter(g_SimplePool->GetObj(SObjectTag{FOURCC('ANCS'), ancsId}))
, x13c_armCharacter(g_SimplePool->GetObj(skSuitArmNames[0]))
, x160_xferEffect(g_SimplePool->GetObj(skBeamXferNames[size_t(GetWeaponIndex(type))]))
, x1c0_weaponType(type)
, x1c4_playerId(playerId)
, x1c8_playerMaterial(playerMaterial)
, x200_beamId(GetWeaponIndex(type))
, x20c_shaderIdx(u32(x200_beamId))
, x214_ancsId(ancsId) {
  AllocResPools(x200_beamId);
  BuildDependencyList(x200_beamId);
}

void CGunWeapon::AllocResPools(CPlayerState::EBeamId beam) {
  const CAssetId* const wPair = g_tweakGunRes->GetWeaponPair(beam);
  const char* const* muzzleNames = &skMuzzleNames[size_t(beam) * 2];
  const char* const* frozenNames = &skFrozenNames[size_t(beam) * 2];

  for (size_t i = 0; i < x16c_muzzleEffects.capacity(); ++i) {
    x16c_muzzleEffects.push_back(g_SimplePool->GetObj(muzzleNames[i]));
    x144_weapons.push_back(g_SimplePool->GetObj(SObjectTag{FOURCC('WPSC'), wPair[i]}));
    x188_frozenEffects.push_back(g_SimplePool->GetObj(frozenNames[i]));
  }
}

void CGunWeapon::FreeResPools() {
  x160_xferEffect.Unlock();

  for (size_t i = 0; i < x16c_muzzleEffects.size(); ++i) {
    x16c_muzzleEffects[i].Unlock();
    x144_weapons[i].Unlock();
    x188_frozenEffects[i].Unlock();
  }

  x10c_anims.clear();
  x1a4_muzzleGenerators.clear();
  x1d0_velInfo.Clear();
}

void CGunWeapon::FillTokenVector(const std::vector<SObjectTag>& tags, std::vector<CToken>& objects) {
  for (const SObjectTag& tag : tags)
    objects.push_back(g_SimplePool->GetObj(tag));
}

void CGunWeapon::BuildDependencyList(CPlayerState::EBeamId beam) {
  TLockedToken<CDependencyGroup> deps = g_SimplePool->GetObj(skDependencyNames[size_t(beam)]);
  TLockedToken<CDependencyGroup> animDeps = g_SimplePool->GetObj(skAnimDependencyNames[size_t(beam)]);
  x12c_deps.reserve(deps->GetObjectTagVector().size() + animDeps->GetObjectTagVector().size());
  FillTokenVector(deps->GetObjectTagVector(), x12c_deps);
  FillTokenVector(animDeps->GetObjectTagVector(), x12c_deps);
}

void CGunWeapon::AsyncLoadSuitArm(CStateManager& mgr) {

  xb0_suitArmModelData = std::nullopt;
  x13c_armCharacter = g_SimplePool->GetObj(skSuitArmNames[size_t(NWeaponTypes::get_current_suit(mgr))]);
  x13c_armCharacter.Lock();
  x218_28_suitArmLocked = true;
}

void CGunWeapon::Reset(CStateManager& mgr) {
  if (!x218_26_loaded)
    return;

  x10_solidModelData->GetAnimationData()->EnableLooping(false);
  if (x218_25_enableCharge)
    x218_25_enableCharge = false;
  else
    x100_gunController->Reset();
}

void CGunWeapon::PlayAnim(NWeaponTypes::EGunAnimType type, bool loop) {
  if (!x218_26_loaded || type < NWeaponTypes::EGunAnimType::BasePosition || type > NWeaponTypes::EGunAnimType::ToBeam) {
    return;
  }

  x10_solidModelData->GetAnimationData()->EnableLooping(loop);
  const CAnimPlaybackParms parms(skAnimTypeList[size_t(type)], -1, 1.f, true);
  x10_solidModelData->GetAnimationData()->SetAnimation(parms, false);
}

void CGunWeapon::PreRenderGunFx(const CStateManager& mgr, const zeus::CTransform& xf) {
  // Empty
}

void CGunWeapon::PostRenderGunFx(const CStateManager& mgr, const zeus::CTransform& xf) {
  if (x218_26_loaded && x1b8_frozenGenerator && x204_frozenEffect != EFrozenFxType::None)
    x1b8_frozenGenerator->Render();
}

void CGunWeapon::UpdateGunFx(bool shotSmoke, float dt, const CStateManager& mgr, const zeus::CTransform& xf) {
  if (x218_26_loaded && x204_frozenEffect != EFrozenFxType::None) {
    if (x204_frozenEffect == EFrozenFxType::Thawed) {
      if (x1b8_frozenGenerator->IsSystemDeletable()) {
        x204_frozenEffect = EFrozenFxType::None;
        x1b8_frozenGenerator.reset();
      } else {
        x1b8_frozenGenerator->SetTranslation(xf.origin);
        x1b8_frozenGenerator->SetOrientation(xf.getRotation());
      }
    } else {
      x1b8_frozenGenerator->SetGlobalOrientAndTrans(xf);
    }
    if (x1b8_frozenGenerator)
      x1b8_frozenGenerator->Update(dt);
  }
}

const std::array<s32, 2> CGunWeapon::skShootAnim{4, 3};

void CGunWeapon::Fire(bool underwater, float dt, EChargeState chargeState, const zeus::CTransform& xf,
                      CStateManager& mgr, TUniqueId homingTarget, float chargeFactor1, float chargeFactor2) {
  CDamageInfo dInfo = GetDamageInfo(mgr, chargeState, chargeFactor1);
  zeus::CVector3f scale(chargeState == EChargeState::Normal ? 1.f : chargeFactor2);
  bool partialCharge = chargeState == EChargeState::Normal ? false : !zeus::close_enough(chargeFactor1, 1.f);
  EProjectileAttrib attribs = EProjectileAttrib::ArmCannon;
  if (partialCharge)
    attribs |= EProjectileAttrib::PartialCharge;
  if (chargeState == EChargeState::Charged)
    attribs |= EProjectileAttrib::Charged;

  CEnergyProjectile* proj = new CEnergyProjectile(
      true, x144_weapons[int(chargeState)], x1c0_weaponType, xf, x1c8_playerMaterial, dInfo, mgr.AllocateUniqueId(),
      kInvalidAreaId, x1c4_playerId, homingTarget, attribs, underwater, scale, {}, -1, false);
  mgr.AddObject(proj);
  proj->Think(dt, mgr);

  if (chargeState == EChargeState::Charged) {
    x218_25_enableCharge = true;
    mgr.GetCameraManager()->AddCameraShaker(CCameraShakeData::skChargedShotCameraShakeData, false);
  }

  x10_solidModelData->GetAnimationData()->EnableLooping(false);
  CAnimPlaybackParms parms(skShootAnim[int(chargeState)], -1, 1.f, true);
  x10_solidModelData->GetAnimationData()->SetAnimation(parms, false);
}

void CGunWeapon::EnableFx(bool enable) {
  // Empty
}

void CGunWeapon::EnableSecondaryFx(ESecondaryFxType type) { x1cc_enabledSecondaryEffect = type; }

void CGunWeapon::EnableFrozenEffect(EFrozenFxType type) {
  switch (type) {
  case EFrozenFxType::Thawed:
    if (x204_frozenEffect == EFrozenFxType::Thawed)
      break;
    x1b8_frozenGenerator = std::make_unique<CElementGen>(x188_frozenEffects[1]);
    x1b8_frozenGenerator->SetGlobalScale(x4_scale);
    break;
  case EFrozenFxType::Frozen:
    if (x204_frozenEffect == EFrozenFxType::Frozen)
      break;
    x1b8_frozenGenerator = std::make_unique<CElementGen>(x188_frozenEffects[0]);
    x1b8_frozenGenerator->SetGlobalScale(x4_scale);
    break;
  default:
    break;
  }
  x204_frozenEffect = type;
}

void CGunWeapon::ActivateCharge(bool enable, bool resetEffect) {
  x1a4_muzzleGenerators[x208_muzzleEffectIdx]->SetParticleEmission(false);
  x208_muzzleEffectIdx = u32(enable);
  if (enable || resetEffect) {
    x1a4_muzzleGenerators[x208_muzzleEffectIdx] =
        std::make_unique<CElementGen>(x16c_muzzleEffects[x208_muzzleEffectIdx]);
  }
}

void CGunWeapon::Touch(const CStateManager& mgr) {
  if (x10_solidModelData) {
    x10_solidModelData->Touch(mgr, x20c_shaderIdx);
    if (xb0_suitArmModelData)
      xb0_suitArmModelData->Touch(mgr, 0);
  }
}

void CGunWeapon::TouchHolo(const CStateManager& mgr) {
  if (x60_holoModelData)
    x60_holoModelData->Touch(mgr, 0);
}

void CGunWeapon::PointGenerator(void* ctx, const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn) {
  reinterpret_cast<CRainSplashGenerator*>(ctx)->GeneratePoints(vn);
}

void CGunWeapon::Draw(bool drawSuitArm, const CStateManager& mgr, const zeus::CTransform& xf, const CModelFlags& flags,
                      const CActorLights* lights) const {
  if (!x218_26_loaded)
    return;

  zeus::CTransform armXf = xf * x10_solidModelData->GetScaledLocatorTransform("elbow");

  if (x1bc_rainSplashGenerator && x1bc_rainSplashGenerator->IsRaining())
    CSkinnedModel::SetPointGeneratorFunc(x1bc_rainSplashGenerator, PointGenerator);

  if (mgr.GetThermalDrawFlag() == EThermalDrawFlag::Hot && x200_beamId != CPlayerState::EBeamId::Ice) {
    /* Hot Draw */
    zeus::CColor mulColor(flags.x4_color.a(), flags.x4_color.a());
    zeus::CColor addColor(0.25f, 0.25f);
    if (x218_29_drawHologram) {
      DrawHologram(mgr, xf, flags);
    } else {
      CModelFlags useFlags(0, 0, 3, zeus::skWhite);
      x10_solidModelData->RenderThermal(xf, mulColor, addColor, useFlags);
    }

    if (drawSuitArm && xb0_suitArmModelData) {
      CModelFlags useFlags(0, 0, 3, zeus::skWhite);
      xb0_suitArmModelData->RenderThermal(xf, mulColor, addColor, useFlags);
    }
  } else {
    /* Cold Draw */
    if (mgr.GetPlayerState()->GetCurrentVisor() != CPlayerState::EPlayerVisor::XRay && !x218_29_drawHologram) {
      CModelFlags useFlags = flags;
      useFlags.x1_matSetIdx = u8(x20c_shaderIdx);
      x10_solidModelData->Render(mgr, xf, lights, useFlags);
    } else {
      DrawHologram(mgr, xf, flags);
    }

    if (drawSuitArm && xb0_suitArmModelData) {
      xb0_suitArmModelData->Render(mgr, armXf, lights, flags);
    }
  }

  if (x1bc_rainSplashGenerator && x1bc_rainSplashGenerator->IsRaining()) {
    CSkinnedModel::ClearPointGeneratorFunc();
    x1bc_rainSplashGenerator->Draw(xf);
  }
}

void CGunWeapon::DrawMuzzleFx(const CStateManager& mgr) const {
  if (const CElementGen* effect = x1a4_muzzleGenerators[x208_muzzleEffectIdx].get()) {
    if (x200_beamId != CPlayerState::EBeamId::Ice &&
        mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::XRay) {
      CElementGen::SetSubtractBlend(true);
      const_cast<CElementGen*>(effect)->Render();
      CElementGen::SetSubtractBlend(false);
    } else {
      const_cast<CElementGen*>(effect)->Render();
    }
  }
}
<commit_msg>CGunWeapon: Eliminate const_cast usages in DrawMuzzleFx()<commit_after>#include "Runtime/Weapon/CGunWeapon.hpp"

#include <algorithm>
#include <array>

#include "Runtime/CDependencyGroup.hpp"
#include "Runtime/CGameState.hpp"
#include "Runtime/CSimplePool.hpp"
#include "Runtime/GameGlobalObjects.hpp"
#include "Runtime/Graphics/CSkinnedModel.hpp"
#include "Runtime/Graphics/CVertexMorphEffect.hpp"
#include "Runtime/Weapon/CEnergyProjectile.hpp"
#include "Runtime/Weapon/CWeapon.hpp"

namespace urde {
namespace {
constexpr std::array skBeamXferNames{
    "PowerXfer", "IceXfer", "WaveXfer", "PlasmaXfer", "PhazonXfer",
};

constexpr std::array skSuitArmNames{
    "PowerArm", "GravityArm", "VariaArm", "PhazonArm", "FusionArm", "FusionArmG", "FusionArmV", "FusionArmP",
};

constexpr std::array skMuzzleNames{
    "PowerMuzzle", "PowerCharge",  "IceMuzzle",    "IceCharge",    "PowerMuzzle",
    "WaveCharge",  "PlasmaMuzzle", "PlasmaCharge", "PhazonMuzzle", "EmptyMuzzle",
};

constexpr std::array skFrozenNames{
    "powerFrozen", "Ice2nd_2",     "iceFrozen", "Ice2nd_2",  "waveFrozen",
    "Ice2nd_2",    "plasmaFrozen", "Ice2nd_2",  "iceFrozen", "Ice2nd_2",
};

constexpr std::array skDependencyNames{
    "Power_DGRP", "Ice_DGRP", "Wave_DGRP", "Plasma_DGRP", "Phazon_DGRP",
};

constexpr std::array skAnimDependencyNames{
    "Power_Anim_DGRP", "Ice_Anim_DGRP", "Wave_Anim_DGRP", "Plasma_Anim_DGRP", "Phazon_Anim_DGRP",
};

constexpr std::array skAnimTypeList{
    0, 4, 1, 2, 3, 5, 6, 7, 8, 9, 10,
};

CPlayerState::EBeamId GetWeaponIndex(EWeaponType type) {
  if (type == EWeaponType::Power)
    return CPlayerState::EBeamId::Power;
  else if (type == EWeaponType::Ice)
    return CPlayerState::EBeamId::Ice;
  else if (type == EWeaponType::Wave)
    return CPlayerState::EBeamId::Wave;
  else if (type == EWeaponType::Plasma)
    return CPlayerState::EBeamId::Plasma;
  else if (type == EWeaponType::Phazon)
    return CPlayerState::EBeamId::Phazon;
  return CPlayerState::EBeamId::Power;
}
} // Anonymous namespace

CGunWeapon::CGunWeapon(CAssetId ancsId, EWeaponType type, TUniqueId playerId, EMaterialTypes playerMaterial,
                       const zeus::CVector3f& scale)
: x4_scale(scale)
, x104_gunCharacter(g_SimplePool->GetObj(SObjectTag{FOURCC('ANCS'), ancsId}))
, x13c_armCharacter(g_SimplePool->GetObj(skSuitArmNames[0]))
, x160_xferEffect(g_SimplePool->GetObj(skBeamXferNames[size_t(GetWeaponIndex(type))]))
, x1c0_weaponType(type)
, x1c4_playerId(playerId)
, x1c8_playerMaterial(playerMaterial)
, x200_beamId(GetWeaponIndex(type))
, x20c_shaderIdx(u32(x200_beamId))
, x214_ancsId(ancsId) {
  AllocResPools(x200_beamId);
  BuildDependencyList(x200_beamId);
}

void CGunWeapon::AllocResPools(CPlayerState::EBeamId beam) {
  const CAssetId* const wPair = g_tweakGunRes->GetWeaponPair(beam);
  const char* const* muzzleNames = &skMuzzleNames[size_t(beam) * 2];
  const char* const* frozenNames = &skFrozenNames[size_t(beam) * 2];

  for (size_t i = 0; i < x16c_muzzleEffects.capacity(); ++i) {
    x16c_muzzleEffects.push_back(g_SimplePool->GetObj(muzzleNames[i]));
    x144_weapons.push_back(g_SimplePool->GetObj(SObjectTag{FOURCC('WPSC'), wPair[i]}));
    x188_frozenEffects.push_back(g_SimplePool->GetObj(frozenNames[i]));
  }
}

void CGunWeapon::FreeResPools() {
  x160_xferEffect.Unlock();

  for (size_t i = 0; i < x16c_muzzleEffects.size(); ++i) {
    x16c_muzzleEffects[i].Unlock();
    x144_weapons[i].Unlock();
    x188_frozenEffects[i].Unlock();
  }

  x10c_anims.clear();
  x1a4_muzzleGenerators.clear();
  x1d0_velInfo.Clear();
}

void CGunWeapon::FillTokenVector(const std::vector<SObjectTag>& tags, std::vector<CToken>& objects) {
  for (const SObjectTag& tag : tags)
    objects.push_back(g_SimplePool->GetObj(tag));
}

void CGunWeapon::BuildDependencyList(CPlayerState::EBeamId beam) {
  TLockedToken<CDependencyGroup> deps = g_SimplePool->GetObj(skDependencyNames[size_t(beam)]);
  TLockedToken<CDependencyGroup> animDeps = g_SimplePool->GetObj(skAnimDependencyNames[size_t(beam)]);
  x12c_deps.reserve(deps->GetObjectTagVector().size() + animDeps->GetObjectTagVector().size());
  FillTokenVector(deps->GetObjectTagVector(), x12c_deps);
  FillTokenVector(animDeps->GetObjectTagVector(), x12c_deps);
}

void CGunWeapon::AsyncLoadSuitArm(CStateManager& mgr) {

  xb0_suitArmModelData = std::nullopt;
  x13c_armCharacter = g_SimplePool->GetObj(skSuitArmNames[size_t(NWeaponTypes::get_current_suit(mgr))]);
  x13c_armCharacter.Lock();
  x218_28_suitArmLocked = true;
}

void CGunWeapon::Reset(CStateManager& mgr) {
  if (!x218_26_loaded)
    return;

  x10_solidModelData->GetAnimationData()->EnableLooping(false);
  if (x218_25_enableCharge)
    x218_25_enableCharge = false;
  else
    x100_gunController->Reset();
}

void CGunWeapon::PlayAnim(NWeaponTypes::EGunAnimType type, bool loop) {
  if (!x218_26_loaded || type < NWeaponTypes::EGunAnimType::BasePosition || type > NWeaponTypes::EGunAnimType::ToBeam) {
    return;
  }

  x10_solidModelData->GetAnimationData()->EnableLooping(loop);
  const CAnimPlaybackParms parms(skAnimTypeList[size_t(type)], -1, 1.f, true);
  x10_solidModelData->GetAnimationData()->SetAnimation(parms, false);
}

void CGunWeapon::PreRenderGunFx(const CStateManager& mgr, const zeus::CTransform& xf) {
  // Empty
}

void CGunWeapon::PostRenderGunFx(const CStateManager& mgr, const zeus::CTransform& xf) {
  if (x218_26_loaded && x1b8_frozenGenerator && x204_frozenEffect != EFrozenFxType::None)
    x1b8_frozenGenerator->Render();
}

void CGunWeapon::UpdateGunFx(bool shotSmoke, float dt, const CStateManager& mgr, const zeus::CTransform& xf) {
  if (x218_26_loaded && x204_frozenEffect != EFrozenFxType::None) {
    if (x204_frozenEffect == EFrozenFxType::Thawed) {
      if (x1b8_frozenGenerator->IsSystemDeletable()) {
        x204_frozenEffect = EFrozenFxType::None;
        x1b8_frozenGenerator.reset();
      } else {
        x1b8_frozenGenerator->SetTranslation(xf.origin);
        x1b8_frozenGenerator->SetOrientation(xf.getRotation());
      }
    } else {
      x1b8_frozenGenerator->SetGlobalOrientAndTrans(xf);
    }
    if (x1b8_frozenGenerator)
      x1b8_frozenGenerator->Update(dt);
  }
}

const std::array<s32, 2> CGunWeapon::skShootAnim{4, 3};

void CGunWeapon::Fire(bool underwater, float dt, EChargeState chargeState, const zeus::CTransform& xf,
                      CStateManager& mgr, TUniqueId homingTarget, float chargeFactor1, float chargeFactor2) {
  CDamageInfo dInfo = GetDamageInfo(mgr, chargeState, chargeFactor1);
  zeus::CVector3f scale(chargeState == EChargeState::Normal ? 1.f : chargeFactor2);
  bool partialCharge = chargeState == EChargeState::Normal ? false : !zeus::close_enough(chargeFactor1, 1.f);
  EProjectileAttrib attribs = EProjectileAttrib::ArmCannon;
  if (partialCharge)
    attribs |= EProjectileAttrib::PartialCharge;
  if (chargeState == EChargeState::Charged)
    attribs |= EProjectileAttrib::Charged;

  CEnergyProjectile* proj = new CEnergyProjectile(
      true, x144_weapons[int(chargeState)], x1c0_weaponType, xf, x1c8_playerMaterial, dInfo, mgr.AllocateUniqueId(),
      kInvalidAreaId, x1c4_playerId, homingTarget, attribs, underwater, scale, {}, -1, false);
  mgr.AddObject(proj);
  proj->Think(dt, mgr);

  if (chargeState == EChargeState::Charged) {
    x218_25_enableCharge = true;
    mgr.GetCameraManager()->AddCameraShaker(CCameraShakeData::skChargedShotCameraShakeData, false);
  }

  x10_solidModelData->GetAnimationData()->EnableLooping(false);
  CAnimPlaybackParms parms(skShootAnim[int(chargeState)], -1, 1.f, true);
  x10_solidModelData->GetAnimationData()->SetAnimation(parms, false);
}

void CGunWeapon::EnableFx(bool enable) {
  // Empty
}

void CGunWeapon::EnableSecondaryFx(ESecondaryFxType type) { x1cc_enabledSecondaryEffect = type; }

void CGunWeapon::EnableFrozenEffect(EFrozenFxType type) {
  switch (type) {
  case EFrozenFxType::Thawed:
    if (x204_frozenEffect == EFrozenFxType::Thawed)
      break;
    x1b8_frozenGenerator = std::make_unique<CElementGen>(x188_frozenEffects[1]);
    x1b8_frozenGenerator->SetGlobalScale(x4_scale);
    break;
  case EFrozenFxType::Frozen:
    if (x204_frozenEffect == EFrozenFxType::Frozen)
      break;
    x1b8_frozenGenerator = std::make_unique<CElementGen>(x188_frozenEffects[0]);
    x1b8_frozenGenerator->SetGlobalScale(x4_scale);
    break;
  default:
    break;
  }
  x204_frozenEffect = type;
}

void CGunWeapon::ActivateCharge(bool enable, bool resetEffect) {
  x1a4_muzzleGenerators[x208_muzzleEffectIdx]->SetParticleEmission(false);
  x208_muzzleEffectIdx = u32(enable);
  if (enable || resetEffect) {
    x1a4_muzzleGenerators[x208_muzzleEffectIdx] =
        std::make_unique<CElementGen>(x16c_muzzleEffects[x208_muzzleEffectIdx]);
  }
}

void CGunWeapon::Touch(const CStateManager& mgr) {
  if (x10_solidModelData) {
    x10_solidModelData->Touch(mgr, x20c_shaderIdx);
    if (xb0_suitArmModelData)
      xb0_suitArmModelData->Touch(mgr, 0);
  }
}

void CGunWeapon::TouchHolo(const CStateManager& mgr) {
  if (x60_holoModelData)
    x60_holoModelData->Touch(mgr, 0);
}

void CGunWeapon::PointGenerator(void* ctx, const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn) {
  reinterpret_cast<CRainSplashGenerator*>(ctx)->GeneratePoints(vn);
}

void CGunWeapon::Draw(bool drawSuitArm, const CStateManager& mgr, const zeus::CTransform& xf, const CModelFlags& flags,
                      const CActorLights* lights) const {
  if (!x218_26_loaded)
    return;

  zeus::CTransform armXf = xf * x10_solidModelData->GetScaledLocatorTransform("elbow");

  if (x1bc_rainSplashGenerator && x1bc_rainSplashGenerator->IsRaining())
    CSkinnedModel::SetPointGeneratorFunc(x1bc_rainSplashGenerator, PointGenerator);

  if (mgr.GetThermalDrawFlag() == EThermalDrawFlag::Hot && x200_beamId != CPlayerState::EBeamId::Ice) {
    /* Hot Draw */
    zeus::CColor mulColor(flags.x4_color.a(), flags.x4_color.a());
    zeus::CColor addColor(0.25f, 0.25f);
    if (x218_29_drawHologram) {
      DrawHologram(mgr, xf, flags);
    } else {
      CModelFlags useFlags(0, 0, 3, zeus::skWhite);
      x10_solidModelData->RenderThermal(xf, mulColor, addColor, useFlags);
    }

    if (drawSuitArm && xb0_suitArmModelData) {
      CModelFlags useFlags(0, 0, 3, zeus::skWhite);
      xb0_suitArmModelData->RenderThermal(xf, mulColor, addColor, useFlags);
    }
  } else {
    /* Cold Draw */
    if (mgr.GetPlayerState()->GetCurrentVisor() != CPlayerState::EPlayerVisor::XRay && !x218_29_drawHologram) {
      CModelFlags useFlags = flags;
      useFlags.x1_matSetIdx = u8(x20c_shaderIdx);
      x10_solidModelData->Render(mgr, xf, lights, useFlags);
    } else {
      DrawHologram(mgr, xf, flags);
    }

    if (drawSuitArm && xb0_suitArmModelData) {
      xb0_suitArmModelData->Render(mgr, armXf, lights, flags);
    }
  }

  if (x1bc_rainSplashGenerator && x1bc_rainSplashGenerator->IsRaining()) {
    CSkinnedModel::ClearPointGeneratorFunc();
    x1bc_rainSplashGenerator->Draw(xf);
  }
}

void CGunWeapon::DrawMuzzleFx(const CStateManager& mgr) const {
  if (CElementGen* const effect = x1a4_muzzleGenerators[x208_muzzleEffectIdx].get()) {
    if (x200_beamId != CPlayerState::EBeamId::Ice &&
        mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::XRay) {
      CElementGen::SetSubtractBlend(true);
      effect->Render();
      CElementGen::SetSubtractBlend(false);
    } else {
      effect->Render();
    }
  }
}

{'fraction_non_alphanumeric': 0.13221153846153846, 'fraction_numerical': 0.02937062937062937, 'mean_word_length': 5.733666862860506, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 139, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4796749', 'n_tokens_mistral': 9237, 'n_tokens_neox': 8589, 'n_words': 1241}