Aktualizacja 1.0.5

This commit is contained in:
2021-11-17 14:16:23 +01:00
parent 60d8da9598
commit 0459bbb90c
9 changed files with 592 additions and 128 deletions
+1
View File
@@ -55,6 +55,7 @@ export default defineComponent({
if (this.store.vehiclePreviewSrc == '') return;
if (ev.key.toLowerCase() == 'escape') this.store.vehiclePreviewSrc = '';
// if(ev.key.toLowerCase() == 'enter')
});
// window.focus();
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.7 KiB

+10 -81
View File
@@ -125,91 +125,20 @@ export default defineComponent({
},
mounted() {
document.addEventListener('wheel', (ev) => {
if (!ev.target) return;
const selectAttr = (ev.target as Element).attributes.getNamedItem('data-select');
if (!selectAttr) return;
if (selectAttr.value == 'loco') {
const chosenLoco = this.store.chosenLoco;
if (!chosenLoco) {
this.store.chosenLoco = this.locoOptions[0];
this.onLocoTypeChange();
return;
}
if (ev.deltaY > 0) {
const nextOptionIndex = this.locoOptions.findIndex((opt) => opt.type == chosenLoco.type) + 1;
if (nextOptionIndex >= this.locoOptions.length) return;
this.store.chosenLoco = this.locoOptions[nextOptionIndex];
this.onLocoTypeChange();
} else {
const prevOptionIndex = this.locoOptions.findIndex((opt) => opt.type == chosenLoco.type) - 1;
if (prevOptionIndex < 0) return;
this.store.chosenLoco = this.locoOptions[prevOptionIndex];
this.onLocoTypeChange();
}
document.addEventListener('keydown', (ev) => {
const keyName = ev.key.toLowerCase();
if (keyName == 'enter') {
ev.preventDefault();
this.addVehicle();
}
if (selectAttr.value == 'car') {
const chosenCar = this.store.chosenCar;
if (keyName == 'backspace') {
if (this.store.stockList.length == 0) return;
if (!chosenCar) {
this.store.chosenCar = this.carOptions[0];
this.onCarTypeChange();
const lastStock = this.store.stockList.slice(-1)[0];
return;
}
if (ev.deltaY > 0) {
const nextOptionIndex = this.carOptions.findIndex((opt) => opt.type == chosenCar.type) + 1;
if (nextOptionIndex >= this.carOptions.length) return;
this.store.chosenCar = this.carOptions[nextOptionIndex];
this.onCarTypeChange();
} else {
const prevOptionIndex = this.carOptions.findIndex((opt) => opt.type == chosenCar.type) - 1;
if (prevOptionIndex < 0) return;
this.store.chosenCar = this.carOptions[prevOptionIndex];
this.onCarTypeChange();
}
}
if (selectAttr.value == 'cargo') {
if (!this.store.chosenCar) return;
if (!this.store.chosenCar.cargoList || this.store.chosenCar.cargoList.length == 0) return;
const chosenCargoList = this.store.chosenCar.cargoList;
if (!this.store.chosenCargo) {
this.store.chosenCargo = chosenCargoList[0];
return;
}
if (ev.deltaY > 0) {
const nextOptionIndex = chosenCargoList.findIndex((cargo) => cargo.id == this.store.chosenCargo?.id) + 1;
if (nextOptionIndex >= chosenCargoList.length) return;
this.store.chosenCargo = chosenCargoList[nextOptionIndex];
} else {
const prevOptionIndex = chosenCargoList.findIndex((cargo) => cargo.id == this.store.chosenCargo?.id) - 1;
if (prevOptionIndex < 0) return;
this.store.chosenCargo = chosenCargoList[prevOptionIndex];
}
if (lastStock.count > 1) lastStock.count--;
else this.store.stockList.splice(-1);
}
});
+182 -32
View File
@@ -1,5 +1,11 @@
<template>
<div class="bottom">
<div class="bg-dimmer" v-if="isRandomizerCardOpen"></div>
<transition name="card-anim">
<randomizer-card v-if="isRandomizerCardOpen" />
</transition>
<section class="image">
<div class="image__wrapper">
<div
@@ -17,13 +23,15 @@
@load="onImageLoad"
@click="onImageClick"
/>
<!-- <img
v-if="store.chosenCar"
:src="store.chosenCar.imageSrc"
:alt="store.chosenCar.type"
@load="onImageLoad"
@click="onImageClick"
/> -->
</div>
</div>
<div class="brief-info" v-if="store.chosenLoco || store.chosenCar">
<b class="text--accent">{{ (store.chosenLoco || store.chosenCar)?.type }}</b>
<div>{{ vehicleTypes[store.chosenLoco?.power || store.chosenCar?.useType || 'loco-e'] }}</div>
<div>
{{ (store.chosenCar || store.chosenLoco)?.length }}m | {{ (store.chosenCar || store.chosenLoco)?.mass }}t |
{{ (store.chosenCar || store.chosenLoco)?.maxSpeed }} km/h
</div>
</div>
</section>
@@ -34,11 +42,14 @@
<div class="stock-list_buttons">
<button class="btn" @click="downloadStock">POBIERZ POCIĄG</button>
<button class="btn" @click="resetStock">ZRESETUJ LISTĘ</button>
<span></span>
<button class="btn" @click="shuffleCars">TASUJ WAGONY</button>
<button class="btn" @click="openRandomizerCard">LOSUJ SKŁAD</button>
</div>
<div class="stock-list_specs">
Masa: <span class="text--accent">{{ totalMass }}</span> t | Długość:
<span class="text--accent">{{ totalLength }}</span>
m
Masa: <span class="text--accent">{{ totalMass }}t</span> | Długość:
<span class="text--accent">{{ totalLength }}m</span>
| Vmax pociągu: <span class="text--accent">{{ maxStockSpeed }} km/h</span>
</div>
<div class="warnings">
@@ -49,6 +60,8 @@
<div class="warning" v-if="warnings.trainTooLong.value">Ten skład jest za długi!</div>
<div class="warning" v-if="warnings.trainTooHeavy.value">Ten skład jest za ciężki!</div>
<div class="warning" v-if="warnings.tooManyLocos.value">Ten skład posiada za dużo pojazdów trakcyjnych!</div>
</div>
<ul>
@@ -72,15 +85,13 @@
@dragover="allowDrop"
draggable="true"
>
<span v-if="stock.supportersOnly" style="color: salmon"> *S* </span>
<span>
<span class="stock__type" :class="{ supporter: stock.supportersOnly }">
{{ stock.isLoco ? stock.type : getCarSpecFromType(stock.type) }}
</span>
<span v-if="stock.cargo"> &nbsp; ({{ stock.cargo?.id }}) </span>
&nbsp;
<span> {{ stock.length }}m</span>
&nbsp;
<span>{{ stock.cargo ? stock.cargo.totalMass : stock.mass }}t</span>
<span class="stock__cargo" v-if="stock.cargo"> {{ stock.cargo.id }} </span>
<span class="stock__length"> {{ stock.length }}m </span>
<span class="stock__mass">{{ stock.cargo ? stock.cargo.totalMass : stock.mass }}t </span>
<span class="stock__speed"> {{ stock.maxSpeed }}km/h </span>
</div>
<div class="item-actions">
@@ -110,13 +121,24 @@
</template>
<script lang="ts">
import { computed, ComputedRef, defineComponent, inject } from 'vue';
import { computed, ComputedRef, defineComponent, inject, provide, reactive, ref } from 'vue';
import { ICarWagon, ILocomotive, IStore } from '@/types';
import RandomizerCard from './RandomizerCard.vue';
export default defineComponent({
components: { RandomizerCard },
setup() {
const store = inject('Store') as IStore;
const isRandomizerCardOpen = ref(false);
provide('isCardOpen', isRandomizerCardOpen);
provide('chosenLength', ref(350));
provide('chosenMass', ref(1000));
provide('chosenLocoType', ref('loco-e'));
provide('chosenCarTypes', reactive([]));
provide('includeSupporterVehicles', ref(false));
return {
store,
locoDataList: inject('locoDataList') as ILocomotive[],
@@ -131,8 +153,11 @@ export default defineComponent({
locoNotSuitable: ComputedRef<boolean>;
trainTooLong: ComputedRef<boolean>;
trainTooHeavy: ComputedRef<boolean>;
tooManyLocos: ComputedRef<boolean>;
},
isRandomizerCardOpen,
hasSupporterOnlyVehicle: computed(() => store.stockList.some((stock) => stock.supportersOnly)),
};
},
@@ -146,13 +171,26 @@ export default defineComponent({
higher: require('@/assets/higher-icon.svg'),
},
imageOffsetY: 0,
draggedVehicleID: -1,
vehicleTypes: {
'loco-e': 'ELEKTROWÓZ',
'loco-s': 'SPALINOWÓZ',
'loco-ezt': 'ELEKTRYCZNY ZESP. TRAKCYJNY',
'loco-szt': 'SPALINOWY ZESP. TRAKCYJNY',
'car-passenger': 'WAGON PASAŻERSKI',
'car-cargo': 'WAGON TOWAROWY',
} as { [key: string]: string },
}),
methods: {
onListItemFocus(vehicleID: number) {
const vehicle = this.store.stockList[vehicleID];
if ((this.store.chosenCar || this.store.chosenLoco)?.imageSrc != vehicle.imgSrc) this.store.imageLoading = true;
if (this.store.showSupporter && !vehicle.supportersOnly) {
this.store.showSupporter = false;
}
@@ -165,7 +203,6 @@ export default defineComponent({
this.store.chosenCar = null;
this.store.chosenCargo = null;
// this.store.onLocoPowerChange(vehicle.useType);
return;
}
@@ -174,8 +211,6 @@ export default defineComponent({
this.store.chosenLoco = null;
this.store.chosenCar = this.carDataList.find((v) => v.type == vehicle.type) || null;
this.store.chosenCargo = vehicle.cargo || null;
// this.chose = vehicle.useType;
},
getCarSpecFromType(typeStr: string) {
@@ -226,12 +261,32 @@ export default defineComponent({
this.store.stockList[index + 1] = tempStock;
},
shuffleCars() {
const availableIndexes = this.store.stockList.reduce((acc, stock, i) => {
if (!stock.isLoco) acc.push(i);
return acc;
}, [] as number[]);
for (let i = 0; i < this.store.stockList.length; i++) {
if (!availableIndexes.includes(i)) continue;
availableIndexes.splice(i, -1);
const randAvailableIndex = availableIndexes[Math.floor(Math.random() * availableIndexes.length)];
const tempSwap = this.store.stockList[randAvailableIndex];
this.store.stockList[randAvailableIndex] = this.store.stockList[i];
this.store.stockList[i] = tempSwap;
}
},
openRandomizerCard() {
this.isRandomizerCardOpen = true;
},
downloadStock() {
if (
this.warnings.locoNotSuitable.value ||
this.warnings.trainTooLong.value ||
this.warnings.trainTooHeavy.value
) {
if (Object.values(this.warnings).some((v) => v.value == true)) {
``;
const allowDownload = confirm(
'Jazda tym pociągiem może być niezgodna z regulaminem symulatora! Czy na pewno chcesz kontynuować?'
@@ -310,6 +365,17 @@ export default defineComponent({
<style lang="scss" scoped>
@import '../styles/global';
.bg-dimmer {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(black, 0.85);
z-index: 100;
}
.bottom {
display: flex;
justify-content: space-between;
@@ -348,6 +414,9 @@ export default defineComponent({
flex-grow: 2;
padding: 0 1em 0 0;
display: flex;
flex-direction: column;
&__wrapper {
max-width: 380px;
width: 22em;
@@ -367,6 +436,8 @@ export default defineComponent({
img {
width: 100%;
height: 100%;
cursor: pointer;
}
.empty-message,
@@ -390,17 +461,42 @@ export default defineComponent({
}
}
.brief-info {
text-align: center;
margin: 1em 0;
font-size: 1.1em;
b {
font-size: 1.2em;
}
div {
margin: 0.25em 0;
}
}
.stock-list {
flex-grow: 3;
width: 100%;
&_buttons {
margin-bottom: 0.5em;
display: flex;
span {
flex-grow: 2;
}
button {
font-size: 0.9em;
padding: 0.4em 0.55em;
margin-right: 0.5em;
margin: 0 0.5em 1em 0;
&:nth-child(5) {
margin-right: 0;
}
&:focus {
color: $accentColor;
@@ -411,6 +507,9 @@ export default defineComponent({
ul {
margin-top: 1em;
max-height: 500px;
overflow: auto;
}
ul li {
@@ -426,19 +525,35 @@ export default defineComponent({
color: $accentColor;
}
&:hover .item-content {
color: $accentColor;
}
display: flex;
align-items: center;
justify-content: space-between;
.item-content {
/* background: whitesmoke; */
display: flex;
flex-wrap: wrap;
color: white;
font-weight: 700;
margin: 1em 0;
margin: 0.5em 0;
margin-right: 0.5em;
transition: color 100ms;
/* max-width: 200px; */
span {
padding: 0.5em;
margin-right: 0.25em;
margin-top: 0.25em;
}
@media screen and (max-width: 800px) {
span {
padding: 0.25em;
}
}
}
.item-actions {
@@ -472,4 +587,39 @@ export default defineComponent({
}
}
}
.stock {
&__type {
background-color: #222;
&.supporter {
background-color: #ff887b;
}
}
&__cargo {
background-color: #333;
}
&__length,
&__mass,
&__speed {
background-color: #555;
}
}
.card-anim {
&-enter {
opacity: 0;
}
&-enter-active,
&-leave-active {
transition: opacity 300ms;
}
&-leave-to {
opacity: 0;
}
}
</style>
+355
View File
@@ -0,0 +1,355 @@
<template>
<div class="card">
<!-- <button class="btn" @click="closeCard">X</button> -->
<div class="wrapper">
<h1>LOSUJ SKŁAD TOWAROWY <img :src="icons.randomize" alt="losuj skład" /></h1>
<h3>
Skład zostanie dołączony do dodanej na liście lokomotywy czołowej bądź wygenerowany z losową w przypadku jej
braku
</h3>
<div class="car-choice">
<p>Dobierz rodzaje wagonów</p>
<div>
<button
class="btn choice-btn"
v-for="car in carList"
:key="car.id"
@click="toggleCarType(car.id)"
:class="{ chosen: chosenCarTypes.includes(car.id) }"
>
{{ car.title }}
</button>
</div>
</div>
<div class="length-choice">
<p>Wybierz preferowaną długość składu (m) i (opcjonalnie) max. masę (t)</p>
<input
type="number"
v-model="chosenLength"
name="length"
max="650"
min="20"
step="10"
title="Długość składu (m)"
/>
<input
type="number"
v-model="chosenMass"
name="length"
max="2500"
min="100"
step="100"
title="Masa składu (t)"
/>
</div>
<div style="margin-top: 1em">
<button
class="btn choice-btn"
:class="{ chosen: includeSupporterVehicles }"
@click="
() => {
includeSupporterVehicles = !includeSupporterVehicles;
}
"
>
DOŁĄCZ POJAZDY DLA SUPPORTERÓW
</button>
</div>
<button class="btn" style="font-size: 1.15em; margin-top: 2em" @click="randomize">LOSUJ SKŁAD!</button>
<button class="btn" style="font-size: 1.15em; margin-top: 2em" @click="closeCard">ZAMKNIJ</button>
</div>
</div>
</template>
<script lang="ts">
import { ICargo, ICarWagon, ILocomotive, IStore } from '@/types';
import { defineComponent, inject } from 'vue';
export default defineComponent({
setup() {
const isCardOpen = inject('isCardOpen') as boolean;
const store = inject('Store') as IStore;
return {
isCardOpen,
store,
locoDataList: inject('locoDataList') as ILocomotive[],
carDataList: inject('carDataList') as ICarWagon[],
chosenLength: inject('chosenLength') as number,
chosenMass: inject('chosenMass') as number,
chosenLocoType: inject('chosenLocoType') as string,
chosenCarTypes: inject('chosenCarTypes') as string[],
includeSupporterVehicles: inject('includeSupporterVehicles') as boolean,
};
},
data: () => ({
icons: {
randomize: require('@/assets/randomize-icon.svg'),
},
carList: [
{
id: 'cisterns',
title: 'CYSTERNY',
types: ['29R'],
},
{
id: 'coal-cars',
title: 'WĘGLARKI',
types: ['412W', '429W'],
},
{
id: 'conteners',
title: 'KONTENEROWCE',
types: ['412Z', '424Z', '627Z'],
},
{
id: 'special-cars',
title: 'SPECJALNE',
types: ['441V', '426S', '304Ca', '209c'],
},
{
id: 'tanks',
title: 'ZBIORNIKOWE',
types: ['408S'],
},
{
id: 'covered-cars',
title: 'KRYTE',
types: ['203V'],
},
],
}),
methods: {
closeCard() {
this.isCardOpen = false;
},
randomize() {
if (this.chosenCarTypes.length == 0) {
alert('Wybierz przynajmniej jeden rodzaj wagonów!');
return;
}
if (this.chosenLength <= 20) {
alert('Długość składu musi być większa niż 20m!');
return;
}
if (this.chosenMass <= 100) {
alert('Masa składu musi być większa niż 100t!');
return;
}
if (this.chosenMass > 2500) {
alert('Masa składu nie powinna przekraczać 2500t!');
return;
}
if (this.chosenLength > 650) {
alert('Długość składu nie może przekraczać 650m dla pociągów towarowych!');
return;
}
let totalStockLength = 0;
let totalStockMass = 0;
if (this.store.stockList.length == 0 || !this.store.stockList[0].isLoco) {
this.store.stockList.length = 0;
const locoSet = this.locoDataList
.filter((loco) => !loco.type.startsWith('EP') && (loco.power == 'loco-e' || loco.power == 'loco-s'))
.filter((loco) => (!this.includeSupporterVehicles && loco.supportersOnly ? false : true));
const randLoco = locoSet[Math.floor(Math.random() * locoSet.length)];
this.addLoco(randLoco);
} else this.store.stockList.length = 1;
totalStockLength += this.store.stockList[0].length;
totalStockMass += this.store.stockList[0].mass;
let availableCarsSet = this.carDataList.filter((car) => {
if (!this.includeSupporterVehicles && car.supportersOnly) return false;
if (this.carList.find((c) => c.types.includes(car.constructionType) && this.chosenCarTypes.includes(c.id)))
return true;
return false;
});
while (totalStockLength < this.chosenLength && totalStockMass < this.chosenMass) {
const randCarIndex = Math.floor(Math.random() * availableCarsSet.length);
const randCar = availableCarsSet[randCarIndex];
// const count = Math.random() < 0.25 ? Math.floor(Math.random() * 2) + 1 : 1;
const count = 1;
if (randCar.length * count + totalStockLength >= this.chosenLength) break;
let randCargo = undefined;
let randNum = Math.random();
if (randCar.cargoList.length != 0 && randNum >= 0.6)
randCargo = randCar.cargoList[Math.floor(Math.random() * randCar.cargoList.length)];
if ((randCargo?.totalMass || randCar.mass) * count + totalStockMass >= this.chosenMass) break;
for (let i = 0; i < count; i++) this.addCar(randCar, randCargo);
totalStockLength += randCar.length * count;
totalStockMass += randCargo?.totalMass || randCar.mass;
}
this.isCardOpen = false;
},
toggleCarType(id: string) {
if (this.chosenCarTypes.includes(id)) this.chosenCarTypes.splice(this.chosenCarTypes.indexOf(id), 1);
else this.chosenCarTypes.push(id);
},
addLoco(loco: ILocomotive) {
const previousStock =
this.store.stockList.length > 0 ? this.store.stockList[this.store.stockList.length - 1] : null;
if (previousStock && previousStock.type == loco.type) {
this.store.stockList[this.store.stockList.length - 1].count++;
return;
}
const stockObj = {
type: loco.type,
length: loco.length,
mass: loco.mass,
maxSpeed: loco.maxSpeed,
isLoco: true,
cargo: undefined,
count: 1,
imgSrc: loco.imageSrc,
useType: loco.power,
supportersOnly: loco.supportersOnly,
};
if (this.store.stockList.length > 0 && !this.store.stockList[0].isLoco) this.store.stockList.unshift(stockObj);
else this.store.stockList.push(stockObj);
},
addCar(car: ICarWagon, cargo?: ICargo) {
const previousStock =
this.store.stockList.length > 0 ? this.store.stockList[this.store.stockList.length - 1] : null;
if (previousStock && previousStock.type == car.type && previousStock.cargo?.id == cargo?.id) {
this.store.stockList[this.store.stockList.length - 1].count++;
return;
}
const stockObj = {
type: car.type,
length: car.length,
mass: car.mass,
maxSpeed: car.maxSpeed,
isLoco: false,
cargo: car.loadable && cargo ? cargo : undefined,
count: 1,
imgSrc: car.imageSrc,
useType: car.useType,
supportersOnly: car.supportersOnly,
};
this.store.stockList.push(stockObj);
},
},
});
</script>
<style lang="scss" scoped>
/* @import url('../styles/global.scss'); */
.card {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 100;
display: flex;
justify-content: center;
text-align: center;
border: 2px solid white;
width: 700px;
padding: 2em 1em;
background: rgba(black, 0.95);
@media screen and (max-width: 700px) {
width: 95%;
}
border-radius: 1em;
}
p {
font-size: 1.2em;
}
h1 {
display: flex;
justify-content: center;
flex-wrap: wrap;
margin: 0;
img {
margin-left: 0.5em;
width: 2em;
}
}
h3 {
margin: 0 0 2em 0;
color: #999;
}
button,
input {
margin: 0.25em;
}
input {
font-size: 1.2em;
}
button.choice-btn {
color: gray;
border-color: gray;
&:hover,
*:focus {
color: white;
border-color: white;
}
user-select: none;
}
button.chosen {
border-color: gold;
color: gold;
}
</style>
+12 -1
View File
@@ -142,7 +142,6 @@ export const carDataList = computed(() => Object.keys(vehicleDataJSON).reduce(
id: cargo.split(":")[0],
totalMass: Number(cargo.split(":")[1]),
})) : [],
mass: carPropsData?.mass || 0,
length: carPropsData?.length || 0,
});
@@ -272,6 +271,18 @@ export const warnings = {
if (headingLoco.type.startsWith("SM") && totalMass.value > 2400) return true;
return false;
}),
tooManyLocos: computed(() => {
if (Store.stockList.reduce((acc, stock) => {
if (!stock.isLoco) return acc;
acc += stock.count;
return acc;
}, 0) > 2) return true;
return false;
})
}
+8
View File
@@ -34,11 +34,19 @@ a {
}
}
p {
font-size: 1.2em;
font-weight: bold;
color: $accentColor;
}
select,
option,
input,
button {
font-family: "Lato", sans-serif;
font-size: 1em;
}
button {