refactor: stock & vehicle typings

This commit is contained in:
2024-04-15 18:32:19 +02:00
parent 61c7f15fcf
commit 541572e415
13 changed files with 175 additions and 133 deletions
+3 -1
View File
@@ -42,7 +42,9 @@ main {
@media screen and (max-width: $breakpointMd) { @media screen and (max-width: $breakpointMd) {
main { main {
display: block; display: flex;
flex-direction: column;
gap: 1em;
} }
} }
</style> </style>
+6 -6
View File
@@ -28,7 +28,8 @@
{{ $t('inputs.input-vehicle') }} {{ $t('inputs.input-vehicle') }}
</option> </option>
<option v-for="loco in locoOptions" :value="loco" :key="loco.type"> <option v-for="loco in locoOptions" :value="loco" :key="loco.type">
{{ loco.type }}<b v-if="loco.restrictions['sponsorOnly']">*</b> {{ loco.type
}}<b v-if="loco.sponsorOnlyTimestamp && loco.sponsorOnlyTimestamp > Date.now()">*</b>
</option> </option>
</select> </select>
</div> </div>
@@ -59,7 +60,8 @@
</option> </option>
<option v-for="car in carOptions" :value="car" :key="car.type"> <option v-for="car in carOptions" :value="car" :key="car.type">
{{ car.type }}<b v-if="car.restrictions['sponsorOnly']">*</b> {{ car.type
}}<b v-if="car.sponsorOnlyTimestamp && car.sponsorOnlyTimestamp > Date.now()">*</b>
</option> </option>
</select> </select>
</div> </div>
@@ -84,6 +86,7 @@
<option :value="null" v-if="!store.chosenCar || !store.chosenCar.loadable"> <option :value="null" v-if="!store.chosenCar || !store.chosenCar.loadable">
{{ $t('inputs.no-cargo-available') }} {{ $t('inputs.no-cargo-available') }}
</option> </option>
<option :value="null" v-else>{{ $t('inputs.cargo-empty') }}</option> <option :value="null" v-else>{{ $t('inputs.cargo-empty') }}</option>
<option v-for="cargo in store.chosenCar?.cargoTypes" :value="cargo" :key="cargo.id"> <option v-for="cargo in store.chosenCar?.cargoTypes" :value="cargo" :key="cargo.id">
@@ -193,10 +196,7 @@ export default defineComponent({
removeVehicle() { removeVehicle() {
if (this.store.stockList.length == 0) return; if (this.store.stockList.length == 0) return;
const lastStock = this.store.stockList.slice(-1)[0]; this.store.stockList.splice(-1);
if (lastStock.count > 1) lastStock.count--;
else this.store.stockList.splice(-1);
}, },
switchVehicles() { switchVehicles() {
+30 -14
View File
@@ -4,8 +4,11 @@
<img <img
:src="getThumbnailURL(store.chosenVehicle.type, 'small')" :src="getThumbnailURL(store.chosenVehicle.type, 'small')"
:data-preview-active="store.chosenVehicle !== null" :data-preview-active="store.chosenVehicle !== null"
:data-sponsor-only="store.chosenVehicle?.restrictions.sponsorOnly" :data-sponsor-only="
:data-team-only="store.chosenVehicle?.restrictions.teamOnly" store.chosenVehicle.sponsorOnlyTimestamp &&
store.chosenVehicle.sponsorOnlyTimestamp > Date.now()
"
:data-team-only="store.chosenVehicle.teamOnly"
@click="onImageClick" @click="onImageClick"
@keydown.enter="onImageClick" @keydown.enter="onImageClick"
@error="onImageError" @error="onImageError"
@@ -41,17 +44,23 @@
}} }}
</div> </div>
<b v-if="store.chosenVehicle.restrictions.sponsorOnly > 0" class="sponsor-only">{{ <b
$t('preview.sponsor-only', [ v-if="
new Date(store.chosenVehicle.restrictions['sponsorOnly']).toLocaleDateString( store.chosenVehicle.sponsorOnlyTimestamp &&
$i18n.locale == 'pl' ? 'pl-PL' : 'en-GB' store.chosenVehicle.sponsorOnlyTimestamp > Date.now()
), "
]) class="sponsor-only"
}}</b> >
{{
$t('preview.sponsor-only', [
new Date(store.chosenVehicle.sponsorOnlyTimestamp).toLocaleDateString(
$i18n.locale == 'pl' ? 'pl-PL' : 'en-GB'
),
])
}}
</b>
<b v-if="store.chosenVehicle.restrictions['teamOnly']" class="team-only">{{ <b v-if="store.chosenVehicle.teamOnly" class="team-only">{{ $t('preview.team-only') }}</b>
$t('preview.team-only')
}}</b>
</div> </div>
</div> </div>
</div> </div>
@@ -120,8 +129,7 @@ export default defineComponent({
align-items: center; align-items: center;
text-align: center; text-align: center;
margin-top: 1em; min-height: 250px;
height: 250px;
& > div { & > div {
max-width: 100%; max-width: 100%;
@@ -152,6 +160,14 @@ img {
background-color: $bgColor; background-color: $bgColor;
} }
.sponsor-only {
color: $sponsorColor;
}
.team-only {
color: $teamColor;
}
.image-info { .image-info {
font-size: 1.1em; font-size: 1.1em;
padding: 0.5em; padding: 0.5em;
+8 -3
View File
@@ -119,6 +119,7 @@ import { useStore } from '../../store';
import stockMixin from '../../mixins/stockMixin'; import stockMixin from '../../mixins/stockMixin';
import { ICargo, ICarWagon, IStock } from '../../types'; import { ICargo, ICarWagon, IStock } from '../../types';
import { isTractionUnit } from '../../utils/vehicleUtils';
export default defineComponent({ export default defineComponent({
name: 'stock-generator', name: 'stock-generator',
@@ -186,8 +187,8 @@ export default defineComponent({
if (!this.isCarGroupingEnabled) return false; if (!this.isCarGroupingEnabled) return false;
stockList.sort((s1, s2) => { stockList.sort((s1, s2) => {
return (s1.constructionType + s1.cargo?.id).localeCompare( return (s1.vehicleRef.constructionType + s1.cargo?.id).localeCompare(
s2.constructionType + s2.cargo?.id s2.vehicleRef.constructionType + s2.cargo?.id
); );
}); });
}, },
@@ -238,7 +239,11 @@ export default defineComponent({
}; };
for (let i = 0; i < 10; i++) { for (let i = 0; i < 10; i++) {
this.store.stockList.splice(this.store.stockList[0]?.isLoco ? 1 : 0); this.store.stockList.splice(
this.store.stockList.length > 0 && isTractionUnit(this.store.stockList[0].vehicleRef)
? 1
: 0
);
let carCount = 0; let carCount = 0;
const maxWeight = const maxWeight =
+33 -32
View File
@@ -132,7 +132,7 @@
(!) (!)
{{ {{
$t('stocklist.warning-team-only-vehicle', [ $t('stocklist.warning-team-only-vehicle', [
teamOnlyVehicles.map((v) => v.type).join(', '), teamOnlyVehicles.map((v) => v.vehicleRef.type).join(', '),
]) ])
}} }}
</div> </div>
@@ -169,7 +169,7 @@
<li <li
v-for="(stock, i) in store.stockList" v-for="(stock, i) in store.stockList"
:key="stock.id" :key="stock.id"
:class="{ loco: stock.isLoco }" :class="{ loco: isTractionUnit(stock.vehicleRef) }"
tabindex="0" tabindex="0"
@click="onListItemClick(i)" @click="onListItemClick(i)"
@keydown.enter="onListItemClick(i)" @keydown.enter="onListItemClick(i)"
@@ -192,22 +192,29 @@
<span <span
class="stock-info-type" class="stock-info-type"
:data-sponsor-only="stock.restrictions.sponsorOnly" :data-sponsor-only="
:data-team-only="stock.restrictions.teamOnly" stock.vehicleRef.sponsorOnlyTimestamp &&
stock.vehicleRef.sponsorOnlyTimestamp > Date.now()
"
:data-team-only="stock.vehicleRef.teamOnly"
> >
{{ stock.isLoco ? stock.type : getCarSpecFromType(stock.type) }} {{
isTractionUnit(stock.vehicleRef)
? stock.vehicleRef.type
: getCarSpecFromType(stock.vehicleRef.type)
}}
</span> </span>
<span class="stock-info-cargo" v-if="stock.cargo"> <span class="stock-info-cargo" v-if="stock.cargo">
{{ stock.cargo.id }} {{ stock.cargo.id }}
</span> </span>
<span class="stock-info-length">{{ stock.length }}m</span> <span class="stock-info-length">{{ stock.vehicleRef.length }}m</span>
<span class="stock-info-mass"> <span class="stock-info-mass">
{{ ((stock.weight + (stock.cargo?.weight ?? 0)) / 1000).toFixed(1) }}t {{ ((stock.vehicleRef.weight + (stock.cargo?.weight ?? 0)) / 1000).toFixed(1) }}t
</span> </span>
<span class="stock-info-speed">{{ stock.maxSpeed }}km/h</span> <span class="stock-info-speed">{{ stock.vehicleRef.maxSpeed }}km/h</span>
</div> </div>
</li> </li>
</transition-group> </transition-group>
@@ -226,6 +233,7 @@ import stockPreviewMixin from '../../mixins/stockPreviewMixin';
import StockThumbnails from '../utils/StockThumbnails.vue'; import StockThumbnails from '../utils/StockThumbnails.vue';
import stockMixin from '../../mixins/stockMixin'; import stockMixin from '../../mixins/stockMixin';
import Checkbox from '../common/Checkbox.vue'; import Checkbox from '../common/Checkbox.vue';
import { isTractionUnit } from '../../utils/vehicleUtils';
export default defineComponent({ export default defineComponent({
name: 'stock-list', name: 'stock-list',
@@ -250,7 +258,7 @@ export default defineComponent({
computed: { computed: {
chosenRealComposition() { chosenRealComposition() {
const currentStockString = this.store.stockList.map((s) => s.type).join(';'); const currentStockString = this.store.stockList.map((s) => s.vehicleRef.type).join(';');
return this.store.realCompositionList.find((rc) => rc.stockString == currentStockString); return this.store.realCompositionList.find((rc) => rc.stockString == currentStockString);
}, },
@@ -265,7 +273,9 @@ export default defineComponent({
return this.store.stockList return this.store.stockList
.map((stock, i) => { .map((stock, i) => {
let stockTypeStr = let stockTypeStr =
stock.isLoco || !stock.cargo ? stock.type : `${stock.type}:${stock.cargo.id}`; isTractionUnit(stock.vehicleRef) || !stock.cargo
? stock.vehicleRef.type
: `${stock.vehicleRef.type}:${stock.cargo.id}`;
if (i == 0 && (includeColdStart || includeDoubleManned)) if (i == 0 && (includeColdStart || includeDoubleManned))
return `${stockTypeStr},${includeColdStart ? 'c' : ''}${includeDoubleManned ? 'd' : ''}`; return `${stockTypeStr},${includeColdStart ? 'c' : ''}${includeDoubleManned ? 'd' : ''}`;
@@ -300,22 +310,24 @@ export default defineComponent({
return ( return (
!this.store.isTrainPassenger && !this.store.isTrainPassenger &&
this.store.stockList.length > 1 && this.store.stockList.length > 1 &&
!this.store.stockList.every((stock) => stock.isLoco) && !this.store.stockList.every((stock) => isTractionUnit(stock.vehicleRef)) &&
this.store.stockList.some((stock) => stock.isLoco && stock.type.startsWith('EP')) this.store.stockList.some(
(stock) => isTractionUnit(stock.vehicleRef) && stock.vehicleRef.type.startsWith('EP')
)
); );
}, },
locoCountExceeded() { locoCountExceeded() {
return ( return (
this.store.stockList.reduce((acc, stock) => { this.store.stockList.reduce((acc, stock) => {
if (stock.isLoco) acc += stock.count; if (isTractionUnit(stock.vehicleRef)) acc += 1;
return acc; return acc;
}, 0) > 2 }, 0) > 2
); );
}, },
teamOnlyVehicles() { teamOnlyVehicles() {
return this.store.stockList.filter((stock) => stock.restrictions.teamOnly); return this.store.stockList.filter((stock) => stock.vehicleRef.teamOnly);
}, },
hasAnyWarnings() { hasAnyWarnings() {
@@ -330,6 +342,8 @@ export default defineComponent({
}, },
methods: { methods: {
isTractionUnit,
copyToClipboard() { copyToClipboard() {
navigator.clipboard.writeText(this.stockString); navigator.clipboard.writeText(this.stockString);
@@ -346,7 +360,8 @@ export default defineComponent({
const stock = this.store.stockList[stockID]; const stock = this.store.stockList[stockID];
this.store.chosenStockListIndex = this.store.chosenStockListIndex =
this.store.chosenStockListIndex == stockID && this.store.chosenVehicle?.type == stock.type this.store.chosenStockListIndex == stockID &&
this.store.chosenVehicle?.type == stock.vehicleRef.type
? -1 ? -1
: stockID; : stockID;
@@ -377,20 +392,6 @@ export default defineComponent({
this.store.chosenStockListIndex = -1; this.store.chosenStockListIndex = -1;
}, },
addStock(index: number) {
if (index == -1) return;
this.store.stockList[index].count++;
},
subStock(index: number) {
if (index == -1) return;
if (this.store.stockList[index].count < 2) return;
this.store.stockList[index].count--;
},
removeStock(index: number) { removeStock(index: number) {
if (index == -1) return; if (index == -1) return;
@@ -424,7 +425,7 @@ export default defineComponent({
shuffleCars() { shuffleCars() {
const availableIndexes = this.store.stockList.reduce((acc, stock, i) => { const availableIndexes = this.store.stockList.reduce((acc, stock, i) => {
if (!stock.isLoco) acc.push(i); if (!isTractionUnit(stock.vehicleRef)) acc.push(i);
return acc; return acc;
}, [] as number[]); }, [] as number[]);
@@ -446,7 +447,7 @@ export default defineComponent({
downloadStock() { downloadStock() {
if (this.store.stockList.length == 0) return alert(this.$t('stocklist.alert-empty')); if (this.store.stockList.length == 0) return alert(this.$t('stocklist.alert-empty'));
const defaultName = `${this.chosenRealComposition ? this.chosenRealComposition.stockId + ' ' : ''}${this.store.stockList[0].type} ${(this.store.totalWeight / 1000).toFixed(1)}t; ${ const defaultName = `${this.chosenRealComposition ? this.chosenRealComposition.stockId + ' ' : ''}${this.store.stockList[0].vehicleRef.type} ${(this.store.totalWeight / 1000).toFixed(1)}t; ${
this.store.totalLength this.store.totalLength
}m; vmax ${this.store.maxStockSpeed}`; }m; vmax ${this.store.maxStockSpeed}`;
@@ -645,7 +646,7 @@ li > .stock-info {
color: $teamColor; color: $teamColor;
} }
&[data-sponsor-only] { &[data-sponsor-only='true'] {
color: $sponsorColor; color: $sponsorColor;
} }
} }
+26 -11
View File
@@ -48,8 +48,6 @@
v-for="vehicle in computedVehicles" v-for="vehicle in computedVehicles"
:key="vehicle.type" :key="vehicle.type"
:data-preview="vehicle.type === store.chosenVehicle?.type" :data-preview="vehicle.type === store.chosenVehicle?.type"
:data-sponsor-only="vehicle.restrictions.sponsorOnly > 0"
:data-team-only="vehicle.restrictions.teamOnly"
@click="previewVehicle(vehicle)" @click="previewVehicle(vehicle)"
@dblclick="addVehicle(vehicle)" @dblclick="addVehicle(vehicle)"
@keydown.enter="previewVehicle(vehicle)" @keydown.enter="previewVehicle(vehicle)"
@@ -58,7 +56,16 @@
<img loading="lazy" width="120" :src="getThumbnailURL(vehicle.type, 'small')" /> <img loading="lazy" width="120" :src="getThumbnailURL(vehicle.type, 'small')" />
<span> <span>
<b class="vehicle-name"> {{ vehicle.type.replace(/_/g, ' ') }} </b> <span
class="vehicle-name"
:class="{
'sponsor-only':
vehicle.sponsorOnlyTimestamp && vehicle.sponsorOnlyTimestamp > Date.now(),
'team-only': vehicle.teamOnly,
}"
>
<b>{{ vehicle.type.replace(/_/g, ' ') }}</b>
</span>
<div class="vehicle-group"> <div class="vehicle-group">
{{ $t(`wiki.${vehicle.group}`) }} | {{ $t(`wiki.${vehicle.group}`) }} |
@@ -238,14 +245,6 @@ export default defineComponent({
background-color: #435288; background-color: #435288;
} }
&[data-sponsor-only='true'] {
box-shadow: 0 0 5px 0 $sponsorColor;
}
&[data-team-only='true'] {
box-shadow: 0 0 5px 0 $teamColor;
}
& > span { & > span {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -260,6 +259,22 @@ export default defineComponent({
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.sponsor-only {
color: $sponsorColor;
&::after {
content: '*';
}
}
.team-only {
color: $teamColor;
&::after {
content: '*';
}
}
.vehicle-props { .vehicle-props {
color: #ccc; color: #ccc;
} }
+17 -8
View File
@@ -5,7 +5,10 @@
v-for="(stock, stockIndex) in store.stockList" v-for="(stock, stockIndex) in store.stockList"
:key="stockIndex" :key="stockIndex"
:data-selected="store.chosenStockListIndex == stockIndex" :data-selected="store.chosenStockListIndex == stockIndex"
:data-sponsor="stock.restrictions.sponsorOnly" :data-sponsor-only="
stock.vehicleRef.sponsorOnlyTimestamp && stock.vehicleRef.sponsorOnlyTimestamp > Date.now()
"
:data-team-only="stock.vehicleRef.teamOnly"
draggable="true" draggable="true"
@dragstart="onDragStart(stockIndex)" @dragstart="onDragStart(stockIndex)"
@drop="onDrop($event, stockIndex)" @drop="onDrop($event, stockIndex)"
@@ -13,14 +16,14 @@
@click="onListItemClick(stockIndex)" @click="onListItemClick(stockIndex)"
> >
<b> <b>
{{ stock.type }} {{ stock.vehicleRef.type }}
</b> </b>
<img <img
draggable="false" draggable="false"
:src="`https://rj.td2.info.pl/dist/img/thumbnails/${stock.type}.png`" :src="`https://rj.td2.info.pl/dist/img/thumbnails/${stock.vehicleRef.type}.png`"
:alt="stock.type" :alt="stock.vehicleRef.type"
:title="stock.type" :title="stock.vehicleRef.type"
@error="stockImageError($event, stock)" @error="stockImageError($event, stock)"
/> />
</div> </div>
@@ -43,7 +46,7 @@ const onListItemClick = (index: number) => {
}; };
const stockImageError = (e: Event, stock: IStock) => { const stockImageError = (e: Event, stock: IStock) => {
(e.target as HTMLImageElement).src = `images/${stock.group}-unknown.png`; (e.target as HTMLImageElement).src = `images/${stock.vehicleRef.group}-unknown.png`;
}; };
watch( watch(
@@ -88,6 +91,8 @@ const allowDrop = (e: DragEvent) => {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import '../../styles/global.scss';
.stock-thumbnails { .stock-thumbnails {
display: flex; display: flex;
overflow: auto; overflow: auto;
@@ -121,8 +126,12 @@ const allowDrop = (e: DragEvent) => {
margin: 0 1em; margin: 0 1em;
} }
&[data-sponsor='true'] > b { &[data-sponsor-only='true'] > b {
color: salmon; color: $sponsorColor;
}
&[data-team-only='true'] > b {
color: $teamColor;
} }
img { img {
+12 -17
View File
@@ -15,21 +15,11 @@ export default defineComponent({
return `${Math.random().toString(36).slice(5)}`; return `${Math.random().toString(36).slice(5)}`;
}, },
getStockObject(vehicle: IVehicle, cargo?: ICargo | null, count = 1): IStock { getStockObject(vehicle: IVehicle, cargo?: ICargo | null): IStock {
const isLoco = isTractionUnit(vehicle);
return { return {
id: this.getStockId(), id: this.getStockId(),
type: vehicle.type, vehicleRef: vehicle,
length: vehicle.length, cargo: !isTractionUnit(vehicle) && vehicle.loadable && cargo ? cargo : undefined,
weight: vehicle.weight,
maxSpeed: vehicle.maxSpeed,
isLoco,
cargo: !isLoco && vehicle.loadable && cargo ? cargo : undefined,
count,
group: isLoco ? vehicle.group : vehicle.group,
constructionType: vehicle.constructionType,
restrictions: vehicle.restrictions,
}; };
}, },
@@ -38,14 +28,19 @@ export default defineComponent({
const stock = this.getStockObject(vehicle, cargo); const stock = this.getStockObject(vehicle, cargo);
if (stock.isLoco && !this.store.stockList[0]?.isLoco) this.store.stockList.unshift(stock); if (
isTractionUnit(stock.vehicleRef) &&
this.store.stockList.length > 0 &&
!isTractionUnit(this.store.stockList[0].vehicleRef)
)
this.store.stockList.unshift(stock);
else this.store.stockList.push(stock); else this.store.stockList.push(stock);
}, },
addLocomotive(loco: ILocomotive) { addLocomotive(loco: ILocomotive) {
const stockObj = this.getStockObject(loco); const stockObj = this.getStockObject(loco);
if (this.store.stockList.length > 0 && !this.store.stockList[0].isLoco) if (this.store.stockList.length > 0 && !isTractionUnit(this.store.stockList[0].vehicleRef))
this.store.stockList.unshift(stockObj); this.store.stockList.unshift(stockObj);
else this.store.stockList.push(stockObj); else this.store.stockList.push(stockObj);
}, },
@@ -72,9 +67,9 @@ export default defineComponent({
let vehicle: IVehicle | null = null; let vehicle: IVehicle | null = null;
let vehicleCargo: ICargo | null = null; let vehicleCargo: ICargo | null = null;
const isLoco = /^(EU|EP|ET|SM|EN|2EN|SN)/.test(type); const isTractionUnit = /^(EU|EP|ET|SM|EN|2EN|SN)/.test(type);
if (isLoco) { if (isTractionUnit) {
const [locoType, spawnProps] = type.split(','); const [locoType, spawnProps] = type.split(',');
vehicle = this.store.locoDataList.find((loco) => loco.type == locoType) || null; vehicle = this.store.locoDataList.find((loco) => loco.type == locoType) || null;
+10 -11
View File
@@ -14,19 +14,18 @@ export default defineComponent({
methods: { methods: {
previewStock(stock: IStock) { previewStock(stock: IStock) {
if (stock.isLoco) { const vehicleRef = stock.vehicleRef;
const chosenLoco = this.store.locoDataList.find((v) => v.type == stock.type) || null;
this.store.chosenVehicle = chosenLoco;
this.store.chosenLoco = chosenLoco;
this.store.chosenCargo = null;
this.store.chosenLocoGroup = stock.group as LocoGroupType;
} else {
const chosenCar = this.store.carDataList.find((v) => v.type == stock.type) || null;
this.store.chosenVehicle = chosenCar;
this.store.chosenCar = chosenCar;
this.store.chosenVehicle = vehicleRef;
if (isTractionUnit(vehicleRef)) {
this.store.chosenLoco = vehicleRef;
this.store.chosenCargo = null;
this.store.chosenLocoGroup = vehicleRef.group as LocoGroupType;
} else {
this.store.chosenCar = vehicleRef;
this.store.chosenCargo = stock.cargo || null; this.store.chosenCargo = stock.cargo || null;
this.store.chosenCarGroup = stock.group as WagonGroupType; this.store.chosenCarGroup = vehicleRef.group as WagonGroupType;
} }
}, },
+9 -6
View File
@@ -13,6 +13,7 @@ import { defineStore } from 'pinia';
import { import {
acceptableWeight, acceptableWeight,
carDataList, carDataList,
isTractionUnit,
isTrainPassenger, isTrainPassenger,
locoDataList, locoDataList,
maxStockSpeed, maxStockSpeed,
@@ -96,25 +97,27 @@ export const useStore = defineStore({
stockSupportsColdStart: (state) => { stockSupportsColdStart: (state) => {
if (state.stockList.length == 0) return false; if (state.stockList.length == 0) return false;
if (!state.stockList[0].isLoco) return false; if (!isTractionUnit(state.stockList[0].vehicleRef)) return false;
const headingLoco = state.stockList[0]; const headingLoco = state.stockList[0];
return ( return (
state.vehiclesData?.vehicleProps.find((stock) => stock.type == headingLoco.constructionType) state.vehiclesData?.vehicleProps.find(
?.coldStart ?? false (stock) => stock.type == headingLoco.vehicleRef.constructionType
)?.coldStart ?? false
); );
}, },
stockSupportsDoubleManning: (state) => { stockSupportsDoubleManning: (state) => {
if (state.stockList.length == 0) return false; if (state.stockList.length == 0) return false;
if (!state.stockList[0].isLoco) return false; if (!isTractionUnit(state.stockList[0].vehicleRef)) return false;
const headingLoco = state.stockList[0]; const headingLoco = state.stockList[0];
return ( return (
state.vehiclesData?.vehicleProps.find((stock) => stock.type == headingLoco.constructionType) state.vehiclesData?.vehicleProps.find(
?.doubleManned ?? false (stock) => stock.type == headingLoco.vehicleRef.constructionType
)?.doubleManned ?? false
); );
}, },
}, },
+1 -1
View File
@@ -6,7 +6,7 @@ $textColor: #fff;
$secondaryColor: #1b1b1b; $secondaryColor: #1b1b1b;
$accentColor: #e4c428; $accentColor: #e4c428;
$sponsorColor: salmon; $sponsorColor: gold;
$teamColor: #ff4848; $teamColor: #ff4848;
@font-face { @font-face {
+5 -11
View File
@@ -54,11 +54,12 @@ export interface ILocomotive {
constructionType: string; constructionType: string;
cabinType: string; cabinType: string;
maxSpeed: number; maxSpeed: number;
restrictions: Record<RestrictionType, any>;
weight: number; weight: number;
length: number; length: number;
coldStart: boolean; coldStart: boolean;
doubleManned: boolean; doubleManned: boolean;
sponsorOnlyTimestamp: number;
teamOnly: boolean;
} }
export interface ICarWagon { export interface ICarWagon {
@@ -66,25 +67,18 @@ export interface ICarWagon {
group: WagonGroupType; group: WagonGroupType;
constructionType: string; constructionType: string;
loadable: boolean; loadable: boolean;
restrictions: Record<RestrictionType, any>;
maxSpeed: number; maxSpeed: number;
weight: number; weight: number;
length: number; length: number;
cargoTypes: ICargo[]; cargoTypes: ICargo[];
sponsorOnlyTimestamp: number;
teamOnly: boolean;
} }
export interface IStock { export interface IStock {
id: string; id: string;
type: string; vehicleRef: IVehicle;
group: LocoGroupType | WagonGroupType;
constructionType: string;
length: number;
weight: number;
maxSpeed: number;
cargo?: ICargo; cargo?: ICargo;
isLoco: boolean;
restrictions: Record<RestrictionType, any>;
count: number;
} }
export interface IRealComposition { export interface IRealComposition {
+15 -12
View File
@@ -39,7 +39,8 @@ export function locoDataList(vehiclesData: IVehiclesData | undefined) {
constructionType, constructionType,
cabinType, cabinType,
restrictions: restrictions ?? {}, sponsorOnlyTimestamp: restrictions?.sponsorOnly ?? 0,
teamOnly: restrictions?.teamOnly ?? false,
maxSpeed: locoProps.speed, maxSpeed: locoProps.speed,
length: locoProps.length, length: locoProps.length,
@@ -75,7 +76,8 @@ export function carDataList(vehiclesData: IVehiclesData | undefined) {
loadable: wagonProps.cargoTypes ? wagonProps.cargoTypes.length > 0 : false, loadable: wagonProps.cargoTypes ? wagonProps.cargoTypes.length > 0 : false,
cargoTypes: wagonProps?.cargoTypes ?? [], cargoTypes: wagonProps?.cargoTypes ?? [],
restrictions: restrictions ?? {}, sponsorOnlyTimestamp: restrictions?.sponsorOnly ?? 0,
teamOnly: restrictions?.teamOnly ?? false,
maxSpeed: wagonProps.speed, maxSpeed: wagonProps.speed,
weight: wagonProps?.weight || 0, weight: wagonProps?.weight || 0,
@@ -88,25 +90,26 @@ export function carDataList(vehiclesData: IVehiclesData | undefined) {
export function totalWeight(stockList: IStock[]) { export function totalWeight(stockList: IStock[]) {
return stockList.reduce( return stockList.reduce(
(acc, stock) => acc + (stock.weight + (stock.cargo?.weight ?? 0)) * stock.count, (acc, stock) => acc + (stock.vehicleRef.weight + (stock.cargo?.weight ?? 0)),
0 0
); );
} }
export function totalLength(stockList: IStock[]) { export function totalLength(stockList: IStock[]) {
return stockList.reduce((acc, stock) => acc + stock.length * stock.count, 0); return stockList.reduce((acc, stock) => acc + stock.vehicleRef.length, 0);
} }
export function maxStockSpeed(stockList: IStock[]) { export function maxStockSpeed(stockList: IStock[]) {
const stockSpeedLimit = stockList.reduce( const stockSpeedLimit = stockList.reduce(
(acc, stock) => (stock.maxSpeed < acc || acc == 0 ? stock.maxSpeed : acc), (acc, stock) => (stock.vehicleRef.maxSpeed < acc || acc == 0 ? stock.vehicleRef.maxSpeed : acc),
0 0
); );
const headingLoco = stockList[0]?.isLoco ? stockList[0] : undefined; const headingLoco =
stockList[0] && isTractionUnit(stockList[0].vehicleRef) ? stockList[0] : undefined;
if (!headingLoco) return stockSpeedLimit; if (!headingLoco) return stockSpeedLimit;
const locoType = headingLoco.type.split('-')[0]; const locoType = headingLoco.vehicleRef.type.split('-')[0];
if (/^(EN|2EN|SN)/.test(locoType)) return stockSpeedLimit; if (/^(EN|2EN|SN)/.test(locoType)) return stockSpeedLimit;
@@ -121,9 +124,9 @@ export function maxStockSpeed(stockList: IStock[]) {
} }
export function acceptableWeight(stockList: IStock[]) { export function acceptableWeight(stockList: IStock[]) {
if (stockList.length == 0 || !stockList[0].isLoco) return 0; if (stockList.length == 0 || !isTractionUnit(stockList[0].vehicleRef)) return 0;
const activeLocomotiveType = stockList[0].type.split('-')[0]; const activeLocomotiveType = stockList[0].vehicleRef.type.split('-')[0];
const locoMassLimit = calculateMassLimit( const locoMassLimit = calculateMassLimit(
activeLocomotiveType as MassLimitLocoType, activeLocomotiveType as MassLimitLocoType,
@@ -135,9 +138,9 @@ export function acceptableWeight(stockList: IStock[]) {
export function isTrainPassenger(stockList: IStock[]) { export function isTrainPassenger(stockList: IStock[]) {
if (stockList.length == 0) return false; if (stockList.length == 0) return false;
if (stockList.every((stock) => stock.isLoco)) return false; if (stockList.every((stock) => isTractionUnit(stock.vehicleRef))) return false;
return stockList return stockList
.filter((stock) => !stock.isLoco) .filter((stock) => !isTractionUnit(stock.vehicleRef))
.every((stock) => stock.group === 'wagon-passenger'); .every((stock) => stock.vehicleRef.group === 'wagon-passenger');
} }