</x-boxleft>
<x-boxleft id="range" class="bar clear">
- <x-bar class="pause" id="pausebar">Paused</x-bar>
+ <x-bar class="pause" id="pausebar">Game paused</x-bar>
<x-bar class="error" id="errbar"> </x-bar>
<x-bar class="nosleep" id="nsbar"> </x-bar>
</x-boxleft>
// Helper functions:
+// Zero-left-pad a value in range [0;99] to two digits:
function pad2( x ) {
return x > 9 ? x : '0' + x;
}
-function s2hms(s) {
- var sgn = Math.sign(s);
- s = Math.abs(s);
- return ( sgn < 0 ? '-' : '' )
- + pad2( Math.floor(s / 3600) ) + ':'
- + pad2( Math.floor(s % 3600 / 60) ) + ':'
- + pad2( Math.floor(s % 60 ) );
-}
-
+// Convert seconds to "HH:MM" format:
function s2hm(s) {
var sgn = Math.sign(s);
s = Math.abs(s);
+ pad2( Math.floor(s % 3600 / 60) );
}
-function m2hm(s) {
- var sgn = Math.sign(s);
- s = Math.abs(s);
- return ( sgn < 0 ? '-' : '' )
- + pad2( Math.floor(s / 60) ) + ':'
- + pad2( Math.floor(s % 60) );
+// Convert minutes to "HH:MM" format:
+function m2hm(m) {
+ return s2hm( m * 60 );
}
+// Convert minutes to "DotW HH:MM" format:
function m2dhm(m) {
var d = [ 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun' ];
return d[ Math.floor(m / 1440 % 7) ] + ' ' + m2hm(m % 1440);
}
+// Set CSS class of element depending on warning level:
function warn(elem, lvl) {
if ( lvl == 0 ) {
elem.classList.remove('warn1');
var last_fuel = -1;
var last_odometer = -1;
+// State of telemetry saved from the last update cycle:
+var last_tele = null;
+
// Display update callback:
function update_cb() {
if (this.readyState == 4 && this.status == 200) {
var tele = JSON.parse(this.responseText);
- //// pause and error bar status:
-
+ // Check telemetry live status:
if ( !(tele.tele_flags & TELE_FLAG_ALIVE) ) {
if ( tnow() - last_active > 300 ) // 5 minutes NoSleep timeout
disableNoSleep();
- pausebar.style.display = 'none';
- errbar.style.display = 'block';
- errbar.innerHTML = 'Game offline';
+ if ( !last_tele || last_tele.tele_flags != tele.tele_tele_flags ) {
+ pausebar.style.display = 'none';
+ errbar.style.display = 'block';
+ errbar.innerHTML = 'Game offline';
+ }
+ last_tele = tele;
return;
}
- else if ( tele.tele_version !== TELE_VERSION ) {
- errbar.style.display = 'block';
- errbar.innerHTML = 'Version mismatch';
- } else {
- errbar.style.display = 'none';
+
+ // Check telemetry version:
+ if ( !last_tele || last_tele.version != tele.tele_version ) {
+ if ( tele.tele_version !== TELE_VERSION ) {
+ errbar.style.display = 'block';
+ errbar.innerHTML = 'Version mismatch';
+ } else {
+ errbar.style.display = 'none';
+ }
}
+ // Check game paused status:
if ( tele.paused ) {
if ( tnow() - last_active > 600 ) // 10 minutes NoSleep timeout
disableNoSleep();
- pausebar.style.display = 'block';
+ if ( pausebar.style.display != 'block' )
+ pausebar.style.display = 'block';
}
else {
last_active = tnow();
- pausebar.style.display = 'none';
+ if ( pausebar.style.display != 'none' )
+ pausebar.style.display = 'none';
}
//// "speedo" box
// speedometer:
- var aspeed = Math.abs( tele.speed );
- speed.innerHTML = (aspeed * 3.6).toFixed(0);
- if ( tele.nav_slimit > 0 && aspeed > tele.nav_slimit + 1.9 )
- warn( speed, 2 );
- else if ( tele.nav_slimit > 0 && aspeed > tele.nav_slimit + 0.3 )
- warn( speed, 1 );
- else
- warn( speed, 0 );
+ if ( !last_tele || last_tele.speed != tele.speed ) {
+ var aspeed = Math.abs( tele.speed );
+ speed.innerHTML = (aspeed * 3.6).toFixed(0);
+ if ( tele.nav_slimit > 0 && aspeed > tele.nav_slimit + 1.9 )
+ warn( speed, 2 );
+ else if ( tele.nav_slimit > 0 && aspeed > tele.nav_slimit + 0.3 )
+ warn( speed, 1 );
+ else
+ warn( speed, 0 );
+ }
// speed limit:
- if ( tele.nav_slimit > 0 ) {
- slimit.innerHTML = (tele.nav_slimit * 3.6).toFixed(0);
- slimitsign.style.visibility = 'visible';
+ if ( !last_tele || last_tele.nav_slimit != tele.nav_slimit ) {
+ if ( tele.nav_slimit > 0 ) {
+ slimit.innerHTML = (tele.nav_slimit * 3.6).toFixed(0);
+ slimitsign.style.visibility = 'visible';
+ }
+ else
+ slimitsign.style.visibility = 'hidden';
}
- else
- slimitsign.style.visibility = 'hidden';
// cruise control:
- cctrl.innerHTML = Math.round(tele.cctrl * 3.6);
+ if ( !last_tele || last_tele.cctrl != tele.cctrl )
+ cctrl.innerHTML = Math.round(tele.cctrl * 3.6);
// engine gear:
- gear.innerHTML = dgear(tele.gear_disp, tele.gear_fwdcnt, tele.shifter);
- if ( tele.clutch_eff > 0 )
- gear.classList.add('hilite');
- else
- gear.classList.remove('hilite');
- // engine rpm:
- rpm.innerHTML = tele.rpm.toFixed(0);
+ if ( !last_tele || last_tele.gear_disp != tele.gear_disp || last_tele.shifter != tele.shifter )
+ gear.innerHTML = dgear(tele.gear_disp, tele.gear_fwdcnt, tele.shifter);
+ // clutch:
+ if ( !last_tele || last_tele.clutch_eff != tele.clutch_eff ) {
+ if ( tele.clutch_eff > 0 )
+ gear.classList.add('hilite');
+ else
+ gear.classList.remove('hilite');
+ }
+ // engine rpm and rpm bar:
+ if ( !last_tele || last_tele.rpm != tele.rpm ) {
+ rpm.innerHTML = tele.rpm.toFixed(0);
+ rpmbar.style.width = (100 - tele.rpm / 25).toFixed(0) + '%';
+ }
// throttle bar:
- thrbar.style.width = (100 - tele.throttle_eff * 100).toFixed(0) + '%';
- // rpm bar:
- rpmbar.style.width = (100 - tele.rpm / 25).toFixed(0) + '%';
+ if ( !last_tele || last_tele.throttle_eff != tele.throttle_eff )
+ thrbar.style.width = (100 - tele.throttle_eff * 100).toFixed(0) + '%';
- //// "range" box
+ //// "fuel & range" box
// fuel amount:
- fuel.innerHTML = (tele.fuel - 0.5).toFixed(0);
- warn( fuel, tele.fuel_warn ? 1 : 0 );
-
+ if ( !last_tele || last_tele.fuel != tele.fuel ) {
+ fuel.innerHTML = (tele.fuel - 0.5).toFixed(0);
+ warn( fuel, tele.fuel_warn ? 1 : 0 );
+ }
// estimated range remaining:
- fuel_range.innerHTML = (tele.fuel_range - 0.5).toFixed(0);
-
+ if ( !last_tele || last_tele.fuel_range != tele.fuel_range )
+ fuel_range.innerHTML = (tele.fuel_range - 0.5).toFixed(0);
// current fuel consumption:
+ // Note: here we're not checking against last telemetry!
if ( last_fuel != tele.fuel && last_odometer != tele.odometer ) {
if ( last_fuel > 0 && last_odometer > 0 ) {
var fc = (last_fuel-tele.fuel)*100 / (tele.odometer-last_odometer);
else {
// keep last displayed value
}
-
// average fuel consumption:
- fuel_avg.innerHTML = (tele.fuel_avg * 100).toFixed(1);
-
+ if ( !last_tele || last_tele.fuel_avg != tele.fuel_avg )
+ fuel_avg.innerHTML = (tele.fuel_avg * 100).toFixed(1);
// odometer:
- odometer.innerHTML = tele.odometer.toFixed(1);
+ if ( !last_tele || last_tele.odometer != tele.odometer )
+ odometer.innerHTML = tele.odometer.toFixed(1);
//// "nav" box
// current day and time:
- nav_date.innerHTML = m2dhm(tele.game_time);
-
+ if ( !last_tele || last_tele.game_time != tele.game_time )
+ nav_date.innerHTML = m2dhm(tele.game_time);
// remaining distance to destination:
- nav_dist.innerHTML = (tele.nav_dist / 1000).toFixed(0);
-
+ if ( !last_tele || last_tele.nav_dist != tele.nav_dist )
+ nav_dist.innerHTML = (tele.nav_dist / 1000).toFixed(0);
// estimated time till arrival at destination:
- nav_eta.innerHTML = s2hm(tele.nav_eta);
-
+ if ( !last_tele || last_tele.nav_eta != tele.nav_eta )
+ nav_eta.innerHTML = s2hm(tele.nav_eta);
// time until next rest stop:
- next_rest.innerHTML = m2hm(tele.next_rest);
- warn( next_rest, tele.next_rest < 60 ? 2 : tele.next_rest < 99 ? 1 : 0 );
-
+ if ( !last_tele || last_tele.next_rest != tele.next_rest ) {
+ next_rest.innerHTML = m2hm(tele.next_rest);
+ warn( next_rest, tele.next_rest < 60 ? 2 : tele.next_rest < 99 ? 1 : 0 );
+ }
// remaining time until job delivery date:
- job_ttd.innerHTML =
- tele.job_isvalid
- ? tele.job_deltime != 4294967295
- ? m2hm(tele.job_deltime - tele.game_time)
- : '<span class="special">[external]</span>'
- : '-'
+ if ( !last_tele || last_tele.job_deltime != tele.job_deltime || last_tele.job_isvalid != tele.job_isvalid ) {
+ job_ttd.innerHTML =
+ tele.job_isvalid
+ ? tele.job_deltime != 4294967295
+ ? m2hm(tele.job_deltime - tele.game_time)
+ : '<span class="special">[external]</span>'
+ : '-'
+ }
//// "job" box
- // make and model of truck and number of trailers
- vehicle.innerHTML = tele.truck_brand + ' ' + tele.truck_name;
- trailer.innerHTML = tele.trailer_cnt;
- cargo.innerHTML = tele.job_isvalid ? tele.job_cargo : '-';
- cargomass.innerHTML = tele.job_isvalid ? (tele.job_cargo_mass / 1000).toFixed(0) + 't' : '-';
- source.innerHTML = tele.job_isvalid ? tele.job_source_city : '-';
- destination.innerHTML = tele.job_isvalid ? tele.job_destination_city : '-';
- reward.innerHTML = tele.job_isvalid ? tele.job_income + '.-' : '-';
+ // make and model of truck:
+ if ( !last_tele || last_tele.truck_brand != tele.truck_brand )
+ vehicle.innerHTML = tele.truck_brand + ' ' + tele.truck_name;
+ // number of trailers:
+ if ( !last_tele || last_tele.trailer_cnt != tele.trailer_cnt )
+ trailer.innerHTML = tele.trailer_cnt;
+ // current job parameters:
+ if ( !last_tele || last_tele.job_isvalid != tele.job_isvalid ) {
+ cargo.innerHTML = tele.job_isvalid ? tele.job_cargo : '-';
+ cargomass.innerHTML = tele.job_isvalid ? (tele.job_cargo_mass / 1000).toFixed(0) + 't' : '-';
+ source.innerHTML = tele.job_isvalid ? tele.job_source_city : '-';
+ destination.innerHTML = tele.job_isvalid ? tele.job_destination_city : '-';
+ reward.innerHTML = tele.job_isvalid ? tele.job_income + '.-' : '-';
+ }
+
+ // Save current telemetry state:
+ last_tele = tele;
}
else if (this.readyState == 4) {
disableNoSleep();