2
#include "../BuildingType/Body.h"
3
#include <BulletClass.h>
4
#include <LaserDrawClass.h>
6
DEFINE_HOOK(44B2FE, BuildingClass_Mi_Attack_IsPrism, 6)
8
GET(BuildingClass *, B, ESI);
9
GET(int, idxWeapon, EBP); //which weapon was chosen to attack the target with
10
R->EAX<BuildingTypeClass *>(B->Type);
12
enum { IsPrism = 0x44B310, IsNotPrism = 0x44B630, IsCustomPrism = 0x44B6D6};
14
BuildingTypeClass *pMasterType = B->Type;
15
BuildingTypeExt::ExtData *pMasterTypeData = BuildingTypeExt::ExtMap.Find(pMasterType);
17
if (pMasterTypeData->PrismForwarding.Enabled == BuildingTypeExt::cPrismForwarding::YES
18
|| pMasterTypeData->PrismForwarding.Enabled == BuildingTypeExt::cPrismForwarding::ATTACK) {
20
if (B->PrismStage == pcs_Idle) {
21
B->PrismStage = pcs_Master;
22
B->DelayBeforeFiring = B->Type->DelayedFireDelay;
23
B->PrismTargetCoords.X = 0;
24
B->PrismTargetCoords.Y = B->PrismTargetCoords.Z = 0;
25
B->DestroyNthAnim(BuildingAnimSlot::Active);
26
B->PlayNthAnim(BuildingAnimSlot::Special);
34
//when it reaches zero we can't acquire any more slaves
35
while (BuildingTypeExt::cPrismForwarding::AcquireSlaves_MultiStage(B, B, stage++, 0, &NetworkSize, &LongestChain) != 0) {}
37
//now we have all the towers we know the longest chain, and can set all the towers' charge delays
38
BuildingTypeExt::cPrismForwarding::SetChargeDelay(B, LongestChain);
40
} else if (B->PrismStage == pcs_Slave) {
41
Debug::Log("PrismForwarding: Converting Slave to Master\n");
42
//a slave tower is changing into a master tower at the last second
43
B->PrismStage = pcs_Master;
44
BuildingExt::ExtData *pMasterData = BuildingExt::ExtMap.Find(B);
45
pMasterData->PrismForwarding.SupportTarget = NULL;
49
return IsCustomPrism; //always custom, the new code is a complete rewrite of the old code
56
DEFINE_HOOK(447FAE, BuildingClass_GetObjectActivityState, 6)
58
GET(BuildingClass *, B, ESI);
59
enum { BusyCharging = 0x447FB8, NotBusyCharging = 0x447FC3};
61
if(B->DelayBeforeFiring > 0) {
62
//if this is a slave prism tower, then it might still be able to become a master tower at this time
63
BuildingTypeClass *pType = B->Type;
64
BuildingTypeExt::ExtData *pTypeData = BuildingTypeExt::ExtMap.Find(pType);
65
if (pTypeData->PrismForwarding.Enabled == BuildingTypeExt::cPrismForwarding::YES
66
|| pTypeData->PrismForwarding.Enabled == BuildingTypeExt::cPrismForwarding::ATTACK) {
68
if (B->PrismStage == pcs_Slave && pTypeData->PrismForwarding.BreakSupport) {
69
return NotBusyCharging;
74
return NotBusyCharging;
77
//NB: PrismTargetCoords is not just a coord struct, it's a union whose first dword is the used weapon index and two others are undefined...
78
DEFINE_HOOK(4503F0, BuildingClass_Update_Prism, 9)
80
GET(BuildingClass *, pThis, ECX);
81
if(int PrismStage = pThis->PrismStage) {
82
BuildingExt::ExtData *pData = BuildingExt::ExtMap.Find(pThis);
83
if (pData->PrismForwarding.PrismChargeDelay <= 0) {
84
--pThis->DelayBeforeFiring;
85
if(pThis->DelayBeforeFiring <= 0) {
86
if(PrismStage == pcs_Slave) {
87
if (BuildingClass *pTarget = pData->PrismForwarding.SupportTarget) {
88
BuildingExt::ExtData *pTargetData = BuildingExt::ExtMap.Find(pTarget);
89
BuildingTypeClass *pType = pThis->Type;
90
BuildingTypeExt::ExtData *pTypeData = BuildingTypeExt::ExtMap.Find(pType);
91
Debug::Log("[PrismForwarding] Slave firing. SM=%d MR=%lf\n",
92
pTypeData->PrismForwarding.SupportModifier.Get(), pData->PrismForwarding.ModifierReserve);
93
pTargetData->PrismForwarding.ModifierReserve +=
94
(pTypeData->PrismForwarding.SupportModifier.Get() + pData->PrismForwarding.ModifierReserve);
95
pTargetData->PrismForwarding.DamageReserve +=
96
(pTypeData->PrismForwarding.DamageAdd.Get() + pData->PrismForwarding.DamageReserve);
97
pThis->FireLaser(pThis->PrismTargetCoords);
101
if(PrismStage == pcs_Master) {
102
if(ObjectClass *Target = pThis->Target) {
103
if(pThis->GetFireError(Target, pThis->PrismTargetCoords.X, true) == FireError::OK) {
104
if(BulletClass *LaserBeam = pThis->Fire(Target, pThis->PrismTargetCoords.X)) {
105
BuildingTypeClass *pType = pThis->Type;
106
BuildingTypeExt::ExtData *pTypeData = BuildingTypeExt::ExtMap.Find(pType);
107
LaserBeam->DamageMultiplier = ((pData->PrismForwarding.ModifierReserve + 100) * 256) / 100; //apparently this is divided by 256 elsewhere
108
LaserBeam->Health += pTypeData->PrismForwarding.DamageAdd.Get() + pData->PrismForwarding.DamageReserve;
113
//This tower's job is done. Go idle.
114
pData->PrismForwarding.ModifierReserve = 0.0;
115
pData->PrismForwarding.DamageReserve = 0;
116
pData->PrismForwarding.Senders.Clear();
117
pThis->SupportingPrisms = 0; //Ares doesn't actually use this, but maintaining it anyway (as direct feeds only)
118
pData->PrismForwarding.SupportTarget = NULL;
119
pThis->PrismStage = pcs_Idle;
122
//still in delayed charge so not actually charging yet
123
--pData->PrismForwarding.PrismChargeDelay;
124
pThis->DestroyNthAnim(BuildingAnimSlot::Active);
125
pThis->PlayNthAnim(BuildingAnimSlot::Special);
131
DEFINE_HOOK(44ABD0, BuildingClass_FireLaser, 5)
133
GET(BuildingClass *, B, ECX);
134
LEA_STACK(CoordStruct *, pTargetXYZ, 0x4);
136
BuildingTypeClass *pType = B->Type;
137
BuildingTypeExt::ExtData *pTypeData = BuildingTypeExt::ExtMap.Find(pType);
139
CoordStruct SourceXYZ, Base = {0, 0, 0};
140
B->GetFLH(&SourceXYZ, 0, Base);
142
ColorStruct blank(0, 0, 0);
144
LaserDrawClass * LaserBeam;
145
GAME_ALLOC(LaserDrawClass, LaserBeam, SourceXYZ, *pTargetXYZ,
146
B->Owner->LaserColor, blank, blank, pTypeData->PrismForwarding.SupportDuration);
149
LaserBeam->IsHouseColor = true;
150
LaserBeam->field_1C = 3;
153
B->SupportingPrisms = 0;
154
B->ReloadTimer.Start(pTypeData->PrismForwarding.SupportDelay);
159
//these are all for cleaning up when a prism tower becomes unavailable
160
DEFINE_HOOK(4424EF, PrismForward_BuildingDestroyed, 6)
162
GET(BuildingClass *, B, ESI);
163
BuildingTypeExt::cPrismForwarding::RemoveSlave(B, true);
167
DEFINE_HOOK(447113, PrismForward_BuildingSold, 6)
169
GET(BuildingClass *, B, ESI);
170
BuildingTypeExt::cPrismForwarding::RemoveSlave(B, true);
174
DEFINE_HOOK(448277, PrismForward_BuildingChangeOwner, 5)
176
GET(BuildingClass *, B, ESI);
177
GET_STACK(HouseClass *, newOwner, 0x5C);
179
HouseClass * oldOwner = B->Owner;
181
if (newOwner != oldOwner) {
182
BuildingTypeClass *pType = B->Type;
183
BuildingTypeExt::ExtData *pTypeData = BuildingTypeExt::ExtMap.Find(pType);
185
if (pTypeData->PrismForwarding.ToAllies) {
186
BuildingClass *LastTarget = B;
187
BuildingClass *FirstTarget = NULL;
189
BuildingExt::ExtData *pData = BuildingExt::ExtMap.Find(LastTarget);
190
BuildingClass *NextTarget = pData->PrismForwarding.SupportTarget;
192
FirstTarget = NextTarget;
195
//LastTarget is now the master (firing) tower
196
if (newOwner->IsAlliedWith(LastTarget->Owner) && newOwner->IsAlliedWith(FirstTarget->Owner)) {
197
//alliances check out so this slave tower can keep on charging.
201
LastTarget = NextTarget;
204
//if we reach this point then the alliance checks have failed
205
BuildingTypeExt::cPrismForwarding::RemoveSlave(B, false);