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

Return-To-The-Roots / s25client / 24783147581

22 Apr 2026 02:11PM UTC coverage: 50.384% (+0.02%) from 50.362%
24783147581

push

github

web-flow
Merge pull request #1913 from Flamefire/soldier-cancel

79 of 104 new or added lines in 13 files covered. (75.96%)

1 existing line in 1 file now uncovered.

23066 of 45780 relevant lines covered (50.38%)

42797.98 hits per line

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

75.59
/libs/s25main/figures/nofAggressiveDefender.cpp
1
// Copyright (C) 2005 - 2026 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,
4✔
15
                                             const unsigned char rank, nofAttacker& attacker)
4✔
16
    : nofActiveSoldier(pos, player, home, rank, SoldierState::AggressivedefendingWalkingToAggressor),
17
      attacker(&attacker), attacked_goal(attacker.GetAttackedGoal())
4✔
18
{
19
    // Notify building to protect
20
    attacked_goal->LinkAggressiveDefender(*this);
4✔
21
}
4✔
22

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

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

33
void nofAggressiveDefender::Destroy()
12✔
34
{
35
    RTTR_Assert(!attacker);
12✔
36
    RTTR_Assert(!attacked_goal);
12✔
37
    nofActiveSoldier::Destroy();
12✔
38
}
12✔
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()
26✔
66
{
67
    if(state == SoldierState::AggressivedefendingWalkingToAggressor)
26✔
68
        MissAggressiveDefendingWalk();
12✔
69
    else
70
        nofActiveSoldier::Walked();
14✔
71
}
26✔
72

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

78
void nofAggressiveDefender::HomeDestroyedAtBegin()
×
79
{
NEW
80
    homeBld = 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()
12✔
93
{
94
    if(attacked_goal)
12✔
95
    {
96
        attacked_goal->UnlinkAggressiveDefender(*this);
10✔
97
        attacked_goal = nullptr;
10✔
98
    }
99
}
12✔
100

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

107
    // Ist evtl. unser Heimatgebäude zerstört?
108
    if(!homeBld)
1✔
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();
1✔
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()
4✔
136
{
137
    RTTR_Assert(!attacker);
4✔
138
    // Wenns das Zielgebäude nich mehr gibt, gleich nach Hause gehen!
139
    if(!attacked_goal)
4✔
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;
4✔
148

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

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

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

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

178
void nofAggressiveDefender::MissAggressiveDefendingWalk()
14✔
179
{
180
    if(!homeBld)
14✔
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;
5✔
188
    }
189

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

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

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

213
    // Look for enemies
214
    if(TryFightingNearbyEnemy())
10✔
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?
9✔
224

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

228
    if(dir)
9✔
229
    {
230
        // Continue walking towards him
231
        StartWalking(*dir);
8✔
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()
3✔
242
{
243
    InformTargetsAboutCancelling();
3✔
244
    ReturnHome();
3✔
245
}
3✔
246

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

254
void nofAggressiveDefender::InformTargetsAboutCancelling()
12✔
255
{
256
    nofActiveSoldier::InformTargetsAboutCancelling();
12✔
257
    CancelAtAttacker();
12✔
258
    CancelAtAttackedBld();
12✔
259
}
12✔
260

261
void nofAggressiveDefender::CancelAtAttacker()
16✔
262
{
263
    if(attacker)
16✔
264
    {
265
        RTTR_Assert(attacker->GetHuntingDefender() == this);
11✔
266
        attacker->AggressiveDefenderLost();
11✔
267
        attacker = nullptr;
11✔
268
    }
269
}
16✔
270

271
nofActiveSoldier::SoldierState nofAggressiveDefender::FreeFightAborted()
2✔
272
{
273
    // Continue with normal walking towards our goal
274
    return SoldierState::AggressivedefendingWalkingToAggressor;
2✔
275
}
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