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