Add object shore/flooding support, adjust handling of foundations

Add info to debug window
pull/341/head
Jonathan G Rennison 3 years ago
parent d9116106ca
commit 06fa1ae332

@ -1855,6 +1855,7 @@
<li>m7: animation counter</li>
<li style="color: blue">m4 bits 7..5: update counter (for objects using land ground sprites), incremented on every periodic processing.<BR>
For snow and desert, these bits are not used, tile is updated on every periodic processing.</li>
<li style="color: blue">m4 bits 4: tile has no effective foundation.</li>
<li style="color: blue">m4 bits 3..2: ground type (for objects using land ground sprites):
<table style="color: blue">
<tr>
@ -1866,6 +1867,11 @@
<td nowrap valign=top><tt>1</tt>&nbsp; </td>
<td align=left>snow or desert</td>
</tr>
<tr>
<td nowrap valign=top><tt>2</tt>&nbsp; </td>
<td align=left>shore/coast</td>
</tr>
</table>
</li>
<li style="color: blue">m4 bits 1..0: density (for objects using land ground sprites):

@ -324,7 +324,7 @@ the array so you can quickly see what is used and what is not.
<td class="bits"><span class="free">O</span><span class="used" title="Water class">XX</span> <span class="used" title="Owner">XXXXX</span></td>
<td class="bits"><span class="pool" title="Object index on pool (m2 + m5)">XXXX XXXX XXXX XXXX</span></td>
<td class="bits"><span class="used" title="Random bits">XXXX XXXX</span></td>
<td class="bits"><span class="patch" title="Ground update counter">PPP</span><span class="free">O</span> <span class="patch" title="Ground type: grass/bare, snow/desert">PP</span> <span class="patch" title="Ground density">PP</span></td>
<td class="bits"><span class="patch" title="Ground update counter">PPP</span> <span class="patch" title="Tile has no effective foundation">P</span> <span class="patch" title="Ground type: grass/bare, snow/desert, shore">PP</span> <span class="patch" title="Ground density">PP</span></td>
<td class="bits"><span class="pool" title="Object index on pool (m2 + m5)">XXXX XXXX</span></td>
<td class="bits"><span class="free">OOOO OOOO</span></td>
<td class="bits"><span class="used" title="Animation counter">XXXX XXXX</span></td>

@ -43,6 +43,7 @@ extern const GRFFeatureInfo _grf_feature_list[] = {
GRFFeatureInfo("action0_signals_extra_aspects", 1),
GRFFeatureInfo("action3_signals_custom_signal_sprites", 1),
GRFFeatureInfo("action0_object_use_land_ground", 1),
GRFFeatureInfo("action0_object_edge_foundation_mode", 1),
GRFFeatureInfo(),
};

@ -427,7 +427,7 @@ static void DrawTileLayout(TileInfo *ti, const TileLayoutSpriteGroup *group, con
PaletteID pal = dts->ground.pal;
if (spec->ctrl_flags & OBJECT_CTRL_FLAG_USE_LAND_GROUND) {
if (IsTileOnWater(ti->tile)) {
if (IsTileOnWater(ti->tile) && GetObjectGroundType(ti->tile) != OBJECT_GROUND_SHORE) {
DrawWaterClassGround(ti);
} else {
switch (GetObjectGroundType(ti->tile)) {
@ -439,6 +439,10 @@ static void DrawTileLayout(TileInfo *ti, const TileLayoutSpriteGroup *group, con
DrawGroundSprite(GetSpriteIDForSnowDesert(ti->tileh, GetObjectGroundDensity(ti->tile)), PAL_NONE);
break;
case OBJECT_GROUND_SHORE:
DrawShoreTile(ti->tileh);
break;
default:
/* This should never be reached, just draw a black sprite to make the problem clear without being unnecessarily punitive */
DrawGroundSprite(SPR_FLAT_BARE_LAND + SlopeToSpriteOffset(ti->tileh), PALETTE_ALL_BLACK);

@ -71,6 +71,40 @@ void InitializeObjects()
Object::ResetTypeCounts();
}
/**
* Set the object has no effective foundation flag for this tile.
* Set tileh to SLOPE_ELEVATED if not known, it will be redetermined if required.
*/
void SetShouldObjectHaveNoFoundation(TileIndex tile, Slope tileh, ObjectType type, const ObjectSpec *spec)
{
if (type == OBJECT_OWNED_LAND) {
SetObjectHasNoEffectiveFoundation(tile, true);
return;
}
if (((spec->flags & OBJECT_FLAG_HAS_NO_FOUNDATION) == 0) && (spec->ctrl_flags & OBJECT_CTRL_FLAG_EDGE_FOUNDATION)) {
if (tileh == SLOPE_ELEVATED) tileh = GetTileSlope(tile);
if (IsSteepSlope(tileh)) {
SetObjectHasNoEffectiveFoundation(tile, false);
return;
}
if (tileh == SLOPE_FLAT) {
SetObjectHasNoEffectiveFoundation(tile, true);
return;
}
uint8 flags = spec->edge_foundation[Object::GetByTile(tile)->view];
DiagDirection edge = (DiagDirection)GB(flags, 0, 2);
Slope incline = InclinedSlope(edge);
SetObjectHasNoEffectiveFoundation(tile, !(IsOddParity(incline & tileh) || (flags & OBJECT_EF_FLAG_FOUNDATION_LOWER && !(tileh & incline))));
} else {
SetObjectHasNoEffectiveFoundation(tile, false);
}
}
/**
* Actually build the object.
* @param type The type of object to build.
@ -129,6 +163,7 @@ void BuildObject(ObjectType type, TileIndex tile, CompanyID owner, Town *town, u
if ((spec->ctrl_flags & OBJECT_CTRL_FLAG_USE_LAND_GROUND) && wc == WATER_CLASS_INVALID) {
SetObjectGroundTypeDensity(t, OBJECT_GROUND_GRASS, 0);
}
SetShouldObjectHaveNoFoundation(t, SLOPE_ELEVATED, type, spec);
MarkTileDirtyByTile(t, VMDF_NOT_MAP_MODE);
}
@ -605,7 +640,7 @@ static int GetSlopePixelZ_Object(TileIndex tile, uint x, uint y)
static Foundation GetFoundation_Object(TileIndex tile, Slope tileh)
{
return IsObjectType(tile, OBJECT_OWNED_LAND) ? FOUNDATION_NONE : FlatteningFoundation(tileh);
return GetObjectHasNoEffectiveFoundation(tile) ? FOUNDATION_NONE : FlatteningFoundation(tileh);
}
/**
@ -854,9 +889,13 @@ static void TileLoop_Object(TileIndex tile)
if (IsTileOnWater(tile)) {
TileLoop_Water(tile);
} else if (spec->ctrl_flags & OBJECT_CTRL_FLAG_USE_LAND_GROUND) {
switch (_settings_game.game_creation.landscape) {
case LT_TROPIC: TileLoopObjectGroundDesert(tile); break;
case LT_ARCTIC: TileLoopObjectGroundAlps(tile); break;
if (GetObjectGroundType(tile) == OBJECT_GROUND_SHORE) {
TileLoop_Water(tile);
} else {
switch (_settings_game.game_creation.landscape) {
case LT_TROPIC: TileLoopObjectGroundDesert(tile); break;
case LT_ARCTIC: TileLoopObjectGroundAlps(tile); break;
}
}
if (GetObjectGroundType(tile) == OBJECT_GROUND_GRASS && GetObjectGroundDensity(tile) != 3) {
@ -1105,6 +1144,13 @@ static CommandCost TerraformTile_Object(TileIndex tile, DoCommandFlag flags, int
CommandCost ret = CheckTileOwnership(tile);
if (ret.Succeeded()) return CommandCost();
} else if (AutoslopeEnabled() && type != OBJECT_TRANSMITTER && type != OBJECT_LIGHTHOUSE) {
const ObjectSpec *spec = ObjectSpec::Get(type);
if (flags & DC_EXEC) {
SetShouldObjectHaveNoFoundation(tile, tileh_new, type, spec);
if (GetObjectGroundType(tile) == OBJECT_GROUND_SHORE) SetObjectGroundTypeDensity(tile, OBJECT_GROUND_GRASS, 0);
}
/* Behaviour:
* - Both new and old slope must not be steep.
* - TileMaxZ must not be changed.
@ -1113,7 +1159,7 @@ static CommandCost TerraformTile_Object(TileIndex tile, DoCommandFlag flags, int
*/
int z_old;
Slope tileh_old = GetTileSlope(tile, &z_old);
const ObjectSpec *spec = ObjectSpec::Get(type);
/* Object height must not be changed. Slopes must not be steep. */
if (!IsSteepSlope(tileh_old) && !IsSteepSlope(tileh_new) && (GetObjectEffectiveZ(tile, spec, z_old, tileh_old) == GetObjectEffectiveZ(tile, spec, z_new, tileh_new))) {

@ -16,6 +16,7 @@
enum ObjectGround {
OBJECT_GROUND_GRASS = 0, ///< Grass or bare
OBJECT_GROUND_SNOW_DESERT = 1, ///< Snow or desert
OBJECT_GROUND_SHORE = 2, ///< Shore
};
ObjectType GetObjectType(TileIndex t);
@ -155,6 +156,18 @@ static inline void SetObjectGroundTypeDensity(TileIndex t, ObjectGround type, ui
_m[t].m4 = 0 << 5 | type << 2 | density;
}
static inline bool GetObjectHasNoEffectiveFoundation(TileIndex t)
{
assert_tile(IsTileType(t, MP_OBJECT), t);
return GB(_m[t].m4, 4, 1);
}
static inline void SetObjectHasNoEffectiveFoundation(TileIndex t, bool no_foundation)
{
assert_tile(IsTileType(t, MP_OBJECT), t);
SB(_m[t].m4, 4, 1, no_foundation ? 1 : 0);
}
/**
* Make an Object tile.
* @param t The tile to make and object tile.

@ -861,8 +861,12 @@ class NIHObject : public NIHelper {
uint class_id = ObjectClass::Get(spec->cls_id)->global_id;
seprintf(buffer, lastof(buffer), " index: %u, type ID: %u, class ID: %c%c%c%c", id, GetObjectType(index), class_id >> 24, class_id >> 16, class_id >> 8, class_id);
output.print(buffer);
seprintf(buffer, lastof(buffer), " view: %u, colour: %u", obj->view, obj->colour);
seprintf(buffer, lastof(buffer), " view: %u, colour: %u, effective foundation: %u", obj->view, obj->colour, !GetObjectHasNoEffectiveFoundation(index));
output.print(buffer);
if (spec->ctrl_flags & OBJECT_CTRL_FLAG_USE_LAND_GROUND) {
seprintf(buffer, lastof(buffer), " ground type: %u, density: %u, counter: %u, water class: %u", GetObjectGroundType(index), GetObjectGroundDensity(index), GetObjectGroundCounter(index), GetWaterClass(index));
output.print(buffer);
}
seprintf(buffer, lastof(buffer), " animation: frames: %u, status: %u, speed: %u, triggers: 0x%X", spec->animation.frames, spec->animation.status, spec->animation.speed, spec->animation.triggers);
output.print(buffer);
seprintf(buffer, lastof(buffer), " size: %ux%u, height: %u, views: %u", GB(spec->size, 4, 4), GB(spec->size, 0, 4), spec->height, spec->views);

@ -38,6 +38,9 @@
#include "company_gui.h"
#include "newgrf_generic.h"
#include "industry.h"
#include "object_base.h"
#include "object_map.h"
#include "newgrf_object.h"
#include "table/strings.h"
@ -1121,7 +1124,6 @@ FloodingBehaviour GetFloodingBehaviour(TileIndex tile)
FALLTHROUGH;
case MP_STATION:
case MP_INDUSTRY:
case MP_OBJECT:
return (GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE;
case MP_RAILWAY:
@ -1133,6 +1135,9 @@ FloodingBehaviour GetFloodingBehaviour(TileIndex tile)
case MP_TREES:
return (GetTreeGround(tile) == TREE_GROUND_SHORE ? FLOOD_DRYUP : FLOOD_NONE);
case MP_OBJECT:
return (GetObjectGroundType(tile) == OBJECT_GROUND_SHORE ? FLOOD_DRYUP : ((GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE));
default:
return FLOOD_NONE;
}
@ -1177,6 +1182,30 @@ void DoFloodTile(TileIndex target)
}
break;
case MP_OBJECT: {
const ObjectSpec *spec = ObjectSpec::GetByTile(target);
if ((spec->ctrl_flags & OBJECT_CTRL_FLAG_USE_LAND_GROUND) && (spec->ctrl_flags & OBJECT_CTRL_FLAG_EDGE_FOUNDATION)) {
Object *obj = Object::GetByTile(target);
uint8 flags = spec->edge_foundation[obj->view];
DiagDirection edge = (DiagDirection)GB(flags, 0, 2);
Slope incline = InclinedSlope(edge);
if (!(tileh & incline) && !(flags & OBJECT_EF_FLAG_FOUNDATION_LOWER)) {
/* object is on the lower edge with no foundation, and now underwater, clear the tile and then flood it */
if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) {
MakeShore(target);
MarkTileDirtyByTile(target);
flooded = true;
}
break;
}
SetWaterClass(target, WATER_CLASS_SEA);
SetObjectGroundTypeDensity(target, OBJECT_GROUND_SHORE, 3);
MarkTileDirtyByTile(target, VMDF_NOT_MAP_MODE);
flooded = true;
}
break;
}
default:
break;
}
@ -1243,6 +1272,12 @@ static void DoDryUp(TileIndex tile)
}
break;
case MP_OBJECT:
SetWaterClass(tile, WATER_CLASS_INVALID);
SetObjectGroundTypeDensity(tile, OBJECT_GROUND_GRASS, 3);
MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE);
break;
default: NOT_REACHED();
}
@ -1274,6 +1309,7 @@ void TileLoop_Water(TileIndex tile)
/* TREE_GROUND_SHORE is the sign of a previous flood. */
if (IsTileType(dest, MP_TREES) && GetTreeGround(dest) == TREE_GROUND_SHORE) continue;
if (IsTileType(dest, MP_OBJECT) && (!GetObjectHasNoEffectiveFoundation(dest) || GetObjectGroundType(dest) == OBJECT_GROUND_SHORE)) continue;
int z_dest;
Slope slope_dest = GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;

Loading…
Cancel
Save