Skip to content

Commit

Permalink
Add tile bounds (#105)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexbatalov authored Sep 28, 2023
1 parent 1db15fe commit 2716012
Show file tree
Hide file tree
Showing 5 changed files with 269 additions and 11 deletions.
5 changes: 5 additions & 0 deletions src/game/gmouse.cc
Original file line number Diff line number Diff line change
Expand Up @@ -859,6 +859,11 @@ void gmouse_handle_event(int mouseX, int mouseY, int mouseState)
return;
}

// CE: Make sure we cannot go outside of the map.
if (!tile_point_inside_bound(mouseX, mouseY)) {
return;
}

if ((mouseState & MOUSE_EVENT_RIGHT_BUTTON_DOWN) != 0) {
if ((mouseState & MOUSE_EVENT_RIGHT_BUTTON_REPEAT) == 0) {
if (gmouse_3d_is_on()) {
Expand Down
4 changes: 4 additions & 0 deletions src/game/map.cc
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,9 @@ int map_set_elevation(int elevation)
gmouse_set_cursor(MOUSE_CURSOR_NONE);
map_elevation = elevation;

// CE: Recalculate bounds.
tile_update_bounds_base();

register_clear(obj_dude);
dude_stand(obj_dude, obj_dude->rotation, obj_dude->fid);
partyMemberSyncPosition();
Expand Down Expand Up @@ -1611,6 +1614,7 @@ static void map_scroll_refresh_game(Rect* rect)
grid_render(&rectToUpdate, map_elevation);
obj_render_pre_roof(&rectToUpdate, map_elevation);
square_render_roof(&rectToUpdate, map_elevation);
bounds_render(&rectToUpdate, map_elevation);
obj_render_post_roof(&rectToUpdate, map_elevation);
}

Expand Down
30 changes: 29 additions & 1 deletion src/game/object.cc
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,19 @@ void obj_render_pre_roof(Rect* rect, int elevation)
return;
}

// CE: Constrain rect to tile bounds so that we don't draw outside.
if (tile_inside_bound(&updatedRect) != 0) {
// Mouse hex cursor is a special case - should be shown as outline when
// out of bounds (see `obj_render_outline`).
outlineCount = 0;
if ((obj_mouse_flat->flags & OBJECT_HIDDEN) == 0
&& (obj_mouse_flat->outline & OUTLINE_TYPE_MASK) != 0
&& (obj_mouse_flat->outline & OUTLINE_DISABLED) == 0) {
outlinedObjects[outlineCount++] = obj_mouse_flat;
}
return;
}

int ambientIntensity = light_get_ambient();
int minX = updatedRect.ulx - 320;
int minY = updatedRect.uly - 240;
Expand Down Expand Up @@ -874,8 +887,23 @@ void obj_render_post_roof(Rect* rect, int elevation)
return;
}

// CE: Constrain rect to tile bounds so that we don't draw outside.
Rect constrainedRect = updatedRect;
if (tile_inside_bound(&constrainedRect) != 0) {
constrainedRect.ulx = 0;
constrainedRect.uly = 0;
constrainedRect.lrx = 0;
constrainedRect.lry = 0;
}

for (int index = 0; index < outlineCount; index++) {
obj_render_outline(outlinedObjects[index], &updatedRect);
// Mouse hex cursor is a special case - should be shown without
// constraining otherwise its hidden.
if (outlinedObjects[index] == obj_mouse_flat) {
obj_render_outline(outlinedObjects[index], &updatedRect);
} else {
obj_render_outline(outlinedObjects[index], &constrainedRect);
}
}

text_object_render(&updatedRect);
Expand Down
235 changes: 225 additions & 10 deletions src/game/tile.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "game/tile.h"

#include <assert.h>
#include <limits.h>
#include <string.h>

#define _USE_MATH_DEFINES
Expand Down Expand Up @@ -557,6 +558,9 @@ int tile_set_center(int tile, int flags)

tile_center_tile = tile;

// CE: Updates bounds screen coordinates.
tile_update_bounds_rect();

if ((flags & TILE_SET_CENTER_REFRESH_WINDOW) != 0) {
// NOTE: Uninline.
tile_refresh_display();
Expand Down Expand Up @@ -606,6 +610,7 @@ static void refresh_game(Rect* rect, int elevation)
square_render_floor(&rectToUpdate, elevation);
obj_render_pre_roof(&rectToUpdate, elevation);
square_render_roof(&rectToUpdate, elevation);
bounds_render(&rectToUpdate, elevation);
obj_render_post_roof(&rectToUpdate, elevation);
blit(&rectToUpdate);
}
Expand Down Expand Up @@ -1154,10 +1159,16 @@ void square_render_roof(Rect* rect, int elevation)
int maxX;
int maxY;

square_xy_roof(rect->ulx, rect->uly, elevation, &temp, &minY);
square_xy_roof(rect->lrx, rect->uly, elevation, &minX, &temp);
square_xy_roof(rect->ulx, rect->lry, elevation, &maxX, &temp);
square_xy_roof(rect->lrx, rect->lry, elevation, &temp, &maxY);
// CE: Constrain rect to tile bounds so that we don't draw outside.
Rect constrainedRect = *rect;
if (tile_inside_bound(&constrainedRect) != 0) {
return;
}

square_xy_roof(constrainedRect.ulx, constrainedRect.uly, elevation, &temp, &minY);
square_xy_roof(constrainedRect.lrx, constrainedRect.uly, elevation, &minX, &temp);
square_xy_roof(constrainedRect.ulx, constrainedRect.lry, elevation, &maxX, &temp);
square_xy_roof(constrainedRect.lrx, constrainedRect.lry, elevation, &temp, &maxY);

if (minX < 0) {
minX = 0;
Expand Down Expand Up @@ -1191,7 +1202,7 @@ void square_render_roof(Rect* rect, int elevation)
int screenX;
int screenY;
square_coord_roof(squareTile, &screenX, &screenY, elevation);
roof_draw(fid, screenX, screenY, rect, light);
roof_draw(fid, screenX, screenY, &constrainedRect, light);
}
}
}
Expand Down Expand Up @@ -1378,10 +1389,16 @@ void square_render_floor(Rect* rect, int elevation)
int minX;
int temp;

square_xy(rect->ulx, rect->uly, elevation, &temp, &minY);
square_xy(rect->lrx, rect->uly, elevation, &minX, &temp);
square_xy(rect->ulx, rect->lry, elevation, &maxX, &temp);
square_xy(rect->lrx, rect->lry, elevation, &temp, &maxY);
// CE: Constrain rect to tile bounds so that we don't draw outside.
Rect constrainedRect = *rect;
if (tile_inside_bound(&constrainedRect) != 0) {
return;
}

square_xy(constrainedRect.ulx, constrainedRect.uly, elevation, &temp, &minY);
square_xy(constrainedRect.lrx, constrainedRect.uly, elevation, &minX, &temp);
square_xy(constrainedRect.ulx, constrainedRect.lry, elevation, &maxX, &temp);
square_xy(constrainedRect.lrx, constrainedRect.lry, elevation, &temp, &maxY);

if (minX < 0) {
minX = 0;
Expand Down Expand Up @@ -1412,7 +1429,7 @@ void square_render_floor(Rect* rect, int elevation)
int tileScreenY;
square_coord(squareTile, &tileScreenX, &tileScreenY, elevation);
int fid = art_id(OBJ_TYPE_TILE, frmId & 0xFFF, 0, 0, 0);
floor_draw(fid, tileScreenX, tileScreenY, rect);
floor_draw(fid, tileScreenX, tileScreenY, &constrainedRect);
}
}
baseSquareTile += square_width;
Expand Down Expand Up @@ -1960,4 +1977,202 @@ int tile_scroll_to(int tile, int flags)
return rc;
}

static Rect tile_bounds_rect;
static int tile_bounds_left_off;
static int tile_bounds_top_off;
static int tile_bounds_right_off;
static int tile_bounds_bottom_off;

void tile_update_bounds_base()
{
int min_x = INT_MAX;
int min_y = INT_MAX;
int max_x = INT_MIN;
int max_y = INT_MIN;

// Determine bounding rectangle of scroll blocking objects.
for (int tile = 0; tile < grid_size; tile++) {
if (obj_scroll_blocking_at(tile, map_elevation) == 0) {
int x;
int y;
tile_coord(tile, &x, &y, map_elevation);
x += 16;
y += 8;

if (x < min_x) {
min_x = x;
}

if (y < min_y) {
min_y = y;
}

if (x > max_x) {
max_x = x;
}

if (y > max_y) {
max_y = y;
}
}
}

// Translate bounding rectangle in screen coordinates (which are relative
// to screen center tile) to offsets from reference tile (geometric center
// of the map).

int geometric_center_x;
int geometric_center_y;
tile_coord(20100, &geometric_center_x, &geometric_center_y, map_elevation);
geometric_center_x += 16;
geometric_center_y += 8;

tile_bounds_left_off = min_x - geometric_center_x;
tile_bounds_top_off = min_y - geometric_center_y;
tile_bounds_right_off = max_x - geometric_center_x;
tile_bounds_bottom_off = max_y - geometric_center_y;
}

void tile_update_bounds_rect()
{
// Translate offsets from reference tile to screen coordinates.

int geometric_center_x;
int geometric_center_y;
tile_coord(20100, &geometric_center_x, &geometric_center_y, map_elevation);
geometric_center_x += 16;
geometric_center_y += 8;

tile_bounds_rect.ulx = tile_bounds_left_off + geometric_center_x;
tile_bounds_rect.uly = tile_bounds_top_off + geometric_center_y;
tile_bounds_rect.lrx = tile_bounds_right_off + geometric_center_x;
tile_bounds_rect.lry = tile_bounds_bottom_off + geometric_center_y;

// The bounding rectangle' corners are centers from scroll blocking objects.
// Since we're dealing with hex map where each row is shifted, we have two
// sets of blockers on each edge - to handle odd and even rows. Depending
// on scroll blockers location we can either have center tile to "touch"
// one scroll blocker or be "surrounded" by three of them. This requires
// bounds to be multiple of scroll steps.

int tile_center_x;
int tile_center_y;
tile_coord(tile_center_tile, &tile_center_x, &tile_center_y, map_elevation);
tile_center_x += 16;
tile_center_y += 8;

tile_bounds_rect.ulx -= (tile_bounds_rect.ulx - tile_center_x) % 32;
tile_bounds_rect.uly -= (tile_bounds_rect.uly - tile_center_y) % 24;
tile_bounds_rect.lrx -= (tile_bounds_rect.lrx - tile_center_x) % 32;
tile_bounds_rect.lry -= (tile_bounds_rect.lry - tile_center_y) % 24;

// Scroll blocker itself cannot become center tile, so inset bounds for one
// full tile size.
tile_bounds_rect.ulx += 32;
tile_bounds_rect.uly += 16;
tile_bounds_rect.lrx -= 32;
tile_bounds_rect.lry -= 16;

// Scroll blockers where placed for 640x480 resolution, which means visible
// rect is half of than amount in each direction.
tile_bounds_rect.ulx -= 640 / 2;
tile_bounds_rect.uly -= (480 - 100) / 2;
tile_bounds_rect.lrx += 640 / 2;
tile_bounds_rect.lry += (480 - 100) / 2;

// Adjust for vertical layout.
tile_bounds_rect.uly += 8;
tile_bounds_rect.lry -= 8;

// Decrement one px to make sure rect is what engine expects it to be.
tile_bounds_rect.lrx -= 1;
tile_bounds_rect.lry -= 1;
}

int tile_inside_bound(Rect* rect)
{
return rect_inside_bound(rect, &tile_bounds_rect, rect);
}

bool tile_point_inside_bound(int x, int y)
{
return x >= tile_bounds_rect.ulx && x <= tile_bounds_rect.lrx
&& y >= tile_bounds_rect.uly && y <= tile_bounds_rect.lry;
}

void bounds_render(Rect* rect, int elevation)
{
constexpr int kShadowSize = 16;

Rect edge;

// Left.
edge.ulx = tile_bounds_rect.ulx;
edge.uly = tile_bounds_rect.uly;
edge.lrx = tile_bounds_rect.ulx + kShadowSize;
edge.lry = tile_bounds_rect.lry;
if (rect_inside_bound(&edge, rect, &edge) == 0) {
for (int y = edge.uly; y <= edge.lry; y++) {
unsigned char* dest = buf + buf_full * y + edge.ulx;
int step = edge.ulx - tile_bounds_rect.ulx;
for (int x = edge.ulx; x <= edge.lrx; x++) {
unsigned char color = *dest;
*dest++ = intensityColorTable[color][step * 128 / kShadowSize];
step++;
}
}
}

// Top.
edge.ulx = tile_bounds_rect.ulx;
edge.uly = tile_bounds_rect.uly;
edge.lrx = tile_bounds_rect.lrx;
edge.lry = tile_bounds_rect.uly + kShadowSize;
if (rect_inside_bound(&edge, rect, &edge) == 0) {
int step = edge.uly - tile_bounds_rect.uly;
for (int y = edge.uly; y <= edge.lry; y++) {
unsigned char* dest = buf + buf_full * y + edge.ulx;
for (int x = edge.ulx; x <= edge.lrx; x++) {
unsigned char color = *dest;
*dest++ = intensityColorTable[color][step * 128 / kShadowSize];
}
step++;
}
}

// Right.
edge.ulx = tile_bounds_rect.lrx - kShadowSize;
edge.uly = tile_bounds_rect.uly;
edge.lrx = tile_bounds_rect.lrx;
edge.lry = tile_bounds_rect.lry;
if (rect_inside_bound(&edge, rect, &edge) == 0) {
for (int y = edge.uly; y <= edge.lry; y++) {
unsigned char* dest = buf + buf_full * y + edge.lrx;
int step = tile_bounds_rect.lrx - edge.lrx;
for (int x = edge.lrx; x >= edge.ulx; x--) {
unsigned char color = *dest;
*dest-- = intensityColorTable[color][step * 128 / kShadowSize];
step++;
}
}
}

// Bottom.
edge.ulx = tile_bounds_rect.ulx;
edge.uly = tile_bounds_rect.lry - kShadowSize;
edge.lrx = tile_bounds_rect.lrx;
edge.lry = tile_bounds_rect.lry;
if (rect_inside_bound(&edge, rect, &edge) == 0) {
int step = tile_bounds_rect.lry - edge.lry;
for (int y = edge.lry; y >= edge.uly; y--) {
unsigned char* dest = buf + buf_full * y + edge.ulx;
for (int x = edge.ulx; x <= edge.lrx; x++) {
unsigned char color = *dest;
*dest++ = intensityColorTable[color][step * 128 / kShadowSize];
}
step++;
}
}
}

} // namespace fallout
6 changes: 6 additions & 0 deletions src/game/tile.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ void floor_draw(int fid, int x, int y, Rect* rect);
int tile_make_line(int currentCenterTile, int newCenterTile, int* tiles, int tilesCapacity);
int tile_scroll_to(int tile, int flags);

void tile_update_bounds_base();
void tile_update_bounds_rect();
int tile_inside_bound(Rect* rect);
bool tile_point_inside_bound(int x, int y);
void bounds_render(Rect* rect, int elevation);

} // namespace fallout

#endif /* FALLOUT_GAME_TILE_H_ */

0 comments on commit 2716012

Please sign in to comment.