(svn r10508) -Codechange: allow customizable animation schemes for industries.
authorrubidium
Wed, 11 Jul 2007 15:03:29 +0000
changeset 7229 a5f262f6df1b
parent 7228 24f0a19ca622
child 7230 1da1567909fc
(svn r10508) -Codechange: allow customizable animation schemes for industries.
src/economy.cpp
src/industry.h
src/industry_cmd.cpp
src/newgrf.cpp
src/newgrf_callbacks.h
src/newgrf_industrytiles.cpp
src/newgrf_industrytiles.h
src/table/build_industry.h
--- a/src/economy.cpp	Wed Jul 11 08:35:14 2007 +0000
+++ b/src/economy.cpp	Wed Jul 11 15:03:29 2007 +0000
@@ -36,6 +36,7 @@
 #include "newgrf_sound.h"
 #include "newgrf_callbacks.h"
 #include "newgrf_industries.h"
+#include "newgrf_industrytiles.h"
 #include "unmovable.h"
 #include "date.h"
 #include "cargotype.h"
@@ -1251,6 +1252,8 @@
 			best->produced_cargo_waiting[0] = min(best->produced_cargo_waiting[0] + (num_pieces * indspec->input_cargo_multiplier[accepted_cargo_index][0] / 256), 0xFFFF);
 			best->produced_cargo_waiting[1] = min(best->produced_cargo_waiting[1] + (num_pieces * indspec->input_cargo_multiplier[accepted_cargo_index][1] / 256), 0xFFFF);
 		}
+
+		StartStopIndustryTileAnimation(best, IAT_INDUSTRY_RECEIVED_CARGO);
 	}
 }
 
--- a/src/industry.h	Wed Jul 11 08:35:14 2007 +0000
+++ b/src/industry.h	Wed Jul 11 15:03:29 2007 +0000
@@ -186,6 +186,10 @@
 	                                      ///< state instead of the construction state
 	/* Newgrf data */
 	uint8 callback_flags;                 ///< Flags telling which grf callback is set
+	uint16 animation_info;                ///< Information about the animation (is it looping, how many loops etc)
+	uint8 animation_speed;                ///< The speed of the animation
+	uint8 animation_triggers;             ///< When to start the animation
+	uint8 animation_special_flags;        ///< Extra flags to influence the animation
 	bool enabled;                         ///< entity still avaible (by default true).newgrf can disable it, though
 	struct GRFFileProps grf_prop;
 };
--- a/src/industry_cmd.cpp	Wed Jul 11 08:35:14 2007 +0000
+++ b/src/industry_cmd.cpp	Wed Jul 11 15:03:29 2007 +0000
@@ -413,7 +413,7 @@
 
 		am = MoveGoodsToStation(i->xy, i->width, i->height, indspec->produced_cargo[0], cw);
 		i->this_month_transported[0] += am;
-		if (am != 0) {
+		if (am != 0 && !StartStopIndustryTileAnimation(i, IAT_INDUSTRY_DISTRIBUTES_CARGO)) {
 			uint newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_production;
 
 			if (newgfx != INDUSTRYTILE_NOANIM) {
@@ -442,8 +442,14 @@
 static void AnimateTile_Industry(TileIndex tile)
 {
 	byte m;
+	IndustryGfx gfx = GetIndustryGfx(tile);
 
-	switch (GetIndustryGfx(tile)) {
+	if (GetIndustryTileSpec(gfx)->animation_info != 0xFFFF) {
+		AnimateNewIndustryTile(tile);
+		return;
+	}
+
+	switch (gfx) {
 	case GFX_SUGAR_MINE_SIEVE:
 		if ((_tick_counter & 1) == 0) {
 			m = GetIndustryAnimationState(tile) + 1;
@@ -629,6 +635,7 @@
 	stage = GetIndustryConstructionStage(tile) + 1;
 	SetIndustryConstructionCounter(tile, 0);
 	SetIndustryConstructionStage(tile, stage);
+	StartStopIndustryTileAnimation(tile, IAT_CONSTRUCTION_STATE_CHANGE);
 	if (stage == 3) {
 		SetIndustryCompleted(tile, true);
 	}
@@ -637,7 +644,15 @@
 
 	if (!IsIndustryCompleted(tile)) return;
 
-	switch (GetIndustryGfx(tile)) {
+	IndustryGfx gfx = GetIndustryGfx(tile);
+	if (gfx >= NEW_INDUSTRYTILEOFFSET) {
+		/* New industry */
+		const IndustryTileSpec *its = GetIndustryTileSpec(gfx);
+		if (its->animation_info != 0xFFFF) AddAnimatedTile(tile);
+		return;
+	}
+
+	switch (gfx) {
 	case GFX_POWERPLANT_CHIMNEY:
 		CreateIndustryEffectSmoke(tile);
 		break;
@@ -701,6 +716,8 @@
 
 	TransportIndustryGoods(tile);
 
+	if (StartStopIndustryTileAnimation(tile, IAT_TILELOOP)) return;
+
 	newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_next;
 	if (newgfx != INDUSTRYTILE_NOANIM) {
 		ResetIndustryConstructionStage(tile);
@@ -1032,6 +1049,7 @@
 	if (_game_mode == GM_EDITOR) return;
 
 	FOR_ALL_INDUSTRIES(i) {
+		StartStopIndustryTileAnimation(i, IAT_INDUSTRY_TICK);
 		ProduceIndustryGoods(i);
 	}
 }
--- a/src/newgrf.cpp	Wed Jul 11 08:35:14 2007 +0000
+++ b/src/newgrf.cpp	Wed Jul 11 15:03:29 2007 +0000
@@ -1765,19 +1765,19 @@
 				break;
 
 			case 0x0F: // Animation information
-				grf_load_word(&buf); // TODO
+				tsp->animation_info = grf_load_word(&buf);
 				break;
 
 			case 0x10: // Animation speed
-				grf_load_byte(&buf); // TODO
+				tsp->animation_speed = grf_load_byte(&buf);
 				break;
 
 			case 0x11: // Triggers for callback 25
-				grf_load_byte(&buf); // TODO
+				tsp->animation_triggers = grf_load_byte(&buf);
 				break;
 
 			case 0x12: // Special flags
-				grf_load_byte(&buf); // TODO
+				tsp->animation_special_flags = grf_load_byte(&buf);
 				break;
 
 			default:
--- a/src/newgrf_callbacks.h	Wed Jul 11 08:35:14 2007 +0000
+++ b/src/newgrf_callbacks.h	Wed Jul 11 15:03:29 2007 +0000
@@ -85,13 +85,13 @@
 	CBID_STATION_TILE_LAYOUT             = 0x24,
 
 	/** Called for periodically starting or stopping the animation. */
-	CBID_INDTILE_ANIM_START_STOP         = 0x25, // not implemented
+	CBID_INDTILE_ANIM_START_STOP         = 0x25,
 
 	/** Called to determine industry tile next animation frame. */
-	CBID_INDTILE_ANIM_NEXT_FRAME         = 0x26, // not implemented
+	CBID_INDTILE_ANIM_NEXT_FRAME         = 0x26,
 
 	/** Called to indicate how long the current animation frame should last. */
-	CBID_INDTILE_ANIMATION_SPEED         = 0x27, // not implemented
+	CBID_INDTILE_ANIMATION_SPEED         = 0x27,
 
 	/** Called to determine if the given industry can be built on specific area. */
 	CBID_INDUSTRY_LOCATION               = 0x28,
--- a/src/newgrf_industrytiles.cpp	Wed Jul 11 08:35:14 2007 +0000
+++ b/src/newgrf_industrytiles.cpp	Wed Jul 11 15:03:29 2007 +0000
@@ -15,6 +15,7 @@
 #include "newgrf_spritegroup.h"
 #include "newgrf_callbacks.h"
 #include "newgrf_industries.h"
+#include "newgrf_industrytiles.h"
 #include "newgrf_text.h"
 #include "industry_map.h"
 #include "clear_map.h"
@@ -249,3 +250,104 @@
 		default: _error_message = GetGRFStringID(its->grf_prop.grffile->grfid, 0xD000 + callback_res); return false;
 	}
 }
+
+void AnimateNewIndustryTile(TileIndex tile)
+{
+	Industry *ind = GetIndustryByTile(tile);
+	IndustryGfx gfx = GetIndustryGfx(tile);
+	const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
+	byte animation_speed = itspec->animation_speed;
+
+	if (HASBIT(itspec->callback_flags, CBM_INDT_ANIM_SPEED)) {
+		uint16 callback_res = GetIndustryTileCallback(CBID_INDTILE_ANIMATION_SPEED, 0, 0, gfx, ind, tile);
+		if (callback_res != CALLBACK_FAILED) animation_speed = clamp(callback_res & 0xFF, 0, 16);
+	}
+
+	/* An animation speed of 2 means the animation frame changes 4 ticks, and
+	 * increasing this value by one doubles the wait. 0 is the minimum value
+	 * allowed for animation_speed, which corresponds to 30ms, and 16 is the
+	 * maximum, corresponding to around 33 minutes. */
+	if ((_tick_counter % (1 << animation_speed)) != 0) return;
+
+	bool frame_set_by_callback = false;
+	byte frame = GetIndustryAnimationState(tile);
+	uint16 num_frames = GB(itspec->animation_info, 0, 8) + 1;
+
+	if (HASBIT(itspec->callback_flags, CBM_INDT_ANIM_NEXT_FRAME)) {
+		uint16 callback_res = GetIndustryTileCallback(CBID_INDTILE_ANIM_NEXT_FRAME, HASBIT(itspec->animation_special_flags, 0) ? Random() : 0, 0, gfx, ind, tile);
+
+		if (callback_res != CALLBACK_FAILED) {
+			frame_set_by_callback = true;
+
+			switch (callback_res & 0xFF) {
+				case 0xFF:
+					DeleteAnimatedTile(tile);
+					break;
+				case 0xFE:
+					/* Carry on as normal. */
+					frame_set_by_callback = false;
+					break;
+				default:
+					frame = callback_res & 0xFF;
+					break;
+			}
+		}
+	}
+
+	if (!frame_set_by_callback) {
+		if (frame < num_frames) {
+			frame++;
+		} else if (frame == num_frames && GB(itspec->animation_info, 8, 8) == 1) {
+			/* This animation loops, so start again from the beginning */
+			frame = 0;
+		} else {
+			/* This animation doesn't loop, so stay here */
+			DeleteAnimatedTile(tile);
+		}
+	}
+
+	SetIndustryAnimationState(tile, frame);
+	MarkTileDirtyByTile(tile);
+}
+
+static void ChangeIndustryTileAnimationFrame(TileIndex tile, IndustryAnimationTrigger iat, uint32 random_bits, IndustryGfx gfx, Industry *ind)
+{
+	uint16 callback_res = GetIndustryTileCallback(CBID_INDTILE_ANIM_START_STOP, random_bits, iat, gfx, ind, tile);
+	if (callback_res == CALLBACK_FAILED) return;
+
+	switch (callback_res & 0xFF) {
+		case 0xFD: /* Do nothing. */         break;
+		case 0xFE: AddAnimatedTile(tile);    break;
+		case 0xFF: DeleteAnimatedTile(tile); break;
+		default:
+			SetIndustryAnimationState(tile, callback_res & 0xFF);
+			AddAnimatedTile(tile);
+			break;
+	}
+}
+
+bool StartStopIndustryTileAnimation(TileIndex tile, IndustryAnimationTrigger iat, uint32 random)
+{
+	IndustryGfx gfx = GetIndustryGfx(tile);
+	const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
+
+	if (!HASBIT(itspec->animation_triggers, iat)) return false;
+
+	Industry *ind = GetIndustryByTile(tile);
+	ChangeIndustryTileAnimationFrame(tile, iat, random, gfx, ind);
+	return true;
+}
+
+bool StartStopIndustryTileAnimation(const Industry *ind, IndustryAnimationTrigger iat)
+{
+	bool ret = true;
+	uint32 random = Random();
+	BEGIN_TILE_LOOP(tile, ind->width, ind->height, ind->xy)
+		if (IsTileType(tile, MP_INDUSTRY) && GetIndustryIndex(tile) == ind->index) {
+			ret &= StartStopIndustryTileAnimation(tile, iat, random);
+			SB(random, 0, 16, Random());
+		}
+	END_TILE_LOOP(tile, ind->width, ind->height, ind->xy)
+
+	return ret;
+}
--- a/src/newgrf_industrytiles.h	Wed Jul 11 08:35:14 2007 +0000
+++ b/src/newgrf_industrytiles.h	Wed Jul 11 15:03:29 2007 +0000
@@ -5,8 +5,20 @@
 #ifndef NEWGRF_INDUSTRYTILES_H
 #define NEWGRF_INDUSTRYTILES_H
 
+enum IndustryAnimationTrigger {
+	IAT_CONSTRUCTION_STATE_CHANGE,
+	IAT_TILELOOP,
+	IAT_INDUSTRY_TICK,
+	IAT_INDUSTRY_RECEIVED_CARGO,
+	IAT_INDUSTRY_DISTRIBUTES_CARGO,
+};
+
 bool DrawNewIndustryTile(TileInfo *ti, Industry *i, IndustryGfx gfx, const IndustryTileSpec *inds);
 uint16 GetIndustryTileCallback(uint16 callback, uint32 param1, uint32 param2, IndustryGfx gfx_id, Industry *industry, TileIndex tile);
 bool PerformIndustryTileSlopeCheck(TileIndex tile, const IndustryTileSpec *its, IndustryType type, IndustryGfx gfx);
 
+void AnimateNewIndustryTile(TileIndex tile);
+bool StartStopIndustryTileAnimation(TileIndex tile, IndustryAnimationTrigger iat, uint32 random = Random());
+bool StartStopIndustryTileAnimation(const Industry *ind, IndustryAnimationTrigger iat);
+
 #endif /* NEWGRF_INDUSTRYTILES_H */
--- a/src/table/build_industry.h	Wed Jul 11 08:35:14 2007 +0000
+++ b/src/table/build_industry.h	Wed Jul 11 15:03:29 2007 +0000
@@ -1532,7 +1532,7 @@
  * @param a2  next frame of animation
  * @param a3  chooses between animation or construction state
  */
-#define MT(ca1, c1, ca2, c2, ca3, c3, sl, a1, a2, a3) {{c1, c2, c3}, {ca1, ca2, ca3}, sl, a1, a2, a3, 0, true, {0, 0, NULL, NULL, 0}}
+#define MT(ca1, c1, ca2, c2, ca3, c3, sl, a1, a2, a3) {{c1, c2, c3}, {ca1, ca2, ca3}, sl, a1, a2, a3, 0, 0xFFFF, 2, 0, 0, true, {0, 0, NULL, NULL, 0}}
 static const IndustryTileSpec _origin_industry_tile_specs[NEW_INDUSTRYTILEOFFSET] = {
 	/* Coal Mine */
 	MT(0,  CT_INVALID,      0,  CT_INVALID,   0,  CT_INVALID,    SLOPE_STEEP,  INDUSTRYTILE_NOANIM,   INDUSTRYTILE_NOANIM,  false),