* Handle all of the aspects of a vehicle breakdown * This includes adding smoke and sounds, and ending the breakdown when appropriate. * @return true iff the vehicle is stopped because of a breakdown * @note This function always returns false for aircraft, since these never stop for breakdowns */
| 1330 | * @note This function always returns false for aircraft, since these never stop for breakdowns |
| 1331 | */ |
| 1332 | bool Vehicle::HandleBreakdown() |
| 1333 | { |
| 1334 | /* Possible states for Vehicle::breakdown_ctr |
| 1335 | * 0 - vehicle is running normally |
| 1336 | * 1 - vehicle is currently broken down |
| 1337 | * 2 - vehicle is going to break down now |
| 1338 | * >2 - vehicle is counting down to the actual breakdown event */ |
| 1339 | switch (this->breakdown_ctr) { |
| 1340 | case 0: |
| 1341 | return false; |
| 1342 | |
| 1343 | case 2: |
| 1344 | this->breakdown_ctr = 1; |
| 1345 | |
| 1346 | if (this->breakdowns_since_last_service != 255) { |
| 1347 | this->breakdowns_since_last_service++; |
| 1348 | } |
| 1349 | |
| 1350 | if (this->type == VEH_AIRCRAFT) { |
| 1351 | /* Aircraft just need this flag, the rest is handled elsewhere */ |
| 1352 | this->vehstatus.Set(VehState::AircraftBroken); |
| 1353 | } else { |
| 1354 | this->cur_speed = 0; |
| 1355 | |
| 1356 | if (!PlayVehicleSound(this, VSE_BREAKDOWN)) { |
| 1357 | bool train_or_ship = this->type == VEH_TRAIN || this->type == VEH_SHIP; |
| 1358 | SndPlayVehicleFx((_settings_game.game_creation.landscape != LandscapeType::Toyland) ? |
| 1359 | (train_or_ship ? SND_10_BREAKDOWN_TRAIN_SHIP : SND_0F_BREAKDOWN_ROADVEHICLE) : |
| 1360 | (train_or_ship ? SND_3A_BREAKDOWN_TRAIN_SHIP_TOYLAND : SND_35_BREAKDOWN_ROADVEHICLE_TOYLAND), this); |
| 1361 | } |
| 1362 | |
| 1363 | if (!this->vehstatus.Test(VehState::Hidden) && !EngInfo(this->engine_type)->misc_flags.Test(EngineMiscFlag::NoBreakdownSmoke)) { |
| 1364 | EffectVehicle *u = CreateEffectVehicleRel(this, 4, 4, 5, EV_BREAKDOWN_SMOKE); |
| 1365 | if (u != nullptr) u->animation_state = this->breakdown_delay * 2; |
| 1366 | } |
| 1367 | } |
| 1368 | |
| 1369 | this->MarkDirty(); // Update graphics after speed is zeroed |
| 1370 | SetWindowDirty(WC_VEHICLE_VIEW, this->index); |
| 1371 | SetWindowDirty(WC_VEHICLE_DETAILS, this->index); |
| 1372 | |
| 1373 | [[fallthrough]]; |
| 1374 | case 1: |
| 1375 | /* Aircraft breakdowns end only when arriving at the airport */ |
| 1376 | if (this->type == VEH_AIRCRAFT) return false; |
| 1377 | |
| 1378 | /* For trains this function is called twice per tick, so decrease v->breakdown_delay at half the rate */ |
| 1379 | if ((this->tick_counter & (this->type == VEH_TRAIN ? 3 : 1)) == 0) { |
| 1380 | if (--this->breakdown_delay == 0) { |
| 1381 | this->breakdown_ctr = 0; |
| 1382 | this->MarkDirty(); |
| 1383 | SetWindowDirty(WC_VEHICLE_VIEW, this->index); |
| 1384 | } |
| 1385 | } |
| 1386 | return true; |
| 1387 | |
| 1388 | default: |
| 1389 | if (!this->current_order.IsType(OT_LOADING)) this->breakdown_ctr--; |
no test coverage detected