Skip to content

Scripting: allow precise and safe control of peep animations#21913

Merged
Gymnasiast merged 20 commits into
OpenRCT2:developfrom
AaronVanGeffen:peep-script-anim
May 5, 2024
Merged

Scripting: allow precise and safe control of peep animations#21913
Gymnasiast merged 20 commits into
OpenRCT2:developfrom
AaronVanGeffen:peep-script-anim

Conversation

@AaronVanGeffen

@AaronVanGeffen AaronVanGeffen commented Apr 27, 2024

Copy link
Copy Markdown
Member

This PR introduces methods for scripts to precisely and safely control the animation frames used to render guests and staff members. This may be used to compose intricate dioramas using peeps. However, the guests and staff have to be rendered immobile, or they will carry on with whatever they were doing, resetting their sprite.

Guests have more animations available than staff members. In turn, animations available to staff differs based on the staff type. To see what animations can be used, scripts can use the animationsAvailable property, which exists for both guests and staff.

A future PR may introduce functionality to control peeps' actions as well. However, this would have to touch core peep logic, which is less desirable.

Another request was to allow scripts to manage guests items, including food and drinks. I believe this has already been introduced in #21062.

NB: I wrote this while on public transport, so it could do with a fair bit of testing, still.

@Basssiiie and @Manticore-007, this one's for you.

@AaronVanGeffen AaronVanGeffen changed the title Allow scripts to precisely and safely animation frames for peeps Allow scripts to precisely and safely control peep animations Apr 27, 2024
Comment thread distribution/openrct2.d.ts Outdated
Comment thread distribution/openrct2.d.ts Outdated
@Manticore-007

Copy link
Copy Markdown

I am testing it right now, but the peep (guest or staff) keeps their animation on 'walking'. It looks like it's state is preventing the animation from executing, but I need @AaronVanGeffen or @Basssiiie to confirm that.

@AaronVanGeffen

AaronVanGeffen commented Apr 28, 2024

Copy link
Copy Markdown
Member Author

Could you share the code you're using to test?

Edit: I had added a call to UpdateCurrentActionSpriteType to update the entity bounding boxes, but that inadvertently reset the sprite as well. I've split off UpdateSpriteBoundingBox from that function, so all should be good now.

@AaronVanGeffen

Copy link
Copy Markdown
Member Author

Funnily enough, both @Manticore-007 and I were testing with the 'picked up' sprite for peeps and staff members, and were surprised at how much it was glitching. Turns out these sprites do not have four rotations, so we were incorrectly offsetting into them. Of course, these sprites were meant to be drawn under the mouse pointer, and never meant to be used for walking peeps! 😄

I have changed Peep::Paint to compensate, in such a way that there should be no impact for other states, performance or otherwise.

@Gymnasiast

Copy link
Copy Markdown
Member

So what’s the status here?

@AaronVanGeffen

AaronVanGeffen commented Apr 28, 2024

Copy link
Copy Markdown
Member Author

Ready to go, as far as I'm concerned. I believe @Manticore-007 has been experimenting a bunch already, too. Let's wait for him and @Basssiiie to comment.

Probably good to increment the plugin version before merging, as a means of feature detection.

@AaronVanGeffen

Copy link
Copy Markdown
Member Author

Leaving this here so I don't forget: @Manticore-007 has asked for an extra property/function to get a peep's walking animation sprite ids. Should be very doable for this PR.

@Manticore-007

Copy link
Copy Markdown

Leaving this here so I don't forget: @Manticore-007 has asked for an extra property/function to get a peep's walking animation sprite ids. Should be very doable for this PR.

If it is easy to implement, I would love to use them in the first tab of the Peep Editor just like the first tab when clicking a guest or staff member, so I need the colours of the selected peep too. But this is just some luxury thingy, nothing practical.

And apologies for responding slow, I'm not used to communicating via GitHub that much yet.

@AaronVanGeffen

AaronVanGeffen commented Apr 28, 2024

Copy link
Copy Markdown
Member Author

Well, I have added a method for obtaining the walking animation sprite ids. I couldn't resist finishing that up today 😄

I need the colours of the selected peep too. But this is just some luxury thingy, nothing practical.

I believe this information is already exported. Consider the following property for Staff:

    interface Staff extends Peep {
        /**
         * Colour of the staff member. Not applicable for entertainers.
         */
        colour: number;

For Guests, the following two properties are available:

    interface Guest extends Peep {
        /**
         * Colour of the guest's t-shirt.
         */
        tshirtColour: number;

        /**
         * Colour of the guest's trousers.
         */
        trousersColour: number;

@AaronVanGeffen AaronVanGeffen changed the title Allow scripts to precisely and safely control peep animations Scripting: allow precise and safe control of peep animations Apr 28, 2024

@Basssiiie Basssiiie left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll have a test later as well.

Did you plan on adding the flag to block a guest's state in this PR as well, or is that for a later PR? So they don't regain energy after being frozen or get included in the park rating. Because IMHO that'd be quite crucial for actually using the guest animations API. 🙂

Comment thread distribution/openrct2.d.ts Outdated
Comment thread distribution/openrct2.d.ts Outdated
@AaronVanGeffen

Copy link
Copy Markdown
Member Author

Did you plan on adding the flag to block a guest's state in this PR as well, or is that for a later PR? So they don't regain energy after being frozen or get included in the park rating. Because IMHO that'd be quite crucial for actually using the guest animations API. 🙂

That is something for a future PR, yes. I don't want to change the core peep logic in this PR.

You can already use this code as-is, though. Peeps retain their animation as long as they don't change action. They just don't support freezing yet.

@Manticore-007

Manticore-007 commented May 1, 2024

Copy link
Copy Markdown

While I have a mechanic and let him answer his phone and turning him into something else, the game will crash.

Edit: turning a mowing handyman into a mechanic also crashes the game.

#21920 fixes that, right?

@AaronVanGeffen

Copy link
Copy Markdown
Member Author

Yep, that's what the other PR is for, indeed 😁

@Gymnasiast Gymnasiast added this to the After v0.4.11 milestone May 2, 2024

@Basssiiie Basssiiie left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've had a test and found a few issues with guest sprites:

  • getAnimationSprites returns the entire animation timeline including duplicate spirtes, but animationOffset is not an offset into that timeline, but merely an offset into the spritesheet. This is especially visible with non-repeating animations like clap, drowning etc.

  • Setting the animation to eatFood or sittingEatFood without a food item gets the animation of the peep crossing its arms (either sitting or not), an animation that is not in the list otherwise? (Is this intended?)

  • Getting animation returns walking for guests sitting on benches with food items instead when sitting still. (See image below)

image

  • animation and getAnimationSprites return animations for walking when the guest is standing still in a queue with a sprite that seems to not be in the sprites list.

  • getAnimationSprites on guests with an umbrella or hat returns sprites with a headless guest and no umbrella (when raining) or hat. Balloons are also missing for guests with balloons.

image

All the API's for staff members seem to be alright, I could not find any issues there.

As is usual, click here for my test script. 🙂
registerPlugin({
	name: "Test peep anims",
	version: "1",
	authors: ['Basssiiie'],
	targetApiVersion: 82,
	type: "local",
	licence: "MIT",
	main()
	{
		ui.registerMenuItem("Test peep anims", function()
		{
			ui.activateTool({
				id: "test-peep-anims",
				cursor: "cross_hair",
				onDown: function(args)
				{
					var id = args.entityId;
					if (id == undefined) return;

					var peep = map.getEntity(id);
					if (peep.type !== "guest" && peep.type !== "staff") return;

					var anims = peep.availableAnimations;
					var shopItems = [
						"balloon", "hat", "map", "sunglasses", "toy", "tshirt", "umbrella", "photo1", "photo2", "photo3",
						"photo4", "voucher", "beef_noodles", "burger", "candyfloss", "chicken", "chips", "chocolate", "cookie",
						"doughnut", "hot_dog", "fried_rice_noodles", "funnel_cake", "ice_cream", "meatball_soup", "pizza", "popcorn",
						"pretzel", "roast_sausage", "sub_sandwich", "tentacle", "toffee_apple", "wonton_soup", "coffee", "drink",
						"fruit_juice", "iced_tea", "lemonade", "soybean_milk", "sujeonggwa"
					];
					var window = ui.openWindow({
						classification: "test-peep-anims",
						title: "Peep anims",
						width: 210,
						height: 300,
						maxWidth: 2000,
						maxHeight: 300,
						onUpdate: function()
						{
							var animShow = window.findWidget("anim-show");
							var animOffset = window.findWidget("anim-offset");
							var animLength = window.findWidget("anim-length");

							animShow.text = "Animation: " + peep.animation;
							animOffset.text = String(peep.animationOffset);
							animLength.text = "Length: " + peep.animationLength;
						},
						widgets: [
							{
								type: "label",
								x: 5,
								y: 20,
								width: 200,
								height: 15,
								text: "Name: " + peep.name
							},
							{
								name: "anim-show",
								type: "label",
								x: 5,
								y: 40,
								width: 200,
								height: 15,
								text: "Animation: " + peep.animation
							},
							{
								type: "dropdown",
								x: 5,
								y: 60,
								width: 200,
								height: 15,
								items: anims,
								onChange: function(index)
								{
									peep.animation = anims[index];
								}
							},
							{
								name: "anim-offset",
								type: "textbox",
								x: 5,
								y: 80,
								width: 200,
								height: 15,
								text: String(peep.animationOffset),
								onChange: function(text)
								{
									peep.animationOffset = Number.parseInt(text);
								}
							},
							{
								name: "anim-length",
								type: "label",
								x: 5,
								y: 100,
								width: 200,
								height: 15,
								text: "Length: " + peep.animationLength
							},
							{
								type: "dropdown",
								x: 5,
								y: 120,
								width: 200,
								height: 15,
								items: shopItems,
								onChange: function(index)
								{
									peep.removeAllItems();
									peep.giveItem({ type: shopItems[index] });
								}
							},
							{
								type: "custom",
								x: 5,
								y: 140,
								width: 2000,
								height: 150,
								onDraw: function(gfx)
								{
									var y = 0;
									for (var rot = 0; rot < 4; rot++)
									{
										var sprites = peep.getAnimationSpriteIds(peep.animation, rot);
										var x = 0;
										var height = 0;
										for (var idx = 0; idx < sprites.length; idx++)
										{
											var sprite = sprites[idx];
											var image = gfx.getImage(sprite);
											gfx.image(sprite, x - image.offset.x, y - image.offset.y);
											x += image.width + 5;
											height = Math.max(height, image.height);
										}
										y += height + 5;
									}
								}
							},
						]
					})
				}
			})
		})
	}
});

Comment thread distribution/openrct2.d.ts Outdated
@AaronVanGeffen

AaronVanGeffen commented May 5, 2024

Copy link
Copy Markdown
Member Author

getAnimationSprites returns the entire animation timeline including duplicate spirtes, but animationOffset is not an offset into that timeline, but merely an offset into the spritesheet. This is especially visible with non-repeating animations like clap, drowning etc.

Fixed. The getter now returns the animation offset rather than the sprite image offset. Looking at the code, the setter already worked correctly.

Setting the animation to eatFood or sittingEatFood without a food item gets the animation of the peep crossing its arms (either sitting or not), an animation that is not in the list otherwise? (Is this intended?)

It probably won't surprise you that the script engine just maps eatFood and sittingEatFood to an internal animation state, which is just another number, of course.

Honestly, I'm not sure sure if and how these 'arms crossed' sprites are used in the state machine, internally. If we figure that out, we could add another alias for it. Similarly, eatFood shares its number with a waving animation for entertainers, which we've already exposed differently (wave).

Something we can refine later on as well, as far as I'm concerned.

Getting animation returns walking for guests sitting on benches with food items instead when sitting still.

This is an odd one that I haven't narrowed down. Perhaps walking is a misnomer here. It is actually the normal state, which actually means walking most of the time. This is why I've exposed it as such. Any suggestions?

animation and getAnimationSprites return animations for walking when the guest is standing still in a queue with a sprite that seems to not be in the sprites list.

Well spotted. It seems queueing may be handled differently from the regular animations. I'm not sure how to go about this. Any suggestions?

getAnimationSprites on guests with an umbrella or hat returns sprites with a headless guest and no umbrella (when raining) or hat. Balloons are also missing for guests with balloons.

This is because the hat, umbrella, and balloon sprites are actually rendered separately. The guest sprites already have a primary and secondary colour set for their shirts and trousers. It seems the item sprites are rendered separately to make them independently recolourable. Not something we can change with the current set-up, as you can imagine.

@Basssiiie

Copy link
Copy Markdown
Member

This is an odd one that I haven't narrowed down. Perhaps walking is a misnomer here. It is actually the normal state, which actually means walking most of the time. This is why I've exposed it as such. Any suggestions?

I can agree with having most of the points mentioned for another time or another PR, except for this one. I can imagine a player user would like to know if a guest is sitting on a bench or not in some way or another, and it'd be weird if animation_get doesn't say sitting while its animation is obviously sitting. 😅 I don't know what is going internally either in the state machine or during drawing, but I'd prefer similar logic for getting the animation IMHO.

@AaronVanGeffen

AaronVanGeffen commented May 5, 2024

Copy link
Copy Markdown
Member Author

@Basssiiie You're right. It seems it is more complicated than I would like, though. Consider the following code excerpt from Guest::UpdateSitting() in Guest.cpp:

else if (SittingSubState == PeepSittingSubState::SatDown)
{
if (!IsActionInterruptable())
{
UpdateAction();
if (!IsActionWalking())
return;
Action = PeepActionType::Idle;
TryGetUpFromSitting();
return;
}

Note how Action is set to PeepActionType::Idle. This is what we're running into: the sprite action type is set to None for Idle or Walking. Obviously, when the sprite is actually updated later on, the correct animation is used, though. As far as I can tell, while they guest is sitting peacefully, unmoving, the action and sprite are in this undefined state. Very unfortunate.

As I don't want to change the state machine, I have come up with a compromise that adds an exception just for idle, sitting peeps. It's not the nicest, but it works:

Screenshot_2024-05-05_at_21 19 49

@Gymnasiast

Copy link
Copy Markdown
Member

Time to merge, could you add a changelog entry?

@AaronVanGeffen

Copy link
Copy Markdown
Member Author

I'd like a go-ahead from @Basssiiie first, if you don't mind.

The other peep scripting PR, #21714, is ready to go, though. Let's deal with that first, and rebase this one after, shall we?

@Gymnasiast Gymnasiast modified the milestones: After v0.4.11, v0.4.12 May 5, 2024

@Basssiiie Basssiiie left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks for your efforts and patience! 😄

@Gymnasiast Gymnasiast enabled auto-merge (squash) May 5, 2024 21:00
@Gymnasiast Gymnasiast merged commit 893392d into OpenRCT2:develop May 5, 2024
@AaronVanGeffen AaronVanGeffen deleted the peep-script-anim branch May 5, 2024 21:18
janisozaur added a commit that referenced this pull request Jul 7, 2024
- Feature: [#622] Add option to align the top toolbar buttons horizontally centred (off by default).
- Feature: [#20263] Ability to increase the size of the map in the (0, 0) direction.
- Feature: [#21714] [Plugin] Costume assignment is now tailored to each staff type.
- Feature: [#21853] Enlarged UI mode.
- Feature: [#21893, #22065] On launch, the game now indicates what system is being initialised.
- Feature: [#21913] [Plugin] Allow precise and safe control of peep animations.
- Feature: [#22046] [Plugin] Add interface for crashed vehicle particle.
- Feature: [#22085] [Plugin] The result of actions that create banners now includes the bannerIndex.
- Feature: [#22087] [Plugin] Expose guests’ favourite rides to the plugin API.
- Feature: [#22090] [Plugin] Allow writing of paused state in non-networked settings.
- Feature: [#22140] Add option to automatically close dropdown menus if Enlarged UI is enabled.
- Feature: [#22150] [Plugin] Expose monthly expenditure history to the plugin API.
- Feature: [#22210] [Plugin] Peeps can now be made stationary or completely frozen.
- Feature: [#22210] [Plugin] The direction in which a peep is facing can now be manipulated.
- Improved: [#19870] Allow using new colours in UI themes.
- Improved: [#21774] The Alpine Coaster now supports using the alternative colour schemes.
- Improved: [#21853] Dropdowns now automatically use multiple columns if they are too tall for the screen.
- Improved: [#21981] Rendering performance of the map window has been improved considerably.
- Improved: [#21981] The map window now defaults to showing as much of the map as fits the screen.
- Improved: [#21983] Taking a screenshot now shows a message again, closing when taking another.
- Improved: [#22026] The options window now stays centred when window scaling is changed.
- Improved: [#22060] [Plugin] The scroll wheel can now be used to modify spinner widget values in custom/script windows.
- Improved: [#22065] Joining a network game now indicates progress using coaster trains.
- Improved: [#22075] [Plugin] Plugins can now use G1 Icons.
- Improved: [#22084] The game now temporarily pauses while the load/save window is open.
- Improved: [#22217] See-through items are ignored again in viewport/pointer interaction.
- Improved: [objects#238] Add preview image for invisible queue.
- Improved: [objects#329] Add RCT1AA lay-down coaster trains (for import only).
- Change: [#7248] Small mini-maps are now centred in the map window.
- Change: [#20240] Heavy snow and blizzards now make guests buy and use umbrellas.
- Change: [#21043] The new music styles are no longer added to old parks automatically.
- Change: [#21214] Wacky Worlds and Time Twister’s scenario names now match their park names.
- Change: [#21991] UI themes JSON now use colour names and a translucency bool, instead of a number (old themes still work).
- Change: [#22057] Reorder Time Twister’s scenarios and adjust their difficulty classification.
- Change: [#22173] Patrol path selection is visible over existing patrol paths.
- Change: [#22196] Make track navigation buttons holdable.
- Change: [#22227] [Plugin] Ride prices are now constrained for plugins as well.
- Fix: [#13234] Vehicle weight sometimes wrong after using Remove All Guests cheat.
- Fix: [#13294] Map corners are cut off in some directions (original bug).
- Fix: [#14630] Non-ASCII thousands and decimal separators not processed correctly.
- Fix: [#21496] Some RCT1 scenery is hidden after saving and reloading.
- Fix: [#21533] Support glitches on Hybrid Coaster.
- Fix: [#21974] No reason specified when attempting to place benches, lamps, or bins on path with no unconnected edges (original bug).
- Fix: [#21987] [Plugin] API cannot handle negative removal prices.
- Fix: [#22008] Uninverted Lay-down roller coaster uses the wrong support type.
- Fix: [#22012] [Plugin] Images on ImgButton widgets cannot be updated.
- Fix: [#22121] Some news items in the “Recent Messages” window have the wrong text colour.
- Fix: [#22152] [Plugin] Negative signed integers are truncated.
- Fix: [#22161] Using arrow keys in textboxes crashes the game.
- Fix: [#22174] Cheats are reset when starting a server.
- Fix: [#22185] Intensity and nausea are incorrectly sorted in the rides list after ratings invalidation.
- Fix: [#22226] Red traffic light shows incorrect sprite when pressed.
- Fix: [objects#323] Incorrect wall boundaries on large WW/TT scenery objects.
- Fix: [objects#331] Incorrect hover car capacity string.
- Fix: [objects#334] Incorrect school bus capacity string.
- Fix: [objects#337] Swan Boats use an incorrect third remap colour (original bug).
CorySanin added a commit to CorySanin/OpenRCT2 that referenced this pull request Feb 3, 2025
Release v0.4.12

- Feature: [OpenRCT2#622] Add option to align the top toolbar buttons horizontally centred (off by default).
- Feature: [OpenRCT2#20263] Ability to increase the size of the map in the (0, 0) direction.
- Feature: [OpenRCT2#21714] [Plugin] Costume assignment is now tailored to each staff type.
- Feature: [OpenRCT2#21853] Enlarged UI mode.
- Feature: [OpenRCT2#21893, OpenRCT2#22065] On launch, the game now indicates what system is being initialised.
- Feature: [OpenRCT2#21913] [Plugin] Allow precise and safe control of peep animations.
- Feature: [OpenRCT2#22046] [Plugin] Add interface for crashed vehicle particle.
- Feature: [OpenRCT2#22085] [Plugin] The result of actions that create banners now includes the bannerIndex.
- Feature: [OpenRCT2#22087] [Plugin] Expose guests’ favourite rides to the plugin API.
- Feature: [OpenRCT2#22090] [Plugin] Allow writing of paused state in non-networked settings.
- Feature: [OpenRCT2#22140] Add option to automatically close dropdown menus if Enlarged UI is enabled.
- Feature: [OpenRCT2#22150] [Plugin] Expose monthly expenditure history to the plugin API.
- Feature: [OpenRCT2#22210] [Plugin] Peeps can now be made stationary or completely frozen.
- Feature: [OpenRCT2#22210] [Plugin] The direction in which a peep is facing can now be manipulated.
- Improved: [OpenRCT2#19870] Allow using new colours in UI themes.
- Improved: [OpenRCT2#21774] The Alpine Coaster now supports using the alternative colour schemes.
- Improved: [OpenRCT2#21853] Dropdowns now automatically use multiple columns if they are too tall for the screen.
- Improved: [OpenRCT2#21981] Rendering performance of the map window has been improved considerably.
- Improved: [OpenRCT2#21981] The map window now defaults to showing as much of the map as fits the screen.
- Improved: [OpenRCT2#21983] Taking a screenshot now shows a message again, closing when taking another.
- Improved: [OpenRCT2#22026] The options window now stays centred when window scaling is changed.
- Improved: [OpenRCT2#22060] [Plugin] The scroll wheel can now be used to modify spinner widget values in custom/script windows.
- Improved: [OpenRCT2#22065] Joining a network game now indicates progress using coaster trains.
- Improved: [OpenRCT2#22075] [Plugin] Plugins can now use G1 Icons.
- Improved: [OpenRCT2#22084] The game now temporarily pauses while the load/save window is open.
- Improved: [OpenRCT2#22217] See-through items are ignored again in viewport/pointer interaction.
- Improved: [objects#238] Add preview image for invisible queue.
- Improved: [objects#329] Add RCT1AA lay-down coaster trains (for import only).
- Change: [OpenRCT2#7248] Small mini-maps are now centred in the map window.
- Change: [OpenRCT2#20240] Heavy snow and blizzards now make guests buy and use umbrellas.
- Change: [OpenRCT2#21043] The new music styles are no longer added to old parks automatically.
- Change: [OpenRCT2#21214] Wacky Worlds and Time Twister’s scenario names now match their park names.
- Change: [OpenRCT2#21991] UI themes JSON now use colour names and a translucency bool, instead of a number (old themes still work).
- Change: [OpenRCT2#22057] Reorder Time Twister’s scenarios and adjust their difficulty classification.
- Change: [OpenRCT2#22173] Patrol path selection is visible over existing patrol paths.
- Change: [OpenRCT2#22196] Make track navigation buttons holdable.
- Change: [OpenRCT2#22227] [Plugin] Ride prices are now constrained for plugins as well.
- Fix: [OpenRCT2#13234] Vehicle weight sometimes wrong after using Remove All Guests cheat.
- Fix: [OpenRCT2#13294] Map corners are cut off in some directions (original bug).
- Fix: [OpenRCT2#14630] Non-ASCII thousands and decimal separators not processed correctly.
- Fix: [OpenRCT2#21496] Some RCT1 scenery is hidden after saving and reloading.
- Fix: [OpenRCT2#21533] Support glitches on Hybrid Coaster.
- Fix: [OpenRCT2#21974] No reason specified when attempting to place benches, lamps, or bins on path with no unconnected edges (original bug).
- Fix: [OpenRCT2#21987] [Plugin] API cannot handle negative removal prices.
- Fix: [OpenRCT2#22008] Uninverted Lay-down roller coaster uses the wrong support type.
- Fix: [OpenRCT2#22012] [Plugin] Images on ImgButton widgets cannot be updated.
- Fix: [OpenRCT2#22121] Some news items in the “Recent Messages” window have the wrong text colour.
- Fix: [OpenRCT2#22152] [Plugin] Negative signed integers are truncated.
- Fix: [OpenRCT2#22161] Using arrow keys in textboxes crashes the game.
- Fix: [OpenRCT2#22174] Cheats are reset when starting a server.
- Fix: [OpenRCT2#22185] Intensity and nausea are incorrectly sorted in the rides list after ratings invalidation.
- Fix: [OpenRCT2#22226] Red traffic light shows incorrect sprite when pressed.
- Fix: [objects#323] Incorrect wall boundaries on large WW/TT scenery objects.
- Fix: [objects#331] Incorrect hover car capacity string.
- Fix: [objects#334] Incorrect school bus capacity string.
- Fix: [objects#337] Swan Boats use an incorrect third remap colour (original bug).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants