~ares-developers/ares/gd03

« back to all changes in this revision

Viewing changes to Ext/BuildingType/PrismForward.cpp

  • Committer: Renegade
  • Date: 2010-05-29 08:12:17 UTC
  • Revision ID: git-v1:0a1bb6321f04d723afe64d1b843dc87b4da783ec
Creating /trunk/src.

git-svn-id: svn://svn.renegadeprojects.com/ares/trunk@622 859b54a9-7a54-0410-aeb3-f8d2f1fa40fd

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#include "Body.h"
2
 
#include "../Building/Body.h"
3
 
#include "../Techno/Body.h"
4
 
#include <BulletClass.h>
5
 
#include <LaserDrawClass.h>
6
 
 
7
 
#include <vector>
8
 
#include <algorithm>
9
 
 
10
 
void BuildingTypeExt::cPrismForwarding::Initialize(BuildingTypeClass *pThis) {
11
 
        this->Enabled = NO;
12
 
        if (pThis == RulesClass::Instance->PrismType) {
13
 
                this->Enabled = YES;
14
 
        }
15
 
        this->Targets.AddItem(pThis);
16
 
}
17
 
 
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)) {
22
 
                        this->Enabled = YES;
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) {
28
 
                        this->Enabled = NO;
29
 
                }
30
 
        }
31
 
 
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);
37
 
                                if(target) {
38
 
                                        this->Targets.AddItem(target);
39
 
                                }
40
 
                        }
41
 
                }
42
 
 
43
 
                INI_EX exINI(pINI);
44
 
 
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");
51
 
 
52
 
                if (this->SupportRange != -1) {
53
 
                        this->SupportRange = this->SupportRange * 256; //stored in leptons, not cells
54
 
                }
55
 
 
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");
60
 
 
61
 
                int ChargeDelay = pINI->ReadInteger(pID, "PrismForwarding.ChargeDelay", this->ChargeDelay);
62
 
                if (ChargeDelay >= 1) {
63
 
                        this->ChargeDelay.Set(ChargeDelay);
64
 
                } else {
65
 
                        Debug::Log("[Developer Error] %s has an invalid PrismForwarding.ChargeDelay (%d), overriding to 1.\n", pThis->ID, ChargeDelay);
66
 
                }
67
 
 
68
 
        }
69
 
}
70
 
 
71
 
signed int BuildingTypeExt::cPrismForwarding::GetSupportRange(BuildingTypeClass *pThis) {
72
 
        if(this->SupportRange != 0) {
73
 
                return this->SupportRange;
74
 
        }
75
 
        if(WeaponTypeClass* Secondary = pThis->get_Secondary()) {
76
 
                return Secondary->Range;
77
 
        } else if(WeaponTypeClass* Primary = pThis->get_Primary()) {
78
 
                return Primary->Range;
79
 
        }
80
 
        return 0;
81
 
}
82
 
 
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:
88
 
        // 1---2---4---6
89
 
        // |        \
90
 
        // |         7
91
 
        // |
92
 
        // 3---5--8
93
 
        // as opposed to
94
 
        // 1---2---3---4
95
 
        // |          /
96
 
        // |         5
97
 
        // |
98
 
        // 6---7--8
99
 
        // ...which would not be as good.
100
 
        int countSlaves = 0;
101
 
        if (stage == 0) {
102
 
                countSlaves += AcquireSlaves_SingleStage(MasterTower, TargetTower, stage, (chain + 1), NetworkSize, LongestChain);
103
 
        } else {
104
 
                BuildingExt::ExtData *pTargetData = BuildingExt::ExtMap.Find(TargetTower);
105
 
                int senderIdx = 0;
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);
109
 
                        ++senderIdx;
110
 
                }
111
 
        }
112
 
        return countSlaves;
113
 
}
114
 
 
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
118
 
 
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);
123
 
 
124
 
        signed int MaxFeeds = pTargetTypeData->PrismForwarding.MaxFeeds;
125
 
        signed int MaxNetworkSize = pMasterTypeData->PrismForwarding.MaxNetworkSize;
126
 
        signed int MaxChainLength = pMasterTypeData->PrismForwarding.MaxChainLength;
127
 
 
128
 
        if (MaxFeeds == 0
129
 
                        || (MaxChainLength != -1 && MaxChainLength < chain)
130
 
                        || (MaxNetworkSize != -1 && MaxNetworkSize <= *NetworkSize)) {
131
 
                return 0;
132
 
        }
133
 
 
134
 
        struct PrismTargetData {
135
 
                BuildingClass * Tower;
136
 
                int Distance;
137
 
 
138
 
                bool operator < (PrismTargetData const &rhs) {
139
 
                        return this->Distance < rhs.Distance;
140
 
                }
141
 
        };
142
 
 
143
 
        CoordStruct MyPosition, curPosition;
144
 
        TargetTower->GetPosition_2(&MyPosition);
145
 
 
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);
155
 
 
156
 
                                PrismTargetData pd = {SlaveTower, Distance};
157
 
                                EligibleTowers.push_back(pd);
158
 
                        }
159
 
                }
160
 
        }
161
 
 
162
 
        std::sort(EligibleTowers.begin(), EligibleTowers.end());
163
 
        //std::reverse(EligibleTowers.begin(), EligibleTowers.end());
164
 
        
165
 
        //now enslave the towers in order of proximity
166
 
        int iFeeds = 0;
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
171
 
                ++iFeeds;
172
 
                ++(*NetworkSize);
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);
181
 
 
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);
186
 
        }
187
 
 
188
 
        if (iFeeds != 0 && chain > *LongestChain) {
189
 
                ++(*LongestChain);
190
 
        }
191
 
 
192
 
        return iFeeds;
193
 
}
194
 
 
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)) {
233
 
                                                                                        //within range
234
 
                                                                                        return true;
235
 
                                                                                }
236
 
                                                                        }
237
 
                                                                }
238
 
                                                        }
239
 
                                                }
240
 
                                        }
241
 
                                }
242
 
                        }
243
 
                }
244
 
        }
245
 
        return false;
246
 
}
247
 
 
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));
255
 
        
256
 
        int endChain = LongestChain;
257
 
        while (endChain >= 0) {
258
 
                SetChargeDelay_Get(TargetTower, 0, endChain, LongestChain, LongestCDelay, LongestFDelay);
259
 
                --endChain;
260
 
        }
261
 
        
262
 
        int temp = 0;
263
 
        while (temp != LongestChain) {
264
 
                ++temp;
265
 
        }
266
 
 
267
 
        SetChargeDelay_Set(TargetTower, 0, LongestCDelay, LongestFDelay);
268
 
        delete [] LongestFDelay;
269
 
        delete [] LongestCDelay;
270
 
}
271
 
 
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;
282
 
                        }
283
 
                        if ( TargetTower->DelayBeforeFiring > LongestFDelay[chain]) {
284
 
                                LongestFDelay[chain] = TargetTower->DelayBeforeFiring;
285
 
                        }
286
 
                }
287
 
        } else {
288
 
                //ascend to the next chain
289
 
                int senderIdx = 0;
290
 
                while(senderIdx < pTargetData->PrismForwarding.Senders.Count) {
291
 
                        BuildingClass *SenderTower = pTargetData->PrismForwarding.Senders[senderIdx];
292
 
                        SetChargeDelay_Get(SenderTower, (chain + 1), endChain, LongestChain, LongestCDelay, LongestFDelay);
293
 
                        ++senderIdx;
294
 
                }
295
 
        }
296
 
}
297
 
 
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];
302
 
        int senderIdx = 0;
303
 
        while (senderIdx < pTargetData->PrismForwarding.Senders.Count) {
304
 
                BuildingClass *Sender = pTargetData->PrismForwarding.Senders[senderIdx];
305
 
                SetChargeDelay_Set(Sender, (chain + 1), LongestCDelay, LongestFDelay);
306
 
                ++senderIdx;
307
 
        }
308
 
}
309
 
 
310
 
 
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);
320
 
                        if(idx != -1) {
321
 
                                pTargetData->PrismForwarding.Senders.RemoveItem(idx);
322
 
                        }
323
 
                }
324
 
                if (bCease) {
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;
332
 
                }
333
 
        }
334
 
}
335
 
 
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
355
 
                        int senderIdx = 0;
356
 
                        while(senderIdx < pSlaveData->PrismForwarding.Senders.Count) {
357
 
                                if (BuildingClass *NextTower = pTargetData->PrismForwarding.Senders[senderIdx]) {
358
 
                                        OrphanSlave(NextTower);
359
 
                                        ++senderIdx;
360
 
                                }
361
 
                        }
362
 
                }
363
 
        }
364
 
}
365