From 4b769d95c1588e13acd8e9e6fea02efdae2336ca Mon Sep 17 00:00:00 2001 From: jerrrrycho Date: Sun, 8 Nov 2026 02:05:45 +0100 Subject: [PATCH 1/2] fix: SOD lamp shows the doors of the whole consist in three states (eu07/maszyna#288) The door closure signalling lamp (i-door_blocked) showed only Doors.is_locked of the occupied vehicle, so a door open in another car or a coupled unit didn't show on it. TMoverParameters::door_closure() gives the state of one vehicle (none, locked, released, open), the driver gathers the most severe one of the train in determine_consist_state(), next to IsAnyDoorOpen, and the lamp is lit for locked doors, blinks for closed but released ones (a permit given, or no lock engaged on doors that need no permit) and is dark with a door open. doorclosuresignal in eu07.ini (default yes) switches it; with no the lamp shows is_locked of the occupied vehicle as before. No data change needed. --- McZapkie/MOVER.h | 17 +++++ McZapkie/Mover.cpp | 37 +++++++++++ tests/unit/test_door_closure.cpp | 110 +++++++++++++++++++++++++++++++ utilities/Globals.cpp | 7 ++ utilities/Globals.h | 2 + vehicle/Driver.cpp | 3 + vehicle/Driver.h | 1 + vehicle/Train.cpp | 11 +++- 8 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 tests/unit/test_door_closure.cpp diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 16bb207f..45e3305c 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -261,6 +261,22 @@ enum class range_t /// Affects the entire consist. consist }; +/// State of the door closure signalling (SOD) of a vehicle or a consist, ordered from the least to the most +/// severe: the state of a consist is the most severe state of its vehicles. +enum class door_closure_t +{ + /// No doors worked by the crew: the vehicle doesn't take part in the signalling. + none, + /// All doors closed and locked: they can't be opened. + locked, + /// All doors closed, but released: a permit is given, or no lock holds them shut. + released, + /// A door is open, or not fully closed yet. + open +}; +/// Whether the door closure signalling lamp is lit: steadily for locked doors, in the lit phase of the +/// blinking for released ones, never with a door open or with no doors signalled. +bool door_closure_lamp(door_closure_t const State, bool const BlinkLit); /// Possible settings for an enable/disable input pair (mutually exclusive). enum class operation_t { @@ -2593,6 +2609,7 @@ class TMoverParameters bool LockDoors(bool const State, range_t const Notify = range_t::consist); bool signal_departure(bool const State, range_t const Notify = range_t::consist); // toggles departure warning void update_doors(double const Deltatime); // door controller update + door_closure_t door_closure() const; // state of the door closure signalling of this vehicle /* funkcje dla samochodow*/ bool ChangeOffsetH(double DeltaOffset); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 20761bac..03fa3e6d 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -8699,6 +8699,43 @@ bool TMoverParameters::signal_departure(bool const State, range_t const Notify) return true; } +// state of the door closure signalling (SOD) of this vehicle: open while a door isn't fully closed, released while +// the closed doors can be opened (a permit given, or, for doors that need none, no lock engaged), locked otherwise. +// doors the crew doesn't close (autonomous) aren't signalled, the same as for the door lights of the consist +door_closure_t TMoverParameters::door_closure() const +{ + if (Doors.range == 0.f || Doors.close_control == control_t::autonomous) + { + return door_closure_t::none; + } + if (std::ranges::any_of(Doors.instances, [](basic_door const &Door) { return false == Door.is_closed; })) + { + return door_closure_t::open; + } + if (Doors.is_locked) + { + return door_closure_t::locked; + } + if (Doors.permit_needed && std::ranges::none_of(Doors.instances, [](basic_door const &Door) { return Door.open_permit; })) + { + return door_closure_t::locked; + } + return door_closure_t::released; +} + +bool door_closure_lamp(door_closure_t const State, bool const BlinkLit) +{ + switch (State) + { + case door_closure_t::locked: + return true; + case door_closure_t::released: + return BlinkLit; + default: + return false; + } +} + // automatic door controller update void TMoverParameters::update_doors(double const Deltatime) { diff --git a/tests/unit/test_door_closure.cpp b/tests/unit/test_door_closure.cpp new file mode 100644 index 00000000..abfa5a7e --- /dev/null +++ b/tests/unit/test_door_closure.cpp @@ -0,0 +1,110 @@ +#include "stdafx.h" +#include "doctest.h" +#include "scenario.h" + +// the door closure signalling (SOD, the i-door_blocked lamp of a cab): the state of each vehicle's doors and of the +// whole train, the most severe of its vehicles, as the driver gathers it for the lamp (eu07/maszyna#288) + +using test::scenario; +using namespace test::channels; + +namespace { + +// the state of the whole train, the way TController::determine_consist_state() gathers it +door_closure_t consist_closure(scenario &Scenario) { + auto closure{door_closure_t::none}; + for (std::size_t i = 0; i < Scenario.train().size(); ++i) { + closure = std::max(closure, Scenario.vehicle(i).door_closure()); + } + return closure; +} + +} // namespace + +TEST_CASE("door closure: the lamp is lit for locked doors, blinks for released ones and is dark for open ones") { + for (auto const lit : {true, false}) { + CAPTURE(lit); + CHECK(door_closure_lamp(door_closure_t::locked, lit)); + CHECK(door_closure_lamp(door_closure_t::released, lit) == lit); + CHECK_FALSE(door_closure_lamp(door_closure_t::open, lit)); + CHECK_FALSE(door_closure_lamp(door_closure_t::none, lit)); + } + // a consist takes the most severe state of its vehicles + CHECK(std::max(door_closure_t::none, door_closure_t::locked) == door_closure_t::locked); + CHECK(std::max(door_closure_t::locked, door_closure_t::released) == door_closure_t::released); + CHECK(std::max(door_closure_t::released, door_closure_t::open) == door_closure_t::open); +} + +TEST_CASE("door closure: a unit with permits, locked, released by the permit and open, in any of its cars") { + scenario scenario{"door closure/elf", motion() + doors()}; + scenario.add("elf_v1/21we-a", 1).add("elf_v1/21we-b").add("elf_v1/21we-c"); + scenario.start_up(); + auto &cab{scenario.cab()}; + auto &last{scenario.vehicle(scenario.train().size() - 1)}; + // closed with no permit: no door can be opened + CHECK(cab.door_closure() == door_closure_t::locked); + CHECK(last.door_closure() == door_closure_t::locked); + CHECK(consist_closure(scenario) == door_closure_t::locked); + + scenario.act("permit left"); + cab.PermitDoors(side::left, true); + scenario.wait(2.0); + CHECK(last.door_closure() == door_closure_t::released); + CHECK(consist_closure(scenario) == door_closure_t::released); + + scenario.act("the last car opens its own door"); + last.OperateDoors(side::left, true, range_t::local); + scenario.wait(5.0); + // the cab's own doors stay closed, the train is open all the same + CHECK(cab.door_closure() == door_closure_t::released); + CHECK(last.door_closure() == door_closure_t::open); + CHECK(consist_closure(scenario) == door_closure_t::open); + + scenario.act("close, the steps stay out under the permit"); + last.OperateDoors(side::left, false, range_t::local); + cab.OperateDoors(side::left, false); + scenario.wait(10.0); + CHECK(last.Doors.instances[side::left].position <= 0.f); + // a step out isn't a closed door + CHECK(consist_closure(scenario) == door_closure_t::open); + + scenario.act("revoke the permit"); + cab.PermitDoors(side::left, false); + scenario.wait(10.0); + CHECK(consist_closure(scenario) == door_closure_t::locked); +} + +TEST_CASE("door closure: the doors of a unit without permits are released at a standstill") { + scenario scenario{"door closure/en57", motion() + doors()}; + scenario.add("en57_v1/5bgaiii_led_spot", 1).add("en57_v1/6ba_840").add("en57_v1/5bgb"); + scenario.start_up(); + auto &cab{scenario.cab()}; + auto &middle{scenario.vehicle(1)}; + REQUIRE_FALSE(cab.Doors.permit_needed); + REQUIRE(middle.Doors.permit_needed); + // the door lock engages only once the train runs (DoorLockSpeed), till then the end cars' doors can be opened + CHECK(cab.door_closure() == door_closure_t::released); + CHECK(middle.door_closure() == door_closure_t::locked); + CHECK(consist_closure(scenario) == door_closure_t::released); + scenario.act("open right"); + cab.OperateDoors(side::right, true); + scenario.wait(10.0); + CHECK(consist_closure(scenario) == door_closure_t::open); + scenario.act("close right"); + cab.OperateDoors(side::right, false); + scenario.wait(10.0); + CHECK(consist_closure(scenario) == door_closure_t::released); +} + +TEST_CASE("door closure: a locomotive has no doors to signal, its coach does") { + scenario scenario{"door closure/eu07 with a coach", motion() + doors()}; + scenario.add("4e_v1/4e", 1).add("bdhpumn_v3/bdhpumn"); + scenario.start_up(); + CHECK(scenario.cab().door_closure() == door_closure_t::none); + scenario.act("open right"); + scenario.cab().PermitDoors(side::right, true); + scenario.cab().OperateDoors(side::right, true); + scenario.wait(10.0); + CHECK(scenario.vehicle(1).door_closure() == door_closure_t::open); + CHECK(consist_closure(scenario) == door_closure_t::open); +} diff --git a/utilities/Globals.cpp b/utilities/Globals.cpp index b4f2e14b..a8aadec2 100644 --- a/utilities/Globals.cpp +++ b/utilities/Globals.cpp @@ -506,6 +506,12 @@ bool global_settings::ConfigParseSimulation(cParser& Parser, const std::string& return true; } + if (token == "doorclosuresignal") + { + ParseOne(Parser, DoorClosureSignal); + return true; + } + if (token == "movelight") { ParseOne(Parser, fMoveLight, 1, false); @@ -1573,6 +1579,7 @@ global_settings::export_as_text( std::ostream &Output ) const { export_as_text( Output, "skyenabled", asSky ); export_as_text( Output, "defaultext", szDefaultExt ); export_as_text( Output, "newaircouplers", bnewAirCouplers ); + export_as_text( Output, "doorclosuresignal", DoorClosureSignal ); export_as_text( Output, "anisotropicfiltering", AnisotropicFiltering ); export_as_text( Output, "usevbo", bUseVBO ); export_as_text( Output, "feedbackmode", iFeedbackMode ); diff --git a/utilities/Globals.h b/utilities/Globals.h index ad216cd9..971f8495 100644 --- a/utilities/Globals.h +++ b/utilities/Globals.h @@ -115,6 +115,8 @@ struct global_settings { std::string Period{}; // time of the day, based on sun position bool FullPhysics{ true }; // full calculations performed for each simulation step bool bnewAirCouplers{ true }; + bool DoorClosureSignal{ true }; // door closure signalling lamp (i-door_blocked) shows the doors of the whole consist in three states + float fMoveLight{ 0.f }; // numer dnia w roku albo -1 bool FakeLight{ false }; // toggle between fixed and dynamic daylight double fTimeSpeed{ 1.0 }; // przyspieszenie czasu, zmienna do testów diff --git a/vehicle/Driver.cpp b/vehicle/Driver.cpp index 9f83b6d5..778b9700 100644 --- a/vehicle/Driver.cpp +++ b/vehicle/Driver.cpp @@ -5937,6 +5937,7 @@ TController::determine_consist_state() { IsAnyDoorOnlyOpen[ side::right ] = IsAnyDoorOnlyOpen[ side::left ] = false; IsAnyDoorOpen[ side::right ] = IsAnyDoorOpen[ side::left ] = false; IsAnyDoorPermitActive[ side::right ] = IsAnyDoorPermitActive[ side::left ] = false; + auto doorclosure { door_closure_t::none }; ConsistShade = 0.0; auto *p { pVehicles[ end::front ] }; // pojazd na czole składu double dy; // składowa styczna grawitacji, w przedziale <0,1> @@ -5998,12 +5999,14 @@ TController::determine_consist_state() { IsAnyDoorPermitActive[ side::right ] |= rightdoor.open_permit; IsAnyDoorPermitActive[ side::left ] |= leftdoor.open_permit; } + doorclosure = std::max( doorclosure, vehicle->door_closure() ); } // measure lighting level // TBD: apply weight (multiplier) to partially lit vehicles? ConsistShade += p->fShade > 0.0 ? p->fShade : 1.0; p = p->Next(); // pojazd podłączony z tyłu (patrząc od czoła) } + DoorClosure = doorclosure; // calculate average amount of received sunlight ConsistShade /= iVehicles; diff --git a/vehicle/Driver.h b/vehicle/Driver.h index f1975fca..d750fc39 100644 --- a/vehicle/Driver.h +++ b/vehicle/Driver.h @@ -632,6 +632,7 @@ private: bool IsAnyDoorOpen[ 2 ]; // state of door in the consist bool IsAnyDoorOnlyOpen[ 2 ]; // state of door in the consist regardless of step bool IsAnyDoorPermitActive[ 2 ]; // state of door permit in the consist + door_closure_t DoorClosure{ door_closure_t::none }; // state of the door closure signalling (SOD) of the consist bool IsAnyLineBreakerOpen{ false }; // state of line breaker in all powered vehicles under control bool IsAnyConverterOverloadRelayOpen{ false }; // state of converter overload relays in all vehicles under control bool IsAnyMotorOverloadRelayOpen{ false }; // state of motor overload relays in all vehicles under control diff --git a/vehicle/Train.cpp b/vehicle/Train.cpp index e30635f4..3a4c42db 100644 --- a/vehicle/Train.cpp +++ b/vehicle/Train.cpp @@ -9108,7 +9108,16 @@ bool TTrain::Update(double const Deltatime) btLampkaDoorLeft.Turn(DynamicObject->Mechanik->IsAnyDoorOpen[cab_to_end() == end::front ? side::left : side::right]); btLampkaDoorRight.Turn(DynamicObject->Mechanik->IsAnyDoorOpen[cab_to_end() == end::front ? side::right : side::left]); } - btLampkaBlokadaDrzwi.Turn(mvOccupied->Doors.is_locked); + if (Global.DoorClosureSignal && DynamicObject->Mechanik != nullptr) + { + // door closure signalling (SOD) of the whole consist: lit with all doors closed and locked, blinking with + // them closed but released, dark with a door open + btLampkaBlokadaDrzwi.Turn(door_closure_lamp(DynamicObject->Mechanik->DoorClosure, simulation::Time.data().wSecond % 2 < 1)); + } + else + { + btLampkaBlokadaDrzwi.Turn(mvOccupied->Doors.is_locked); + } btLampkaDoorLockOff.Turn(false == mvOccupied->Doors.lock_enabled); btLampkaDepartureSignal.Turn(mvControlled->DepartureSignal); btLampkaNapNastHam.Turn(mvControlled->DirActive != 0 && mvOccupied->EpFuse); // napiecie na nastawniku hamulcowym From 57db0087ff43e898bd949525edd704ebf1576a78 Mon Sep 17 00:00:00 2001 From: jerrrrycho Date: Sun, 8 Nov 2026 18:30:22 +0100 Subject: [PATCH 2/2] fix: the SOD lamp of the whole consist is opt-in per vehicle (DoorClosureSignal) The three-state door closure lamp is switched on by DoorClosureSignal=Yes in the Doors: section of the .fiz of the vehicle whose cab shows the lamp (the occupied vehicle), off by default: without it the lamp keeps showing the lock of the vehicle's own doors. The eu07.ini switch doorclosuresignal is gone, the data decides. Sets whose cars lack DoorNeedPermit would blink at every standstill, so only the sets with permits get the key. --- McZapkie/MOVER.h | 4 +++ McZapkie/Mover.cpp | 7 +++++ tests/unit/test_door_closure.cpp | 48 ++++++++++++++++++++++++++++++++ utilities/Globals.cpp | 7 ----- utilities/Globals.h | 2 -- vehicle/Train.cpp | 9 +++--- 6 files changed, 64 insertions(+), 13 deletions(-) diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 45e3305c..a1a10207 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -1455,6 +1455,7 @@ class TMoverParameters float auto_velocity{-1.f}; // automatic door closure velocity threshold bool auto_include_remote{false}; // automatic door closure applies also to remote control bool permit_needed{false}; + bool closure_signal{false}; // the door closure lamp (SOD) of the cab signals the doors of the whole consist in three states std::vector permit_presets; // permit presets selectable with preset switch float voltage{0.f}; // power type required for door movement // ld inputs @@ -2610,6 +2611,9 @@ class TMoverParameters bool signal_departure(bool const State, range_t const Notify = range_t::consist); // toggles departure warning void update_doors(double const Deltatime); // door controller update door_closure_t door_closure() const; // state of the door closure signalling of this vehicle + // whether the door closure lamp in the cab of this vehicle is lit: with DoorClosureSignal, for the given state of the + // consist; without it, for the lock of the vehicle's own doors, as the lamp always worked + bool door_closure_lamp_lit(door_closure_t const Consist, bool const BlinkLit) const; /* funkcje dla samochodow*/ bool ChangeOffsetH(double DeltaOffset); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 03fa3e6d..ce3c0845 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -8723,6 +8723,11 @@ door_closure_t TMoverParameters::door_closure() const return door_closure_t::released; } +bool TMoverParameters::door_closure_lamp_lit(door_closure_t const Consist, bool const BlinkLit) const +{ + return Doors.closure_signal ? door_closure_lamp(Consist, BlinkLit) : Doors.is_locked; +} + bool door_closure_lamp(door_closure_t const State, bool const BlinkLit) { switch (State) @@ -10613,6 +10618,8 @@ void TMoverParameters::LoadFIZ_Doors(std::string const &line) extract_value(Doors.auto_include_remote, "DoorAutoCloseRemote", line, ""); // operation permit extract_value(Doors.permit_needed, "DoorNeedPermit", line, ""); + // the door closure lamp (SOD) of the cab signals the doors of the whole consist + extract_value(Doors.closure_signal, "DoorClosureSignal", line, ""); { auto permitpresets = Split(extract_value("DoorPermitList", line), '|'); for (auto const &permit : permitpresets) diff --git a/tests/unit/test_door_closure.cpp b/tests/unit/test_door_closure.cpp index abfa5a7e..c92d8fef 100644 --- a/tests/unit/test_door_closure.cpp +++ b/tests/unit/test_door_closure.cpp @@ -1,11 +1,14 @@ #include "stdafx.h" #include "doctest.h" #include "scenario.h" +#include "vehicle.h" // the door closure signalling (SOD, the i-door_blocked lamp of a cab): the state of each vehicle's doors and of the // whole train, the most severe of its vehicles, as the driver gathers it for the lamp (eu07/maszyna#288) using test::scenario; +using test::definition; +using test::vehicle; using namespace test::channels; namespace { @@ -108,3 +111,48 @@ TEST_CASE("door closure: a locomotive has no doors to signal, its coach does") { CHECK(scenario.vehicle(1).door_closure() == door_closure_t::open); CHECK(consist_closure(scenario) == door_closure_t::open); } + +TEST_CASE("door closure: the signalling is switched on by DoorClosureSignal in the Doors section, off without it") { + SUBCASE("without the key") { + vehicle wagon{definition::load("wagon")}; + CHECK_FALSE(wagon->Doors.closure_signal); + } + SUBCASE("with the key") { + vehicle wagon{definition::load("wagon").set("Doors", "DoorClosureSignal", "Yes")}; + CHECK(wagon->Doors.closure_signal); + } +} + +TEST_CASE("door closure: without DoorClosureSignal the lamp shows the lock of the vehicle's own doors, as before") { + vehicle wagon{definition::load("wagon")}; + REQUIRE_FALSE(wagon->Doors.closure_signal); + for (auto const locked : {true, false}) { + wagon->Doors.is_locked = locked; + for (auto const consist : {door_closure_t::none, door_closure_t::locked, door_closure_t::released, door_closure_t::open}) { + for (auto const lit : {true, false}) { + CAPTURE(locked); + CAPTURE(static_cast(consist)); + CAPTURE(lit); + // no blinking at a standstill with the doors closed, whatever the consist does + CHECK(wagon->door_closure_lamp_lit(consist, lit) == locked); + } + } + } +} + +TEST_CASE("door closure: with DoorClosureSignal the lamp shows the consist in three states") { + vehicle wagon{definition::load("wagon").set("Doors", "DoorClosureSignal", "Yes")}; + REQUIRE(wagon->Doors.closure_signal); + for (auto const locked : {true, false}) { + // the vehicle's own lock doesn't matter, the consist does + wagon->Doors.is_locked = locked; + for (auto const lit : {true, false}) { + CAPTURE(locked); + CAPTURE(lit); + CHECK(wagon->door_closure_lamp_lit(door_closure_t::locked, lit)); + CHECK(wagon->door_closure_lamp_lit(door_closure_t::released, lit) == lit); + CHECK_FALSE(wagon->door_closure_lamp_lit(door_closure_t::open, lit)); + CHECK_FALSE(wagon->door_closure_lamp_lit(door_closure_t::none, lit)); + } + } +} diff --git a/utilities/Globals.cpp b/utilities/Globals.cpp index a8aadec2..b4f2e14b 100644 --- a/utilities/Globals.cpp +++ b/utilities/Globals.cpp @@ -506,12 +506,6 @@ bool global_settings::ConfigParseSimulation(cParser& Parser, const std::string& return true; } - if (token == "doorclosuresignal") - { - ParseOne(Parser, DoorClosureSignal); - return true; - } - if (token == "movelight") { ParseOne(Parser, fMoveLight, 1, false); @@ -1579,7 +1573,6 @@ global_settings::export_as_text( std::ostream &Output ) const { export_as_text( Output, "skyenabled", asSky ); export_as_text( Output, "defaultext", szDefaultExt ); export_as_text( Output, "newaircouplers", bnewAirCouplers ); - export_as_text( Output, "doorclosuresignal", DoorClosureSignal ); export_as_text( Output, "anisotropicfiltering", AnisotropicFiltering ); export_as_text( Output, "usevbo", bUseVBO ); export_as_text( Output, "feedbackmode", iFeedbackMode ); diff --git a/utilities/Globals.h b/utilities/Globals.h index 971f8495..ad216cd9 100644 --- a/utilities/Globals.h +++ b/utilities/Globals.h @@ -115,8 +115,6 @@ struct global_settings { std::string Period{}; // time of the day, based on sun position bool FullPhysics{ true }; // full calculations performed for each simulation step bool bnewAirCouplers{ true }; - bool DoorClosureSignal{ true }; // door closure signalling lamp (i-door_blocked) shows the doors of the whole consist in three states - float fMoveLight{ 0.f }; // numer dnia w roku albo -1 bool FakeLight{ false }; // toggle between fixed and dynamic daylight double fTimeSpeed{ 1.0 }; // przyspieszenie czasu, zmienna do testów diff --git a/vehicle/Train.cpp b/vehicle/Train.cpp index 3a4c42db..bbcdd177 100644 --- a/vehicle/Train.cpp +++ b/vehicle/Train.cpp @@ -9108,11 +9108,12 @@ bool TTrain::Update(double const Deltatime) btLampkaDoorLeft.Turn(DynamicObject->Mechanik->IsAnyDoorOpen[cab_to_end() == end::front ? side::left : side::right]); btLampkaDoorRight.Turn(DynamicObject->Mechanik->IsAnyDoorOpen[cab_to_end() == end::front ? side::right : side::left]); } - if (Global.DoorClosureSignal && DynamicObject->Mechanik != nullptr) + if (DynamicObject->Mechanik != nullptr) { - // door closure signalling (SOD) of the whole consist: lit with all doors closed and locked, blinking with - // them closed but released, dark with a door open - btLampkaBlokadaDrzwi.Turn(door_closure_lamp(DynamicObject->Mechanik->DoorClosure, simulation::Time.data().wSecond % 2 < 1)); + // with DoorClosureSignal in the definition of the cab's vehicle, the door closure signalling (SOD) of the whole + // consist: lit with all doors closed and locked, blinking with them closed but released, dark with a door open. + // without it, the lock of the vehicle's own doors, as before + btLampkaBlokadaDrzwi.Turn(mvOccupied->door_closure_lamp_lit(DynamicObject->Mechanik->DoorClosure, simulation::Time.data().wSecond % 2 < 1)); } else {