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

Return-To-The-Roots / s25client / 21285142390

23 Jan 2026 11:49AM UTC coverage: 50.761% (+0.1%) from 50.663%
21285142390

Pull #1679

github

web-flow
Merge b1ffe8192 into 12da8bf44
Pull Request #1679: Add all classic S2 cheats and a few more

94 of 155 new or added lines in 12 files covered. (60.65%)

8 existing lines in 6 files now uncovered.

22800 of 44916 relevant lines covered (50.76%)

41543.76 hits per line

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

9.24
/libs/s25main/nodeObjs/noTree.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 "noTree.h"
6

7
#include "EventManager.h"
8
#include "FOWObjects.h"
9
#include "GameInterface.h"
10
#include "GlobalGameSettings.h"
11
#include "Loader.h"
12
#include "SerializedGameData.h"
13
#include "addons/const_addons.h"
14
#include "network/GameClient.h"
15
#include "noAnimal.h"
16
#include "noDisappearingMapEnvObject.h"
17
#include "noExtension.h"
18
#include "ogl/glSmartBitmap.h"
19
#include "random/Random.h"
20
#include "world/GameWorld.h"
21
#include <array>
22

23
unsigned short noTree::DRAW_COUNTER = 0;
24

25
noTree::noTree(const MapPoint pos, const unsigned char type, const unsigned char size)
14,180✔
26
    : noCoordBase(NodalObjectType::Tree, pos), type(type), size(size), event(nullptr), produce_animal_event(nullptr)
14,180✔
27
{
28
    // Wenn der Baum klein ist, muss später mal wachsen
29
    if(!size)
14,180✔
30
    {
31
        event = GetEvMgr().AddEvent(this, WAIT_LENGTH);
×
32
        state = State::GrowingWait;
×
33
    } else
34
        state = State::Nothing;
14,180✔
35

36
    // Every nth tree produces animals, but no palm and pineapple trees
37
    const std::array<unsigned, 6> TREESPERANIMALSPAWN = {20, 13, 10, 6, 4, 2};
14,180✔
38
    produce_animals = (type < 3 || type > 5)
492✔
39
                      && (RANDOM_RAND(TREESPERANIMALSPAWN[world->GetGGS().getSelection(AddonId::MORE_ANIMALS)]) == 0);
14,672✔
40

41
    // Falls das der Fall ist, dann wollen wir doch gleich mal eins produzieren
42
    if(produce_animals)
14,180✔
43
        produce_animal_event = GetEvMgr().AddEvent(this, 6000 + RANDOM_RAND(2000), 3);
661✔
44
}
14,180✔
45

46
noTree::~noTree() = default;
28,360✔
47

48
void noTree::Destroy()
×
49
{
50
    GetEvMgr().RemoveEvent(produce_animal_event);
×
51
    noCoordBase::Destroy();
×
52
}
×
53

54
void noTree::Serialize(SerializedGameData& sgd) const
×
55
{
56
    noCoordBase::Serialize(sgd);
×
57

58
    sgd.PushUnsignedChar(type);
×
59
    sgd.PushUnsignedChar(size);
×
60
    sgd.PushEnum<uint8_t>(state);
×
61
    sgd.PushEvent(event);
×
62
    sgd.PushEvent(produce_animal_event);
×
63
    sgd.PushBool(produce_animals);
×
64
}
×
65

66
noTree::noTree(SerializedGameData& sgd, const unsigned obj_id)
×
67
    : noCoordBase(sgd, obj_id), type(sgd.PopUnsignedChar()), size(sgd.PopUnsignedChar()), state(sgd.Pop<State>()),
×
68
      event(sgd.PopEvent()), produce_animal_event(sgd.PopEvent()), produce_animals(sgd.PopBool())
×
69
{}
×
70

71
void noTree::Draw(DrawPoint drawPt)
×
72
{
73
    switch(state)
×
74
    {
75
        case State::Nothing:
×
76
        case State::FallingWait:
77
        {
78
            // Wenn er ausgewachsen ist, dann animiert zeichnen
79
            LOADER
×
80
              .tree_cache[type]
×
81
                         [GAMECLIENT.GetGlobalAnimation(8, 7 - GetX() % 2, 3 + GetY() % 3, GetX() * GetY() * 10 * type)]
×
82
              .draw(drawPt);
×
83

84
            // je mehr Bäume gezeichnet, desto mehr Vogelgezwitscher
85
            ++DRAW_COUNTER;
×
86
        }
87
        break;
×
88
        case State::GrowingWait:
×
89
        {
90
            // normal zeichnen, wächst nicht
91
            LOADER.tree_cache[type][8 + size].draw(drawPt);
×
92
        }
93
        break;
×
94
        case State::GrowingGrow:
×
95
        {
96
            // alten Baum ausblenden
97
            unsigned transparency = (GAMECLIENT.Interpolate(0xFF, event)) << 24;
×
98

99
            LOADER.tree_cache[type][8 + size].draw(drawPt, 0xFFFFFFFF - transparency);
×
100

101
            if(size == 2)
×
102
            {
103
                LOADER.tree_cache[type][0].draw(drawPt, transparency | 0xFFFFFF);
×
104
            } else
105
            {
106
                LOADER.tree_cache[type][8 + size + 1].draw(drawPt, transparency | 0xFFFFFF);
×
107
            }
108
        }
109
        break;
×
110
        case State::FallingFall:
×
111
        {
112
            // Umfallen beschleunigen --> für erste Frames mehr Zeit
113
            unsigned short i = GAMECLIENT.Interpolate(9, event);
×
114

115
            if(i < 4)
×
116
                i = 0;
×
117
            else if(i < 7)
×
118
                i = 1;
×
119
            else
120
                i = 2;
×
121

122
            LOADER.tree_cache[type][11 + i].draw(drawPt);
×
123
        }
124
        break;
×
125
        case State::FallingFallen:
×
126
        {
127
            LOADER.tree_cache[type][14].draw(drawPt);
×
128
        }
129
        break;
×
130
    }
131
}
×
132

133
void noTree::HandleEvent(const unsigned id)
×
134
{
135
    // Ein Tier-Produzier-Event?
136
    if(id == 3)
×
137
    {
138
        // Neues Tier erzeugen
139
        ProduceAnimal();
×
140
        // nächstes Event anmelden
141
        produce_animal_event = GetEvMgr().AddEvent(this, 6000 + RANDOM_RAND(2000), 3);
×
142

143
        return;
×
144
    }
145

146
    switch(state)
×
147
    {
148
        case State::GrowingWait:
×
149
        {
150
            // Der Baum hat gewartet, also wächst er jetzt
151
            event = GetEvMgr().AddEvent(this, GROWING_LENGTH);
×
152
            state = State::GrowingGrow;
×
153
        }
154
        break;
×
155
        case State::GrowingGrow:
×
156
        {
157
            // Wenn er ausgewachsen ist, dann nicht, ansonsten nochmal ein "Warteevent" anmelden, damit er noch weiter
158
            // wächst
159
            if(++size != 3)
×
160
            {
161
                event = GetEvMgr().AddEvent(this, WAIT_LENGTH);
×
162
                // Erstmal wieder bis zum nächsten Wachsstumsschub warten
163
                state = State::GrowingWait;
×
164
            } else
165
            {
166
                // bin nun ausgewachsen
167
                state = State::Nothing;
×
168
                event = nullptr;
×
169
            }
170
        }
171
        break;
×
172
        case State::FallingWait:
×
173
        {
174
            // Jetzt umfallen
175
            state = State::FallingFall;
×
176

177
            event = GetEvMgr().AddEvent(this, 15);
×
178
        }
179
        break;
×
180
        case State::FallingFall:
×
181
        {
182
            // Baum ist gefallen, nach bestimmer Zeit verschwinden
183
            state = State::FallingFallen;
×
184
            event = GetEvMgr().AddEvent(this, 28);
×
185
        }
186
        break;
×
187
        case State::FallingFallen:
×
188
        {
189
            // Baum verschwindet nun und es bleibt ein Baumstumpf zurück
190
            event = nullptr;
×
191
            GetEvMgr().AddToKillList(this);
×
192

193
            // Due to the "build headquarters" cheat, there could be an HQ in these directions. Replace stump with
194
            // extension which would have otherwise been placed in noBaseBuilding ctor.
NEW
195
            bool shouldPlaceStump = true;
×
NEW
196
            for(const Direction i : {Direction::East, Direction::SouthEast, Direction::SouthWest})
×
197
            {
NEW
198
                const noBase* neighborNo = world->GetNO(world->GetNeighbour(pos, i));
×
199

NEW
200
                if(neighborNo->GetType() == NodalObjectType::Building
×
NEW
201
                   && static_cast<const noBaseBuilding*>(neighborNo)->GetBuildingType() == BuildingType::Headquarters)
×
202
                {
NEW
203
                    world->SetNO(pos, new noExtension(this), true);
×
NEW
204
                    shouldPlaceStump = false;
×
NEW
205
                    break;
×
206
                }
207
            }
208

NEW
209
            if(shouldPlaceStump)
×
210
            {
NEW
211
                world->SetNO(pos, new noDisappearingMapEnvObject(pos, 531), true);
×
NEW
212
                world->RecalcBQAroundPoint(pos);
×
213
            }
214

215
            // Minimap Bescheid geben (Baum gefallen)
216
            if(world->GetGameInterface())
×
217
                world->GetGameInterface()->GI_UpdateMinimap(pos);
×
218
        }
219
        break;
×
220
        default: break;
×
221
    }
222
}
223

224
std::unique_ptr<FOWObject> noTree::CreateFOWObject() const
×
225
{
226
    return std::make_unique<fowTree>(type, size);
×
227
}
228

229
void noTree::FallSoon()
×
230
{
231
    // Warten bis der Holzfäller fertig ist und der Baum dann umfällt
232
    event = GetEvMgr().AddEvent(this, 105);
×
233
    state = State::FallingWait;
×
234
}
×
235

236
void noTree::DontFall()
×
237
{
238
    if(state == State::FallingWait)
×
239
        GetEvMgr().RemoveEvent(event);
×
240
}
×
241

242
void noTree::ProduceAnimal()
×
243
{
244
    // neues Tier erzeugen, zufälliger Typ
245
    constexpr std::array<Species, 6> possibleSpecies = {
×
246
      {Species::RabbitWhite, Species::RabbitGrey, Species::Fox, Species::Stag, Species::Deer, Species::Sheep}};
247
    world->AddFigure(pos, std::make_unique<noAnimal>(RANDOM_ELEMENT(possibleSpecies), pos)).StartLiving();
×
248
}
×
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