Mercurial > hg > openttd
changeset 3561:a3e82fe897d1 draft
(svn r4439) - NewGRF: Add support for Action 0x10. This also required an extra pre-stage (before initialize and activation) to scan the GRF file for GOTO labels. Big thanks for peter1138 for the guidance and answers, as well as parts of the code.
author | Darkvater <Darkvater@openttd.org> |
---|---|
date | Sat, 15 Apr 2006 21:27:59 +0000 |
parents | 895599c22104 |
children | 270c3c68569b |
files | newgrf.c newgrf.h |
diffstat | 2 files changed, 97 insertions(+), 8 deletions(-) [+] |
line wrap: on
line diff
--- a/newgrf.c +++ b/newgrf.c @@ -38,7 +38,7 @@ GRFFile *_first_grffile; static int _cur_spriteid; static int _cur_stage; -static int _nfo_line; +static uint32 _nfo_line; /* 32 * 8 = 256 flags. Apparently TTDPatch uses this many.. */ static uint32 _ttdpatch_flags[8]; @@ -1849,6 +1849,8 @@ uint32 param_val = 0; uint32 cond_val = 0; bool result; + GRFLabel *label; + GRFLabel *choice = NULL; check_length(len, 6, "SkipIf"); param = buf[1]; @@ -1947,6 +1949,30 @@ } numsprites = grf_load_byte(&buf); + + /* numsprites can be a GOTO label if it has been defined in the GRF + * file. The jump will always be the first matching label that follows + * the current nfo_line. If no matching label is found, the first matching + * label in the file is used. */ + for (label = _cur_grffile->label; label != NULL; label = label->next) { + if (label->label != numsprites) continue; + + /* Remember a goto before the current line */ + if (choice == NULL) choice = label; + /* If we find a label here, this is definitely good */ + if (label->nfo_line > _nfo_line) { + choice = label; + break; + } + } + + if (choice != NULL) { + grfmsg(GMS_NOTICE, "Jumping to label 0x%0X at line %d, test was true.", choice->label, choice->nfo_line); + FioSeekTo(choice->pos, SEEK_SET); + _nfo_line = choice->nfo_line; + return; + } + grfmsg(GMS_NOTICE, "Skipping %d sprites, test was true.", numsprites); _skip_sprites = numsprites; if (_skip_sprites == 0) { @@ -2065,6 +2091,12 @@ /* <0C> [<ignored...>] * * V ignored Anything following the 0C is ignored */ + + static char comment[256]; + if (len == 1) return; + + ttd_strlcpy(comment, buf + 1, minu(sizeof(comment), len)); + grfmsg(GMS_NOTICE, "GRFComment: %s", comment); } /* Action 0x0D */ @@ -2278,6 +2310,36 @@ } } +static void DefineGotoLabel(byte *buf, int len) +{ + /* <10> <label> [<comment>] + * + * B label The label to define + * V comment Optional comment - ignored */ + + GRFLabel *label; + + check_length(len, 1, "GRFLabel"); + buf++; len--; + + label = malloc(sizeof(*label)); + label->label = grf_load_byte(&buf); + label->nfo_line = _nfo_line; + label->pos = FioGetPos(); + label->next = NULL; + + /* Set up a linked list of goto targets which we will search in an Action 0x7/0x9 */ + if (_cur_grffile->label == NULL) { + _cur_grffile->label = label; + } else { + /* Attach the label to the end of the list */ + GRFLabel *l; + for (l = _cur_grffile->label; l->next != NULL; l = l->next); + l->next = label; + } + + grfmsg(GMS_NOTICE, "DefineGotoLabel: GOTO target with label 0x%X", label->label); +} static void InitializeGRFSpecial(void) { @@ -2410,6 +2472,19 @@ AddTypeToEngines(); } +/** Reset all NewGRFData that was used only while processing data */ +static void ClearTemporaryNewGRFData(void) +{ + /* Clear the GOTO labels used for GRF processing */ + GRFLabel *l; + for (l = _cur_grffile->label; l != NULL;) { + GRFLabel *l2 = l->next; + free(l); + l = l2; + } + _cur_grffile->label = NULL; +} + static void InitNewGRFFile(const char* filename, int sprite_offset) { GRFFile *newfile; @@ -2482,14 +2557,18 @@ { /* XXX: There is a difference between staged loading in TTDPatch and * here. In TTDPatch, for some reason actions 1 and 2 are carried out - * during stage 0, whilst action 3 is carried out during stage 1 (to + * during stage 1, whilst action 3 is carried out during stage 2 (to * "resolve" cargo IDs... wtf). This is a little problem, because cargo * IDs are valid only within a given set (action 1) block, and may be * overwritten after action 3 associates them. But overwriting happens * in an earlier stage than associating, so... We just process actions - * 1 and 2 in stage 1 now, let's hope that won't get us into problems. + * 1 and 2 in stage 2 now, let's hope that won't get us into problems. * --pasky */ - uint32 action_mask = (stage == 0) ? 0x0001FB40 : 0x0001FFBF; + /* 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 SpecialSpriteHandler handlers[] = { /* 0x00 */ VehicleChangeInfo, /* 0x01 */ NewSpriteSet, @@ -2507,7 +2586,7 @@ /* 0x0D */ ParamSet, /* 0x0E */ GRFInhibit, /* 0x0F */ NULL, // TODO implement - /* 0x10 */ NULL // TODO implement + /* 0x10 */ DefineGotoLabel, }; byte* buf = malloc(num); @@ -2520,7 +2599,7 @@ if (action >= lengthof(handlers)) { DEBUG(grf, 7) ("Skipping unknown action 0x%02X", action); - } else if (!HASBIT(action_mask, action)) { + } else if (!HASBIT(action_mask[stage], action)) { DEBUG(grf, 7) ("Skipping action 0x%02X in stage %d", action, stage); } else if (handlers[action] == NULL) { DEBUG(grf, 7) ("Skipping unsupported Action 0x%02X", action); @@ -2548,7 +2627,7 @@ if (stage != 0) { _cur_grffile = GetFileByFilename(filename); if (_cur_grffile == NULL) error("File ``%s'' lost in cache.\n", filename); - if (!(_cur_grffile->flags & 0x0001)) return; + if (stage > 1 && !(_cur_grffile->flags & 0x0001)) return; } FioOpenFile(file_index, filename); @@ -2624,7 +2703,7 @@ * in each loading stage, (try to) open each file specified in the config * and load information from it. */ _custom_sprites_base = load_index; - for (stage = 0; stage < 2; stage++) { + for (stage = 0; stage <= 2; stage++) { uint slot = file_index; uint j; @@ -2637,6 +2716,7 @@ } if (stage == 0) InitNewGRFFile(_newgrf_files[j], _cur_spriteid); LoadNewGRFFile(_newgrf_files[j], slot++, stage); + if (stage == 2) ClearTemporaryNewGRFData(); DEBUG(spritecache, 2) ("Currently %i sprites are loaded", load_index); } }
--- a/newgrf.h +++ b/newgrf.h @@ -6,6 +6,13 @@ #include "sprite.h" #include "station.h" +typedef struct GRFLabel { + byte label; + uint32 nfo_line; + uint32 pos; + struct GRFLabel *next; +} GRFLabel; + typedef struct GRFFile GRFFile; struct GRFFile { char *filename; @@ -39,6 +46,8 @@ uint32 param[0x80]; uint param_end; /// one more than the highest set parameter + + GRFLabel *label; ///< Pointer to the first label. This is a linked list, not an array. }; extern GRFFile *_first_grffile;