* Call CBID_VEHICLE_SPAWN_VISUAL_EFFECT and spawn requested effects. * @param v Vehicle to create effects for. */
| 2702 | * @param v Vehicle to create effects for. |
| 2703 | */ |
| 2704 | static void SpawnAdvancedVisualEffect(const Vehicle *v) |
| 2705 | { |
| 2706 | std::array<int32_t, 4> regs100; |
| 2707 | uint16_t callback = GetVehicleCallback(CBID_VEHICLE_SPAWN_VISUAL_EFFECT, 0, Random(), v->engine_type, v, regs100); |
| 2708 | if (callback == CALLBACK_FAILED) return; |
| 2709 | |
| 2710 | uint count = GB(callback, 0, 2); |
| 2711 | assert(count <= std::size(regs100)); |
| 2712 | bool auto_center = HasBit(callback, 13); |
| 2713 | bool auto_rotate = !HasBit(callback, 14); |
| 2714 | |
| 2715 | int8_t l_center = 0; |
| 2716 | if (auto_center) { |
| 2717 | /* For road vehicles: Compute offset from vehicle position to vehicle center */ |
| 2718 | if (v->type == VEH_ROAD) l_center = -(int)(VEHICLE_LENGTH - RoadVehicle::From(v)->gcache.cached_veh_length) / 2; |
| 2719 | } else { |
| 2720 | /* For trains: Compute offset from vehicle position to sprite position */ |
| 2721 | if (v->type == VEH_TRAIN) l_center = (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2; |
| 2722 | } |
| 2723 | |
| 2724 | Direction l_dir = v->direction; |
| 2725 | if (v->type == VEH_TRAIN && Train::From(v)->flags.Test(VehicleRailFlag::Flipped)) l_dir = ReverseDir(l_dir); |
| 2726 | Direction t_dir = ChangeDir(l_dir, DIRDIFF_90RIGHT); |
| 2727 | |
| 2728 | int8_t x_center = _vehicle_smoke_pos[l_dir] * l_center; |
| 2729 | int8_t y_center = _vehicle_smoke_pos[t_dir] * l_center; |
| 2730 | |
| 2731 | for (uint i = 0; i < count; i++) { |
| 2732 | int32_t reg = regs100[i]; |
| 2733 | uint type = GB(reg, 0, 8); |
| 2734 | int8_t x = GB(reg, 8, 8); |
| 2735 | int8_t y = GB(reg, 16, 8); |
| 2736 | int8_t z = GB(reg, 24, 8); |
| 2737 | |
| 2738 | if (auto_rotate) { |
| 2739 | int8_t l = x; |
| 2740 | int8_t t = y; |
| 2741 | x = _vehicle_smoke_pos[l_dir] * l + _vehicle_smoke_pos[t_dir] * t; |
| 2742 | y = _vehicle_smoke_pos[t_dir] * l - _vehicle_smoke_pos[l_dir] * t; |
| 2743 | } |
| 2744 | |
| 2745 | if (type >= 0xF0) { |
| 2746 | switch (type) { |
| 2747 | case 0xF1: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_STEAM_SMOKE); break; |
| 2748 | case 0xF2: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_DIESEL_SMOKE); break; |
| 2749 | case 0xF3: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_ELECTRIC_SPARK); break; |
| 2750 | case 0xFA: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_BREAKDOWN_SMOKE_AIRCRAFT); break; |
| 2751 | default: break; |
| 2752 | } |
| 2753 | } |
| 2754 | } |
| 2755 | } |
| 2756 | |
| 2757 | /** |
| 2758 | * Test if a bridge is above a vehicle. |
no test coverage detected