mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-22 23:19:19 +02:00
scenery groups export and deserialization, associated events included in scenery node groups, AI brake charging tweak, door locking and vehicle hunting oscillation sounds
This commit is contained in:
27
Console.cpp
27
Console.cpp
@@ -275,14 +275,13 @@ void Console::ValueSet(int x, double y)
|
||||
WriteLog( " fraction=" + std::to_string( y ) );
|
||||
}
|
||||
}
|
||||
double temp = (((((Global.fCalibrateOut[x][5] * y) + Global.fCalibrateOut[x][4]) * y +
|
||||
Global.fCalibrateOut[x][3]) *
|
||||
y +
|
||||
Global.fCalibrateOut[x][2]) *
|
||||
y +
|
||||
Global.fCalibrateOut[x][1]) *
|
||||
y +
|
||||
Global.fCalibrateOut[x][0]; // zakres <0;1>
|
||||
double temp = (((((
|
||||
Global.fCalibrateOut[x][5] * y)
|
||||
+ Global.fCalibrateOut[x][4]) * y
|
||||
+ Global.fCalibrateOut[x][3]) * y
|
||||
+ Global.fCalibrateOut[x][2]) * y
|
||||
+ Global.fCalibrateOut[x][1]) * y
|
||||
+ Global.fCalibrateOut[x][0]; // zakres <0;1>
|
||||
if( Global.iCalibrateOutDebugInfo == x ) {
|
||||
WriteLog( " calibrated=" + std::to_string( temp ) );
|
||||
}
|
||||
@@ -320,11 +319,13 @@ float Console::AnalogCalibrateGet(int x)
|
||||
if (iMode == 4 && PoKeys55[0])
|
||||
{
|
||||
float b = PoKeys55[0]->fAnalog[x];
|
||||
b = (((((Global.fCalibrateIn[x][5] * b) + Global.fCalibrateIn[x][4]) * b +
|
||||
Global.fCalibrateIn[x][3]) * b +
|
||||
Global.fCalibrateIn[x][2]) * b +
|
||||
Global.fCalibrateIn[x][1]) * b +
|
||||
Global.fCalibrateIn[x][0];
|
||||
b = (((((
|
||||
Global.fCalibrateIn[x][5] * b)
|
||||
+ Global.fCalibrateIn[x][4]) * b
|
||||
+ Global.fCalibrateIn[x][3]) * b
|
||||
+ Global.fCalibrateIn[x][2]) * b
|
||||
+ Global.fCalibrateIn[x][1]) * b
|
||||
+ Global.fCalibrateIn[x][0];
|
||||
if (x == 0) return (b + 2) / 8;
|
||||
if (x == 1) return b/10;
|
||||
else return b;
|
||||
|
||||
24
Driver.cpp
24
Driver.cpp
@@ -2021,8 +2021,12 @@ bool TController::CheckVehicles(TOrders user)
|
||||
pVehicles[1] = p; // zapamiętanie ostatniego
|
||||
fLength += p->MoverParameters->Dim.L; // dodanie długości pojazdu
|
||||
fMass += p->MoverParameters->TotalMass; // dodanie masy łącznie z ładunkiem
|
||||
if (fVelMax < 0 ? true : p->MoverParameters->Vmax < fVelMax)
|
||||
fVelMax = p->MoverParameters->Vmax; // ustalenie maksymalnej prędkości dla składu
|
||||
fVelMax = min_speed( fVelMax, p->MoverParameters->Vmax ); // ustalenie maksymalnej prędkości dla składu
|
||||
// reset oerlikon brakes consist flag as different type was detected
|
||||
if( ( p->MoverParameters->BrakeSubsystem != TBrakeSubSystem::ss_ESt )
|
||||
&& ( p->MoverParameters->BrakeSubsystem != TBrakeSubSystem::ss_LSt ) ) {
|
||||
iDrivigFlags &= ~( moveOerlikons );
|
||||
}
|
||||
p = p->Neightbour(dir); // pojazd podłączony od wskazanej strony
|
||||
}
|
||||
if (main)
|
||||
@@ -2034,9 +2038,8 @@ bool TController::CheckVehicles(TOrders user)
|
||||
p = pVehicles[0];
|
||||
while (p)
|
||||
{
|
||||
if (TrainParams)
|
||||
if (p->asDestination == "none")
|
||||
p->DestinationSet(TrainParams->Relation2, TrainParams->TrainName); // relacja docelowa, jeśli nie było
|
||||
if (p->asDestination == "none")
|
||||
p->DestinationSet(TrainParams->Relation2, TrainParams->TrainName); // relacja docelowa, jeśli nie było
|
||||
if (AIControllFlag) // jeśli prowadzi komputer
|
||||
p->RaLightsSet(0, 0); // gasimy światła
|
||||
if (p->MoverParameters->EnginePowerSource.SourceType == TPowerSource::CurrentCollector)
|
||||
@@ -3020,10 +3023,8 @@ void TController::SpeedSet()
|
||||
mvOccupied->DirectionForward(); //żeby EN57 jechały na drugiej nastawie
|
||||
{
|
||||
if (mvControlling->MainCtrlPos &&
|
||||
!mvControlling
|
||||
->StLinFlag) // jak niby jedzie, ale ma rozłączone liniowe
|
||||
mvControlling->DecMainCtrl(
|
||||
2); // to na zero i czekać na przewalenie kułakowego
|
||||
!mvControlling->StLinFlag) // jak niby jedzie, ale ma rozłączone liniowe
|
||||
mvControlling->DecMainCtrl(2); // to na zero i czekać na przewalenie kułakowego
|
||||
else
|
||||
switch (mvControlling->MainCtrlPos)
|
||||
{ // ruch nastawnika uzależniony jest od aktualnie ustawionej
|
||||
@@ -5225,10 +5226,7 @@ TController::UpdateSituation(double dt) {
|
||||
}
|
||||
|
||||
if( ( mvOccupied->BrakeCtrlPos < 0 )
|
||||
&& ( mvOccupied->EqvtPipePress > (
|
||||
fReady < 0.25 ?
|
||||
5.1 :
|
||||
5.2 ) ) ) {
|
||||
&& ( mvOccupied->EqvtPipePress > ( fReady < 0.25 ? 5.1 : 5.2 ) ) ) {
|
||||
mvOccupied->BrakeLevelSet( mvOccupied->Handle->GetPos( bh_RP ) );
|
||||
}
|
||||
}
|
||||
|
||||
51
DynObj.cpp
51
DynObj.cpp
@@ -4203,6 +4203,21 @@ void TDynamicObject::RenderSounds() {
|
||||
}
|
||||
}
|
||||
}
|
||||
// door locks
|
||||
if( MoverParameters->DoorBlockedFlag() != m_doorlocks ) {
|
||||
// toggle state of the locks...
|
||||
m_doorlocks = !m_doorlocks;
|
||||
// ...and play relevant sounds
|
||||
for( auto &door : m_doorsounds ) {
|
||||
if( m_doorlocks ) {
|
||||
door.lock.play( sound_flags::exclusive );
|
||||
}
|
||||
else {
|
||||
door.unlock.play( sound_flags::exclusive );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// horns
|
||||
if( TestFlag( MoverParameters->WarningSignal, 1 ) ) {
|
||||
sHorn1.play( sound_flags::exclusive | sound_flags::looping );
|
||||
@@ -5413,7 +5428,7 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName,
|
||||
}
|
||||
|
||||
else if( token == "dooropen:" ) {
|
||||
sound_source soundtemplate { sound_placement::general };
|
||||
sound_source soundtemplate { sound_placement::general, 25.f };
|
||||
soundtemplate.deserialize( parser, sound_type::single );
|
||||
soundtemplate.owner( this );
|
||||
for( auto &door : m_doorsounds ) {
|
||||
@@ -5425,7 +5440,7 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName,
|
||||
}
|
||||
|
||||
else if( token == "doorclose:" ) {
|
||||
sound_source soundtemplate { sound_placement::general };
|
||||
sound_source soundtemplate { sound_placement::general, 25.f };
|
||||
soundtemplate.deserialize( parser, sound_type::single );
|
||||
soundtemplate.owner( this );
|
||||
for( auto &door : m_doorsounds ) {
|
||||
@@ -5436,8 +5451,32 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName,
|
||||
}
|
||||
}
|
||||
|
||||
else if( token == "doorlock:" ) {
|
||||
sound_source soundtemplate { sound_placement::general, 12.5f };
|
||||
soundtemplate.deserialize( parser, sound_type::single );
|
||||
soundtemplate.owner( this );
|
||||
for( auto &door : m_doorsounds ) {
|
||||
// apply configuration to all defined doors, but preserve their individual offsets
|
||||
auto const dooroffset { door.lock.offset() };
|
||||
door.lock = soundtemplate;
|
||||
door.lock.offset( dooroffset );
|
||||
}
|
||||
}
|
||||
|
||||
else if( token == "doorunlock:" ) {
|
||||
sound_source soundtemplate { sound_placement::general, 12.5f };
|
||||
soundtemplate.deserialize( parser, sound_type::single );
|
||||
soundtemplate.owner( this );
|
||||
for( auto &door : m_doorsounds ) {
|
||||
// apply configuration to all defined doors, but preserve their individual offsets
|
||||
auto const dooroffset { door.unlock.offset() };
|
||||
door.unlock = soundtemplate;
|
||||
door.unlock.offset( dooroffset );
|
||||
}
|
||||
}
|
||||
|
||||
else if( token == "doorstepopen:" ) {
|
||||
sound_source soundtemplate { sound_placement::general };
|
||||
sound_source soundtemplate { sound_placement::general, 20.f };
|
||||
soundtemplate.deserialize( parser, sound_type::single );
|
||||
soundtemplate.owner( this );
|
||||
for( auto &door : m_doorsounds ) {
|
||||
@@ -5449,7 +5488,7 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName,
|
||||
}
|
||||
|
||||
else if( token == "doorstepclose:" ) {
|
||||
sound_source soundtemplate { sound_placement::general };
|
||||
sound_source soundtemplate { sound_placement::general, 20.f };
|
||||
soundtemplate.deserialize( parser, sound_type::single );
|
||||
soundtemplate.owner( this );
|
||||
for( auto &door : m_doorsounds ) {
|
||||
@@ -5539,6 +5578,8 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName,
|
||||
auto const location { glm::vec3 { MoverParameters->Dim.W * 0.5f, MoverParameters->Dim.H * 0.5f, offset } };
|
||||
door.rsDoorClose.offset( location );
|
||||
door.rsDoorOpen.offset( location );
|
||||
door.lock.offset( location );
|
||||
door.unlock.offset( location );
|
||||
door.step_close.offset( location );
|
||||
door.step_open.offset( location );
|
||||
m_doorsounds.emplace_back( door );
|
||||
@@ -5549,6 +5590,8 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName,
|
||||
auto const location { glm::vec3 { MoverParameters->Dim.W * -0.5f, MoverParameters->Dim.H * 0.5f, offset } };
|
||||
door.rsDoorClose.offset( location );
|
||||
door.rsDoorOpen.offset( location );
|
||||
door.lock.offset( location );
|
||||
door.unlock.offset( location );
|
||||
door.step_close.offset( location );
|
||||
door.step_open.offset( location );
|
||||
m_doorsounds.emplace_back( door );
|
||||
|
||||
11
DynObj.h
11
DynObj.h
@@ -305,10 +305,12 @@ private:
|
||||
};
|
||||
|
||||
struct door_sounds {
|
||||
sound_source rsDoorOpen { sound_placement::general, 25.f }; // Ra: przeniesione z kabiny
|
||||
sound_source rsDoorClose { sound_placement::general, 25.f };
|
||||
sound_source step_open { sound_placement::general, 25.f };
|
||||
sound_source step_close { sound_placement::general, 25.f };
|
||||
sound_source rsDoorOpen { sound_placement::general }; // Ra: przeniesione z kabiny
|
||||
sound_source rsDoorClose { sound_placement::general };
|
||||
sound_source lock { sound_placement::general };
|
||||
sound_source unlock { sound_placement::general };
|
||||
sound_source step_open { sound_placement::general };
|
||||
sound_source step_close { sound_placement::general };
|
||||
};
|
||||
|
||||
struct exchange_sounds {
|
||||
@@ -423,6 +425,7 @@ private:
|
||||
std::array<coupler_sounds, 2> m_couplersounds; // always front and rear
|
||||
std::vector<pantograph_sounds> m_pantographsounds; // typically 2 but can be less (or more?)
|
||||
std::vector<door_sounds> m_doorsounds; // can expect symmetrical arrangement, but don't count on it
|
||||
bool m_doorlocks { false }; // sound helper, current state of door locks
|
||||
sound_source sDepartureSignal { sound_placement::general };
|
||||
sound_source sHorn1 { sound_placement::external, 5 * EU07_SOUND_RUNNINGNOISECUTOFFRANGE };
|
||||
sound_source sHorn2 { sound_placement::external, 5 * EU07_SOUND_RUNNINGNOISECUTOFFRANGE };
|
||||
|
||||
@@ -1764,11 +1764,15 @@ event_manager::export_as_text( std::ostream &Output ) const {
|
||||
|
||||
Output << "// events\n";
|
||||
for( auto const *event : m_events ) {
|
||||
event->export_as_text( Output );
|
||||
if( event->group() == null_handle ) {
|
||||
event->export_as_text( Output );
|
||||
}
|
||||
}
|
||||
Output << "// event launchers\n";
|
||||
for( auto const *launcher : m_launchers.sequence() ) {
|
||||
launcher->export_as_text( Output );
|
||||
if( launcher->group() == null_handle ) {
|
||||
launcher->export_as_text( Output );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
19
Event.h
19
Event.h
@@ -95,6 +95,10 @@ public:
|
||||
bool StopCommand();
|
||||
void StopCommandSent();
|
||||
void Append(TEvent *e);
|
||||
void
|
||||
group( scene::group_handle Group );
|
||||
scene::group_handle
|
||||
group() const;
|
||||
// members
|
||||
std::string asName;
|
||||
bool m_ignored { false }; // replacement for tp_ignored
|
||||
@@ -114,9 +118,24 @@ public:
|
||||
bool m_conditionalelse { false }; // TODO: make a part of condition struct
|
||||
|
||||
private:
|
||||
// methods
|
||||
void Conditions( cParser *parser, std::string s );
|
||||
// members
|
||||
scene::group_handle m_group { null_handle }; // group this event belongs to, if any
|
||||
};
|
||||
|
||||
inline
|
||||
void
|
||||
TEvent::group( scene::group_handle Group ) {
|
||||
m_group = Group;
|
||||
}
|
||||
|
||||
inline
|
||||
scene::group_handle
|
||||
TEvent::group() const {
|
||||
return m_group;
|
||||
}
|
||||
|
||||
class event_manager {
|
||||
|
||||
public:
|
||||
|
||||
12
Globals.h
12
Globals.h
@@ -141,12 +141,12 @@ struct global_settings {
|
||||
double fBrakeStep{ 1.0 }; // krok zmiany hamulca dla klawiszy [Num3] i [Num9]
|
||||
// parametry kalibracyjne wejść z pulpitu
|
||||
double fCalibrateIn[ 6 ][ 6 ] = {
|
||||
{ 0, 1, 0, 0, 0, 0 },
|
||||
{ 0, 1, 0, 0, 0, 0 },
|
||||
{ 0, 1, 0, 0, 0, 0 },
|
||||
{ 0, 1, 0, 0, 0, 0 },
|
||||
{ 0, 1, 0, 0, 0, 0 },
|
||||
{ 0, 1, 0, 0, 0, 0 } };
|
||||
{ 0, 0, 0, 0, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0, 0 } };
|
||||
// parametry kalibracyjne wyjść dla pulpitu
|
||||
double fCalibrateOut[ 7 ][ 6 ] = {
|
||||
{ 0, 1, 0, 0, 0, 0 },
|
||||
|
||||
133
Train.cpp
133
Train.cpp
@@ -4409,13 +4409,16 @@ void TTrain::UpdateMechPosition(double dt)
|
||||
&& ( true == mvOccupied->TruckHunting ) ) {
|
||||
// hunting oscillation
|
||||
HuntingAngle = clamp_circular( HuntingAngle + 4.0 * HuntingShake.frequency * dt * mvOccupied->Vel, 360.0 );
|
||||
shakevector.x +=
|
||||
( std::sin( glm::radians( HuntingAngle ) ) * dt * HuntingShake.scale )
|
||||
* interpolate(
|
||||
auto const huntingamount =
|
||||
interpolate(
|
||||
0.0, 1.0,
|
||||
clamp(
|
||||
( mvOccupied->Vel - HuntingShake.fadein_begin ) / ( HuntingShake.fadein_end - HuntingShake.fadein_begin ),
|
||||
0.0, 1.0 ) );
|
||||
shakevector.x +=
|
||||
( std::sin( glm::radians( HuntingAngle ) ) * dt * HuntingShake.scale )
|
||||
* huntingamount;
|
||||
IsHunting = ( huntingamount > 0.025 );
|
||||
}
|
||||
|
||||
if( iVel > 0.5 ) {
|
||||
@@ -5873,60 +5876,24 @@ TTrain::update_sounds( double const Deltatime ) {
|
||||
&& ( false == Global.CabWindowOpen )
|
||||
&& ( DynamicObject->GetVelocity() > 0.5 ) ) {
|
||||
|
||||
// frequency calculation
|
||||
auto const normalizer { (
|
||||
true == rsRunningNoise.is_combined() ?
|
||||
mvOccupied->Vmax * 0.01f :
|
||||
1.f ) };
|
||||
auto const frequency {
|
||||
rsRunningNoise.m_frequencyoffset
|
||||
+ rsRunningNoise.m_frequencyfactor * mvOccupied->Vel * normalizer };
|
||||
|
||||
// volume calculation
|
||||
volume =
|
||||
rsRunningNoise.m_amplitudeoffset
|
||||
+ rsRunningNoise.m_amplitudefactor * mvOccupied->Vel;
|
||||
if( std::abs( mvOccupied->nrot ) > 0.01 ) {
|
||||
// hamulce wzmagaja halas
|
||||
auto const brakeforceratio { (
|
||||
clamp(
|
||||
mvOccupied->UnitBrakeForce / std::max( 1.0, mvOccupied->BrakeForceR( 1.0, mvOccupied->Vel ) / ( mvOccupied->NAxles * std::max( 1, mvOccupied->NBpA ) ) ),
|
||||
0.0, 1.0 ) ) };
|
||||
|
||||
volume *= 1 + 0.125 * brakeforceratio;
|
||||
}
|
||||
// scale volume by track quality
|
||||
// TODO: track quality and/or environment factors as separate subroutine
|
||||
volume *=
|
||||
interpolate(
|
||||
0.8, 1.2,
|
||||
clamp(
|
||||
DynamicObject->MyTrack->iQualityFlag / 20.0,
|
||||
0.0, 1.0 ) );
|
||||
// for single sample sounds muffle the playback at low speeds
|
||||
if( false == rsRunningNoise.is_combined() ) {
|
||||
volume *=
|
||||
interpolate(
|
||||
0.0, 1.0,
|
||||
clamp(
|
||||
mvOccupied->Vel / 40.0,
|
||||
0.0, 1.0 ) );
|
||||
}
|
||||
|
||||
if( volume > 0.05 ) {
|
||||
rsRunningNoise
|
||||
.pitch( frequency )
|
||||
.gain( volume )
|
||||
.play( sound_flags::exclusive | sound_flags::looping );
|
||||
}
|
||||
else {
|
||||
rsRunningNoise.stop();
|
||||
}
|
||||
update_sounds_runningnoise( rsRunningNoise );
|
||||
}
|
||||
else {
|
||||
// don't play the optional ending sound if the listener switches views
|
||||
rsRunningNoise.stop( true == FreeFlyModeFlag );
|
||||
}
|
||||
// hunting oscillation noise
|
||||
if( ( false == FreeFlyModeFlag )
|
||||
&& ( false == Global.CabWindowOpen )
|
||||
&& ( DynamicObject->GetVelocity() > 0.5 )
|
||||
&& ( IsHunting ) ) {
|
||||
|
||||
update_sounds_runningnoise( rsHuntingNoise );
|
||||
}
|
||||
else {
|
||||
// don't play the optional ending sound if the listener switches views
|
||||
rsHuntingNoise.stop( true == FreeFlyModeFlag );
|
||||
}
|
||||
|
||||
// McZapkie-141102: SHP i czuwak, TODO: sygnalizacja kabinowa
|
||||
if (mvOccupied->SecuritySystem.Status > 0) {
|
||||
@@ -5977,6 +5944,58 @@ TTrain::update_sounds( double const Deltatime ) {
|
||||
}
|
||||
}
|
||||
|
||||
void TTrain::update_sounds_runningnoise( sound_source &Sound ) {
|
||||
// frequency calculation
|
||||
auto const normalizer { (
|
||||
true == Sound.is_combined() ?
|
||||
mvOccupied->Vmax * 0.01f :
|
||||
1.f ) };
|
||||
auto const frequency {
|
||||
Sound.m_frequencyoffset
|
||||
+ Sound.m_frequencyfactor * mvOccupied->Vel * normalizer };
|
||||
|
||||
// volume calculation
|
||||
auto volume =
|
||||
Sound.m_amplitudeoffset
|
||||
+ Sound.m_amplitudefactor * mvOccupied->Vel;
|
||||
if( std::abs( mvOccupied->nrot ) > 0.01 ) {
|
||||
// hamulce wzmagaja halas
|
||||
auto const brakeforceratio { (
|
||||
clamp(
|
||||
mvOccupied->UnitBrakeForce / std::max( 1.0, mvOccupied->BrakeForceR( 1.0, mvOccupied->Vel ) / ( mvOccupied->NAxles * std::max( 1, mvOccupied->NBpA ) ) ),
|
||||
0.0, 1.0 ) ) };
|
||||
|
||||
volume *= 1 + 0.125 * brakeforceratio;
|
||||
}
|
||||
// scale volume by track quality
|
||||
// TODO: track quality and/or environment factors as separate subroutine
|
||||
volume *=
|
||||
interpolate(
|
||||
0.8, 1.2,
|
||||
clamp(
|
||||
DynamicObject->MyTrack->iQualityFlag / 20.0,
|
||||
0.0, 1.0 ) );
|
||||
// for single sample sounds muffle the playback at low speeds
|
||||
if( false == Sound.is_combined() ) {
|
||||
volume *=
|
||||
interpolate(
|
||||
0.0, 1.0,
|
||||
clamp(
|
||||
mvOccupied->Vel / 40.0,
|
||||
0.0, 1.0 ) );
|
||||
}
|
||||
|
||||
if( volume > 0.05 ) {
|
||||
Sound
|
||||
.pitch( frequency )
|
||||
.gain( volume )
|
||||
.play( sound_flags::exclusive | sound_flags::looping );
|
||||
}
|
||||
else {
|
||||
Sound.stop();
|
||||
}
|
||||
}
|
||||
|
||||
bool TTrain::CabChange(int iDirection)
|
||||
{ // McZapkie-090902: zmiana kabiny 1->0->2 i z powrotem
|
||||
if( ( DynamicObject->Mechanik == nullptr )
|
||||
@@ -6146,6 +6165,14 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName)
|
||||
rsRunningNoise.m_amplitudefactor /= ( 1 + mvOccupied->Vmax );
|
||||
rsRunningNoise.m_frequencyfactor /= ( 1 + mvOccupied->Vmax );
|
||||
}
|
||||
else if( token == "huntingnoise:" ) {
|
||||
// hunting oscillation sound:
|
||||
rsHuntingNoise.deserialize( parser, sound_type::single, sound_parameters::amplitude | sound_parameters::frequency, mvOccupied->Vmax );
|
||||
rsHuntingNoise.owner( DynamicObject );
|
||||
|
||||
rsHuntingNoise.m_amplitudefactor /= ( 1 + mvOccupied->Vmax );
|
||||
rsHuntingNoise.m_frequencyfactor /= ( 1 + mvOccupied->Vmax );
|
||||
}
|
||||
else if (token == "mechspring:")
|
||||
{
|
||||
// parametry bujania kamery:
|
||||
@@ -6217,7 +6244,7 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
|
||||
&dsbReverserKey, &dsbNastawnikJazdy, &dsbNastawnikBocz,
|
||||
&dsbSwitch, &dsbPneumaticSwitch,
|
||||
&rsHiss, &rsHissU, &rsHissE, &rsHissX, &rsHissT, &rsSBHiss, &rsSBHissU,
|
||||
&rsFadeSound, &rsRunningNoise,
|
||||
&rsFadeSound, &rsRunningNoise, &rsHuntingNoise,
|
||||
&dsbHasler, &dsbBuzzer, &dsbSlipAlarm, &m_radiosound, &m_radiostop
|
||||
};
|
||||
for( auto sound : sounds ) {
|
||||
|
||||
3
Train.h
3
Train.h
@@ -142,6 +142,7 @@ class TTrain
|
||||
void set_paired_open_motor_connectors_button( bool const State );
|
||||
// update function subroutines
|
||||
void update_sounds( double const Deltatime );
|
||||
void update_sounds_runningnoise( sound_source &Sound );
|
||||
|
||||
// command handlers
|
||||
// NOTE: we're currently using universal handlers and static handler map but it may be beneficial to have these implemented on individual class instance basis
|
||||
@@ -572,6 +573,7 @@ public: // reszta może by?publiczna
|
||||
float fadein_end { 0.f }; // full effect speed in km/h
|
||||
} HuntingShake;
|
||||
float HuntingAngle { 0.f }; // crude approximation of hunting oscillation; current angle of sine wave
|
||||
bool IsHunting { false };
|
||||
|
||||
sound_source dsbReverserKey { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // hunter-121211
|
||||
sound_source dsbNastawnikJazdy { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
|
||||
@@ -591,6 +593,7 @@ public: // reszta może by?publiczna
|
||||
|
||||
sound_source rsFadeSound { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
|
||||
sound_source rsRunningNoise{ sound_placement::internal, EU07_SOUND_GLOBALRANGE };
|
||||
sound_source rsHuntingNoise{ sound_placement::internal, EU07_SOUND_GLOBALRANGE };
|
||||
|
||||
sound_source dsbHasler { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
|
||||
sound_source dsbBuzzer { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE };
|
||||
|
||||
@@ -37,9 +37,10 @@ basic_editor::translate( scene::basic_node *Node, glm::dvec3 const &Location, bo
|
||||
else {
|
||||
// translate entire group
|
||||
// TODO: contextual switch between group and item translation
|
||||
auto nodegroup { scene::Groups.group( Node->group() ) };
|
||||
// TODO: translation of affected/relevant events
|
||||
auto &nodegroup { scene::Groups.group( Node->group() ).nodes };
|
||||
std::for_each(
|
||||
nodegroup.first, nodegroup.second,
|
||||
std::begin( nodegroup ), std::end( nodegroup ),
|
||||
[&]( auto *node ) {
|
||||
translate_node( node, node->location() + translation ); } );
|
||||
}
|
||||
@@ -59,9 +60,10 @@ basic_editor::translate( scene::basic_node *Node, float const Offset ) {
|
||||
else {
|
||||
// translate entire group
|
||||
// TODO: contextual switch between group and item translation
|
||||
auto nodegroup { scene::Groups.group( Node->group() ) };
|
||||
// TODO: translation of affected/relevant events
|
||||
auto &nodegroup { scene::Groups.group( Node->group() ).nodes };
|
||||
std::for_each(
|
||||
nodegroup.first, nodegroup.second,
|
||||
std::begin( nodegroup ), std::end( nodegroup ),
|
||||
[&]( auto *node ) {
|
||||
translate_node( node, offset ); } );
|
||||
}
|
||||
@@ -146,10 +148,11 @@ basic_editor::rotate( scene::basic_node *Node, glm::vec3 const &Angle, float con
|
||||
else {
|
||||
// rotate entire group
|
||||
// TODO: contextual switch between group and item rotation
|
||||
// TODO: translation of affected/relevant events
|
||||
auto const rotationcenter { Node->location() };
|
||||
auto nodegroup { scene::Groups.group( Node->group() ) };
|
||||
auto &nodegroup { scene::Groups.group( Node->group() ).nodes };
|
||||
std::for_each(
|
||||
nodegroup.first, nodegroup.second,
|
||||
std::begin( nodegroup ), std::end( nodegroup ),
|
||||
[&]( auto *node ) {
|
||||
rotate_node( node, rotation );
|
||||
if( node != Node ) {
|
||||
|
||||
@@ -10,6 +10,9 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "stdafx.h"
|
||||
#include "scenenodegroups.h"
|
||||
|
||||
#include "event.h"
|
||||
#include "memcell.h"
|
||||
|
||||
namespace scene {
|
||||
|
||||
node_groups Groups;
|
||||
@@ -37,7 +40,7 @@ node_groups::close() {
|
||||
|
||||
auto lookup { m_groupmap.find( closinggroup ) };
|
||||
if( ( lookup != m_groupmap.end() )
|
||||
&& ( lookup->second.size() <= 1 ) ) {
|
||||
&& ( ( lookup->second.nodes.size() + lookup->second.events.size() ) <= 1 ) ) {
|
||||
|
||||
erase( lookup );
|
||||
}
|
||||
@@ -65,20 +68,62 @@ node_groups::insert( scene::group_handle const Group, scene::basic_node *Node )
|
||||
|
||||
if( Group == null_handle ) { return; }
|
||||
|
||||
auto &nodesequence { m_groupmap[ Group ] };
|
||||
auto &nodesequence { m_groupmap[ Group ].nodes };
|
||||
if( std::find( std::begin( nodesequence ), std::end( nodesequence ), Node ) == std::end( nodesequence ) ) {
|
||||
// don't add the same node twice
|
||||
nodesequence.emplace_back( Node );
|
||||
}
|
||||
}
|
||||
|
||||
// places provided event in specified group
|
||||
void
|
||||
node_groups::insert( scene::group_handle const Group, TEvent *Event ) {
|
||||
|
||||
// TBD, TODO: automatically unregister the event from its current group?
|
||||
Event->group( Group );
|
||||
|
||||
if( Group == null_handle ) { return; }
|
||||
|
||||
auto &eventsequence { m_groupmap[ Group ].events };
|
||||
if( std::find( std::begin( eventsequence ), std::end( eventsequence ), Event ) == std::end( eventsequence ) ) {
|
||||
// don't add the same node twice
|
||||
eventsequence.emplace_back( Event );
|
||||
}
|
||||
}
|
||||
|
||||
// sends basic content of the class in legacy (text) format to provided stream
|
||||
void
|
||||
node_groups::export_as_text( std::ostream &Output ) const {
|
||||
|
||||
for( auto const &group : m_groupmap ) {
|
||||
|
||||
Output << "group\n";
|
||||
for( auto *node : group.second.nodes ) {
|
||||
// HACK: auto-generated memory cells aren't exported, so we check for this
|
||||
// TODO: is_exportable as basic_node method
|
||||
if( ( typeid( *node ) == typeid( TMemCell ) )
|
||||
&& ( false == static_cast<TMemCell *>( node )->is_exportable ) ) {
|
||||
continue;
|
||||
}
|
||||
node->export_as_text( Output );
|
||||
}
|
||||
for( auto *event : group.second.events ) {
|
||||
event->export_as_text( Output );
|
||||
}
|
||||
Output << "endgroup\n";
|
||||
}
|
||||
}
|
||||
|
||||
// removes specified group from the group list and group information from the group's nodes
|
||||
void
|
||||
node_groups::erase( group_map::const_iterator Group ) {
|
||||
|
||||
for( auto *node : Group->second ) {
|
||||
for( auto *node : Group->second.nodes ) {
|
||||
node->group( null_handle );
|
||||
}
|
||||
for( auto *event : Group->second.events ) {
|
||||
event->group( null_handle );
|
||||
}
|
||||
m_groupmap.erase( Group );
|
||||
}
|
||||
|
||||
|
||||
@@ -13,14 +13,16 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
namespace scene {
|
||||
|
||||
struct basic_group {
|
||||
// members
|
||||
std::vector<scene::basic_node *> nodes;
|
||||
std::vector<TEvent *> events;
|
||||
};
|
||||
|
||||
// holds lists of grouped scene nodes
|
||||
class node_groups {
|
||||
// NOTE: during scenario deserialization encountering *.inc file causes creation of a new group on the group stack
|
||||
// this allows all nodes listed in this *.inc file to be grouped and potentially modified together by the editor.
|
||||
private:
|
||||
// types
|
||||
using node_sequence = std::vector<scene::basic_node *>;
|
||||
|
||||
public:
|
||||
// constructors
|
||||
node_groups() = default;
|
||||
@@ -37,14 +39,20 @@ public:
|
||||
// places provided node in specified group
|
||||
void
|
||||
insert( scene::group_handle const Group, scene::basic_node *Node );
|
||||
std::pair<node_sequence::iterator, node_sequence::iterator>
|
||||
// places provided event in specified group
|
||||
void
|
||||
insert( scene::group_handle const Group, TEvent *Event );
|
||||
// grants direct access to specified group
|
||||
scene::basic_group &
|
||||
group( scene::group_handle const Group ) {
|
||||
auto &group { m_groupmap[ Group ] };
|
||||
return { std::begin( group ), std::end( group ) }; }
|
||||
return m_groupmap[ Group ]; }
|
||||
// sends basic content of the class in legacy (text) format to provided stream
|
||||
void
|
||||
export_as_text( std::ostream &Output ) const;
|
||||
|
||||
private:
|
||||
// types
|
||||
using group_map = std::unordered_map<scene::group_handle, node_sequence>;
|
||||
using group_map = std::unordered_map<scene::group_handle, scene::basic_group>;
|
||||
// methods
|
||||
// removes specified group from the group list and group information from the group's nodes
|
||||
void
|
||||
|
||||
@@ -73,6 +73,8 @@ state_serializer::deserialize( cParser &Input, scene::scratch_data &Scratchpad )
|
||||
{ "description", &state_serializer::deserialize_description },
|
||||
{ "event", &state_serializer::deserialize_event },
|
||||
{ "firstinit", &state_serializer::deserialize_firstinit },
|
||||
{ "group", &state_serializer::deserialize_group },
|
||||
{ "endgroup", &state_serializer::deserialize_endgroup },
|
||||
{ "light", &state_serializer::deserialize_light },
|
||||
{ "node", &state_serializer::deserialize_node },
|
||||
{ "origin", &state_serializer::deserialize_origin },
|
||||
@@ -237,7 +239,10 @@ state_serializer::deserialize_event( cParser &Input, scene::scratch_data &Scratc
|
||||
Scratchpad.location.offset.top().z ) );
|
||||
event->Load( &Input, offset );
|
||||
|
||||
if( false == simulation::Events.insert( event ) ) {
|
||||
if( true == simulation::Events.insert( event ) ) {
|
||||
scene::Groups.insert( scene::Groups.handle(), event );
|
||||
}
|
||||
else {
|
||||
delete event;
|
||||
}
|
||||
}
|
||||
@@ -256,6 +261,18 @@ state_serializer::deserialize_firstinit( cParser &Input, scene::scratch_data &Sc
|
||||
Scratchpad.initialized = true;
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_group( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
scene::Groups.create();
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_endgroup( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
scene::Groups.close();
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_light( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
@@ -897,27 +914,39 @@ state_serializer::export_as_text( std::string const &Scenariofile ) const {
|
||||
filename = Global.asCurrentSceneryPath + filename + "_export";
|
||||
|
||||
std::ofstream scmfile { filename + ".scm" };
|
||||
// groups
|
||||
scmfile << "// groups\n";
|
||||
scene::Groups.export_as_text( scmfile );
|
||||
// tracks
|
||||
scmfile << "// paths\n";
|
||||
for( auto const *path : Paths.sequence() ) {
|
||||
path->export_as_text( scmfile );
|
||||
if( path->group() == null_handle ) {
|
||||
path->export_as_text( scmfile );
|
||||
}
|
||||
}
|
||||
// traction
|
||||
scmfile << "// traction\n";
|
||||
for( auto const *traction : Traction.sequence() ) {
|
||||
traction->export_as_text( scmfile );
|
||||
if( traction->group() == null_handle ) {
|
||||
traction->export_as_text( scmfile );
|
||||
}
|
||||
}
|
||||
// power grid
|
||||
scmfile << "// traction power sources\n";
|
||||
for( auto const *powersource : Powergrid.sequence() ) {
|
||||
powersource->export_as_text( scmfile );
|
||||
if( powersource->group() == null_handle ) {
|
||||
powersource->export_as_text( scmfile );
|
||||
}
|
||||
}
|
||||
// models
|
||||
scmfile << "// instanced models\n";
|
||||
for( auto const *instance : Instances.sequence() ) {
|
||||
instance->export_as_text( scmfile );
|
||||
if( instance->group() == null_handle ) {
|
||||
instance->export_as_text( scmfile );
|
||||
}
|
||||
}
|
||||
// sounds
|
||||
// NOTE: sounds currently aren't included in groups
|
||||
scmfile << "// sounds\n";
|
||||
Region->export_as_text( scmfile );
|
||||
|
||||
@@ -925,7 +954,8 @@ state_serializer::export_as_text( std::string const &Scenariofile ) const {
|
||||
// mem cells
|
||||
ctrfile << "// memory cells\n";
|
||||
for( auto const *memorycell : Memory.sequence() ) {
|
||||
if( true == memorycell->is_exportable ) {
|
||||
if( ( true == memorycell->is_exportable )
|
||||
&& ( memorycell->group() == null_handle ) ) {
|
||||
memorycell->export_as_text( ctrfile );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ private:
|
||||
void deserialize_description( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_event( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_firstinit( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_group( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_endgroup( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_light( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_node( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_origin( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
|
||||
Reference in New Issue
Block a user