grfspecial.c
changeset 369 3742b39b6cca
parent 368 3ad9aa36606c
child 372 ec1e802872c7
equal deleted inserted replaced
368:3ad9aa36606c 369:3742b39b6cca
   532 	}
   532 	}
   533 #undef shift_buf
   533 #undef shift_buf
   534 }
   534 }
   535 
   535 
   536 
   536 
   537 /* A sprite superset contains all sprites of a given vehicle (or multiple
   537 /* A sprite group contains all sprites of a given vehicle (or multiple
   538  * vehicles) when carrying given cargo. It consists of several sprite sets.
   538  * vehicles) when carrying given cargo. It consists of several sprite sets.
   539  * Superset ids are refered as "cargo id"s by TTDPatch documentation,
   539  * Group ids are refered as "cargo id"s by TTDPatch documentation,
   540  * contributing to the global confusion.
   540  * contributing to the global confusion.
   541  *
   541  *
   542  * A sprite set contains all sprites of a given vehicle carrying given cargo at
   542  * A sprite set contains all sprites of a given vehicle carrying given cargo at
   543  * a given *stage* - that is usually its load stage. Ie. you can have a
   543  * a given *stage* - that is usually its load stage. Ie. you can have a
   544  * spriteset for an empty wagon, wagon full of coal, half-filled wagon etc.
   544  * spriteset for an empty wagon, wagon full of coal, half-filled wagon etc.
   549 static int _spriteset_numsets;
   549 static int _spriteset_numsets;
   550 static int _spriteset_numents;
   550 static int _spriteset_numents;
   551 static int _spriteset_feature;
   551 static int _spriteset_feature;
   552 
   552 
   553 static int _spritesset_count;
   553 static int _spritesset_count;
   554 static struct SpriteSuperSet *_spritesset;
   554 static struct SpriteGroup *_spritesset;
   555 
   555 
   556 /* Action 0x01 */
   556 /* Action 0x01 */
   557 static void SpriteNewSet(byte *buf, int len)
   557 static void NewSpriteSet(byte *buf, int len)
   558 {
   558 {
   559 	/* <01> <feature> <num-sets> <num-ent>
   559 	/* <01> <feature> <num-sets> <num-ent>
   560 	 *
   560 	 *
   561 	 * B feature       feature to define sprites for
   561 	 * B feature       feature to define sprites for
   562 	 *                 0, 1, 2, 3: veh-type, 4: train stations
   562 	 *                 0, 1, 2, 3: veh-type, 4: train stations
   585 	_spriteset_numsets = buf[2];
   585 	_spriteset_numsets = buf[2];
   586 	_spriteset_numents = buf[3];
   586 	_spriteset_numents = buf[3];
   587 }
   587 }
   588 
   588 
   589 /* Action 0x02 */
   589 /* Action 0x02 */
   590 static void SpriteNewSuperset(byte *buf, int len)
   590 static void NewSpriteGroup(byte *buf, int len)
   591 {
   591 {
   592 	byte *bufend = buf + len;
   592 	byte *bufend = buf + len;
   593 
   593 
   594 	/* <02> <feature> <set-id> <type/num-entries> <feature-specific-data...>
   594 	/* <02> <feature> <set-id> <type/num-entries> <feature-specific-data...>
   595 	 *
   595 	 *
   607 	 * when. --pasky */
   607 	 * when. --pasky */
   608 	uint8 feature;
   608 	uint8 feature;
   609 	uint8 setid;
   609 	uint8 setid;
   610 	uint8 numloaded;
   610 	uint8 numloaded;
   611 	uint8 numloading;
   611 	uint8 numloading;
   612 	struct SpriteSuperSet *superset;
   612 	struct SpriteGroup *group;
   613 	int i;
   613 	int i;
   614 
   614 
   615 	check_length(len, 5, "SpriteNewSuperset");
   615 	check_length(len, 5, "SpriteNewGroup");
   616 	feature = buf[1];
   616 	feature = buf[1];
   617 	setid = buf[2];
   617 	setid = buf[2];
   618 	numloaded = buf[3];
   618 	numloaded = buf[3];
   619 	numloading = buf[4];
   619 	numloading = buf[4];
   620 
   620 
   621 	if (feature == 4) {
   621 	if (feature == 4) {
   622 		grfmsg(GMS_WARN, "SpriteNewSuperset: Stations unsupported, skipping.");
   622 		grfmsg(GMS_WARN, "SpriteNewGroup: Stations unsupported, skipping.");
   623 		return;
   623 		return;
   624 	}
   624 	}
   625 
   625 
   626 	if (numloaded == 0x81) {
   626 	if (numloaded == 0x81) {
   627 		// XXX: This is _VERY_ ad hoc just to handle Dm3. And that is
   627 		// XXX: This is _VERY_ ad hoc just to handle Dm3. And that is
   628 		// a semi-futile ask because the great Patchman himself says
   628 		// a semi-futile ask because the great Patchman himself says
   629 		// this is just buggy. It dereferences last (first) byte of
   629 		// this is just buggy. It dereferences last (first) byte of
   630 		// a schedule list pointer of the vehicle and if it's 0xff
   630 		// a schedule list pointer of the vehicle and if it's 0xff
   631 		// it uses superset 01, otherwise it uses superset 00. Now
   631 		// it uses group 01, otherwise it uses group 00. Now
   632 		// if _you_ understand _that_... We just assume it is never
   632 		// if _you_ understand _that_... We just assume it is never
   633 		// 0xff and therefore go for superset 00. --pasky
   633 		// 0xff and therefore go for group 00. --pasky
   634 		uint8 var = buf[4];
   634 		uint8 var = buf[4];
   635 		//uint8 shiftnum = buf[5];
   635 		//uint8 shiftnum = buf[5];
   636 		//uint8 andmask = buf[6];
   636 		//uint8 andmask = buf[6];
   637 		uint8 nvar = buf[7];
   637 		uint8 nvar = buf[7];
   638 		//uint32 val;
   638 		//uint32 val;
   639 		uint16 def;
   639 		uint16 def;
   640 
   640 
   641 		grfmsg(GMS_WARN, "SpriteNewSuperset(0x81): Unsupported variable %x. Using default cid.", var);
   641 		grfmsg(GMS_WARN, "SpriteNewGroup(0x81): Unsupported variable %x. Using default cid.", var);
   642 
   642 
   643 		//val = (0xff << shiftnum) & andmask;
   643 		//val = (0xff << shiftnum) & andmask;
   644 
   644 
   645 		//Go for the default.
   645 		//Go for the default.
   646 		if (setid >= _spritesset_count) {
   646 		if (setid >= _spritesset_count) {
   647 			_spritesset_count = setid + 1;
   647 			_spritesset_count = setid + 1;
   648 			_spritesset = realloc(_spritesset, _spritesset_count * sizeof(struct SpriteSuperSet));
   648 			_spritesset = realloc(_spritesset, _spritesset_count * sizeof(struct SpriteGroup));
   649 		}
   649 		}
   650 		buf += 8 + nvar * 4;
   650 		buf += 8 + nvar * 4;
   651 		def = grf_load_word(&buf);
   651 		def = grf_load_word(&buf);
   652 		_spritesset[setid] = _spritesset[def];
   652 		_spritesset[setid] = _spritesset[def];
   653 		return;
   653 		return;
   654 
   654 
   655 	} else if (numloaded & 0x80) {
   655 	} else if (numloaded & 0x80) {
   656 		grfmsg(GMS_WARN, "SpriteNewSuperset(0x%x): Unsupported special superset.", numloaded);
   656 		grfmsg(GMS_WARN, "SpriteNewGroup(0x%x): Unsupported special group.", numloaded);
   657 		return;
   657 		return;
   658 	}
   658 	}
   659 
   659 
   660 	if (!_spriteset_start) {
   660 	if (!_spriteset_start) {
   661 		grfmsg(GMS_WARN, "SpriteNewSuperset: No sprite set to work on! Skipping.");
   661 		grfmsg(GMS_WARN, "SpriteNewGroup: No sprite set to work on! Skipping.");
   662 		return;
   662 		return;
   663 	}
   663 	}
   664 
   664 
   665 	if (_spriteset_feature != feature) {
   665 	if (_spriteset_feature != feature) {
   666 		grfmsg(GMS_WARN, "SpriteNewSuperset: Superset feature %x doesn't match set feature %x! Skipping.", feature, _spriteset_feature);
   666 		grfmsg(GMS_WARN, "SpriteNewGroup: Group feature %x doesn't match set feature %x! Skipping.", feature, _spriteset_feature);
   667 		return;
   667 		return;
   668 	}
   668 	}
   669 
   669 
   670 	if (setid >= _spritesset_count) {
   670 	if (setid >= _spritesset_count) {
   671 		_spritesset_count = setid + 1;
   671 		_spritesset_count = setid + 1;
   672 		_spritesset = realloc(_spritesset, _spritesset_count * sizeof(struct SpriteSuperSet));
   672 		_spritesset = realloc(_spritesset, _spritesset_count * sizeof(struct SpriteGroup));
   673 	}
   673 	}
   674 	superset = &_spritesset[setid];
   674 	group = &_spritesset[setid];
   675 	memset(superset, 0, sizeof(struct SpriteSuperSet));
   675 	memset(group, 0, sizeof(struct SpriteGroup));
   676 	superset->sprites_per_set = _spriteset_numents;
   676 	group->sprites_per_set = _spriteset_numents;
   677 
   677 
   678 	buf += 5;
   678 	buf += 5;
   679 
   679 
   680 	for (i = 0; buf < bufend && i < numloaded; i++) {
   680 	for (i = 0; buf < bufend && i < numloaded; i++) {
   681 		uint16 spriteset_id = grf_load_word(&buf);
   681 		uint16 spriteset_id = grf_load_word(&buf);
   682 
   682 
   683 		if (_spritesset[setid].loaded_count > 16) {
   683 		if (_spritesset[setid].loaded_count > 16) {
   684 			grfmsg(GMS_WARN, "SpriteNewSuperset: More than 16 sprites in superset %x, skipping.", setid);
   684 			grfmsg(GMS_WARN, "SpriteNewGroup: More than 16 sprites in group %x, skipping.", setid);
   685 			return;
   685 			return;
   686 		}
   686 		}
   687 		superset->loaded[superset->loaded_count++]
   687 		group->loaded[group->loaded_count++]
   688 			= _spriteset_start + spriteset_id * _spriteset_numents;
   688 			= _spriteset_start + spriteset_id * _spriteset_numents;
   689 	}
   689 	}
   690 
   690 
   691 	for (i = 0; buf < bufend && i < numloading; i++) {
   691 	for (i = 0; buf < bufend && i < numloading; i++) {
   692 		uint16 spriteset_id = grf_load_word(&buf);
   692 		uint16 spriteset_id = grf_load_word(&buf);
   693 
   693 
   694 		if (_spritesset[setid].loading_count > 16) {
   694 		if (_spritesset[setid].loading_count > 16) {
   695 			grfmsg(GMS_WARN, "SpriteNewSuperset: More than 16 sprites in superset %x, skipping.", setid);
   695 			grfmsg(GMS_WARN, "SpriteNewGroup: More than 16 sprites in group %x, skipping.", setid);
   696 			return;
   696 			return;
   697 		}
   697 		}
   698 		superset->loading[superset->loading_count++] = _spriteset_start + spriteset_id * _spriteset_numents;
   698 		group->loading[group->loading_count++] = _spriteset_start + spriteset_id * _spriteset_numents;
   699 	}
   699 	}
   700 }
   700 }
   701 
   701 
   702 /* Action 0x03 */
   702 /* Action 0x03 */
   703 static void VehicleMapSpriteSuperset(byte *buf, int len)
   703 static void NewVehicle_SpriteGroupMapping(byte *buf, int len)
   704 {
   704 {
   705 	/* <03> <feature> <n-id> <ids>... <num-cid> [<cargo-type> <cid>]... <def-cid>
   705 	/* <03> <feature> <n-id> <ids>... <num-cid> [<cargo-type> <cid>]... <def-cid>
   706 	 * id-list	:= [<id>] [id-list]
   706 	 * id-list	:= [<id>] [id-list]
   707 	 * cargo-list	:= <cargo-type> <cid> [cargo-list]
   707 	 * cargo-list	:= <cargo-type> <cid> [cargo-list]
   708 	 *
   708 	 *
   709 	 * B feature       see action 0
   709 	 * B feature       see action 0
   710 	 * B n-id          bits 0-6: how many IDs this definition applies to
   710 	 * B n-id          bits 0-6: how many IDs this definition applies to
   711 	 *                 bit 7: if set, this is a wagon override definition (see below)
   711 	 *                 bit 7: if set, this is a wagon override definition (see below)
   712 	 * B ids           the IDs for which this definition applies
   712 	 * B ids           the IDs for which this definition applies
   713 	 * B num-cid       number of cargo IDs in this definition
   713 	 * B num-cid       number of cargo IDs (sprite group IDs) in this definition
   714 	 *                 can be zero, in that case the def-cid is used always
   714 	 *                 can be zero, in that case the def-cid is used always
   715 	 * B cargo-type    type of this cargo type (e.g. mail=2, wood=7, see below)
   715 	 * B cargo-type    type of this cargo type (e.g. mail=2, wood=7, see below)
   716 	 * W cid           cargo ID for this type of cargo
   716 	 * W cid           cargo ID (sprite group ID) for this type of cargo
   717 	 * W def-cid       default cargo ID */
   717 	 * W def-cid       default cargo ID (sprite group ID) */
   718 	/* TODO: Only trains supported now. */
   718 	/* TODO: Only trains supported now. */
   719 	/* TODO: Multiple cargo support could be useful even for trains/cars -
   719 	/* TODO: Multiple cargo support could be useful even for trains/cars -
   720 	 * cargo id 0xff is used for showing images in the build train list. */
   720 	 * cargo id 0xff is used for showing images in the build train list. */
   721 
   721 
   722 	static byte *last_engines;
   722 	static byte *last_engines;
   725 	uint8 idcount;
   725 	uint8 idcount;
   726 	int wagover;
   726 	int wagover;
   727 	uint8 cidcount;
   727 	uint8 cidcount;
   728 	int c, i;
   728 	int c, i;
   729 
   729 
   730 	check_length(len, 7, "VehicleMapSpriteSuperset");
   730 	check_length(len, 7, "VehicleMapSpriteGroup");
   731 	feature = buf[1];
   731 	feature = buf[1];
   732 	idcount = buf[2] & 0x7F;
   732 	idcount = buf[2] & 0x7F;
   733 	wagover = buf[2] & 0x80;
   733 	wagover = buf[2] & 0x80;
   734 	cidcount = buf[3 + idcount];
   734 	cidcount = buf[3 + idcount];
   735 
   735 
   736 	if (feature == 4) {
   736 	if (feature == 4) {
   737 		grfmsg(GMS_WARN, "VehicleMapSpriteSuperset: Stations unsupported, skipping.");
   737 		grfmsg(GMS_WARN, "VehicleMapSpriteGroup: Stations unsupported, skipping.");
   738 		return;
   738 		return;
   739 	}
   739 	}
   740 
   740 
   741 	// FIXME: Tropicset contains things like:
   741 	// FIXME: Tropicset contains things like:
   742 	// 03 00 01 19 01 00 00 00 00 - this is missing one 00 at the end,
   742 	// 03 00 01 19 01 00 00 00 00 - this is missing one 00 at the end,
   743 	// what should we exactly do with that? --pasky
   743 	// what should we exactly do with that? --pasky
   744 
   744 
   745 	if (!_spriteset_start || !_spritesset) {
   745 	if (!_spriteset_start || !_spritesset) {
   746 		grfmsg(GMS_WARN, "VehicleMapSpriteSuperset: No sprite set to work on! Skipping.");
   746 		grfmsg(GMS_WARN, "VehicleMapSpriteGroup: No sprite set to work on! Skipping.");
   747 		return;
   747 		return;
   748 	}
   748 	}
   749 
   749 
   750 	if (!wagover && last_engines_count != idcount) {
   750 	if (!wagover && last_engines_count != idcount) {
   751 		last_engines = realloc(last_engines, idcount);
   751 		last_engines = realloc(last_engines, idcount);
   756 		uint8 engine = buf[3 + i] + _vehshifts[feature];
   756 		uint8 engine = buf[3 + i] + _vehshifts[feature];
   757 		byte *bp = &buf[4 + idcount];
   757 		byte *bp = &buf[4 + idcount];
   758 
   758 
   759 		for (c = 0; c < cidcount; c++) {
   759 		for (c = 0; c < cidcount; c++) {
   760 			uint8 ctype = grf_load_byte(&bp);
   760 			uint8 ctype = grf_load_byte(&bp);
   761 			uint16 supersetid = grf_load_word(&bp);
   761 			uint16 groupid = grf_load_word(&bp);
   762 
   762 
   763 			if (supersetid >= _spritesset_count) {
   763 			if (groupid >= _spritesset_count) {
   764 				grfmsg(GMS_WARN, "VehicleMapSpriteSuperset: Spriteset %x out of range %x, skipping.", supersetid, _spritesset_count);
   764 				grfmsg(GMS_WARN, "VehicleMapSpriteGroup: Spriteset %x out of range %x, skipping.", groupid, _spritesset_count);
   765 				return;
   765 				return;
   766 			}
   766 			}
   767 
   767 
   768 			if (ctype == 0xFF)
   768 			if (ctype == 0xFF)
   769 				ctype = CID_PURCHASE;
   769 				ctype = CID_PURCHASE;
   770 
   770 
   771 			if (wagover) {
   771 			if (wagover) {
   772 				// TODO: No multiple cargo types per vehicle yet. --pasky
   772 				// TODO: No multiple cargo types per vehicle yet. --pasky
   773 				SetWagonOverrideSprites(engine, &_spritesset[supersetid], last_engines, last_engines_count);
   773 				SetWagonOverrideSprites(engine, &_spritesset[groupid], last_engines, last_engines_count);
   774 			} else {
   774 			} else {
   775 				SetCustomEngineSprites(engine, ctype, &_spritesset[supersetid]);
   775 				SetCustomEngineSprites(engine, ctype, &_spritesset[groupid]);
   776 				last_engines[i] = engine;
   776 				last_engines[i] = engine;
   777 			}
   777 			}
   778 		}
   778 		}
   779 	}
   779 	}
   780 
   780 
   781 	{
   781 	{
   782 		byte *bp = buf + 4 + idcount + cidcount * 3;
   782 		byte *bp = buf + 4 + idcount + cidcount * 3;
   783 		uint16 supersetid = grf_load_word(&bp);
   783 		uint16 groupid = grf_load_word(&bp);
   784 
   784 
   785 		for (i = 0; i < idcount; i++) {
   785 		for (i = 0; i < idcount; i++) {
   786 			uint8 engine = buf[3 + i] + _vehshifts[feature];
   786 			uint8 engine = buf[3 + i] + _vehshifts[feature];
   787 
   787 
   788 			// Don't tell me you don't love duplicated code!
   788 			// Don't tell me you don't love duplicated code!
   789 			if (supersetid >= _spritesset_count) {
   789 			if (groupid >= _spritesset_count) {
   790 				grfmsg(GMS_WARN, "VehicleMapSpriteSuperset: Spriteset %x out of range %x, skipping.", supersetid, _spritesset_count);
   790 				grfmsg(GMS_WARN, "VehicleMapSpriteGroup: Spriteset %x out of range %x, skipping.", groupid, _spritesset_count);
   791 				return;
   791 				return;
   792 			}
   792 			}
   793 
   793 
   794 			if (wagover) {
   794 			if (wagover) {
   795 				// TODO: No multiple cargo types per vehicle yet. --pasky
   795 				// TODO: No multiple cargo types per vehicle yet. --pasky
   796 				SetWagonOverrideSprites(engine, &_spritesset[supersetid], last_engines, last_engines_count);
   796 				SetWagonOverrideSprites(engine, &_spritesset[groupid], last_engines, last_engines_count);
   797 			} else {
   797 			} else {
   798 				SetCustomEngineSprites(engine, CID_DEFAULT, &_spritesset[supersetid]);
   798 				SetCustomEngineSprites(engine, CID_DEFAULT, &_spritesset[groupid]);
   799 				last_engines[i] = engine;
   799 				last_engines[i] = engine;
   800 			}
   800 			}
   801 		}
   801 		}
   802 	}
   802 	}
   803 }
   803 }
  1302 void DecodeSpecialSprite(const char *filename, int num, int spriteid, int stage)
  1302 void DecodeSpecialSprite(const char *filename, int num, int spriteid, int stage)
  1303 {
  1303 {
  1304 #define NUM_ACTIONS 0xF
  1304 #define NUM_ACTIONS 0xF
  1305 	static const SpecialSpriteHandler handlers[NUM_ACTIONS] = {
  1305 	static const SpecialSpriteHandler handlers[NUM_ACTIONS] = {
  1306 		/* 0x0 */ VehicleChangeInfo,
  1306 		/* 0x0 */ VehicleChangeInfo,
  1307 		/* 0x1 */ SpriteNewSet,
  1307 		/* 0x1 */ NewSpriteSet,
  1308 		/* 0x2 */ SpriteNewSuperset,
  1308 		/* 0x2 */ NewSpriteGroup,
  1309 		/* 0x3 */ VehicleMapSpriteSuperset,
  1309 		/* 0x3 */ NewVehicle_SpriteGroupMapping,
  1310 		/* 0x4 */ VehicleNewName,
  1310 		/* 0x4 */ VehicleNewName,
  1311 		/* 0x5 */ GraphicsNew,
  1311 		/* 0x5 */ GraphicsNew,
  1312 		/* 0x6 */ CfgApply,
  1312 		/* 0x6 */ CfgApply,
  1313 		/* 0x7 */ SkipIf,
  1313 		/* 0x7 */ SkipIf,
  1314 		/* 0x8 */ GRFInfo,
  1314 		/* 0x8 */ GRFInfo,
  1339 
  1339 
  1340 	action = buf[0];
  1340 	action = buf[0];
  1341 
  1341 
  1342 	/* XXX: Action 0x03 is temporarily processed together with actions 0x01
  1342 	/* XXX: Action 0x03 is temporarily processed together with actions 0x01
  1343 	 * and 0x02 before it is fixed to be reentrant (probably storing the
  1343 	 * and 0x02 before it is fixed to be reentrant (probably storing the
  1344 	 * superset information in {struct GRFFile}). --pasky */
  1344 	 * group information in {struct GRFFile}). --pasky */
  1345 
  1345 
  1346 	if (stage == 0) {
  1346 	if (stage == 0) {
  1347 		/* During initialization, actions 0, 3, 4, 5 and 7 are ignored. */
  1347 		/* During initialization, actions 0, 3, 4, 5 and 7 are ignored. */
  1348 
  1348 
  1349 		if ((action == 0x00) /*|| (action == 0x03)*/ || (action == 0x04)
  1349 		if ((action == 0x00) /*|| (action == 0x03)*/ || (action == 0x04)