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

Return-To-The-Roots / s25client / 19616826773

23 Nov 2025 08:27PM UTC coverage: 50.521% (+0.05%) from 50.474%
19616826773

Pull #1817

github

web-flow
Merge 4a3c7a2ba into 6da68acba
Pull Request #1817: Proposal to turn off/on bird sounds

2 of 66 new or added lines in 4 files covered. (3.03%)

727 existing lines in 11 files now uncovered.

22550 of 44635 relevant lines covered (50.52%)

35034.0 hits per line

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

12.27
/libs/s25main/world/GameWorldView.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 "world/GameWorldView.h"
6
#include "CatapultStone.h"
7
#include "FOWObjects.h"
8
#include "GamePlayer.h"
9
#include "GlobalGameSettings.h"
10
#include "Loader.h"
11
#include "MapGeometry.h"
12
#include "Settings.h"
13
#include "addons/AddonMaxWaterwayLength.h"
14
#include "buildings/noBuildingSite.h"
15
#include "buildings/nobMilitary.h"
16
#include "buildings/nobUsual.h"
17
#include "drivers/VideoDriverWrapper.h"
18
#include "helpers/EnumArray.h"
19
#include "helpers/containerUtils.h"
20
#include "helpers/toString.h"
21
#include "ogl/FontStyle.h"
22
#include "ogl/glArchivItem_Bitmap.h"
23
#include "ogl/glFont.h"
24
#include "ogl/glSmartBitmap.h"
25
#include "world/GameWorldBase.h"
26
#include "world/GameWorldViewer.h"
27
#include "gameTypes/RoadBuildState.h"
28
#include "gameData/BuildingConsts.h"
29
#include "gameData/GuiConsts.h"
30
#include "gameData/MapConsts.h"
31
#include "s25util/error.h"
32
#include "s25util/warningSuppression.h"
33
#include <glad/glad.h>
34
#include <boost/format.hpp>
35
#include <cmath>
36

37
GameWorldView::GameWorldView(const GameWorldViewer& gwv, const Position& pos, const Extent& size)
9✔
38
    : selPt(0, 0), show_bq(SETTINGS.ingame.showBQ), show_names(SETTINGS.ingame.showNames),
9✔
39
      show_productivity(SETTINGS.ingame.showProductivity), offset(0, 0), lastOffset(0, 0), gwv(gwv), origin_(pos),
18✔
40
      size_(size), zoomFactor_(1.f), targetZoomFactor_(1.f), zoomSpeed_(0.f)
18✔
41
{
42
    updateEffectiveZoomFactor();
9✔
43
    MoveBy({0, 0});
9✔
44
}
9✔
45

46
const GameWorldBase& GameWorldView::GetWorld() const
78✔
47
{
48
    return gwv.GetWorld();
78✔
49
}
50

51
SoundManager& GameWorldView::GetSoundMgr()
×
52
{
53
    return const_cast<GameWorldViewer&>(gwv).GetSoundMgr();
×
54
}
55

56
void GameWorldView::SetNextZoomFactor()
×
57
{
58
    if(zoomFactor_ == targetZoomFactor_) // == with float is ok here, is explicitly set in last step //-V550
×
59
        return;
×
60

61
    float remainingZoomDiff = targetZoomFactor_ - zoomFactor_;
×
62

63
    if(std::abs(remainingZoomDiff) <= 0.5 * zoomSpeed_ * zoomSpeed_ / ZOOM_ACCELERATION)
×
64
    {
65
        // deceleration towards zero zoom speed
66
        if(zoomSpeed_ > 0)
×
67
            zoomSpeed_ -= ZOOM_ACCELERATION;
×
68
        else
69
            zoomSpeed_ += ZOOM_ACCELERATION;
×
70
    } else
71
    {
72
        // acceleration to unlimited speed
73
        if(remainingZoomDiff > 0)
×
74
            zoomSpeed_ += ZOOM_ACCELERATION;
×
75
        else
76
            zoomSpeed_ -= ZOOM_ACCELERATION;
×
77
    }
78

79
    if(std::abs(remainingZoomDiff) < std::abs(zoomSpeed_))
×
80
    {
81
        // last step
82
        zoomFactor_ = targetZoomFactor_;
×
83
        zoomSpeed_ = 0;
×
84
    }
85

86
    zoomFactor_ = zoomFactor_ + zoomSpeed_;
×
87
    updateEffectiveZoomFactor();
×
88
    CalcFxLx();
×
89
}
90

91
float GameWorldView::SetZoomFactor(float zoomFactor, bool smoothTransition /* = true*/)
28✔
92
{
93
    targetZoomFactor_ = zoomFactor;
28✔
94
    if(!smoothTransition)
28✔
95
    {
96
        zoomFactor_ = targetZoomFactor_;
×
UNCOV
97
        updateEffectiveZoomFactor();
×
98
        CalcFxLx();
×
99
    }
100
    return targetZoomFactor_;
28✔
101
}
102

103
float GameWorldView::GetCurrentTargetZoomFactor() const
44✔
104
{
105
    return targetZoomFactor_;
44✔
106
}
107

108
struct ObjectBetweenLines
109
{
110
    noBase& obj;
111
    DrawPoint pos; // Zeichenposition
112

UNCOV
113
    ObjectBetweenLines(noBase& obj, const DrawPoint& pos) : obj(obj), pos(pos) {}
×
114
};
115

UNCOV
116
void GameWorldView::Draw(const RoadBuildState& rb, const MapPoint selected, bool drawMouse, unsigned* water)
×
117
{
UNCOV
118
    SetNextZoomFactor();
×
119

120
    const auto windowSize = VIDEODRIVER.GetWindowSize();
×
UNCOV
121
    const auto& guiScale = VIDEODRIVER.getGuiScale();
×
122
    const auto screenOrigin = guiScale.viewToScreen(origin_);
×
UNCOV
123
    const auto screenSize = guiScale.viewToScreen(size_);
×
124
    glScissor(screenOrigin.x, windowSize.height - (screenOrigin.y + screenSize.y), screenSize.x, screenSize.y);
×
125

126
    int shortestDistToMouse = 100000;
×
127
    Position mousePos = VIDEODRIVER.GetMousePos();
×
128
    mousePos -= Position(origin_);
×
UNCOV
129
    if(effectiveZoomFactor_ != 1.f) //-V550
×
130
    {
131
        glMatrixMode(GL_PROJECTION);
×
132
        glPushMatrix();
×
133
        glScalef(effectiveZoomFactor_, effectiveZoomFactor_, 1);
×
134
        // Offset to center view
135
        PointF diff(size_.x - size_.x / effectiveZoomFactor_, size_.y - size_.y / effectiveZoomFactor_);
×
136
        diff = diff / 2.f;
×
137
        glTranslatef(-diff.x, -diff.y, 0.f);
×
138
        // Also adjust mouse
139
        mousePos = Position(PointF(mousePos) / effectiveZoomFactor_ + diff);
×
140
        glMatrixMode(GL_MODELVIEW);
×
141
    }
142

143
    glTranslatef(static_cast<GLfloat>(origin_.x) / effectiveZoomFactor_,
×
144
                 static_cast<GLfloat>(origin_.y) / effectiveZoomFactor_, 0.0f);
×
145

UNCOV
146
    glTranslatef(static_cast<GLfloat>(-offset.x), static_cast<GLfloat>(-offset.y), 0.0f);
×
147
    const TerrainRenderer& terrainRenderer = gwv.GetTerrainRenderer();
×
148
    terrainRenderer.Draw(GetFirstPt(), GetLastPt(), gwv, water);
×
UNCOV
149
    glTranslatef(static_cast<GLfloat>(offset.x), static_cast<GLfloat>(offset.y), 0.0f);
×
150

151
    for(int y = firstPt.y; y <= lastPt.y; ++y)
×
152
    {
153
        // Figuren speichern, die in dieser Zeile gemalt werden müssen
154
        // und sich zwischen zwei Zeilen befinden, da sie dazwischen laufen
155
        std::vector<ObjectBetweenLines> between_lines;
×
156

UNCOV
157
        for(int x = firstPt.x; x <= lastPt.x; ++x)
×
158
        {
159
            Position curOffset;
×
UNCOV
160
            const MapPoint curPt = terrainRenderer.ConvertCoords(Position(x, y), &curOffset);
×
161
            DrawPoint curPos = GetWorld().GetNodePos(curPt) - offset + curOffset;
×
162

163
            Position mouseDist = mousePos - curPos;
×
164
            mouseDist *= mouseDist;
×
165
            if(std::abs(mouseDist.x) + std::abs(mouseDist.y) < shortestDistToMouse)
×
166
            {
167
                selPt = curPt;
×
168
                selPtOffset = curOffset;
×
169
                shortestDistToMouse = std::abs(mouseDist.x) + std::abs(mouseDist.y);
×
170
            }
171

172
            Visibility visibility = gwv.GetVisibility(curPt);
×
173

UNCOV
174
            DrawBoundaryStone(curPt, curPos, visibility);
×
175

176
            if(visibility == Visibility::Visible)
×
177
            {
178
                DrawObject(curPt, curPos);
×
UNCOV
179
                DrawMovingFiguresFromBelow(terrainRenderer, Position(x, y), between_lines);
×
180
                DrawFigures(curPt, curPos, between_lines);
×
181

182
                // Construction aid mode
183
                if(show_bq)
×
184
                    DrawConstructionAid(curPt, curPos);
×
UNCOV
185
            } else if(visibility == Visibility::FogOfWar)
×
186
            {
187
                const FOWObject* fowobj = gwv.GetYoungestFOWObject(MapPoint(curPt));
×
188
                if(fowobj)
×
189
                    fowobj->Draw(curPos);
×
190
            }
191

192
            for(IDrawNodeCallback* callback : drawNodeCallbacks)
×
193
                callback->onDraw(curPt, curPos);
×
194
        }
195

196
        // Figuren zwischen den Zeilen zeichnen
197
        for(auto& between_line : between_lines)
×
UNCOV
198
            between_line.obj.Draw(between_line.pos);
×
199
    }
200

201
    if(show_names || show_productivity)
×
202
        DrawNameProductivityOverlay(terrainRenderer);
×
203

UNCOV
204
    DrawGUI(rb, terrainRenderer, selected, drawMouse);
×
205

206
    // Umherfliegende Katapultsteine zeichnen
UNCOV
207
    for(auto* catapult_stone : GetWorld().catapult_stones)
×
208
    {
UNCOV
209
        if(gwv.GetVisibility(catapult_stone->dest_building) == Visibility::Visible
×
UNCOV
210
           || gwv.GetVisibility(catapult_stone->dest_map) == Visibility::Visible)
×
211
            catapult_stone->Draw(offset);
×
212
    }
213

214
    if(effectiveZoomFactor_ != 1.f) //-V550
×
215
    {
UNCOV
216
        glMatrixMode(GL_PROJECTION);
×
UNCOV
217
        glPopMatrix();
×
218
        glMatrixMode(GL_MODELVIEW);
×
219
    }
220
    glTranslatef(-static_cast<GLfloat>(origin_.x) / effectiveZoomFactor_,
×
221
                 -static_cast<GLfloat>(origin_.y) / effectiveZoomFactor_, 0.0f);
×
222

UNCOV
223
    glScissor(0, 0, windowSize.width, windowSize.height);
×
224
}
×
225

UNCOV
226
void GameWorldView::DrawGUI(const RoadBuildState& rb, const TerrainRenderer& terrainRenderer,
×
227
                            const MapPoint& selectedPt, bool drawMouse)
228
{
229
    // Falls im Straßenbaumodus: Punkte um den aktuellen Straßenbaupunkt herum ermitteln
230
    helpers::EnumArray<MapPoint, Direction> road_points;
×
231

UNCOV
232
    unsigned maxWaterWayLen = 0;
×
UNCOV
233
    if(rb.mode != RoadBuildMode::Disabled)
×
234
    {
UNCOV
235
        for(const auto dir : helpers::EnumRange<Direction>{})
×
236
            road_points[dir] = GetWorld().GetNeighbour(rb.point, dir);
×
237

UNCOV
238
        const unsigned index = GetWorld().GetGGS().getSelection(AddonId::MAX_WATERWAY_LENGTH);
×
239
        RTTR_Assert(index < waterwayLengths.size());
×
240
        maxWaterWayLen = waterwayLengths[index];
×
241
    }
242

243
    for(int x = firstPt.x; x <= lastPt.x; ++x)
×
244
    {
UNCOV
245
        for(int y = firstPt.y; y <= lastPt.y; ++y)
×
246
        {
247
            // Coordinates transform
UNCOV
248
            Position curOffset;
×
249
            MapPoint curPt = terrainRenderer.ConvertCoords(Position(x, y), &curOffset);
×
UNCOV
250
            Position curPos = GetWorld().GetNodePos(curPt) - offset + curOffset;
×
251

252
            /// Current point indicated by Mouse
253
            if(drawMouse && selPt == curPt)
×
254
            {
255
                // Mauszeiger am boden
UNCOV
256
                unsigned mid = 22;
×
257
                if(rb.mode == RoadBuildMode::Disabled)
×
258
                {
UNCOV
259
                    switch(gwv.GetBQ(curPt))
×
260
                    {
261
                        case BuildingQuality::Flag: mid = 40; break;
×
UNCOV
262
                        case BuildingQuality::Mine: mid = 41; break;
×
263
                        case BuildingQuality::Hut: mid = 42; break;
×
UNCOV
264
                        case BuildingQuality::House: mid = 43; break;
×
265
                        case BuildingQuality::Castle: mid = 44; break;
×
266
                        case BuildingQuality::Harbor: mid = 45; break;
×
267
                        default: break;
×
268
                    }
269
                }
270
                LOADER.GetMapTexture(mid)->DrawFull(curPos);
×
271
            }
272

273
            // Currently selected point
274
            if(selectedPt == curPt)
×
UNCOV
275
                LOADER.GetMapTexture(20)->DrawFull(curPos);
×
276

277
            // not building roads, no further action needed
278
            if(rb.mode == RoadBuildMode::Disabled)
×
279
                continue;
×
280

281
            // we dont own curPt, no need for any rendering...
282
            if(!gwv.IsPlayerTerritory(curPt))
×
283
                continue;
×
284

285
            // we are in road build mode
286
            // highlight current route pt
287
            if(rb.point == curPt)
×
288
            {
UNCOV
289
                LOADER.GetMapTexture(21)->DrawFull(curPos);
×
UNCOV
290
                continue;
×
291
            }
292

293
            // ensure that curPt is a neighbour of rb.point
294
            if(!helpers::contains(road_points, curPt))
×
295
            {
UNCOV
296
                continue;
×
297
            }
298

299
            // test on maximal water way length
300
            if(rb.mode == RoadBuildMode::Boat && maxWaterWayLen != 0 && rb.route.size() >= maxWaterWayLen)
×
UNCOV
301
                continue;
×
302

303
            // render special icon for route revert
304
            if(!rb.route.empty() && road_points[rb.route.back() + 3u] == curPt)
×
305
            {
UNCOV
306
                LOADER.GetMapTexture(67)->DrawFull(curPos);
×
UNCOV
307
                continue;
×
308
            }
309

310
            // is a flag but not the route start flag, as it would revert the route.
311
            const bool targetFlag = GetWorld().GetNO(curPt)->GetType() == NodalObjectType::Flag && curPt != rb.start;
×
UNCOV
312
            int altitude = GetWorld().GetNode(rb.point).altitude;
×
UNCOV
313
            if(targetFlag || gwv.IsRoadAvailable(rb.mode == RoadBuildMode::Boat, curPt))
×
314
            {
315
                unsigned id;
316
                switch(int(GetWorld().GetNode(curPt).altitude) - altitude)
×
317
                {
UNCOV
318
                    case 1: id = 61; break;
×
UNCOV
319
                    case 2:
×
320
                    case 3: id = 62; break;
×
UNCOV
321
                    case 4:
×
322
                    case 5: id = 63; break;
×
323
                    case -1: id = 64; break;
×
324
                    case -2:
×
325
                    case -3: id = 65; break;
×
326
                    case -4:
×
327
                    case -5: id = 66; break;
×
328
                    default: id = 60; break;
×
329
                }
330
                if(!targetFlag)
×
331
                    LOADER.GetMapTexture(id)->DrawFull(curPos);
×
332
                else
333
                {
334
                    DrawPoint lastPos = GetWorld().GetNodePos(rb.point) - offset + curOffset;
×
335
                    DrawPoint halfWayPos = (curPos + lastPos) / 2;
×
UNCOV
336
                    LOADER.GetMapTexture(id)->DrawFull(halfWayPos);
×
UNCOV
337
                    LOADER.GetMapTexture(20)->DrawFull(curPos);
×
338
                }
339
            }
340
        }
341
    }
UNCOV
342
}
×
343

UNCOV
344
void GameWorldView::DrawNameProductivityOverlay(const TerrainRenderer& terrainRenderer)
×
345
{
346
    for(int x = firstPt.x; x <= lastPt.x; ++x)
×
347
    {
348
        for(int y = firstPt.y; y <= lastPt.y; ++y)
×
349
        {
350
            // Coordinate transform
UNCOV
351
            Position curOffset;
×
352
            MapPoint pt = terrainRenderer.ConvertCoords(Position(x, y), &curOffset);
×
353

UNCOV
354
            const auto* no = GetWorld().GetSpecObj<noBaseBuilding>(pt);
×
355
            if(!no)
×
356
                continue;
×
357

358
            Position curPos = GetWorld().GetNodePos(pt) - offset + curOffset;
×
359
            curPos.y -= 22;
×
360

361
            // Is object not belonging to local player?
362
            if(no->GetPlayer() != gwv.GetPlayerId())
×
363
            {
UNCOV
364
                if(GetWorld().GetGGS().getSelection(AddonId::MILITARY_AID) == 2 && gwv.GetNumSoldiersForAttack(pt) > 0)
×
365
                {
366
                    auto* attackAidImage = LOADER.GetImageN("map_new", 20000);
×
UNCOV
367
                    attackAidImage->DrawFull(curPos - DrawPoint(0, attackAidImage->getHeight()));
×
368
                }
UNCOV
369
                continue;
×
370
            }
371

372
            // Draw object name
373
            if(show_names)
×
374
            {
UNCOV
375
                unsigned color = (no->GetGOT() == GO_Type::Buildingsite) ? COLOR_GREY : COLOR_YELLOW;
×
UNCOV
376
                SmallFont->Draw(curPos, _(BUILDING_NAMES[no->GetBuildingType()]),
×
377
                                FontStyle::CENTER | FontStyle::VCENTER, color);
UNCOV
378
                curPos.y += SmallFont->getHeight();
×
379
            }
380

381
            // Draw productivity/soldiers
382
            if(show_productivity)
×
UNCOV
383
                DrawProductivity(*no, curPos);
×
384
        }
385
    }
386
}
×
387

UNCOV
388
void GameWorldView::DrawProductivity(const noBaseBuilding& no, const DrawPoint& curPos)
×
389
{
390
    const GO_Type got = no.GetGOT();
×
UNCOV
391
    if(got == GO_Type::Buildingsite)
×
392
    {
UNCOV
393
        unsigned color = COLOR_GREY;
×
394

395
        unsigned short p = static_cast<const noBuildingSite&>(no).GetBuildProgress();
×
UNCOV
396
        SmallFont->Draw(curPos, (boost::format("(%1% %%)") % p).str(), FontStyle::CENTER | FontStyle::VCENTER, color);
×
397
    } else if(got == GO_Type::NobUsual || got == GO_Type::NobShipyard || got == GO_Type::NobTemple)
×
398
    {
399
        const auto& n = static_cast<const nobUsual&>(no);
×
400
        std::string text;
×
401
        unsigned color = COLOR_0_PERCENT;
×
402

403
        if(!n.HasWorker())
×
404
            text = _("(House unoccupied)");
×
405
        else if(n.IsProductionDisabledVirtual())
×
UNCOV
406
            text = _("(stopped)");
×
407
        else
408
        {
409
            // Catapult and Lookout tower doesn't have productivity!
410
            if(n.GetBuildingType() == BuildingType::Catapult || n.GetBuildingType() == BuildingType::LookoutTower)
×
UNCOV
411
                return;
×
412

UNCOV
413
            unsigned short p = n.GetProductivity();
×
414
            text = helpers::toString(p) + " %";
×
415
            if(p >= 60)
×
UNCOV
416
                color = COLOR_60_PERCENT;
×
417
            else if(p >= 30)
×
418
                color = COLOR_30_PERCENT;
×
419
            else if(p >= 20)
×
420
                color = COLOR_20_PERCENT;
×
421
        }
422
        SmallFont->Draw(curPos, text, FontStyle::CENTER | FontStyle::VCENTER, color);
×
423
    } else if(got == GO_Type::NobMilitary)
×
424
    {
425
        // Display amount of soldiers
426
        unsigned soldiers_count = static_cast<const nobMilitary&>(no).GetNumTroops();
×
427
        std::string sSoldiers;
×
UNCOV
428
        if(soldiers_count == 1)
×
UNCOV
429
            sSoldiers = _("(1 soldier)");
×
430
        else
431
            sSoldiers = boost::str(boost::format(_("(%d soldiers)")) % soldiers_count);
×
432

433
        SmallFont->Draw(curPos, sSoldiers, FontStyle::CENTER | FontStyle::VCENTER,
×
UNCOV
434
                        (soldiers_count > 0) ? COLOR_YELLOW : COLOR_RED);
×
435
    }
436
}
437

438
void GameWorldView::DrawFigures(const MapPoint& pt, const DrawPoint& curPos,
×
439
                                std::vector<ObjectBetweenLines>& between_lines) const
440
{
UNCOV
441
    for(noBase& figure : GetWorld().GetFigures(pt))
×
442
    {
UNCOV
443
        if(figure.IsMoving())
×
444
        {
445
            // Drawn from above
UNCOV
446
            Direction curMoveDir = static_cast<noMovable&>(figure).GetCurMoveDir();
×
447
            if(curMoveDir == Direction::NorthEast || curMoveDir == Direction::NorthWest)
×
UNCOV
448
                continue;
×
449
            // Draw later
450
            between_lines.push_back(ObjectBetweenLines(figure, curPos));
×
451
        } else if(figure.GetGOT() == GO_Type::Ship)
×
452
            between_lines.push_back(ObjectBetweenLines(figure, curPos)); // TODO: Why special handling for ships?
×
453
        else
454
            // Ansonsten jetzt schon zeichnen
455
            figure.Draw(curPos);
×
456
    }
UNCOV
457
}
×
458

459
void GameWorldView::DrawMovingFiguresFromBelow(const TerrainRenderer& terrainRenderer, const DrawPoint& curPos,
×
460
                                               std::vector<ObjectBetweenLines>& between_lines)
461
{
462
    // First draw figures moving towards this point from below
463
    static const std::array<Direction, 2> aboveDirs = {{Direction::NorthEast, Direction::NorthWest}};
UNCOV
464
    for(Direction dir : aboveDirs)
×
465
    {
466
        // Get figures opposite the current dir and check if they are moving in this dir
467
        // Coordinates transform
468
        Position curOffset;
×
UNCOV
469
        MapPoint curPt = terrainRenderer.ConvertCoords(GetNeighbour(curPos, dir + 3u), &curOffset);
×
UNCOV
470
        Position figPos = GetWorld().GetNodePos(curPt) - offset + curOffset;
×
471

472
        for(noBase& figure : GetWorld().GetFigures(curPt))
×
473
        {
474
            if(figure.IsMoving() && static_cast<noMovable&>(figure).GetCurMoveDir() == dir)
×
UNCOV
475
                between_lines.push_back(ObjectBetweenLines(figure, figPos));
×
476
        }
477
    }
478
}
×
479

480
constexpr auto getBqImgs()
481
{
482
    helpers::EnumArray<unsigned, BuildingQuality> imgs{};
483
    imgs[BuildingQuality::Flag] = 50;
484
    imgs[BuildingQuality::Hut] = 51;
485
    imgs[BuildingQuality::House] = 52;
486
    imgs[BuildingQuality::Castle] = 53;
487
    imgs[BuildingQuality::Mine] = 54;
488
    imgs[BuildingQuality::Harbor] = 55;
489
    return imgs;
490
}
491

UNCOV
492
void GameWorldView::DrawConstructionAid(const MapPoint& pt, const DrawPoint& curPos)
×
493
{
UNCOV
494
    BuildingQuality bq = gwv.GetBQ(pt);
×
UNCOV
495
    if(bq != BuildingQuality::Nothing)
×
496
    {
UNCOV
497
        constexpr auto bqImgs = getBqImgs();
×
498
        auto* bm = LOADER.GetMapTexture(bqImgs[bq]);
×
499
        // Draw building quality icon
UNCOV
500
        bm->DrawFull(curPos);
×
501
        // Show ability to construct military buildings
502
        if(GetWorld().GetGGS().isEnabled(AddonId::MILITARY_AID))
×
503
        {
504
            if(!GetWorld().IsMilitaryBuildingNearNode(pt, gwv.GetPlayerId())
×
UNCOV
505
               && (bq == BuildingQuality::Hut || bq == BuildingQuality::House || bq == BuildingQuality::Castle
×
506
                   || bq == BuildingQuality::Harbor))
×
UNCOV
507
                LOADER.GetImageN("map_new", 20000)->DrawFull(curPos - DrawPoint(-1, bm->GetSize().y + 5));
×
508
        }
509
    }
510
}
×
511

UNCOV
512
void GameWorldView::DrawObject(const MapPoint& pt, const DrawPoint& curPos) const
×
513
{
514
    noBase* obj = GetWorld().GetNode(pt).obj;
×
UNCOV
515
    if(!obj)
×
516
        return;
×
517

518
    obj->Draw(curPos);
×
519
}
520

UNCOV
521
void GameWorldView::DrawBoundaryStone(const MapPoint& pt, const DrawPoint pos, Visibility vis)
×
522
{
UNCOV
523
    if(vis == Visibility::Invisible)
×
UNCOV
524
        return;
×
525

UNCOV
526
    const bool isFoW = vis == Visibility::FogOfWar;
×
527

528
    const BoundaryStones& boundary_stones =
UNCOV
529
      isFoW ? gwv.GetYoungestFOWNode(pt).boundary_stones : GetWorld().GetNode(pt).boundary_stones;
×
530
    const unsigned char owner = boundary_stones[BorderStonePos::OnPoint];
×
531

UNCOV
532
    if(!owner)
×
533
        return;
×
534

UNCOV
535
    const Nation nation = GetWorld().GetPlayer(owner - 1).nation;
×
536
    unsigned player_color = GetWorld().GetPlayer(owner - 1).color;
×
537
    if(isFoW)
×
UNCOV
538
        player_color = CalcPlayerFOWDrawColor(player_color);
×
539

540
    const auto curVertexPos = gwv.GetTerrainRenderer().GetVertexPos(pt);
×
541
    for(const auto bPos : helpers::EnumRange<BorderStonePos>{})
×
542
    {
UNCOV
543
        DrawPoint curPos;
×
544
        if(bPos == BorderStonePos::OnPoint)
×
545
            curPos = pos;
×
UNCOV
546
        else if(boundary_stones[bPos])
×
547
            curPos = pos
548
                     - DrawPoint((curVertexPos - gwv.GetTerrainRenderer().GetNeighbourVertexPos(pt, toDirection(bPos)))
×
549
                                 / 2.0f);
×
550
        else
UNCOV
551
            continue;
×
552
        LOADER.boundary_stone_cache[nation].draw(curPos, isFoW ? FOW_DRAW_COLOR : COLOR_WHITE, player_color);
×
553
    }
554
}
555

556
void GameWorldView::ToggleShowBQ()
×
557
{
UNCOV
558
    show_bq = !show_bq;
×
UNCOV
559
    SaveIngameSettingsValues();
×
560
    onHudSettingsChanged();
×
UNCOV
561
}
×
562

563
void GameWorldView::ToggleShowNames()
×
564
{
565
    show_names = !show_names;
×
UNCOV
566
    SaveIngameSettingsValues();
×
567
    onHudSettingsChanged();
×
UNCOV
568
}
×
569

570
void GameWorldView::ToggleShowProductivity()
×
571
{
572
    show_productivity = !show_productivity;
×
UNCOV
573
    SaveIngameSettingsValues();
×
574
    onHudSettingsChanged();
×
UNCOV
575
}
×
576

577
void GameWorldView::ToggleShowNamesAndProductivity()
×
578
{
579
    if(show_productivity && show_names)
×
UNCOV
580
        show_productivity = show_names = false;
×
581
    else
UNCOV
582
        show_productivity = show_names = true;
×
583
    SaveIngameSettingsValues();
×
584
    onHudSettingsChanged();
×
UNCOV
585
}
×
586

587
void GameWorldView::CopyHudSettingsTo(GameWorldView& other, bool copyBQ) const
×
588
{
589
    other.show_bq = (copyBQ ? show_bq : false);
×
UNCOV
590
    other.show_names = show_names;
×
591
    other.show_productivity = show_productivity;
×
UNCOV
592
}
×
593

594
void GameWorldView::MoveBy(const DrawPoint& numPixels)
22✔
595
{
596
    MoveTo(offset + numPixels);
22✔
597
}
22✔
598

599
void GameWorldView::MoveTo(const DrawPoint& newPos)
32✔
600
{
601
    offset = newPos;
32✔
602
    DrawPoint size(GetWorld().GetWidth() * TR_W, GetWorld().GetHeight() * TR_H);
32✔
603
    if(size.x && size.y)
32✔
604
    {
605
        offset.x %= size.x;
32✔
606
        offset.y %= size.y;
32✔
607

608
        if(offset.x < 0)
32✔
609
            offset.x += size.x;
5✔
610
        if(offset.y < 0)
32✔
611
            offset.y += size.y;
6✔
612
    }
613

614
    CalcFxLx();
32✔
615
}
32✔
616

617
void GameWorldView::MoveToMapPt(const MapPoint pt)
6✔
618
{
619
    if(!pt.isValid())
6✔
UNCOV
620
        return;
×
621

622
    lastOffset = offset;
6✔
623
    Position nodePos = GetWorld().GetNodePos(pt);
6✔
624

625
    MoveTo(nodePos - GetSize() / 2u);
6✔
626
}
627

UNCOV
628
void GameWorldView::MoveToLastPosition()
×
629
{
UNCOV
630
    Position newLastOffset = offset;
×
631

632
    MoveTo(lastOffset);
×
633

634
    lastOffset = newLastOffset;
×
UNCOV
635
}
×
636

UNCOV
637
void GameWorldView::AddDrawNodeCallback(IDrawNodeCallback* newCallback)
×
638
{
639
    RTTR_Assert(newCallback);
×
UNCOV
640
    drawNodeCallbacks.push_back(newCallback);
×
641
}
×
642

643
void GameWorldView::RemoveDrawNodeCallback(IDrawNodeCallback* callbackToRemove)
×
644
{
645
    auto itPos = helpers::find(drawNodeCallbacks, callbackToRemove);
×
UNCOV
646
    RTTR_Assert(itPos != drawNodeCallbacks.end());
×
647
    drawNodeCallbacks.erase(itPos);
×
UNCOV
648
}
×
649

650
void GameWorldView::CalcFxLx()
32✔
651
{
652
    // Calc first and last point in map units (with 1 extra for incomplete triangles)
653
    firstPt.x = offset.x / TR_W - 1;
32✔
654
    firstPt.y = offset.y / TR_H - 1;
32✔
655
    lastPt.x = (offset.x + size_.x) / TR_W + 1;
32✔
656
    const auto maxAltitude = gwv.getMaxNodeAltitude();
32✔
657
    lastPt.y = (offset.y + size_.y + maxAltitude * HEIGHT_FACTOR) / TR_H + 1;
32✔
658

659
    if(effectiveZoomFactor_ != 1.f) //-V550
32✔
660
    {
661
        // Calc pixels we can remove from sides, as they are not drawn due to zoom
UNCOV
662
        PointF diff(size_.x - size_.x / effectiveZoomFactor_, size_.y - size_.y / effectiveZoomFactor_);
×
663
        // Stay centered by removing half the pixels from opposite sites
UNCOV
664
        diff = diff / 2.f;
×
665
        // Convert to map points
666
        diff.x /= TR_W;
×
UNCOV
667
        diff.y /= TR_H;
×
668
        // Don't remove to much
UNCOV
669
        diff.x = std::floor(diff.x);
×
670
        diff.y = std::floor(diff.y);
×
671
        firstPt = Position(PointF(firstPt) + diff);
×
UNCOV
672
        lastPt = Position(PointF(lastPt) - diff);
×
673
    }
674
}
32✔
675

676
void GameWorldView::Resize(const Extent& newSize)
×
677
{
UNCOV
678
    size_ = newSize;
×
UNCOV
679
    CalcFxLx();
×
680
}
×
681

682
void GameWorldView::SaveIngameSettingsValues() const
×
683
{
684
    auto& ingameSettings = SETTINGS.ingame;
×
UNCOV
685
    ingameSettings.showBQ = show_bq;
×
686
    ingameSettings.showNames = show_names;
×
UNCOV
687
    ingameSettings.showProductivity = show_productivity;
×
688
}
×
689

690
void GameWorldView::updateEffectiveZoomFactor()
9✔
691
{
692
    // partially "undo" GUI scale depending on DPI scale
693
    // => zoom levels should look the same on screens with different DPI regardless of GUI scale
694
    effectiveZoomFactor_ = VIDEODRIVER.getGuiScale().screenToView(zoomFactor_ * VIDEODRIVER.getDpiScale());
9✔
695
}
9✔
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