1 /***************************************************************************
2 * Mechanized Assault and Exploration Reloaded Projectfile *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
18 ***************************************************************************/
19 #include <cmath>
20
21 #include "game/data/units/building.h"
22
23 #include "game/logic/client.h"
24 #include "game/logic/clientevents.h"
25 #include "utility/listhelpers.h"
26 #include "game/logic/fxeffects.h"
27 #include "main.h"
28 #include "netmessage.h"
29 #include "pcx.h"
30 #include "game/data/player/player.h"
31 #include "game/logic/server.h"
32 #include "game/logic/serverevents.h"
33 #include "settings.h"
34 #include "game/logic/upgradecalculator.h"
35 #include "game/data/units/vehicle.h"
36 #include "video.h"
37 #include "unifonts.h"
38 #include "game/data/report/savedreportsimple.h"
39 #include "game/data/report/special/savedreportresourcechanged.h"
40 #include "utility/random.h"
41
42 #include "ui/sound/soundmanager.h"
43 #include "ui/sound/effects/soundeffectvoice.h"
44
45 using namespace std;
46
47
48 //--------------------------------------------------------------------------
cBuildListItem()49 cBuildListItem::cBuildListItem()
50 {}
51
52 //--------------------------------------------------------------------------
cBuildListItem(sID type_,int remainingMetal_)53 cBuildListItem::cBuildListItem (sID type_, int remainingMetal_) :
54 type (type_),
55 remainingMetal (remainingMetal_)
56 {}
57
58 //--------------------------------------------------------------------------
cBuildListItem(const cBuildListItem & other)59 cBuildListItem::cBuildListItem (const cBuildListItem& other) :
60 type (other.type),
61 remainingMetal (other.remainingMetal)
62 {}
63
64 //--------------------------------------------------------------------------
cBuildListItem(cBuildListItem && other)65 cBuildListItem::cBuildListItem (cBuildListItem&& other) :
66 type (std::move (other.type)),
67 remainingMetal (std::move (other.remainingMetal))
68 {}
69
70 //--------------------------------------------------------------------------
operator =(const cBuildListItem & other)71 cBuildListItem& cBuildListItem::operator= (const cBuildListItem& other)
72 {
73 type = other.type;
74 remainingMetal = other.remainingMetal;
75 return *this;
76 }
77
78 //--------------------------------------------------------------------------
operator =(cBuildListItem && other)79 cBuildListItem& cBuildListItem::operator= (cBuildListItem && other)
80 {
81 type = std::move (other.type);
82 remainingMetal = std::move (other.remainingMetal);
83 return *this;
84 }
85
86 //--------------------------------------------------------------------------
getType() const87 const sID& cBuildListItem::getType() const
88 {
89 return type;
90 }
91
92 //--------------------------------------------------------------------------
setType(const sID & type_)93 void cBuildListItem::setType (const sID& type_)
94 {
95 auto oldType = type;
96 type = type_;
97 if (type != oldType) typeChanged();
98 }
99
100 //--------------------------------------------------------------------------
getRemainingMetal() const101 int cBuildListItem::getRemainingMetal() const
102 {
103 return remainingMetal;
104 }
105
106 //--------------------------------------------------------------------------
setRemainingMetal(int value)107 void cBuildListItem::setRemainingMetal (int value)
108 {
109 std::swap (remainingMetal, value);
110 if (value != remainingMetal) remainingMetalChanged();
111 }
112
113 //--------------------------------------------------------------------------
114 // cBuilding Implementation
115 //--------------------------------------------------------------------------
116
117 //--------------------------------------------------------------------------
cBuilding(const sUnitData * b,cPlayer * Owner,unsigned int ID)118 cBuilding::cBuilding (const sUnitData* b, cPlayer* Owner, unsigned int ID) :
119 cUnit ((Owner != 0 && b != 0) ? Owner->getUnitDataCurrentVersion (b->ID) : 0,
120 Owner,
121 ID),
122 isWorking (false)
123 {
124 setSentryActive (data.canAttack != TERRAIN_NONE);
125
126 RubbleTyp = 0;
127 RubbleValue = 0;
128 researchArea = cResearch::kAttackResearch;
129 uiData = b ? UnitsData.getBuildingUI (b->ID) : 0;
130 points = 0;
131
132 if (Owner == nullptr || b == nullptr)
133 {
134 return;
135 }
136
137 BaseN = false;
138 BaseBN = false;
139 BaseE = false;
140 BaseBE = false;
141 BaseS = false;
142 BaseBS = false;
143 BaseW = false;
144 BaseBW = false;
145 repeatBuild = false;
146
147 MaxMetalProd = 0;
148 MaxGoldProd = 0;
149 MaxOilProd = 0;
150 data.setHitpoints (data.getHitpointsMax());
151 data.setAmmo (data.getAmmoMax());
152 SubBase = nullptr;
153 buildSpeed = 0;
154
155 if (data.isBig)
156 {
157 DamageFXPointX = random (64) + 32;
158 DamageFXPointY = random (64) + 32;
159 DamageFXPointX2 = random (64) + 32;
160 DamageFXPointY2 = random (64) + 32;
161 }
162 else
163 {
164 DamageFXPointX = random (64 - 24);
165 DamageFXPointY = random (64 - 24);
166 }
167
168 refreshData();
169
170 buildListChanged.connect ([&]() { statusChanged(); });
171 buildListFirstItemDataChanged.connect ([&]() { statusChanged(); });
172 researchAreaChanged.connect ([&]() { statusChanged(); });
173 metalPerRoundChanged.connect([&]() { statusChanged(); });
174 ownerChanged.connect ([&]() { registerOwnerEvents(); });
175
176 registerOwnerEvents();
177 }
178
179 //--------------------------------------------------------------------------
~cBuilding()180 cBuilding::~cBuilding()
181 {
182 }
183
184 //----------------------------------------------------
185 /** Returns a string with the current state */
186 //----------------------------------------------------
getStatusStr(const cPlayer * player) const187 string cBuilding::getStatusStr (const cPlayer* player) const
188 {
189 if (isDisabled())
190 {
191 string sText;
192 sText = lngPack.i18n ("Text~Comp~Disabled") + " (";
193 sText += iToStr (getDisabledTurns()) + ")";
194 return sText;
195 }
196 if (isUnitWorking() || (factoryHasJustFinishedBuilding() && isDisabled() == false))
197 {
198 // Factory:
199 if (!data.canBuild.empty() && !buildList.empty() && getOwner() == player)
200 {
201 const cBuildListItem& buildListItem = buildList[0];
202 const string& unitName = buildListItem.getType().getUnitDataOriginalVersion()->name;
203 string sText;
204
205 if (buildListItem.getRemainingMetal() > 0)
206 {
207 int iRound;
208
209 iRound = (int) ceilf (buildListItem.getRemainingMetal() / (float)getMetalPerRound());
210 sText = lngPack.i18n ("Text~Comp~Producing") + lngPack.i18n ("Text~Punctuation~Colon");
211 sText += unitName + " (";
212 sText += iToStr (iRound) + ")";
213
214 if (font->getTextWide (sText, FONT_LATIN_SMALL_WHITE) > 126)
215 {
216 sText = lngPack.i18n ("Text~Comp~Producing") + ":\n";
217 sText += unitName + " (";
218 sText += iToStr (iRound) + ")";
219 }
220
221 return sText;
222 }
223 else //new unit is rdy + which kind of unit
224 {
225 sText = lngPack.i18n ("Text~Comp~Producing_Fin");
226 sText += lngPack.i18n ("Text~Punctuation~Colon");
227 sText += unitName;
228
229 if (font->getTextWide (sText) > 126)
230 {
231 sText = lngPack.i18n ("Text~Comp~Producing_Fin");
232 sText += ":\n";
233 sText += unitName;
234 }
235 return sText;
236 }
237 }
238
239 // Research Center
240 if (data.canResearch && getOwner() == player)
241 {
242 string sText = lngPack.i18n ("Text~Comp~Working") + "\n";
243 for (int area = 0; area < cResearch::kNrResearchAreas; area++)
244 {
245 if (getOwner()->getResearchCentersWorkingOnArea ((cResearch::ResearchArea)area) > 0)
246 {
247 switch (area)
248 {
249 case cResearch::kAttackResearch: sText += lngPack.i18n ("Text~Others~Attack"); break;
250 case cResearch::kShotsResearch: sText += lngPack.i18n ("Text~Others~Shots_7"); break;
251 case cResearch::kRangeResearch: sText += lngPack.i18n ("Text~Others~Range"); break;
252 case cResearch::kArmorResearch: sText += lngPack.i18n ("Text~Others~Armor_7"); break;
253 case cResearch::kHitpointsResearch: sText += lngPack.i18n ("Text~Others~Hitpoints_7"); break;
254 case cResearch::kSpeedResearch: sText += lngPack.i18n ("Text~Others~Speed"); break;
255 case cResearch::kScanResearch: sText += lngPack.i18n ("Text~Others~Scan"); break;
256 case cResearch::kCostResearch: sText += lngPack.i18n ("Text~Others~Costs"); break;
257 }
258 sText += lngPack.i18n ("Text~Punctuation~Colon") + iToStr (getOwner()->getResearchState().getRemainingTurns (area, getOwner()->getResearchCentersWorkingOnArea ((cResearch::ResearchArea)area))) + "\n";
259 }
260 }
261 return sText;
262 }
263
264 // Goldraffinerie:
265 if (data.convertsGold && getOwner() == player)
266 {
267 string sText;
268 sText = lngPack.i18n ("Text~Comp~Working") + "\n";
269 sText += lngPack.i18n ("Text~Title~Credits") + lngPack.i18n ("Text~Punctuation~Colon");
270 sText += iToStr (getOwner()->getCredits());
271 return sText;
272 }
273
274 return lngPack.i18n ("Text~Comp~Working");
275 }
276
277 if (isAttacking())
278 return lngPack.i18n ("Text~Comp~AttackingStatusStr");
279 else if (isBeeingAttacked())
280 return lngPack.i18n ("Text~Comp~IsBeeingAttacked");
281 else if (isSentryActive())
282 return lngPack.i18n ("Text~Comp~Sentry");
283 else if (isManualFireActive())
284 return lngPack.i18n ("Text~Comp~ReactionFireOff");
285
286 return lngPack.i18n ("Text~Comp~Waits");
287 }
288
289
290 //--------------------------------------------------------------------------
makeReport(cSoundManager & soundManager) const291 void cBuilding::makeReport (cSoundManager& soundManager) const
292 {
293 if (data.canResearch && isUnitWorking() && getOwner() && getOwner()->isCurrentTurnResearchAreaFinished (getResearchArea()))
294 {
295 soundManager.playSound (std::make_shared<cSoundEffectVoice> (eSoundEffectType::VoiceUnitStatus, VoiceData.VOIResearchComplete));
296 }
297 }
298
299 //--------------------------------------------------------------------------
300 /** Refreshs all data to the maximum values */
301 //--------------------------------------------------------------------------
refreshData()302 bool cBuilding::refreshData()
303 {
304 // NOTE: according to MAX 1.04 units get their shots/movepoints back even if they are disabled
305
306 if (data.getShots() < data.getShotsMax())
307 {
308 data.setShots (std::min (this->data.getShotsMax(), this->data.getAmmo()));
309 return true;
310 }
311 return false;
312 }
313
render_rubble(SDL_Surface * surface,const SDL_Rect & dest,float zoomFactor,bool drawShadow) const314 void cBuilding::render_rubble (SDL_Surface* surface, const SDL_Rect& dest, float zoomFactor, bool drawShadow) const
315 {
316 assert (!getOwner());
317
318 SDL_Rect src;
319
320 if (data.isBig)
321 {
322 if (!UnitsData.dirt_big) return;
323 src.w = src.h = (int) (UnitsData.dirt_big_org->h * zoomFactor);
324 }
325 else
326 {
327 if (!UnitsData.dirt_small) return;
328 src.w = src.h = (int) (UnitsData.dirt_small_org->h * zoomFactor);
329 }
330
331 src.x = src.w * RubbleTyp;
332 SDL_Rect tmp = dest;
333 src.y = 0;
334
335 // draw the shadows
336 if (drawShadow)
337 {
338 if (data.isBig)
339 {
340 CHECK_SCALING (*UnitsData.dirt_big_shw, *UnitsData.dirt_big_shw_org, zoomFactor);
341 SDL_BlitSurface (UnitsData.dirt_big_shw.get(), &src, surface, &tmp);
342 }
343 else
344 {
345 CHECK_SCALING (*UnitsData.dirt_small_shw, *UnitsData.dirt_small_shw_org, zoomFactor);
346 SDL_BlitSurface (UnitsData.dirt_small_shw.get(), &src, surface, &tmp);
347 }
348 }
349
350 // draw the building
351 tmp = dest;
352
353 if (data.isBig)
354 {
355 CHECK_SCALING (*UnitsData.dirt_big, *UnitsData.dirt_big_org, zoomFactor);
356 SDL_BlitSurface (UnitsData.dirt_big.get(), &src, surface, &tmp);
357 }
358 else
359 {
360 CHECK_SCALING (*UnitsData.dirt_small, *UnitsData.dirt_small_org, zoomFactor);
361 SDL_BlitSurface (UnitsData.dirt_small.get(), &src, surface, &tmp);
362 }
363 }
364
render_beton(SDL_Surface * surface,const SDL_Rect & dest,float zoomFactor) const365 void cBuilding::render_beton (SDL_Surface* surface, const SDL_Rect& dest, float zoomFactor) const
366 {
367 SDL_Rect tmp = dest;
368 if (data.isBig)
369 {
370 CHECK_SCALING (*GraphicsData.gfx_big_beton, *GraphicsData.gfx_big_beton_org, zoomFactor);
371
372 if (alphaEffectValue && cSettings::getInstance().isAlphaEffects())
373 SDL_SetSurfaceAlphaMod (GraphicsData.gfx_big_beton.get(), alphaEffectValue);
374 else
375 SDL_SetSurfaceAlphaMod (GraphicsData.gfx_big_beton.get(), 254);
376
377 SDL_BlitSurface (GraphicsData.gfx_big_beton.get(), nullptr, surface, &tmp);
378 }
379 else
380 {
381 CHECK_SCALING (*UnitsData.ptr_small_beton, *UnitsData.ptr_small_beton_org, zoomFactor);
382 if (alphaEffectValue && cSettings::getInstance().isAlphaEffects())
383 SDL_SetSurfaceAlphaMod (UnitsData.ptr_small_beton, alphaEffectValue);
384 else
385 SDL_SetSurfaceAlphaMod (UnitsData.ptr_small_beton, 254);
386
387 SDL_BlitSurface (UnitsData.ptr_small_beton, nullptr, surface, &tmp);
388 SDL_SetSurfaceAlphaMod (UnitsData.ptr_small_beton, 254);
389 }
390 }
391
render_simple(SDL_Surface * surface,const SDL_Rect & dest,float zoomFactor,int animationTime,int alpha) const392 void cBuilding::render_simple (SDL_Surface* surface, const SDL_Rect& dest, float zoomFactor, int animationTime, int alpha) const
393 {
394 int frameNr = dir;
395 if (data.hasFrames && data.isAnimated && cSettings::getInstance().isAnimations() &&
396 isDisabled() == false)
397 {
398 frameNr = (animationTime % data.hasFrames);
399 }
400
401 render_simple (surface, dest, zoomFactor, data, *uiData, getOwner(), frameNr, alpha);
402 }
403
render_simple(SDL_Surface * surface,const SDL_Rect & dest,float zoomFactor,const sUnitData & data,const sBuildingUIData & uiData,const cPlayer * owner,int frameNr,int alpha)404 /*static*/ void cBuilding::render_simple (SDL_Surface* surface, const SDL_Rect& dest, float zoomFactor, const sUnitData& data, const sBuildingUIData& uiData, const cPlayer* owner, int frameNr, int alpha)
405 {
406 // read the size:
407 SDL_Rect src;
408 src.x = 0;
409 src.y = 0;
410 if (data.hasFrames)
411 {
412 src.w = Round (64.0f * zoomFactor);
413 src.h = Round (64.0f * zoomFactor);
414 }
415 else
416 {
417 src.w = (int) (uiData.img_org->w * zoomFactor);
418 src.h = (int) (uiData.img_org->h * zoomFactor);
419 }
420
421 // blit the players color and building graphic
422 if (data.hasPlayerColor && owner) SDL_BlitSurface (owner->getColor().getTexture(), nullptr, GraphicsData.gfx_tmp.get(), nullptr);
423 else SDL_FillRect (GraphicsData.gfx_tmp.get(), nullptr, 0x00FF00FF);
424
425 if (data.hasFrames)
426 {
427 src.x = frameNr * Round (64.0f * zoomFactor);
428
429 CHECK_SCALING (*uiData.img, *uiData.img_org, zoomFactor);
430 SDL_BlitSurface (uiData.img.get(), &src, GraphicsData.gfx_tmp.get(), nullptr);
431
432 src.x = 0;
433 }
434 else if (data.hasClanLogos)
435 {
436 CHECK_SCALING (*uiData.img, *uiData.img_org, zoomFactor);
437 src.x = 0;
438 src.y = 0;
439 src.w = (int) (128 * zoomFactor);
440 src.h = (int) (128 * zoomFactor);
441 // select clan image
442 if (owner && owner->getClan() != -1)
443 src.x = (int) ((owner->getClan() + 1) * 128 * zoomFactor);
444 SDL_BlitSurface (uiData.img.get(), &src, GraphicsData.gfx_tmp.get(), nullptr);
445 }
446 else
447 {
448 CHECK_SCALING (*uiData.img, *uiData.img_org, zoomFactor);
449 SDL_BlitSurface (uiData.img.get(), nullptr, GraphicsData.gfx_tmp.get(), nullptr);
450 }
451
452 // draw the building
453 SDL_Rect tmp = dest;
454
455 src.x = 0;
456 src.y = 0;
457
458 SDL_SetSurfaceAlphaMod (GraphicsData.gfx_tmp.get(), alpha);
459 SDL_BlitSurface (GraphicsData.gfx_tmp.get(), &src, surface, &tmp);
460 }
461
462
render(unsigned long long animationTime,SDL_Surface * surface,const SDL_Rect & dest,float zoomFactor,bool drawShadow,bool drawConcrete) const463 void cBuilding::render (unsigned long long animationTime, SDL_Surface* surface, const SDL_Rect& dest, float zoomFactor, bool drawShadow, bool drawConcrete) const
464 {
465 // Note: when changing something in this function,
466 // make sure to update the caching rules!
467
468 // check, if it is dirt:
469 if (!getOwner())
470 {
471 render_rubble (surface, dest, zoomFactor, drawShadow);
472 return;
473 }
474
475 // draw the concrete
476 if (data.hasBetonUnderground && drawConcrete)
477 {
478 render_beton (surface, dest, zoomFactor);
479 }
480 // draw the connector slots:
481 if ((this->SubBase && !alphaEffectValue) || data.isConnectorGraphic)
482 {
483 drawConnectors (surface, dest, zoomFactor, drawShadow);
484 if (data.isConnectorGraphic) return;
485 }
486
487 // draw the shadows
488 if (drawShadow)
489 {
490 SDL_Rect tmp = dest;
491 if (alphaEffectValue && cSettings::getInstance().isAlphaEffects())
492 SDL_SetSurfaceAlphaMod (uiData->shw.get(), alphaEffectValue / 5);
493 else
494 SDL_SetSurfaceAlphaMod (uiData->shw.get(), 50);
495
496 CHECK_SCALING (*uiData->shw, *uiData->shw_org, zoomFactor);
497 blittAlphaSurface (uiData->shw.get(), nullptr, surface, &tmp);
498 }
499
500 render_simple (surface, dest, zoomFactor, animationTime, alphaEffectValue && cSettings::getInstance().isAlphaEffects() ? alphaEffectValue : 254);
501 }
502
503 //--------------------------------------------------------------------------
updateNeighbours(const cMap & map)504 void cBuilding::updateNeighbours (const cMap& map)
505 {
506 if (!data.isBig)
507 {
508 getOwner()->base.checkNeighbour (getPosition() + cPosition (0, -1), *this);
509 getOwner()->base.checkNeighbour (getPosition() + cPosition (1, 0), *this);
510 getOwner()->base.checkNeighbour (getPosition() + cPosition (0, 1), *this);
511 getOwner()->base.checkNeighbour (getPosition() + cPosition (-1, 0), *this);
512 }
513 else
514 {
515 getOwner()->base.checkNeighbour (getPosition() + cPosition (0, -1), *this);
516 getOwner()->base.checkNeighbour (getPosition() + cPosition (1, -1), *this);
517 getOwner()->base.checkNeighbour (getPosition() + cPosition (2, 0), *this);
518 getOwner()->base.checkNeighbour (getPosition() + cPosition (2, 1), *this);
519 getOwner()->base.checkNeighbour (getPosition() + cPosition (0, 2), *this);
520 getOwner()->base.checkNeighbour (getPosition() + cPosition (1, 2), *this);
521 getOwner()->base.checkNeighbour (getPosition() + cPosition (-1, 0), *this);
522 getOwner()->base.checkNeighbour (getPosition() + cPosition (-1, 1), *this);
523 }
524 CheckNeighbours (map);
525 }
526
527 //--------------------------------------------------------------------------
528 /** Checks, if there are neighbours */
529 //--------------------------------------------------------------------------
CheckNeighbours(const cMap & map)530 void cBuilding::CheckNeighbours (const cMap& map)
531 {
532 #define CHECK_NEIGHBOUR(x, y, m) \
533 if (map.isValidPosition (cPosition(x, y))) \
534 { \
535 const cBuilding* b = map.getField(cPosition(x, y)).getTopBuilding(); \
536 if (b && b->getOwner() == getOwner() && b->data.connectsToBase) \
537 {m = true;}else{m = false;} \
538 }
539
540 if (!data.isBig)
541 {
542 CHECK_NEIGHBOUR (getPosition().x() , getPosition().y() - 1, BaseN)
543 CHECK_NEIGHBOUR (getPosition().x() + 1, getPosition().y() , BaseE)
544 CHECK_NEIGHBOUR (getPosition().x() , getPosition().y() + 1, BaseS)
545 CHECK_NEIGHBOUR (getPosition().x() - 1, getPosition().y() , BaseW)
546 }
547 else
548 {
549 CHECK_NEIGHBOUR (getPosition().x() , getPosition().y() - 1, BaseN)
550 CHECK_NEIGHBOUR (getPosition().x() + 1, getPosition().y() - 1, BaseBN)
551 CHECK_NEIGHBOUR (getPosition().x() + 2, getPosition().y() , BaseE)
552 CHECK_NEIGHBOUR (getPosition().x() + 2, getPosition().y() + 1, BaseBE)
553 CHECK_NEIGHBOUR (getPosition().x() , getPosition().y() + 2, BaseS)
554 CHECK_NEIGHBOUR (getPosition().x() + 1, getPosition().y() + 2, BaseBS)
555 CHECK_NEIGHBOUR (getPosition().x() - 1, getPosition().y() , BaseW)
556 CHECK_NEIGHBOUR (getPosition().x() - 1, getPosition().y() + 1, BaseBW)
557 }
558 }
559
560 //--------------------------------------------------------------------------
561 /** Draws the connectors at the building: */
562 //--------------------------------------------------------------------------
drawConnectors(SDL_Surface * surface,SDL_Rect dest,float zoomFactor,bool drawShadow) const563 void cBuilding::drawConnectors (SDL_Surface* surface, SDL_Rect dest, float zoomFactor, bool drawShadow) const
564 {
565 SDL_Rect src, temp;
566
567 CHECK_SCALING (*UnitsData.ptr_connector, *UnitsData.ptr_connector_org, zoomFactor);
568 CHECK_SCALING (*UnitsData.ptr_connector_shw, *UnitsData.ptr_connector_shw_org, zoomFactor);
569
570 if (alphaEffectValue) SDL_SetSurfaceAlphaMod (UnitsData.ptr_connector, alphaEffectValue);
571 else SDL_SetSurfaceAlphaMod (UnitsData.ptr_connector, 254);
572
573 src.y = 0;
574 src.x = 0;
575 src.h = src.w = UnitsData.ptr_connector->h;
576
577 if (!data.isBig)
578 {
579 if (BaseN && BaseE && BaseS && BaseW) src.x = 15;
580 else if (BaseN && BaseE && BaseS && !BaseW) src.x = 13;
581 else if (BaseN && BaseE && !BaseS && BaseW) src.x = 12;
582 else if (BaseN && BaseE && !BaseS && !BaseW) src.x = 8;
583 else if (BaseN && !BaseE && BaseS && BaseW) src.x = 11;
584 else if (BaseN && !BaseE && BaseS && !BaseW) src.x = 5;
585 else if (BaseN && !BaseE && !BaseS && BaseW) src.x = 7;
586 else if (BaseN && !BaseE && !BaseS && !BaseW) src.x = 1;
587 else if (!BaseN && BaseE && BaseS && BaseW) src.x = 14;
588 else if (!BaseN && BaseE && BaseS && !BaseW) src.x = 9;
589 else if (!BaseN && BaseE && !BaseS && BaseW) src.x = 6;
590 else if (!BaseN && BaseE && !BaseS && !BaseW) src.x = 2;
591 else if (!BaseN && !BaseE && BaseS && BaseW) src.x = 10;
592 else if (!BaseN && !BaseE && BaseS && !BaseW) src.x = 3;
593 else if (!BaseN && !BaseE && !BaseS && BaseW) src.x = 4;
594 else if (!BaseN && !BaseE && !BaseS && !BaseW) src.x = 0;
595 src.x *= src.h;
596
597 if (src.x != 0 || data.isConnectorGraphic)
598 {
599 // blit shadow
600 temp = dest;
601 if (drawShadow) blittAlphaSurface (UnitsData.ptr_connector_shw, &src, surface, &temp);
602 // blit the image
603 temp = dest;
604 SDL_BlitSurface (UnitsData.ptr_connector, &src, surface, &temp);
605 }
606 }
607 else
608 {
609 // make connector stubs of big buildings.
610 // upper left field
611 src.x = 0;
612 if (BaseN && BaseW) src.x = 7;
613 else if (BaseN && !BaseW) src.x = 1;
614 else if (!BaseN && BaseW) src.x = 4;
615 src.x *= src.h;
616
617 if (src.x != 0)
618 {
619 temp = dest;
620 if (drawShadow) blittAlphaSurface (UnitsData.ptr_connector_shw, &src, surface, &temp);
621 temp = dest;
622 SDL_BlitSurface (UnitsData.ptr_connector, &src, surface, &temp);
623 }
624
625 // upper right field
626 src.x = 0;
627 dest.x += Round (64.0f * zoomFactor);
628 if (BaseBN && BaseE) src.x = 8;
629 else if (BaseBN && !BaseE) src.x = 1;
630 else if (!BaseBN && BaseE) src.x = 2;
631 src.x *= src.h;
632
633 if (src.x != 0)
634 {
635 temp = dest;
636 if (drawShadow) blittAlphaSurface (UnitsData.ptr_connector_shw, &src, surface, &temp);
637 temp = dest;
638 SDL_BlitSurface (UnitsData.ptr_connector, &src, surface, &temp);
639 }
640
641 // lower right field
642 src.x = 0;
643 dest.y += Round (64.0f * zoomFactor);
644 if (BaseBE && BaseBS) src.x = 9;
645 else if (BaseBE && !BaseBS) src.x = 2;
646 else if (!BaseBE && BaseBS) src.x = 3;
647 src.x *= src.h;
648
649 if (src.x != 0)
650 {
651 temp = dest;
652 if (drawShadow) blittAlphaSurface (UnitsData.ptr_connector_shw, &src, surface, &temp);
653 temp = dest;
654 SDL_BlitSurface (UnitsData.ptr_connector, &src, surface, &temp);
655 }
656
657 // lower left field
658 src.x = 0;
659 dest.x -= Round (64.0f * zoomFactor);
660 if (BaseS && BaseBW) src.x = 10;
661 else if (BaseS && !BaseBW) src.x = 3;
662 else if (!BaseS && BaseBW) src.x = 4;
663 src.x *= src.h;
664
665 if (src.x != 0)
666 {
667 temp = dest;
668 if (drawShadow) blittAlphaSurface (UnitsData.ptr_connector_shw, &src, surface, &temp);
669 temp = dest;
670 SDL_BlitSurface (UnitsData.ptr_connector, &src, surface, &temp);
671 }
672 }
673 }
674
675 //--------------------------------------------------------------------------
676 /** starts the building for the server thread */
677 //--------------------------------------------------------------------------
ServerStartWork(cServer & server)678 void cBuilding::ServerStartWork (cServer& server)
679 {
680 if (isUnitWorking())
681 {
682 sendDoStartWork (server, *this);
683 return;
684 }
685
686 //-- first check all requirements
687
688 if (isDisabled())
689 {
690 sendSavedReport (server, cSavedReportSimple (eSavedReportType::BuildingDisabled), getOwner());
691 return;
692 }
693
694 // needs human workers:
695 if (data.needsHumans)
696 {
697 if (SubBase->HumanNeed + data.needsHumans > SubBase->HumanProd)
698 {
699 sendSavedReport (server, cSavedReportSimple (eSavedReportType::TeamInsufficient), getOwner());
700 return;
701 }
702 }
703
704 // needs gold:
705 if (data.convertsGold)
706 {
707 if (data.convertsGold + SubBase->GoldNeed > SubBase->getGoldProd() + SubBase->getGold())
708 {
709 sendSavedReport (server, cSavedReportSimple (eSavedReportType::GoldInsufficient), getOwner());
710 return;
711 }
712 }
713
714 // needs raw material:
715 if (data.needsMetal)
716 {
717 if (SubBase->MetalNeed + std::min (getMetalPerRound(), buildList[0].getRemainingMetal()) > SubBase->getMetalProd() + SubBase->getMetal())
718 {
719 sendSavedReport (server, cSavedReportSimple (eSavedReportType::MetalInsufficient), getOwner());
720 return;
721 }
722 }
723
724 // needs oil:
725 if (data.needsOil)
726 {
727 // check if there is enough Oil for the generators
728 // (current production + reserves)
729 if (data.needsOil + SubBase->OilNeed > SubBase->getOil() + SubBase->getMaxOilProd())
730 {
731 sendSavedReport (server, cSavedReportSimple (eSavedReportType::FuelInsufficient), getOwner());
732 return;
733 }
734 else if (data.needsOil + SubBase->OilNeed > SubBase->getOil() + SubBase->getOilProd())
735 {
736 // increase oil production
737 int missingOil = data.needsOil + SubBase->OilNeed - (SubBase->getOil() + SubBase->getOilProd());
738
739 int metal = SubBase->getMetalProd();
740 int gold = SubBase->getGoldProd();
741
742 // temporay decrease metal and gold production
743 SubBase->setMetalProd (0);
744 SubBase->setGoldProd (0);
745
746 SubBase->changeOilProd (missingOil);
747
748 SubBase->setGoldProd (gold);
749 SubBase->setMetalProd (metal);
750
751 sendSavedReport (server, cSavedReportResourceChanged (RES_OIL, missingOil, true), getOwner());
752 if (SubBase->getMetalProd() < metal)
753 sendSavedReport (server, cSavedReportResourceChanged (RES_METAL, metal - SubBase->getMetalProd(), false), getOwner());
754 if (SubBase->getGoldProd() < gold)
755 sendSavedReport (server, cSavedReportResourceChanged (RES_GOLD, gold - SubBase->getGoldProd(), false), getOwner());
756 }
757 }
758
759 // IsWorking is set to true before checking the energy production.
760 // So if an energy generator has to be started,
761 // it can use the fuel production of this building
762 // (when this building is a mine).
763 setWorking (true);
764
765 // set mine values. This has to be undone, if the energy is insufficient
766 if (data.canMineMaxRes > 0)
767 {
768 int mineFree = data.canMineMaxRes;
769
770 SubBase->changeMetalProd (MaxMetalProd);
771 mineFree -= MaxMetalProd;
772
773 SubBase->changeGoldProd (min (MaxGoldProd, mineFree));
774 mineFree -= min (MaxGoldProd, mineFree);
775
776 SubBase->changeOilProd (min (MaxOilProd, mineFree));
777 }
778
779 // Energy consumers:
780 if (data.needsEnergy)
781 {
782 if (data.needsEnergy + SubBase->EnergyNeed > SubBase->EnergyProd)
783 {
784 // try to increase energy production
785 if (!SubBase->increaseEnergyProd (server, data.needsEnergy + SubBase->EnergyNeed - SubBase->EnergyProd))
786 {
787 setWorking (false);
788
789 // reset mine values
790 if (data.canMineMaxRes > 0)
791 {
792 int metal = SubBase->getMetalProd();
793 int oil = SubBase->getOilProd();
794 int gold = SubBase->getGoldProd();
795
796 SubBase->setMetalProd (0);
797 SubBase->setOilProd (0);
798 SubBase->setGoldProd (0);
799
800 SubBase->setMetalProd (min (metal, SubBase->getMaxAllowedMetalProd()));
801 SubBase->setGoldProd (min (gold, SubBase->getMaxAllowedGoldProd()));
802 SubBase->setOilProd (min (oil, SubBase->getMaxAllowedOilProd()));
803 }
804
805 sendSavedReport (server, cSavedReportSimple (eSavedReportType::EnergyInsufficient), getOwner());
806 return;
807 }
808 sendSavedReport (server, cSavedReportSimple (eSavedReportType::EnergyToLow), getOwner());
809 }
810 }
811
812 //-- everything is ready to start the building
813
814 SubBase->EnergyProd += data.produceEnergy;
815 SubBase->EnergyNeed += data.needsEnergy;
816
817 SubBase->HumanNeed += data.needsHumans;
818 SubBase->HumanProd += data.produceHumans;
819
820 SubBase->OilNeed += data.needsOil;
821
822 // raw material consumer:
823 if (data.needsMetal)
824 SubBase->MetalNeed += std::min (getMetalPerRound(), buildList[0].getRemainingMetal());
825
826 // gold consumer:
827 SubBase->GoldNeed += data.convertsGold;
828
829 // research building
830 if (data.canResearch)
831 {
832 getOwner()->startAResearch (researchArea);
833 }
834
835 if (data.canScore)
836 {
837 sendNumEcos (server, *getOwner());
838 }
839
840 sendSubbaseValues (server, *SubBase, *getOwner());
841 sendDoStartWork (server, *this);
842 }
843
844 //------------------------------------------------------------
845 /** starts the building in the client thread */
846 //------------------------------------------------------------
clientStartWork()847 void cBuilding::clientStartWork()
848 {
849 if (isUnitWorking())
850 return;
851 setWorking (true);
852 if (data.canResearch)
853 getOwner()->startAResearch (researchArea);
854 }
855
856 //--------------------------------------------------------------------------
857 /** Stops the building's working in the server thread */
858 //--------------------------------------------------------------------------
ServerStopWork(cServer & server,bool override)859 void cBuilding::ServerStopWork (cServer& server, bool override)
860 {
861 if (!isUnitWorking())
862 {
863 sendDoStopWork (server, *this);
864 return;
865 }
866
867 // energy generators
868 if (data.produceEnergy)
869 {
870 if (SubBase->EnergyNeed > SubBase->EnergyProd - data.produceEnergy && !override)
871 {
872 sendSavedReport (server, cSavedReportSimple (eSavedReportType::EnergyIsNeeded), getOwner());
873 return;
874 }
875
876 SubBase->EnergyProd -= data.produceEnergy;
877 SubBase->OilNeed -= data.needsOil;
878 }
879
880 setWorking (false);
881
882 // Energy consumers:
883 if (data.needsEnergy)
884 SubBase->EnergyNeed -= data.needsEnergy;
885
886 // raw material consumer:
887 if (data.needsMetal)
888 SubBase->MetalNeed -= std::min (getMetalPerRound(), buildList[0].getRemainingMetal());
889
890 // gold consumer
891 if (data.convertsGold)
892 SubBase->GoldNeed -= data.convertsGold;
893
894 // human consumer
895 if (data.needsHumans)
896 SubBase->HumanNeed -= data.needsHumans;
897
898 // Minen:
899 if (data.canMineMaxRes > 0)
900 {
901 int metal = SubBase->getMetalProd();
902 int oil = SubBase->getOilProd();
903 int gold = SubBase->getGoldProd();
904
905 SubBase->setMetalProd (0);
906 SubBase->setOilProd (0);
907 SubBase->setGoldProd (0);
908
909 SubBase->setMetalProd (min (metal, SubBase->getMaxAllowedMetalProd()));
910 SubBase->setGoldProd (min (gold, SubBase->getMaxAllowedGoldProd()));
911 SubBase->setOilProd (min (oil, SubBase->getMaxAllowedOilProd()));
912 }
913
914 if (data.canResearch)
915 {
916 getOwner()->stopAResearch (researchArea);
917 }
918
919 if (data.canScore)
920 {
921 sendNumEcos (server, *getOwner());
922 }
923
924 sendSubbaseValues (server, *SubBase, *getOwner());
925 sendDoStopWork (server, *this);
926 }
927
928 //------------------------------------------------------------
929 /** stops the building in the client thread */
930 //------------------------------------------------------------
clientStopWork()931 void cBuilding::clientStopWork()
932 {
933 if (!isUnitWorking())
934 return;
935 setWorking (false);
936 if (data.canResearch)
937 getOwner()->stopAResearch (researchArea);
938 }
939
940 //------------------------------------------------------------
canTransferTo(const cPosition & position,const cMapField & overUnitField) const941 bool cBuilding::canTransferTo (const cPosition& position, const cMapField& overUnitField) const
942 {
943 if (overUnitField.getVehicle())
944 {
945 const cVehicle* v = overUnitField.getVehicle();
946
947 if (v->getOwner() != this->getOwner())
948 return false;
949
950 if (v->data.storeResType != data.storeResType)
951 return false;
952
953 if (v->isUnitBuildingABuilding() || v->isUnitClearing())
954 return false;
955
956 for (size_t i = 0; i != SubBase->buildings.size(); ++i)
957 {
958 const cBuilding* b = SubBase->buildings[i];
959
960 if (b->isNextTo (position)) return true;
961 }
962
963 return false;
964 }
965 else if (overUnitField.getTopBuilding())
966 {
967 const cBuilding* b = overUnitField.getTopBuilding();
968
969 if (b == this)
970 return false;
971
972 if (b->SubBase != SubBase)
973 return false;
974
975 if (b->getOwner() != this->getOwner())
976 return false;
977
978 if (data.storeResType != b->data.storeResType)
979 return false;
980
981 return true;
982 }
983 return false;
984 }
985
986 //--------------------------------------------------------------------------
canExitTo(const cPosition & position,const cMap & map,const sUnitData & vehicleData) const987 bool cBuilding::canExitTo (const cPosition& position, const cMap& map, const sUnitData& vehicleData) const
988 {
989 if (!map.possiblePlaceVehicle (vehicleData, position, getOwner())) return false;
990 if (!isNextTo (position)) return false;
991
992 return true;
993 }
994
995 //--------------------------------------------------------------------------
canLoad(const cPosition & position,const cMap & map,bool checkPosition) const996 bool cBuilding::canLoad (const cPosition& position, const cMap& map, bool checkPosition) const
997 {
998 if (map.isValidPosition (position) == false) return false;
999
1000 if (canLoad (map.getField (position).getPlane(), checkPosition)) return true;
1001 else return canLoad (map.getField (position).getVehicle(), checkPosition);
1002 }
1003
1004 //--------------------------------------------------------------------------
1005 /** returns, if the vehicle can be loaded from its position: */
1006 //--------------------------------------------------------------------------
canLoad(const cVehicle * Vehicle,bool checkPosition) const1007 bool cBuilding::canLoad (const cVehicle* Vehicle, bool checkPosition) const
1008 {
1009 if (!Vehicle) return false;
1010
1011 if (Vehicle->isUnitLoaded()) return false;
1012
1013 if (data.getStoredUnits() == data.storageUnitsMax) return false;
1014
1015 if (checkPosition && !isNextTo (Vehicle->getPosition())) return false;
1016
1017 if (!Contains (data.storeUnitsTypes, Vehicle->data.isStorageType)) return false;
1018
1019 if (Vehicle->getClientMoveJob() && (Vehicle->isUnitMoving() || Vehicle->isAttacking() || Vehicle->MoveJobActive)) return false;
1020
1021 if (Vehicle->getOwner() != getOwner() || Vehicle->isUnitBuildingABuilding() || Vehicle->isUnitClearing()) return false;
1022
1023 if (Vehicle->isBeeingAttacked()) return false;
1024
1025 return true;
1026 }
1027
1028 //--------------------------------------------------------------------------
1029 /** loads a vehicle: */
1030 //--------------------------------------------------------------------------
storeVehicle(cVehicle & vehicle,cMap & map)1031 void cBuilding::storeVehicle (cVehicle& vehicle, cMap& map)
1032 {
1033 map.deleteVehicle (vehicle);
1034 if (vehicle.isSentryActive())
1035 {
1036 vehicle.getOwner()->deleteSentry (vehicle);
1037 }
1038
1039 vehicle.setLoaded (true);
1040 vehicle.setIsBeeinAttacked (false);
1041
1042 storedUnits.push_back (&vehicle);
1043 data.setStoredUnits (data.getStoredUnits() + 1);
1044
1045 getOwner()->doScan();
1046 }
1047
1048 //-----------------------------------------------------------------------
1049 // Unloads a vehicle
exitVehicleTo(cVehicle & vehicle,const cPosition & position,cMap & map)1050 void cBuilding::exitVehicleTo (cVehicle& vehicle, const cPosition& position, cMap& map)
1051 {
1052 Remove (storedUnits, &vehicle);
1053
1054 data.setStoredUnits (data.getStoredUnits() - 1);
1055
1056 map.addVehicle (vehicle, position);
1057
1058 vehicle.setPosition (position);
1059
1060 vehicle.setLoaded (false);
1061
1062 getOwner()->doScan();
1063 }
1064
1065 //-------------------------------------------------------------------------------
1066 // Draws big symbols for the info menu:
1067 //-------------------------------------------------------------------------------
DrawSymbolBig(eSymbolsBig sym,int x,int y,int maxx,int value,int orgvalue,SDL_Surface * sf)1068 void cBuilding::DrawSymbolBig (eSymbolsBig sym, int x, int y, int maxx, int value, int orgvalue, SDL_Surface* sf)
1069 {
1070 SDL_Rect src = {0, 0, 0, 0};
1071
1072 switch (sym)
1073 {
1074 case SBSpeed:
1075 src.x = 0;
1076 src.y = 109;
1077 src.w = 11;
1078 src.h = 12;
1079 break;
1080
1081 case SBHits:
1082 src.x = 11;
1083 src.y = 109;
1084 src.w = 7;
1085 src.h = 11;
1086 break;
1087
1088 case SBAmmo:
1089 src.x = 18;
1090 src.y = 109;
1091 src.w = 9;
1092 src.h = 14;
1093 break;
1094
1095 case SBAttack:
1096 src.x = 27;
1097 src.y = 109;
1098 src.w = 10;
1099 src.h = 14;
1100 break;
1101
1102 case SBShots:
1103 src.x = 37;
1104 src.y = 109;
1105 src.w = 15;
1106 src.h = 7;
1107 break;
1108
1109 case SBRange:
1110 src.x = 52;
1111 src.y = 109;
1112 src.w = 13;
1113 src.h = 13;
1114 break;
1115
1116 case SBArmor:
1117 src.x = 65;
1118 src.y = 109;
1119 src.w = 11;
1120 src.h = 14;
1121 break;
1122
1123 case SBScan:
1124 src.x = 76;
1125 src.y = 109;
1126 src.w = 13;
1127 src.h = 13;
1128 break;
1129
1130 case SBMetal:
1131 src.x = 89;
1132 src.y = 109;
1133 src.w = 12;
1134 src.h = 15;
1135 break;
1136
1137 case SBOil:
1138 src.x = 101;
1139 src.y = 109;
1140 src.w = 11;
1141 src.h = 12;
1142 break;
1143
1144 case SBGold:
1145 src.x = 112;
1146 src.y = 109;
1147 src.w = 13;
1148 src.h = 10;
1149 break;
1150
1151 case SBEnergy:
1152 src.x = 125;
1153 src.y = 109;
1154 src.w = 13;
1155 src.h = 17;
1156 break;
1157
1158 case SBHuman:
1159 src.x = 138;
1160 src.y = 109;
1161 src.w = 12;
1162 src.h = 16;
1163 break;
1164 }
1165
1166 maxx -= src.w;
1167
1168 if (orgvalue < value)
1169 {
1170 maxx -= src.w + 3;
1171 }
1172
1173 int offx = src.w;
1174
1175 while (offx * value >= maxx)
1176 {
1177 offx--;
1178
1179 if (offx < 4)
1180 {
1181 value /= 2;
1182 orgvalue /= 2;
1183 offx = src.w;
1184 }
1185 }
1186
1187 SDL_Rect dest;
1188 dest.x = x;
1189 dest.y = y;
1190
1191 Uint32 color = SDL_MapRGB (sf->format, 0xFC, 0, 0);
1192 for (int i = 0; i < value; i++)
1193 {
1194 if (i == orgvalue)
1195 {
1196 SDL_Rect mark;
1197 dest.x += src.w + 3;
1198 mark.x = dest.x - src.w / 2;
1199 mark.y = dest.y;
1200 mark.w = 1;
1201 mark.h = src.h;
1202 SDL_FillRect (sf, &mark, color);
1203 }
1204
1205 SDL_BlitSurface (GraphicsData.gfx_hud_stuff.get(), &src, sf, &dest);
1206
1207 dest.x += offx;
1208 }
1209 }
1210
1211 //-------------------------------------------------------------------------------
1212 /** checks the resources that are available under the mining station */
1213 //--------------------------------------------------------------------------
1214
CheckRessourceProd(const cServer & server)1215 void cBuilding::CheckRessourceProd (const cServer& server)
1216 {
1217 auto position = getPosition();
1218
1219 MaxMetalProd = 0;
1220 MaxGoldProd = 0;
1221 MaxOilProd = 0;
1222 const sResources* res = &server.Map->getResource (position);
1223
1224 switch (res->typ)
1225 {
1226 case RES_METAL: MaxMetalProd += res->value; break;
1227 case RES_GOLD: MaxGoldProd += res->value; break;
1228 case RES_OIL: MaxOilProd += res->value; break;
1229 }
1230
1231 position.x()++;
1232 res = &server.Map->getResource (position);
1233 switch (res->typ)
1234 {
1235 case RES_METAL: MaxMetalProd += res->value; break;
1236 case RES_GOLD: MaxGoldProd += res->value; break;
1237 case RES_OIL: MaxOilProd += res->value; break;
1238 }
1239
1240 position.y()++;
1241 res = &server.Map->getResource (position);
1242 switch (res->typ)
1243 {
1244 case RES_METAL: MaxMetalProd += res->value; break;
1245 case RES_GOLD: MaxGoldProd += res->value; break;
1246 case RES_OIL: MaxOilProd += res->value; break;
1247 }
1248
1249 position.x()--;
1250 res = &server.Map->getResource (position);
1251 switch (res->typ)
1252 {
1253 case RES_METAL: MaxMetalProd += res->value; break;
1254 case RES_GOLD: MaxGoldProd += res->value; break;
1255 case RES_OIL: MaxOilProd += res->value; break;
1256 }
1257
1258 MaxMetalProd = min (MaxMetalProd, data.canMineMaxRes);
1259 MaxGoldProd = min (MaxGoldProd, data.canMineMaxRes);
1260 MaxOilProd = min (MaxOilProd, data.canMineMaxRes);
1261 }
1262
1263 //--------------------------------------------------------------------------
1264 /** calculates the costs and the duration of the 3 buildspeeds
1265 * for the vehicle with the given base costs
1266 * iRemainingMetal is only needed for recalculating costs of vehicles
1267 * in the Buildqueue and is set per default to -1 */
1268 //--------------------------------------------------------------------------
calcTurboBuild(std::array<int,3> & turboBuildRounds,std::array<int,3> & turboBuildCosts,int vehicleCosts,int remainingMetal) const1269 void cBuilding::calcTurboBuild (std::array<int, 3>& turboBuildRounds, std::array<int, 3>& turboBuildCosts, int vehicleCosts, int remainingMetal) const
1270 {
1271 // first calc costs for a new Vehical
1272
1273 // 1x
1274 turboBuildCosts[0] = vehicleCosts;
1275
1276 // 2x
1277 int a = turboBuildCosts[0];
1278 turboBuildCosts[1] = turboBuildCosts[0];
1279
1280 while (a >= 2 * data.needsMetal)
1281 {
1282 turboBuildCosts[1] += 2 * data.needsMetal;
1283 a -= 2 * data.needsMetal;
1284 }
1285
1286 // 4x
1287 turboBuildCosts[2] = turboBuildCosts[1];
1288 a = turboBuildCosts[1];
1289
1290 while (a >= 15)
1291 {
1292 turboBuildCosts[2] += (12 * data.needsMetal - min (a, 8 * data.needsMetal));
1293 a -= 8 * data.needsMetal;
1294 }
1295
1296 // now this is a litle bit tricky ...
1297 // trying to calculate a plausible value,
1298 // if we are changing the speed of an already started build-job
1299 if (remainingMetal >= 0)
1300 {
1301 float WorkedRounds;
1302
1303 switch (buildSpeed) // BuildSpeed here is the previous build speed
1304 {
1305 case 0:
1306 WorkedRounds = (turboBuildCosts[0] - remainingMetal) / (1.f * data.needsMetal);
1307 turboBuildCosts[0] -= (int) (1 * 1 * data.needsMetal * WorkedRounds);
1308 turboBuildCosts[1] -= (int) (0.5f * 4 * data.needsMetal * WorkedRounds);
1309 turboBuildCosts[2] -= (int) (0.25f * 12 * data.needsMetal * WorkedRounds);
1310 break;
1311
1312 case 1:
1313 WorkedRounds = (turboBuildCosts[1] - remainingMetal) / (float) (4 * data.needsMetal);
1314 turboBuildCosts[0] -= (int) (2 * 1 * data.needsMetal * WorkedRounds);
1315 turboBuildCosts[1] -= (int) (1 * 4 * data.needsMetal * WorkedRounds);
1316 turboBuildCosts[2] -= (int) (0.5f * 12 * data.needsMetal * WorkedRounds);
1317 break;
1318
1319 case 2:
1320 WorkedRounds = (turboBuildCosts[2] - remainingMetal) / (float) (12 * data.needsMetal);
1321 turboBuildCosts[0] -= (int) (4 * 1 * data.needsMetal * WorkedRounds);
1322 turboBuildCosts[1] -= (int) (2 * 4 * data.needsMetal * WorkedRounds);
1323 turboBuildCosts[2] -= (int) (1 * 12 * data.needsMetal * WorkedRounds);
1324 break;
1325 }
1326 }
1327
1328 // calc needed Rounds
1329 turboBuildRounds[0] = (int) ceilf (turboBuildCosts[0] / (1.f * data.needsMetal));
1330
1331 if (data.maxBuildFactor > 1)
1332 {
1333 turboBuildRounds[1] = (int) ceilf (turboBuildCosts[1] / (4.f * data.needsMetal));
1334 turboBuildRounds[2] = (int) ceilf (turboBuildCosts[2] / (12.f * data.needsMetal));
1335 }
1336 else
1337 {
1338 turboBuildRounds[1] = 0;
1339 turboBuildRounds[2] = 0;
1340 }
1341 }
1342
1343 //--------------------------------------------------------------------------
isDetectedByPlayer(const cPlayer * player) const1344 bool cBuilding::isDetectedByPlayer (const cPlayer* player) const
1345 {
1346 return Contains (detectedByPlayerList, player);
1347 }
1348
1349 //--------------------------------------------------------------------------
setDetectedByPlayer(cServer & server,cPlayer * player,bool addToDetectedInThisTurnList)1350 void cBuilding::setDetectedByPlayer (cServer& server, cPlayer* player, bool addToDetectedInThisTurnList)
1351 {
1352 if (!isDetectedByPlayer (player))
1353 detectedByPlayerList.push_back (player);
1354 }
1355
1356 //--------------------------------------------------------------------------
resetDetectedByPlayer(const cPlayer * player)1357 void cBuilding::resetDetectedByPlayer (const cPlayer* player)
1358 {
1359 Remove (detectedByPlayerList, player);
1360 }
1361
1362 //--------------------------------------------------------------------------
makeDetection(cServer & server)1363 void cBuilding::makeDetection (cServer& server)
1364 {
1365 // check whether the building has been detected by others
1366 if (data.isStealthOn == TERRAIN_NONE) return;
1367
1368 if (data.isStealthOn & AREA_EXP_MINE)
1369 {
1370 auto& playerList = server.playerList;
1371 for (unsigned int i = 0; i < playerList.size(); i++)
1372 {
1373 auto& player = *playerList[i];
1374 if (&player == getOwner()) continue;
1375 if (player.hasMineDetection (getPosition()))
1376 {
1377 setDetectedByPlayer (server, &player);
1378 }
1379 }
1380 }
1381 }
1382
1383 //--------------------------------------------------------------------------
sBuildingUIData()1384 sBuildingUIData::sBuildingUIData()
1385 {}
1386
1387 //--------------------------------------------------------------------------
sBuildingUIData(sBuildingUIData && other)1388 sBuildingUIData::sBuildingUIData (sBuildingUIData&& other) :
1389 img (std::move (other.img)), img_org (std::move (other.img_org)),
1390 shw (std::move (other.shw)), shw_org (std::move (other.shw_org)),
1391 eff (std::move (other.eff)), eff_org (std::move (other.eff_org)),
1392 video (std::move (other.video)),
1393 info (std::move (other.info)),
1394 Start (std::move (other.Start)),
1395 Running (std::move (other.Running)),
1396 Stop (std::move (other.Stop)),
1397 Attack (std::move (other.Attack)),
1398 Wait (std::move (other.Wait))
1399 {}
1400
1401 //--------------------------------------------------------------------------
operator =(sBuildingUIData && other)1402 sBuildingUIData& sBuildingUIData::operator= (sBuildingUIData && other)
1403 {
1404 img = std::move (other.img);
1405 img_org = std::move (other.img_org);
1406 shw = std::move (other.shw);
1407 shw_org = std::move (other.shw_org);
1408 eff = std::move (other.eff);
1409 eff_org = std::move (other.eff_org);
1410 video = std::move (other.video);
1411 info = std::move (other.info);
1412
1413 Start = std::move (other.Start);
1414 Running = std::move (other.Running);
1415 Stop = std::move (other.Stop);
1416 Attack = std::move (other.Attack);
1417 Wait = std::move (other.Wait);
1418 return *this;
1419 }
1420
1421 //--------------------------------------------------------------------------
scaleSurfaces(float factor)1422 void sBuildingUIData::scaleSurfaces (float factor)
1423 {
1424 scaleSurface (img_org.get(), img.get(), (int) (img_org->w * factor), (int) (img_org->h * factor));
1425 scaleSurface (shw_org.get(), shw.get(), (int) (shw_org->w * factor), (int) (shw_org->h * factor));
1426 if (eff_org) scaleSurface (eff_org.get(), eff.get(), (int) (eff_org->w * factor), (int) (eff_org->h * factor));
1427 }
1428
1429 //-----------------------------------------------------------------------------
1430 //-----------------------------------------------------------------------------
1431 //-- methods, that already have been extracted as part of cUnit refactoring
1432 //-----------------------------------------------------------------------------
1433 //-----------------------------------------------------------------------------
1434
1435 //-----------------------------------------------------------------------------
factoryHasJustFinishedBuilding() const1436 bool cBuilding::factoryHasJustFinishedBuilding() const
1437 {
1438 return (!buildList.empty() && isUnitWorking() == false && buildList[0].getRemainingMetal() <= 0);
1439 }
1440
1441 //-----------------------------------------------------------------------------
executeStopCommand(const cClient & client) const1442 void cBuilding::executeStopCommand (const cClient& client) const
1443 {
1444 sendWantStopWork (client, *this);
1445 }
1446
1447 //-----------------------------------------------------------------------------
executeUpdateBuildingCommmand(const cClient & client,bool updateAllOfSameType) const1448 void cBuilding::executeUpdateBuildingCommmand (const cClient& client, bool updateAllOfSameType) const
1449 {
1450 sendUpgradeBuilding (client, *this, updateAllOfSameType);
1451 }
1452
1453 //-----------------------------------------------------------------------------
buildingCanBeStarted() const1454 bool cBuilding::buildingCanBeStarted() const
1455 {
1456 return (data.canWork && isUnitWorking() == false
1457 && (!buildList.empty() || data.canBuild.empty()));
1458 }
1459
1460 //-----------------------------------------------------------------------------
buildingCanBeUpgraded() const1461 bool cBuilding::buildingCanBeUpgraded() const
1462 {
1463 const sUnitData& upgraded = *getOwner()->getUnitDataCurrentVersion (data.ID);
1464 return (data.getVersion() != upgraded.getVersion() && SubBase && SubBase->getMetal() >= 2);
1465 }
1466
1467 //-----------------------------------------------------------------------------
isBuildListEmpty() const1468 bool cBuilding::isBuildListEmpty() const
1469 {
1470 return buildList.empty();
1471 }
1472
1473 //-----------------------------------------------------------------------------
getBuildListSize() const1474 size_t cBuilding::getBuildListSize() const
1475 {
1476 return buildList.size();
1477 }
1478
1479 //-----------------------------------------------------------------------------
getBuildListItem(size_t index) const1480 const cBuildListItem& cBuilding::getBuildListItem (size_t index) const
1481 {
1482 return buildList[index];
1483 }
1484
1485 //-----------------------------------------------------------------------------
getBuildListItem(size_t index)1486 cBuildListItem& cBuilding::getBuildListItem (size_t index)
1487 {
1488 return buildList[index];
1489 }
1490
1491 //-----------------------------------------------------------------------------
setBuildList(std::vector<cBuildListItem> buildList_)1492 void cBuilding::setBuildList (std::vector<cBuildListItem> buildList_)
1493 {
1494 buildList = std::move (buildList_);
1495
1496 buildListFirstItemSignalConnectionManager.disconnectAll();
1497 if (!buildList.empty())
1498 {
1499 buildListFirstItemSignalConnectionManager.connect (buildList[0].remainingMetalChanged, [this]() { buildListFirstItemDataChanged(); });
1500 buildListFirstItemSignalConnectionManager.connect (buildList[0].typeChanged, [this]() { buildListFirstItemDataChanged(); });
1501 }
1502
1503 buildListChanged();
1504 }
1505
1506 //-----------------------------------------------------------------------------
addBuildListItem(cBuildListItem item)1507 void cBuilding::addBuildListItem (cBuildListItem item)
1508 {
1509 buildList.push_back (std::move (item));
1510
1511 buildListFirstItemSignalConnectionManager.disconnectAll();
1512 if (!buildList.empty())
1513 {
1514 buildListFirstItemSignalConnectionManager.connect (buildList[0].remainingMetalChanged, [this]() { buildListFirstItemDataChanged(); });
1515 buildListFirstItemSignalConnectionManager.connect (buildList[0].typeChanged, [this]() { buildListFirstItemDataChanged(); });
1516 }
1517
1518 buildListChanged();
1519 }
1520
1521 //-----------------------------------------------------------------------------
removeBuildListItem(size_t index)1522 void cBuilding::removeBuildListItem (size_t index)
1523 {
1524 buildList.erase (buildList.begin() + index);
1525
1526 buildListFirstItemSignalConnectionManager.disconnectAll();
1527 if (!buildList.empty())
1528 {
1529 buildListFirstItemSignalConnectionManager.connect (buildList[0].remainingMetalChanged, [this]() { buildListFirstItemDataChanged(); });
1530 buildListFirstItemSignalConnectionManager.connect (buildList[0].typeChanged, [this]() { buildListFirstItemDataChanged(); });
1531 }
1532
1533 buildListChanged();
1534 }
1535
1536 //-----------------------------------------------------------------------------
getBuildSpeed() const1537 int cBuilding::getBuildSpeed() const
1538 {
1539 return buildSpeed;
1540 }
1541
1542 //-----------------------------------------------------------------------------
getMetalPerRound() const1543 int cBuilding::getMetalPerRound() const
1544 {
1545 return metalPerRound;
1546 }
1547
1548 //-----------------------------------------------------------------------------
getRepeatBuild() const1549 bool cBuilding::getRepeatBuild() const
1550 {
1551 return repeatBuild;
1552 }
1553
1554 //-----------------------------------------------------------------------------
setWorking(bool value)1555 void cBuilding::setWorking (bool value)
1556 {
1557 std::swap (isWorking, value);
1558 if (value != isWorking) workingChanged();
1559 }
1560
1561 //-----------------------------------------------------------------------------
setBuildSpeed(int value)1562 void cBuilding::setBuildSpeed(int value)
1563 {
1564 std::swap(buildSpeed, value);
1565 if(value != buildSpeed) buildSpeedChanged();
1566 }
1567
1568 //-----------------------------------------------------------------------------
setMetalPerRound(int value)1569 void cBuilding::setMetalPerRound(int value)
1570 {
1571 std::swap(metalPerRound, value);
1572 if(value != metalPerRound) metalPerRoundChanged();
1573 }
1574
1575 //-----------------------------------------------------------------------------
setRepeatBuild(bool value)1576 void cBuilding::setRepeatBuild(bool value)
1577 {
1578 std::swap(repeatBuild, value);
1579 if(value != repeatBuild) repeatBuildChanged();
1580 }
1581
1582 //-----------------------------------------------------------------------------
setResearchArea(cResearch::ResearchArea area)1583 void cBuilding::setResearchArea (cResearch::ResearchArea area)
1584 {
1585 std::swap (researchArea, area);
1586 if (researchArea != area) researchAreaChanged();
1587 }
1588
1589 //-----------------------------------------------------------------------------
getResearchArea() const1590 cResearch::ResearchArea cBuilding::getResearchArea() const
1591 {
1592 return researchArea;
1593 }
1594
1595 //-----------------------------------------------------------------------------
registerOwnerEvents()1596 void cBuilding::registerOwnerEvents()
1597 {
1598 ownerSignalConnectionManager.disconnectAll();
1599
1600 if (getOwner() == nullptr) return;
1601
1602 if (data.convertsGold)
1603 {
1604 ownerSignalConnectionManager.connect (getOwner()->creditsChanged, [&]() { statusChanged(); });
1605 }
1606
1607 if (data.canResearch)
1608 {
1609 ownerSignalConnectionManager.connect (getOwner()->researchCentersWorkingOnAreaChanged, [&] (cResearch::ResearchArea) { statusChanged(); });
1610 ownerSignalConnectionManager.connect (getOwner()->getResearchState().neededResearchPointsChanged, [&] (cResearch::ResearchArea) { statusChanged(); });
1611 ownerSignalConnectionManager.connect (getOwner()->getResearchState().currentResearchPointsChanged, [&] (cResearch::ResearchArea) { statusChanged(); });
1612 }
1613 }
1614