1 // ==============================================================
2 // This file is part of Glest (www.glest.org)
3 //
4 // Copyright (C) 2001-2008 Marti�o Figueroa
5 //
6 // You can redistribute this code and/or modify it under
7 // the terms of the GNU General Public License as published
8 // by the Free Software Foundation; either version 2 of the
9 // License, or (at your option) any later version
10 // ==============================================================
11
12 #include "faction.h"
13
14 #include <algorithm>
15 #include <cassert>
16
17 #include "resource_type.h"
18 #include "unit.h"
19 #include "util.h"
20 #include "sound_renderer.h"
21 #include "renderer.h"
22 #include "tech_tree.h"
23 #include "leak_dumper.h"
24
25 using namespace Shared::Util;
26
27 namespace Glest{ namespace Game{
28
29 // =====================================================
30 // class Faction
31 // =====================================================
32
init(const FactionType * factionType,ControlType control,TechTree * techTree,int factionIndex,int teamIndex,int startLocationIndex,bool thisFaction,bool giveResources)33 void Faction::init(
34 const FactionType *factionType, ControlType control, TechTree *techTree,
35 int factionIndex, int teamIndex, int startLocationIndex, bool thisFaction, bool giveResources)
36 {
37 this->control= control;
38 this->factionType= factionType;
39 this->startLocationIndex= startLocationIndex;
40 this->index= factionIndex;
41 this->teamIndex= teamIndex;
42 this->thisFaction= thisFaction;
43
44 resources.resize(techTree->getResourceTypeCount());
45 store.resize(techTree->getResourceTypeCount());
46 for(int i=0; i<techTree->getResourceTypeCount(); ++i){
47 const ResourceType *rt= techTree->getResourceType(i);
48 int resourceAmount= giveResources? factionType->getStartingResourceAmount(rt): 0;
49 resources[i].init(rt, resourceAmount);
50 store[i].init(rt, 0);
51 }
52
53 texture= Renderer::getInstance().newTexture2D(rsGame);
54 texture->load("data/core/faction_textures/faction"+intToStr(index)+".tga");
55 }
56
end()57 void Faction::end(){
58 deleteValues(units.begin(), units.end());
59 }
60
61 // ================== get ==================
62
getResource(const ResourceType * rt) const63 const Resource *Faction::getResource(const ResourceType *rt) const{
64 for(int i=0; i<resources.size(); ++i){
65 if(rt==resources[i].getType()){
66 return &resources[i];
67 }
68 }
69 assert(false);
70 return NULL;
71 }
72
getStoreAmount(const ResourceType * rt) const73 int Faction::getStoreAmount(const ResourceType *rt) const{
74 for(int i=0; i<store.size(); ++i){
75 if(rt==store[i].getType()){
76 return store[i].getAmount();
77 }
78 }
79 assert(false);
80 return 0;
81 }
82
getCpuControl() const83 bool Faction::getCpuControl() const{
84 return control==ctCpu || control==ctCpuUltra;
85 }
86
87
88 // ==================== upgrade manager ====================
89
startUpgrade(const UpgradeType * ut)90 void Faction::startUpgrade(const UpgradeType *ut){
91 upgradeManager.startUpgrade(ut, index);
92 }
93
cancelUpgrade(const UpgradeType * ut)94 void Faction::cancelUpgrade(const UpgradeType *ut){
95 upgradeManager.cancelUpgrade(ut);
96 }
97
finishUpgrade(const UpgradeType * ut)98 void Faction::finishUpgrade(const UpgradeType *ut){
99 upgradeManager.finishUpgrade(ut);
100 for(int i=0; i<getUnitCount(); ++i){
101 getUnit(i)->applyUpgrade(ut);
102 }
103 }
104
105 // ==================== reqs ====================
106
107 //checks if all required units and upgrades are present
reqsOk(const RequirableType * rt) const108 bool Faction::reqsOk(const RequirableType *rt) const{
109
110 //required units
111 for(int i=0; i<rt->getUnitReqCount(); ++i){
112 bool found=false;
113 for(int j=0; j<getUnitCount(); ++j){
114 Unit *unit= getUnit(j);
115 const UnitType *ut= unit->getType();
116 if(rt->getUnitReq(i)==ut && unit->isOperative()){
117 found= true;
118 break;
119 }
120 }
121 if(!found){
122 return false;
123 }
124 }
125
126 //required upgrades
127 for(int i=0; i<rt->getUpgradeReqCount(); ++i){
128 if(!upgradeManager.isUpgraded(rt->getUpgradeReq(i))){
129 return false;
130 }
131 }
132 return true;
133
134 }
135
reqsOk(const CommandType * ct) const136 bool Faction::reqsOk(const CommandType *ct) const{
137
138 if(ct->getProduced()!=NULL && !reqsOk(ct->getProduced())){
139 return false;
140 }
141
142 if(ct->getClass()==ccUpgrade){
143 const UpgradeCommandType *uct= static_cast<const UpgradeCommandType*>(ct);
144 if(upgradeManager.isUpgradingOrUpgraded(uct->getProducedUpgrade())){
145 return false;
146 }
147 }
148
149 return reqsOk(static_cast<const RequirableType*>(ct));
150 }
151
152 // ================== cost application ==================
153
154 //apply costs except static production (start building/production)
applyCosts(const ProducibleType * p)155 bool Faction::applyCosts(const ProducibleType *p){
156
157 if(!checkCosts(p)){
158 return false;
159 }
160
161 //for each unit cost spend it
162 //pass 2, decrease resources, except negative static costs (ie: farms)
163 for(int i=0; i<p->getCostCount(); ++i){
164 const ResourceType *rt= p->getCost(i)->getType();
165 int cost= p->getCost(i)->getAmount();
166 if((cost>0 || rt->getClass()!=rcStatic) && rt->getClass()!=rcConsumable){
167 incResourceAmount(rt, -(cost));
168 }
169
170 }
171 return true;
172 }
173
174 //apply discount (when a morph ends)
applyDiscount(const ProducibleType * p,int discount)175 void Faction::applyDiscount(const ProducibleType *p, int discount){
176 //increase resources
177 for(int i=0; i<p->getCostCount(); ++i){
178 const ResourceType *rt= p->getCost(i)->getType();
179 int cost= p->getCost(i)->getAmount();
180 if((cost>0 || rt->getClass()!=rcStatic) && rt->getClass()!=rcConsumable){
181 incResourceAmount(rt, cost*discount/100);
182 }
183 }
184 }
185
186 //apply static production (for starting units)
applyStaticCosts(const ProducibleType * p)187 void Faction::applyStaticCosts(const ProducibleType *p){
188
189 //decrease static resources
190 for(int i=0; i<p->getCostCount(); ++i){
191 const ResourceType *rt= p->getCost(i)->getType();
192 if(rt->getClass()==rcStatic){
193 int cost= p->getCost(i)->getAmount();
194 if(cost>0){
195 incResourceAmount(rt, -cost);
196 }
197 }
198 }
199 }
200
201 //apply static production (when a mana source is done)
applyStaticProduction(const ProducibleType * p)202 void Faction::applyStaticProduction(const ProducibleType *p){
203
204 //decrease static resources
205 for(int i=0; i<p->getCostCount(); ++i){
206 const ResourceType *rt= p->getCost(i)->getType();
207 if(rt->getClass()==rcStatic){
208 int cost= p->getCost(i)->getAmount();
209 if(cost<0){
210 incResourceAmount(rt, -cost);
211 }
212 }
213 }
214 }
215
216 //deapply all costs except static production (usually when a building is cancelled)
deApplyCosts(const ProducibleType * p)217 void Faction::deApplyCosts(const ProducibleType *p){
218
219 //increase resources
220 for(int i=0; i<p->getCostCount(); ++i){
221 const ResourceType *rt= p->getCost(i)->getType();
222 int cost= p->getCost(i)->getAmount();
223 if((cost>0 || rt->getClass()!=rcStatic) && rt->getClass()!=rcConsumable){
224 incResourceAmount(rt, cost);
225 }
226
227 }
228 }
229
230 //deapply static costs (usually when a unit dies)
deApplyStaticCosts(const ProducibleType * p)231 void Faction::deApplyStaticCosts(const ProducibleType *p){
232
233 //decrease resources
234 for(int i=0; i<p->getCostCount(); ++i){
235 const ResourceType *rt= p->getCost(i)->getType();
236 if(rt->getClass()==rcStatic){
237 int cost= p->getCost(i)->getAmount();
238 incResourceAmount(rt, cost);
239 }
240 }
241 }
242
243 //deapply static costs, but not negative costs, for when building gets killed
deApplyStaticConsumption(const ProducibleType * p)244 void Faction::deApplyStaticConsumption(const ProducibleType *p){
245
246 //decrease resources
247 for(int i=0; i<p->getCostCount(); ++i){
248 const ResourceType *rt= p->getCost(i)->getType();
249 if(rt->getClass()==rcStatic){
250 int cost= p->getCost(i)->getAmount();
251 if(cost>0){
252 incResourceAmount(rt, cost);
253 }
254 }
255 }
256 }
257
258 //apply resource on interval (cosumable resouces)
applyCostsOnInterval()259 void Faction::applyCostsOnInterval(){
260
261 //increment consumables
262 for(int j=0; j<getUnitCount(); ++j){
263 Unit *unit= getUnit(j);
264 if(unit->isOperative()){
265 for(int k=0; k<unit->getType()->getCostCount(); ++k){
266 const Resource *resource= unit->getType()->getCost(k);
267 if(resource->getType()->getClass()==rcConsumable && resource->getAmount()<0){
268 incResourceAmount(resource->getType(), -resource->getAmount());
269 }
270 }
271 }
272 }
273
274 //decrement consumables
275 for(int j=0; j<getUnitCount(); ++j){
276 Unit *unit= getUnit(j);
277 if(unit->isOperative()){
278 for(int k=0; k<unit->getType()->getCostCount(); ++k){
279 const Resource *resource= unit->getType()->getCost(k);
280 if(resource->getType()->getClass()==rcConsumable && resource->getAmount()>0){
281 incResourceAmount(resource->getType(), -resource->getAmount());
282
283 //decrease unit hp
284 if(getResource(resource->getType())->getAmount()<0){
285 resetResourceAmount(resource->getType());
286 unit->decHp(unit->getType()->getMaxHp()/3);
287 StaticSound *sound= unit->getType()->getFirstStOfClass(scDie)->getSound();
288 if(sound!=NULL && thisFaction){
289 SoundRenderer::getInstance().playFx(sound);
290 }
291 }
292 }
293 }
294 }
295 }
296 }
297
checkCosts(const ProducibleType * pt)298 bool Faction::checkCosts(const ProducibleType *pt){
299
300 //for each unit cost check if enough resources
301 for(int i=0; i<pt->getCostCount(); ++i){
302 const ResourceType *rt= pt->getCost(i)->getType();
303 int cost= pt->getCost(i)->getAmount();
304 if(cost>0){
305 int available= getResource(rt)->getAmount();
306 if(cost>available){
307 return false;
308 }
309 }
310 }
311
312 return true;
313 }
314
315 // ================== diplomacy ==================
316
isAlly(const Faction * faction)317 bool Faction::isAlly(const Faction *faction){
318 return teamIndex==faction->getTeam();
319 }
320
321 // ================== misc ==================
322
incResourceAmount(const ResourceType * rt,int amount)323 void Faction::incResourceAmount(const ResourceType *rt, int amount){
324 for(int i=0; i<resources.size(); ++i){
325 Resource *r= &resources[i];
326 if(r->getType()==rt){
327 r->setAmount(r->getAmount()+amount);
328 if(r->getType()->getClass()!=rcStatic && r->getAmount()>getStoreAmount(rt)){
329 r->setAmount(getStoreAmount(rt));
330 }
331 return;
332 }
333 }
334 assert(false);
335 }
336
setResourceBalance(const ResourceType * rt,int balance)337 void Faction::setResourceBalance(const ResourceType *rt, int balance){
338 for(int i=0; i<resources.size(); ++i){
339 Resource *r= &resources[i];
340 if(r->getType()==rt){
341 r->setBalance(balance);
342 return;
343 }
344 }
345 assert(false);
346 }
347
findUnit(int id)348 Unit *Faction::findUnit(int id){
349 UnitMap::iterator it= unitMap.find(id);
350
351 if(it==unitMap.end()){
352 return NULL;
353 }
354 return it->second;
355 }
356
addUnit(Unit * unit)357 void Faction::addUnit(Unit *unit){
358 units.push_back(unit);
359 unitMap.insert(make_pair(unit->getId(), unit));
360 }
361
removeUnit(Unit * unit)362 void Faction::removeUnit(Unit *unit){
363 for(int i=0; i<units.size(); ++i){
364 if(units[i]==unit){
365 units.erase(units.begin()+i);
366 unitMap.erase(unit->getId());
367 assert(units.size()==unitMap.size());
368 return;
369 }
370 }
371 assert(false);
372 }
373
addStore(const UnitType * unitType)374 void Faction::addStore(const UnitType *unitType){
375 for(int i=0; i<unitType->getStoredResourceCount(); ++i){
376 const Resource *r= unitType->getStoredResource(i);
377 for(int j=0; j<store.size(); ++j){
378 Resource *storedResource= &store[j];
379 if(storedResource->getType() == r->getType()){
380 storedResource->setAmount(storedResource->getAmount() + r->getAmount());
381 }
382 }
383 }
384 }
385
removeStore(const UnitType * unitType)386 void Faction::removeStore(const UnitType *unitType){
387 for(int i=0; i<unitType->getStoredResourceCount(); ++i){
388 const Resource *r= unitType->getStoredResource(i);
389 for(int j=0; j<store.size(); ++j){
390 Resource *storedResource= &store[j];
391 if(storedResource->getType() == r->getType()){
392 storedResource->setAmount(storedResource->getAmount() - r->getAmount());
393 }
394 }
395 }
396 limitResourcesToStore();
397 }
398
limitResourcesToStore()399 void Faction::limitResourcesToStore(){
400 for(int i=0; i<resources.size(); ++i){
401 Resource *r= &resources[i];
402 Resource *s= &store[i];
403 if(r->getType()->getClass()!=rcStatic && r->getAmount()>s->getAmount()){
404 r->setAmount(s->getAmount());
405 }
406 }
407 }
408
resetResourceAmount(const ResourceType * rt)409 void Faction::resetResourceAmount(const ResourceType *rt){
410 for(int i=0; i<resources.size(); ++i){
411 if(resources[i].getType()==rt){
412 resources[i].setAmount(0);
413 return;
414 }
415 }
416 assert(false);
417 }
418
419 }}//end namespace
420