Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
b6ff651
add configurable selection of vehicles on train as a target
Manticore-007 May 22, 2025
c873fc2
changed `let` to `const`
Manticore-007 May 22, 2025
82367ec
fix: multiple `Opening curly brace appears on the same line as contro…
Manticore-007 May 22, 2025
337d15d
fix: edited expression to function call
Manticore-007 May 22, 2025
f250fc9
changed `Custom selection of vehicles` to `Specific vehicles`
Manticore-007 May 22, 2025
41de90e
fixed `setSequence` function
Manticore-007 May 23, 2025
3e41c69
fixed opening curly brace
Manticore-007 May 23, 2025
9742eb9
removed export from function
Manticore-007 May 23, 2025
d7eff63
fixed lastVehicle variable
Manticore-007 May 23, 2025
192f02e
changed "last vehicle" to "amount of vehicles"
Manticore-007 May 23, 2025
10e005e
Forgot an underscore
Manticore-007 May 23, 2025
ac9a50b
fixed values for "amount of vehicles" spinner
Manticore-007 May 23, 2025
bbeb56e
Menus for Specific vehicles on all trains
Manticore-007 May 23, 2025
aa5b16f
add configurable selection of vehicles on all trains as a target
Manticore-007 May 23, 2025
5d21d88
added all trains check
Manticore-007 May 23, 2025
650a717
renamed function
Manticore-007 May 24, 2025
7432047
Fixed the code so every key including `spacing` works
Manticore-007 May 24, 2025
c9cc11e
fixed amount of vehicles after closing and reopening plugin
Manticore-007 May 24, 2025
ab74f51
Menus for Specific vehicles on all trains
Manticore-007 May 23, 2025
6dd297f
add configurable selection of vehicles on all trains as a target
Manticore-007 May 23, 2025
f3c97c9
Merge branch 'Specific-vehicles-on-all-trains' of https://github.com/…
Manticore-007 May 24, 2025
2a14aa0
dropdowns visible for specific vehicles on all trains
Manticore-007 May 24, 2025
a4695fa
Merge pull request #1 from Manticore-007/Specific-vehicles-on-all-trains
Manticore-007 May 24, 2025
8b6a0de
add a third element in `VehicleSpan` for sequence, removed old sequen…
Manticore-007 May 25, 2025
c29e4e7
add store `isSequenceVisible`
Manticore-007 May 25, 2025
afdad10
repaired syntax mistakes
Manticore-007 May 25, 2025
5c54870
repaired tests files
Manticore-007 May 25, 2025
2bca5dc
another tests repair
Manticore-007 May 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 25 additions & 12 deletions src/services/vehicleCopier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ export const enum CopyOptions
AllVehiclesOnTrain,
PrecedingVehiclesOnTrain,
FollowingVehiclesOnTrain,
SpecificVehiclesOnTrain,
AllVehiclesOnAllTrains,
PrecedingVehiclesOnAllTrains,
FollowingVehiclesOnAllTrains,
SameVehicleOnAllTrains
SameVehicleOnAllTrains,
SpecificVehiclesOnAllTrains
}

/**
Expand All @@ -31,10 +33,12 @@ export const copyOptions = <const>[
"All vehicles on this train",
"Preceding vehicles on this train",
"Following vehicles on this train",
"Specific vehicles on this train",
"All vehicles on all trains",
"Preceding vehicles on all trains",
"Following vehicles on all trains",
"Same vehicle number on all trains"
"Same vehicle number on all trains",
"Specific vehicles on all trains"
];


Expand Down Expand Up @@ -62,42 +66,51 @@ export const enum CopyFilter
* Gets the targeted vehicles based on the selected copy option, in the following
* format; [[ car id, amount of following cars (inclusive) ], ...].
*/
export function getTargets(copyOption: CopyOptions, ride: [ParkRide, number] | null, train: [RideTrain, number] | null, vehicle: [RideVehicle, number] | null): [number, number | null][]
export function getTargets(copyOption: CopyOptions, ride: [ParkRide, number] | null, train: [RideTrain, number] | null, vehicle: [RideVehicle, number] | null, amount: number, sequence: number): [number, number | null, number][]
{
if (ride && train && vehicle)
{
switch (copyOption)
{
case CopyOptions.AllVehiclesOnTrain:
{
return [[ train[0]._carId, null ]];
return [[ train[0]._carId, null, 1 ]];
}
case CopyOptions.PrecedingVehiclesOnTrain:
{
return [[ train[0]._carId, vehicle[1] + 1 ]];
return [[ train[0]._carId, vehicle[1] + 1, 1 ]];
}
case CopyOptions.FollowingVehiclesOnTrain:
{
return [[ vehicle[0]._id, null ]];
return [[ vehicle[0]._id, null, 1 ]];
}
case CopyOptions.SpecificVehiclesOnTrain:
{
return [[ vehicle[0]._id, amount, sequence ]];
}
case CopyOptions.AllVehiclesOnAllTrains:
{
return getTargetsOnAllTrains(ride, t => [ t._carId, null ]);
return getTargetsOnAllTrains(ride, t => [ t._carId, null, 1 ]);
}
case CopyOptions.PrecedingVehiclesOnAllTrains:
{
const amountOfVehicles = (vehicle[1] + 1);
return getTargetsOnAllTrains(ride, t => [ t._carId, amountOfVehicles ]);
return getTargetsOnAllTrains(ride, t => [ t._carId, amountOfVehicles, 1 ]);
}
case CopyOptions.FollowingVehiclesOnAllTrains:
{
const index = vehicle[1];
return getTargetsOnAllTrains(ride, t => [ t._at(index)._id, null ]);
return getTargetsOnAllTrains(ride, t => [ t._at(index)._id, null, 1 ]);
}
case CopyOptions.SameVehicleOnAllTrains:
{
const index = vehicle[1];
return getTargetsOnAllTrains(ride, t => [ t._at(index)._id, 1 ]);
return getTargetsOnAllTrains(ride, t => [ t._at(index)._id, 1, 1 ]);
}
case CopyOptions.SpecificVehiclesOnAllTrains:
{
const index = vehicle[1];
return getTargetsOnAllTrains(ride, t => [ t._at(index)._id, amount, sequence ]);
}
}
}
Expand Down Expand Up @@ -157,7 +170,7 @@ export function getVehicleSettings(source: RideVehicle, filters: CopyFilter): Ve
/**
* Applies the set of vehicle settings to the specified targets.
*/
export function applyToTargets(settings: VehicleSettings, targets: [number, number | null][]): void
export function applyToTargets(settings: VehicleSettings, targets: [number, number | null, number][]): void
{
execute({ settings, targets });
}
Expand Down Expand Up @@ -237,7 +250,7 @@ function applyVehicleSettings(car: Car, settings: VehicleSettings): void
/**
* Finds the matching targets on all trains of the specified ride.
*/
function getTargetsOnAllTrains(ride: [ParkRide, number], callback: (train: RideTrain) => [number, number | null]): [number, number | null][]
function getTargetsOnAllTrains(ride: [ParkRide, number], callback: (train: RideTrain) => [number, number | null, number]): [number, number | null, number][]
{
return ride[0]._trains().map(callback);
}
1 change: 0 additions & 1 deletion src/services/vehicleEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,6 @@ function updateVehicleSetting(args: UpdateVehicleSettingArgs): void
return;
}
}

forEachVehicle(targets, callback);
}

Expand Down
20 changes: 12 additions & 8 deletions src/services/vehicleSpan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ import { isNull } from "../utilities/type";
import { invoke, refreshVehicle } from "./events";

/**
* A tuple for targeting a span of entities. The first tuple value specifies a car id
* and the second tuple value specifies to how many vehicles the change should be applied.
* A tuple for targeting a span of entities. The first tuple value specifies a car id,
* the second tuple value specifies to how many vehicles and the third tuple
* specifies every number of vehicles to which the change should be applied
*
* For example: `[33, 2]` applies the paste to the vehicle with id 33, and the first
* one after. A `null` applies the paste from the first vehicle to the end of the train.
* For example: `[33, 10, 4]` applies the paste from the vehicle with id 33 to ten
* vehicles, every fourth vehicle. A `null` in the second tuple applies the paste
* from the first vehicle to the end of the train.
*/
export type VehicleSpan = [number, number | null];
export type VehicleSpan = [number, number | null, number];


/**
Expand All @@ -21,6 +23,7 @@ export function forEachVehicle(vehicles: VehicleSpan[], action: (car: Car, index
{
const span = vehicles[s];
const maximum = span[1];
const sequence = span[2];
let currentId = span[0];
let count = 0;

Expand All @@ -29,10 +32,11 @@ export function forEachVehicle(vehicles: VehicleSpan[], action: (car: Car, index
const car = getCarById(currentId);
if (!car)
break;

action(car, count);
if (count % sequence === 0)
{
action(car, count);
}
invoke(refreshVehicle, currentId);

const nextId = car.nextCarOnTrain;
if (isNull(nextId))
break;
Expand Down
58 changes: 53 additions & 5 deletions src/ui/mainWindow.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { button, checkbox, CheckboxParams, colourPicker, compute, dropdown, dropdownSpinner, DropdownSpinnerParams, FlexiblePosition, groupbox, horizontal, label, SpinnerParams, toggle, twoway, vertical, viewport, WidgetCreator, window } from "openrct2-flexui";
import { button, checkbox, CheckboxParams, colourPicker, compute, dropdown, dropdownSpinner, DropdownSpinnerParams, FlexiblePosition, groupbox, horizontal, label, spinner, SpinnerParams, toggle, twoway, vertical, viewport, WidgetCreator, window } from "openrct2-flexui";
import { isDevelopment, pluginVersion } from "../environment";
import { RideType } from "../objects/rideType";
import { RideVehicleVariant, VehicleVisibility } from "../objects/rideVehicleVariant";
Expand Down Expand Up @@ -55,7 +55,7 @@ model._selectedRide.subscribe(r =>
const mainWindow = window({
title,
width: { value: 515, min: 515, max: 560 },
height: 415,
height: 430,
spacing: 5,
onOpen: () => model._open(),
onClose: () =>
Expand Down Expand Up @@ -244,14 +244,62 @@ const mainWindow = window({
"All vehicles on this train",
"Preceding vehicles on this train",
"Following vehicles on this train",
"Specific vehicles on this train",
"All vehicles on all trains",
"Preceding vehicles on all trains",
"Following vehicles on all trains",
"Same vehicle number on all trains"
"Same vehicle number on all trains",
"Specific vehicles on all trains"
],
tooltip: applyOptionsTip,
selectedIndex: model._copyTargetOption,
onChange: idx => model._copyTargetOption.set(idx)
onChange: idx =>
{
model._setSequence(idx);
model._copyTargetOption.set(idx);
}
}),
horizontal({
padding: { top: -4, right: 1 },
content: [
label({
text: "Apply to every # vehicle(s):",
tooltip: "Applies settings to every selected number of vehicles",
width: 180,
visibility: model._isSequenceVisible
}),
spinner({
tooltip: "Applies settings to every selected number of vehicles",
width: 60,
value: compute(model._sequence, s => s),
minimum: 1,
maximum: compute(model._vehicles, c => c.length || 1),
step: model._multiplier,
visibility: model._isSequenceVisible,
onChange: v => model._sequence.set(v)
})
]
}),
horizontal({
padding: { top: -4, right: 1 },
content: [
label({
text: "Amount of vehicles to modify",
tooltip: "Selects which vehicle of the train is the last to modify",
width: 180,
visibility: model._isSequenceVisible
}),
spinner({
tooltip: "Sets the amount of vehicles to modify",
width: 60,
value: compute(model._vehicles, c => c.length),
minimum: 1,
maximum: compute(model._vehicles, model._selectedVehicle, (c, s) => (s) ? c.length - s[1] : 1),
step: model._multiplier,
visibility: model._isSequenceVisible,
onChange: v => model._amount.set(v)
})
]
}),
horizontal([
button({
Expand Down Expand Up @@ -479,7 +527,7 @@ function applySelectedSettingsToRide(): void
{
applyToTargets(
getVehicleSettings(vehicle[0], model._copyFilters.get()),
getTargets(model._copyTargetOption.get(), model._selectedRide.get(), model._selectedTrain.get(), vehicle)
getTargets(model._copyTargetOption.get(), model._selectedRide.get(), model._selectedTrain.get(), vehicle, model._amount.get(), model._sequence.get())
);
}
}
Expand Down
24 changes: 21 additions & 3 deletions src/viewmodels/vehicleViewModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,21 @@ export class VehicleViewModel
readonly _isUnpowered = compute(this._selectedVehicle, this._type, this._variant, v => !v || !v[0]._isPowered());
readonly _isPicking = store<boolean>(false);
readonly _isDragging = store<boolean>(false);
readonly _isSequence = store<boolean>(false);
readonly _isEditDisabled = compute(this._selectedVehicle, v => !v);
readonly _isSpinDisabled = compute(this._spinFrames, v => !v);
readonly _isPositionDisabled = compute(this._isMoving, this._isEditDisabled, (m, e) => m || e);
readonly _isSequenceVisible = compute(this._isSequence, s => s ? "visible" : "none");
readonly _formatPosition = (pos: number): string => (this._isEditDisabled.get() ? "Not available" : pos.toString());
readonly _multiplierIndex = store<number>(0);
readonly _multiplier = compute(this._multiplierIndex, idx => (10 ** idx));

readonly _sequence = store<number>(1);
readonly _amount = compute(this._vehicles, c => c.length);

readonly _copyFilters = store(CopyFilter.Default);
readonly _copyTargetOption = store<CopyOptions>(0);
readonly _copyTargets = compute(this._copyTargetOption, this._selectedVehicle, (o, v) => getTargets(o, this._selectedRide.get(), this._selectedTrain.get(), v));
readonly _copyTargets = compute(this._copyTargetOption, this._selectedVehicle, this._amount, this._sequence, (o, v, a, s) => getTargets(o, this._selectedRide.get(), this._selectedTrain.get(), v, a, s ));
readonly _synchronizeTargets = store<boolean>(false);
readonly _clipboard = store<VehicleSettings | null>(null);

Expand Down Expand Up @@ -302,7 +307,7 @@ export class VehicleViewModel
}
else
{
action([[ vehicle[0]._id, 1 ]], value);
action([[ vehicle[0]._id, 1, this._sequence.get()]], value);
}
}
else
Expand Down Expand Up @@ -357,6 +362,19 @@ export class VehicleViewModel
}
}

/**
* Toggle the visibilty of specific vehicles options.
*/
_setSequence(index: number): void
{
const check = index === CopyOptions.SpecificVehiclesOnTrain || index === CopyOptions.SpecificVehiclesOnAllTrains;
this._isSequence.set(check);
if (!check)
{
this._sequence.set(1);
}
}

/**
* Copies the currently selected vehicle to the clipboard, or clears clipboard.
*/
Expand All @@ -383,7 +401,7 @@ export class VehicleViewModel
const settings = this._clipboard.get();
if (vehicle && settings)
{
applyToTargets(settings, [[ vehicle[0]._id, 1 ]]);
applyToTargets(settings, [[ vehicle[0]._id, 1, this._sequence.get()]]);
}
}

Expand Down
Loading