diff --git a/projects/openttd.vcproj b/projects/openttd.vcproj index 45042187fd..ca587c9ea6 100644 --- a/projects/openttd.vcproj +++ b/projects/openttd.vcproj @@ -512,6 +512,9 @@ + + @@ -934,6 +937,9 @@ + + diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj index 57c9cfca4d..9ac7e6cb5e 100644 --- a/projects/openttd_vs80.vcproj +++ b/projects/openttd_vs80.vcproj @@ -911,6 +911,10 @@ RelativePath=".\..\src\newgrf_callbacks.h" > + + @@ -1467,6 +1471,10 @@ RelativePath=".\..\src\newgrf.cpp" > + + diff --git a/source.list b/source.list index a172190b91..ce9113853a 100644 --- a/source.list +++ b/source.list @@ -138,6 +138,7 @@ network/network_server.h network/network_udp.h newgrf.h newgrf_callbacks.h +newgrf_canal.h newgrf_cargo.h newgrf_config.h newgrf_engine.h @@ -282,6 +283,7 @@ ai/trolly/trolly.cpp # NewGRF newgrf.cpp +newgrf_canal.cpp newgrf_cargo.cpp newgrf_config.cpp newgrf_engine.cpp diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 97411ca031..45075b65f2 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -39,6 +39,7 @@ #include "table/town_land.h" #include "cargotype.h" #include "industry.h" +#include "newgrf_canal.h" /* TTDPatch extended GRF format codec * (c) Petr Baudis 2004 (GPL'd) @@ -2244,6 +2245,7 @@ static void NewSpriteGroup(byte *buf, int len) case GSF_SHIP: case GSF_AIRCRAFT: case GSF_STATION: + case GSF_CANAL: case GSF_CARGOS: { byte sprites = _cur_grffile->spriteset_numents; @@ -2513,6 +2515,30 @@ static void VehicleMapSpriteGroup(byte *buf, byte feature, uint8 idcount, uint8 } +static void CanalMapSpriteGroup(byte *buf, uint8 idcount, uint8 cidcount) +{ + byte *bp = &buf[4 + idcount + cidcount * 3]; + uint16 groupid = grf_load_word(&bp); + + if (groupid >= _cur_grffile->spritegroups_count || _cur_grffile->spritegroups[groupid] == NULL) { + grfmsg(1, "CanalMapSpriteGroup: Spriteset 0x%04X out of range 0x%X or empty, skipping.", + groupid, _cur_grffile->spritegroups_count); + return; + } + + for (uint i = 0; i < idcount; i++) { + CanalFeature cf = (CanalFeature)buf[3 + i]; + + if (cf >= CF_END) { + grfmsg(1, "CanalMapSpriteGroup: Canal subset %d out of range, skipping", cf); + continue; + } + + _canal_sg[cf] = _cur_grffile->spritegroups[groupid]; + } +} + + static void StationMapSpriteGroup(byte *buf, uint8 idcount, uint8 cidcount) { for (uint i = 0; i < idcount; i++) { @@ -2661,6 +2687,10 @@ static void FeatureMapSpriteGroup(byte *buf, int len) VehicleMapSpriteGroup(buf, feature, idcount, cidcount, wagover); return; + case GSF_CANAL: + CanalMapSpriteGroup(buf, idcount, cidcount); + return; + case GSF_STATION: StationMapSpriteGroup(buf, idcount, cidcount); return; @@ -4315,6 +4345,9 @@ static void ResetNewGRFData() ResetStationClasses(); ResetCustomStations(); + /* Reset canal sprite groups */ + memset(_canal_sg, 0, sizeof(_canal_sg)); + /* Reset the snowline table. */ ClearSnowLine(); diff --git a/src/newgrf_canal.cpp b/src/newgrf_canal.cpp new file mode 100644 index 0000000000..9a4ebe2331 --- /dev/null +++ b/src/newgrf_canal.cpp @@ -0,0 +1,96 @@ +/* $Id$ */ + +#include "stdafx.h" +#include "openttd.h" +#include "variables.h" +#include "landscape.h" +#include "debug.h" +#include "newgrf.h" +#include "newgrf_callbacks.h" +#include "newgrf_spritegroup.h" +#include "newgrf_canal.h" + + +/** Table of canal 'feature' sprite groups */ +const SpriteGroup *_canal_sg[CF_END]; + + +/* Random bits and triggers are not supported for canals, so the following + * three functions are stubs. */ +static uint32 CanalGetRandomBits(const ResolverObject *object) +{ + return 0; +} + + +static uint32 CanalGetTriggers(const ResolverObject *object) +{ + return 0; +} + + +static void CanalSetTriggers(const ResolverObject *object, int triggers) +{ + return; +} + + +static uint32 CanalGetVariable(const ResolverObject *object, byte variable, byte parameter, bool *available) +{ + TileIndex tile = object->u.canal.tile; + + switch (variable) { + case 0x80: + return TileHeight(tile); + + case 0x81: + return ((_opt.landscape == LT_ARCTIC && GetTileZ(tile) > GetSnowLine()) ? 4 : 0) | + (_opt.landscape == LT_TROPIC ? GetTropicZone(tile) : 0); + } + + DEBUG(grf, 1, "Unhandled canal property 0x%02X", variable); + + *available = false; + return 0; +} + + +static const SpriteGroup *CanalResolveReal(const ResolverObject *object, const SpriteGroup *group) +{ + if (group->g.real.num_loaded == 0) return NULL; + + return group->g.real.loaded[0]; +} + + +static void NewCanalResolver(ResolverObject *res, TileIndex tile) +{ + res->GetRandomBits = &CanalGetRandomBits; + res->GetTriggers = &CanalGetTriggers; + res->SetTriggers = &CanalSetTriggers; + res->GetVariable = &CanalGetVariable; + res->ResolveReal = &CanalResolveReal; + + res->u.canal.tile = tile; + + res->callback = 0; + res->callback_param1 = 0; + res->callback_param2 = 0; + res->last_value = 0; + res->trigger = 0; + res->reseed = 0; +} + + +SpriteID GetCanalSprite(CanalFeature feature, TileIndex tile) +{ + ResolverObject object; + const SpriteGroup *group; + + NewCanalResolver(&object, tile); + + group = Resolve(_canal_sg[feature], &object); + if (group == NULL || group->type != SGT_RESULT) return 0; + + return group->g.result.sprite; +} diff --git a/src/newgrf_canal.h b/src/newgrf_canal.h new file mode 100644 index 0000000000..23fb3a9a8a --- /dev/null +++ b/src/newgrf_canal.h @@ -0,0 +1,29 @@ +/* $Id$ */ + +#ifndef NEWGRF_CANAL_H +#define NEWGRF_CANAL_H + +/** List of different canal 'features'. + * Each feature gets an entry in the canal spritegroup table */ +enum CanalFeature { + CF_WATERSLOPE, + CF_LOCKS, + CF_DIKES, + CF_ICON, + CF_DOCKS, + CF_END, +}; + + +/** Table of canal 'feature' sprite groups */ +extern const SpriteGroup *_canal_sg[CF_END]; + + +/** Lookup the base sprite to use for a canal. + * @param feature Which canal feature we want. + * @param tile Tile index of canal, if appropriate. + * @return Base sprite returned by GRF, or 0 if none. + */ +SpriteID GetCanalSprite(CanalFeature feature, TileIndex tile); + +#endif /* NEWGRF_CANAL_H */ diff --git a/src/newgrf_spritegroup.h b/src/newgrf_spritegroup.h index fc5fcb5149..83cead28ab 100644 --- a/src/newgrf_spritegroup.h +++ b/src/newgrf_spritegroup.h @@ -182,6 +182,9 @@ struct ResolverObject { const struct Vehicle *parent; EngineID self_type; } vehicle; + struct { + TileIndex tile; + } canal; struct { TileIndex tile; const struct Station *st; diff --git a/src/table/water_land.h b/src/table/water_land.h index 9562c1d02c..c6de3c9c8c 100644 --- a/src/table/water_land.h +++ b/src/table/water_land.h @@ -47,86 +47,86 @@ static const WaterDrawTileStruct* const _shipdepot_display_seq[] = { }; static const WaterDrawTileStruct _shiplift_display_seq_0[] = { - BEGIN(SPR_CANALS_BASE + 6), - { 0, 0, 0, 0x10, 1, 0x14, SPR_CANALS_BASE + 9 + 0 + 1 }, - { 0, 0xF, 0, 0x10, 1, 0x14, SPR_CANALS_BASE + 9 + 4 + 1 }, + BEGIN(1), + { 0, 0, 0, 0x10, 1, 0x14, 0 + 1 }, + { 0, 0xF, 0, 0x10, 1, 0x14, 4 + 1 }, END(0) }; static const WaterDrawTileStruct _shiplift_display_seq_1[] = { - BEGIN(SPR_CANALS_BASE + 5), - { 0, 0, 0, 1, 0x10, 0x14, SPR_CANALS_BASE + 9 + 0 }, - { 0xF, 0, 0, 1, 0x10, 0x14, SPR_CANALS_BASE + 9 + 4 }, + BEGIN(0), + { 0, 0, 0, 1, 0x10, 0x14, 0 }, + { 0xF, 0, 0, 1, 0x10, 0x14, 4 }, END(0) }; static const WaterDrawTileStruct _shiplift_display_seq_2[] = { - BEGIN(SPR_CANALS_BASE + 7), - { 0, 0, 0, 0x10, 1, 0x14, SPR_CANALS_BASE + 9 + 0 + 2 }, - { 0, 0xF, 0, 0x10, 1, 0x14, SPR_CANALS_BASE + 9 + 4 + 2 }, + BEGIN(2), + { 0, 0, 0, 0x10, 1, 0x14, 0 + 2 }, + { 0, 0xF, 0, 0x10, 1, 0x14, 4 + 2 }, END(0) }; static const WaterDrawTileStruct _shiplift_display_seq_3[] = { - BEGIN(SPR_CANALS_BASE + 8), - { 0, 0, 0, 1, 0x10, 0x14, SPR_CANALS_BASE + 9 + 0 + 3 }, - { 0xF, 0, 0, 1, 0x10, 0x14, SPR_CANALS_BASE + 9 + 4 + 3 }, + BEGIN(3), + { 0, 0, 0, 1, 0x10, 0x14, 0 + 3 }, + { 0xF, 0, 0, 1, 0x10, 0x14, 4 + 3 }, END(0) }; static const WaterDrawTileStruct _shiplift_display_seq_0b[] = { BEGIN(0xFDD), - { 0, 0, 0, 0x10, 1, 0x14, SPR_CANALS_BASE + 9 + 8 + 1 }, - { 0, 0xF, 0, 0x10, 1, 0x14, SPR_CANALS_BASE + 9 + 12 + 1 }, + { 0, 0, 0, 0x10, 1, 0x14, 8 + 1 }, + { 0, 0xF, 0, 0x10, 1, 0x14, 12 + 1 }, END(0) }; static const WaterDrawTileStruct _shiplift_display_seq_1b[] = { BEGIN(0xFDD), - { 0, 0, 0, 0x1, 0x10, 0x14, SPR_CANALS_BASE + 9 + 8 }, - { 0xF, 0, 0, 0x1, 0x10, 0x14, SPR_CANALS_BASE + 9 + 12 }, + { 0, 0, 0, 0x1, 0x10, 0x14, 8 }, + { 0xF, 0, 0, 0x1, 0x10, 0x14, 12 }, END(0) }; static const WaterDrawTileStruct _shiplift_display_seq_2b[] = { BEGIN(0xFDD), - { 0, 0, 0, 0x10, 1, 0x14, SPR_CANALS_BASE + 9 + 8 + 2 }, - { 0, 0xF, 0, 0x10, 1, 0x14, SPR_CANALS_BASE + 9 + 12 + 2 }, + { 0, 0, 0, 0x10, 1, 0x14, 8 + 2 }, + { 0, 0xF, 0, 0x10, 1, 0x14, 12 + 2 }, END(0) }; static const WaterDrawTileStruct _shiplift_display_seq_3b[] = { BEGIN(0xFDD), - { 0, 0, 0, 1, 0x10, 0x14, SPR_CANALS_BASE + 9 + 8 + 3 }, - { 0xF, 0, 0, 1, 0x10, 0x14, SPR_CANALS_BASE + 9 + 12 + 3 }, + { 0, 0, 0, 1, 0x10, 0x14, 8 + 3 }, + { 0xF, 0, 0, 1, 0x10, 0x14, 12 + 3 }, END(0) }; static const WaterDrawTileStruct _shiplift_display_seq_0t[] = { BEGIN(0xFDD), - { 0, 0, 0, 0x10, 1, 0x14, SPR_CANALS_BASE + 9 + 16 + 1 }, - { 0, 0xF, 0, 0x10, 1, 0x14, SPR_CANALS_BASE + 9 + 20 + 1 }, + { 0, 0, 0, 0x10, 1, 0x14, 16 + 1 }, + { 0, 0xF, 0, 0x10, 1, 0x14, 20 + 1 }, END(8) }; static const WaterDrawTileStruct _shiplift_display_seq_1t[] = { BEGIN(0xFDD), - { 0, 0, 0, 0x1, 0x10, 0x14, SPR_CANALS_BASE + 9 + 16 }, - { 0xF, 0, 0, 0x1, 0x10, 0x14, SPR_CANALS_BASE + 9 + 20 }, + { 0, 0, 0, 0x1, 0x10, 0x14, 16 }, + { 0xF, 0, 0, 0x1, 0x10, 0x14, 20 }, END(8) }; static const WaterDrawTileStruct _shiplift_display_seq_2t[] = { BEGIN(0xFDD), - { 0, 0, 0, 0x10, 1, 0x14, SPR_CANALS_BASE + 9 + 16 + 2 }, - { 0, 0xF, 0, 0x10, 1, 0x14, SPR_CANALS_BASE + 9 + 20 + 2 }, + { 0, 0, 0, 0x10, 1, 0x14, 16 + 2 }, + { 0, 0xF, 0, 0x10, 1, 0x14, 20 + 2 }, END(8) }; static const WaterDrawTileStruct _shiplift_display_seq_3t[] = { BEGIN(0xFDD), - { 0, 0, 0, 1, 0x10, 0x14, SPR_CANALS_BASE + 9 + 16 + 3 }, - { 0xF, 0, 0, 1, 0x10, 0x14, SPR_CANALS_BASE + 9 + 20 + 3 }, + { 0, 0, 0, 1, 0x10, 0x14, 16 + 3 }, + { 0xF, 0, 0, 1, 0x10, 0x14, 20 + 3 }, END(8) }; diff --git a/src/water_cmd.cpp b/src/water_cmd.cpp index 67dcb6f50b..69210cfe09 100644 --- a/src/water_cmd.cpp +++ b/src/water_cmd.cpp @@ -25,6 +25,7 @@ #include "train.h" #include "water_map.h" #include "newgrf.h" +#include "newgrf_canal.h" static const SpriteID _water_shore_sprites[] = { 0, @@ -373,39 +374,43 @@ void DrawCanalWater(TileIndex tile) { uint wa; + /* Test for custom graphics, else use the default */ + SpriteID dikes_base = GetCanalSprite(CF_DIKES, tile); + if (dikes_base == 0) dikes_base = SPR_CANALS_BASE + 57; + /* determine the edges around with water. */ wa = IsWateredTile(TILE_ADDXY(tile, -1, 0)) << 0; wa += IsWateredTile(TILE_ADDXY(tile, 0, 1)) << 1; wa += IsWateredTile(TILE_ADDXY(tile, 1, 0)) << 2; wa += IsWateredTile(TILE_ADDXY(tile, 0, -1)) << 3; - if (!(wa & 1)) DrawGroundSprite(SPR_CANALS_BASE + 57, PAL_NONE); - if (!(wa & 2)) DrawGroundSprite(SPR_CANALS_BASE + 58, PAL_NONE); - if (!(wa & 4)) DrawGroundSprite(SPR_CANALS_BASE + 59, PAL_NONE); - if (!(wa & 8)) DrawGroundSprite(SPR_CANALS_BASE + 60, PAL_NONE); + if (!(wa & 1)) DrawGroundSprite(dikes_base, PAL_NONE); + if (!(wa & 2)) DrawGroundSprite(dikes_base + 1, PAL_NONE); + if (!(wa & 4)) DrawGroundSprite(dikes_base + 2, PAL_NONE); + if (!(wa & 8)) DrawGroundSprite(dikes_base + 3, PAL_NONE); /* right corner */ switch (wa & 0x03) { - case 0: DrawGroundSprite(SPR_CANALS_BASE + 57 + 4, PAL_NONE); break; - case 3: if (!IsWateredTile(TILE_ADDXY(tile, -1, 1))) DrawGroundSprite(SPR_CANALS_BASE + 57 + 8, PAL_NONE); break; + case 0: DrawGroundSprite(dikes_base + 4, PAL_NONE); break; + case 3: if (!IsWateredTile(TILE_ADDXY(tile, -1, 1))) DrawGroundSprite(dikes_base + 8, PAL_NONE); break; } /* bottom corner */ switch (wa & 0x06) { - case 0: DrawGroundSprite(SPR_CANALS_BASE + 57 + 5, PAL_NONE); break; - case 6: if (!IsWateredTile(TILE_ADDXY(tile, 1, 1))) DrawGroundSprite(SPR_CANALS_BASE + 57 + 9, PAL_NONE); break; + case 0: DrawGroundSprite(dikes_base + 5, PAL_NONE); break; + case 6: if (!IsWateredTile(TILE_ADDXY(tile, 1, 1))) DrawGroundSprite(dikes_base + 9, PAL_NONE); break; } /* left corner */ switch (wa & 0x0C) { - case 0: DrawGroundSprite(SPR_CANALS_BASE + 57 + 6, PAL_NONE); break; - case 12: if (!IsWateredTile(TILE_ADDXY(tile, 1, -1))) DrawGroundSprite(SPR_CANALS_BASE + 57 + 10, PAL_NONE); break; + case 0: DrawGroundSprite(dikes_base + 6, PAL_NONE); break; + case 12: if (!IsWateredTile(TILE_ADDXY(tile, 1, -1))) DrawGroundSprite(dikes_base + 10, PAL_NONE); break; } /* upper corner */ switch (wa & 0x09) { - case 0: DrawGroundSprite(SPR_CANALS_BASE + 57 + 7, PAL_NONE); break; - case 9: if (!IsWateredTile(TILE_ADDXY(tile, -1, -1))) DrawGroundSprite(SPR_CANALS_BASE + 57 + 11, PAL_NONE); break; + case 0: DrawGroundSprite(dikes_base + 7, PAL_NONE); break; + case 9: if (!IsWateredTile(TILE_ADDXY(tile, -1, -1))) DrawGroundSprite(dikes_base + 11, PAL_NONE); break; } } @@ -421,12 +426,30 @@ static void DrawWaterStuff(const TileInfo *ti, const WaterDrawTileStruct *wdts, SpriteID palette, uint base ) { - DrawGroundSprite(wdts++->image, PAL_NONE); + SpriteID image; + SpriteID water_base = GetCanalSprite(CF_WATERSLOPE, ti->tile); + SpriteID locks_base = GetCanalSprite(CF_LOCKS, ti->tile); + + /* If no custom graphics, use defaults */ + if (water_base == 0) water_base = SPR_CANALS_BASE + 5; + if (locks_base == 0) { + locks_base = SPR_CANALS_BASE + 9; + } else { + /* If using custom graphics, ignore the variation on height */ + base = 0; + } + + image = wdts++->image; + if (image < 4) image += water_base; + DrawGroundSprite(image, PAL_NONE); for (; wdts->delta_x != 0x80; wdts++) { - SpriteID image = wdts->image + base; + SpriteID image = wdts->image; SpriteID pal; + if (image < 24) image += locks_base; + image += base; + if (HASBIT(_transparent_opt, TO_BUILDINGS)) { SETBIT(image, PALETTE_MODIFIER_TRANSPARENT); pal = PALETTE_TO_TRANSPARENT;