Implement CPlasmaProjectile

This commit is contained in:
Jack Andersen 2019-01-02 17:47:28 -10:00
parent 4f3c8daf27
commit 5b55320e9b
30 changed files with 1203 additions and 238 deletions

View File

@ -12,6 +12,25 @@
<option name="SPACE_AFTER_REFERENCE_IN_DECLARATION" value="true" />
</Objective-C>
<Objective-C-extensions>
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cpp" header="hpp" fileNamingConvention="NONE" />
<pair source="c" header="h" fileNamingConvention="NONE" />

View File

@ -17,31 +17,31 @@ struct NewIntroBoss : IScriptObject {
Value<float> unknown1;
UniqueID32 weaponDesc;
DamageInfo damageInfo;
UniqueID32 particle1;
UniqueID32 particle2;
UniqueID32 texture1;
UniqueID32 texture2;
UniqueID32 beamContactFxId;
UniqueID32 beamPulseFxId;
UniqueID32 beamTextureId;
UniqueID32 beamGlowTextureId;
void addCMDLRigPairs(PAKRouter<PAKBridge>& pakRouter, CharacterAssociations<UniqueID32>& charAssoc) const {
actorParameters.addCMDLRigPairs(pakRouter, charAssoc, patternedInfo.animationParameters);
}
void nameIDs(PAKRouter<PAKBridge>& pakRouter) const {
if (particle1) {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(particle1);
ent->name = name + "_part1";
if (beamContactFxId) {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(beamContactFxId);
ent->name = name + "_beamContactFxId";
}
if (particle2) {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(particle2);
ent->name = name + "_part2";
if (beamPulseFxId) {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(beamPulseFxId);
ent->name = name + "_beamPulseFxId";
}
if (texture1) {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(texture1);
ent->name = name + "_tex1";
if (beamTextureId) {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(beamTextureId);
ent->name = name + "_beamTextureId";
}
if (texture2) {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(texture2);
ent->name = name + "_tex2";
if (beamGlowTextureId) {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(beamGlowTextureId);
ent->name = name + "_beamGlowTextureId";
}
patternedInfo.nameIDs(pakRouter, name + "_patterned");
actorParameters.nameIDs(pakRouter, name + "_actp");
@ -49,10 +49,10 @@ struct NewIntroBoss : IScriptObject {
void gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut, std::vector<hecl::ProjectPath>& lazyOut) const {
g_curSpec->flattenDependencies(weaponDesc, pathsOut);
g_curSpec->flattenDependencies(particle1, pathsOut);
g_curSpec->flattenDependencies(particle2, pathsOut);
g_curSpec->flattenDependencies(texture1, pathsOut);
g_curSpec->flattenDependencies(texture2, pathsOut);
g_curSpec->flattenDependencies(beamContactFxId, pathsOut);
g_curSpec->flattenDependencies(beamPulseFxId, pathsOut);
g_curSpec->flattenDependencies(beamTextureId, pathsOut);
g_curSpec->flattenDependencies(beamGlowTextureId, pathsOut);
patternedInfo.depIDs(pathsOut);
actorParameters.depIDs(pathsOut, lazyOut);
}

View File

@ -424,47 +424,47 @@ struct ActorParameters : BigDNA {
struct BeamInfo : BigDNA {
AT_DECL_DNA_YAML
Value<atUint32> propertyCount;
Value<atUint32> unknown1;
UniqueID32 particle1;
UniqueID32 particle2;
UniqueID32 texture1;
UniqueID32 texture2;
Value<float> unknown2;
Value<float> unknown3;
Value<float> unknown4;
Value<float> unknown5;
Value<float> unknown6;
Value<float> unknown7;
Value<float> unknown8;
Value<float> unknown9;
Value<float> unknown10;
DNAColor unknown11;
DNAColor unknown12;
Value<atUint32> beamAttributes;
UniqueID32 contactFxId;
UniqueID32 pulseFxId;
UniqueID32 textureId;
UniqueID32 glowTextureId;
Value<float> length;
Value<float> radius;
Value<float> expansionSpeed;
Value<float> lifeTime;
Value<float> pulseSpeed;
Value<float> shutdownTime;
Value<float> contactFxScale;
Value<float> pulseFxScale;
Value<float> travelSpeed;
DNAColor innerColor;
DNAColor outerColor;
void nameIDs(PAKRouter<PAKBridge>& pakRouter, const std::string& name) const {
if (particle1) {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(particle1);
if (contactFxId) {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(contactFxId);
ent->name = name + "_part1";
}
if (particle2) {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(particle2);
if (pulseFxId) {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(pulseFxId);
ent->name = name + "_part2";
}
if (texture1) {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(texture1);
if (textureId) {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(textureId);
ent->name = name + "_tex1";
}
if (texture2) {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(texture2);
if (glowTextureId) {
PAK::Entry* ent = (PAK::Entry*)pakRouter.lookupEntry(glowTextureId);
ent->name = name + "_tex2";
}
}
void depIDs(std::vector<hecl::ProjectPath>& pathsOut) const {
g_curSpec->flattenDependencies(particle1, pathsOut);
g_curSpec->flattenDependencies(particle2, pathsOut);
g_curSpec->flattenDependencies(texture1, pathsOut);
g_curSpec->flattenDependencies(texture2, pathsOut);
g_curSpec->flattenDependencies(contactFxId, pathsOut);
g_curSpec->flattenDependencies(pulseFxId, pathsOut);
g_curSpec->flattenDependencies(textureId, pathsOut);
g_curSpec->flattenDependencies(glowTextureId, pathsOut);
}
};

View File

@ -837,7 +837,7 @@ bool CBSJump::CheckForWallJump(CBodyController& bc, CStateManager& mgr) {
float distToWall = (xc_waypoint1 - act->GetTranslation()).magnitude();
zeus::CAABox aabb = act->GetBoundingBox();
float xExtent = (aabb.max.x() - aabb.min.x()) * 0.5f;
if (distToWall < 1.414f * xExtent || (act->CanLongJump() && distToWall < 3.f * xExtent)) {
if (distToWall < 1.414f * xExtent || (act->MadeSolidCollision() && distToWall < 3.f * xExtent)) {
x4_state = x30_26_wallBounceRight ? pas::EJumpState::WallBounceRight : pas::EJumpState::WallBounceLeft;
CPASAnimParmData parms(13, CPASAnimParm::FromEnum(s32(x4_state)), CPASAnimParm::FromEnum(s32(x8_jumpType)));
bc.PlayBestAnimation(parms, *mgr.GetActiveRandom());
@ -851,7 +851,7 @@ bool CBSJump::CheckForWallJump(CBodyController& bc, CStateManager& mgr) {
void CBSJump::CheckForLand(CBodyController& bc, CStateManager& mgr) {
if (TCastToPtr<CPatterned> act = bc.GetOwner()) {
if (act->CanLongJump() || act->IsOnGround()) {
if (act->MadeSolidCollision() || act->IsOnGround()) {
x4_state = pas::EJumpState::OutOfJump;
CPASAnimParmData parms(13, CPASAnimParm::FromEnum(s32(x4_state)), CPASAnimParm::FromEnum(s32(x8_jumpType)));
bc.PlayBestAnimation(parms, *mgr.GetActiveRandom());
@ -1044,7 +1044,7 @@ void CBSHurled::PlayLandAnimation(CBodyController& bc, CStateManager& mgr) {
bool CBSHurled::ShouldStartStrikeWall(CBodyController& bc) const {
if (TCastToPtr<CPatterned> ai = bc.GetOwner()) {
if (ai->CanLongJump())
if (ai->MadeSolidCollision())
if (!ai->IsOnGround())
return true;
}
@ -1361,7 +1361,7 @@ void CBSWallHang::FixInPlace(CBodyController& bc) {
bool CBSWallHang::CheckForLand(CBodyController& bc, CStateManager& mgr) {
if (TCastToPtr<CPatterned> ai = bc.GetOwner()) {
if (ai->CanLongJump() || ai->IsOnGround()) {
if (ai->MadeSolidCollision() || ai->IsOnGround()) {
x4_state = pas::EWallHangState::DetachOutOfJump;
CPASAnimParmData parms(20, CPASAnimParm::FromEnum(s32(x4_state)));
bc.PlayBestAnimation(parms, *mgr.GetActiveRandom());
@ -1379,7 +1379,7 @@ bool CBSWallHang::CheckForWall(CBodyController& bc, CStateManager& mgr) {
if (wp)
magSq = (wp->GetTranslation() - ai->GetTranslation()).magSquared();
if (magSq < 1.f || ai->CanLongJump()) {
if (magSq < 1.f || ai->MadeSolidCollision()) {
x4_state = pas::EWallHangState::IntoWallHang;
CPASAnimParmData parms(20, CPASAnimParm::FromEnum(s32(x4_state)));
std::pair<float, s32> best = bc.GetPASDatabase().FindBestAnimation(parms, *mgr.GetActiveRandom(), -1);

View File

@ -615,6 +615,16 @@ CBooRenderer::CBooRenderer(IObjectStore& store, IFactory& resFac)
m_staticEntropy = store.GetObj("RandomStaticEntropy");
CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) {
u8 clearPixel[] = {0, 0, 0, 0};
m_clearTexture = ctx.newStaticTexture(1, 1, 1, boo::TextureFormat::RGBA8,
boo::TextureClampMode::Repeat, clearPixel, 4).get();
u8 blackPixel[] = {0, 0, 0, 255};
m_blackTexture = ctx.newStaticTexture(1, 1, 1, boo::TextureFormat::RGBA8,
boo::TextureClampMode::Repeat, blackPixel, 4).get();
u8 whitePixel[] = {255, 255, 255, 255};
m_whiteTexture = ctx.newStaticTexture(1, 1, 1, boo::TextureFormat::RGBA8,
boo::TextureClampMode::Repeat, whitePixel, 4).get();
GenerateFogVolumeRampTex(ctx);
GenerateSphereRampTex(ctx);
m_ballShadowId = ctx.newRenderTexture(m_ballShadowIdW, m_ballShadowIdH, boo::TextureClampMode::Repeat, 1, 0);

View File

@ -106,6 +106,10 @@ class CBooRenderer final : public IRenderer {
// boo::ITextureS* xe4_blackTex = nullptr;
bool xee_24_ : 1;
boo::ObjToken<boo::ITexture> m_clearTexture;
boo::ObjToken<boo::ITexture> m_blackTexture;
boo::ObjToken<boo::ITexture> m_whiteTexture;
boo::ObjToken<boo::ITextureR> x14c_reflectionTex;
// boo::ITextureS* x150_mirrorRamp = nullptr;
boo::ObjToken<boo::ITextureS> x1b8_fogVolumeRamp;
@ -269,6 +273,10 @@ public:
const boo::ObjToken<boo::IGraphicsBufferS>& GetScanLinesEvenVBO() const { return m_scanLinesEvenVBO; }
const boo::ObjToken<boo::IGraphicsBufferS>& GetScanLinesOddVBO() const { return m_scanLinesOddVBO; }
const boo::ObjToken<boo::ITexture>& GetClearTexture() { return m_clearTexture; }
const boo::ObjToken<boo::ITexture>& GetBlackTexture() { return m_blackTexture; }
const boo::ObjToken<boo::ITexture>& GetWhiteTexture() { return m_whiteTexture; }
static void BindMainDrawTarget() { CGraphics::g_BooMainCommandQueue->setRenderTarget(CGraphics::g_SpareTexture); }
void BindReflectionDrawTarget() { CGraphics::g_BooMainCommandQueue->setRenderTarget(x14c_reflectionTex); }
void BindBallShadowIdTarget() {

View File

@ -22,6 +22,7 @@ set(GRAPHICS_SOURCES
Shaders/CLineRendererShaders.hpp Shaders/CLineRendererShaders.cpp
Shaders/CTexturedQuadFilter.hpp Shaders/CTexturedQuadFilter.cpp
Shaders/CColoredQuadFilter.hpp Shaders/CColoredQuadFilter.cpp
Shaders/CColoredStripShader.hpp Shaders/CColoredStripShader.cpp
Shaders/CModelShaders.hpp Shaders/CModelShaders.cpp
Shaders/CModelShadersGLSL.cpp Shaders/CModelShadersHLSL.cpp Shaders/CModelShadersMetal.cpp
Shaders/CThermalColdFilter.hpp Shaders/CThermalColdFilter.cpp

View File

@ -0,0 +1,75 @@
#include "CColoredStripShader.hpp"
#include "Graphics/CGraphics.hpp"
#include "hecl/Pipeline.hpp"
#include "GameGlobalObjects.hpp"
#include "Graphics/CBooRenderer.hpp"
namespace urde {
static boo::ObjToken<boo::IShaderPipeline> s_Pipeline;
static boo::ObjToken<boo::IShaderPipeline> s_AdditivePipeline;
static boo::ObjToken<boo::IShaderPipeline> s_FullAdditivePipeline;
void CColoredStripShader::Initialize() {
s_Pipeline = hecl::conv->convert(Shader_CColoredStripShader{});
s_AdditivePipeline = hecl::conv->convert(Shader_CColoredStripShaderAdditive{});
s_FullAdditivePipeline = hecl::conv->convert(Shader_CColoredStripShaderFullAdditive{});
}
void CColoredStripShader::Shutdown() {
s_Pipeline.reset();
s_AdditivePipeline.reset();
s_FullAdditivePipeline.reset();
}
static const boo::ObjToken<boo::IShaderPipeline>& SelectPipeline(CColoredStripShader::Mode mode) {
switch (mode) {
case CColoredStripShader::Mode::Alpha:
default:
return s_Pipeline;
case CColoredStripShader::Mode::Additive:
return s_AdditivePipeline;
case CColoredStripShader::Mode::FullAdditive:
return s_FullAdditivePipeline;
}
}
void CColoredStripShader::BuildResources(boo::IGraphicsDataFactory::Context& ctx, size_t maxVerts, Mode mode,
boo::ObjToken<boo::ITexture> tex) {
m_vbo = ctx.newDynamicBuffer(boo::BufferUse::Vertex, sizeof(Vert), maxVerts);
m_uniBuf = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(Uniform), 1);
boo::ObjToken<boo::IGraphicsBuffer> bufs[] = {m_uniBuf.get()};
boo::PipelineStage stages[] = {boo::PipelineStage::Vertex};
boo::ObjToken<boo::ITexture> texs[1];
if (tex)
texs[0] = tex;
else
texs[0] = g_Renderer->GetWhiteTexture();
m_dataBind = ctx.newShaderDataBinding(SelectPipeline(mode), m_vbo.get(), nullptr, nullptr, 1, bufs, stages, nullptr,
nullptr, 1, texs, nullptr, nullptr);
}
CColoredStripShader::CColoredStripShader(size_t maxVerts, Mode mode, boo::ObjToken<boo::ITexture> tex) {
CGraphics::CommitResources([this, maxVerts, mode, tex](boo::IGraphicsDataFactory::Context& ctx) {
BuildResources(ctx, maxVerts, mode, tex);
return true;
} BooTrace);
}
CColoredStripShader::CColoredStripShader(boo::IGraphicsDataFactory::Context& ctx, size_t maxVerts, Mode mode,
boo::ObjToken<boo::ITexture> tex) {
BuildResources(ctx, maxVerts, mode, tex);
}
void CColoredStripShader::draw(const zeus::CColor& color, size_t numVerts, const Vert* verts) {
m_vbo->load(verts, sizeof(Vert) * numVerts);
m_uniform.m_matrix = CGraphics::GetPerspectiveProjectionMatrix(true) * CGraphics::g_GXModelView.toMatrix4f();
m_uniform.m_color = color;
m_uniBuf->load(&m_uniform, sizeof(m_uniform));
CGraphics::SetShaderDataBinding(m_dataBind);
CGraphics::DrawArray(0, numVerts);
}
}

View File

@ -0,0 +1,43 @@
#pragma once
#include "boo/graphicsdev/IGraphicsDataFactory.hpp"
#include "zeus/CMatrix4f.hpp"
#include "zeus/CColor.hpp"
namespace urde
{
class CColoredStripShader {
public:
enum class Mode {
Alpha,
Additive,
FullAdditive
};
private:
struct Uniform {
zeus::CMatrix4f m_matrix;
zeus::CColor m_color;
};
boo::ObjToken<boo::IGraphicsBufferD> m_vbo;
boo::ObjToken<boo::IGraphicsBufferD> m_uniBuf;
boo::ObjToken<boo::IShaderDataBinding> m_dataBind;
Uniform m_uniform;
void BuildResources(boo::IGraphicsDataFactory::Context& ctx, size_t maxVerts, Mode mode,
boo::ObjToken<boo::ITexture> tex);
public:
struct Vert {
zeus::CVector3f m_pos;
zeus::CColor m_color;
zeus::CVector2f m_uv;
};
static void Initialize();
static void Shutdown();
CColoredStripShader(size_t maxVerts, Mode mode, boo::ObjToken<boo::ITexture> tex);
CColoredStripShader(boo::IGraphicsDataFactory::Context& ctx, size_t maxVerts, Mode mode,
boo::ObjToken<boo::ITexture> tex);
void draw(const zeus::CColor& color, size_t numVerts, const Vert* verts);
};
}

View File

@ -4,6 +4,7 @@
#include "Graphics/Shaders/CThermalHotFilter.hpp"
#include "Graphics/Shaders/CSpaceWarpFilter.hpp"
#include "Graphics/Shaders/CColoredQuadFilter.hpp"
#include "Graphics/Shaders/CColoredStripShader.hpp"
#include "Graphics/Shaders/CTexturedQuadFilter.hpp"
#include "Graphics/Shaders/CCameraBlurFilter.hpp"
#include "Graphics/Shaders/CXRayBlurFilter.hpp"
@ -244,6 +245,7 @@ CMain::BooSetter::BooSetter(boo::IGraphicsDataFactory* factory, boo::IGraphicsCo
CAABoxShader::Initialize();
CWorldShadowShader::Initialize();
CColoredQuadFilter::Initialize();
CColoredStripShader::Initialize();
CTexturedQuadFilter::Initialize();
CTexturedQuadFilterAlpha::Initialize();
CTextSupportShader::Initialize();
@ -823,6 +825,7 @@ void CMain::Shutdown() {
CAABoxShader::Shutdown();
CWorldShadowShader::Shutdown();
CColoredQuadFilter::Shutdown();
CColoredStripShader::Shutdown();
CTexturedQuadFilter::Shutdown();
CTexturedQuadFilterAlpha::Shutdown();
CTextSupportShader::Shutdown();

View File

@ -477,7 +477,7 @@ void CBeetle::Generate(CStateManager& mgr, EStateMsg msg, float dt) {
AddMaterial(EMaterialTypes::Character, EMaterialTypes::Solid, EMaterialTypes::GroundCollider, mgr);
x328_25_verticalMovement = false;
x838_25_burrowing = false;
if (x328_26_longJump)
if (x328_26_solidCollision)
DeathDelete(mgr);
break;
default:
@ -581,7 +581,7 @@ void CBeetle::Attack(CStateManager& mgr, EStateMsg msg, float dt) {
default:
break;
}
if (x328_26_longJump)
if (x328_26_solidCollision)
x838_24_hitSomething = true;
break;
case EStateMsg::Deactivate:

View File

@ -104,7 +104,7 @@ void CEyeball::Think(float dt, CStateManager& mgr) {
if (GetActive()) {
CPlasmaProjectile* projectile = static_cast<CPlasmaProjectile*>(mgr.ObjectById(x5ec_projectileId));
if (projectile && projectile->GetActive())
projectile->UpdateFX(GetLctrTransform(skEyeLocator), dt, mgr);
projectile->UpdateFx(GetLctrTransform(skEyeLocator), dt, mgr);
}
if (x60c_28_firingBeam) {
@ -125,7 +125,7 @@ void CEyeball::CreateBeam(CStateManager& mgr) {
mgr.AddObject(new CPlasmaProjectile(x5b4_projectileInfo.Token(), "EyeBall_Beam"sv, EWeaponType::AI, beamInfo,
zeus::CTransform::Identity(), EMaterialTypes::Immovable,
x5b4_projectileInfo.GetDamage(), x5ec_projectileId, GetAreaIdAlways(),
GetUniqueId(), 8, false, EProjectileAttrib::KeepInCinematic));
GetUniqueId(), {}, false, EProjectileAttrib::KeepInCinematic));
}
void CEyeball::InActive(CStateManager&, EStateMsg msg, float) {

View File

@ -14,17 +14,17 @@ namespace urde::MP1 {
CNewIntroBoss::CNewIntroBoss(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,
CModelData&& mData, const CPatternedInfo& pInfo, const CActorParameters& actParms,
float f1, CAssetId projectile, const CDamageInfo& dInfo, CAssetId part1, CAssetId part2,
CAssetId tex1, CAssetId tex2)
float f1, CAssetId projectile, const CDamageInfo& dInfo, CAssetId beamContactFxId,
CAssetId beamPulseFxId, CAssetId beamTextureId, CAssetId beamGlowTextureId)
: CPatterned(ECharacter::NewIntroBoss, uid, name, EFlavorType::Zero, info, xf, std::move(mData), pInfo,
EMovementType::Flyer, EColliderType::One, EBodyType::Restricted, actParms, EKnockBackVariant::Medium)
, x570_(f1)
, x574_boneTracking(*GetModelData()->GetAnimationData(), "Head_1"sv, zeus::degToRad(80.f), zeus::degToRad(180.f), false)
, x5ac_projectileInfo(projectile, dInfo)
, x5f0_(part1)
, x5f4_(part2)
, x5f8_(tex1)
, x5fc_(tex2) {
, x5f0_beamContactFxId(beamContactFxId)
, x5f4_beamPulseFxId(beamPulseFxId)
, x5f8_beamTextureId(beamTextureId)
, x5fc_beamGlowTextureId(beamGlowTextureId) {
const_cast<TToken<CWeaponDescription>*>(&x5ac_projectileInfo.Token())->Lock();
x574_boneTracking.SetActive(true);
}
@ -58,10 +58,12 @@ void CNewIntroBoss::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CSt
x450_bodyController->Activate(mgr);
if (x5d4_stage1Projectile == kInvalidUniqueId) {
CBeamInfo stage1BeamInfo = CBeamInfo(3, x5f0_, x5f4_, x5f8_, x5fc_, 50, 1.f, 1.f, 1.5f, 20.f, 1.f, 4.f, 8.f,
zeus::CColor::skYellow, zeus::CColor(0.1098f, 0.5764f, 0.1592f), 150.f);
CBeamInfo stage2BeamInfo(3, x5f0_, x5f4_, x5f8_, x5fc_, 50, 1.f, 1.f, 2.f, 20.f, 1.f, 4.f, 8.f,
zeus::CColor::skYellow, zeus::CColor(0.1098f, 0.5764f, 0.1592f), 150.f);
CBeamInfo stage1BeamInfo(3, x5f0_beamContactFxId, x5f4_beamPulseFxId, x5f8_beamTextureId, x5fc_beamGlowTextureId,
50, 1.f, 1.f, 1.5f, 20.f, 1.f, 4.f, 8.f, zeus::CColor::skYellow,
zeus::CColor(0.1098f, 0.5764f, 0.1592f), 150.f);
CBeamInfo stage2BeamInfo(3, x5f0_beamContactFxId, x5f4_beamPulseFxId, x5f8_beamTextureId, x5fc_beamGlowTextureId,
50, 1.f, 1.f, 2.f, 20.f, 1.f, 4.f, 8.f, zeus::CColor::skYellow,
zeus::CColor(0.1098f, 0.5764f, 0.1592f), 150.f);
x5d4_stage1Projectile = mgr.AllocateUniqueId();
x5d6_stage2Projectile = mgr.AllocateUniqueId();
@ -69,15 +71,15 @@ void CNewIntroBoss::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CSt
CPlasmaProjectile* stage1Projectile =
new CPlasmaProjectile(x5ac_projectileInfo.Token(), "IntroBoss_Beam"sv, EWeaponType::AI, stage1BeamInfo, {},
EMaterialTypes::Character, x5ac_projectileInfo.GetDamage(), x5d4_stage1Projectile,
GetAreaIdAlways(), GetUniqueId(), 8, true, EProjectileAttrib::KeepInCinematic);
GetAreaIdAlways(), GetUniqueId(), {}, true, EProjectileAttrib::KeepInCinematic);
CPlasmaProjectile* stage2Projectile =
new CPlasmaProjectile(x5ac_projectileInfo.Token(), "IntroBoss_Beam_Stage2"sv, EWeaponType::AI, stage2BeamInfo,
{}, EMaterialTypes::Character, x5ac_projectileInfo.GetDamage(), x5d6_stage2Projectile,
GetAreaIdAlways(), GetUniqueId(), 8, true, EProjectileAttrib::KeepInCinematic);
GetAreaIdAlways(), GetUniqueId(), {}, true, EProjectileAttrib::KeepInCinematic);
CPlasmaProjectile* stage3Projectile =
new CPlasmaProjectile(x5ac_projectileInfo.Token(), "IntroBoss_Beam_Stage2"sv, EWeaponType::AI, stage2BeamInfo,
{}, EMaterialTypes::Character, x5ac_projectileInfo.GetDamage(), x5d8_stage3Projectile,
GetAreaIdAlways(), GetUniqueId(), 8, true, EProjectileAttrib::KeepInCinematic);
GetAreaIdAlways(), GetUniqueId(), {}, true, EProjectileAttrib::KeepInCinematic);
mgr.AddObject(stage1Projectile);
mgr.AddObject(stage2Projectile);
mgr.AddObject(stage3Projectile);
@ -219,16 +221,18 @@ void CNewIntroBoss::Think(float dt, CStateManager& mgr) {
CPlasmaProjectile* curProjectile = static_cast<CPlasmaProjectile*>(mgr.ObjectById(x676_curProjectile));
if (curProjectile && curProjectile->GetActive()) {
x628_ += dt;
x628_firingTime += dt;
zeus::CTransform xf = GetLctrTransform(x5dc_damageLocator);
if (x400_25_alive) {
zeus::CQuaternion clampedQuat = zeus::CQuaternion::clampedRotateTo(
(x610_lookPos + (zeus::min(x628_ / 1.5f, 1.f) * (x61c_ - x610_lookPos))) - xf.origin, xf.frontVector(),
zeus::CQuaternion clampedQuat = zeus::CQuaternion::clampedRotateTo(xf.frontVector(),
(x610_lookPos + (zeus::min(x628_firingTime / 1.5f, 1.f) * (x61c_startPlayerPos - x610_lookPos))) - xf.origin,
zeus::CRelAngle::FromDegrees(30.f));
curProjectile->UpdateFX(clampedQuat.toTransform() * xf.getRotation(), dt, mgr);
zeus::CTransform newXf = clampedQuat.toTransform() * xf.getRotation();
newXf.origin = xf.origin;
curProjectile->UpdateFx(newXf, dt, mgr);
} else
curProjectile->UpdateFX(xf, dt, mgr);
curProjectile->UpdateFx(xf, dt, mgr);
}
TCastToPtr<CCollisionActor> headAct = mgr.ObjectById(x600_headActor);
@ -263,7 +267,8 @@ void CNewIntroBoss::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& nod
zeus::CTransform xf = GetLctrTransform(x5dc_damageLocator);
zeus::CVector3f playerPos = PlayerPos(mgr);
x604_predictedPlayerPos = x610_lookPos = x62c_targetPos = playerPos;
x628_ = 0.f;
x61c_startPlayerPos = playerPos;
x628_firingTime = 0.f;
if (GetLocoForHealth(mgr) == pas::ELocomotionType::Combat)
x676_curProjectile = x5d8_stage3Projectile;
else if (GetLocoForHealth(mgr) == pas::ELocomotionType::Lurk)
@ -337,24 +342,24 @@ bool CNewIntroBoss::ShouldAttack(CStateManager& mgr, float dt) {
bool CNewIntroBoss::AIStage(CStateManager& mgr, float) { return x568_locomotion != GetLocoForHealth(mgr); }
bool CNewIntroBoss::AnimOver(urde::CStateManager&, float) { return x56c_ == 3; }
bool CNewIntroBoss::AnimOver(urde::CStateManager&, float) { return x56c_stateProg == 3; }
void CNewIntroBoss::Generate(CStateManager& mgr, EStateMsg msg, float dt) {
if (msg == EStateMsg::Activate) {
x56c_ = 0;
x56c_stateProg = 0;
x568_locomotion = GetLocoForHealth(mgr);
SendScriptMsgs(EScriptObjectState::Entered, mgr, EScriptObjectMessage::None);
} else if (msg == EStateMsg::Update) {
if (x56c_ == 0) {
if (x56c_stateProg == 0) {
if (x450_bodyController->GetBodyStateInfo().GetCurrentStateId() == pas::EAnimationState::Generate) {
x56c_ = 2;
x56c_stateProg = 2;
return;
}
x450_bodyController->GetCommandMgr().DeliverCmd(CBCGenerateCmd(GetGenerateForHealth(mgr)));
} else if (x56c_ == 2) {
} else if (x56c_stateProg == 2) {
if (x450_bodyController->GetBodyStateInfo().GetCurrentStateId() != pas::EAnimationState::Generate) {
x56c_ = 3;
x56c_stateProg = 3;
SendScriptMsgs(EScriptObjectState::Exited, mgr, EScriptObjectMessage::None);
}
}
@ -373,18 +378,18 @@ bool CNewIntroBoss::InAttackPosition(CStateManager& mgr, float dt) {
void CNewIntroBoss::Attack(CStateManager& mgr, EStateMsg msg, float dt) {
if (msg == EStateMsg::Activate)
x56c_ = 0;
x56c_stateProg = 0;
else if (msg == EStateMsg::Update) {
if (x56c_ == 0) {
if (x56c_stateProg == 0) {
if (x450_bodyController->GetBodyStateInfo().GetCurrentStateId() == pas::EAnimationState::ProjectileAttack)
x56c_ = 2;
x56c_stateProg = 2;
else {
x450_bodyController->GetCommandMgr().DeliverCmd(
CBCProjectileAttackCmd(pas::ESeverity::One, mgr.GetPlayer().GetTranslation(), false));
}
} else if (x56c_ == 2) {
} else if (x56c_stateProg == 2) {
if (x450_bodyController->GetBodyStateInfo().GetCurrentStateId() != pas::EAnimationState::ProjectileAttack) {
x56c_ = 3;
x56c_stateProg = 3;
x638_ = 0.f;
}

View File

@ -11,7 +11,7 @@ class CCollisionActorManager;
namespace MP1 {
class CNewIntroBoss : public CPatterned {
pas::ELocomotionType x568_locomotion = pas::ELocomotionType::Relaxed;
u32 x56c_ = 0;
u32 x56c_stateProg = 0;
float x570_;
CBoneTracking x574_boneTracking;
CProjectileInfo x5ac_projectileInfo;
@ -20,16 +20,16 @@ class CNewIntroBoss : public CPatterned {
TUniqueId x5d8_stage3Projectile = kInvalidUniqueId;
std::string x5dc_damageLocator; // ???
std::unique_ptr<CCollisionActorManager> x5ec_collisionManager;
CAssetId x5f0_;
CAssetId x5f4_;
CAssetId x5f8_;
CAssetId x5fc_;
CAssetId x5f0_beamContactFxId;
CAssetId x5f4_beamPulseFxId;
CAssetId x5f8_beamTextureId;
CAssetId x5fc_beamGlowTextureId;
TUniqueId x600_headActor = kInvalidUniqueId;
TUniqueId x602_pelvisActor = kInvalidUniqueId;
zeus::CVector3f x604_predictedPlayerPos;
zeus::CVector3f x610_lookPos;
zeus::CVector3f x61c_;
float x628_ = 0.f;
zeus::CVector3f x61c_startPlayerPos;
float x628_firingTime = 0.f;
zeus::CVector3f x62c_targetPos;
float x638_ = 0.2f;
float x63c_attackTime = 8.f;
@ -48,8 +48,9 @@ class CNewIntroBoss : public CPatterned {
public:
DEFINE_PATTERNED(NewIntroBoss)
CNewIntroBoss(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,
CModelData&& mData, const CPatternedInfo& pInfo, const CActorParameters& actParms, float, CAssetId,
const CDamageInfo& dInfo, CAssetId, CAssetId, CAssetId, CAssetId);
CModelData&& mData, const CPatternedInfo& pInfo, const CActorParameters& actParms,
float f1, CAssetId projectile, const CDamageInfo& dInfo, CAssetId beamContactFxId,
CAssetId beamPulseFxId, CAssetId beamTextureId, CAssetId beamGlowTextureId);
void Accept(IVisitor& visitor);
void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager&);

View File

@ -5,62 +5,87 @@
#include "zeus/CColor.hpp"
namespace urde {
struct CBeamInfo {
class CBeamInfo {
u32 x0_;
s32 x4_;
CAssetId x8_;
CAssetId xc_;
CAssetId x10_;
CAssetId x14_;
s32 x18_;
float x1c_;
float x20_;
float x24_;
float x28_;
float x2c_;
float x30_;
float x34_;
float x38_;
zeus::CColor x3c_;
zeus::CColor x40_;
/*
* 0x1: motion blur
* 0x2: pulse effect
* 0x4: one shot
* 0x8: phazon damage
*/
s32 x4_beamAttributes;
CAssetId x8_contactFxId;
CAssetId xc_pulseFxId;
CAssetId x10_textureId;
CAssetId x14_glowTextureId;
s32 x18_length;
float x1c_radius;
float x20_expansionSpeed;
float x24_lifeTime;
float x28_pulseSpeed;
float x2c_shutdownTime;
float x30_contactFxScale;
float x34_pulseFxScale;
float x38_travelSpeed;
zeus::CColor x3c_innerColor;
zeus::CColor x40_outerColor;
public:
CBeamInfo(CInputStream& in)
: x0_(in.readUint32Big())
, x4_(in.readUint32Big())
, x8_(in.readUint32Big())
, xc_(in.readUint32Big())
, x10_(in.readUint32Big())
, x14_(in.readUint32Big())
, x18_(in.readFloatBig())
, x1c_(in.readFloatBig())
, x20_(in.readFloatBig())
, x24_(in.readFloatBig())
, x28_(in.readFloatBig())
, x2c_(in.readFloatBig())
, x30_(in.readFloatBig())
, x34_(in.readFloatBig())
, x38_(in.readFloatBig())
, x3c_(zeus::CColor::ReadRGBABig(in))
, x40_(zeus::CColor::ReadRGBABig(in)) {}
, x4_beamAttributes(in.readUint32Big())
, x8_contactFxId(in.readUint32Big())
, xc_pulseFxId(in.readUint32Big())
, x10_textureId(in.readUint32Big())
, x14_glowTextureId(in.readUint32Big())
, x18_length(in.readFloatBig())
, x1c_radius(in.readFloatBig())
, x20_expansionSpeed(in.readFloatBig())
, x24_lifeTime(in.readFloatBig())
, x28_pulseSpeed(in.readFloatBig())
, x2c_shutdownTime(in.readFloatBig())
, x30_contactFxScale(in.readFloatBig())
, x34_pulseFxScale(in.readFloatBig())
, x38_travelSpeed(in.readFloatBig())
, x3c_innerColor(zeus::CColor::ReadRGBABig(in))
, x40_outerColor(zeus::CColor::ReadRGBABig(in)) {}
CBeamInfo(s32 w1, CAssetId w2, CAssetId w3, CAssetId w4, CAssetId w5, s32 w6, float f1, float f2, float f3, float f4,
float f5, float f6, float f7, const zeus::CColor& col1, const zeus::CColor& col2, float f8)
: x4_(w1)
, x8_(w2)
, xc_(w3)
, x10_(w4)
, x14_(w5)
, x18_(w6)
, x1c_(f1)
, x20_(f2)
, x24_(f3)
, x28_(f4)
, x2c_(f5)
, x30_(f6)
, x34_(f7)
, x38_(f8)
, x3c_(col1)
, x40_(col2) {}
CBeamInfo(s32 beamAttributes, CAssetId contactFxId, CAssetId pulseFxId, CAssetId textureId, CAssetId glowTextureId,
s32 length, float radius, float f2, float f3, float f4, float f5, float contactFxScale, float pulseFxScale,
const zeus::CColor& innerColor, const zeus::CColor& outerColor, float travelSpeed)
: x4_beamAttributes(beamAttributes)
, x8_contactFxId(contactFxId)
, xc_pulseFxId(pulseFxId)
, x10_textureId(textureId)
, x14_glowTextureId(glowTextureId)
, x18_length(length)
, x1c_radius(radius)
, x20_expansionSpeed(f2)
, x24_lifeTime(f3)
, x28_pulseSpeed(f4)
, x2c_shutdownTime(f5)
, x30_contactFxScale(contactFxScale)
, x34_pulseFxScale(pulseFxScale)
, x38_travelSpeed(travelSpeed)
, x3c_innerColor(innerColor)
, x40_outerColor(outerColor) {}
s32 GetBeamAttributes() const { return x4_beamAttributes; }
CAssetId GetContactFxId() const { return x8_contactFxId; }
CAssetId GetPulseFxId() const { return xc_pulseFxId; }
CAssetId GetTextureId() const { return x10_textureId; }
CAssetId GetGlowTextureId() const { return x14_glowTextureId; }
s32 GetLength() const { return x18_length; }
float GetRadius() const { return x1c_radius; }
float GetExpansionSpeed() const { return x20_expansionSpeed; }
float GetLifeTime() const { return x24_lifeTime; }
float GetPulseSpeed() const { return x28_pulseSpeed; }
float GetShutdownTime() const { return x2c_shutdownTime; }
float GetContactFxScale() const { return x30_contactFxScale; }
float GetPulseFxScale() const { return x34_pulseFxScale; }
float GetTravelSpeed() const { return x38_travelSpeed; }
const zeus::CColor& GetInnerColor() const { return x3c_innerColor; }
const zeus::CColor& GetOuterColor() const { return x40_outerColor; }
};
} // namespace urde

View File

@ -1,41 +1,91 @@
#include "Weapon/CBeamProjectile.hpp"
#include "TCastTo.hpp"
#include "CStateManager.hpp"
namespace urde {
CBeamProjectile::CBeamProjectile(const TToken<CWeaponDescription>& wDesc, std::string_view name, EWeaponType wType,
const zeus::CTransform& xf, s32 flags, float f1, float f2, EMaterialTypes matType,
const CDamageInfo& dInfo, TUniqueId uid, TAreaId aid, TUniqueId owner,
EProjectileAttrib attribs, bool b1)
const zeus::CTransform& xf, s32 maxLength, float beamRadius, float travelSpeed,
EMaterialTypes matType, const CDamageInfo& dInfo, TUniqueId uid, TAreaId aid,
TUniqueId owner, EProjectileAttrib attribs, bool growingBeam)
: CGameProjectile(false, wDesc, name, wType, xf, matType, dInfo, uid, aid, owner, kInvalidUniqueId, attribs, false,
zeus::CVector3f::skOne, {}, -1, false)
, x2e8_(std::abs(flags))
, x2ec_(x2e8_)
, x2f0_(1.f / x2ec_)
, x2f4_(f1)
, x300_(b1 == false ? x2ec_ : 0.f)
, x308_(f2)
, x464_24_(b1)
, x464_25_(false) {}
zeus::CVector3f::skOne, {}, 0xffff, false)
, x2e8_intMaxLength(std::abs(maxLength))
, x2ec_maxLength(x2e8_intMaxLength)
, x2f0_invMaxLength(1.f / x2ec_maxLength)
, x2f4_beamRadius(beamRadius)
, x300_intBeamLength(growingBeam ? 0.f : x2ec_maxLength)
, x304_beamLength(x2ec_maxLength)
, x308_travelSpeed(travelSpeed)
, x464_24_growingBeam(growingBeam)
, x464_25_enableTouchDamage(false) {
x384_.resize(10);
x400_pointCache.resize(8);
}
std::experimental::optional<zeus::CAABox> CBeamProjectile::GetTouchBounds() const {
if (!GetActive())
return {};
if (!x464_25_) {
if (x464_25_enableTouchDamage) {
zeus::CVector3f pos = GetTranslation();
return {{pos - 1.f, pos + 1.f}};
return {{pos - 0.1f, pos + 0.1f}};
}
return {};
}
void CBeamProjectile::CalculateRenderBounds() { x9c_renderBounds = x354_.getTransformedAABox(x324_); }
void CBeamProjectile::CalculateRenderBounds() { x9c_renderBounds = x354_.getTransformedAABox(x324_xf); }
void CBeamProjectile::ResetBeam(CStateManager&, bool) {
if (x464_24_)
x300_ = 0.f;
if (x464_24_growingBeam)
x300_intBeamLength = 0.f;
}
void CBeamProjectile::UpdateFX(const zeus::CTransform&, float, CStateManager&) {}
void CBeamProjectile::SetCollisionResultData(EDamageType dType, CRayCastResult& res, TUniqueId id) {
x2f8_damageType = dType;
x304_beamLength = res.GetT();
x318_collisionPoint = res.GetPoint();
x30c_collisionNormal = res.GetPlane().normal();
x2fe_collisionActorId = dType == EDamageType::Actor ? id : kInvalidUniqueId;
SetTranslation(res.GetPoint());
}
void CBeamProjectile::UpdateFx(const zeus::CTransform& xf, float dt, CStateManager& mgr) {
if (!GetActive())
return;
SetTransform(xf.getRotation());
if (x464_24_growingBeam) {
x300_intBeamLength += x308_travelSpeed * dt;
if (x300_intBeamLength > x2ec_maxLength)
x300_intBeamLength = x2ec_maxLength;
}
x304_beamLength = x300_intBeamLength;
x2f8_damageType = EDamageType::None;
x298_previousPos = xf.origin;
zeus::CVector3f beamEnd = xf.basis[1].normalized() * x300_intBeamLength + xf.origin;
SetTranslation(beamEnd);
x354_ = zeus::CAABox(zeus::CVector3f{-x2f4_beamRadius, 0.f, -x2f4_beamRadius},
zeus::CVector3f{x2f4_beamRadius, x304_beamLength, x2f4_beamRadius});
x36c_ = zeus::CAABox(zeus::CVector3f{-x2f4_beamRadius, 0.f, -x2f4_beamRadius},
zeus::CVector3f{x2f4_beamRadius, x300_intBeamLength, x2f4_beamRadius}).getTransformedAABox(xf);
rstl::reserved_vector<TUniqueId, 1024> nearList;
mgr.BuildNearList(nearList, x36c_, CMaterialFilter::MakeExclude({EMaterialTypes::ProjectilePassthrough}), nullptr);
TUniqueId collideId = kInvalidUniqueId;
CRayCastResult res = RayCollisionCheckWithWorld(collideId, x298_previousPos, beamEnd, x300_intBeamLength, nearList, mgr);
if (TCastToPtr<CActor> act = mgr.ObjectById(collideId)) {
SetCollisionResultData(EDamageType::Actor, res, collideId);
if (x464_25_enableTouchDamage)
ApplyDamageToActors(mgr, CDamageInfo(x12c_curDamageInfo, dt));
} else if (res.IsValid()) {
SetCollisionResultData(EDamageType::World, res, kInvalidUniqueId);
if (x464_25_enableTouchDamage)
mgr.ApplyDamageToWorld(xec_ownerId, *this, res.GetPoint(), CDamageInfo(x12c_curDamageInfo, dt), xf8_filter);
} else {
x318_collisionPoint = xf * zeus::CVector3f(x2f4_beamRadius, x304_beamLength, x2f4_beamRadius);
SetTranslation(x318_collisionPoint);
}
x324_xf = xf;
}
void CBeamProjectile::Accept(urde::IVisitor& visitor) { visitor.Visit(this); }

View File

@ -3,48 +3,61 @@
#include "Weapon/CGameProjectile.hpp"
namespace urde {
class CBeamProjectile : public CGameProjectile {
u32 x2e8_;
float x2ec_;
float x2f0_;
float x2f4_;
u32 x2f8_ = 0;
public:
enum class EDamageType {
None,
Actor,
World
};
private:
s32 x2e8_intMaxLength;
float x2ec_maxLength;
float x2f0_invMaxLength;
float x2f4_beamRadius;
EDamageType x2f8_damageType = EDamageType::None;
TUniqueId x2fc_ = kInvalidUniqueId;
TUniqueId x2fe_ = kInvalidUniqueId;
float x300_;
float x304_;
float x308_;
zeus::CVector3f x30c_ = zeus::CVector3f::skUp;
zeus::CTransform x324_;
TUniqueId x2fe_collisionActorId = kInvalidUniqueId;
float x300_intBeamLength;
float x304_beamLength;
float x308_travelSpeed;
zeus::CVector3f x30c_collisionNormal = zeus::CVector3f::skUp;
zeus::CVector3f x318_collisionPoint = zeus::CVector3f::skZero;
zeus::CTransform x324_xf;
zeus::CAABox x354_ = zeus::CAABox::skNullBox;
zeus::CAABox x36c_ = zeus::CAABox::skNullBox;
rstl::reserved_vector<zeus::CVector3f, 10> x384_;
rstl::reserved_vector<zeus::CVector3f, 8> x400_;
bool x464_24_ : 1;
bool x464_25_ : 1;
rstl::reserved_vector<zeus::CVector3f, 8> x400_pointCache;
bool x464_24_growingBeam : 1;
bool x464_25_enableTouchDamage : 1;
void SetCollisionResultData(EDamageType dType, CRayCastResult& res, TUniqueId id);
public:
CBeamProjectile(const TToken<CWeaponDescription>& wDesc, std::string_view name, EWeaponType wType,
const zeus::CTransform& xf, s32 flags, float f1, float f2, EMaterialTypes matType,
const CDamageInfo& dInfo, TUniqueId uid, TAreaId aid, TUniqueId owner, EProjectileAttrib attribs,
bool b1);
const zeus::CTransform& xf, s32 maxLength, float beamRadius, float travelSpeed,
EMaterialTypes matType, const CDamageInfo& dInfo, TUniqueId uid, TAreaId aid, TUniqueId owner,
EProjectileAttrib attribs, bool growingBeam);
void Accept(IVisitor& visitor);
float GetMaxRadius() const;
zeus::CVector3f GetSurfaceNormal() const;
void GetDamageType() const;
void GetCurrentPos() const;
void PointCache();
void GetPointCache() const;
void CauseDamage(bool);
zeus::CVector3f GetBeamOrigin() const;
void GetInvMaxLength() const;
void GetCurrentLength();
void GetMaxLength();
s32 GetIntMaxLength();
float GetMaxRadius() const { return x2f4_beamRadius; }
const zeus::CVector3f& GetSurfaceNormal() const { return x30c_collisionNormal; }
EDamageType GetDamageType() const { return x2f8_damageType; }
const zeus::CVector3f& GetCurrentPos() const { return x318_collisionPoint; }
rstl::reserved_vector<zeus::CVector3f, 8>& PointCache() { return x400_pointCache; }
const rstl::reserved_vector<zeus::CVector3f, 8>& GetPointCache() const { return x400_pointCache; }
void CauseDamage(bool b) { x464_25_enableTouchDamage = b; }
const zeus::CTransform& GetBeamTransform() const { return x324_xf; }
float GetInvMaxLength() const { return x2f0_invMaxLength; }
float GetCurrentLength() const { return x304_beamLength; }
float GetMaxLength() const { return x2ec_maxLength; }
s32 GetIntMaxLength() const { return x2e8_intMaxLength; }
TUniqueId GetCollisionActorId() const { return x2fe_collisionActorId; }
std::experimental::optional<zeus::CAABox> GetTouchBounds() const;
void CalculateRenderBounds();
virtual void ResetBeam(CStateManager&, bool);
virtual void UpdateFX(const zeus::CTransform&, float, CStateManager&);
virtual void UpdateFx(const zeus::CTransform&, float, CStateManager&);
virtual void Fire(const zeus::CTransform&, CStateManager&, bool) = 0;
};
} // namespace urde

View File

@ -28,7 +28,7 @@ CGameProjectile::CGameProjectile(bool active, const TToken<CWeaponDescription>&
, x168_visorSfx(visorSfx)
, x170_projectile(wDesc, xf.origin, xf.basis, scale,
(attribs & EProjectileAttrib::ParticleOPTS) == EProjectileAttrib::ParticleOPTS)
, x298_lastOrigin(xf.origin)
, x298_previousPos(xf.origin)
, x2a4_projExtent((xe8_projectileAttribs & EProjectileAttrib::BigProjectile) == EProjectileAttrib::BigProjectile ? 0.25f
: 0.1f)
, x2c0_homingTargetId(homingTarget)
@ -186,7 +186,7 @@ void CGameProjectile::UpdateProjectileMovement(float dt, CStateManager& mgr) {
if (x2e4_26_waterUpdate)
useDt = 37.5f * dt * dt;
x298_lastOrigin = x34_transform.origin;
x298_previousPos = x34_transform.origin;
x170_projectile.Update(useDt);
SetTransform(x170_projectile.GetTransform());
SetTranslation(x170_projectile.GetTranslation());
@ -196,12 +196,12 @@ void CGameProjectile::UpdateProjectileMovement(float dt, CStateManager& mgr) {
CRayCastResult CGameProjectile::DoCollisionCheck(TUniqueId& idOut, CStateManager& mgr) {
CRayCastResult res;
if (x2e4_24_active) {
zeus::CVector3f posDelta = x34_transform.origin - x298_lastOrigin;
zeus::CVector3f posDelta = x34_transform.origin - x298_previousPos;
rstl::reserved_vector<TUniqueId, 1024> nearList;
mgr.BuildNearList(nearList, GetProjectileBounds(),
CMaterialFilter::MakeExclude(EMaterialTypes::ProjectilePassthrough), this);
res = RayCollisionCheckWithWorld(idOut, x298_lastOrigin, x34_transform.origin, posDelta.magnitude(), nearList, mgr);
res = RayCollisionCheckWithWorld(idOut, x298_previousPos, x34_transform.origin, posDelta.magnitude(), nearList, mgr);
}
return res;
}
@ -335,25 +335,25 @@ CProjectileTouchResult CGameProjectile::CanCollideWithComplexCollision(CActor& a
if (useAct) {
const CCollisionPrimitive* prim = useAct->GetCollisionPrimitive();
zeus::CTransform xf = useAct->GetPrimitiveTransform();
zeus::CVector3f deltaPos = GetTranslation() - x298_lastOrigin;
zeus::CVector3f deltaPos = GetTranslation() - x298_previousPos;
if (deltaPos.canBeNormalized()) {
zeus::CVector3f dir = deltaPos.normalized();
float mag = deltaPos.magnitude();
CRayCastResult res = prim->CastRayInternal(
{x298_lastOrigin, dir, mag, xf,
{x298_previousPos, dir, mag, xf,
CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {EMaterialTypes::ProjectilePassthrough})});
if (!res.IsValid()) {
if (prim->GetPrimType() == FOURCC('SPHR')) {
mag *= 2.f;
CRayCastResult res2 = prim->CastRayInternal(
{x298_lastOrigin - dir * mag, dir, deltaPos.magnitude(), xf,
{x298_previousPos - dir * mag, dir, deltaPos.magnitude(), xf,
CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {EMaterialTypes::ProjectilePassthrough})});
if (res2.IsValid())
return {act.GetUniqueId(), {res2}};
} else if (TCastToPtr<CCollisionActor> cAct = act) {
float rad = cAct->GetSphereRadius();
if ((x298_lastOrigin - GetTranslation()).magSquared() < rad * rad) {
zeus::CVector3f point = x298_lastOrigin - dir * rad * 1.125f;
if ((x298_previousPos - GetTranslation()).magSquared() < rad * rad) {
zeus::CVector3f point = x298_previousPos - dir * rad * 1.125f;
zeus::CUnitVector3f revDir(-dir);
return {act.GetUniqueId(), {{0.f, point, {revDir, point.dot(revDir)}, act.GetMaterialList()}}};
}
@ -415,12 +415,12 @@ CProjectileTouchResult CGameProjectile::CanCollideWithTrigger(CActor& act, CStat
}
zeus::CAABox CGameProjectile::GetProjectileBounds() const {
return {{std::min(x298_lastOrigin.x(), GetTranslation().x()) - x2a4_projExtent,
std::min(x298_lastOrigin.y(), GetTranslation().y()) - x2a4_projExtent,
std::min(x298_lastOrigin.z(), GetTranslation().z()) - x2a4_projExtent},
{std::max(x298_lastOrigin.x(), GetTranslation().x()) + x2a4_projExtent,
std::max(x298_lastOrigin.y(), GetTranslation().y()) + x2a4_projExtent,
std::max(x298_lastOrigin.z(), GetTranslation().z()) + x2a4_projExtent}};
return {{std::min(x298_previousPos.x(), GetTranslation().x()) - x2a4_projExtent,
std::min(x298_previousPos.y(), GetTranslation().y()) - x2a4_projExtent,
std::min(x298_previousPos.z(), GetTranslation().z()) - x2a4_projExtent},
{std::max(x298_previousPos.x(), GetTranslation().x()) + x2a4_projExtent,
std::max(x298_previousPos.y(), GetTranslation().y()) + x2a4_projExtent,
std::max(x298_previousPos.z(), GetTranslation().z()) + x2a4_projExtent}};
}
std::experimental::optional<zeus::CAABox> CGameProjectile::GetTouchBounds() const {

View File

@ -30,7 +30,7 @@ protected:
std::experimental::optional<TLockedToken<CGenDescription>> x158_visorParticle;
u16 x168_visorSfx;
CProjectileWeapon x170_projectile;
zeus::CVector3f x298_lastOrigin;
zeus::CVector3f x298_previousPos;
float x2a4_projExtent;
float x2a8_homingDt = 0.03f;
double x2b0_targetHomingTime = 0.0;
@ -83,6 +83,6 @@ public:
zeus::CAABox GetProjectileBounds() const;
std::experimental::optional<zeus::CAABox> GetTouchBounds() const;
TUniqueId GetHomingTargetId() const { return x2c0_homingTargetId; }
zeus::CVector3f GetPreviousPos() const { return x298_lastOrigin; }
zeus::CVector3f GetPreviousPos() const { return x298_previousPos; }
};
} // namespace urde

View File

@ -1,17 +1,436 @@
#include "CPlasmaProjectile.hpp"
#include "TCastTo.hpp"
#include "GameGlobalObjects.hpp"
#include "CSimplePool.hpp"
#include "World/CGameLight.hpp"
#include "CStateManager.hpp"
#include "Graphics/CBooRenderer.hpp"
#include "World/CPlayer.hpp"
#include "World/CHUDBillboardEffect.hpp"
namespace urde {
CPlasmaProjectile::RenderObjects::RenderObjects(boo::IGraphicsDataFactory::Context& ctx,
boo::ObjToken<boo::ITexture> tex,
boo::ObjToken<boo::ITexture> glowTex)
: m_beamStrip1(ctx, 8, CColoredStripShader::Mode::Additive, {})
, m_beamStrip2(ctx, 10, CColoredStripShader::Mode::FullAdditive, tex)
, m_beamStrip3(ctx, 18, CColoredStripShader::Mode::FullAdditive, tex)
, m_beamStrip4(ctx, 14, CColoredStripShader::Mode::Additive, glowTex)
, m_motionBlurStrip(ctx, 16, CColoredStripShader::Mode::Alpha, {}) {}
CPlasmaProjectile::CPlasmaProjectile(const TToken<CWeaponDescription>& wDesc, std::string_view name, EWeaponType wType,
const CBeamInfo& bInfo, const zeus::CTransform& xf, EMaterialTypes matType,
const CDamageInfo& dInfo, TUniqueId uid, TAreaId aid, TUniqueId owner, u32 w1,
bool b1, EProjectileAttrib attribs)
: CBeamProjectile(wDesc, name, wType, xf, bInfo.x18_, bInfo.x1c_, bInfo.x38_, matType, dInfo, uid, aid, owner, attribs,
b1) {}
const CDamageInfo& dInfo, TUniqueId uid, TAreaId aid, TUniqueId owner,
const PlayerEffectResoures& res, bool growingBeam, EProjectileAttrib attribs)
: CBeamProjectile(wDesc, name, wType, xf, bInfo.GetLength(), bInfo.GetRadius(), bInfo.GetTravelSpeed(), matType,
dInfo, uid, aid, owner, attribs, growingBeam)
, x478_beamAttributes(bInfo.GetBeamAttributes())
, x47c_lifeTime(bInfo.GetLifeTime())
, x480_pulseSpeed(bInfo.GetPulseSpeed())
, x484_shutdownTime(bInfo.GetShutdownTime())
, x488_expansionSpeed(bInfo.GetExpansionSpeed())
, x48c_(bInfo.GetLength() / 32.f)
, x490_innerColor(bInfo.GetInnerColor())
, x494_outerColor(bInfo.GetOuterColor()) {
x4e8_texture = g_SimplePool->GetObj(SObjectTag{FOURCC('TXTR'), bInfo.GetTextureId()});
x4f4_glowTexture = g_SimplePool->GetObj(SObjectTag{FOURCC('TXTR'), bInfo.GetGlowTextureId()});
x500_contactFxDesc = g_SimplePool->GetObj(SObjectTag{FOURCC('PART'), bInfo.GetContactFxId()});
x50c_pulseFxDesc = g_SimplePool->GetObj(SObjectTag{FOURCC('PART'), bInfo.GetPulseFxId()});
x518_contactGen = std::make_unique<CElementGen>(x500_contactFxDesc, CElementGen::EModelOrientationType::One);
x51c_pulseGen = std::make_unique<CElementGen>(x50c_pulseFxDesc, CElementGen::EModelOrientationType::Normal);
x524_freezeSteamTxtr = res[0];
x528_freezeIceTxtr = res[1];
if (res[2] != UINT64_MAX)
x52c_visorElectric = g_SimplePool->GetObj(SObjectTag{FOURCC('ELSC'), res[2]});
if (res[3] != UINT64_MAX)
x538_visorParticle = g_SimplePool->GetObj(SObjectTag{FOURCC('PART'), res[3]});
x544_freezeSfx = CSfxManager::TranslateSFXID(res[4]);
x546_electricSfx = CSfxManager::TranslateSFXID(res[5]);
x548_25_enableEnergyPulse = true;
x548_28_drawOwnerFirst = growingBeam;
x518_contactGen->SetGlobalScale(zeus::CVector3f(bInfo.GetContactFxScale()));
x51c_pulseGen->SetGlobalScale(zeus::CVector3f(bInfo.GetPulseFxScale()));
x518_contactGen->SetParticleEmission(false);
x51c_pulseGen->SetParticleEmission(false);
CGraphics::CommitResources([this](boo::IGraphicsDataFactory::Context& ctx) {
m_renderObjs.emplace(ctx, x4e8_texture->GetBooTexture(), x4f4_glowTexture->GetBooTexture());
return true;
} BooTrace);
}
void CPlasmaProjectile::Accept(IVisitor& visitor) { visitor.Visit(this); }
void CPlasmaProjectile::Fire(const zeus::CTransform&, CStateManager&, bool) { SetActive(true); }
void CPlasmaProjectile::SetLightsActive(bool active, CStateManager& mgr) {
for (TUniqueId lid : x468_lights) {
if (lid != kInvalidUniqueId) {
if (TCastToPtr<CGameLight> light = mgr.ObjectById(lid)) {
light->SetActive(active);
}
}
}
}
void CPlasmaProjectile::CreatePlasmaLights(u32 sourceId, const CLight& l, CStateManager& mgr) {
DeletePlasmaLights(mgr);
x468_lights.reserve(3);
for (int i = 0; i < 3; ++i) {
TUniqueId lid = mgr.AllocateUniqueId();
auto* light =
new CGameLight(lid, GetAreaId(), GetActive(), ""sv, GetTransform(), GetUniqueId(), l, sourceId, 0, 0.f);
mgr.AddObject(light);
x468_lights.push_back(lid);
}
}
void CPlasmaProjectile::DeletePlasmaLights(CStateManager& mgr) {
for (TUniqueId lid : x468_lights)
mgr.FreeScriptObject(lid);
x468_lights.clear();
}
void CPlasmaProjectile::UpdateLights(float expansion, float dt, CStateManager& mgr) {
if (x520_weaponGen) {
x520_weaponGen->Update(dt);
CLight l = x520_weaponGen->GetLight();
l.SetColor(zeus::CColor::lerp(zeus::CColor::skClear, l.GetColor(), expansion));
float halfLen = 0.5f * GetCurrentLength();
float y = 0.f;
for (TUniqueId lid : x468_lights) {
if (TCastToPtr<CGameLight> light = mgr.ObjectById(lid)) {
light->SetTransform({});
light->SetTranslation(GetBeamTransform() * zeus::CVector3f(0.f, y, 0.f));
light->SetLight(l);
}
y += halfLen;
}
}
}
void CPlasmaProjectile::UpdateEnergyPulse(float dt) {
if (GetDamageType() != EDamageType::None && x548_25_enableEnergyPulse) {
x4d8_energyPulseTimer -= dt;
if (x4d8_energyPulseTimer <= 0.f) {
x4d8_energyPulseTimer = 2.f * dt;
x51c_pulseGen->SetParticleEmission(true);
float t = GetCurrentLength() / GetMaxLength();
for (float i = 0.f; i <= t; i += 0.1f) {
float y = i * GetMaxLength() + x4cc_energyPulseStartY;
if (y > GetCurrentLength())
continue;
x51c_pulseGen->SetTranslation({0.f, y, 0.f});
x51c_pulseGen->ForceParticleCreation(1);
}
x51c_pulseGen->SetGlobalOrientAndTrans(GetBeamTransform());
x51c_pulseGen->SetParticleEmission(false);
}
}
x51c_pulseGen->Update(dt);
}
void CPlasmaProjectile::RenderMotionBlur() const {
CGraphics::SetModelMatrix({});
zeus::CColor color1 = x494_outerColor;
zeus::CColor color2 = x494_outerColor;
color1.a() = 63.f / 255.f;
color2.a() = 0.f;
CColoredStripShader::Vert verts[16];
for (int i = 0; i < 8; ++i) {
auto& v1 = verts[i * 2];
auto& v2 = verts[i * 2 + 1];
v1.m_pos = GetBeamTransform().origin;
v1.m_color = zeus::CColor::lerp(color1, color2, i / 8.f);
v2.m_pos = GetPointCache()[i];
v2.m_color = v1.m_color;
}
m_renderObjs->m_motionBlurStrip.draw(zeus::CColor::skWhite, 16, verts);
}
void CPlasmaProjectile::RenderBeam(s32 subdivs, float width, const zeus::CColor& color, s32 flags,
CColoredStripShader& shader) const {
// Flags: 0x1: textured, 0x2: length controlled UVY 0x4: alpha controlled additive blend,
// 0x8: glow texture, 0x10: subtractive blend
if ((flags & 0x1) == 0 || (flags & 0x8) ? x4f4_glowTexture.IsLoaded() : x4e8_texture.IsLoaded()) {
float angIncrement = 2.f * M_PIF / float(subdivs);
float uvY1 = -(x4cc_energyPulseStartY / 16.f);
float uvY2 = (uvY1 + float((flags & 0x3) == 0x3) != 0.f) ? 2.f : 0.5f * GetCurrentLength();
CColoredStripShader::Vert verts[18];
s32 numNodes = subdivs + 1;
float angle = 0.f;
bool flip = false;
for (s32 i = 0; i < numNodes; ++i) {
CColoredStripShader::Vert& v0 = verts[i * 2];
CColoredStripShader::Vert& v1 = verts[i * 2 + 1];
float x = std::cos(angle);
float y = std::sin(angle);
float uvX;
if (flags & 0x8)
uvX = 0.5f * y;
else if (flip)
uvX = width;
else
uvX = 0.f;
flip ^= true;
v0.m_pos = zeus::CVector3f(width * x, 0.f, width * y);
v0.m_color = color;
v0.m_uv = zeus::CVector2f(uvX, uvY1);
v1.m_pos = zeus::CVector3f(width * x, GetCurrentLength(), width * y);
v1.m_color = color;
v1.m_uv = zeus::CVector2f(uvX, uvY2);
angle += angIncrement;
}
shader.draw(zeus::CColor::skWhite, numNodes * 2, verts);
}
}
void CPlasmaProjectile::ResetBeam(CStateManager& mgr, bool fullReset) {
if (fullReset) {
SetActive(false);
SetLightsActive(false, mgr);
x4bc_lifeTimer = 0.f;
x4c0_expansionT = 0.f;
x4c8_beamAngle = 0.f;
x4d0_shutdownTimer = 0.f;
x4d4_contactPulseTimer = 0.f;
x4d8_energyPulseTimer = 0.f;
x4dc_playerEffectPulseTimer = 0.f;
x4b4_expansionState = EExpansionState::Inactive;
x548_26_firing = false;
x518_contactGen->SetParticleEmission(false);
x51c_pulseGen->SetParticleEmission(false);
} else {
x548_26_firing = false;
x4b4_expansionState = EExpansionState::Release;
x518_contactGen->SetParticleEmission(false);
x51c_pulseGen->SetParticleEmission(false);
}
}
float CPlasmaProjectile::UpdateBeamState(float dt, CStateManager& mgr) {
switch (x4b4_expansionState) {
case EExpansionState::Attack:
if (x4c0_expansionT > 0.5f)
x4b4_expansionState = EExpansionState::Sustain;
else
x4c0_expansionT += dt * x488_expansionSpeed;
break;
case EExpansionState::Sustain:
if (x478_beamAttributes & 0x4) {
if (x4bc_lifeTimer > x47c_lifeTime)
x4b4_expansionState = EExpansionState::Release;
else
x4bc_lifeTimer += dt;
}
break;
case EExpansionState::Release:
x4c0_expansionT += dt * x488_expansionSpeed;
if (x4c0_expansionT > 1.f) {
x4c0_expansionT = 1.f;
x4b4_expansionState = EExpansionState::Done;
x548_25_enableEnergyPulse = false;
}
break;
case EExpansionState::Done:
x4d0_shutdownTimer += dt;
if (x4d0_shutdownTimer > x484_shutdownTime &&
(!x518_contactGen || x518_contactGen->GetParticleCountAll() == 0)) {
x4b4_expansionState = EExpansionState::Inactive;
ResetBeam(mgr, true);
}
break;
default:
break;
}
return -4.f * x4c0_expansionT * (x4c0_expansionT - 1.f);
}
void CPlasmaProjectile::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr) {
switch (msg) {
case EScriptObjectMessage::Registered: {
xe6_27_thermalVisorFlags = 2;
const SChildGeneratorDesc& apsm = x170_projectile.GetWeaponDescription()->x34_APSM;
if (apsm)
x520_weaponGen = std::make_unique<CElementGen>(apsm.m_token);
if (x520_weaponGen && x520_weaponGen->SystemHasLight())
CreatePlasmaLights(x170_projectile.GetWeaponDescription().GetObjectTag()->id.Value(),
x520_weaponGen->GetLight(), mgr);
else
x520_weaponGen.reset();
if (x548_28_drawOwnerFirst)
xc6_nextDrawNode = xec_ownerId;
mgr.AddWeaponId(xec_ownerId, xf0_weaponType);
break;
}
case EScriptObjectMessage::Deleted:
mgr.RemoveWeaponId(xec_ownerId, xf0_weaponType);
DeletePlasmaLights(mgr);
if (x548_29_activePlayerPhazon) {
mgr.GetPlayer().DecrementPhazon();
x548_29_activePlayerPhazon = false;
}
break;
default:
break;
}
CGameProjectile::AcceptScriptMsg(msg, sender, mgr);
}
void CPlasmaProjectile::MakeBillboardEffect(const std::experimental::optional<TToken<CGenDescription>>& particle,
const std::experimental::optional<TToken<CElectricDescription>>& electric,
std::string_view name, CStateManager& mgr) {
auto* effect = new CHUDBillboardEffect(particle, electric, mgr.AllocateUniqueId(), true, name,
CHUDBillboardEffect::GetNearClipDistance(mgr),
CHUDBillboardEffect::GetScaleForPOV(mgr),
zeus::CColor::skWhite, zeus::CVector3f::skOne, zeus::CVector3f::skZero);
mgr.AddObject(effect);
}
void CPlasmaProjectile::UpdatePlayerEffects(float dt, CStateManager& mgr) {
x4dc_playerEffectPulseTimer -= dt;
if ((x4b4_expansionState == EExpansionState::Attack || x4b4_expansionState == EExpansionState::Sustain) &&
x4dc_playerEffectPulseTimer <= 0.f && GetDamageType() == EDamageType::Actor &&
GetCollisionActorId() == mgr.GetPlayer().GetUniqueId()) {
if ((x478_beamAttributes & 0x8) && !x548_29_activePlayerPhazon) {
x548_29_activePlayerPhazon = true;
x4e4_playerDamageTimer = 0.f;
mgr.GetPlayer().IncrementPhazon();
}
switch (xf0_weaponType) {
case EWeaponType::Ice:
mgr.GetPlayer().Freeze(mgr, x524_freezeSteamTxtr, x544_freezeSfx, x528_freezeIceTxtr);
break;
case EWeaponType::Wave:
if (x52c_visorElectric) {
MakeBillboardEffect({}, {x52c_visorElectric}, "PlasmaElectricFx"sv, mgr);
CSfxManager::SfxStart(x546_electricSfx, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId);
mgr.GetPlayer().SetHudDisable(3.f, 0.5f, 2.5f);
mgr.GetPlayer().SetOrbitRequestForTarget(mgr.GetPlayer().GetOrbitTargetId(),
CPlayer::EPlayerOrbitRequest::ActivateOrbitSource, mgr);
mgr.GetPlayerState()->GetStaticInterference().AddSource(GetUniqueId(), 0.2f, 3.f);
}
break;
case EWeaponType::Plasma:
if (x538_visorParticle)
MakeBillboardEffect({x538_visorParticle}, {}, "PlasmaVisorFx"sv, mgr);
break;
default:
break;
}
x4dc_playerEffectPulseTimer = 0.75f;
}
if (x548_29_activePlayerPhazon) {
CDamageInfo scaledDamage(x498_phazonDamage, dt);
mgr.ApplyDamage(GetUniqueId(), mgr.GetPlayer().GetUniqueId(), xec_ownerId, scaledDamage, xf8_filter,
zeus::CVector3f::skZero);
x4e4_playerDamageTimer += dt;
if (x4e4_playerDamageTimer >= x4e0_playerDamageDuration) {
mgr.GetPlayer().DecrementPhazon();
x4e4_playerDamageTimer = 0.f;
x548_29_activePlayerPhazon = false;
}
}
}
void CPlasmaProjectile::UpdateFx(const zeus::CTransform& xf, float dt, CStateManager& mgr) {
if (!GetActive())
return;
x548_27_texturesLoaded = x4e8_texture.IsLoaded() && x4f4_glowTexture.IsLoaded();
CauseDamage(x4b4_expansionState == EExpansionState::Attack || x4b4_expansionState == EExpansionState::Sustain);
CBeamProjectile::UpdateFx(xf, dt, mgr);
UpdatePlayerEffects(dt, mgr);
if (x478_beamAttributes & 0x1) {
for (int i = 7; i > 0; --i)
PointCache()[i] = PointCache()[i - 1];
PointCache()[0] = GetCurrentPos();
}
if (x518_contactGen) {
x4d4_contactPulseTimer -= dt;
if ((GetDamageType() != EDamageType::None ? x548_25_enableEnergyPulse : false) && x4d4_contactPulseTimer <= 0.f) {
x518_contactGen->SetOrientation(zeus::lookAt(zeus::CVector3f::skZero, GetSurfaceNormal()));
x518_contactGen->SetTranslation(GetSurfaceNormal() * 0.001f + GetCurrentPos());
x518_contactGen->SetParticleEmission(true);
x4d4_contactPulseTimer = 1.f / 16.f;
} else {
x518_contactGen->SetParticleEmission(false);
}
x518_contactGen->Update(dt);
}
float modulation = UpdateBeamState(dt, mgr);
UpdateEnergyPulse(dt);
x4c8_beamAngle += 720.f * dt;
if (x4c8_beamAngle > 360.f)
x4c8_beamAngle = 0.f;
x4b8_beamWidth = modulation * GetMaxRadius();
x4c4_expansion = modulation;
x4cc_energyPulseStartY += dt * x480_pulseSpeed;
if (x4cc_energyPulseStartY > 5.f)
x4cc_energyPulseStartY = 0.f;
UpdateLights(modulation, dt, mgr);
}
void CPlasmaProjectile::Fire(const zeus::CTransform& xf, CStateManager& mgr, bool b) {
SetActive(true);
SetLightsActive(true, mgr);
x548_25_enableEnergyPulse = true;
x548_26_firing = true;
x548_24_ = b;
x4b4_expansionState = EExpansionState::Attack;
if (x478_beamAttributes & 0x1)
std::fill(PointCache().begin(), PointCache().end(), xf.origin);
}
void CPlasmaProjectile::Touch(CActor& other, CStateManager& mgr) {
// Empty
}
bool CPlasmaProjectile::CanRenderUnsorted(const CStateManager& mgr) const {
return false;
}
void CPlasmaProjectile::AddToRenderer(const zeus::CFrustum& frustum, const CStateManager& mgr) const {
if (GetActive()) {
g_Renderer->AddParticleGen(*x518_contactGen);
if (x478_beamAttributes & 0x2) {
g_Renderer->AddParticleGen(*x51c_pulseGen);
}
}
EnsureRendered(mgr, GetBeamTransform().origin, GetSortingBounds(mgr));
}
void CPlasmaProjectile::Render(const CStateManager& mgr) const {
if (!GetActive())
return;
zeus::CTransform xf = GetBeamTransform();
// Subtractive blending for xray
s32 flags = mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::XRay ? 0x10 : 0x0;
if ((x478_beamAttributes & 0x1) == 0)
xf.origin += mgr.GetCameraManager()->GetGlobalCameraTranslation(mgr);
// Z test, no write
if ((x478_beamAttributes & 0x1) && x548_25_enableEnergyPulse && x4b4_expansionState != EExpansionState::Attack)
RenderMotionBlur();
// Pass1: alpha-controlled additive
CGraphics::SetModelMatrix(xf);
RenderBeam(3, 0.25f * x4b8_beamWidth, zeus::CColor(1.f, 0.3f), flags | 0x4, m_renderObjs->m_beamStrip1);
// Pass2: textured
CGraphics::SetModelMatrix(xf * zeus::CTransform::RotateY(zeus::degToRad(x4c8_beamAngle)));
RenderBeam(4, 0.5f * x4b8_beamWidth, x490_innerColor, flags | 0x1, m_renderObjs->m_beamStrip2);
// Pass3: textured | length-controlled UVY
CGraphics::SetModelMatrix(xf * zeus::CTransform::RotateY(zeus::degToRad(-x4c8_beamAngle)));
RenderBeam(8, x4b8_beamWidth, x494_outerColor, flags | 0x3, m_renderObjs->m_beamStrip3);
// Pass4: textured | alpha-controlled additive | glow texture
CGraphics::SetModelMatrix(xf);
RenderBeam(6, 1.25f * x4b8_beamWidth, x494_outerColor, flags | 0xd, m_renderObjs->m_beamStrip4);
}
} // namespace urde

View File

@ -3,18 +3,111 @@
#include "Weapon/CBeamProjectile.hpp"
#include "Weapon/CBeamInfo.hpp"
#include "World/CDamageInfo.hpp"
#include "Graphics/Shaders/CColoredStripShader.hpp"
namespace urde {
class CPlasmaProjectile : public CBeamProjectile {
public:
struct PlayerEffectResoures : rstl::reserved_vector<u64, 8> {
PlayerEffectResoures(u64 a = UINT64_MAX, u64 b = UINT64_MAX, u64 c = UINT64_MAX, u64 d = UINT64_MAX,
u64 e = UINT64_MAX, u64 f = UINT64_MAX, u64 g = UINT64_MAX, u64 h = UINT64_MAX)
: rstl::reserved_vector<u64, 8>({a, b, c, d, e, f, g, h}) {}
};
private:
std::vector<TUniqueId> x468_lights;
s32 x478_beamAttributes;
float x47c_lifeTime;
float x480_pulseSpeed;
float x484_shutdownTime;
float x488_expansionSpeed;
float x48c_;
zeus::CColor x490_innerColor;
zeus::CColor x494_outerColor;
CDamageInfo x498_phazonDamage;
enum class EExpansionState {
Inactive,
Attack,
Sustain,
Release,
Done
};
EExpansionState x4b4_expansionState = EExpansionState::Inactive;
float x4b8_beamWidth = 0.f;
float x4bc_lifeTimer = 0.f;
float x4c0_expansionT = 0.f;
float x4c4_expansion = 0.f;
float x4c8_beamAngle = 0.f;
float x4cc_energyPulseStartY = 0.f;
float x4d0_shutdownTimer = 0.f;
float x4d4_contactPulseTimer = 0.f;
float x4d8_energyPulseTimer = 0.f;
float x4dc_playerEffectPulseTimer = 0.f;
float x4e0_playerDamageDuration = 0.f;
float x4e4_playerDamageTimer = 0.f;
TLockedToken<CTexture> x4e8_texture;
TLockedToken<CTexture> x4f4_glowTexture;
TCachedToken<CGenDescription> x500_contactFxDesc;
TCachedToken<CGenDescription> x50c_pulseFxDesc;
std::unique_ptr<CElementGen> x518_contactGen;
std::unique_ptr<CElementGen> x51c_pulseGen;
std::unique_ptr<CElementGen> x520_weaponGen;
CAssetId x524_freezeSteamTxtr;
CAssetId x528_freezeIceTxtr;
TToken<CElectricDescription> x52c_visorElectric; // Used to be optional
TToken<CGenDescription> x538_visorParticle; // Used to be optional
u16 x544_freezeSfx;
u16 x546_electricSfx;
union {
struct {
bool x548_24_ : 1;
bool x548_25_enableEnergyPulse : 1;
bool x548_26_firing : 1;
bool x548_27_texturesLoaded : 1;
bool x548_28_drawOwnerFirst : 1;
bool x548_29_activePlayerPhazon : 1;
};
u32 _dummy3 = 0;
};
struct RenderObjects {
CColoredStripShader m_beamStrip1;
CColoredStripShader m_beamStrip2;
CColoredStripShader m_beamStrip3;
CColoredStripShader m_beamStrip4;
CColoredStripShader m_motionBlurStrip;
RenderObjects(boo::IGraphicsDataFactory::Context& ctx,
boo::ObjToken<boo::ITexture> tex,
boo::ObjToken<boo::ITexture> glowTex);
};
mutable std::optional<RenderObjects> m_renderObjs;
void SetLightsActive(bool active, CStateManager& mgr);
void CreatePlasmaLights(u32 sourceId, const CLight& l, CStateManager& mgr);
void DeletePlasmaLights(CStateManager& mgr);
void UpdateLights(float expansion, float dt, CStateManager& mgr);
void UpdateEnergyPulse(float dt);
void RenderMotionBlur() const;
void RenderBeam(s32 subdivs, float width, const zeus::CColor& color, s32 flags,
CColoredStripShader& shader) const;
float UpdateBeamState(float dt, CStateManager& mgr);
void MakeBillboardEffect(const std::experimental::optional<TToken<CGenDescription>>& particle,
const std::experimental::optional<TToken<CElectricDescription>>& electric,
std::string_view name, CStateManager& mgr);
void UpdatePlayerEffects(float dt, CStateManager& mgr);
public:
CPlasmaProjectile(const TToken<CWeaponDescription>& wDesc, std::string_view name, EWeaponType wType,
const CBeamInfo& bInfo, const zeus::CTransform& xf, EMaterialTypes matType,
const CDamageInfo& dInfo, TUniqueId uid, TAreaId aid, TUniqueId owner, u32 w1, bool b1,
EProjectileAttrib attribs);
const CDamageInfo& dInfo, TUniqueId uid, TAreaId aid, TUniqueId owner,
const PlayerEffectResoures& res, bool growingBeam, EProjectileAttrib attribs);
void Accept(IVisitor& visitor);
void UpdateFx(const zeus::CTransform&, float, CStateManager&) {}
void Fire(const zeus::CTransform&, CStateManager&, bool);
void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr);
void ResetBeam(CStateManager& mgr, bool fullReset);
void UpdateFx(const zeus::CTransform& xf, float dt, CStateManager& mgr);
void Fire(const zeus::CTransform& xf, CStateManager& mgr, bool b);
void Touch(CActor& other, CStateManager& mgr);
bool CanRenderUnsorted(const CStateManager& mgr) const;
void AddToRenderer(const zeus::CFrustum& frustum, const CStateManager& mgr) const;
void Render(const CStateManager& mgr) const;
};
} // namespace urde

View File

@ -304,7 +304,7 @@ void CPatterned::Think(float dt, CStateManager& mgr) {
x460_knockBackController.Update(thinkDt, mgr, *this);
x4e4_latestPredictedTranslation = GetTranslation() + PredictMotion(thinkDt).x0_translation;
x328_26_longJump = false;
x328_26_solidCollision = false;
if (x420_curDamageRemTime > 0.f)
x420_curDamageRemTime -= dt;
@ -320,7 +320,7 @@ void CPatterned::Think(float dt, CStateManager& mgr) {
if (x3cc_playerLeashRadius != 0.f) {
zeus::CVector3f diffVec = (GetTranslation() - mgr.GetPlayer().GetTranslation());
if (diffVec.magSquared() > x3cc_playerLeashRadius)
if (diffVec.magSquared() > x3cc_playerLeashRadius * x3cc_playerLeashRadius)
x3d4_curPlayerLeashTime += dt;
else
x3d4_curPlayerLeashTime = 0.f;
@ -333,6 +333,44 @@ void CPatterned::Think(float dt, CStateManager& mgr) {
x2f8_waypointPauseRemTime -= dt;
}
void CPatterned::CollidedWith(TUniqueId other, const CCollisionInfoList& list, CStateManager& mgr) {
if (x420_curDamageRemTime <= 0.f) {
if (TCastToPtr<CPlayer> player = mgr.ObjectById(other)) {
bool jumpOnHead = player->GetTimeSinceJump() < 5.f && list.GetCount() != 0 &&
list.Front().GetNormalLeft().z() > 0.707f;
if (x400_25_alive || jumpOnHead) {
CDamageInfo cDamage = GetContactDamage();
if (!x400_25_alive || x450_bodyController->IsFrozen())
cDamage.SetDamage(0.f);
if (jumpOnHead) {
mgr.ApplyDamage(GetUniqueId(), player->GetUniqueId(), GetUniqueId(), cDamage,
CMaterialFilter::skPassEverything, -player->GetVelocity());
player->ResetTimeSinceJump();
} else if (x400_25_alive && !x450_bodyController->IsFrozen()) {
mgr.ApplyDamage(GetUniqueId(), player->GetUniqueId(), GetUniqueId(), cDamage,
CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {}), zeus::CVector3f::skZero);
}
x420_curDamageRemTime = x424_damageWaitTime;
}
}
}
static CMaterialList testList(EMaterialTypes::Solid, EMaterialTypes::Ceiling, EMaterialTypes::Wall,
EMaterialTypes::Floor, EMaterialTypes::Character);
for (const CCollisionInfo& info : list) {
if (info.GetMaterialLeft().Intersection(testList)) {
if (!info.GetMaterialLeft().HasMaterial(EMaterialTypes::Floor)) {
if (!x310_moveVec.isZero() && info.GetNormalLeft().dot(x310_moveVec) >= 0.f)
continue;
} else if (!x400_31_isFlyer) {
continue;
}
x328_26_solidCollision = true;
return;
}
}
CPhysicsActor::CollidedWith(other, list, mgr);
}
void CPatterned::Touch(CActor& act, CStateManager& mgr) {
if (!x400_25_alive)
return;
@ -604,8 +642,7 @@ bool CPatterned::Leash(CStateManager&, float arg) {
bool ret = x3d4_curPlayerLeashTime > x3d0_playerLeashTime;
if (ret) {
float posToLeashMagSq = (x3a0_latestLeashPosition - GetTranslation()).magSquared();
if (posToLeashMagSq > x3c8_leashRadius * x3c8_leashRadius)
return true;
return posToLeashMagSq > x3c8_leashRadius * x3c8_leashRadius;
}
return ret;
}
@ -1586,7 +1623,7 @@ void CPatterned::ThinkAboutMove(float dt) {
switch (x3f8_moveState) {
case EMoveState::Zero:
if (!x328_26_longJump)
if (!x328_26_solidCollision)
break;
case EMoveState::One:
doMove = false;
@ -1601,7 +1638,7 @@ void CPatterned::ThinkAboutMove(float dt) {
x3f8_moveState = EMoveState::Three;
case EMoveState::Three:
doMove = true;
if (!x328_26_longJump) {
if (!x328_26_solidCollision) {
x3f8_moveState = EMoveState::Zero;
break;
}

View File

@ -120,7 +120,7 @@ protected:
struct {
bool x328_24_inPosition : 1;
bool x328_25_verticalMovement : 1;
bool x328_26_longJump : 1;
bool x328_26_solidCollision : 1;
bool x328_27_onGround : 1;
bool x328_28_prevOnGround : 1;
bool x328_29_noPatternShagging : 1;
@ -263,6 +263,7 @@ public:
void PreRender(CStateManager&, const zeus::CFrustum&);
void Render(const CStateManager& mgr) const;
void CollidedWith(TUniqueId, const CCollisionInfoList&, CStateManager& mgr);
void Touch(CActor& act, CStateManager& mgr);
std::experimental::optional<zeus::CAABox> GetTouchBounds() const;
bool CanRenderUnsorted(const CStateManager& mgr) const;
@ -373,7 +374,7 @@ public:
void SetCoverPoint(CScriptCoverPoint* cp, TUniqueId& id);
void ReleaseCoverPoint(CStateManager& mgr, TUniqueId& id);
bool CanLongJump() const { return x328_26_longJump; }
bool MadeSolidCollision() const { return x328_26_solidCollision; }
bool IsMakingBigStrike() const { return x402_28_isMakingBigStrike; }
// region Casting Functions

View File

@ -588,6 +588,8 @@ public:
const std::vector<TUniqueId>& GetOnScreenOrbitObjects() const { return x354_onScreenOrbitObjects; }
const std::vector<TUniqueId>& GetOffScreenOrbitObjects() const { return x364_offScreenOrbitObjects; }
void SetPlayerHitWallDuringMove();
float GetTimeSinceJump() const { return x2a8_timeSinceJump; }
void ResetTimeSinceJump() { x2a8_timeSinceJump = 1000.f; }
ESurfaceRestraints GetCurrentSurfaceRestraint() const { return x2ac_surfaceRestraint; }
ESurfaceRestraints GetSurfaceRestraint() const {
return x2b0_outOfWaterTicks == 2 ? GetCurrentSurfaceRestraint() : ESurfaceRestraints::Water;

View File

@ -35,7 +35,7 @@ void CScriptBeam::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId objId, CSt
mgr.AddObject(new CPlasmaProjectile(xe8_weaponDescription, x10_name + "-Projectile",
x138_damageInfo.GetWeaponMode().GetType(), xf4_beamInfo, x34_transform,
EMaterialTypes::Projectile, x138_damageInfo, x8_uid, x4_areaId,
x154_projectileId, 8, false, EProjectileAttrib::PlasmaProjectile));
x154_projectileId, {}, false, EProjectileAttrib::PlasmaProjectile));
} else if (msg == EScriptObjectMessage::Deleted) {
}

View File

@ -791,14 +791,14 @@ CEntity* ScriptLoader::LoadNewIntroBoss(CStateManager& mgr, CInputStream& in, in
CActorParameters actParms = LoadActorParameters(in);
float f1 = in.readFloatBig();
CAssetId w1(in);
CAssetId projectile(in);
CDamageInfo dInfo(in);
CAssetId w2(in);
CAssetId w3(in);
CAssetId w4(in);
CAssetId w5(in);
CAssetId beamContactFxId(in);
CAssetId beamPulseFxId(in);
CAssetId beamTextureId(in);
CAssetId beamGlowTextureId(in);
const CAnimationParameters& aParms = pInfo.GetAnimationParameters();
FourCC animType = g_ResFactory->GetResourceTypeById(aParms.GetACSFile());
@ -808,7 +808,7 @@ CEntity* ScriptLoader::LoadNewIntroBoss(CStateManager& mgr, CInputStream& in, in
CAnimRes res(aParms.GetACSFile(), aParms.GetCharacter(), head.x40_scale, aParms.GetInitialAnimation(), true);
return new MP1::CNewIntroBoss(mgr.AllocateUniqueId(), head.x0_name, info, head.x10_transform, res, pInfo, actParms,
f1, w1, dInfo, w2, w3, w4, w5);
f1, projectile, dInfo, beamContactFxId, beamPulseFxId, beamTextureId, beamGlowTextureId);
}
CEntity* ScriptLoader::LoadSpawnPoint(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info) {

View File

@ -255,6 +255,14 @@ public:
using const_reverse_iterator = typename base::const_reverse_iterator;
reserved_vector() : x0_size(0) {}
template <size_t LN>
reserved_vector(const T(&l)[LN])
: x0_size(LN) {
static_assert(LN <= N, "initializer array too large for reserved_vector");
for (size_t i = 0; i < LN; ++i)
::new (static_cast<void*>(std::addressof(_value(i)))) T(l[i]);
}
reserved_vector(const reserved_vector& other) : x0_size(other.x0_size) {
for (size_t i = 0; i < x0_size; ++i)
::new (static_cast<void*>(std::addressof(_value(i)))) T(other._value(i));

View File

@ -0,0 +1,151 @@
#shader CColoredStripShader
#attribute position4
#attribute color
#attribute uv4
#srcfac srcalpha
#dstfac invsrcalpha
#primitive tristrips
#depthtest lequal
#depthwrite false
#culling none
#vertex glsl
layout(location=0) in vec4 posIn;
layout(location=1) in vec4 colorIn;
layout(location=2) in vec4 uvIn;
UBINDING0 uniform ColoredQuadUniform
{
mat4 xf;
vec4 color;
};
struct VertToFrag
{
vec4 color;
vec2 uv;
};
SBINDING(0) out VertToFrag vtf;
void main()
{
vtf.color = colorIn * color;
vtf.uv = uvIn.xy;
gl_Position = xf * vec4(posIn.xyz, 1.0);
}
#fragment glsl
struct VertToFrag
{
vec4 color;
vec2 uv;
};
SBINDING(0) in VertToFrag vtf;
layout(location=0) out vec4 colorOut;
TBINDING0 uniform sampler2D tex;
void main()
{
colorOut = vtf.color * texture(tex, vtf.uv);
}
#vertex hlsl
struct VertData
{
float4 posIn : POSITION;
float4 colorIn : COLOR;
float4 uvIn : UV;
};
cbuffer ColoredQuadUniform : register(b0)
{
float4x4 xf;
float4 color;
};
struct VertToFrag
{
float4 position : SV_Position;
float4 color : COLOR;
float2 uv : UV;
};
VertToFrag main(in VertData v)
{
VertToFrag vtf;
vtf.color = v.colorIn * color;
vtf.uv = v.uvIn.xy;
vtf.position = mul(xf, float4(v.posIn.xyz, 1.0));
return vtf;
}
#fragment hlsl
SamplerState samp : register(s0);
Texture2D tex0 : register(t0);
struct VertToFrag
{
float4 position : SV_Position;
float4 color : COLOR;
float2 uv : UV;
};
float4 main(in VertToFrag vtf) : SV_Target0
{
return vtf.color * tex0.Sample(samp, vtf.uv);
}
#vertex metal
struct VertData
{
float4 posIn [[ attribute(0) ]];
float4 colorIn [[ attribute(1) ]];
float4 uvIn [[ attribute(2) ]];
};
struct ColoredQuadUniform
{
float4x4 xf;
float4 color;
};
struct VertToFrag
{
float4 position [[ position ]];
float4 color;
float2 uv;
};
vertex VertToFrag vmain(VertData v [[ stage_in ]], constant ColoredQuadUniform& cqu [[ buffer(2) ]])
{
VertToFrag vtf;
vtf.color = v.colorIn * cqu.color;
vtf.uv = v.uvIn.xy;
vtf.position = cqu.xf * float4(v.posIn.xyz, 1.0);
return vtf;
}
#fragment metal
struct VertToFrag
{
float4 position [[ position ]];
float4 color;
float2 uv;
};
fragment float4 fmain(VertToFrag vtf [[ stage_in ]],
sampler samp [[ sampler(0) ]],
texture2d<float> tex0 [[ texture(0) ]])
{
return vtf.color * tex0.sample(samp, vtf.uv);
}
#shader CColoredStripShaderAdditive : CColoredStripShader
#srcfac srcalpha
#dstfac one
#shader CColoredStripShaderFullAdditive : CColoredStripShader
#srcfac one
#dstfac one

View File

@ -7,6 +7,7 @@ include_directories(../hecl/include
add_shader(CAABoxShader)
add_shader(CCameraBlurFilter)
add_shader(CColoredQuadFilter)
add_shader(CColoredStripShader)
add_shader(CDecalShaders)
add_shader(CElementGenShaders)
add_shader(CEnergyBarShader)

2
hecl

@ -1 +1 @@
Subproject commit cdba678eee605cf0aff96f1276bc3593fca0de2b
Subproject commit d4a0f17336f19906a6c4f2ed83fd34945f017593