summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--newgrf.c121
1 files changed, 100 insertions, 21 deletions
diff --git a/newgrf.c b/newgrf.c
index 9b3c06bce..ed2eee750 100644
--- a/newgrf.c
+++ b/newgrf.c
@@ -53,6 +53,9 @@ static byte _misc_grf_features = 0;
/* 32 * 8 = 256 flags. Apparently TTDPatch uses this many.. */
static uint32 _ttdpatch_flags[8];
+/* Used by Action 0x06 to preload a pseudo sprite and modify its content */
+static byte *_preload_sprite = NULL;
+
typedef enum grfspec_feature {
GSF_TRAIN,
@@ -1939,23 +1942,6 @@ static void GraphicsNew(byte *buf, int len)
}
}
-/* Action 0x06 */
-static void CfgApply(byte *buf, int len)
-{
- /* <06> <param-num> <param-size> <offset> ... <FF>
- *
- * B param-num Number of parameter to substitute (First = "zero")
- * Ignored if that parameter was not specified in newgrf.cfg
- * B param-size How many bytes to replace. If larger than 4, the
- * bytes of the following parameter are used. In that
- * case, nothing is applied unless *all* parameters
- * were specified.
- * B offset Offset into data from beginning of next sprite
- * to place where parameter is to be stored. */
- /* TODO */
- grfmsg(GMS_NOTICE, "CfgApply: Ignoring (not implemented).\n");
-}
-
static uint32 GetParamVal(byte param, uint32 *cond_val)
{
switch (param) {
@@ -2014,6 +2000,86 @@ static uint32 GetParamVal(byte param, uint32 *cond_val)
}
}
+/* Action 0x06 */
+static void CfgApply(byte *buf, int len)
+{
+ /* <06> <param-num> <param-size> <offset> ... <FF>
+ *
+ * B param-num Number of parameter to substitute (First = "zero")
+ * Ignored if that parameter was not specified in newgrf.cfg
+ * B param-size How many bytes to replace. If larger than 4, the
+ * bytes of the following parameter are used. In that
+ * case, nothing is applied unless *all* parameters
+ * were specified.
+ * B offset Offset into data from beginning of next sprite
+ * to place where parameter is to be stored. */
+
+ /* Preload the next sprite */
+ uint32 pos = FioGetPos();
+ uint16 num = FioReadWord();
+ uint8 type = FioReadByte();
+
+ /* Check if the sprite is a pseudo sprite. We can't operate on real sprites. */
+ if (type == 0xFF) {
+ _preload_sprite = malloc(num);
+ FioReadBlock(_preload_sprite, num);
+ }
+
+ /* Reset the file position to the start of the next sprite */
+ FioSeekTo(pos, SEEK_SET);
+
+ if (type != 0xFF) {
+ grfmsg(GMS_NOTICE, "CfgApply: Ignoring (next sprite is real, unsupported)");
+ return;
+ }
+
+ /* Now perform the Action 0x06 on our data. */
+ buf++;
+
+ for (;;) {
+ uint i;
+ uint param_num;
+ uint param_size;
+ uint offset;
+ bool add_value;
+
+ /* Read the parameter to apply. 0xFF indicates no more data to change. */
+ param_num = grf_load_byte(&buf);
+ if (param_num == 0xFF) break;
+
+ /* Get the size of the parameter to use. If the size covers multiple
+ * double words, sequential parameter values are used. */
+ param_size = grf_load_byte(&buf);
+
+ /* Bit 7 of param_size indicates we should add to the original value
+ * instead of replacing it. */
+ add_value = HASBIT(param_size, 7);
+ param_size = GB(param_size, 0, 7);
+
+ /* Where to apply the data to within the pseudo sprite data. */
+ offset = grf_load_extended(&buf);
+
+ /* If the parameter is a GRF parameter (not an internal variable) check
+ * if it (and all further sequential parameters) has been defined. */
+ if (param_num < 0x80 && (param_num + (param_size - 1) / 4) >= _cur_grffile->param_end) {
+ grfmsg(GMS_NOTICE, "CfgApply: Ignoring (param %d not set)", (param_num + (param_size - 1) / 4));
+ break;
+ }
+
+ DEBUG(grf, 8) ("CfgApply: Applying %u bytes from parameter 0x%02X at offset 0x%04X", param_size, param_num, offset);
+
+ for (i = 0; i < param_size; i++) {
+ uint32 value = GetParamVal(param_num + i / 4, NULL);
+
+ if (add_value) {
+ _preload_sprite[offset + i] += GB(value, (i % 4) * 8, 8);
+ } else {
+ _preload_sprite[offset + i] = GB(value, (i % 4) * 8, 8);
+ }
+ }
+ }
+}
+
/* Action 0x07 */
/* Action 0x09 */
static void SkipIf(byte *buf, int len)
@@ -2771,7 +2837,7 @@ static void DecodeSpecialSprite(uint num, uint stage)
/* We need a pre-stage to set up GOTO labels of Action 0x10 because the grf
* is not in memory and scanning the file every time would be too expensive.
* In other stages we skip action 0x10 since it's already dealt with. */
- static const uint32 action_mask[] = {0x10000, 0x0000FB40, 0x0000FFBF};
+ static const uint32 action_mask[] = {0x10000, 0x0000FB40, 0x0000FFFF};
static const SpecialSpriteHandler handlers[] = {
/* 0x00 */ FeatureChangeInfo,
@@ -2793,12 +2859,25 @@ static void DecodeSpecialSprite(uint num, uint stage)
/* 0x10 */ DefineGotoLabel,
};
- byte* buf = malloc(num);
+ byte* buf;
byte action;
- if (buf == NULL) error("DecodeSpecialSprite: Could not allocate memory");
+ if (_preload_sprite == NULL) {
+ /* No preloaded sprite to work with; allocate and read the
+ * pseudo sprite content. */
+ buf = malloc(num);
+ if (buf == NULL) error("DecodeSpecialSprite: Could not allocate memory");
+ FioReadBlock(buf, num);
+ } else {
+ /* Use the preloaded sprite data. */
+ buf = _preload_sprite;
+ _preload_sprite = NULL;
+ DEBUG(grf, 7) ("DecodeSpecialSprite: Using preloaded pseudo sprite data");
+
+ /* Skip the real (original) content of this action. */
+ FioSeekTo(num, SEEK_CUR);
+ }
- FioReadBlock(buf, num);
action = buf[0];
if (action >= lengthof(handlers)) {