-
Notifications
You must be signed in to change notification settings - Fork 95
Expand file tree
/
Copy pathPickedMovableObject.cpp
More file actions
154 lines (126 loc) · 4.63 KB
/
Copy pathPickedMovableObject.cpp
File metadata and controls
154 lines (126 loc) · 4.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Copyright (C) 2005 - 2023 Settlers Freaks (sf-team at siedler25.org)
//
// SPDX-License-Identifier: GPL-2.0-or-later
#include "PickedMovableObject.h"
#include "desktops/dskGameInterface.h"
#include "drivers/VideoDriverWrapper.h"
#include "world/GameWorldBase.h"
#include "world/GameWorldView.h"
#include "nodeObjs/noMovable.h"
#include <cmath>
using namespace std::chrono_literals;
namespace {
constexpr unsigned PickRadius = 2;
constexpr unsigned TrackRadius = 5;
constexpr auto PickedObjectExpiration = 5s;
// Make (ab-)use of CheckPointsInRadius() easier
constexpr bool CheckPointsBreak = true;
constexpr bool CheckPointsContinue = false;
} // namespace
PickedMovableObject PickedMovableObject::pick(const GameWorldView& gwv, MapPoint mapPt, DrawPoint drawPt, bool expire)
{
// DEBUG REMOVE BEFORE MERGE
unsigned i = 1;
const auto offset = gwv.GetOffset();
const auto center = gwv.GetSize() / 2.f;
const auto zoomFactor = gwv.GetZoomFactor();
const auto& world = gwv.GetWorld();
const auto worldSize = world.GetSize() * DrawPoint(TR_W, TR_H);
auto minDistance = std::numeric_limits<float>::max();
PickedMovableObject pmo;
world.CheckPointsInRadius(
mapPt, PickRadius,
[&](MapPoint curPt, unsigned) {
if(gwv.GetViewer().GetVisibility(curPt) != Visibility::Visible)
return CheckPointsContinue;
DrawPoint curDrawPt = world.GetNodePos(curPt);
if(curDrawPt.x < offset.x)
curDrawPt.x += worldSize.x;
if(curDrawPt.y < offset.y)
curDrawPt.y += worldSize.y;
curDrawPt -= offset;
for(const noBase& obj : world.GetFigures(curPt))
{
const auto* movable = dynamic_cast<const noMovable*>(&obj);
if(!movable)
continue;
DrawPoint objDrawPt = curDrawPt;
if(movable->IsMoving())
objDrawPt += movable->CalcWalkingRelative();
objDrawPt = DrawPoint((objDrawPt - center) * zoomFactor + center);
// DEBUG REMOVE BEFORE MERGE
dskGameInterface::SetDebugPoint(i++, objDrawPt, 8, 4, MakeColor(255, 255, 0, 255));
auto diff = Point<float>(objDrawPt - drawPt);
float distance = std::sqrt(diff.x * diff.x + diff.y * diff.y);
if(distance < minDistance)
{
pmo.id_ = movable->GetObjId();
pmo.mapPt_ = curPt;
pmo.drawPt_ = objDrawPt; // TODO Do we need the unwrapped point here or was this always wrong?
minDistance = distance;
}
}
return CheckPointsContinue;
},
true);
if(pmo.isValid() && expire)
pmo.expiration_.start();
return pmo;
}
PickedMovableObject PickedMovableObject::pickAtCursor(const GameWorldView& gwv, bool expire)
{
return pick(gwv, gwv.GetSelectedPt(), DrawPoint(VIDEODRIVER.GetMousePos()), expire);
}
PickedMovableObject PickedMovableObject::pickAtViewCenter(const GameWorldView& gwv, bool expire)
{
const auto centerMapPt = gwv.GetWorld().MakeMapPoint((gwv.GetFirstPt() + gwv.GetLastPt()) / 2);
const auto centerDrawPt = DrawPoint(gwv.GetSize() / 2u);
return pick(gwv, centerMapPt, centerDrawPt, expire);
}
bool PickedMovableObject::isValid() const
{
return id_ != 0 && (!expiration_.isRunning() || expiration_.getElapsed() < PickedObjectExpiration);
}
void PickedMovableObject::cancelExpiration()
{
expiration_.stop();
}
void PickedMovableObject::invalidate()
{
id_ = 0;
}
bool PickedMovableObject::track(const GameWorldView& gwv)
{
if(!isValid())
return false;
const auto& world = gwv.GetWorld();
const auto success = world.CheckPointsInRadius(
mapPt_, TrackRadius,
[&](MapPoint curPt, unsigned) {
if(gwv.GetViewer().GetVisibility(curPt) != Visibility::Visible)
return CheckPointsContinue;
for(const noBase& obj : world.GetFigures(curPt))
{
if(obj.GetObjId() != id_)
continue;
const auto& movable = dynamic_cast<const noMovable&>(obj);
mapPt_ = curPt;
drawPt_ = world.GetNodePos(curPt);
if(movable.IsMoving())
drawPt_ += movable.CalcWalkingRelative();
return CheckPointsBreak;
}
return CheckPointsContinue;
},
true);
if(!success)
invalidate();
return success;
}
bool PickedMovableObject::track(GameWorldView& gwv, bool moveTo)
{
const auto success = track(gwv);
if(success && moveTo)
gwv.MoveTo(drawPt_ - gwv.GetSize() / 2u);
return success;
}