• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Return-To-The-Roots / s25client / 9438171052

09 Jun 2024 05:06PM UTC coverage: 50.409% (+0.004%) from 50.405%
9438171052

push

github

Flamefire
Consistently use GetWareTex and GetWareTexStack instead of GetMapTexture

Makes adding new textures for additional wares much easier
because we have only one place to add a lookup for the new texture.

0 of 7 new or added lines in 5 files covered. (0.0%)

8 existing lines in 2 files now uncovered.

22085 of 43812 relevant lines covered (50.41%)

31067.07 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.71
/libs/s25main/nodeObjs/noFlag.cpp
1
// Copyright (C) 2005 - 2021 Settlers Freaks (sf-team at siedler25.org)
2
//
3
// SPDX-License-Identifier: GPL-2.0-or-later
4

5
#include "noFlag.h"
6
#include "EventManager.h"
7
#include "FOWObjects.h"
8
#include "GamePlayer.h"
9
#include "Loader.h"
10
#include "SerializedGameData.h"
11
#include "Ware.h"
12
#include "buildings/noBuilding.h"
13
#include "enum_cast.hpp"
14
#include "figures/nofCarrier.h"
15
#include "helpers/EnumRange.h"
16
#include "network/GameClient.h"
17
#include "ogl/glArchivItem_Bitmap.h"
18
#include "ogl/glSmartBitmap.h"
19
#include "world/GameWorld.h"
20
#include "gameData/TerrainDesc.h"
21
#include <algorithm>
22

23
noFlag::noFlag(const MapPoint pos, const unsigned char player)
1,162✔
24
    : noRoadNode(NodalObjectType::Flag, pos, player), ani_offset(rand() % 20000)
1,162✔
25
{
26
    // BWUs nullen
27
    for(auto& bwu : bwus)
5,810✔
28
    {
29
        bwu.id = 0xFFFFFFFF;
4,648✔
30
        bwu.last_gf = 0;
4,648✔
31
    }
32

33
    // Gucken, ob die Flagge auf einen bereits bestehenden Weg gesetzt wurde
34
    Direction dir;
35
    noFlag* flag = world->GetRoadFlag(pos, dir);
1,162✔
36

37
    if(flag && flag->GetRoute(dir))
1,162✔
38
        flag->GetRoute(dir)->SplitRoad(this);
14✔
39

40
    // auf Wasseranteile prüfen
41
    if(world->HasTerrain(pos, [](const auto& desc) { return desc.kind == TerrainKind::Water; }))
8,103✔
42
        flagtype = FlagType::Water;
11✔
43
    else
44
        flagtype = FlagType::Normal;
1,151✔
45
}
1,162✔
46

47
noFlag::noFlag(SerializedGameData& sgd, const unsigned obj_id)
11✔
48
    : noRoadNode(sgd, obj_id), ani_offset(rand() % 20000), flagtype(sgd.Pop<FlagType>())
11✔
49
{
50
    if(sgd.GetGameDataVersion() < 8)
11✔
51
    {
52
        for(unsigned i = 0; i < wares.max_size(); i++)
×
53
        {
54
            auto* ware = sgd.PopObject<Ware>(GO_Type::Ware);
×
55
            if(ware)
×
56
                wares.emplace_back(ware);
×
57
        }
58
    } else
59
        sgd.PopObjectContainer(wares, GO_Type::Ware);
11✔
60

61
    // BWUs laden
62
    for(auto& bwu : bwus)
55✔
63
    {
64
        bwu.id = sgd.PopUnsignedInt();
44✔
65
        bwu.last_gf = sgd.PopUnsignedInt();
44✔
66
    }
67
}
11✔
68

69
noFlag::~noFlag() = default;
2,346✔
70

71
void noFlag::Destroy()
753✔
72
{
73
    /// Da ist dann nichts
74
    world->SetNO(pos, nullptr);
753✔
75

76
    // Waren vernichten
77
    for(auto& ware : wares)
2,259✔
78
    {
79
        // Inventur entsprechend verringern
80
        ware->WareLost(player);
×
81
        ware->Destroy();
×
82
    }
83
    wares.clear();
753✔
84

85
    // Den Flag-Workern Bescheid sagen, die hier ggf. arbeiten
86
    world->GetPlayer(player).FlagDestroyed(this);
753✔
87

88
    noRoadNode::Destroy();
753✔
89
}
753✔
90

91
void noFlag::Serialize(SerializedGameData& sgd) const
23✔
92
{
93
    noRoadNode::Serialize(sgd);
23✔
94

95
    sgd.PushEnum<uint8_t>(flagtype);
23✔
96
    sgd.PushObjectContainer(wares, true);
23✔
97

98
    // BWUs speichern
99
    for(const auto& bwu : bwus)
115✔
100
    {
101
        sgd.PushUnsignedInt(bwu.id);
92✔
102
        sgd.PushUnsignedInt(bwu.last_gf);
92✔
103
    }
104
}
23✔
105

106
void noFlag::Draw(DrawPoint drawPt)
×
107
{
108
    // Positionen der Waren an der Flagge relativ zur Flagge
109
    static constexpr std::array<DrawPoint, 8> WARES_POS = {
110
      {{0, 0}, {-4, 0}, {3, -1}, {-7, -1}, {6, -2}, {-10, -2}, {9, -5}, {-13, -5}}};
111

112
    unsigned ani_step = GAMECLIENT.GetGlobalAnimation(8, 2, 1, ani_offset);
×
113

114
    LOADER.flag_cache[world->GetPlayer(player).nation][flagtype][ani_step].draw(drawPt, 0xFFFFFFFF,
×
115
                                                                                world->GetPlayer(player).color);
×
116

117
    // Waren (von hinten anfangen zu zeichnen)
118
    for(unsigned i = wares.size(); i > 0; --i)
×
119
    {
NEW
120
        LOADER.GetWareStackTex(wares[i - 1]->type)->DrawFull(drawPt + WARES_POS[i - 1]);
×
121
    }
122
}
×
123

124
/**
125
 *  Erzeugt von ihnen selbst ein FOW Objekt als visuelle "Erinnerung"
126
 *  für den Fog of War.
127
 */
128
std::unique_ptr<FOWObject> noFlag::CreateFOWObject() const
×
129
{
130
    const GamePlayer& owner = world->GetPlayer(player);
×
131
    return std::make_unique<fowFlag>(owner.color, owner.nation, flagtype);
×
132
}
133

134
/**
135
 *  Legt eine Ware an der Flagge ab.
136
 */
137
void noFlag::AddWare(std::unique_ptr<Ware> ware)
109✔
138
{
139
    // First add ware, then tell carrier. So get the info from the ware first
140
    const RoadPathDirection nextDir = ware->GetNextDir();
109✔
141
    wares.push_back(std::move(ware));
109✔
142

143
    if(nextDir != RoadPathDirection::None)
109✔
144
        GetRoute(toDirection(nextDir))->AddWareJob(this);
109✔
145
}
109✔
146

147
/**
148
 * Wählt eine Ware von einer Flagge aus (anhand der Transportreihenfolge),
149
 * entfernt sie von der Flagge und gibt sie zurück.
150
 *
151
 * wenn swap_wares true ist, bedeutet dies, dass Waren nur ausgetauscht werden
152
 * und somit nicht die Träger benachrichtigt werden müssen.
153
 */
154
std::unique_ptr<Ware> noFlag::SelectWare(const Direction roadDir, const bool swap_wares, const noFigure* const carrier)
102✔
155
{
156
    // Index merken, damit wir die enstprechende Ware dann entfernen können
157
    int best_ware_index = -1;
102✔
158

159
    // Die mit der niedrigsten, d.h. höchsten Priorität wird als erstes transportiert
160
    for(unsigned i = 0; i < wares.size(); ++i)
560✔
161
    {
162
        if(wares[i]->GetNextDir() == toRoadPathDirection(roadDir))
356✔
163
        {
164
            if(best_ware_index >= 0)
174✔
165
            {
166
                if(world->GetPlayer(player).GetTransportPriority(wares[i]->type)
144✔
167
                   < world->GetPlayer(player).GetTransportPriority(wares[best_ware_index]->type))
144✔
168
                {
169
                    best_ware_index = i;
×
170
                }
171
            } else
172
                best_ware_index = i;
102✔
173
        }
174
    }
175

176
    // Ware von der Flagge entfernen
177
    std::unique_ptr<Ware> bestWare;
102✔
178
    if(best_ware_index >= 0)
102✔
179
    {
180
        bestWare = std::move(wares[best_ware_index]);
204✔
181
        wares.erase(wares.begin() + best_ware_index);
204✔
182
    }
183

184
    // ggf. anderen Trägern Bescheid sagen, aber nicht dem, der die Ware aufgehoben hat!
185
    GetRoute(roadDir)->WareJobRemoved(carrier);
102✔
186

187
    if(!swap_wares && bestWare)
102✔
188
    {
189
        // Wenn nun wieder ein Platz frei ist, allen Wegen rundrum sowie evtl Warenhäusern
190
        // Bescheid sagen, die evtl waren, dass sie wieder was ablegen können
191
        for(const auto dir : helpers::EnumRange<Direction>{})
1,552✔
192
        {
193
            const auto* route = GetRoute(dir);
580✔
194
            if(!route)
580✔
195
                continue;
342✔
196

197
            if(route->GetLength() == 1)
238✔
198
            {
199
                // Gebäude?
200

201
                if(world->GetSpecObj<noBase>(world->GetNeighbour(pos, Direction::NorthWest))->GetType()
75✔
202
                   == NodalObjectType::Building)
75✔
203
                {
204
                    if(world->GetSpecObj<noBuilding>(world->GetNeighbour(pos, Direction::NorthWest))->FreePlaceAtFlag())
73✔
205
                        break;
8✔
206
                }
207
            } else
208
            {
209
                // Richtiger Weg --> Träger Bescheid sagen
210
                for(unsigned char c = 0; c < 2; ++c)
489✔
211
                {
212
                    if(route->hasCarrier(c))
326✔
213
                    {
214
                        if(route->getCarrier(c)->SpaceAtFlag(this == route->GetF2()))
165✔
215
                            break;
×
216
                    }
217
                }
218
            }
219
        }
220
    }
221

222
    return bestWare;
102✔
223
}
224

225
unsigned noFlag::GetNumWaresForRoad(const Direction dir) const
1,448✔
226
{
227
    const auto roadDir = toRoadPathDirection(dir);
1,448✔
228
    return helpers::count_if(wares, [roadDir](const auto& ware) { return ware->GetNextDir() == roadDir; });
1,907✔
229
}
230

231
/**
232
 *  Gibt Wegstrafpunkte für das Pathfinden für Waren, die in eine bestimmte
233
 *  Richtung noch transportiert werden müssen.
234
 */
235
unsigned noFlag::GetPunishmentPoints(const Direction dir) const
1,050✔
236
{
237
    // Waren zählen, die in diese Richtung transportiert werden müssen
238
    unsigned points = GetNumWaresForRoad(dir) * 2;
1,050✔
239

240
    const RoadSegment* routeInDir = GetRoute(dir);
1,050✔
241
    const nofCarrier* humanCarrier = routeInDir->getCarrier(0);
1,050✔
242
    if(humanCarrier)
1,050✔
243
    {
244
        // normal carrier has been ordered from the warehouse but has not yet arrived and no donkey
245
        if(humanCarrier->GetCarrierState() == CarrierState::FigureWork && !routeInDir->hasCarrier(1))
708✔
246
            points += 50;
104✔
247
    } else if(!routeInDir->hasCarrier(1))
342✔
248
        points += 500; // No carrier at all -> Large penalty
342✔
249

250
    return points;
1,050✔
251
}
252

253
/**
254
 *  Zerstört evtl. vorhandenes Gebäude bzw. Baustelle vor der Flagge.
255
 */
256
void noFlag::DestroyAttachedBuilding()
727✔
257
{
258
    // Achtung es wird ein Feuer durch Destroy gesetzt, daher Objekt merken!
259
    noBase* no = world->GetNO(world->GetNeighbour(pos, Direction::NorthWest));
727✔
260
    if(no->GetType() == NodalObjectType::Buildingsite || no->GetType() == NodalObjectType::Building)
727✔
261
    {
262
        no->Destroy();
13✔
263
        delete no;
13✔
264
    }
265
}
727✔
266

267
/**
268
 *  Baut normale Flaggen zu "gloriösen" aus bei Eselstraßen.
269
 */
270
void noFlag::Upgrade()
4✔
271
{
272
    if(flagtype == FlagType::Normal)
4✔
273
        flagtype = FlagType::Large;
3✔
274
}
4✔
275

276
/**
277
 *  Feind übernimmt die Flagge.
278
 */
279
void noFlag::Capture(const unsigned char new_owner)
6✔
280
{
281
    // Alle Straßen um mich herum zerstören bis auf die zum Gebäude
282
    for(const auto dir : helpers::EnumRange<Direction>{})
96✔
283
    {
284
        if(dir != Direction::NorthWest)
36✔
285
            DestroyRoad(dir);
30✔
286
    }
287

288
    // Waren vernichten
289
    for(auto& ware : wares)
18✔
290
    {
291
        ware->WareLost(player);
×
292
        ware->Destroy();
×
293
    }
294
    wares.clear();
6✔
295

296
    // Unregister this flag in the players flags
297
    world->GetPlayer(player).FlagDestroyed(this);
6✔
298
    this->player = new_owner;
6✔
299
}
6✔
300

301
/**
302
 *  Ist diese Flagge für eine bestimmte Lagerhausflüchtlingsgruppe (BWU) nicht zugänglich?
303
 */
304
bool noFlag::IsImpossibleForBWU(const unsigned bwu_id) const
26✔
305
{
306
    // Zeitintervall, in der die Zugänglichkeit der Flaggen von einer bestimmten BWU überprüft wird
307
    const unsigned MAX_BWU_INTERVAL = 2000;
26✔
308

309
    // BWU-ID erstmal suchen
310
    for(auto bwu : bwus)
130✔
311
    {
312
        if(bwu.id == bwu_id)
104✔
313
        {
314
            // Wenn letzter TÜV noch nicht zu lange zurückliegt, können wir sie als unzugänglich zurückgeben
315
            return GetEvMgr().GetCurrentGF() - bwu.last_gf <= MAX_BWU_INTERVAL;
×
316
        }
317
    }
318

319
    return false;
26✔
320
}
321

322
/**
323
 *  Hinzufügen, dass diese Flagge für eine bestimmte Lagerhausgruppe nicht zugänglich ist.
324
 */
325
void noFlag::ImpossibleForBWU(const unsigned bwu_id)
×
326
{
327
    // Evtl gibts BWU schon --> Dann einfach GF-Zahl aktualisieren
328
    for(auto& bwu : bwus)
×
329
    {
330
        if(bwu.id == bwu_id)
×
331
        {
332
            bwu.last_gf = GetEvMgr().GetCurrentGF();
×
333
            return;
×
334
        }
335
    }
336

337
    // Gibts noch nicht, dann den ältesten BWU-Account raussuchen und den überschreiben
338
    unsigned oldest_gf = 0xFFFFFFFF;
×
339
    unsigned oldest_account_id = 0;
×
340

341
    for(unsigned i = 0; i < bwus.size(); ++i)
×
342
    {
343
        if(bwus[i].last_gf < oldest_gf)
×
344
        {
345
            // Neuer ältester
346
            oldest_gf = bwus[i].last_gf;
×
347
            oldest_account_id = i;
×
348
        }
349
    }
350

351
    // Den ältesten dann schließlich überschreiben
352
    bwus[oldest_account_id].id = bwu_id;
×
353
    bwus[oldest_account_id].last_gf = oldest_gf;
×
354
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc