mirror of
https://github.com/alexbatalov/fallout1-ce.git
synced 2024-10-04 13:49:51 +00:00
Add tile bounds (#105)
This commit is contained in:
parent
1db15fe6b5
commit
271601221e
@ -859,6 +859,11 @@ void gmouse_handle_event(int mouseX, int mouseY, int mouseState)
|
|||||||
return;
|
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_DOWN) != 0) {
|
||||||
if ((mouseState & MOUSE_EVENT_RIGHT_BUTTON_REPEAT) == 0) {
|
if ((mouseState & MOUSE_EVENT_RIGHT_BUTTON_REPEAT) == 0) {
|
||||||
if (gmouse_3d_is_on()) {
|
if (gmouse_3d_is_on()) {
|
||||||
|
@ -455,6 +455,9 @@ int map_set_elevation(int elevation)
|
|||||||
gmouse_set_cursor(MOUSE_CURSOR_NONE);
|
gmouse_set_cursor(MOUSE_CURSOR_NONE);
|
||||||
map_elevation = elevation;
|
map_elevation = elevation;
|
||||||
|
|
||||||
|
// CE: Recalculate bounds.
|
||||||
|
tile_update_bounds_base();
|
||||||
|
|
||||||
register_clear(obj_dude);
|
register_clear(obj_dude);
|
||||||
dude_stand(obj_dude, obj_dude->rotation, obj_dude->fid);
|
dude_stand(obj_dude, obj_dude->rotation, obj_dude->fid);
|
||||||
partyMemberSyncPosition();
|
partyMemberSyncPosition();
|
||||||
@ -1611,6 +1614,7 @@ static void map_scroll_refresh_game(Rect* rect)
|
|||||||
grid_render(&rectToUpdate, map_elevation);
|
grid_render(&rectToUpdate, map_elevation);
|
||||||
obj_render_pre_roof(&rectToUpdate, map_elevation);
|
obj_render_pre_roof(&rectToUpdate, map_elevation);
|
||||||
square_render_roof(&rectToUpdate, map_elevation);
|
square_render_roof(&rectToUpdate, map_elevation);
|
||||||
|
bounds_render(&rectToUpdate, map_elevation);
|
||||||
obj_render_post_roof(&rectToUpdate, map_elevation);
|
obj_render_post_roof(&rectToUpdate, map_elevation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -772,6 +772,19 @@ void obj_render_pre_roof(Rect* rect, int elevation)
|
|||||||
return;
|
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 ambientIntensity = light_get_ambient();
|
||||||
int minX = updatedRect.ulx - 320;
|
int minX = updatedRect.ulx - 320;
|
||||||
int minY = updatedRect.uly - 240;
|
int minY = updatedRect.uly - 240;
|
||||||
@ -874,8 +887,23 @@ void obj_render_post_roof(Rect* rect, int elevation)
|
|||||||
return;
|
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++) {
|
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);
|
text_object_render(&updatedRect);
|
||||||
|
235
src/game/tile.cc
235
src/game/tile.cc
@ -1,6 +1,7 @@
|
|||||||
#include "game/tile.h"
|
#include "game/tile.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define _USE_MATH_DEFINES
|
#define _USE_MATH_DEFINES
|
||||||
@ -557,6 +558,9 @@ int tile_set_center(int tile, int flags)
|
|||||||
|
|
||||||
tile_center_tile = tile;
|
tile_center_tile = tile;
|
||||||
|
|
||||||
|
// CE: Updates bounds screen coordinates.
|
||||||
|
tile_update_bounds_rect();
|
||||||
|
|
||||||
if ((flags & TILE_SET_CENTER_REFRESH_WINDOW) != 0) {
|
if ((flags & TILE_SET_CENTER_REFRESH_WINDOW) != 0) {
|
||||||
// NOTE: Uninline.
|
// NOTE: Uninline.
|
||||||
tile_refresh_display();
|
tile_refresh_display();
|
||||||
@ -606,6 +610,7 @@ static void refresh_game(Rect* rect, int elevation)
|
|||||||
square_render_floor(&rectToUpdate, elevation);
|
square_render_floor(&rectToUpdate, elevation);
|
||||||
obj_render_pre_roof(&rectToUpdate, elevation);
|
obj_render_pre_roof(&rectToUpdate, elevation);
|
||||||
square_render_roof(&rectToUpdate, elevation);
|
square_render_roof(&rectToUpdate, elevation);
|
||||||
|
bounds_render(&rectToUpdate, elevation);
|
||||||
obj_render_post_roof(&rectToUpdate, elevation);
|
obj_render_post_roof(&rectToUpdate, elevation);
|
||||||
blit(&rectToUpdate);
|
blit(&rectToUpdate);
|
||||||
}
|
}
|
||||||
@ -1154,10 +1159,16 @@ void square_render_roof(Rect* rect, int elevation)
|
|||||||
int maxX;
|
int maxX;
|
||||||
int maxY;
|
int maxY;
|
||||||
|
|
||||||
square_xy_roof(rect->ulx, rect->uly, elevation, &temp, &minY);
|
// CE: Constrain rect to tile bounds so that we don't draw outside.
|
||||||
square_xy_roof(rect->lrx, rect->uly, elevation, &minX, &temp);
|
Rect constrainedRect = *rect;
|
||||||
square_xy_roof(rect->ulx, rect->lry, elevation, &maxX, &temp);
|
if (tile_inside_bound(&constrainedRect) != 0) {
|
||||||
square_xy_roof(rect->lrx, rect->lry, elevation, &temp, &maxY);
|
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) {
|
if (minX < 0) {
|
||||||
minX = 0;
|
minX = 0;
|
||||||
@ -1191,7 +1202,7 @@ void square_render_roof(Rect* rect, int elevation)
|
|||||||
int screenX;
|
int screenX;
|
||||||
int screenY;
|
int screenY;
|
||||||
square_coord_roof(squareTile, &screenX, &screenY, elevation);
|
square_coord_roof(squareTile, &screenX, &screenY, elevation);
|
||||||
roof_draw(fid, screenX, screenY, rect, light);
|
roof_draw(fid, screenX, screenY, &constrainedRect, light);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1378,10 +1389,16 @@ void square_render_floor(Rect* rect, int elevation)
|
|||||||
int minX;
|
int minX;
|
||||||
int temp;
|
int temp;
|
||||||
|
|
||||||
square_xy(rect->ulx, rect->uly, elevation, &temp, &minY);
|
// CE: Constrain rect to tile bounds so that we don't draw outside.
|
||||||
square_xy(rect->lrx, rect->uly, elevation, &minX, &temp);
|
Rect constrainedRect = *rect;
|
||||||
square_xy(rect->ulx, rect->lry, elevation, &maxX, &temp);
|
if (tile_inside_bound(&constrainedRect) != 0) {
|
||||||
square_xy(rect->lrx, rect->lry, elevation, &temp, &maxY);
|
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) {
|
if (minX < 0) {
|
||||||
minX = 0;
|
minX = 0;
|
||||||
@ -1412,7 +1429,7 @@ void square_render_floor(Rect* rect, int elevation)
|
|||||||
int tileScreenY;
|
int tileScreenY;
|
||||||
square_coord(squareTile, &tileScreenX, &tileScreenY, elevation);
|
square_coord(squareTile, &tileScreenX, &tileScreenY, elevation);
|
||||||
int fid = art_id(OBJ_TYPE_TILE, frmId & 0xFFF, 0, 0, 0);
|
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;
|
baseSquareTile += square_width;
|
||||||
@ -1960,4 +1977,202 @@ int tile_scroll_to(int tile, int flags)
|
|||||||
return rc;
|
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
|
} // namespace fallout
|
||||||
|
@ -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_make_line(int currentCenterTile, int newCenterTile, int* tiles, int tilesCapacity);
|
||||||
int tile_scroll_to(int tile, int flags);
|
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
|
} // namespace fallout
|
||||||
|
|
||||||
#endif /* FALLOUT_GAME_TILE_H_ */
|
#endif /* FALLOUT_GAME_TILE_H_ */
|
||||||
|
Loading…
Reference in New Issue
Block a user