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

Return-To-The-Roots / s25client / 19550882615

20 Nov 2025 08:47PM UTC coverage: 50.483% (+0.01%) from 50.469%
19550882615

push

github

web-flow
Merge pull request #1829 from Flamefire/speed

Make all game speeds available to "v" key

13 of 35 new or added lines in 7 files covered. (37.14%)

4 existing lines in 1 file now uncovered.

22515 of 44599 relevant lines covered (50.48%)

35056.13 hits per line

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

34.95
/libs/s25main/Game.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 "Game.h"
6
#include "EconomyModeHandler.h"
7
#include "EventManager.h"
8
#include "GameInterface.h"
9
#include "GamePlayer.h"
10
#include "addons/AddonEconomyModeGameLength.h"
11
#include "addons/const_addons.h"
12
#include "ai/AIPlayer.h"
13
#include "lua/LuaInterfaceGame.h"
14
#include "network/GameClient.h"
15
#include "gameData/GameConsts.h"
16
#include <boost/optional.hpp>
17

18
Game::Game(GlobalGameSettings settings, unsigned startGF, const std::vector<PlayerInfo>& players)
26✔
19
    : Game(std::move(settings), std::make_unique<EventManager>(startGF), players)
26✔
20
{}
26✔
21

22
Game::Game(GlobalGameSettings settings, std::unique_ptr<EventManager> em, const std::vector<PlayerInfo>& players)
155✔
23
    : ggs_(std::move(settings)), em_(std::move(em)), world_(players, ggs_, *em_), started_(false), finished_(false)
155✔
24
{}
155✔
25

26
Game::~Game() = default;
155✔
27

28
void Game::Start(bool startFromSave)
2✔
29
{
30
    if(started_)
2✔
31
        return;
×
32
    started_ = true;
2✔
33
    if(startFromSave)
2✔
34
        CheckObjective();
×
35
    else
36
    {
37
        if(ggs_.objective == GameObjective::EconomyMode)
2✔
38
        {
39
            unsigned int selection = ggs_.getSelection(AddonId::ECONOMY_MODE_GAME_LENGTH);
2✔
40
            world_.setEconHandler(
2✔
41
              std::make_unique<EconomyModeHandler>(duration_to_gfs(AddonEconomyModeGameLengthList[selection])));
4✔
42
        }
43
        StatisticStep();
2✔
44
    }
45
    if(world_.HasLua())
2✔
46
        world_.GetLua().EventStart(!startFromSave);
×
47
}
48

49
void Game::AddAIPlayer(std::unique_ptr<AIPlayer> newAI)
13✔
50
{
51
    aiPlayers_.push_back(std::move(newAI));
13✔
52
}
13✔
53

54
void Game::SetLua(std::unique_ptr<LuaInterfaceGame> newLua)
25✔
55
{
56
    lua = std::move(newLua);
25✔
57
    world_.SetLua(lua.get());
25✔
58
}
25✔
59

60
namespace {
61
unsigned getNumAlivePlayers(const GameWorldBase& world)
×
62
{
63
    unsigned numPlayersAlive = 0;
×
64
    for(unsigned i = 0; i < world.GetNumPlayers(); ++i)
×
65
    {
66
        if(!world.GetPlayer(i).IsDefeated())
×
67
            ++numPlayersAlive;
×
68
    }
69
    return numPlayersAlive;
×
70
}
71
} // namespace
72

73
void Game::RunGF()
×
74
{
75
    unsigned numPlayersAlive = getNumAlivePlayers(world_);
×
76
    //  EventManager Bescheid sagen
77
    em_->ExecuteNextGF();
×
78
    // Notfallprogramm durchlaufen lassen
79
    for(unsigned i = 0; i < world_.GetNumPlayers(); ++i)
×
80
    {
81
        GamePlayer& player = world_.GetPlayer(i);
×
82
        if(player.isUsed())
×
83
        {
84
            // Auf Notfall testen (Wenige Bretter/Steine und keine Holzindustrie)
85
            player.TestForEmergencyProgramm();
×
86
            player.TestPacts();
×
87
        }
88
    }
89

90
    if(world_.HasLua())
×
91
        world_.GetLua().EventGameFrame(em_->GetCurrentGF());
×
92
    // Update statistic every 30 seconds
NEW
93
    constexpr auto GFsIn30s = static_cast<unsigned>(duration_to_gfs(30s));
×
94
    if(em_->GetCurrentGF() % GFsIn30s == 0)
×
95
        StatisticStep();
×
96
    // If some players got defeated check objective
97
    if(getNumAlivePlayers(world_) < numPlayersAlive)
×
98
        CheckObjective();
×
99
}
×
100

101
void Game::StatisticStep()
2✔
102
{
103
    for(unsigned i = 0; i < world_.GetNumPlayers(); ++i)
8✔
104
        world_.GetPlayer(i).StatisticStep();
6✔
105

106
    CheckObjective();
2✔
107
}
2✔
108

109
void Game::CheckObjective()
2✔
110
{
111
    // Check objective if there is one
112
    if(finished_ || (ggs_.objective != GameObjective::Conquer3_4 && ggs_.objective != GameObjective::TotalDomination))
2✔
113
        return;
2✔
114

115
    unsigned maxPoints = 0, maxTeamPoints = 0, totalPoints = 0, bestPlayer = 0;
×
116
    boost::optional<unsigned> bestTeam;
×
117

118
    const auto getPlayerMask = [](unsigned playerId) { return 1u << playerId; };
×
119

120
    // Find out best player. Since at least 3/4 of the populated land is needed to win, we don't care about ties.
121
    for(unsigned i = 0; i < world_.GetNumPlayers(); ++i)
×
122
    {
123
        const GamePlayer& player = world_.GetPlayer(i);
×
124
        if(player.IsDefeated())
×
125
            continue;
×
126
        const unsigned points = player.GetStatisticCurrentValue(StatisticType::Country);
×
127
        if(points > maxPoints)
×
128
        {
129
            maxPoints = points;
×
130
            bestPlayer = i;
×
131
        }
132
        totalPoints += points;
×
133
        if(ggs_.lockedTeams) // in games with locked team settings check for team victory
×
134
        {
135
            unsigned curTeam = getPlayerMask(i);
×
136
            unsigned teamPoints = points;
×
137
            // Add points of all players in this players team (excluding himself)
138
            for(unsigned j = 0; j < world_.GetNumPlayers(); ++j)
×
139
            {
140
                if(i == j || !player.IsAlly(j))
×
141
                    continue;
×
142
                curTeam = curTeam | getPlayerMask(j);
×
143
                const GamePlayer& teamPlayer = world_.GetPlayer(j);
×
144
                if(!teamPlayer.IsDefeated())
×
145
                    teamPoints += teamPlayer.GetStatisticCurrentValue(StatisticType::Country);
×
146
            }
147
            if(teamPoints > maxTeamPoints)
×
148
            {
149
                maxTeamPoints = teamPoints;
×
150
                bestTeam = curTeam;
×
151
            }
152
        }
153
    }
154
    // No one has land -> All lost?
155
    if(totalPoints == 0u)
×
156
        return;
×
157

158
    switch(ggs_.objective)
×
159
    {
160
        case GameObjective::Conquer3_4: // at least 3/4 of the land
×
161
            if(maxTeamPoints * 4u >= totalPoints * 3u || maxPoints * 4u >= totalPoints * 3u)
×
162
                finished_ = true;
×
163
            break;
×
164

165
        case GameObjective::TotalDomination: // whole populated land
×
166
            if(maxTeamPoints == totalPoints || maxPoints == totalPoints)
×
167
                finished_ = true;
×
168
            break;
×
169
        default: break;
×
170
    }
171

172
    // We have a winner!
173
    if(world_.GetGameInterface() && finished_)
×
174
    {
175
        // If there is a team that is best and it does not only consist of the best player
176
        // then it is a team victory, else a single players victory
177
        if(bestTeam && *bestTeam != getPlayerMask(bestPlayer))
×
178
            world_.GetGameInterface()->GI_TeamWinner(*bestTeam);
×
179
        else
180
            world_.GetGameInterface()->GI_Winner(bestPlayer);
×
181
    }
182
}
183

184
AIPlayer* Game::GetAIPlayer(unsigned id)
8✔
185
{
186
    for(AIPlayer& ai : aiPlayers_)
8✔
187
    {
188
        if(ai.GetPlayerId() == id)
8✔
189
            return &ai;
8✔
190
    }
191
    return nullptr;
×
192
}
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