2
#include "../Building/Body.h"
3
#include "../Techno/Body.h"
4
#include <BulletClass.h>
5
#include <LaserDrawClass.h>
10
void BuildingTypeExt::cPrismForwarding::Initialize(BuildingTypeClass *pThis) {
12
if (pThis == RulesClass::Instance->PrismType) {
15
this->Targets.AddItem(pThis);
18
void BuildingTypeExt::cPrismForwarding::LoadFromINIFile(BuildingTypeClass *pThis, CCINIClass* pINI) {
19
const char * pID = pThis->ID;
20
if(pINI->ReadString(pID, "PrismForwarding", "", Ares::readBuffer, Ares::readLength)) {
21
if((strcmp(Ares::readBuffer, "yes") == 0) || (strcmp(Ares::readBuffer, "true") == 0)) {
23
} else if(strcmp(Ares::readBuffer, "forward") == 0) {
24
this->Enabled = FORWARD;
25
} else if(strcmp(Ares::readBuffer, "attack") == 0) {
26
this->Enabled = ATTACK;
27
} else if((strcmp(Ares::readBuffer, "no") == 0) || (strcmp(Ares::readBuffer, "false"))== 0) {
32
if (this->Enabled != NO) {
33
if(pINI->ReadString(pID, "PrismForwarding.Targets", "", Ares::readBuffer, Ares::readLength)) {
34
this->Targets.Clear();
35
for(char *cur = strtok(Ares::readBuffer, ","); cur && *cur; cur = strtok(NULL, ",")) {
36
BuildingTypeClass * target = BuildingTypeClass::Find(cur);
38
this->Targets.AddItem(target);
45
this->MaxFeeds.Read(&exINI, pID, "PrismForwarding.MaxFeeds");
46
this->MaxChainLength.Read(&exINI, pID, "PrismForwarding.MaxChainLength");
47
this->MaxNetworkSize.Read(&exINI, pID, "PrismForwarding.MaxNetworkSize");
48
this->SupportModifier.Read(&exINI, pID, "PrismForwarding.SupportModifier");
49
this->DamageAdd.Read(&exINI, pID, "PrismForwarding.DamageAdd");
50
this->SupportRange.Read(&exINI, pID, "PrismForwarding.SupportRange");
52
if (this->SupportRange != -1) {
53
this->SupportRange = this->SupportRange * 256; //stored in leptons, not cells
56
this->SupportDelay.Read(&exINI, pID, "PrismForwarding.SupportDelay");
57
this->ToAllies.Read(&exINI, pID, "PrismForwarding.ToAllies");
58
this->MyHeight.Read(&exINI, pID, "PrismForwarding.MyHeight");
59
this->BreakSupport.Read(&exINI, pID, "PrismForwarding.BreakSupport");
61
int ChargeDelay = pINI->ReadInteger(pID, "PrismForwarding.ChargeDelay", this->ChargeDelay);
62
if (ChargeDelay >= 1) {
63
this->ChargeDelay.Set(ChargeDelay);
65
Debug::Log("[Developer Error] %s has an invalid PrismForwarding.ChargeDelay (%d), overriding to 1.\n", pThis->ID, ChargeDelay);
71
signed int BuildingTypeExt::cPrismForwarding::GetSupportRange(BuildingTypeClass *pThis) {
72
if(this->SupportRange != 0) {
73
return this->SupportRange;
75
if(WeaponTypeClass* Secondary = pThis->get_Secondary()) {
76
return Secondary->Range;
77
} else if(WeaponTypeClass* Primary = pThis->get_Primary()) {
78
return Primary->Range;
83
int BuildingTypeExt::cPrismForwarding::AcquireSlaves_MultiStage
84
(BuildingClass *MasterTower, BuildingClass *TargetTower, int stage, int chain, int *NetworkSize, int *LongestChain) {
85
//get all slaves for a specific stage in the prism chain
86
//this is done for all sibling chains in parallel, so we prefer multiple short chains over one really long chain
87
//towers should be added in the following way:
99
// ...which would not be as good.
102
countSlaves += AcquireSlaves_SingleStage(MasterTower, TargetTower, stage, (chain + 1), NetworkSize, LongestChain);
104
BuildingExt::ExtData *pTargetData = BuildingExt::ExtMap.Find(TargetTower);
106
while(senderIdx < pTargetData->PrismForwarding.Senders.Count) {
107
BuildingClass *SenderTower = pTargetData->PrismForwarding.Senders[senderIdx];
108
countSlaves += AcquireSlaves_MultiStage(MasterTower, SenderTower, (stage - 1), (chain + 1), NetworkSize, LongestChain);
115
int BuildingTypeExt::cPrismForwarding::AcquireSlaves_SingleStage
116
(BuildingClass *MasterTower, BuildingClass *TargetTower, int stage, int chain, int *NetworkSize, int *LongestChain) {
117
//set up immediate slaves for this particular tower
119
BuildingTypeClass *pMasterType = MasterTower->Type;
120
BuildingTypeExt::ExtData *pMasterTypeData = BuildingTypeExt::ExtMap.Find(pMasterType);
121
BuildingTypeClass *pTargetType = TargetTower->Type;
122
BuildingTypeExt::ExtData *pTargetTypeData = BuildingTypeExt::ExtMap.Find(pTargetType);
124
signed int MaxFeeds = pTargetTypeData->PrismForwarding.MaxFeeds;
125
signed int MaxNetworkSize = pMasterTypeData->PrismForwarding.MaxNetworkSize;
126
signed int MaxChainLength = pMasterTypeData->PrismForwarding.MaxChainLength;
129
|| (MaxChainLength != -1 && MaxChainLength < chain)
130
|| (MaxNetworkSize != -1 && MaxNetworkSize <= *NetworkSize)) {
134
struct PrismTargetData {
135
BuildingClass * Tower;
138
bool operator < (PrismTargetData const &rhs) {
139
return this->Distance < rhs.Distance;
143
CoordStruct MyPosition, curPosition;
144
TargetTower->GetPosition_2(&MyPosition);
146
//first, find eligible towers
147
std::vector<PrismTargetData> EligibleTowers;
148
//for(int i = 0; i < TargetTower->Owner->Buildings.Count; ++i) {
149
for (int i = 0; i < BuildingClass::Array->Count; ++i) {
150
//if (BuildingClass *SlaveTower = B->Owner->Buildings[i]) {
151
if (BuildingClass *SlaveTower = BuildingClass::Array->GetItem(i)) {
152
if (ValidateSupportTower(MasterTower, TargetTower, SlaveTower)) {
153
SlaveTower->GetPosition_2(&curPosition);
154
int Distance = MyPosition.DistanceFrom(curPosition);
156
PrismTargetData pd = {SlaveTower, Distance};
157
EligibleTowers.push_back(pd);
162
std::sort(EligibleTowers.begin(), EligibleTowers.end());
163
//std::reverse(EligibleTowers.begin(), EligibleTowers.end());
165
//now enslave the towers in order of proximity
167
while (EligibleTowers.size() != 0 && (MaxFeeds == -1 || iFeeds < MaxFeeds) && (MaxNetworkSize == -1 || *NetworkSize < MaxNetworkSize)) {
168
BuildingClass * nearestPrism = EligibleTowers[0].Tower;
169
EligibleTowers.erase(EligibleTowers.begin());
170
//we have a slave tower! do the bizzo
173
++TargetTower->SupportingPrisms; //Ares doesn't actually use this, but maintaining it anyway (as direct feeds only)
174
CoordStruct FLH, Base = {0, 0, 0};
175
TargetTower->GetFLH(&FLH, 0, Base);
176
nearestPrism->DelayBeforeFiring = nearestPrism->Type->DelayedFireDelay;
177
nearestPrism->PrismStage = pcs_Slave;
178
nearestPrism->PrismTargetCoords = FLH;
179
nearestPrism->DestroyNthAnim(BuildingAnimSlot::Active);
180
nearestPrism->PlayNthAnim(BuildingAnimSlot::Special);
182
BuildingExt::ExtData *pSlaveData = BuildingExt::ExtMap.Find(nearestPrism);
183
BuildingExt::ExtData *pTargetData = BuildingExt::ExtMap.Find(TargetTower);
184
pSlaveData->PrismForwarding.SupportTarget = TargetTower;
185
pTargetData->PrismForwarding.Senders.AddItem(nearestPrism);
188
if (iFeeds != 0 && chain > *LongestChain) {
195
bool BuildingTypeExt::cPrismForwarding::ValidateSupportTower(
196
BuildingClass *MasterTower, BuildingClass *TargetTower, BuildingClass *SlaveTower) {
197
//MasterTower = the firing tower. This might be the same as TargetTower, it might not.
198
//TargetTower = the tower that we are forwarding to
199
//SlaveTower = the tower being considered to support TargetTower
200
if(SlaveTower->IsAlive) {
201
if(SlaveTower->ReloadTimer.Ignorable()) {
202
if(SlaveTower != TargetTower) {
203
if (!SlaveTower->DelayBeforeFiring) {
204
int SlaveMission = SlaveTower->GetCurrentMission();
205
if(!SlaveTower->IsBeingDrained() && SlaveMission != mission_Attack
206
&& SlaveMission != mission_Construction && SlaveMission != mission_Selling) {
207
TechnoExt::ExtData *pData = TechnoExt::ExtMap.Find(SlaveTower);
208
if (pData->IsOperated() && pData->IsPowered() && !SlaveTower->IsUnderEMP() &&!SlaveTower->IsBeingWarpedOut()) {
209
BuildingExt::ExtData *pSlaveData = BuildingExt::ExtMap.Find(SlaveTower);
210
BuildingTypeClass *pSlaveType = SlaveTower->Type;
211
BuildingTypeExt::ExtData *pSlaveTypeData = BuildingTypeExt::ExtMap.Find(pSlaveType);
212
if (pSlaveTypeData->PrismForwarding.Enabled == YES || pSlaveTypeData->PrismForwarding.Enabled == FORWARD) {
213
//building is a prism tower
214
BuildingTypeClass *pTargetType = TargetTower->Type;
215
if (pSlaveTypeData->PrismForwarding.Targets.FindItemIndex(&pTargetType) != -1) {
216
//valid type to forward from
217
HouseClass *pMasterHouse = MasterTower->Owner;
218
HouseClass *pTargetHouse = TargetTower->Owner;
219
HouseClass *pSlaveHouse = SlaveTower->Owner;
220
if ((pSlaveHouse == pTargetHouse && pSlaveHouse == pMasterHouse)
221
|| (pSlaveTypeData->PrismForwarding.ToAllies
222
&& pSlaveHouse->IsAlliedWith(pTargetHouse) && pSlaveHouse->IsAlliedWith(pMasterHouse))) {
223
//ownership/alliance rules satisfied
224
CellStruct tarCoords = TargetTower->GetCell()->MapCoords;
225
CoordStruct MyPosition, curPosition;
226
TargetTower->GetPosition_2(&MyPosition);
227
SlaveTower->GetPosition_2(&curPosition);
228
int Distance = MyPosition.DistanceFrom(curPosition);
229
Debug::Log("[PrismForwarding] Distance=%u, SupportRange=%d\n",
230
Distance, pSlaveTypeData->PrismForwarding.GetSupportRange(pSlaveType));
231
if(pSlaveTypeData->PrismForwarding.SupportRange == -1
232
|| Distance <= pSlaveTypeData->PrismForwarding.GetSupportRange(pSlaveType)) {
248
void BuildingTypeExt::cPrismForwarding::SetChargeDelay
249
(BuildingClass * TargetTower, int LongestChain) {
250
int ArrayLen = LongestChain + 1;
251
DWORD *LongestCDelay = new DWORD[ArrayLen];
252
memset(LongestCDelay, 0, ArrayLen * sizeof(DWORD));
253
DWORD *LongestFDelay = new DWORD[ArrayLen];
254
memset(LongestFDelay, 0, ArrayLen * sizeof(DWORD));
256
int endChain = LongestChain;
257
while (endChain >= 0) {
258
SetChargeDelay_Get(TargetTower, 0, endChain, LongestChain, LongestCDelay, LongestFDelay);
263
while (temp != LongestChain) {
267
SetChargeDelay_Set(TargetTower, 0, LongestCDelay, LongestFDelay);
268
delete [] LongestFDelay;
269
delete [] LongestCDelay;
272
void BuildingTypeExt::cPrismForwarding::SetChargeDelay_Get
273
(BuildingClass * TargetTower, int chain, int endChain, int LongestChain, DWORD *LongestCDelay, DWORD *LongestFDelay) {
274
BuildingExt::ExtData *pTargetData = BuildingExt::ExtMap.Find(TargetTower);
275
if (chain == endChain) {
276
if (chain != LongestChain) {
277
BuildingTypeExt::ExtData *pTypeData = BuildingTypeExt::ExtMap.Find(TargetTower->Type);
278
//update the delays for this chain
279
int thisDelay = pTypeData->PrismForwarding.ChargeDelay.Get() + LongestCDelay[chain + 1];
280
if ( thisDelay > LongestCDelay[chain]) {
281
LongestCDelay[chain] = thisDelay;
283
if ( TargetTower->DelayBeforeFiring > LongestFDelay[chain]) {
284
LongestFDelay[chain] = TargetTower->DelayBeforeFiring;
288
//ascend to the next chain
290
while(senderIdx < pTargetData->PrismForwarding.Senders.Count) {
291
BuildingClass *SenderTower = pTargetData->PrismForwarding.Senders[senderIdx];
292
SetChargeDelay_Get(SenderTower, (chain + 1), endChain, LongestChain, LongestCDelay, LongestFDelay);
298
void BuildingTypeExt::cPrismForwarding::SetChargeDelay_Set
299
(BuildingClass * TargetTower, int chain, DWORD *LongestCDelay, DWORD *LongestFDelay) {
300
BuildingExt::ExtData *pTargetData = BuildingExt::ExtMap.Find(TargetTower);
301
pTargetData->PrismForwarding.PrismChargeDelay = (LongestFDelay[chain] - TargetTower->DelayBeforeFiring) + LongestCDelay[chain];
303
while (senderIdx < pTargetData->PrismForwarding.Senders.Count) {
304
BuildingClass *Sender = pTargetData->PrismForwarding.Senders[senderIdx];
305
SetChargeDelay_Set(Sender, (chain + 1), LongestCDelay, LongestFDelay);
311
//Need to find out all the places that this should be called and call it!
312
//Death of tower, temporal, EMP, loss of power
313
void BuildingTypeExt::cPrismForwarding::RemoveSlave(BuildingClass *SlaveTower, bool bCease) {
314
if (int PrismStage = SlaveTower->PrismStage) {
315
BuildingExt::ExtData *pSlaveData = BuildingExt::ExtMap.Find(SlaveTower);
316
OrphanSlave(SlaveTower);
317
if (BuildingClass *TargetTower = pSlaveData->PrismForwarding.SupportTarget) {
318
BuildingExt::ExtData *pTargetData = BuildingExt::ExtMap.Find(TargetTower);
319
signed int idx = pTargetData->PrismForwarding.Senders.FindItemIndex(&SlaveTower);
321
pTargetData->PrismForwarding.Senders.RemoveItem(idx);
325
pSlaveData->PrismForwarding.PrismChargeDelay = 0;
326
SlaveTower->DelayBeforeFiring = 0;
327
pSlaveData->PrismForwarding.ModifierReserve = 0.0;
328
pSlaveData->PrismForwarding.DamageReserve = 0;
329
SlaveTower->DestroyNthAnim(BuildingAnimSlot::Special);
330
//SlaveTower->PlayNthAnim(BuildingAnimSlot::Active); //do we need this?
331
SlaveTower->PrismStage = pcs_Idle;
336
void BuildingTypeExt::cPrismForwarding::OrphanSlave(BuildingClass *SlaveTower) {
337
if (int PrismStage = SlaveTower->PrismStage) {
338
BuildingExt::ExtData *pSlaveData = BuildingExt::ExtMap.Find(SlaveTower);
339
BuildingTypeClass *pSlaveType = SlaveTower->Type;
340
BuildingTypeExt::ExtData *pSlaveTypeData = BuildingTypeExt::ExtMap.Find(pSlaveType);
341
if (pSlaveData->PrismForwarding.PrismChargeDelay) {
342
//hasn't started charging yet, so can go idle immediately
343
SlaveTower->PrismStage = pcs_Idle;
344
pSlaveData->PrismForwarding.PrismChargeDelay = 0;
345
SlaveTower->DelayBeforeFiring = 0;
346
pSlaveData->PrismForwarding.ModifierReserve = 0.0;
347
pSlaveData->PrismForwarding.DamageReserve = 0;
348
SlaveTower->DestroyNthAnim(BuildingAnimSlot::Special);
349
//SlaveTower->PlayNthAnim(BuildingAnimSlot::Active); //do we need this?
350
} //else this is already charging so allow anim to continue
351
if (BuildingClass *TargetTower = pSlaveData->PrismForwarding.SupportTarget) {
352
BuildingExt::ExtData *pTargetData = BuildingExt::ExtMap.Find(TargetTower);
353
--TargetTower->SupportingPrisms; //Ares doesn't actually use this, but maintaining it anyway (as direct feeds only)
354
pSlaveData->PrismForwarding.SupportTarget = NULL; //thus making this slave tower an orphan
356
while(senderIdx < pSlaveData->PrismForwarding.Senders.Count) {
357
if (BuildingClass *NextTower = pTargetData->PrismForwarding.Senders[senderIdx]) {
358
OrphanSlave(NextTower);