diff --git a/README.md b/README.md
index 110507a..37f87b9 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@ Your troubles are long gone with ***Ride Price Manager***!
## Using the Plugin
- First, follow the installation instructions below
-- Once installed, the plugin should work automatically in game. It will _automagically_ update the prices of all your rides.
+- Once installed, the plugin should work automatically in game. It will _automagically_ update the prices of all your rides every in-game day.
- By default, the plugin chooses the highest price that guests are willing to pay for a ride.
- That number is determined by ride rating, ride age, and other factors.
- You can configure the plugin via the "Ride Price Manager" _control panel_, which is available **under the Map Dropdown** on the top bar. There, you can:
@@ -18,6 +18,9 @@ Your troubles are long gone with ***Ride Price Manager***!
- add a "Lazy Tax" to decrease ride prices. This is for people that think this plugin is overpowered or just want to re-balance the game a little bit.
- allow prices greater than $20.00 for high value rides.
- Guests are willing to pay more than $20 for some rides, but you can't set a price to more than $20 via the UI. This allows the plugin to bypass that check.
+- There are also two buttons in the _control panel_:
+ - "Make ALL Rides FREE" which does just that. This may be useful in conjunction with the "Ignore free rides" option.
+ - "Force Recalculate ALL Prices Now" also does what it says on the tin. Note that it doesn't use the "Ignore free rides" option, and recalculates free rides.
## Installation
1. Install a compatible version of OpenRCT2 (requires [`0.3.0-develop-bc33ef3`](https://openrct2.org/downloads/develop/v0.3.0-bc33ef3) released 2020/09/03 or [newer](https://openrct2.org/downloads/develop/latest))
@@ -29,9 +32,30 @@ Your troubles are long gone with ***Ride Price Manager***!
4. Run OpenRCT2!
5. Once in a scenario, open the options window via the Map dropdown to configure the plugin.
+## Multiplayer
+This plugin is now updated to work in Multiplayer! However, there are some things to know...
+
+- The plugin must be installed on the server to automatically update prices every in-game day.
+- When the prices are updated daily, only the config on the server is used.
+- Any player with the plugin can still use the "Force recalculate" and "Make rides free" buttons. There are no permissions. File an issue if you are dealing with griefers.
+- For the recalculate button, the client's config is used, but will be bulldozed when server recalculates prices on the next in-game day.
+
+To set the server config, you will need to edit the `plugin.store.json` file (typically in `C:\Users\{User}\Documents\OpenRCT2`). If that file doesn't exist, use the following as the file contents. If some keys already exist, just add the `RidePriceManager` block to what's already there. And don't mess up the commas!
+
+```
+{
+ "RidePriceManager": {
+ "pluginEnabled": true,
+ "ignoreFreeRidesEnabled": true,
+ "goodValueEnabled": false,
+ "lazyTaxFactor": 0,
+ "unboundPriceEnabled": false
+ }
+}
+```
+
## Possible Future Plans
-- Check if this works with server play
- - And make it work with server play
+- Have better tools for managing the price of transport rides.
- Automatically set park prices & allow configuration of a max admission price.
- This would help early-game ramp-up.
- Manage shop prices
@@ -52,7 +76,7 @@ If you want to request a feature or find a bug, open an issue on GitHub (as long
- Run a Command Prompt as Administrator
- `cd` to the repository
- `mklink .\lib\openrct2.d.ts "C:\Program Files\OpenRCT2\openrct2.d.ts"`
-- Edit `ride-price-manager\rollup.config.dev.js` so that it puts the build in your plugin folder.
+- Edit `ride-price-manager\rollup.config.dev.js` so that it puts the build in your plugin folder. Sorry that this is custom to me :O
- Run `npm run watch`
- Make your changes.
- Make sure to update the version number in `package.json` and in `index.js`.
@@ -60,6 +84,7 @@ If you want to request a feature or find a bug, open an issue on GitHub (as long
## Thanks
- Thanks to [OpenRCT2](https://github.com/OpenRCT2/OpenRCT2) for revitalizing a sweet game & releasing the plugin API.
-- Thanks to **oli414** for the [boilerplate template](https://github.com/oli414/openrct2-plugin-boilerplate). I adapted it to fit TypeScript for this project initally, before **wisnia74** came out with [a very well made and comprehensive TypeScript plugin template](https://github.com/wisnia74/openrct2-typescript-mod-template), which I now use for this plugin. You should definitely use that one if you want to make your own plugin.
+- This plugin is powered by **wisnia74**'s [very well made and comprehensive TypeScript plugin template](https://github.com/wisnia74/openrct2-typescript-mod-template). I highly recommend you use that one if you want to make your own plugin. So thank you, wisnia!
+- Originally, this plugin was powered by **oli414**'s [boilerplate template](https://github.com/oli414/openrct2-plugin-boilerplate) (which I adapted to support TypeScript, but it still wasn't as nice as the new plugin template). Thanks oli for helping me get the ball rolling :)
- Thanks to [Marcel Vos](https://www.youtube.com/channel/UCBlXovStrlQkVA2xJEROUNg) for getting me back into RCT2.
- And many many thanks to [IntelOrca](https://github.com/IntelOrca) for all of the Plugin support. The Plugin API is super fun, and I can't wait to see what all people make for it.
diff --git a/package.json b/package.json
index 0429f3d..7e376dc 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "ride-price-manager",
- "version": "1.3.0",
+ "version": "1.3.1",
"description": "Ride Price Manager is a plugin for OpenRCT2 that automagically updates the prices of all your rides",
"main": "app.js",
"scripts": {
diff --git a/src/RidePrices.ts b/src/RidePrices.ts
new file mode 100644
index 0000000..7823bcf
--- /dev/null
+++ b/src/RidePrices.ts
@@ -0,0 +1,84 @@
+///
+
+import config from './config';
+
+export default class RidePrices {
+ public static updateRidePrices(): void {
+ if (!config.getPluginEnabled()) {
+ return;
+ }
+ map.rides.map((ride: Ride) => { // eslint-disable-line array-callback-return
+ if (ride.price[0] === 0 && config.getIgnoreFreeRidesEnabled()) {
+ // Ignore free rides.
+ return;
+ }
+ RidePrices.setRidePrice(ride);
+ });
+ }
+
+ public static forceUpdateRidePrices(): void {
+ map.rides.map((ride: Ride) => RidePrices.setRidePrice(ride));
+ }
+
+ public static makeRidesFree(): void {
+ map.rides.map((ride: Ride) => RidePrices.setRidePrice(ride, 0));
+ }
+
+ private static setRidePrice(ride: Ride, priceInDimes?: number): void {
+ if (!RidePrices.isOpenAndRatedRide(ride)) {
+ return;
+ }
+
+ if (priceInDimes === undefined) {
+ priceInDimes = RidePrices.calculateRidePrice(ride);
+ }
+
+ // Set the price via an action (so it works in multiplayer)
+ context.executeAction(
+ 'ridesetprice',
+ {
+ ride: ride.id,
+ price: priceInDimes,
+ isPrimaryPrice: true,
+ },
+ () => { },
+ );
+ }
+
+ private static isOpenAndRatedRide(ride: Ride): boolean {
+ // Ignore shops & facilites.
+ return ride.classification === 'ride'
+ // Ignore closed/testing rides.
+ && ride.status === 'open'
+ // Ignore unrated rides.
+ && ride.excitement !== -1;
+ }
+
+ private static calculateRidePrice(ride: Ride): number {
+ // See /src/openrct2/peep/Guest.cpp for logic.
+ // if (peep_flags & PEEP_FLAGS_HAS_PAID_FOR_PARK_ENTRY) value /= 4;
+ const value = park.entranceFee > 0 && !park.getFlag('freeParkEntry')
+ ? Math.floor(ride.value / 4)
+ : ride.value;
+
+ // See /src/openrct2/peep/Guest.cpp for logic.
+ // if (ridePrice > value * 2) ChoseNotToGoOnRide
+ // if (ridePrice <= value / 2) InsertNewThought(PEEP_THOUGHT_TYPE_GOOD_VALUE)
+ let priceInDimes = config.getGoodValueEnabled()
+ ? Math.floor(value / 2)
+ : value * 2;
+
+ if (config.getLazyTaxFactor() > 0) {
+ priceInDimes *= (1 - config.getLazyTaxFactor());
+ priceInDimes = Math.floor(priceInDimes);
+ }
+
+ if (!config.getUnboundPriceEnabled()) {
+ // Max price is $20 via the UI.
+ priceInDimes = Math.min(priceInDimes, 200);
+ }
+
+ return priceInDimes;
+ }
+};
+
diff --git a/src/main.ts b/src/main.ts
index 87c74f8..7a0eb8a 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -1,18 +1,24 @@
///
-import { updateRidePrices } from './ridePriceFunctions';
+import RidePrices from './RidePrices';
import showWindow from './window';
function main(): void {
- ui.registerMenuItem('Ride Price Manager', () => {
- showWindow();
- });
+ // Headless server homies don't need to register UI, you feel me?
+ if (ui) {
+ ui.registerMenuItem('Ride Price Manager', () => {
+ showWindow();
+ });
+ }
- context.subscribe('interval.day', () => {
- updateRidePrices();
- });
+ // Only the server/singleplayer automatically triggers prices updates.
+ if (network.mode !== 'client') {
+ context.subscribe('interval.day', () => {
+ RidePrices.updateRidePrices();
+ });
- updateRidePrices();
+ RidePrices.updateRidePrices();
+ }
}
export default main;
diff --git a/src/registerPlugin.ts b/src/registerPlugin.ts
index 8980c38..c594f03 100644
--- a/src/registerPlugin.ts
+++ b/src/registerPlugin.ts
@@ -4,7 +4,7 @@ import main from './main';
registerPlugin({
name: 'Ride Price Manager',
- version: '1.3.0',
+ version: '1.3.1',
authors: ['mgovea', 'Sadret'],
type: 'remote',
licence: 'MIT',
diff --git a/src/ridePriceFunctions.ts b/src/ridePriceFunctions.ts
deleted file mode 100644
index 37574af..0000000
--- a/src/ridePriceFunctions.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-///
-
-import config from './config';
-
-function updateRidePrices(): void {
- if (!config.getPluginEnabled()) {
- return;
- }
- map.rides.map((ride: Ride) => { // eslint-disable-line array-callback-return
- if (ride.price[0] === 0 && config.getIgnoreFreeRidesEnabled()) {
- // Ignore free rides.
- return;
- }
- updateRidePrice(ride);
- });
-}
-
-function forceUpdateRidePrices(): void {
- map.rides.map(updateRidePrice);
-}
-
-function makeRidesFree(): void {
- map.rides.map((ride: Ride) => { // eslint-disable-line array-callback-return
- setRidePrice(ride, 0);
- });
-}
-
-function updateRidePrice(ride: Ride): void {
- if (ride.classification !== 'ride') {
- // Ignore shops & facilites.
- return;
- }
-
- if (ride.status !== 'open' || ride.excitement === -1) {
- // Don't change the price of closed/testing and unrated rides.
- return;
- }
-
- // See /src/openrct2/peep/Guest.cpp for logic.
- // if (peep_flags & PEEP_FLAGS_HAS_PAID_FOR_PARK_ENTRY) value /= 4;
- const value = park.entranceFee > 0
- ? Math.floor(ride.value / 4)
- : ride.value;
-
- // See /src/openrct2/peep/Guest.cpp for logic.
- // if (ridePrice > value * 2) ChoseNotToGoOnRide
- // if (ridePrice <= value / 2) InsertNewThought(PEEP_THOUGHT_TYPE_GOOD_VALUE)
- let priceInDimes = config.getGoodValueEnabled()
- ? Math.floor(value / 2)
- : value * 2;
-
- if (config.getLazyTaxFactor() > 0) {
- priceInDimes *= (1 - config.getLazyTaxFactor());
- priceInDimes = Math.floor(priceInDimes);
- }
-
- if (!config.getUnboundPriceEnabled()) {
- // Max price is $20 via the UI.
- priceInDimes = Math.min(priceInDimes, 200);
- }
-
- setRidePrice(ride, priceInDimes);
-}
-
-function setRidePrice(ride: Ride, priceInDimes: number): void {
- // Set the price via an action (so it works in multiplayer)
- context.executeAction(
- 'ridesetprice',
- {
- ride: ride.id,
- price: priceInDimes,
- isPrimaryPrice: true,
- },
- () => { },
- );
-}
-
-export {
- updateRidePrices,
- forceUpdateRidePrices,
- makeRidesFree,
-};
diff --git a/src/window.ts b/src/window.ts
index d7a0646..e0230e1 100644
--- a/src/window.ts
+++ b/src/window.ts
@@ -1,7 +1,7 @@
///
import config, { LazyTaxOption, lazyTaxOptions } from './config'; // eslint-disable-line no-unused-vars
-import { forceUpdateRidePrices, makeRidesFree } from './ridePriceFunctions';
+import RidePrices from './RidePrices';
const windowTag = 'ride_management';
const lQuote = decodeURI('%E2%80%9C');
@@ -157,7 +157,7 @@ function makeRecalculateButton(y: number): ButtonWidget {
y,
'Immediately set the price for all rides, overriding the "Ignore Free" preference',
'Force Recalculate ALL Prices Now',
- forceUpdateRidePrices,
+ RidePrices.forceUpdateRidePrices,
);
}
@@ -166,7 +166,7 @@ function makeAllRidesFreeButton(y: number): ButtonWidget {
y,
'Immediately make all rides free.',
'Make ALL Rides FREE',
- makeRidesFree,
+ RidePrices.makeRidesFree,
);
}