diff --git a/Source/Contents/Actors/GameActor.h b/Source/Contents/Actors/GameActor.h index 97093df1..05105eac 100644 --- a/Source/Contents/Actors/GameActor.h +++ b/Source/Contents/Actors/GameActor.h @@ -6,6 +6,16 @@ #include +enum { + BODYSTATE_NORMAL, + BODYSTATE_STONECURSE, + BODYSTATE_FREEZING, + BODYSTATE_STUN, + BODYSTATE_SLEEP, + BODYSTATE_UNDEAD, + BODYSTATE_STONECURSE_ING, +}; + class CGameActor : public CRenderObject { public: ~CGameActor() override; diff --git a/Source/Contents/Actors/RenderObject.cpp b/Source/Contents/Actors/RenderObject.cpp index dca88f7a..930fa621 100644 --- a/Source/Contents/Actors/RenderObject.cpp +++ b/Source/Contents/Actors/RenderObject.cpp @@ -115,7 +115,7 @@ void CRenderObject::SetAnimation(unsigned animation, int, int repeat) { this->render.previousAnimation = animation; this->render.curMotion = 0; this->render.unknown_006C = repeat; - this->render.unknown_009C[1] = 0; + this->render.isMotionFinished = 0; this->render.unknown_0060 = 1.0f; this->render.unknown_0064 = 1.0f; this->render.unknown_00C8 = 0; @@ -423,9 +423,9 @@ void CRenderObject::JitterBounds(float* output, const int* input, float offset, // FUNCTION: fn_21090 void CGameActor::ProcessBodyState() { switch (this->bodyState) { - case 1: - case 2: - this->render.unknown_009C[2] = 1; + case BODYSTATE_FREEZING: + case BODYSTATE_STONECURSE: + this->render.isMotionFreezed = true; break; } } diff --git a/Source/Contents/Actors/RenderObjectState.cpp b/Source/Contents/Actors/RenderObjectState.cpp index a1085839..32a23184 100644 --- a/Source/Contents/Actors/RenderObjectState.cpp +++ b/Source/Contents/Actors/RenderObjectState.cpp @@ -46,13 +46,13 @@ void RenderObjectState::Reset(ResourceMgr& resources, JobNames& names) { this->color = 0xFFFFFFFFu; this->unknown_00A2 = 0; this->unknown_00A4 = 0; - this->unknown_009C[1] = 0; - this->unknown_009C[2] = 0; + this->isMotionFinished = 0; + this->isMotionFreezed = 0; this->unknown_0078 = 0; this->unknown_007C = 0; this->started = timeGetTime(); - this->unknown_009C[3] = 0; - this->unknown_009C[0] = 0; + this->isSingleColor = 0; + this->isLieOnGround = 0; this->unknown_00A3 = 0; this->overrideColor = 0xFFFF0000u; this->unknown_0080 = 0; diff --git a/Source/Contents/Actors/RenderObjectState.h b/Source/Contents/Actors/RenderObjectState.h index 26e10035..58e33eb4 100644 --- a/Source/Contents/Actors/RenderObjectState.h +++ b/Source/Contents/Actors/RenderObjectState.h @@ -47,7 +47,10 @@ struct RenderObjectState { /* 0090 */ std::uint32_t unknown_0090; /* 0094 */ std::uint32_t unknown_0094; /* 0098 */ std::uint32_t color; - /* 009C */ unsigned char unknown_009C[4]; + /* 009C */ bool isLieOnGround; + /* 009D */ bool isMotionFinished; + /* 009E */ bool isMotionFreezed; + /* 009F */ bool isSingleColor; /* 00A0 */ unsigned char visible; /* 00A1 */ unsigned char enabled; /* 00A2 */ unsigned char unknown_00A2; diff --git a/Source/Contents/Effects/EffectParticle.h b/Source/Contents/Effects/EffectParticle.h index fb611fb6..3d806798 100644 --- a/Source/Contents/Effects/EffectParticle.h +++ b/Source/Contents/Effects/EffectParticle.h @@ -38,6 +38,10 @@ struct EffectParticle : CRenderObject { void PrimSMA(); void PrimShieldBoomerang3(); bool PrimSuperAngel(); + void PrimThrowItem(); + bool PrimPeong(); + void PrimGI3(); + void PrimWaterFall(); bool AdvanceFrame(); void UpdateRecords(); diff --git a/Source/Contents/Effects/EffectPrimitiveMotion.cpp b/Source/Contents/Effects/EffectPrimitiveMotion.cpp index 3ed65021..a4329e8c 100644 --- a/Source/Contents/Effects/EffectPrimitiveMotion.cpp +++ b/Source/Contents/Effects/EffectPrimitiveMotion.cpp @@ -1488,6 +1488,7 @@ void EffectParticle::PrimSMA() { } // OFFSET: 0x00BC2A60 +// FUNCTION: fn_19835 void EffectParticle::PrimShieldBoomerang3() { EffectPrimitiveSlot* slots = this->state.slots; FaceCamera(slots); @@ -1552,6 +1553,7 @@ void EffectParticle::PrimShieldBoomerang3() { } // OFFSET: 0x00BC3C70 +// FUNCTION: fn_19840 bool EffectParticle::PrimSuperAngel() { const AttachedEffect* master = this->state.master; this->render.position[0] = master->render.position[0]; @@ -1699,6 +1701,182 @@ bool EffectParticle::PrimSuperAngel() { return true; } +// OFFSET: 0x00BC4730 +void EffectParticle::PrimThrowItem() { + EffectPrimitiveSlot* slots = this->state.slots; + FaceCamera(slots); + + const AttachedEffect* master = this->state.master; + this->render.position[0] = master->render.position[0]; + this->render.position[1] = master->render.position[1]; + this->render.position[2] = master->render.position[2]; + + EffectPrimitiveSlot& slot = slots[0]; + + if (slot.life != 1) { + return; + } + + ++slot.process; + + if (slot.process % 2 == 1) { + if (slot.process > 3) { + FollowTrail(slots[3], slots[2], 25); + } + + if (slot.process > 2) { + FollowTrail(slots[2], slots[1], 25); + } + + if (slot.process > 1) { + FollowTrail(slots[1], slot, 150); + } + } + + if (slot.flag1[2] == 15) { + slot.fullDisplayAngle += 45; + } else { + slot.fullDisplayAngle += 10; + } + + if (slot.fullDisplayAngle >= 360) { + slot.fullDisplayAngle -= 360; + } + + if (slot.process == 1) { + const float x = this->state.offset.x - slot.vecBNow.x; + const float z = this->state.offset.z - slot.vecBNow.z; + CalculateVectorAngle(x, z, &slot.rotStart); + } + + float progress = static_cast(slot.process); + progress /= static_cast(slot.flag1[1]); + + if (progress > 1.05f) { + slot.alphaB -= 20; + + if (slot.alphaB < 0) { + slot.alphaB = 0; + } + + return; + } + + if (progress > 1.0f) { + progress = 1.0f; + } + + const int arc = static_cast(180.0f * progress); + slot.vecBPre.y += slot.height[2]; + + if (slot.flag1[2] == 0) { + slot.vecBNow.y = slot.vecBPre.y - g_sinTable[arc] * 10.0f; + } else if (slot.flag1[2] == 15) { + slot.vecBNow.y = slot.vecBPre.y - g_sinTable[arc]; + } else { + slot.vecBNow.y = slot.vecBPre.y - g_sinTable[arc] * 30.0f; + } + + slot.vecBNow.x += slot.height[1] * g_cosTable[slot.rotStart]; + slot.vecBNow.z += slot.height[1] * g_sinTable[slot.rotStart]; +} + +// OFFSET: 0x00BC06B0 +bool EffectParticle::PrimPeong() { + FaceCamera(this->state.slots); + + for (int index = 0; index < 4; ++index) { + EffectPrimitiveSlot& slot = this->state.slots[index]; + + if (slot.life != 1) { + continue; + } + + ++slot.process; + + if (slot.process <= 0) { + continue; + } + + if (slot.process <= 90) { + const float cosine = g_cosTable[slot.riseAngle]; + float sine = g_sinTable[slot.riseAngle]; + slot.vecBPre.x += cosine * slot.maxHeight; + slot.vecBPre.z += sine * slot.maxHeight; + + int angle = slot.process * 2; + + if (angle >= 360) { + angle -= 360; + } + + sine = g_sinTable[angle]; + slot.vecBPre.y = slot.vecBNow.y - sine * slot.maxHeight * 50.0f; + } + + if (slot.process <= 25) { + slot.alphaB += 2; + } + + if (slot.process > 70) { + --slot.alphaB; + } + + if (slot.alphaB < 0) { + slot.alphaB = 0; + } + } + + return true; +} + +// OFFSET: 0x00BBDE10 +void EffectParticle::PrimGI3() { + for (int index = 0; index < 4; ++index) { + EffectPrimitiveSlot& slot = this->state.slots[index]; + + if (slot.life != 1) { + continue; + } + + slot.process += 1; + slot.distance -= 0.01f; + + if (slot.process >= 10) { + slot.alphaB -= 1; + + if (slot.alphaB <= 0) { + slot.alphaB = 0; + + if (slot.process > 30) { + slot.life = 0; + } + + slot.distance = 20.0f; + slot.riseAngle = 81 + 9; + } + } else { + slot.alphaB += 10; + } + + for (int sample = 0; sample < 21; ++sample) { + slot.height[sample] = slot.maxHeight * g_sinTable[slot.process]; + } + } +} + +// OFFSET: 0x00BEBC40 +// FUNCTION: fn_19971 +void EffectParticle::PrimWaterFall() { + for (int index = 0; index < 4; ++index) { + EffectPrimitiveSlot& slot = this->state.slots[index]; + + if (slot.life > 0) { + ++slot.process; + } + } +} + // OFFSET: 0x00BB6F30 // FUNCTION: fn_19779 bool EffectParticle::UpdateHit6() { diff --git a/Source/Contents/Items/ItemInfo.cpp b/Source/Contents/Items/ItemInfo.cpp index 5a69eb96..9d57e23e 100644 --- a/Source/Contents/Items/ItemInfo.cpp +++ b/Source/Contents/Items/ItemInfo.cpp @@ -387,3 +387,8 @@ bool ItemInfo::IsElementalStone() const { bool ItemInfo::IsAboveItemId600() const { return std::atoi(this->itemId.c_str()) > 500 && std::atoi(this->itemId.c_str()) > 600; } + +// OFFSET: 0x005FCCF0 +int ItemInfo::GetItemId() const { + return std::atoi(this->itemId.c_str()); +} diff --git a/Source/Contents/Items/ItemInfo.h b/Source/Contents/Items/ItemInfo.h index 1781d37c..843455e1 100644 --- a/Source/Contents/Items/ItemInfo.h +++ b/Source/Contents/Items/ItemInfo.h @@ -65,6 +65,7 @@ struct alignas(8) ItemInfo { bool operator<(const ItemInfo& other) const; bool SetName(const char* name); void SetItemId(int value); + int GetItemId() const; bool HasSpecialCard() const; bool IsApprenticeItem() const; bool IsForgeMaterial() const; diff --git a/Source/Contents/Sound/SoundMaker.cpp b/Source/Contents/Sound/SoundMaker.cpp index 0866bfb8..3634ab82 100644 --- a/Source/Contents/Sound/SoundMaker.cpp +++ b/Source/Contents/Sound/SoundMaker.cpp @@ -203,7 +203,7 @@ void CBlurPC::SendObjectMessage( this->unknown_04F8 = *reinterpret_cast(&b); break; case 3: - this->render.unknown_009C[2] = 1; + this->render.isMotionFreezed = 1; break; default: CPc::SendObjectMessage(sender, message, a, b, c, d, e, f, g, h, i, 0, 0, 0, 0); @@ -242,7 +242,7 @@ void CHalluNPC::SendObjectMessage( this->unknown_0440 = *reinterpret_cast(&b); break; case 3: - this->render.unknown_009C[2] = 1; + this->render.isMotionFreezed = 1; break; default: CNpc::SendObjectMessage(sender, message, a, b, c, d, e, f, g, h, i, 0, 0, 0, 0); @@ -273,7 +273,7 @@ void CHalluPC2::SendObjectMessage( this->unknown_04F8 = *reinterpret_cast(&b); break; case 3: - this->render.unknown_009C[2] = 1; + this->render.isMotionFreezed = 1; break; default: CPc::SendObjectMessage(sender, message, a, b, c, d, e, f, g, h, i, 0, 0, 0, 0); @@ -304,7 +304,7 @@ void CHalluPC::SendObjectMessage( this->unknown_04F8 = *reinterpret_cast(&b); break; case 3: - this->render.unknown_009C[2] = 1; + this->render.isMotionFreezed = 1; break; default: CPc::SendObjectMessage(sender, message, a, b, c, d, e, f, g, h, i, 0, 0, 0, 0); @@ -330,7 +330,7 @@ void CHalluPlant::SendObjectMessage( this->render.color &= (b << 24) + 0xFFFFFF; break; case 3: - this->render.unknown_009C[2] = 1; + this->render.isMotionFreezed = 1; break; default: CNpc::SendObjectMessage(sender, message, a, b, c, d, e, f, g, h, i, 0, 0, 0, 0); diff --git a/Source/UI/Shortcuts/ShortcutDrop.cpp b/Source/UI/Shortcuts/ShortcutDrop.cpp index 41830d06..23c11dda 100644 --- a/Source/UI/Shortcuts/ShortcutDrop.cpp +++ b/Source/UI/Shortcuts/ShortcutDrop.cpp @@ -127,7 +127,7 @@ void ShortcutDrop::Drop(UIWindow& window, ShortcutGrid& grid, int x, int y, cons const int column = grid.HitTest(x, y, this->itemSlotActive, this->currentRow); if (column != -1 && 9 * grid.rows <= 9 * this->currentRow + column) { if (this->itemSlotActive) { - this->bindings.AssignItem(static_cast(std::atoi(item.itemId.c_str())), column); + this->bindings.AssignItem(static_cast(item.GetItemId()), column); Refresh(window); } @@ -145,7 +145,7 @@ void ShortcutDrop::Drop(UIWindow& window, ShortcutGrid& grid, int x, int y, cons const int column = grid.HitTest(x, y, this->itemSlotActive, this->currentRow); if (column != -1 && grid.rows > this->currentRow) { const int index = 9 * this->currentRow + column; - this->bindings.Assign(0, static_cast(std::atoi(item.itemId.c_str())), 0, index, bank, this->currentRow, this->script, *this->mode); + this->bindings.Assign(0, static_cast(item.GetItemId()), 0, index, bank, this->currentRow, this->script, *this->mode); if (value.slot != index) { RemoveFirst(this->bindings.cooldowns, index); } diff --git a/Source/UI/Shortcuts/UIShortCutWnd.cpp b/Source/UI/Shortcuts/UIShortCutWnd.cpp index be6093f5..28fcf52b 100644 --- a/Source/UI/Shortcuts/UIShortCutWnd.cpp +++ b/Source/UI/Shortcuts/UIShortCutWnd.cpp @@ -318,7 +318,7 @@ inline void ShortcutUse::Use(const NormalItemSlot& slot) { case 0: case 1: case 2: - if (std::atoi(item.itemId.c_str()) != 12802 || this->dialogs.Confirm(this->naming.Message(2373), 2, 0, 0, "Message", 280, 120) != 188) { + if (item.GetItemId() != 12802 || this->dialogs.Confirm(this->naming.Message(2373), 2, 0, 0, "Message", 280, 120) != 188) { use(); }