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

Return-To-The-Roots / s25client / 12454926545

22 Dec 2024 02:06PM UTC coverage: 50.23% (+0.005%) from 50.225%
12454926545

Pull #1681

github

web-flow
Merge 2ae89be01 into 17844c810
Pull Request #1681: Add support for campaign status

57 of 112 new or added lines in 10 files covered. (50.89%)

3 existing lines in 3 files now uncovered.

22360 of 44515 relevant lines covered (50.23%)

35626.14 hits per line

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

32.14
/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)
27✔
19
    : Game(std::move(settings), std::make_unique<EventManager>(startGF), players)
27✔
20
{}
27✔
21

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

26
Game::~Game() = default;
153✔
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(std::make_unique<EconomyModeHandler>(AddonEconomyModeGameLengthList[selection]
4✔
41
                                                                       / SPEED_GF_LENGTHS[referenceSpeed]));
6✔
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)
14✔
50
{
51
    aiPlayers_.push_back(std::move(newAI));
14✔
52
}
14✔
53

54
void Game::SetLua(std::unique_ptr<LuaInterfaceGame> newLua)
26✔
55
{
56
    lua = std::move(newLua);
26✔
57
    world_.SetLua(lua.get());
26✔
58
}
26✔
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
93
    constexpr unsigned GFsIn30s = std::chrono::duration<unsigned>(30) / SPEED_GF_LENGTHS[referenceSpeed];
×
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

NEW
182
        if(world_.HasLua() && IsWinnerHuman(bestTeam.value_or(0), bestPlayer))
×
NEW
183
            world_.GetLua().EventHumanWinner();
×
184
    }
185
}
186

NEW
187
bool Game::IsWinnerHuman(unsigned bestTeam, unsigned bestPlayer) const
×
188
{
NEW
189
    if(world_.GetPlayer(bestPlayer).isHuman())
×
NEW
190
        return true;
×
191

NEW
192
    for(auto i = 0u; i < world_.GetNumPlayers(); ++i)
×
NEW
193
        if(world_.GetPlayer(bestTeam & (1 << i)).isHuman())
×
NEW
194
            return true;
×
195

NEW
196
    return false;
×
197
}
198

199
AIPlayer* Game::GetAIPlayer(unsigned id)
9✔
200
{
201
    for(AIPlayer& ai : aiPlayers_)
9✔
202
    {
203
        if(ai.GetPlayerId() == id)
9✔
204
            return &ai;
9✔
205
    }
206
    return nullptr;
×
207
}
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