Add object shore/flooding support, adjust handling of foundations

Add info to debug window
This commit is contained in:
Jonathan G Rennison
2021-12-05 21:20:58 +00:00
parent d9116106ca
commit 06fa1ae332
8 changed files with 119 additions and 9 deletions

View File

@@ -1855,6 +1855,7 @@
<li>m7: animation counter</li> <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> <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> 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): <li style="color: blue">m4 bits 3..2: ground type (for objects using land ground sprites):
<table style="color: blue"> <table style="color: blue">
<tr> <tr>
@@ -1866,6 +1867,11 @@
<td nowrap valign=top><tt>1</tt>&nbsp; </td> <td nowrap valign=top><tt>1</tt>&nbsp; </td>
<td align=left>snow or desert</td> <td align=left>snow or desert</td>
</tr> </tr>
<tr>
<td nowrap valign=top><tt>2</tt>&nbsp; </td>
<td align=left>shore/coast</td>
</tr>
</table> </table>
</li> </li>
<li style="color: blue">m4 bits 1..0: density (for objects using land ground sprites): <li style="color: blue">m4 bits 1..0: density (for objects using land ground sprites):

View File

@@ -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="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="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="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="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="free">OOOO OOOO</span></td>
<td class="bits"><span class="used" title="Animation counter">XXXX XXXX</span></td> <td class="bits"><span class="used" title="Animation counter">XXXX XXXX</span></td>

View File

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

View File

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

View File

@@ -71,6 +71,40 @@ void InitializeObjects()
Object::ResetTypeCounts(); 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. * Actually build the object.
* @param type The type of object to build. * @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) { if ((spec->ctrl_flags & OBJECT_CTRL_FLAG_USE_LAND_GROUND) && wc == WATER_CLASS_INVALID) {
SetObjectGroundTypeDensity(t, OBJECT_GROUND_GRASS, 0); SetObjectGroundTypeDensity(t, OBJECT_GROUND_GRASS, 0);
} }
SetShouldObjectHaveNoFoundation(t, SLOPE_ELEVATED, type, spec);
MarkTileDirtyByTile(t, VMDF_NOT_MAP_MODE); 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) 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)) { if (IsTileOnWater(tile)) {
TileLoop_Water(tile); TileLoop_Water(tile);
} else if (spec->ctrl_flags & OBJECT_CTRL_FLAG_USE_LAND_GROUND) { } else if (spec->ctrl_flags & OBJECT_CTRL_FLAG_USE_LAND_GROUND) {
switch (_settings_game.game_creation.landscape) { if (GetObjectGroundType(tile) == OBJECT_GROUND_SHORE) {
case LT_TROPIC: TileLoopObjectGroundDesert(tile); break; TileLoop_Water(tile);
case LT_ARCTIC: TileLoopObjectGroundAlps(tile); break; } 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) { 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); CommandCost ret = CheckTileOwnership(tile);
if (ret.Succeeded()) return CommandCost(); if (ret.Succeeded()) return CommandCost();
} else if (AutoslopeEnabled() && type != OBJECT_TRANSMITTER && type != OBJECT_LIGHTHOUSE) { } 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: /* Behaviour:
* - Both new and old slope must not be steep. * - Both new and old slope must not be steep.
* - TileMaxZ must not be changed. * - TileMaxZ must not be changed.
@@ -1113,7 +1159,7 @@ static CommandCost TerraformTile_Object(TileIndex tile, DoCommandFlag flags, int
*/ */
int z_old; int z_old;
Slope tileh_old = GetTileSlope(tile, &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. */ /* 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))) { if (!IsSteepSlope(tileh_old) && !IsSteepSlope(tileh_new) && (GetObjectEffectiveZ(tile, spec, z_old, tileh_old) == GetObjectEffectiveZ(tile, spec, z_new, tileh_new))) {

View File

@@ -16,6 +16,7 @@
enum ObjectGround { enum ObjectGround {
OBJECT_GROUND_GRASS = 0, ///< Grass or bare OBJECT_GROUND_GRASS = 0, ///< Grass or bare
OBJECT_GROUND_SNOW_DESERT = 1, ///< Snow or desert OBJECT_GROUND_SNOW_DESERT = 1, ///< Snow or desert
OBJECT_GROUND_SHORE = 2, ///< Shore
}; };
ObjectType GetObjectType(TileIndex t); 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; _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. * Make an Object tile.
* @param t The tile to make and object tile. * @param t The tile to make and object tile.

View File

@@ -861,8 +861,12 @@ class NIHObject : public NIHelper {
uint class_id = ObjectClass::Get(spec->cls_id)->global_id; 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); 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); 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); 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); 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); 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); 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);

View File

@@ -38,6 +38,9 @@
#include "company_gui.h" #include "company_gui.h"
#include "newgrf_generic.h" #include "newgrf_generic.h"
#include "industry.h" #include "industry.h"
#include "object_base.h"
#include "object_map.h"
#include "newgrf_object.h"
#include "table/strings.h" #include "table/strings.h"
@@ -1121,7 +1124,6 @@ FloodingBehaviour GetFloodingBehaviour(TileIndex tile)
FALLTHROUGH; FALLTHROUGH;
case MP_STATION: case MP_STATION:
case MP_INDUSTRY: case MP_INDUSTRY:
case MP_OBJECT:
return (GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE; return (GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE;
case MP_RAILWAY: case MP_RAILWAY:
@@ -1133,6 +1135,9 @@ FloodingBehaviour GetFloodingBehaviour(TileIndex tile)
case MP_TREES: case MP_TREES:
return (GetTreeGround(tile) == TREE_GROUND_SHORE ? FLOOD_DRYUP : FLOOD_NONE); 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: default:
return FLOOD_NONE; return FLOOD_NONE;
} }
@@ -1177,6 +1182,30 @@ void DoFloodTile(TileIndex target)
} }
break; 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: default:
break; break;
} }
@@ -1243,6 +1272,12 @@ static void DoDryUp(TileIndex tile)
} }
break; 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(); default: NOT_REACHED();
} }
@@ -1274,6 +1309,7 @@ void TileLoop_Water(TileIndex tile)
/* TREE_GROUND_SHORE is the sign of a previous flood. */ /* 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_TREES) && GetTreeGround(dest) == TREE_GROUND_SHORE) continue;
if (IsTileType(dest, MP_OBJECT) && (!GetObjectHasNoEffectiveFoundation(dest) || GetObjectGroundType(dest) == OBJECT_GROUND_SHORE)) continue;
int z_dest; int z_dest;
Slope slope_dest = GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP; Slope slope_dest = GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP;