Skip to content

Commit 5bf9ec5

Browse files
authored
Merge pull request #47 from cortex-command-community/moredislodgepixel
Added line, circle and box variants of DislodgePixel to SceneMan
2 parents 6801348 + 5a61854 commit 5bf9ec5

File tree

4 files changed

+256
-1
lines changed

4 files changed

+256
-1
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
126126

127127
- Exposed `FrameMan` properties `ScreenCount` and `ResolutionMultiplier` to Lua (R).
128128

129+
- New `SceneMan` Lua functions:
130+
`DislodgePixelCircle(Vector centre, float radius, bool deletePixels)`, which calls `DislodgePixel()` on all pixels in a given circle, returns them as an iterable list. The bool is an optional argument to delete all found pixels immediately; defaults to `false`.
131+
`DislodgePixelRing(Vector centre, float innerRadius, float outerRadius, bool deletePixels)`, same as above but additionally ignores pixels within the inner radius.
132+
`DislodgePixelBox(Vector upperLeftCorner, Vector lowerRightCorner, bool deletePixels)`, similar to above, but in a rectangular area defined by upper left- and lower right corners.
133+
`DislodgePixelLine(Vector startPos, Vector ray, int skip, bool deletePixels)`, calls `DislodgePixel()` on all pixels in a line, like above. Similar in function to a ray cast, so pixels can be skipped.
134+
129135
- New `SceneMan` Lua function `CastTerrainPenetrationRay(Vector start, Vector ray, Vector endPos, int strengthLimit, int skip)`, which adds up the material strength of the terrain pixels encountered along the way, and stops when the accumulated value meets or exceeds `strengthLimit`. `endPos` is filled out with the ending position of the ray, returns `true` or `false` depending on whether the ray was stopped early or not.
130136

131137
</details>
@@ -170,6 +176,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
170176

171177
- The `SceneObject` property `IsBuyable` has been renamed to `Buyable`.
172178

179+
- `SceneMan` Lua function `DislodgePixel()` now optionally accepts a third boolean argument to delete the found pixel immediately. Format is `DislodgePixel(int posX, int posY, bool deletePixel)`. `DislodgePixel()` now also automatically accounts for scene wrapping.
180+
173181
</details>
174182

175183
<details><summary><b>Fixed</b></summary>

Source/Lua/LuaBindingsManagers.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,16 @@ LuaBindingRegisterFunctionDefinitionForType(ManagerLuaBindings, SceneMan) {
331331
.def("ObscuredPoint", (bool(SceneMan::*)(int, int, int)) & SceneMan::ObscuredPoint)
332332
.def("AddSceneObject", &SceneMan::AddSceneObject, luabind::adopt(_2))
333333
.def("CheckAndRemoveOrphans", (int(SceneMan::*)(int, int, int, int, bool)) & SceneMan::RemoveOrphans)
334-
.def("DislodgePixel", &SceneMan::DislodgePixel);
334+
.def("DislodgePixel", &SceneMan::DislodgePixel)
335+
.def("DislodgePixel", &SceneMan::DislodgePixelBool)
336+
.def("DislodgePixelLine", (const std::vector<MovableObject*>* (SceneMan::*)(const Vector& start, const Vector& ray, int skip, bool deletePixels) const) & SceneMan::DislodgePixelLine, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator)
337+
.def("DislodgePixelLine", (const std::vector<MovableObject*>* (SceneMan::*)(const Vector& start, const Vector& ray, int skip) const) & SceneMan::DislodgePixelLineNoBool, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator)
338+
.def("DislodgePixelCircle", (const std::vector<MovableObject*>* (SceneMan::*)(const Vector& centre, float radius, bool deletePixels) const) & SceneMan::DislodgePixelCircle, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator)
339+
.def("DislodgePixelCircle", (const std::vector<MovableObject*>* (SceneMan::*)(const Vector& centre, float radius) const) & SceneMan::DislodgePixelCircleNoBool, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator)
340+
.def("DislodgePixelBox", (const std::vector<MovableObject*>* (SceneMan::*)(const Vector& upperLeftCorner, const Vector& lowerRightCorner, bool deletePixels) const) & SceneMan::DislodgePixelBox, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator)
341+
.def("DislodgePixelBox", (const std::vector<MovableObject*>* (SceneMan::*)(const Vector& upperLeftCorner, const Vector& lowerRightCorner) const) & SceneMan::DislodgePixelBoxNoBool, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator)
342+
.def("DislodgePixelRing", (const std::vector<MovableObject*>* (SceneMan::*)(const Vector& centre, float innerRadius, float outerRadius, bool deletePixels) const) & SceneMan::DislodgePixelRing, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator)
343+
.def("DislodgePixelRing", (const std::vector<MovableObject*>* (SceneMan::*)(const Vector& centre, float innerRadius, float outerRadius) const) & SceneMan::DislodgePixelRingNoBool, luabind::adopt(luabind::return_value) + luabind::return_stl_iterator);
335344
}
336345

337346
LuaBindingRegisterFunctionDefinitionForType(ManagerLuaBindings, CameraMan) {

Source/Managers/SceneMan.cpp

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,7 @@ bool SceneMan::TryPenetrate(int posX,
893893
}
894894

895895
MovableObject* SceneMan::DislodgePixel(int posX, int posY) {
896+
WrapPosition(posX, posY);
896897
int materialID = getpixel(m_pCurrentScene->GetTerrain()->GetMaterialBitmap(), posX, posY);
897898
if (materialID <= MaterialColorKeys::g_MaterialAir) {
898899
return nullptr;
@@ -922,6 +923,180 @@ MovableObject* SceneMan::DislodgePixel(int posX, int posY) {
922923
return pixelMO;
923924
}
924925

926+
// Bool variant to avoid changing the original
927+
MovableObject* SceneMan::DislodgePixelBool(int posX, int posY, bool deletePixel) {
928+
MovableObject* pixelMO = DislodgePixel(posX, posY);
929+
if (pixelMO) {
930+
pixelMO->SetToDelete(deletePixel);
931+
}
932+
return pixelMO;
933+
}
934+
935+
std::vector<MovableObject*>* SceneMan::DislodgePixelCircle(const Vector& centre, float radius, bool deletePixels) {
936+
std::vector<MovableObject*>* pixelList = new std::vector<MovableObject*>();
937+
int limit = static_cast<int>(radius) * 2;
938+
for (int x = 0; x <= limit; x++) {
939+
for (int y = 0; y <= limit; y++) {
940+
Vector checkPos = Vector(static_cast<float>(x) - radius, static_cast<float>(y) - radius) + centre;
941+
Vector distance = ShortestDistance(centre, checkPos, true);
942+
943+
if (distance.MagnitudeIsGreaterThan(radius) && y > limit / 2) {
944+
break;
945+
}
946+
947+
if (!distance.MagnitudeIsGreaterThan(radius)) {
948+
MovableObject* px = DislodgePixelBool(checkPos.m_X, checkPos.m_Y, deletePixels);
949+
if (px) {
950+
pixelList->push_back(px);
951+
}
952+
}
953+
}
954+
}
955+
956+
return pixelList;
957+
}
958+
959+
std::vector<MovableObject*>* SceneMan::DislodgePixelCircleNoBool(const Vector& centre, float radius) {
960+
return DislodgePixelCircle(centre, radius, false);
961+
}
962+
963+
std::vector<MovableObject*>* SceneMan::DislodgePixelRing(const Vector& centre, float innerRadius, float outerRadius, bool deletePixels) {
964+
// Account for users inputting radii in the wrong order
965+
if (outerRadius < innerRadius) {
966+
std::swap(outerRadius, innerRadius);
967+
}
968+
969+
std::vector<MovableObject*>* pixelList = new std::vector<MovableObject*>();
970+
int limit = static_cast<int>(outerRadius) * 2;
971+
for (int x = 0; x <= limit; x++) {
972+
for (int y = 0; y <= limit; y++) {
973+
Vector checkPos = Vector(static_cast<float>(x) - outerRadius, static_cast<float>(y) - outerRadius) + centre;
974+
Vector distance = ShortestDistance(centre, checkPos, true);
975+
976+
if (distance.MagnitudeIsLessThan(innerRadius) && y < limit - y) {
977+
y = limit - y;
978+
continue;
979+
}
980+
981+
if (distance.MagnitudeIsGreaterThan(outerRadius) && y > limit / 2) {
982+
break;
983+
}
984+
985+
if (!distance.MagnitudeIsGreaterThan(outerRadius) && !distance.MagnitudeIsLessThan(innerRadius)) {
986+
MovableObject* px = DislodgePixelBool(checkPos.m_X, checkPos.m_Y, deletePixels);
987+
if (px) {
988+
pixelList->push_back(px);
989+
}
990+
}
991+
}
992+
}
993+
994+
return pixelList;
995+
}
996+
997+
std::vector<MovableObject*>* SceneMan::DislodgePixelRingNoBool(const Vector& centre, float innerRadius, float outerRadius) {
998+
return DislodgePixelRing(centre, innerRadius, outerRadius, false);
999+
}
1000+
1001+
std::vector<MovableObject*>* SceneMan::DislodgePixelBox(const Vector& upperLeftCorner, const Vector& lowerRightCorner, bool deletePixels) {
1002+
std::vector<MovableObject*>* pixelList = new std::vector<MovableObject*>();
1003+
1004+
// Make sure it works even if people input corners in the wrong order
1005+
Vector start = Vector(std::min(upperLeftCorner.m_X, lowerRightCorner.m_X), std::min(upperLeftCorner.m_Y, lowerRightCorner.m_Y));
1006+
Vector end = Vector(std::max(upperLeftCorner.m_X, lowerRightCorner.m_X), std::max(upperLeftCorner.m_Y, lowerRightCorner.m_Y));
1007+
1008+
float width = end.m_X - start.m_X;
1009+
float height = end.m_Y - start.m_Y;
1010+
for (int x = 0; x <= static_cast<int>(width) * 2; x++) {
1011+
for (int y = 0; y <= static_cast<int>(height) * 2; y++) {
1012+
Vector checkPos = start + Vector(static_cast<float>(x), static_cast<float>(y));
1013+
MovableObject* px = DislodgePixelBool(checkPos.m_X, checkPos.m_Y, deletePixels);
1014+
if (px) {
1015+
pixelList->push_back(px);
1016+
}
1017+
}
1018+
}
1019+
1020+
return pixelList;
1021+
}
1022+
1023+
std::vector<MovableObject*>* SceneMan::DislodgePixelBoxNoBool(const Vector& upperLeftCorner, const Vector& lowerRightCorner) {
1024+
return DislodgePixelBox(upperLeftCorner, lowerRightCorner, false);
1025+
}
1026+
1027+
std::vector<MovableObject*>* SceneMan::DislodgePixelLine(const Vector& start, const Vector& ray, int skip, bool deletePixels) {
1028+
std::vector<MovableObject*>* pixelList = new std::vector<MovableObject*>();
1029+
int error, dom, sub, domSteps, skipped = skip;
1030+
int intPos[2], delta[2], delta2[2], increment[2];
1031+
1032+
intPos[X] = std::floor(start.m_X);
1033+
intPos[Y] = std::floor(start.m_Y);
1034+
delta[X] = std::floor(start.m_X + ray.m_X) - intPos[X];
1035+
delta[Y] = std::floor(start.m_Y + ray.m_Y) - intPos[Y];
1036+
1037+
/////////////////////////////////////////////////////
1038+
// Bresenham's line drawing algorithm preparation
1039+
1040+
if (delta[X] < 0) {
1041+
increment[X] = -1;
1042+
delta[X] = -delta[X];
1043+
} else
1044+
increment[X] = 1;
1045+
1046+
if (delta[Y] < 0) {
1047+
increment[Y] = -1;
1048+
delta[Y] = -delta[Y];
1049+
} else
1050+
increment[Y] = 1;
1051+
1052+
// Scale by 2, for better accuracy of the error at the first pixel
1053+
delta2[X] = delta[X] << 1;
1054+
delta2[Y] = delta[Y] << 1;
1055+
1056+
// If X is dominant, Y is submissive, and vice versa.
1057+
if (delta[X] > delta[Y]) {
1058+
dom = X;
1059+
sub = Y;
1060+
} else {
1061+
dom = Y;
1062+
sub = X;
1063+
}
1064+
1065+
error = delta2[sub] - delta[dom];
1066+
1067+
/////////////////////////////////////////////////////
1068+
// Bresenham's line drawing algorithm execution
1069+
1070+
for (domSteps = 0; domSteps < delta[dom]; ++domSteps) {
1071+
intPos[dom] += increment[dom];
1072+
if (error >= 0) {
1073+
intPos[sub] += increment[sub];
1074+
error -= delta2[dom];
1075+
}
1076+
error += delta2[sub];
1077+
1078+
// Only check pixel if we're not due to skip any, or if this is the last pixel
1079+
if (++skipped > skip || domSteps + 1 == delta[dom]) {
1080+
// Scene wrapping
1081+
g_SceneMan.WrapPosition(intPos[X], intPos[Y]);
1082+
1083+
MovableObject* px = DislodgePixelBool(intPos[X], intPos[Y], deletePixels);
1084+
if (px) {
1085+
pixelList->push_back(px);
1086+
}
1087+
1088+
// Reset skip counter
1089+
skipped = 0;
1090+
}
1091+
}
1092+
1093+
return pixelList;
1094+
}
1095+
1096+
std::vector<MovableObject*>* SceneMan::DislodgePixelLineNoBool(const Vector& start, const Vector& ray, int skip) {
1097+
return DislodgePixelLine(start, ray, skip, false);
1098+
}
1099+
9251100
void SceneMan::MakeAllUnseen(Vector pixelSize, const int team) {
9261101
RTEAssert(m_pCurrentScene, "Messing with scene before the scene exists!");
9271102
if (team < Activity::TeamOne || team >= Activity::MaxTeamCount)

Source/Managers/SceneMan.h

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,69 @@ namespace RTE {
403403
/// @return The newly dislodged pixel, if one was found.
404404
MovableObject* DislodgePixel(int posX, int posY);
405405

406+
/// Removes a pixel from the terrain and adds it to MovableMan.
407+
/// @param posX The X coordinate of the terrain pixel.
408+
/// @param posX The Y coordinate of the terrain pixel.
409+
/// @param deletePixel Whether or not to immediately mark the pixel for deletion.
410+
/// @return The newly dislodged pixel, if one was found.
411+
MovableObject* DislodgePixelBool(int posX, int posY, bool deletePixel);
412+
413+
/// Removes a circle of pixels from the terrain and adds them to MovableMan.
414+
/// @param centre The vector position of the centre of the circle.
415+
/// @param radius The radius of the circle of pixels to remove.
416+
/// @param deletePixels Whether or not to immediately mark all found pixels for deletion.
417+
/// @return A list of the removed pixels, if any.
418+
std::vector<MovableObject*>* DislodgePixelCircle(const Vector& centre, float radius, bool deletePixels);
419+
420+
/// Removes a circle of pixels from the terrain and adds them to MovableMan.
421+
/// @param centre The vector position of the centre of the circle.
422+
/// @param radius The radius of the circle of pixels to remove.
423+
/// @return A list of the removed pixels, if any.
424+
std::vector<MovableObject*>* DislodgePixelCircleNoBool(const Vector& centre, float radius);
425+
426+
/// Removes a ring of pixels from the terrain and adds them to MovableMan.
427+
/// @param centre The vector position of the centre of the ring.
428+
/// @param innerRadius The inner radius of the ring of pixels to remove.
429+
/// @param outerRadius The outer radius of the ring of pixels to remove.
430+
/// @param deletePixels Whether or not to immediately mark all found pixels for deletion.
431+
/// @return A list of the removed pixels, if any.
432+
std::vector<MovableObject*>* DislodgePixelRing(const Vector& centre, float innerRadius, float outerRadius, bool deletePixels);
433+
434+
/// Removes a ring of pixels from the terrain and adds them to MovableMan.
435+
/// @param centre The vector position of the centre of the ring.
436+
/// @param innerRadius The inner radius of the ring of pixels to remove.
437+
/// @param outerRadius The outer radius of the ring of pixels to remove.
438+
/// @return A list of the removed pixels, if any.
439+
std::vector<MovableObject*>* DislodgePixelRingNoBool(const Vector& centre, float innerRadius, float outerRadius);
440+
441+
/// Removes a box of pixels from the terrain and adds them to MovableMan.
442+
/// @param upperLeftCorner The vector position of the upper left corner of the box.
443+
/// @param lowerRightCorner The vector position of the lower right corner of the box.
444+
/// @param deletePixels Whether or not to immediately mark all found pixels for deletion.
445+
/// @return A list of the removed pixels, if any.
446+
std::vector<MovableObject*>* DislodgePixelBox(const Vector& upperLeftCorner, const Vector& lowerRightCorner, bool deletePixels);
447+
448+
/// Removes a box of pixels from the terrain and adds them to MovableMan.
449+
/// @param upperLeftCorner The vector position of the upper left corner of the box.
450+
/// @param lowerRightCorner The vector position of the lower right corner of the box.
451+
/// @return A list of the removed pixels, if any.
452+
std::vector<MovableObject*>* DislodgePixelBoxNoBool(const Vector& upperLeftCorner, const Vector& lowerRightCorner);
453+
454+
/// Removes a line of pixels from the terrain and adds them to MovableMan.
455+
/// @param start The starting position.
456+
/// @param ray The vector to trace along.
457+
/// @param skip For every pixel checked along the line, how many to skip between them.
458+
/// @param deletePixels Whether or not to immediately mark all found pixels for deletion.
459+
/// @return A list of the removed pixels, if any.
460+
std::vector<MovableObject*>* DislodgePixelLine(const Vector& start, const Vector& ray, int skip, bool deletePixels);
461+
462+
/// Removes a line of pixels from the terrain and adds them to MovableMan.
463+
/// @param start The starting position.
464+
/// @param ray The vector to trace along.
465+
/// @param skip For every pixel checked along the line, how many to skip between them.
466+
/// @return A list of the removed pixels, if any.
467+
std::vector<MovableObject*>* DislodgePixelLineNoBool(const Vector& start, const Vector& ray, int skip);
468+
406469
/// Sets one team's view of the scene to be unseen, using a generated map
407470
/// of a specific resolution chunkiness.
408471
/// @param pixelSize The dimensions of the pixels that should make up the unseen layer.

0 commit comments

Comments
 (0)