1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2
3 #include <assert.h>
4
5 #include "GroundBlockingObjectMap.h"
6
7 #include "GlobalSynced.h"
8 #include "GlobalConstants.h"
9 #include "Sim/Objects/SolidObject.h"
10 #include "Sim/Objects/SolidObjectDef.h"
11 #include "Sim/Path/IPathManager.h"
12 #include "System/creg/STL_Map.h"
13
14 CGroundBlockingObjectMap* groundBlockingObjectMap;
15
16 CR_BIND(CGroundBlockingObjectMap, (1))
17 CR_REG_METADATA(CGroundBlockingObjectMap, (
18 CR_MEMBER(groundBlockingMap)
19 ))
20
21
22
GetObjectID(CSolidObject * obj)23 inline static const int GetObjectID(CSolidObject* obj)
24 {
25 const int id = obj->GetBlockingMapID();
26 // object should always be a derived type
27 assert(id != -1);
28 return id;
29 }
30
31
AddGroundBlockingObject(CSolidObject * object)32 void CGroundBlockingObjectMap::AddGroundBlockingObject(CSolidObject* object)
33 {
34 if (object->blockMap != NULL) {
35 // if object has a yardmap, add it to map selectively
36 // (checking the specific state of each yardmap cell)
37 AddGroundBlockingObject(object, YARDMAP_BLOCKED);
38 return;
39 }
40
41 const int objID = GetObjectID(object);
42
43 object->SetPhysicalStateBit(CSolidObject::PSTATE_BIT_BLOCKING);
44 object->mapPos = object->GetMapPos();
45 object->groundBlockPos = object->pos;
46
47 const int bx = object->mapPos.x, sx = object->xsize;
48 const int bz = object->mapPos.y, sz = object->zsize;
49 const int minXSqr = bx, maxXSqr = bx + sx;
50 const int minZSqr = bz, maxZSqr = bz + sz;
51
52 for (int zSqr = minZSqr; zSqr < maxZSqr; zSqr++) {
53 for (int xSqr = minXSqr; xSqr < maxXSqr; xSqr++) {
54 BlockingMapCell& cell = groundBlockingMap[xSqr + zSqr * gs->mapx];
55 cell[objID] = object;
56 }
57 }
58
59 // FIXME: needs dependency injection (observer pattern?)
60 if (object->moveDef == NULL && pathManager != NULL) {
61 pathManager->TerrainChange(minXSqr, minZSqr, maxXSqr, maxZSqr, TERRAINCHANGE_OBJECT_INSERTED);
62 }
63 }
64
AddGroundBlockingObject(CSolidObject * object,const YardMapStatus & mask)65 void CGroundBlockingObjectMap::AddGroundBlockingObject(CSolidObject* object, const YardMapStatus& mask)
66 {
67 const int objID = GetObjectID(object);
68
69 object->SetPhysicalStateBit(CSolidObject::PSTATE_BIT_BLOCKING);
70 object->mapPos = object->GetMapPos();
71 object->groundBlockPos = object->pos;
72
73 const int bx = object->mapPos.x, sx = object->xsize;
74 const int bz = object->mapPos.y, sz = object->zsize;
75 const int minXSqr = bx, maxXSqr = bx + sx;
76 const int minZSqr = bz, maxZSqr = bz + sz;
77
78 for (int z = minZSqr; z < maxZSqr; z++) {
79 for (int x = minXSqr; x < maxXSqr; x++) {
80 // unit yardmaps always contain sx=UnitDef::xsize * sz=UnitDef::zsize
81 // cells (the unit->moveDef footprint can have different dimensions)
82 const float3 testPos = float3(x, 0.0f, z) * SQUARE_SIZE;
83
84 if (object->GetGroundBlockingMaskAtPos(testPos) & mask) {
85 BlockingMapCell& cell = groundBlockingMap[x + (z) * gs->mapx];
86 cell[objID] = object;
87 }
88 }
89 }
90
91 // FIXME: needs dependency injection (observer pattern?)
92 if (object->moveDef == NULL && pathManager != NULL) {
93 pathManager->TerrainChange(minXSqr, minZSqr, maxXSqr, maxZSqr, TERRAINCHANGE_OBJECT_INSERTED_YM);
94 }
95 }
96
97
RemoveGroundBlockingObject(CSolidObject * object)98 void CGroundBlockingObjectMap::RemoveGroundBlockingObject(CSolidObject* object)
99 {
100 const int objID = GetObjectID(object);
101
102 const int bx = object->mapPos.x;
103 const int bz = object->mapPos.y;
104 const int sx = object->xsize;
105 const int sz = object->zsize;
106
107 object->ClearPhysicalStateBit(CSolidObject::PSTATE_BIT_BLOCKING);
108
109 for (int z = bz; z < bz + sz; ++z) {
110 for (int x = bx; x < bx + sx; ++x) {
111 const int idx = x + z * gs->mapx;
112
113 BlockingMapCell& cell = groundBlockingMap[idx];
114 cell.erase(objID);
115 }
116 }
117
118 // FIXME: needs dependency injection (observer pattern?)
119 if (object->moveDef == NULL && pathManager != NULL) {
120 pathManager->TerrainChange(bx, bz, bx + sx, bz + sz, TERRAINCHANGE_OBJECT_DELETED);
121 }
122 }
123
124
125 /**
126 * Checks if a ground-square is blocked.
127 * If it's not blocked (empty), then NULL is returned. Otherwise, a
128 * pointer to the top-most / bottom-most blocking object is returned.
129 */
GroundBlockedUnsafe(int mapSquare) const130 CSolidObject* CGroundBlockingObjectMap::GroundBlockedUnsafe(int mapSquare) const {
131 const BlockingMapCell& cell = groundBlockingMap[mapSquare];
132
133 if (cell.empty())
134 return NULL;
135
136 return ((cell.begin())->second);
137 }
138
139
GroundBlocked(int x,int z) const140 CSolidObject* CGroundBlockingObjectMap::GroundBlocked(int x, int z) const {
141 if (x < 0 || x >= gs->mapx || z < 0 || z >= gs->mapy)
142 return NULL;
143
144 return GroundBlockedUnsafe(x + z * gs->mapx);
145 }
146
147
GroundBlocked(const float3 & pos) const148 CSolidObject* CGroundBlockingObjectMap::GroundBlocked(const float3& pos) const {
149 const int xSqr = int(pos.x / SQUARE_SIZE);
150 const int zSqr = int(pos.z / SQUARE_SIZE);
151 return GroundBlocked(xSqr, zSqr);
152 }
153
154
GroundBlocked(int x,int z,CSolidObject * ignoreObj) const155 bool CGroundBlockingObjectMap::GroundBlocked(int x, int z, CSolidObject* ignoreObj) const
156 {
157 if (x < 0 || x >= gs->mapx || z < 0 || z >= gs->mapy)
158 return false;
159
160 const int mapSquare = x + z * gs->mapx;
161
162 if (groundBlockingMap[mapSquare].empty())
163 return false;
164
165 const int objID = GetObjectID(ignoreObj);
166 const BlockingMapCell& cell = groundBlockingMap[mapSquare];
167
168 BlockingMapCellIt it = cell.begin();
169
170 if (it != cell.end()) {
171 if (it->first != objID) {
172 // there are other objects blocking the square
173 return true;
174 } else {
175 // ignoreObj is in the square. Check if there are other objects, too
176 return (cell.size() >= 2);
177 }
178 }
179
180 return false;
181 }
182
183
GroundBlocked(const float3 & pos,CSolidObject * ignoreObj) const184 bool CGroundBlockingObjectMap::GroundBlocked(const float3& pos, CSolidObject* ignoreObj) const
185 {
186 const int xSqr = int(pos.x / SQUARE_SIZE);
187 const int zSqr = int(pos.z / SQUARE_SIZE);
188 return GroundBlocked(xSqr, zSqr, ignoreObj);
189 }
190
191
192
193 /**
194 * Opens up a yard in a blocked area.
195 * When a factory opens up, for example.
196 */
OpenBlockingYard(CSolidObject * object)197 void CGroundBlockingObjectMap::OpenBlockingYard(CSolidObject* object) {
198 RemoveGroundBlockingObject(object);
199 AddGroundBlockingObject(object, YARDMAP_YARDFREE);
200 }
201
202 /**
203 * Closes a yard, blocking the area.
204 * When a factory closes, for example.
205 */
CloseBlockingYard(CSolidObject * object)206 void CGroundBlockingObjectMap::CloseBlockingYard(CSolidObject* object) {
207 RemoveGroundBlockingObject(object);
208 AddGroundBlockingObject(object, YARDMAP_YARDBLOCKED);
209 }
210
211
CheckYard(CSolidObject * yardUnit,const YardMapStatus & mask) const212 inline bool CGroundBlockingObjectMap::CheckYard(CSolidObject* yardUnit, const YardMapStatus& mask) const
213 {
214 for (int z = yardUnit->mapPos.y; z < yardUnit->mapPos.y + yardUnit->zsize; ++z) {
215 for (int x = yardUnit->mapPos.x; x < yardUnit->mapPos.x + yardUnit->xsize; ++x) {
216 if (yardUnit->GetGroundBlockingMaskAtPos(float3(x * SQUARE_SIZE, 0.0f, z * SQUARE_SIZE)) & mask)
217 if (GroundBlocked(x, z, yardUnit))
218 return false;
219 }
220 }
221
222 return true;
223 }
224
225
CanOpenYard(CSolidObject * yardUnit) const226 bool CGroundBlockingObjectMap::CanOpenYard(CSolidObject* yardUnit) const
227 {
228 return CheckYard(yardUnit, YARDMAP_YARDINV);
229 }
230
CanCloseYard(CSolidObject * yardUnit) const231 bool CGroundBlockingObjectMap::CanCloseYard(CSolidObject* yardUnit) const
232 {
233 return CheckYard(yardUnit, YARDMAP_YARD);
234 }
235