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

Return-To-The-Roots / s25client / 21212247939

21 Jan 2026 01:56PM UTC coverage: 50.663% (+0.05%) from 50.61%
21212247939

push

github

Flow86
Use some texture for all buttons

1 of 1 new or added line in 1 file covered. (100.0%)

85 existing lines in 5 files now uncovered.

22698 of 44802 relevant lines covered (50.66%)

35292.98 hits per line

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

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

5
#include "nofAggressiveDefender.h"
6
#include "GlobalGameSettings.h"
7
#include "SerializedGameData.h"
8
#include "addons/const_addons.h"
9
#include "nofAttacker.h"
10
#include "nofPassiveSoldier.h"
11
#include "random/Random.h"
12
#include "world/GameWorld.h"
13

14
nofAggressiveDefender::nofAggressiveDefender(const MapPoint pos, const unsigned char player, nobBaseMilitary& home,
×
15
                                             const unsigned char rank, nofAttacker& attacker)
×
16
    : nofActiveSoldier(pos, player, home, rank, SoldierState::AggressivedefendingWalkingToAggressor),
17
      attacker(&attacker), attacked_goal(attacker.GetAttackedGoal())
×
18
{
19
    // Notify building to protect
20
    attacked_goal->LinkAggressiveDefender(*this);
×
21
}
×
22

23
nofAggressiveDefender::nofAggressiveDefender(const nofPassiveSoldier& other, nofAttacker& attacker)
4✔
24
    : nofActiveSoldier(other, SoldierState::AggressivedefendingWalkingToAggressor), attacker(&attacker),
25
      attacked_goal(attacker.GetAttackedGoal())
4✔
26
{
27
    // Notify building to protect
28
    attacked_goal->LinkAggressiveDefender(*this);
4✔
29
}
4✔
30

31
nofAggressiveDefender::~nofAggressiveDefender() = default;
8✔
32

33
void nofAggressiveDefender::Destroy()
4✔
34
{
35
    RTTR_Assert(!attacker);
4✔
36
    RTTR_Assert(!attacked_goal);
4✔
37
    nofActiveSoldier::Destroy();
4✔
38
}
4✔
39

40
void nofAggressiveDefender::Serialize(SerializedGameData& sgd) const
×
41
{
42
    nofActiveSoldier::Serialize(sgd);
×
43

44
    if(state != SoldierState::WalkingHome && state != SoldierState::FigureWork)
×
45
    {
46
        sgd.PushObject(attacker, true);
×
47
        sgd.PushObject(attacked_goal);
×
48
    }
49
}
×
50

51
nofAggressiveDefender::nofAggressiveDefender(SerializedGameData& sgd, const unsigned obj_id)
×
52
    : nofActiveSoldier(sgd, obj_id)
×
53
{
54
    if(state != SoldierState::WalkingHome && state != SoldierState::FigureWork)
×
55
    {
56
        attacker = sgd.PopObject<nofAttacker>(GO_Type::NofAttacker);
×
57
        attacked_goal = sgd.PopObject<nobBaseMilitary>();
×
58
    } else
59
    {
60
        attacker = nullptr;
×
61
        attacked_goal = nullptr;
×
62
    }
63
}
×
64

65
void nofAggressiveDefender::Walked()
20✔
66
{
67
    if(state == SoldierState::AggressivedefendingWalkingToAggressor)
20✔
68
        MissAggressiveDefendingWalk();
8✔
69
    else
70
        nofActiveSoldier::Walked();
12✔
71
}
20✔
72

73
void nofAggressiveDefender::HomeDestroyed()
1✔
74
{
75
    building = nullptr;
1✔
76
}
1✔
77

78
void nofAggressiveDefender::HomeDestroyedAtBegin()
×
79
{
80
    building = nullptr;
×
81

82
    // angegriffenem Gebäude Bescheid sagen, dass wir doch nicht mehr kommen
83
    InformTargetsAboutCancelling();
×
84

85
    state = SoldierState::FigureWork;
×
86

87
    // Rumirren
88
    StartWandering();
×
89
    StartWalking(RANDOM_ENUM(Direction));
×
90
}
×
91

92
void nofAggressiveDefender::CancelAtAttackedBld()
4✔
93
{
94
    if(attacked_goal)
4✔
95
    {
96
        attacked_goal->UnlinkAggressiveDefender(*this);
3✔
97
        attacked_goal = nullptr;
3✔
98
    }
99
}
4✔
100

101
void nofAggressiveDefender::WonFighting()
×
102
{
103
    // addon BattlefieldPromotion active? -> increase rank!
104
    if(world->GetGGS().isEnabled(AddonId::BATTLEFIELD_PROMOTION))
×
105
        IncreaseRank();
×
106

107
    // Ist evtl. unser Heimatgebäude zerstört?
108
    if(!building)
×
109
    {
110
        // Ziel Bescheid sagen
111
        InformTargetsAboutCancelling();
×
112

113
        // Rumirren
114
        state = SoldierState::FigureWork;
×
115
        StartWandering();
×
116
        Wander();
×
117

118
        return;
×
119
    }
120

121
    // Continue walking to our attacker
122
    MissAggressiveDefendingContinueWalking();
×
123
}
124

125
void nofAggressiveDefender::LostFighting()
1✔
126
{
127
    // Meinem zu Hause Bescheid sagen, dass ich nicht mehr lebe (damit neue Truppen reinkönnen),
128
    // falls es noch existiert
129
    AbrogateWorkplace();
1✔
130

131
    // Ziel Bescheid sagen, das ich verteidigt hatte
132
    InformTargetsAboutCancelling();
1✔
133
}
1✔
134

135
void nofAggressiveDefender::MissionAggressiveDefendingLookForNewAggressor()
2✔
136
{
137
    RTTR_Assert(!attacker);
2✔
138
    // Wenns das Zielgebäude nich mehr gibt, gleich nach Hause gehen!
139
    if(!attacked_goal)
2✔
140
    {
141
        ReturnHomeMissionAggressiveDefending();
×
142
        return;
×
143
    }
144

145
    // Vermeiden, dass in FindAggressor nochmal der Soldat zum Loslaufen gezwungen wird, weil er als state
146
    // noch drinstehen hat, dass er auf einen Kampf wartet
147
    state = SoldierState::AggressivedefendingWalkingToAggressor;
2✔
148

149
    // nach anderen suchen, die in meiner Nähe sind und mich evtl noch mit denen kloppen
150
    attacker = attacked_goal->FindAggressor(*this);
2✔
151
    if(attacker)
2✔
152
    {
153
        // zum Angreifer gehen und mit ihm kämpfen
154
        MissAggressiveDefendingWalk();
×
155
    } else
156
    {
157
        // keiner will mehr mit mir kämpfen, dann geh ich halt wieder nach Hause
158
        ReturnHomeMissionAggressiveDefending();
2✔
159
    }
160
}
161

162
void nofAggressiveDefender::AttackedGoalDestroyed()
1✔
163
{
164
    CancelAtAttacker();
1✔
165
    attacked_goal = nullptr;
1✔
166

167
    /*// Stehen wir? Dann losgehen
168
    if(state == Waitingforfight)
169
        ReturnHome();*/
170
}
1✔
171

172
void nofAggressiveDefender::MissAggressiveDefendingContinueWalking()
×
173
{
174
    state = SoldierState::AggressivedefendingWalkingToAggressor;
×
175
    MissAggressiveDefendingWalk();
×
176
}
×
177

178
void nofAggressiveDefender::MissAggressiveDefendingWalk()
8✔
179
{
180
    if(!building)
8✔
181
    {
182
        // Home destroyed so abort and wander around
183
        InformTargetsAboutCancelling();
1✔
184
        state = SoldierState::FigureWork;
1✔
185
        StartWandering();
1✔
186
        Wander();
1✔
187
        return;
3✔
188
    }
189

190
    if(!attacked_goal)
7✔
191
    {
192
        // Similar when the defended building is gone
193
        ReturnHomeMissionAggressiveDefending();
×
194
        return;
×
195
    }
196

197
    if(!attacker)
7✔
198
    {
199
        // Search for a new attacker if lost
200
        MissionAggressiveDefendingLookForNewAggressor();
1✔
201
        return;
1✔
202
    }
203

204
    // Does he still want to fight?
205
    if(!attacker->IsReadyForFight())
6✔
206
    {
207
        // Look for a new one
208
        CancelAtAttacker();
×
209
        MissionAggressiveDefendingLookForNewAggressor();
×
210
        return;
×
211
    }
212

213
    // Look for enemies
214
    if(TryFightingNearbyEnemy())
6✔
215
    {
216
        // Enemy found -> abort, because nofActiveSoldier handles all things now
217
        // Note it is ok, if the enemy is our attacker.
218
        // If we win, we will either see, that the attacker is busy or be notified because he did
219
        // If we loose, we will tell him later
220
        return;
1✔
221
    }
222

223
    RTTR_Assert(pos != attacker->GetPos()); // If so, why was it not found?
5✔
224

225
    // Calc next walking direction
226
    const auto dir = world->FindHumanPath(pos, attacker->GetPos(), 100, true);
5✔
227

228
    if(dir)
5✔
229
    {
230
        // Continue walking towards him
231
        StartWalking(*dir);
4✔
232
    } else
233
    {
234
        // No route found
235
        // Look for new attacker
236
        CancelAtAttacker();
1✔
237
        MissionAggressiveDefendingLookForNewAggressor();
1✔
238
    }
239
}
240

241
void nofAggressiveDefender::ReturnHomeMissionAggressiveDefending()
2✔
242
{
243
    InformTargetsAboutCancelling();
2✔
244
    ReturnHome();
2✔
245
}
2✔
246

247
void nofAggressiveDefender::AttackerLost()
1✔
248
{
249
    RTTR_Assert(attacker);
1✔
250
    attacker = nullptr;
1✔
251
    // TODO(Replay) When still in leave queue abort to avoid going out and right back
252
}
1✔
253

UNCOV
254
void nofAggressiveDefender::NeedForHomeDefence()
×
255
{
256
    InformTargetsAboutCancelling();
×
UNCOV
257
}
×
258

259
void nofAggressiveDefender::InformTargetsAboutCancelling()
4✔
260
{
261
    nofActiveSoldier::InformTargetsAboutCancelling();
4✔
262
    CancelAtAttacker();
4✔
263
    CancelAtAttackedBld();
4✔
264
}
4✔
265

266
void nofAggressiveDefender::CancelAtAttacker()
6✔
267
{
268
    if(attacker)
6✔
269
    {
270
        RTTR_Assert(attacker->GetHuntingDefender() == this);
3✔
271
        attacker->AggressiveDefenderLost();
3✔
272
        attacker = nullptr;
3✔
273
    }
274
}
6✔
275

276
nofActiveSoldier::SoldierState nofAggressiveDefender::FreeFightAborted()
2✔
277
{
278
    // Continue with normal walking towards our goal
279
    return SoldierState::AggressivedefendingWalkingToAggressor;
2✔
280
}
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