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

Return-To-The-Roots / s25client / 9321419711

31 May 2024 04:36PM UTC coverage: 50.4% (+0.1%) from 50.304%
9321419711

push

github

Flamefire
Add map selection control for campaigns including test

83 of 108 new or added lines in 4 files covered. (76.85%)

2 existing lines in 2 files now uncovered.

22012 of 43675 relevant lines covered (50.4%)

32124.06 hits per line

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

77.23
/libs/s25main/controls/ctrlMapSelection.cpp
1
// Copyright (C) 2024 Settlers Freaks (sf-team at siedler25.org)
2
//
3
// SPDX-License-Identifier: GPL-2.0-or-later
4

5
#include "ctrlMapSelection.h"
6
#include "CollisionDetection.h"
7
#include "Loader.h"
8
#include "RttrConfig.h"
9
#include "driver/MouseCoords.h"
10
#include "helpers/Range.h"
11
#include "ogl/glArchivItem_Bitmap.h"
12
#include <libsiedler2/ArchivItem_Bitmap.h>
13
#include <libsiedler2/ColorBGRA.h>
14
#include <libsiedler2/IAllocator.h>
15
#include <libsiedler2/libsiedler2.h>
16
#include <helpers/format.hpp>
17

18
ctrlMapSelection::ctrlMapSelection(Window* parent, unsigned id, const DrawPoint& pos, const Extent& size,
3✔
19
                                   const SelectionMapInputData& inputData)
3✔
20
    : Window(parent, id, pos, size), inputData(inputData), missionStatus(inputData.missionSelectionInfos.size()),
21
      preview(false)
3✔
22
{
23
    if(!LOADER.LoadFiles({inputData.background.filePath.string(), inputData.map.filePath.string(),
30✔
24
                          inputData.missionMapMask.filePath.string(), inputData.marker.filePath.string(),
6✔
25
                          inputData.conquered.filePath.string()}))
21✔
NEW
26
        throw std::runtime_error("Loading of images for map failed.");
×
27

28
    auto getImage = [](const ImageResource& res) {
15✔
29
        return LOADER.GetImageN(ResourceId::make(res.filePath), res.index);
15✔
30
    };
31

32
    mapImages.background = getImage(inputData.background);
3✔
33
    mapImages.map = getImage(inputData.map);
3✔
34
    mapImages.missionMapMask = getImage(inputData.missionMapMask);
3✔
35
    mapImages.marker = getImage(inputData.marker);
3✔
36
    mapImages.conquered = getImage(inputData.conquered);
3✔
37
    mapImages.enabledMask = createEnabledMask(mapImages.missionMapMask->GetSize());
3✔
38

39
    if(!mapImages.isValid())
3✔
NEW
40
        throw std::runtime_error("Setup of images for map failed");
×
41

42
    updateEnabledMask();
3✔
43
}
3✔
44

45
ctrlMapSelection::~ctrlMapSelection() = default;
3✔
46

47
void ctrlMapSelection::updateEnabledMask()
15✔
48
{
49
    for(const auto x : helpers::range(mapImages.enabledMask->getWidth()))
5,060✔
50
    {
51
        for(const auto y : helpers::range(mapImages.enabledMask->getHeight()))
510,000✔
52
        {
53
            const auto pixelColor = mapImages.missionMapMask->getPixel(x, y);
250,000✔
54
            const auto matchingMission =
55
              std::find_if(inputData.missionSelectionInfos.begin(), inputData.missionSelectionInfos.end(),
56
                           [&pixelColor](const auto& val) { return val.maskAreaColor == pixelColor.asValue(); });
812,500✔
57

58
            auto const index = std::distance(inputData.missionSelectionInfos.begin(), matchingMission);
250,000✔
59
            if(matchingMission == inputData.missionSelectionInfos.end() || missionStatus[index].playable)
250,000✔
60
            {
61
                mapImages.enabledMask->setPixel(x, y, libsiedler2::ColorBGRA());
650,000✔
62
            } else
63
                mapImages.enabledMask->setPixel(x, y, libsiedler2::ColorBGRA(inputData.disabledColor));
87,500✔
64
        }
65
    }
66
}
15✔
67

68
void ctrlMapSelection::setMissionsStatus(const std::vector<MissionStatus>& status)
12✔
69
{
70
    if(inputData.missionSelectionInfos.size() != status.size())
12✔
NEW
71
        throw std::runtime_error(
×
NEW
72
          helpers::format("List has wrong size. %1% != %2%", inputData.missionSelectionInfos.size(), status.size()));
×
73

74
    missionStatus = status;
12✔
75
    updateEnabledMask();
12✔
76
}
12✔
77

78
void ctrlMapSelection::setSelection(size_t select)
198✔
79
{
80
    if(select < inputData.missionSelectionInfos.size())
198✔
81
    {
82
        if(missionStatus[select].playable)
195✔
83
            currentSelectionPos = inputData.missionSelectionInfos[select].ankerPos;
180✔
84
    } else
85
        currentSelectionPos = Position::Invalid();
3✔
86
}
198✔
87

88
int ctrlMapSelection::getCurrentSelection() const
222✔
89
{
90
    const auto match = std::find_if(inputData.missionSelectionInfos.begin(), inputData.missionSelectionInfos.end(),
91
                                    [&](const auto& val) { return val.ankerPos == currentSelectionPos; });
642✔
92
    return match != inputData.missionSelectionInfos.end() ?
222✔
93
             static_cast<int>(std::distance(inputData.missionSelectionInfos.begin(), match)) :
210✔
94
             -1;
222✔
95
}
96

97
void ctrlMapSelection::setPreview(bool previewOnly)
6✔
98
{
99
    preview = previewOnly;
6✔
100
}
6✔
101

102
bool ctrlMapSelection::Msg_LeftUp(const MouseCoords& mc)
198✔
103
{
104
    if(!preview && IsMouseOver(mc.GetPos()))
198✔
105
    {
106
        const auto pickPos = invertScale(mc.GetPos() - getMapPosition());
186✔
107

108
        const auto pixelColor =
109
          mapImages.missionMapMask->getPixel(std::max(0, std::min(pickPos.x, (int)(mapImages.map->GetSize().x - 1))),
186✔
110
                                             std::max(0, std::min(pickPos.y, (int)(mapImages.map->GetSize().y - 1))));
372✔
111

112
        const auto matchingMission =
113
          std::find_if(inputData.missionSelectionInfos.begin(), inputData.missionSelectionInfos.end(),
114
                       [&pixelColor](const auto& val) { return val.maskAreaColor == pixelColor.asValue(); });
564✔
115

116
        if(matchingMission != inputData.missionSelectionInfos.end())
186✔
117
        {
118
            setSelection(std::distance(inputData.missionSelectionInfos.begin(), matchingMission));
180✔
119
            GetParent()->Msg_ButtonClick(GetID());
180✔
120
        }
121
        return true;
186✔
122
    }
123
    return false;
12✔
124
}
125

126
glArchivItem_Bitmap* ctrlMapSelection::createEnabledMask(const Extent& extent)
3✔
127
{
128
    auto enabledMask =
129
      libsiedler2::getAllocator().create<libsiedler2::baseArchivItem_Bitmap>(libsiedler2::BobType::Bitmap);
3✔
130
    enabledMask->init(extent.x, extent.y, libsiedler2::TextureFormat::BGRA);
3✔
131
    auto* res = dynamic_cast<glArchivItem_Bitmap*>(enabledMask.get());
3✔
132
    RTTR_Assert(!enabledMask.get() || res);
3✔
133
    mapImages.enabledMaskMemory = std::move(enabledMask);
3✔
134
    return res;
6✔
135
}
136

137
bool ctrlMapSelection::IsMouseOver(const Position& mousePos) const
186✔
138
{
139
    return IsPointInRect(mousePos, GetDrawRect());
186✔
140
}
141

142
float ctrlMapSelection::getScaleFactor()
558✔
143
{
144
    const auto ratio = PointF(GetSize()) / mapImages.background->GetSize();
558✔
145
    return ratio.x < ratio.y ? ratio.x : ratio.y;
558✔
146
}
147

148
DrawPoint ctrlMapSelection::invertScale(const DrawPoint& scaleIt)
186✔
149
{
150
    return DrawPoint(scaleIt / getScaleFactor());
186✔
151
}
152

153
DrawPoint ctrlMapSelection::getBackgroundPosition()
186✔
154
{
155
    return GetDrawPos() + (GetSize() - scale(mapImages.background->GetSize())) / 2;
186✔
156
}
157

158
DrawPoint ctrlMapSelection::getMapOffsetRelativeToBackground()
186✔
159
{
160
    return scale(inputData.mapOffsetInBackground);
186✔
161
}
162

163
DrawPoint ctrlMapSelection::getMapPosition()
186✔
164
{
165
    return getBackgroundPosition() + getMapOffsetRelativeToBackground();
186✔
166
}
167

NEW
168
DrawPoint ctrlMapSelection::getScaledImageOriginOffset(glArchivItem_Bitmap* bitmap)
×
169
{
NEW
170
    return bitmap->GetOrigin() - scale(bitmap->GetOrigin());
×
171
}
172

NEW
173
void ctrlMapSelection::drawImageOnMap(glArchivItem_Bitmap* image, const Position& drawPos)
×
174
{
NEW
175
    image->DrawFull(
×
NEW
176
      Rect(getMapPosition() + scale(drawPos) + getScaledImageOriginOffset(image), scale(image->GetSize())));
×
NEW
177
}
×
178

NEW
179
void ctrlMapSelection::Draw_()
×
180
{
NEW
181
    Window::Draw_();
×
182

NEW
183
    mapImages.background->DrawFull(Rect(getBackgroundPosition(), scale(mapImages.background->GetSize())));
×
184

NEW
185
    const Rect mapRect = Rect(getMapPosition(), scale(mapImages.map->GetSize()));
×
NEW
186
    mapImages.map->DrawFull(mapRect);
×
NEW
187
    mapImages.enabledMask->DrawFull(mapRect);
×
188

NEW
189
    for(const auto idx : helpers::range(missionStatus.size()))
×
190
    {
NEW
191
        if(!missionStatus[idx].occupied)
×
NEW
192
            continue;
×
193

NEW
194
        drawImageOnMap(mapImages.conquered, inputData.missionSelectionInfos[idx].ankerPos);
×
195
    }
196

NEW
197
    if(!preview && currentSelectionPos.isValid())
×
198
    {
NEW
199
        drawImageOnMap(mapImages.marker, currentSelectionPos);
×
200
    }
NEW
201
}
×
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