summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/newgrf_callbacks.h3
-rw-r--r--src/vehicle.cpp69
-rw-r--r--src/vehicle_base.h1
3 files changed, 70 insertions, 3 deletions
diff --git a/src/newgrf_callbacks.h b/src/newgrf_callbacks.h
index e96d06803..2c30241f0 100644
--- a/src/newgrf_callbacks.h
+++ b/src/newgrf_callbacks.h
@@ -278,6 +278,9 @@ enum CallbackID {
/** Called when industry is built to set initial production level. */
CBID_INDUSTRY_PROD_CHANGE_BUILD = 0x15F, // 15 bit callback
+
+ /** Called to spawn visual effects for vehicles. */
+ CBID_VEHICLE_SPAWN_VISUAL_EFFECT = 0x160, // 15 bit callback
};
/**
diff --git a/src/vehicle.cpp b/src/vehicle.cpp
index dd3da0751..5eee54041 100644
--- a/src/vehicle.cpp
+++ b/src/vehicle.cpp
@@ -2345,6 +2345,62 @@ static const int8 _vehicle_smoke_pos[8] = {
};
/**
+ * Call CBID_VEHICLE_SPAWN_VISUAL_EFFECT and spawn requested effects.
+ * @param v Vehicle to create effects for.
+ */
+static void SpawnAdvancedVisualEffect(const Vehicle *v)
+{
+ uint16 callback = GetVehicleCallback(CBID_VEHICLE_SPAWN_VISUAL_EFFECT, 0, Random(), v->engine_type, v);
+ if (callback == CALLBACK_FAILED) return;
+
+ uint count = GB(callback, 0, 2);
+ bool auto_center = HasBit(callback, 13);
+ bool auto_rotate = !HasBit(callback, 14);
+
+ int8 l_center = 0;
+ if (auto_center) {
+ /* For road vehicles: Compute offset from vehicle position to vehicle center */
+ if (v->type == VEH_ROAD) l_center = -(VEHICLE_LENGTH - RoadVehicle::From(v)->gcache.cached_veh_length) / 2;
+ } else {
+ /* For trains: Compute offset from vehicle position to sprite position */
+ if (v->type == VEH_TRAIN) l_center = (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
+ }
+
+ Direction l_dir = v->direction;
+ if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) l_dir = ReverseDir(l_dir);
+ Direction t_dir = ChangeDir(l_dir, DIRDIFF_90RIGHT);
+
+ int8 x_center = _vehicle_smoke_pos[l_dir] * l_center;
+ int8 y_center = _vehicle_smoke_pos[t_dir] * l_center;
+
+ for (uint i = 0; i < count; i++) {
+ uint32 reg = GetRegister(0x100 + i);
+ uint type = GB(reg, 0, 8);
+ int8 x = GB(reg, 8, 8);
+ int8 y = GB(reg, 16, 8);
+ int8 z = GB(reg, 24, 8);
+
+ if (auto_rotate) {
+ int8 l = x;
+ int8 t = y;
+ x = _vehicle_smoke_pos[l_dir] * l + _vehicle_smoke_pos[t_dir] * t;
+ y = _vehicle_smoke_pos[t_dir] * l - _vehicle_smoke_pos[l_dir] * t;
+ }
+
+ if (type >= 0xF0) {
+ switch (type) {
+ case 0xF1: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_STEAM_SMOKE); break;
+ case 0xF2: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_DIESEL_SMOKE); break;
+ case 0xF3: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_ELECTRIC_SPARK); break;
+ case 0xF6: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_BREAKDOWN_SMOKE); break;
+ case 0xFA: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_BREAKDOWN_SMOKE_AIRCRAFT); break;
+ default: break;
+ }
+ }
+ }
+}
+
+/**
* Draw visual effects (smoke and/or sparks) for a vehicle chain.
* @pre this->IsPrimaryVehicle()
*/
@@ -2385,10 +2441,14 @@ void Vehicle::ShowVisualEffect() const
const Vehicle *v = this;
do {
+ bool advanced = HasBit(v->vcache.cached_vis_effect, VE_ADVANCED_EFFECT);
int effect_offset = GB(v->vcache.cached_vis_effect, VE_OFFSET_START, VE_OFFSET_COUNT) - VE_OFFSET_CENTRE;
VisualEffectSpawnModel effect_model = VESM_NONE;
-
- if (!HasBit(v->vcache.cached_vis_effect, VE_DISABLE_EFFECT)) {
+ if (advanced) {
+ effect_offset = VE_OFFSET_CENTRE;
+ effect_model = (VisualEffectSpawnModel)GB(v->vcache.cached_vis_effect, 0, VE_ADVANCED_EFFECT);
+ if (effect_model >= VESM_END) effect_model = VESM_NONE; // unknown spawning model
+ } else {
effect_model = (VisualEffectSpawnModel)GB(v->vcache.cached_vis_effect, VE_TYPE_START, VE_TYPE_COUNT);
assert(effect_model != (VisualEffectSpawnModel)VE_TYPE_DEFAULT); // should have been resolved by UpdateVisualEffect
assert_compile((uint)VESM_STEAM == (uint)VE_TYPE_STEAM);
@@ -2466,7 +2526,10 @@ void Vehicle::ShowVisualEffect() const
NOT_REACHED();
}
- if (evt != EV_END) {
+ if (evt != EV_END && advanced) {
+ sound = true;
+ SpawnAdvancedVisualEffect(v);
+ } else if (evt != EV_END) {
sound = true;
/* The effect offset is relative to a point 4 units behind the vehicle's
diff --git a/src/vehicle_base.h b/src/vehicle_base.h
index 380f6781d..6c2d16dfc 100644
--- a/src/vehicle_base.h
+++ b/src/vehicle_base.h
@@ -87,6 +87,7 @@ enum VisualEffect {
VE_TYPE_ELECTRIC = 3, ///< Electric sparks
VE_DISABLE_EFFECT = 6, ///< Flag to disable visual effect
+ VE_ADVANCED_EFFECT = VE_DISABLE_EFFECT, ///< Flag for advanced effects
VE_DISABLE_WAGON_POWER = 7, ///< Flag to disable wagon power
VE_DEFAULT = 0xFF, ///< Default value to indicate that visual effect should be based on engine class