diff options
author | Darkvater <darkvater@openttd.org> | 2006-04-15 21:27:59 +0000 |
---|---|---|
committer | Darkvater <darkvater@openttd.org> | 2006-04-15 21:27:59 +0000 |
commit | 12770adba6ebe0f1340b372005d484edff243d03 (patch) | |
tree | 4f0c15b00857a9afbce5e839f851c60bb9a7d198 | |
parent | d63fad7a7b7e0ff6bc6c32f119042a0317961255 (diff) | |
download | openttd-12770adba6ebe0f1340b372005d484edff243d03.tar.xz |
(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.
-rw-r--r-- | newgrf.c | 96 | ||||
-rw-r--r-- | newgrf.h | 9 |
2 files changed, 97 insertions, 8 deletions
@@ -38,7 +38,7 @@ static GRFFile *_cur_grffile; 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 @@ static void SkipIf(byte *buf, int len) 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 @@ static void SkipIf(byte *buf, int len) } 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 @@ static void GRFComment(byte *buf, int len) /* <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 GRFInhibit(byte *buf, int len) } } +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 @@ static void ResetNewGRFData(void) 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 @@ static void DecodeSpecialSprite(uint num, uint stage) { /* 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 @@ static void DecodeSpecialSprite(uint num, uint stage) /* 0x0D */ ParamSet, /* 0x0E */ GRFInhibit, /* 0x0F */ NULL, // TODO implement - /* 0x10 */ NULL // TODO implement + /* 0x10 */ DefineGotoLabel, }; byte* buf = malloc(num); @@ -2520,7 +2599,7 @@ static void DecodeSpecialSprite(uint num, uint stage) 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 @@ static void LoadNewGRFFile(const char* filename, uint file_index, uint stage) 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 @@ void LoadNewGRF(uint load_index, uint file_index) * 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 @@ void LoadNewGRF(uint load_index, uint file_index) } 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); } } @@ -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 @@ struct GRFFile { 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; |