Skip to content

Commit

Permalink
Enforce specific play area regardless of screen resolution (diasurgic…
Browse files Browse the repository at this point in the history
…al#10)

* Enforce play within restricted screen area

* Change radius to 15
  • Loading branch information
kphoenix137 committed Apr 6, 2024
1 parent 0bd2d0b commit 5422e58
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 2 deletions.
23 changes: 23 additions & 0 deletions Source/cursor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,8 @@ bool TrySelectItem(bool flipflag, int mx, int my)

bool TrySelectPixelBased(Point tile)
{
if (!IsScreenPosLegalPlayArea(MousePosition.x, MousePosition.y) && leveltype != DTYPE_TOWN)
return false;
if (demo::IsRunning() || demo::IsRecording() || HeadlessMode) {
// Recorded demos can run headless, but headless mode doesn't support loading sprites that are needed for pixel perfect selection
// => Ensure demos are always compatible
Expand Down Expand Up @@ -627,6 +629,25 @@ void CheckRportal()
}
}

bool IsScreenPosLegalPlayArea(int x, int y)
{
int panelHeight = 128;
Point centerScreen { GetScreenWidth() / 2, (GetScreenHeight() - panelHeight) / 2 };
int screenHeight = 600;
int screenWidth = screenHeight * 16 / 9;
Point boundingBox { screenWidth, screenHeight };
boundingBox.y -= panelHeight;

// Calculate the bounds of the original game resolution centered on the screen
int leftBound = centerScreen.x - (boundingBox.x / 2);
int rightBound = centerScreen.x + (boundingBox.x / 2);
int topBound = centerScreen.y - (boundingBox.y / 2);
int bottomBound = centerScreen.y + (boundingBox.y / 2);

// Check if the cursor is outside the bounding box
return !(x < leftBound || x > rightBound || y < topBound || y > bottomBound);
}

void CheckCursMove()
{
if (IsItemLabelHighlighted())
Expand Down Expand Up @@ -795,6 +816,8 @@ void CheckCursMove()
return;

if (leveltype != DTYPE_TOWN) {
if (!IsScreenPosLegalPlayArea(MousePosition.x, MousePosition.y))
return;
// Never select a monster if a target-player-only spell is selected
if (IsNoneOf(pcurs, CURSOR_HEALOTHER, CURSOR_RESURRECT)) {
if (pcurstemp != -1 && TrySelectMonster(flipflag, currentTile, [](const Monster &monster) {
Expand Down
1 change: 1 addition & 0 deletions Source/cursor.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ void NewCursor(int cursId);
void InitLevelCursor();
void CheckRportal();
void CheckTown();
bool IsScreenPosLegalPlayArea(int x, int y);
void CheckCursMove();

void DrawSoftwareCursor(const Surface &out, Point position, int cursId);
Expand Down
3 changes: 3 additions & 0 deletions Source/diablo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2606,6 +2606,9 @@ int DiabloMain(int argc, char **argv)

bool TryIconCurs()
{
if (!IsScreenPosLegalPlayArea(MousePosition.x, MousePosition.y))
return false;

if (pcurs == CURSOR_RESURRECT) {
if (PlayerUnderCursor != nullptr) {
NetSendCmdParam1(true, CMD_RESURRECT, PlayerUnderCursor->getId());
Expand Down
67 changes: 65 additions & 2 deletions Source/engine/render/scrollrt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,69 @@ void DrawCell(const Surface &out, Point tilePosition, Point targetBufferPosition
}
}

int DetermineRotationCount(int dx, int dy)
{
if (dx > 0 && dy >= 0) return 0; // +x, +y and +x axis
if (dx <= 0 && dy > 0) return 1; // -x, +y and +y axis
if (dx < 0 && dy <= 0) return 2; // -x, -y and -x axis
if (dx >= 0 && dy < 0) return 3; // +x, -y and -y axis
return 0;
}

void ApplyRotationAdjustment(DisplacementOf<int8_t> &offset, int rotationCount)
{
for (int i = 0; i < rotationCount; i++) {
// Apply rotation adjustment logic similar to RotateRadius
int temp = offset.deltaX;
offset.deltaX = offset.deltaY;
offset.deltaY = 7 - temp;
}
}

uint8_t CalculateDimming(Point tilePosition)
{
Point playerLightPosition = Lights[MyPlayer->lightId].position.tile;
DisplacementOf<int8_t> playerLightOffset = Lights[MyPlayer->lightId].position.offset;
int radius = 15; // Should allow full effect from +Light Radius items, but harshly dims the edges. No noticeable change in vanilla settings.
int originalLight = dLight[tilePosition.x][tilePosition.y];

// Adjust player's light offset based on movement
if (playerLightOffset.deltaX < 0) {
playerLightOffset.deltaX += 8;
playerLightPosition.x -= 1;
}
if (playerLightOffset.deltaY < 0) {
playerLightOffset.deltaY += 8;
playerLightPosition.y -= 1;
}

// Calculate the delta between the tile position and the player's light position
int dx = tilePosition.x - playerLightPosition.x;
int dy = tilePosition.y - playerLightPosition.y;

// Determine how many times to rotate based on dx and dy
int rotationCount = DetermineRotationCount(dx, dy);

// Apply the rotation adjustment to playerLightOffset
ApplyRotationAdjustment(playerLightOffset, rotationCount);

// Ensure deltas are within the bounds of the LightConeInterpolations2 array
dx = std::clamp(dx, -31, 31);
dy = std::clamp(dy, -31, 31);

// Use the absolute values to find the linear distance in the interpolation array
int linearDistance = LightConeInterpolations2[std::abs(playerLightOffset.deltaX)][std::abs(playerLightOffset.deltaY)][std::abs(dx)][std::abs(dy)];

// Ensure linearDistance is within the bounds of the LightFalloffs2 array
linearDistance = std::min(linearDistance, 255);

// Determine the dimming level using LightFalloffs2
uint8_t dimmingLevel = LightFalloffs2[radius][linearDistance];

// Apply dimming to the original light level of the tile
return std::clamp(static_cast<int>(originalLight) + dimmingLevel, 0, 15);
}

/**
* @brief Render a floor tile.
* @param out Target buffer
Expand All @@ -578,7 +641,7 @@ void DrawCell(const Surface &out, Point tilePosition, Point targetBufferPosition
*/
void DrawFloor(const Surface &out, Point tilePosition, Point targetBufferPosition)
{
LightTableIndex = dLight[tilePosition.x][tilePosition.y];
LightTableIndex = CalculateDimming(tilePosition);

const uint8_t *tbl = LightTables[LightTableIndex].data();
#ifdef _DEBUG
Expand Down Expand Up @@ -704,7 +767,7 @@ void DrawPlayerHelper(const Surface &out, const Player &player, Point tilePositi
void DrawDungeon(const Surface &out, Point tilePosition, Point targetBufferPosition)
{
assert(InDungeonBounds(tilePosition));
LightTableIndex = dLight[tilePosition.x][tilePosition.y];
LightTableIndex = CalculateDimming(tilePosition);

DrawCell(out, tilePosition, targetBufferPosition);

Expand Down
45 changes: 45 additions & 0 deletions Source/lighting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ std::array<uint8_t, 256> PauseTable;
bool DisableLighting;
#endif
bool UpdateLighting;
constexpr size_t NumLightRadiuses2 = 32;
uint8_t LightFalloffs2[NumLightRadiuses2][128 * 2] = {};
uint8_t LightConeInterpolations2[8][8][32][32] = {};

namespace {

Expand Down Expand Up @@ -318,6 +321,47 @@ void DoVision(Point position, uint8_t radius, MapExplorationType doAutomap, bool
}
}

void MakeCustomLightTable()
{
const float maxDarkness = 15;
const float maxBrightness = 0;
for (unsigned radius = 0; radius < NumLightRadiuses2; radius++) {
const unsigned maxDistance = (radius + 1) * 8; // Compute the maximum effective distance for this radius

// Define the threshold for starting the falloff (75% of the way)
const unsigned falloffStartDistance = static_cast<unsigned>(maxDistance * 0.50);

for (unsigned distance = 0; distance < 256; distance++) {
if (distance > maxDistance) {
// Beyond the effective range of the light, set to maximum darkness
LightFalloffs2[radius][distance] = static_cast<uint8_t>(maxDarkness);
} else if (distance <= falloffStartDistance) {
// Within the 75% range where there's no falloff
LightFalloffs2[radius][distance] = static_cast<uint8_t>(maxBrightness);
} else {
// Calculate a smoother falloff for the last 25%
float factor = static_cast<float>(distance - falloffStartDistance) / (static_cast<float>(maxDistance) - static_cast<float>(falloffStartDistance));
// Directly scale the darkness based on distance
float scaled = maxDarkness * factor;
LightFalloffs2[radius][distance] = static_cast<uint8_t>(std::round(scaled));
}
}
}

// Generate the light cone interpolations
for (int offsetY = 0; offsetY < 8; offsetY++) {
for (int offsetX = 0; offsetX < 8; offsetX++) {
for (int y = 0; y < 32; y++) {
for (int x = 0; x < 32; x++) {
int a = (8 * x - offsetY);
int b = (8 * y - offsetX);
LightConeInterpolations2[offsetX][offsetY][x][y] = static_cast<uint8_t>(sqrt(a * a + b * b));
}
}
}
}
}

void MakeLightTable()
{
// Generate 16 gradually darker translation tables for doing lighting
Expand Down Expand Up @@ -408,6 +452,7 @@ void MakeLightTable()
}
}
}
MakeCustomLightTable();
}

#ifdef _DEBUG
Expand Down
2 changes: 2 additions & 0 deletions Source/lighting.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ extern std::array<uint8_t, 256> PauseTable;
extern bool DisableLighting;
#endif
extern bool UpdateLighting;
extern uint8_t LightFalloffs2[32][128 * 2];
extern uint8_t LightConeInterpolations2[8][8][32][32];

void DoUnLight(Point position, uint8_t radius);
void DoLighting(Point position, uint8_t radius, DisplacementOf<int8_t> offset);
Expand Down
5 changes: 5 additions & 0 deletions Source/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3121,6 +3121,11 @@ void CheckPlrSpell(bool isShiftHeld, SpellID spellID, SpellType spellType)
assert(MyPlayer != nullptr);
Player &myPlayer = *MyPlayer;

if (GetSpellData(spellID).isTargeted()) {
if (!IsScreenPosLegalPlayArea(MousePosition.x, MousePosition.y))
return;
}

if (!IsValidSpell(spellID)) {
myPlayer.Say(HeroSpeech::IDontHaveASpellReady);
return;
Expand Down

0 comments on commit 5422e58

Please sign in to comment.